diff --git a/adapters/operaads/operaads.go b/adapters/operaads/operaads.go new file mode 100644 index 00000000000..890a15ddb5f --- /dev/null +++ b/adapters/operaads/operaads.go @@ -0,0 +1,215 @@ +package operaads + +import ( + "encoding/json" + "fmt" + "github.com/prebid/prebid-server/macros" + "net/http" + "text/template" + + "github.com/mxmCherry/openrtb/v15/openrtb2" + "github.com/prebid/prebid-server/adapters" + "github.com/prebid/prebid-server/config" + "github.com/prebid/prebid-server/errortypes" + "github.com/prebid/prebid-server/openrtb_ext" +) + +type adapter struct { + epTemplate *template.Template +} + +// Builder builds a new instance of the operaads adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) { + epTemplate, err := template.New("endpoint").Parse(config.Endpoint) + if err != nil { + return nil, err + } + bidder := &adapter{ + epTemplate: epTemplate, + } + return bidder, nil +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + impCount := len(request.Imp) + requestData := make([]*adapters.RequestData, 0, impCount) + errs := []error{} + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + + err := checkRequest(request) + if err != nil { + errs = append(errs, err) + return nil, errs + } + + for _, imp := range request.Imp { + requestCopy := *request + var bidderExt adapters.ExtImpBidder + if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { + errs = append(errs, &errortypes.BadInput{ + Message: err.Error(), + }) + continue + } + + var operaadsExt openrtb_ext.ImpExtOperaads + if err := json.Unmarshal(bidderExt.Bidder, &operaadsExt); err != nil { + errs = append(errs, &errortypes.BadInput{ + Message: err.Error(), + }) + continue + } + + err := convertImpression(&imp) + if err != nil { + errs = append(errs, &errortypes.BadInput{ + Message: err.Error(), + }) + continue + } + + imp.TagID = operaadsExt.PlacementID + + requestCopy.Imp = []openrtb2.Imp{imp} + reqJSON, err := json.Marshal(&requestCopy) + if err != nil { + errs = append(errs, err) + return nil, errs + } + + macro := macros.EndpointTemplateParams{PublisherID: operaadsExt.PublisherID, AccountID: operaadsExt.EndpointID} + endpoint, err := macros.ResolveMacros(*a.epTemplate, ¯o) + if err != nil { + errs = append(errs, err) + continue + } + reqData := &adapters.RequestData{ + Method: http.MethodPost, + Uri: endpoint, + Body: reqJSON, + Headers: headers, + } + requestData = append(requestData, reqData) + } + return requestData, errs +} + +func checkRequest(request *openrtb2.BidRequest) error { + if request.Device == nil || len(request.Device.OS) == 0 { + return &errortypes.BadInput{ + Message: "Impression is missing device OS information", + } + } + + return nil +} + +func convertImpression(imp *openrtb2.Imp) error { + if imp.Banner != nil { + bannerCopy, err := convertBanner(imp.Banner) + if err != nil { + return err + } + imp.Banner = bannerCopy + } + if imp.Native != nil && imp.Native.Request != "" { + v := make(map[string]interface{}) + err := json.Unmarshal([]byte(imp.Native.Request), &v) + if err != nil { + return err + } + _, ok := v["native"] + if !ok { + body, err := json.Marshal(struct { + Native interface{} `json:"native"` + }{ + Native: v, + }) + if err != nil { + return err + } + native := *imp.Native + native.Request = string(body) + imp.Native = &native + } + } + return nil +} + +// make sure that banner has openrtb 2.3-compatible size information +func convertBanner(banner *openrtb2.Banner) (*openrtb2.Banner, error) { + if banner.W == nil || banner.H == nil || *banner.W == 0 || *banner.H == 0 { + if len(banner.Format) > 0 { + f := banner.Format[0] + + bannerCopy := *banner + + bannerCopy.W = openrtb2.Int64Ptr(f.W) + bannerCopy.H = openrtb2.Int64Ptr(f.H) + + return &bannerCopy, nil + } else { + return nil, &errortypes.BadInput{ + Message: "Size information missing for banner", + } + } + } + return banner, nil +} + +func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if response.StatusCode == http.StatusNoContent { + return nil, nil + } + + if response.StatusCode == http.StatusBadRequest { + return nil, []error{&errortypes.BadInput{ + 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{ + Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info", response.StatusCode), + }} + } + + var parsedResponse openrtb2.BidResponse + if err := json.Unmarshal(response.Body, &parsedResponse); err != nil { + return nil, []error{&errortypes.BadServerResponse{ + Message: err.Error(), + }} + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(1) + + for _, sb := range parsedResponse.SeatBid { + for i := 0; i < len(sb.Bid); i++ { + bid := sb.Bid[i] + if bid.Price != 0 { + bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ + Bid: &bid, + BidType: getMediaTypeForImp(bid.ImpID, internalRequest.Imp), + }) + } + } + } + return bidResponse, 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/operaads/operaads_test.go b/adapters/operaads/operaads_test.go new file mode 100644 index 00000000000..eb4280b68e9 --- /dev/null +++ b/adapters/operaads/operaads_test.go @@ -0,0 +1,20 @@ +package operaads + +import ( + "testing" + + "github.com/prebid/prebid-server/adapters/adapterstest" + "github.com/prebid/prebid-server/config" + "github.com/prebid/prebid-server/openrtb_ext" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderOperaads, config.Adapter{ + Endpoint: "http://example.com/operaads/ortb/v2/{{.PublisherID}}?ep={{.AccountID}}"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "operaadstest", bidder) +} diff --git a/adapters/operaads/operaadstest/exemplary/native.json b/adapters/operaads/operaadstest/exemplary/native.json new file mode 100644 index 00000000000..4491bd150e4 --- /dev/null +++ b/adapters/operaads/operaadstest/exemplary/native.json @@ -0,0 +1,137 @@ +{ + "mockBidRequest":{ + "id":"some-req-id", + "imp":[ + { + "id":"some-imp-id", + "native":{ + "request":"{\"native\":{\"ver\":\"1.1\",\"layout\":3,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":344,\"hmin\":194}},{\"id\":3,\"required\":1,\"img\":{\"type\":1,\"w\":128,\"wmin\":80,\"h\":128,\"hmin\":80}},{\"id\":4,\"required\":1,\"data\":{\"type\":2,\"len\":90}},{\"id\":6,\"data\":{\"type\":12,\"len\":15}}]}}", + "ver":"1.1" + }, + "ext":{ + "bidder":{ + "placementId":"s123456", + "endpointId":"ep19978", + "publisherId":"pub123" + } + } + } + ], + "site":{ + "domain":"example.com", + "page":"example.com" + }, + "device":{ + "ip":"152.193.6.74", + "os":"android" + }, + "user":{ + "id":"db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid":"8299345306627569435" + }, + "tmax":500 + }, + "httpcalls":[ + { + "expectedRequest":{ + "uri":"http://example.com/operaads/ortb/v2/pub123?ep=ep19978", + "body":{ + "id":"some-req-id", + "imp":[ + { + "id":"some-imp-id", + "tagid":"s123456", + "ext":{ + "bidder":{ + "placementId":"s123456", + "endpointId":"ep19978", + "publisherId":"pub123" + } + }, + "native":{ + "request":"{\"native\":{\"ver\":\"1.1\",\"layout\":3,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":344,\"hmin\":194}},{\"id\":3,\"required\":1,\"img\":{\"type\":1,\"w\":128,\"wmin\":80,\"h\":128,\"hmin\":80}},{\"id\":4,\"required\":1,\"data\":{\"type\":2,\"len\":90}},{\"id\":6,\"data\":{\"type\":12,\"len\":15}}]}}", + "ver":"1.1" + } + } + ], + "site":{ + "domain":"example.com", + "page":"example.com" + }, + "device":{ + "ip":"152.193.6.74", + "os":"android" + }, + "user":{ + "id":"db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid":"8299345306627569435" + }, + "tmax":500 + } + }, + "mockResponse":{ + "status":200, + "body":{ + "id":"some-req-id", + "seatbid":[ + { + "bid":[ + { + "id":"928185755156387460", + "impid":"some-imp-id", + "price":1, + "adid":"69595837", + "adm":"{\"assets\":[{\"id\": 2,\"img\":{\"url\":\"http://example.com/p/creative-image/5e/b6/de/c3/5eb6dec3-4854-4dcd-980a-347f36ab502e.jpg\",\"w\": 344,\"h\": 194}},{\"id\": 3,\"img\":{\"url\":\"http://example.com/p/creative-image/5e/b6/de/c3/5eb6dec3-4854-4dcd-980a-347f36ab502e.jpg\",\"w\": 100,\"h\": 100}} ,{\"id\": 1,\"title\":{\"text\":\"This is an example Prebid Native creative\"}},{\"id\": 4,\"data\":{\"value\":\"This is a Prebid Native Creative. There are many like it, but this one is mine.\"}},{\"id\": 6,\"data\":{\"value\":\"Please.\"}} ],\"link\":{\"url\":\"http://example.com/click?AAAAAAAA8D8AAAAAAADwPwAAAAAAAAAAAAAAAAAA8D8AAAAAAADwPwhdYz3ZyNFNG3fXpZUyLXNZ0o5aAAAAACrElgC-AwAAvgMAAAIAAAC98iUEeP4QAAAAAABVU0QAVVNEAAEAAQARIAAAAAABAgQCAAAAAAEAhBaSXgAAAAA./pp=${AUCTION_PRICE}/cnd=%21OwwGAQiGmooHEL3llyEY-PxDIAQoADoRZGVmYXVsdCNOWU0yOjQwMjM./bn=75922/test=1/referrer=prebid.org/clickenc=http%3A%2F%2Fprebid.org%2Fdev-docs%2Fshow-native-ads.html\"},\"imptrackers\":[\"http://example.com/openrtb_win?e=wqT_3QLFBqBFAwAAAwDWAAUBCNmku9QFEIi6jeuTm_LoTRib7t2u2tLMlnMqNgkAAAECCPA_EQEHEAAA8D8ZCQkIAAAhCQkI8D8pEQkAMQkJqAAAMKqI2wQ4vgdAvgdIAlC95ZchWPj8Q2AAaJFAeJLRBIABAYoBA1VTRJIFBvBQmAEBoAEBqAEBsAEAuAECwAEEyAEC0AEJ2AEA4AEB8AEAigI7dWYoJ2EnLCAxMzc2ODYwLCAxNTE5MzA5NDAxKTt1ZigncicsIDY5NTk1ODM3Nh4A8IqSAvUBIXRETkdfUWlHbW9vSEVMM2xseUVZQUNENF9FTXdBRGdBUUFSSXZnZFFxb2piQkZnQVlMTURhQUJ3QUhnQWdBRUFpQUVBa0FFQm1BRUJvQUVCcUFFRHNBRUF1UUVwaTRpREFBRHdQOEVCS1l1SWd3QUE4RF9KQVhfelYzek1zXzBfMlFFQUFBAQMkRHdQLUFCQVBVQgEOLEFKZ0NBS0FDQUxVQwUQBEwwCQjwTE1BQ0FNZ0NBT0FDQU9nQ0FQZ0NBSUFEQVpBREFKZ0RBYWdEaHBxS0I3b0RFV1JsWm1GMWJIUWpUbGxOTWpvME1ESXqaAjkhT3d3R0FRNvgA8E4tUHhESUFRb0FEb1JaR1ZtWVhWc2RDTk9XVTB5T2pRd01qTS7YAugH4ALH0wHqAgpwcmViaWQub3Jn8gIRCgZBRFZfSUQSBzEzNzY4NjDyARQMQ1BHXwEUNDM1MDMwOTjyAhEKBUNQARPwmQgxNDg0NzIzOIADAYgDAZADAJgDFKADAaoDAMADkBzIAwDYAwDgAwDoAwD4AwOABACSBAkvb3BlbnJ0YjKYBACiBAwxNTIuMTkzLjYuNzSoBJrMI7IEDAgAEAAYACAAMAA4ALgEAMAEAMgEANIEEWRlZmF1bHQjTllNMjo0MDIz2gQCCADgBADwBL3llyGIBQGYBQCgBf____8FA1ABqgULc29tZS1yZXEtaWTABQDJBQAFARTwP9IFCQkFC2QAAADYBQHgBQHwBd4C-gUECAAQAJAGAZgGAA..&s=08b1535744639c904684afe46e3c6c0e4786089f&test=1&referrer=prebid.org&pp=${AUCTION_PRICE}\"]}", + "adomain":[ + "example.com" + ], + "iurl":"http://example.com/cr?id=69595837", + "cid":"958", + "crid":"69595837", + "cat":[ + "IAB3-1" + ], + "ext":{ + + } + } + ], + "seat":"958" + } + ], + "bidid":"8141327771600527856", + "cur":"USD" + } + } + } + ], + "expectedBidResponses":[ + { + "currency":"USD", + "bids":[ + { + "bid":{ + "id":"928185755156387460", + "impid":"some-imp-id", + "price":1, + "adm":"{\"assets\":[{\"id\": 2,\"img\":{\"url\":\"http://example.com/p/creative-image/5e/b6/de/c3/5eb6dec3-4854-4dcd-980a-347f36ab502e.jpg\",\"w\": 344,\"h\": 194}},{\"id\": 3,\"img\":{\"url\":\"http://example.com/p/creative-image/5e/b6/de/c3/5eb6dec3-4854-4dcd-980a-347f36ab502e.jpg\",\"w\": 100,\"h\": 100}} ,{\"id\": 1,\"title\":{\"text\":\"This is an example Prebid Native creative\"}},{\"id\": 4,\"data\":{\"value\":\"This is a Prebid Native Creative. There are many like it, but this one is mine.\"}},{\"id\": 6,\"data\":{\"value\":\"Please.\"}} ],\"link\":{\"url\":\"http://example.com/click?AAAAAAAA8D8AAAAAAADwPwAAAAAAAAAAAAAAAAAA8D8AAAAAAADwPwhdYz3ZyNFNG3fXpZUyLXNZ0o5aAAAAACrElgC-AwAAvgMAAAIAAAC98iUEeP4QAAAAAABVU0QAVVNEAAEAAQARIAAAAAABAgQCAAAAAAEAhBaSXgAAAAA./pp=${AUCTION_PRICE}/cnd=%21OwwGAQiGmooHEL3llyEY-PxDIAQoADoRZGVmYXVsdCNOWU0yOjQwMjM./bn=75922/test=1/referrer=prebid.org/clickenc=http%3A%2F%2Fprebid.org%2Fdev-docs%2Fshow-native-ads.html\"},\"imptrackers\":[\"http://example.com/openrtb_win?e=wqT_3QLFBqBFAwAAAwDWAAUBCNmku9QFEIi6jeuTm_LoTRib7t2u2tLMlnMqNgkAAAECCPA_EQEHEAAA8D8ZCQkIAAAhCQkI8D8pEQkAMQkJqAAAMKqI2wQ4vgdAvgdIAlC95ZchWPj8Q2AAaJFAeJLRBIABAYoBA1VTRJIFBvBQmAEBoAEBqAEBsAEAuAECwAEEyAEC0AEJ2AEA4AEB8AEAigI7dWYoJ2EnLCAxMzc2ODYwLCAxNTE5MzA5NDAxKTt1ZigncicsIDY5NTk1ODM3Nh4A8IqSAvUBIXRETkdfUWlHbW9vSEVMM2xseUVZQUNENF9FTXdBRGdBUUFSSXZnZFFxb2piQkZnQVlMTURhQUJ3QUhnQWdBRUFpQUVBa0FFQm1BRUJvQUVCcUFFRHNBRUF1UUVwaTRpREFBRHdQOEVCS1l1SWd3QUE4RF9KQVhfelYzek1zXzBfMlFFQUFBAQMkRHdQLUFCQVBVQgEOLEFKZ0NBS0FDQUxVQwUQBEwwCQjwTE1BQ0FNZ0NBT0FDQU9nQ0FQZ0NBSUFEQVpBREFKZ0RBYWdEaHBxS0I3b0RFV1JsWm1GMWJIUWpUbGxOTWpvME1ESXqaAjkhT3d3R0FRNvgA8E4tUHhESUFRb0FEb1JaR1ZtWVhWc2RDTk9XVTB5T2pRd01qTS7YAugH4ALH0wHqAgpwcmViaWQub3Jn8gIRCgZBRFZfSUQSBzEzNzY4NjDyARQMQ1BHXwEUNDM1MDMwOTjyAhEKBUNQARPwmQgxNDg0NzIzOIADAYgDAZADAJgDFKADAaoDAMADkBzIAwDYAwDgAwDoAwD4AwOABACSBAkvb3BlbnJ0YjKYBACiBAwxNTIuMTkzLjYuNzSoBJrMI7IEDAgAEAAYACAAMAA4ALgEAMAEAMgEANIEEWRlZmF1bHQjTllNMjo0MDIz2gQCCADgBADwBL3llyGIBQGYBQCgBf____8FA1ABqgULc29tZS1yZXEtaWTABQDJBQAFARTwP9IFCQkFC2QAAADYBQHgBQHwBd4C-gUECAAQAJAGAZgGAA..&s=08b1535744639c904684afe46e3c6c0e4786089f&test=1&referrer=prebid.org&pp=${AUCTION_PRICE}\"]}", + "adid":"69595837", + "adomain":[ + "example.com" + ], + "iurl":"http://example.com/cr?id=69595837", + "cid":"958", + "crid":"69595837", + "cat":[ + "IAB3-1" + ], + "ext":{ + + } + }, + "type":"native" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/operaads/operaadstest/exemplary/simple-banner.json b/adapters/operaads/operaadstest/exemplary/simple-banner.json new file mode 100644 index 00000000000..53b19c82c2a --- /dev/null +++ b/adapters/operaads/operaadstest/exemplary/simple-banner.json @@ -0,0 +1,156 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "domain": "good.site", + "page": "https://good.site/url", + "publisher": { + "id": "test-publisher-id" + }, + "ext": { + "amp": 0 + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "secure": 1, + "ext": { + "bidder": { + "placementId": "s17890", + "endpointId": "ep19979", + "publisherId": "pub456" + } + } + } + ], + "device": { + "os": "android", + "ua": "test-user-agent", + "ip": "123.123.123.123", + "h": 700, + "w": 375 + }, + "at": 1, + "tmax": 200, + "test": 1, + "source": { + "tid": "283746293874293" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com/operaads/ortb/v2/pub456?ep=ep19979", + "body": { + "id": "test-request-id", + "site": { + "domain": "good.site", + "page": "https://good.site/url", + "publisher": { + "id": "test-publisher-id" + }, + "ext": { + "amp": 0 + } + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "s17890", + "banner": { + "h": 250, + "w": 300, + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "secure": 1, + "ext": { + "bidder": { + "placementId": "s17890", + "endpointId": "ep19979", + "publisherId": "pub456" + } + } + } + ], + "device": { + "os": "android", + "ua": "test-user-agent", + "ip": "123.123.123.123", + "h": 700, + "w": 375 + }, + "at": 1, + "tmax": 200, + "test": 1, + "source": { + "tid": "283746293874293" + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "1519967420713_259406708_583019428", + "seatbid": [ + { + "bid": [ + { + "price": 0.5, + "adm": "some-test-ad", + "impid": "1", + "auid": 46, + "id": "1", + "h": 250, + "adomain": [ + "goodadvertiser.com" + ], + "crid": "11_222222", + "w": 300 + } + ], + "seat": "51" + } + ], + "bidid":"8141327771600527856", + "cur":"USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency":"USD", + "bids": [ + { + "bid": { + "price": 0.5, + "adm": "some-test-ad", + "impid": "1", + "id": "1", + "h": 250, + "adomain": [ + "goodadvertiser.com" + ], + "crid": "11_222222", + "w": 300 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/operaads/operaadstest/exemplary/video.json b/adapters/operaads/operaadstest/exemplary/video.json new file mode 100644 index 00000000000..a76bbe5ccf8 --- /dev/null +++ b/adapters/operaads/operaadstest/exemplary/video.json @@ -0,0 +1,173 @@ +{ + "mockBidRequest": { + "id": "test-video-request", + "imp": [ + { + "id": "test-video-imp", + "video": { + "w": 640, + "h": 480, + "mimes": [ + "video/mp4", + "video/x-flv" + ], + "minduration": 5, + "maxduration": 30, + "startdelay": 5, + "playbackmethod": [ + 1, + 3 + ], + "api": [ + 1, + 2 + ], + "protocols": [ + 2, + 3 + ], + "battr": [ + 13, + 14 + ], + "linearity": 1, + "placement": 2, + "minbitrate": 10, + "maxbitrate": 10 + }, + "ext": { + "bidder": { + "placementId":"s00000", + "endpointId":"ep00000", + "publisherId":"pub00000" + } + } + } + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", + "os": "android" + }, + "site": { + "id": "siteID", + "publisher": { + "id": "1234" + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://example.com/operaads/ortb/v2/pub00000?ep=ep00000", + "body": { + "id": "test-video-request", + "imp": [ + { + "id": "test-video-imp", + "tagid": "s00000", + "video": { + "w": 640, + "h": 480, + "mimes": [ + "video/mp4", + "video/x-flv" + ], + "minduration": 5, + "maxduration": 30, + "startdelay": 5, + "playbackmethod": [ + 1, + 3 + ], + "api": [ + 1, + 2 + ], + "protocols": [ + 2, + 3 + ], + "battr": [ + 13, + 14 + ], + "linearity": 1, + "placement": 2, + "minbitrate": 10, + "maxbitrate": 10 + }, + "ext": { + "bidder": { + "placementId":"s00000", + "endpointId":"ep00000", + "publisherId":"pub00000" + } + } + } + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.132 Safari/537.36", + "os": "android" + }, + "site": { + "id": "siteID", + "publisher": { + "id": "1234" + } + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-video-request", + "seatbid": [ + { + "seat": "958", + "bid": [ + { + "id": "7706636740145184841", + "impid": "test-video-imp", + "price": 0.5, + "adid": "29681110", + "adm": "some-test-ad", + "adomain": [ + "example.com" + ], + "crid": "29681110", + "h": 250, + "w": 300 + } + ] + } + ], + "bidid": "5778926625248726496", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "7706636740145184841", + "impid": "test-video-imp", + "price": 0.5, + "adid": "29681110", + "adm": "some-test-ad", + "adomain": [ + "example.com" + ], + "crid": "29681110", + "w": 300, + "h": 250 + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/operaads/operaadstest/supplemental/badrequest.json b/adapters/operaads/operaadstest/supplemental/badrequest.json new file mode 100644 index 00000000000..ff3fe071c4a --- /dev/null +++ b/adapters/operaads/operaadstest/supplemental/badrequest.json @@ -0,0 +1,84 @@ +{ + "mockBidRequest":{ + "id":"some-req-id", + "imp":[ + { + "id":"some-imp-id", + "native":{ + "request":"{\"native\":{\"ver\":\"1.1\",\"layout\":3,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":344,\"hmin\":194}},{\"id\":3,\"required\":1,\"img\":{\"type\":1,\"w\":128,\"wmin\":80,\"h\":128,\"hmin\":80}},{\"id\":4,\"required\":1,\"data\":{\"type\":2,\"len\":90}},{\"id\":6,\"data\":{\"type\":12,\"len\":15}}]}}", + "ver":"1.1" + }, + "ext":{ + "bidder":{ + "placementId":"s123456", + "endpointId":"ep19978", + "publisherId":"pub123" + } + } + } + ], + "site":{ + "domain":"example.com", + "page":"example.com" + }, + "device":{ + "ip":"152.193.6.74", + "os":"android" + }, + "user":{ + "id":"db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid":"8299345306627569435" + }, + "tmax":500 + }, + "httpcalls":[ + { + "expectedRequest":{ + "uri":"http://example.com/operaads/ortb/v2/pub123?ep=ep19978", + "body":{ + "id":"some-req-id", + "imp":[ + { + "id":"some-imp-id", + "tagid":"s123456", + "ext":{ + "bidder":{ + "placementId":"s123456", + "endpointId":"ep19978", + "publisherId":"pub123" + } + }, + "native":{ + "request":"{\"native\":{\"ver\":\"1.1\",\"layout\":3,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":344,\"hmin\":194}},{\"id\":3,\"required\":1,\"img\":{\"type\":1,\"w\":128,\"wmin\":80,\"h\":128,\"hmin\":80}},{\"id\":4,\"required\":1,\"data\":{\"type\":2,\"len\":90}},{\"id\":6,\"data\":{\"type\":12,\"len\":15}}]}}", + "ver":"1.1" + } + } + ], + "site":{ + "domain":"example.com", + "page":"example.com" + }, + "device":{ + "ip":"152.193.6.74", + "os":"android" + }, + "user":{ + "id":"db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid":"8299345306627569435" + }, + "tmax":500 + } + }, + "mockResponse":{ + "status":400, + "body":{} + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/operaads/operaadstest/supplemental/banner-size-miss.json b/adapters/operaads/operaadstest/supplemental/banner-size-miss.json new file mode 100644 index 00000000000..70ac350c2f0 --- /dev/null +++ b/adapters/operaads/operaadstest/supplemental/banner-size-miss.json @@ -0,0 +1,50 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "domain": "good.site", + "page": "https://good.site/url", + "publisher": { + "id": "test-publisher-id" + }, + "ext": { + "amp": 0 + } + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [] + }, + "secure": 1, + "ext": { + "bidder": { + "placementId": "s17890", + "endpointId": "ep19979", + "publisherId": "pub456" + } + } + } + ], + "device": { + "os": "android", + "ua": "test-user-agent", + "ip": "123.123.123.123", + "h": 700, + "w": 375 + }, + "at": 1, + "tmax": 200, + "test": 1, + "source": { + "tid": "283746293874293" + } + }, + "expectedMakeRequestsErrors": [ + { + "value": "Size information missing for banner", + "comparison": "literal" + } + ] +} diff --git a/adapters/operaads/operaadstest/supplemental/miss-native.json b/adapters/operaads/operaadstest/supplemental/miss-native.json new file mode 100644 index 00000000000..918bbc4ded5 --- /dev/null +++ b/adapters/operaads/operaadstest/supplemental/miss-native.json @@ -0,0 +1,137 @@ +{ + "mockBidRequest":{ + "id":"some-req-id", + "imp":[ + { + "id":"some-imp-id", + "native":{ + "request":"{\"ver\":\"1.1\",\"layout\":3,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":344,\"hmin\":194}},{\"id\":3,\"required\":1,\"img\":{\"type\":1,\"w\":128,\"wmin\":80,\"h\":128,\"hmin\":80}},{\"id\":4,\"required\":1,\"data\":{\"type\":2,\"len\":90}},{\"id\":6,\"data\":{\"type\":12,\"len\":15}}]}", + "ver":"1.1" + }, + "ext":{ + "bidder":{ + "placementId":"s123456", + "endpointId":"ep19978", + "publisherId":"pub123" + } + } + } + ], + "site":{ + "domain":"example.com", + "page":"example.com" + }, + "device":{ + "ip":"152.193.6.74", + "os":"android" + }, + "user":{ + "id":"db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid":"8299345306627569435" + }, + "tmax":500 + }, + "httpcalls":[ + { + "expectedRequest":{ + "uri":"http://example.com/operaads/ortb/v2/pub123?ep=ep19978", + "body":{ + "id":"some-req-id", + "imp":[ + { + "id":"some-imp-id", + "tagid":"s123456", + "ext":{ + "bidder":{ + "placementId":"s123456", + "endpointId":"ep19978", + "publisherId":"pub123" + } + }, + "native":{ + "request":"{\"native\":{\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}},{\"id\":2,\"img\":{\"hmin\":194,\"type\":3,\"wmin\":344},\"required\":1},{\"id\":3,\"img\":{\"h\":128,\"hmin\":80,\"type\":1,\"w\":128,\"wmin\":80},\"required\":1},{\"data\":{\"len\":90,\"type\":2},\"id\":4,\"required\":1},{\"data\":{\"len\":15,\"type\":12},\"id\":6}],\"layout\":3,\"ver\":\"1.1\"}}", + "ver":"1.1" + } + } + ], + "site":{ + "domain":"example.com", + "page":"example.com" + }, + "device":{ + "ip":"152.193.6.74", + "os":"android" + }, + "user":{ + "id":"db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid":"8299345306627569435" + }, + "tmax":500 + } + }, + "mockResponse":{ + "status":200, + "body":{ + "id":"some-req-id", + "seatbid":[ + { + "bid":[ + { + "id":"928185755156387460", + "impid":"some-imp-id", + "price":1, + "adid":"69595837", + "adm":"{\"assets\":[{\"id\": 2,\"img\":{\"url\":\"http://example.com/p/creative-image/5e/b6/de/c3/5eb6dec3-4854-4dcd-980a-347f36ab502e.jpg\",\"w\": 344,\"h\": 194}},{\"id\": 3,\"img\":{\"url\":\"http://example.com/p/creative-image/5e/b6/de/c3/5eb6dec3-4854-4dcd-980a-347f36ab502e.jpg\",\"w\": 100,\"h\": 100}} ,{\"id\": 1,\"title\":{\"text\":\"This is an example Prebid Native creative\"}},{\"id\": 4,\"data\":{\"value\":\"This is a Prebid Native Creative. There are many like it, but this one is mine.\"}},{\"id\": 6,\"data\":{\"value\":\"Please.\"}} ],\"link\":{\"url\":\"http://example.com/click?AAAAAAAA8D8AAAAAAADwPwAAAAAAAAAAAAAAAAAA8D8AAAAAAADwPwhdYz3ZyNFNG3fXpZUyLXNZ0o5aAAAAACrElgC-AwAAvgMAAAIAAAC98iUEeP4QAAAAAABVU0QAVVNEAAEAAQARIAAAAAABAgQCAAAAAAEAhBaSXgAAAAA./pp=${AUCTION_PRICE}/cnd=%21OwwGAQiGmooHEL3llyEY-PxDIAQoADoRZGVmYXVsdCNOWU0yOjQwMjM./bn=75922/test=1/referrer=prebid.org/clickenc=http%3A%2F%2Fprebid.org%2Fdev-docs%2Fshow-native-ads.html\"},\"imptrackers\":[\"http://example.com/openrtb_win?e=wqT_3QLFBqBFAwAAAwDWAAUBCNmku9QFEIi6jeuTm_LoTRib7t2u2tLMlnMqNgkAAAECCPA_EQEHEAAA8D8ZCQkIAAAhCQkI8D8pEQkAMQkJqAAAMKqI2wQ4vgdAvgdIAlC95ZchWPj8Q2AAaJFAeJLRBIABAYoBA1VTRJIFBvBQmAEBoAEBqAEBsAEAuAECwAEEyAEC0AEJ2AEA4AEB8AEAigI7dWYoJ2EnLCAxMzc2ODYwLCAxNTE5MzA5NDAxKTt1ZigncicsIDY5NTk1ODM3Nh4A8IqSAvUBIXRETkdfUWlHbW9vSEVMM2xseUVZQUNENF9FTXdBRGdBUUFSSXZnZFFxb2piQkZnQVlMTURhQUJ3QUhnQWdBRUFpQUVBa0FFQm1BRUJvQUVCcUFFRHNBRUF1UUVwaTRpREFBRHdQOEVCS1l1SWd3QUE4RF9KQVhfelYzek1zXzBfMlFFQUFBAQMkRHdQLUFCQVBVQgEOLEFKZ0NBS0FDQUxVQwUQBEwwCQjwTE1BQ0FNZ0NBT0FDQU9nQ0FQZ0NBSUFEQVpBREFKZ0RBYWdEaHBxS0I3b0RFV1JsWm1GMWJIUWpUbGxOTWpvME1ESXqaAjkhT3d3R0FRNvgA8E4tUHhESUFRb0FEb1JaR1ZtWVhWc2RDTk9XVTB5T2pRd01qTS7YAugH4ALH0wHqAgpwcmViaWQub3Jn8gIRCgZBRFZfSUQSBzEzNzY4NjDyARQMQ1BHXwEUNDM1MDMwOTjyAhEKBUNQARPwmQgxNDg0NzIzOIADAYgDAZADAJgDFKADAaoDAMADkBzIAwDYAwDgAwDoAwD4AwOABACSBAkvb3BlbnJ0YjKYBACiBAwxNTIuMTkzLjYuNzSoBJrMI7IEDAgAEAAYACAAMAA4ALgEAMAEAMgEANIEEWRlZmF1bHQjTllNMjo0MDIz2gQCCADgBADwBL3llyGIBQGYBQCgBf____8FA1ABqgULc29tZS1yZXEtaWTABQDJBQAFARTwP9IFCQkFC2QAAADYBQHgBQHwBd4C-gUECAAQAJAGAZgGAA..&s=08b1535744639c904684afe46e3c6c0e4786089f&test=1&referrer=prebid.org&pp=${AUCTION_PRICE}\"]}", + "adomain":[ + "example.com" + ], + "iurl":"http://example.com/cr?id=69595837", + "cid":"958", + "crid":"69595837", + "cat":[ + "IAB3-1" + ], + "ext":{ + + } + } + ], + "seat":"958" + } + ], + "bidid":"8141327771600527856", + "cur":"USD" + } + } + } + ], + "expectedBidResponses":[ + { + "currency":"USD", + "bids":[ + { + "bid":{ + "id":"928185755156387460", + "impid":"some-imp-id", + "price":1, + "adm":"{\"assets\":[{\"id\": 2,\"img\":{\"url\":\"http://example.com/p/creative-image/5e/b6/de/c3/5eb6dec3-4854-4dcd-980a-347f36ab502e.jpg\",\"w\": 344,\"h\": 194}},{\"id\": 3,\"img\":{\"url\":\"http://example.com/p/creative-image/5e/b6/de/c3/5eb6dec3-4854-4dcd-980a-347f36ab502e.jpg\",\"w\": 100,\"h\": 100}} ,{\"id\": 1,\"title\":{\"text\":\"This is an example Prebid Native creative\"}},{\"id\": 4,\"data\":{\"value\":\"This is a Prebid Native Creative. There are many like it, but this one is mine.\"}},{\"id\": 6,\"data\":{\"value\":\"Please.\"}} ],\"link\":{\"url\":\"http://example.com/click?AAAAAAAA8D8AAAAAAADwPwAAAAAAAAAAAAAAAAAA8D8AAAAAAADwPwhdYz3ZyNFNG3fXpZUyLXNZ0o5aAAAAACrElgC-AwAAvgMAAAIAAAC98iUEeP4QAAAAAABVU0QAVVNEAAEAAQARIAAAAAABAgQCAAAAAAEAhBaSXgAAAAA./pp=${AUCTION_PRICE}/cnd=%21OwwGAQiGmooHEL3llyEY-PxDIAQoADoRZGVmYXVsdCNOWU0yOjQwMjM./bn=75922/test=1/referrer=prebid.org/clickenc=http%3A%2F%2Fprebid.org%2Fdev-docs%2Fshow-native-ads.html\"},\"imptrackers\":[\"http://example.com/openrtb_win?e=wqT_3QLFBqBFAwAAAwDWAAUBCNmku9QFEIi6jeuTm_LoTRib7t2u2tLMlnMqNgkAAAECCPA_EQEHEAAA8D8ZCQkIAAAhCQkI8D8pEQkAMQkJqAAAMKqI2wQ4vgdAvgdIAlC95ZchWPj8Q2AAaJFAeJLRBIABAYoBA1VTRJIFBvBQmAEBoAEBqAEBsAEAuAECwAEEyAEC0AEJ2AEA4AEB8AEAigI7dWYoJ2EnLCAxMzc2ODYwLCAxNTE5MzA5NDAxKTt1ZigncicsIDY5NTk1ODM3Nh4A8IqSAvUBIXRETkdfUWlHbW9vSEVMM2xseUVZQUNENF9FTXdBRGdBUUFSSXZnZFFxb2piQkZnQVlMTURhQUJ3QUhnQWdBRUFpQUVBa0FFQm1BRUJvQUVCcUFFRHNBRUF1UUVwaTRpREFBRHdQOEVCS1l1SWd3QUE4RF9KQVhfelYzek1zXzBfMlFFQUFBAQMkRHdQLUFCQVBVQgEOLEFKZ0NBS0FDQUxVQwUQBEwwCQjwTE1BQ0FNZ0NBT0FDQU9nQ0FQZ0NBSUFEQVpBREFKZ0RBYWdEaHBxS0I3b0RFV1JsWm1GMWJIUWpUbGxOTWpvME1ESXqaAjkhT3d3R0FRNvgA8E4tUHhESUFRb0FEb1JaR1ZtWVhWc2RDTk9XVTB5T2pRd01qTS7YAugH4ALH0wHqAgpwcmViaWQub3Jn8gIRCgZBRFZfSUQSBzEzNzY4NjDyARQMQ1BHXwEUNDM1MDMwOTjyAhEKBUNQARPwmQgxNDg0NzIzOIADAYgDAZADAJgDFKADAaoDAMADkBzIAwDYAwDgAwDoAwD4AwOABACSBAkvb3BlbnJ0YjKYBACiBAwxNTIuMTkzLjYuNzSoBJrMI7IEDAgAEAAYACAAMAA4ALgEAMAEAMgEANIEEWRlZmF1bHQjTllNMjo0MDIz2gQCCADgBADwBL3llyGIBQGYBQCgBf____8FA1ABqgULc29tZS1yZXEtaWTABQDJBQAFARTwP9IFCQkFC2QAAADYBQHgBQHwBd4C-gUECAAQAJAGAZgGAA..&s=08b1535744639c904684afe46e3c6c0e4786089f&test=1&referrer=prebid.org&pp=${AUCTION_PRICE}\"]}", + "adid":"69595837", + "adomain":[ + "example.com" + ], + "iurl":"http://example.com/cr?id=69595837", + "cid":"958", + "crid":"69595837", + "cat":[ + "IAB3-1" + ], + "ext":{ + + } + }, + "type":"native" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/operaads/operaadstest/supplemental/missing-device.json b/adapters/operaads/operaadstest/supplemental/missing-device.json new file mode 100644 index 00000000000..3ba01d81632 --- /dev/null +++ b/adapters/operaads/operaadstest/supplemental/missing-device.json @@ -0,0 +1,33 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id-1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": {} + } + } + ], + "site": { + "id": "siteID", + "publisher": { + "id": "1234" + } + } + }, + "expectedMakeRequestsErrors": [ + { + "value": "Impression is missing device OS information", + "comparison": "literal" + } + ] +} diff --git a/adapters/operaads/operaadstest/supplemental/nocontent.json b/adapters/operaads/operaadstest/supplemental/nocontent.json new file mode 100644 index 00000000000..d6baf35d4a6 --- /dev/null +++ b/adapters/operaads/operaadstest/supplemental/nocontent.json @@ -0,0 +1,82 @@ +{ + "mockBidRequest": { + "id": "some-req-id", + "imp": [ + { + "id": "some-imp-id", + "native": { + "request": "{\"native\":{\"ver\":\"1.1\",\"layout\":3,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":344,\"hmin\":194}},{\"id\":3,\"required\":1,\"img\":{\"type\":1,\"w\":128,\"wmin\":80,\"h\":128,\"hmin\":80}},{\"id\":4,\"required\":1,\"data\":{\"type\":2,\"len\":90}},{\"id\":6,\"data\":{\"type\":12,\"len\":15}}]}}", + "ver": "1.1" + }, + "ext": { + "bidder": { + "placementId": "s123456", + "endpointId": "ep19978", + "publisherId": "pub123" + } + } + } + ], + "site": { + "domain": "example.com", + "page": "example.com" + }, + "device": { + "ip": "152.193.6.74", + "os": "android" + }, + "user": { + "id": "db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid": "8299345306627569435" + }, + "tmax": 500 + }, + "httpcalls": [ + { + "expectedRequest": { + "uri": "http://example.com/operaads/ortb/v2/pub123?ep=ep19978", + "body": { + "id": "some-req-id", + "imp": [ + { + "id": "some-imp-id", + "tagid": "s123456", + "ext": { + "bidder": { + "placementId": "s123456", + "endpointId": "ep19978", + "publisherId": "pub123" + } + }, + "native": { + "request": "{\"native\":{\"ver\":\"1.1\",\"layout\":3,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":344,\"hmin\":194}},{\"id\":3,\"required\":1,\"img\":{\"type\":1,\"w\":128,\"wmin\":80,\"h\":128,\"hmin\":80}},{\"id\":4,\"required\":1,\"data\":{\"type\":2,\"len\":90}},{\"id\":6,\"data\":{\"type\":12,\"len\":15}}]}}", + "ver": "1.1" + } + } + ], + "site": { + "domain": "example.com", + "page": "example.com" + }, + "device": { + "ip": "152.193.6.74", + "os": "android" + }, + "user": { + "id": "db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid": "8299345306627569435" + }, + "tmax": 500 + } + }, + "mockResponse": { + "status": 204, + "body": {} + } + } + ], + "expectedBidResponses": [ + ], + "expectedMakeBidsErrors": [ + ] +} \ No newline at end of file diff --git a/adapters/operaads/operaadstest/supplemental/unexcept-statuscode.json b/adapters/operaads/operaadstest/supplemental/unexcept-statuscode.json new file mode 100644 index 00000000000..a6c8c5052ae --- /dev/null +++ b/adapters/operaads/operaadstest/supplemental/unexcept-statuscode.json @@ -0,0 +1,84 @@ +{ + "mockBidRequest":{ + "id":"some-req-id", + "imp":[ + { + "id":"some-imp-id", + "native":{ + "request":"{\"native\":{\"ver\":\"1.1\",\"layout\":3,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":344,\"hmin\":194}},{\"id\":3,\"required\":1,\"img\":{\"type\":1,\"w\":128,\"wmin\":80,\"h\":128,\"hmin\":80}},{\"id\":4,\"required\":1,\"data\":{\"type\":2,\"len\":90}},{\"id\":6,\"data\":{\"type\":12,\"len\":15}}]}}", + "ver":"1.1" + }, + "ext":{ + "bidder":{ + "placementId":"s123456", + "endpointId":"ep19978", + "publisherId":"pub123" + } + } + } + ], + "site":{ + "domain":"example.com", + "page":"example.com" + }, + "device":{ + "ip":"152.193.6.74", + "os":"android" + }, + "user":{ + "id":"db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid":"8299345306627569435" + }, + "tmax":500 + }, + "httpcalls":[ + { + "expectedRequest":{ + "uri":"http://example.com/operaads/ortb/v2/pub123?ep=ep19978", + "body":{ + "id":"some-req-id", + "imp":[ + { + "id":"some-imp-id", + "tagid":"s123456", + "ext":{ + "bidder":{ + "placementId":"s123456", + "endpointId":"ep19978", + "publisherId":"pub123" + } + }, + "native":{ + "request":"{\"native\":{\"ver\":\"1.1\",\"layout\":3,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":90}},{\"id\":2,\"required\":1,\"img\":{\"type\":3,\"wmin\":344,\"hmin\":194}},{\"id\":3,\"required\":1,\"img\":{\"type\":1,\"w\":128,\"wmin\":80,\"h\":128,\"hmin\":80}},{\"id\":4,\"required\":1,\"data\":{\"type\":2,\"len\":90}},{\"id\":6,\"data\":{\"type\":12,\"len\":15}}]}}", + "ver":"1.1" + } + } + ], + "site":{ + "domain":"example.com", + "page":"example.com" + }, + "device":{ + "ip":"152.193.6.74", + "os":"android" + }, + "user":{ + "id":"db089de9-a62e-4861-a881-0ff15e052516", + "buyeruid":"8299345306627569435" + }, + "tmax":500 + } + }, + "mockResponse":{ + "status":205, + "body":{} + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 205. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/operaads/params_test.go b/adapters/operaads/params_test.go new file mode 100644 index 00000000000..e998127b001 --- /dev/null +++ b/adapters/operaads/params_test.go @@ -0,0 +1,54 @@ +package operaads + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/openrtb_ext" +) + +// This file actually intends to test static/bidder-params/operaads.json +// +// These also validate the format of the external API: request.imp[i].ext.operaads + +// TestValidParams makes sure that the operaads 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.BidderOperaads, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected operaads params: %s", validParam) + } + } +} + +// TestInvalidParams makes sure that the operaads 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.BidderOpenx, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{"placementId": "s123", "endpointId": "ep12345", "publisherId": "pub12345"}`, +} + +var invalidParams = []string{ + `{"placementId": "s123"}`, + `{"endpointId": "ep12345"}`, + `{"publisherId": "pub12345"}`, + `{"placementId": "s123", "endpointId": "ep12345"}`, + `{"placementId": "s123", "publisherId": "pub12345"}`, + `{"endpointId": "ep12345", "publisherId": "pub12345"}`, + `{"placementId": "", "endpointId": "", "publisherId": ""}`, +} diff --git a/adapters/operaads/usersync.go b/adapters/operaads/usersync.go new file mode 100644 index 00000000000..aae6fb600e3 --- /dev/null +++ b/adapters/operaads/usersync.go @@ -0,0 +1,11 @@ +package operaads + +import ( + "github.com/prebid/prebid-server/adapters" + "github.com/prebid/prebid-server/usersync" + "text/template" +) + +func NewOperaadsSyncer(temp *template.Template) usersync.Usersyncer { + return adapters.NewSyncer("operaads", temp, adapters.SyncTypeRedirect) +} diff --git a/adapters/operaads/usersync_test.go b/adapters/operaads/usersync_test.go new file mode 100644 index 00000000000..e9b402ac465 --- /dev/null +++ b/adapters/operaads/usersync_test.go @@ -0,0 +1,33 @@ +package operaads + +import ( + "github.com/prebid/prebid-server/privacy/ccpa" + "github.com/prebid/prebid-server/privacy/gdpr" + "testing" + "text/template" + + "github.com/prebid/prebid-server/privacy" + "github.com/stretchr/testify/assert" +) + +func TestOperaadsSyncer(t *testing.T) { + syncURL := "https://t-odx.op-mobile.opera.com/pbs/sync?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&r=localhost%2Fsetuid%3Fbidder%3Doperaads%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24%7BUID%7D" + syncURLTemplate := template.Must( + template.New("sync-template").Parse(syncURL), + ) + + syncer := NewOperaadsSyncer(syncURLTemplate) + syncInfo, err := syncer.GetUsersyncInfo(privacy.Policies{ + GDPR: gdpr.Policy{ + Signal: "A", + Consent: "B", + }, + CCPA: ccpa.Policy{ + Consent: "C", + }}) + + assert.NoError(t, err) + assert.Equal(t, "https://t-odx.op-mobile.opera.com/pbs/sync?gdpr=A&gdpr_consent=B&r=localhost%2Fsetuid%3Fbidder%3Doperaads%26gdpr%3DA%26gdpr_consent%3DB%26uid%3D%24%7BUID%7D", syncInfo.URL) + assert.Equal(t, "redirect", syncInfo.Type) + assert.Equal(t, false, syncInfo.SupportCORS) +} diff --git a/config/config.go b/config/config.go index 36ec4dc04e5..a1056c72fe4 100644 --- a/config/config.go +++ b/config/config.go @@ -623,6 +623,7 @@ func (cfg *Configuration) setDerivedDefaults() { setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderNinthDecimal, "https://rtb.ninthdecimal.com/xp/user-sync?acctid={aid}&&redirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dninthdecimal%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24UID") setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderNoBid, "https://ads.servenobid.com/getsync?tek=pbs&ver=1&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dnobid%26uid%3D%24UID") setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderOpenx, "https://rtb.openx.net/sync/prebid?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&r="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dopenx%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24%7BUID%7D") + setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderOperaads, "https://t.adx.opera.com/pbs/sync?gdpr={{.GDPR}}&us_privacy={{.USPrivacy}}&gdpr_consent={{.GDPRConsent}}&r="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Doperaads%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24%7BUID%7D") setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderOneTag, "https://onetag-sys.com/usync/?redir="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Donetag%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24%7BUSER_TOKEN%7D") setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderOutbrain, "https://prebidtest.zemanta.com/usersync/prebidtest?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&cb="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Doutbrain%26uid%3D__ZUID__") setDefaultUsersync(cfg.Adapters, openrtb_ext.BidderPubmatic, "https://ads.pubmatic.com/AdServer/js/user_sync.html?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&predirect="+url.QueryEscape(externalURL)+"%2Fsetuid%3Fbidder%3Dpubmatic%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D") @@ -880,6 +881,7 @@ func SetupViper(v *viper.Viper, filename string) { v.SetDefault("adapters.nobid.endpoint", "https://ads.servenobid.com/ortb_adreq?tek=pbs&ver=1") v.SetDefault("adapters.onetag.endpoint", "https://prebid-server.onetag-sys.com/prebid-server/{{.PublisherID}}") v.SetDefault("adapters.openx.endpoint", "http://rtb.openx.net/prebid") + v.SetDefault("adapters.operaads.endpoint", "https://s.adx.opera.com/ortb/v2/{{.PublisherID}}?ep={{.AccountID}}") v.SetDefault("adapters.orbidder.endpoint", "https://orbidder.otto.de/openrtb2") v.SetDefault("adapters.outbrain.endpoint", "https://prebidtest.zemanta.com/api/bidder/prebidtest/bid/") v.SetDefault("adapters.pangle.disabled", true) diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 0120005b6c7..6f90f6ad549 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -72,6 +72,7 @@ import ( "github.com/prebid/prebid-server/adapters/nobid" "github.com/prebid/prebid-server/adapters/onetag" "github.com/prebid/prebid-server/adapters/openx" + "github.com/prebid/prebid-server/adapters/operaads" "github.com/prebid/prebid-server/adapters/orbidder" "github.com/prebid/prebid-server/adapters/outbrain" "github.com/prebid/prebid-server/adapters/pangle" @@ -187,6 +188,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderNoBid: nobid.Builder, openrtb_ext.BidderOneTag: onetag.Builder, openrtb_ext.BidderOpenx: openx.Builder, + openrtb_ext.BidderOperaads: operaads.Builder, openrtb_ext.BidderOrbidder: orbidder.Builder, openrtb_ext.BidderOutbrain: outbrain.Builder, openrtb_ext.BidderPangle: pangle.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 2fb50cf391a..cf94fbe429d 100755 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -145,6 +145,7 @@ const ( BidderNoBid BidderName = "nobid" BidderOneTag BidderName = "onetag" BidderOpenx BidderName = "openx" + BidderOperaads BidderName = "operaads" BidderOrbidder BidderName = "orbidder" BidderOutbrain BidderName = "outbrain" BidderPangle BidderName = "pangle" @@ -259,6 +260,7 @@ func CoreBidderNames() []BidderName { BidderNoBid, BidderOneTag, BidderOpenx, + BidderOperaads, BidderOrbidder, BidderOutbrain, BidderPangle, diff --git a/openrtb_ext/imp_operaads.go b/openrtb_ext/imp_operaads.go new file mode 100644 index 00000000000..99ccd7c431b --- /dev/null +++ b/openrtb_ext/imp_operaads.go @@ -0,0 +1,7 @@ +package openrtb_ext + +type ImpExtOperaads struct { + PlacementID string `json:"placementId"` + EndpointID string `json:"endpointId"` + PublisherID string `json:"publisherId"` +} diff --git a/static/bidder-info/operaads.yaml b/static/bidder-info/operaads.yaml new file mode 100644 index 00000000000..b95d81155c1 --- /dev/null +++ b/static/bidder-info/operaads.yaml @@ -0,0 +1,14 @@ +maintainer: + email: adtech-prebid-group@opera.com +modifyingVastXmlAllowed: true +capabilities: + app: + mediaTypes: + - banner + - video + - native + site: + mediaTypes: + - banner + - video + - native \ No newline at end of file diff --git a/static/bidder-params/operaads.json b/static/bidder-params/operaads.json new file mode 100644 index 00000000000..5095c5b2d2b --- /dev/null +++ b/static/bidder-params/operaads.json @@ -0,0 +1,28 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "description": "A schema which validates params accepted by the OperaAds adapter", + "properties": { + "placementId": { + "description": "Placement ID", + "type": "string", + "minLength": 1 + }, + "endpointId": { + "description": "Endpoint ID", + "type": "string", + "minLength": 1 + }, + "publisherId": { + "description": "Publisher ID", + "type": "string", + "minLength": 1 + } + }, + "required": [ + "placementId", + "endpointId", + "publisherId" + ], + "title": "OperaAds Adapter Params", + "type": "object" +} \ No newline at end of file diff --git a/usersync/usersyncers/syncer.go b/usersync/usersyncers/syncer.go index 3dc93c3bfc8..2a22e87ba11 100644 --- a/usersync/usersyncers/syncer.go +++ b/usersync/usersyncers/syncer.go @@ -1,6 +1,7 @@ package usersyncers import ( + "github.com/prebid/prebid-server/adapters/operaads" "strings" "text/template" @@ -159,6 +160,7 @@ func NewSyncerMap(cfg *config.Configuration) map[openrtb_ext.BidderName]usersync insertIntoMap(cfg, syncers, openrtb_ext.BidderOneTag, onetag.NewSyncer) insertIntoMap(cfg, syncers, openrtb_ext.BidderOutbrain, outbrain.NewOutbrainSyncer) insertIntoMap(cfg, syncers, openrtb_ext.BidderOpenx, openx.NewOpenxSyncer) + insertIntoMap(cfg, syncers, openrtb_ext.BidderOperaads, operaads.NewOperaadsSyncer) insertIntoMap(cfg, syncers, openrtb_ext.BidderPubmatic, pubmatic.NewPubmaticSyncer) insertIntoMap(cfg, syncers, openrtb_ext.BidderPulsepoint, pulsepoint.NewPulsepointSyncer) insertIntoMap(cfg, syncers, openrtb_ext.BidderRhythmone, rhythmone.NewRhythmoneSyncer) diff --git a/usersync/usersyncers/syncer_test.go b/usersync/usersyncers/syncer_test.go index 79bf84e329e..18f3a24d1dc 100755 --- a/usersync/usersyncers/syncer_test.go +++ b/usersync/usersyncers/syncer_test.go @@ -71,6 +71,7 @@ func TestNewSyncerMap(t *testing.T) { string(openrtb_ext.BidderNoBid): syncConfig, string(openrtb_ext.BidderOneTag): syncConfig, string(openrtb_ext.BidderOpenx): syncConfig, + string(openrtb_ext.BidderOperaads): syncConfig, string(openrtb_ext.BidderOutbrain): syncConfig, string(openrtb_ext.BidderPubmatic): syncConfig, string(openrtb_ext.BidderPulsepoint): syncConfig,