diff --git a/adapters/aax/aax.go b/adapters/aax/aax.go new file mode 100644 index 00000000000..1a15ebd3a4f --- /dev/null +++ b/adapters/aax/aax.go @@ -0,0 +1,147 @@ +package aax + +import ( + "encoding/json" + "fmt" + "net/http" + "net/url" + + "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 { + endpoint string +} + +type aaxResponseBidExt struct { + AdCodeType string `json:"adCodeType"` +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + var errs []error + + reqJson, err := json.Marshal(request) + if err != nil { + errs = append(errs, err) + return nil, errs + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + + return []*adapters.RequestData{{ + Method: "POST", + Uri: a.endpoint, + Body: reqJson, + Headers: headers, + }}, errs +} + +func (a *adapter) MakeBids(internalRequest *openrtb2.BidRequest, externalRequest *adapters.RequestData, response *adapters.ResponseData) (*adapters.BidderResponse, []error) { + var errs []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 bidResp openrtb2.BidResponse + + if err := json.Unmarshal(response.Body, &bidResp); err != nil { + return nil, []error{err} + } + + bidResponse := adapters.NewBidderResponse() + + for _, seatBid := range bidResp.SeatBid { + for i := range seatBid.Bid { + bidType, err := getMediaTypeForImp(seatBid.Bid[i], internalRequest.Imp) + if err != nil { + errs = append(errs, err) + } else { + b := &adapters.TypedBid{ + Bid: &seatBid.Bid[i], + BidType: bidType, + } + bidResponse.Bids = append(bidResponse.Bids, b) + } + } + } + return bidResponse, errs +} + +// Builder builds a new instance of the Aax adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) { + url := buildEndpoint(config.Endpoint, config.ExtraAdapterInfo) + return &adapter{ + endpoint: url, + }, nil +} + +func getMediaTypeForImp(bid openrtb2.Bid, imps []openrtb2.Imp) (openrtb_ext.BidType, error) { + var bidExt aaxResponseBidExt + err := json.Unmarshal(bid.Ext, &bidExt) + if err == nil { + switch bidExt.AdCodeType { + case "banner": + return openrtb_ext.BidTypeBanner, nil + case "native": + return openrtb_ext.BidTypeNative, nil + case "video": + return openrtb_ext.BidTypeVideo, nil + } + } + + var mediaType openrtb_ext.BidType + var typeCnt = 0 + for _, imp := range imps { + if imp.ID == bid.ImpID { + if imp.Banner != nil { + typeCnt += 1 + mediaType = openrtb_ext.BidTypeBanner + } + if imp.Native != nil { + typeCnt += 1 + mediaType = openrtb_ext.BidTypeNative + } + if imp.Video != nil { + typeCnt += 1 + mediaType = openrtb_ext.BidTypeVideo + } + } + } + if typeCnt == 1 { + return mediaType, nil + } + return mediaType, fmt.Errorf("unable to fetch mediaType in multi-format: %s", bid.ImpID) +} + +func buildEndpoint(aaxUrl, hostUrl string) string { + + if len(hostUrl) == 0 { + return aaxUrl + } + urlObject, err := url.Parse(aaxUrl) + if err != nil { + return aaxUrl + } + values := urlObject.Query() + values.Add("src", hostUrl) + urlObject.RawQuery = values.Encode() + return urlObject.String() +} diff --git a/adapters/aax/aax_test.go b/adapters/aax/aax_test.go new file mode 100644 index 00000000000..7ff6e610f20 --- /dev/null +++ b/adapters/aax/aax_test.go @@ -0,0 +1,30 @@ +package aax + +import ( + "github.com/stretchr/testify/assert" + "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.BidderAax, config.Adapter{ + Endpoint: "https://example.aax.media/rtb/prebid", + ExtraAdapterInfo: "http://localhost:8080/extrnal_url", + }) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "aaxtest", bidder) +} + +func TestEndpointTemplateMalformed(t *testing.T) { + _, buildErr := Builder(openrtb_ext.BidderAax, config.Adapter{ + Endpoint: "{{Malformed}}"}) + + assert.Nil(t, buildErr) +} diff --git a/adapters/aax/aaxtest/exemplary/multi-format.json b/adapters/aax/aaxtest/exemplary/multi-format.json new file mode 100644 index 00000000000..493f268ccf5 --- /dev/null +++ b/adapters/aax/aaxtest/exemplary/multi-format.json @@ -0,0 +1,80 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "1", + "banner": { + "format": [ + { + "w": 320, + "h": 50 + } + ] + }, + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 5 + ], + "w": 320, + "h": 480 + }, + "ext": { + "bidder": { + "cid": "TCID", + "crid": "1234" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.aax.media/rtb/prebid?src=http%3A%2F%2Flocalhost%3A8080%2Fextrnal_url", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "1", + "banner": { + "format": [ + { + "w": 320, + "h": 50 + } + ] + }, + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 5 + ], + "w": 320, + "h": 480 + }, + "ext": { + "bidder": { + "cid": "TCID", + "crid": "1234" + } + } + } + ] + } + }, + "mockResponse": { + "status": 204, + "body": "" + } + } + ], + "expectedBidResponses": [] +} \ No newline at end of file diff --git a/adapters/aax/aaxtest/exemplary/multi-imps.json b/adapters/aax/aaxtest/exemplary/multi-imps.json new file mode 100644 index 00000000000..9ad02293e95 --- /dev/null +++ b/adapters/aax/aaxtest/exemplary/multi-imps.json @@ -0,0 +1,129 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "1", + "banner": { + "format": [ + { + "w": 320, + "h": 50 + } + ] + }, + "ext": { + "bidder": { + "cid": "TCID", + "crid": "1234" + } + } + }, + { + "id": "2", + "banner": { + "format": [ + { + "w": 300, + "h": 50 + } + ] + }, + "ext": { + "bidder": { + "cid": "TCID", + "crid": "1234" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.aax.media/rtb/prebid?src=http%3A%2F%2Flocalhost%3A8080%2Fextrnal_url", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "1", + "banner": { + "format": [ + { + "w": 320, + "h": 50 + } + ] + }, + "ext": { + "bidder": { + "cid": "TCID", + "crid": "1234" + } + } + }, + { + "id": "2", + "banner": { + "format": [ + { + "w": 300, + "h": 50 + } + ] + }, + "ext": { + "bidder": { + "cid": "TCID", + "crid": "1234" + } + } + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "aax", + "bid": [ + { + "id": "test-bid-id", + "impid": "1", + "price": 1.50, + "adm": "some-test-ad", + "crid": "test-crid", + "h": 50, + "w": 320 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "1", + "price": 1.50, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 320, + "h": 50 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/aax/aaxtest/exemplary/no-bid.json b/adapters/aax/aaxtest/exemplary/no-bid.json new file mode 100644 index 00000000000..2ffbdac7e93 --- /dev/null +++ b/adapters/aax/aaxtest/exemplary/no-bid.json @@ -0,0 +1,58 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "cid": "TCID", + "crid": "1234" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.aax.media/rtb/prebid?src=http%3A%2F%2Flocalhost%3A8080%2Fextrnal_url", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "cid": "TCID", + "crid": "1234" + } + } + } + ] + } + }, + "mockResponse": { + "status": 204, + "body": {} + } + } + ], + "expectedBidResponses": [] +} \ No newline at end of file diff --git a/adapters/aax/aaxtest/exemplary/optional-params.json b/adapters/aax/aaxtest/exemplary/optional-params.json new file mode 100644 index 00000000000..37458ed6d0e --- /dev/null +++ b/adapters/aax/aaxtest/exemplary/optional-params.json @@ -0,0 +1,60 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "cid": "TCID", + "crid": "1234", + "tagid_src": "ext" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.aax.media/rtb/prebid?src=http%3A%2F%2Flocalhost%3A8080%2Fextrnal_url", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "1", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": { + "cid": "TCID", + "crid": "1234", + "tagid_src": "ext" + } + } + } + ] + } + }, + "mockResponse": { + "status": 204, + "body": {} + } + } + ], + "expectedBidResponses": [] +} \ No newline at end of file diff --git a/adapters/aax/aaxtest/exemplary/simple-banner.json b/adapters/aax/aaxtest/exemplary/simple-banner.json new file mode 100644 index 00000000000..7e8c0fce1d8 --- /dev/null +++ b/adapters/aax/aaxtest/exemplary/simple-banner.json @@ -0,0 +1,95 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "1", + "banner": { + "format": [ + { + "w": 320, + "h": 50 + } + ] + }, + "ext": { + "bidder": { + "cid": "TCID", + "crid": "1234" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.aax.media/rtb/prebid?src=http%3A%2F%2Flocalhost%3A8080%2Fextrnal_url", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "1", + "banner": { + "format": [ + { + "w": 320, + "h": 50 + } + ] + }, + "ext": { + "bidder": { + "cid": "TCID", + "crid": "1234" + } + } + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "aax", + "bid": [ + { + "id": "test-bid-id", + "impid": "1", + "price": 1.50, + "adm": "some-test-ad", + "crid": "test-crid", + "h": 50, + "w": 320 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "1", + "price": 1.50, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 320, + "h": 50 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/aax/aaxtest/exemplary/simple-video.json b/adapters/aax/aaxtest/exemplary/simple-video.json new file mode 100644 index 00000000000..6ee8d3d8bfe --- /dev/null +++ b/adapters/aax/aaxtest/exemplary/simple-video.json @@ -0,0 +1,101 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "1", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 5 + ], + "w": 320, + "h": 480 + }, + "ext": { + "bidder": { + "cid": "TCID", + "crid": "1234" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.aax.media/rtb/prebid?src=http%3A%2F%2Flocalhost%3A8080%2Fextrnal_url", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "1", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 5 + ], + "w": 320, + "h": 480 + }, + "ext": { + "bidder": { + "cid": "TCID", + "crid": "1234" + } + } + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "aax", + "bid": [ + { + "id": "test-bid-id", + "impid": "1", + "price": 2.50, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 320, + "h": 480 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-bid-id", + "impid": "1", + "price": 2.50, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 320, + "h": 480 + }, + "type": "video" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/aax/aaxtest/supplemental/invalid-req-400-status-code-bad-request.json b/adapters/aax/aaxtest/supplemental/invalid-req-400-status-code-bad-request.json new file mode 100644 index 00000000000..276e0fc381a --- /dev/null +++ b/adapters/aax/aaxtest/supplemental/invalid-req-400-status-code-bad-request.json @@ -0,0 +1,97 @@ +{ + "mockBidRequest": { + "id": "some-request-id", + "tmax": 1000, + "user": { + "buyeruid": "0000-000-000-0000" + }, + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "123456789" + }, + "imp": [ + { + "id": "some-impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "ext": { + "bidder": { + "cid": "TCID", + "crid": "1234" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.aax.media/rtb/prebid?src=http%3A%2F%2Flocalhost%3A8080%2Fextrnal_url", + "body": { + "id": "some-request-id", + "imp": [ + { + "id": "some-impression-id", + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "ext": { + "bidder": { + "cid": "TCID", + "crid": "1234" + } + } + } + ], + "app": { + "publisher": { + "id": "123456789" + }, + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "123456789" + }, + "user": { + "buyeruid": "0000-000-000-0000" + }, + "tmax": 1000 + } + }, + "mockResponse": { + "status": 400 + } + } + ], + "expectedBidResponses": [], + "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/aax/aaxtest/supplemental/invalid-resp-diff-imp-id.json b/adapters/aax/aaxtest/supplemental/invalid-resp-diff-imp-id.json new file mode 100644 index 00000000000..c415c274fcf --- /dev/null +++ b/adapters/aax/aaxtest/supplemental/invalid-resp-diff-imp-id.json @@ -0,0 +1,125 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "cid": "TCID", + "crid": "1234" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com", + "publisher": { + "domain": "example.com" + }, + "ext": { + "amp": 0 + } + }, + "device": { + "ua": "userAgent", + "ip": "193.168.244.1" + }, + "at": 1, + "tmax": 5000, + "cur": [ + "USD" + ], + "regs": { + "ext": { + "gdpr": 0 + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.aax.media/rtb/prebid?src=http%3A%2F%2Flocalhost%3A8080%2Fextrnal_url", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "cid": "TCID", + "crid": "1234" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com", + "publisher": { + "domain": "example.com" + }, + "ext": { + "amp": 0 + } + }, + "device": { + "ua": "userAgent", + "ip": "193.168.244.1" + }, + "at": 1, + "tmax": 5000, + "cur": [ + "USD" + ], + "regs": { + "ext": { + "gdpr": 0 + } + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "tid", + "seatbid": [ + { + "seat": "aax", + "bid": [ + { + "id": "randomid", + "impid": "some-other-imp-id", + "price": 0.500000, + "adid": "12345678", + "adm": "some-test-ad", + "cid": "987", + "crid": "12345678", + "h": 250, + "w": 300 + } + ] + } + ], + "bidid": "bid01" + } + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "unable to fetch mediaType in multi-format: some-other-imp-id", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/aax/aaxtest/supplemental/invalid-resp-multi-imp-type.json b/adapters/aax/aaxtest/supplemental/invalid-resp-multi-imp-type.json new file mode 100644 index 00000000000..23aa0ae6760 --- /dev/null +++ b/adapters/aax/aaxtest/supplemental/invalid-resp-multi-imp-type.json @@ -0,0 +1,151 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "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": { + "cid": "TCID", + "crid": "1234" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com", + "publisher": { + "domain": "example.com" + }, + "ext": { + "amp": 0 + } + }, + "device": { + "ua": "userAgent", + "ip": "193.168.244.1" + }, + "at": 1, + "tmax": 5000, + "cur": [ + "USD" + ], + "regs": { + "ext": { + "gdpr": 0 + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.aax.media/rtb/prebid?src=http%3A%2F%2Flocalhost%3A8080%2Fextrnal_url", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "video": { + "mimes": [ + "video/mp4" + ], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "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": { + "cid": "TCID", + "crid": "1234" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com", + "publisher": { + "domain": "example.com" + }, + "ext": { + "amp": 0 + } + }, + "device": { + "ua": "userAgent", + "ip": "193.168.244.1" + }, + "at": 1, + "tmax": 5000, + "cur": [ + "USD" + ], + "regs": { + "ext": { + "gdpr": 0 + } + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "tid", + "seatbid": [ + { + "seat": "aax", + "bid": [ + { + "id": "randomid", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "12345678", + "adm": "some-test-ad", + "cid": "987", + "crid": "12345678", + "h": 250, + "w": 300 + } + ] + } + ], + "bidid": "bid01" + } + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "unable to fetch mediaType in multi-format: test-imp-id", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/aax/aaxtest/supplemental/valid-req-200-bid-response-from-aax.json b/adapters/aax/aaxtest/supplemental/valid-req-200-bid-response-from-aax.json new file mode 100644 index 00000000000..bad8743488c --- /dev/null +++ b/adapters/aax/aaxtest/supplemental/valid-req-200-bid-response-from-aax.json @@ -0,0 +1,139 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "cid": "TCID", + "crid": "1234" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com", + "publisher": { + "domain": "example.com" + }, + "ext": { + "amp": 0 + } + }, + "device": { + "ua": "userAgent", + "ip": "193.168.244.1" + }, + "at": 1, + "tmax": 5000, + "cur": [ + "USD" + ], + "regs": { + "ext": { + "gdpr": 0 + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.aax.media/rtb/prebid?src=http%3A%2F%2Flocalhost%3A8080%2Fextrnal_url", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "w": 300, + "h": 250 + }, + "ext": { + "bidder": { + "cid": "TCID", + "crid": "1234" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com", + "publisher": { + "domain": "example.com" + }, + "ext": { + "amp": 0 + } + }, + "device": { + "ua": "userAgent", + "ip": "193.168.244.1" + }, + "at": 1, + "tmax": 5000, + "cur": [ + "USD" + ], + "regs": { + "ext": { + "gdpr": 0 + } + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "tid", + "seatbid": [ + { + "seat": "aax", + "bid": [ + { + "id": "randomid", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "12345678", + "adm": "some-test-ad", + "cid": "987", + "crid": "12345678", + "h": 250, + "w": 300 + } + ] + } + ], + "bidid": "bid01" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "randomid", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "12345678", + "adm": "some-test-ad", + "cid": "987", + "crid": "12345678", + "h": 250, + "w": 300 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/aax/aaxtest/supplemental/valid-req-204-response-from-aax.json b/adapters/aax/aaxtest/supplemental/valid-req-204-response-from-aax.json new file mode 100644 index 00000000000..db8219029ff --- /dev/null +++ b/adapters/aax/aaxtest/supplemental/valid-req-204-response-from-aax.json @@ -0,0 +1,66 @@ +{ + "mockBidRequest": { + "app": { + "bundle": "com.example.app" + }, + "id": "req-id", + "device": { + "ifa": "9d8fe0a9-c0dd-4482-b16b-5709b00c608d", + "ip": "1.1.1.1", + "ua": "Mozilla/5.0 (Linux; Android 8.0.0; SM-G960F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36" + }, + "imp": [ + { + "ext": { + "bidder": { + "cid": "TCID", + "crid": "1234" + } + }, + "banner": { + "w": 320, + "h": 50 + }, + "id": "imp-id" + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://example.aax.media/rtb/prebid?src=http%3A%2F%2Flocalhost%3A8080%2Fextrnal_url", + "body": { + "app": { + "bundle": "com.example.app" + }, + "id": "req-id", + "device": { + "ifa": "9d8fe0a9-c0dd-4482-b16b-5709b00c608d", + "ip": "1.1.1.1", + "ua": "Mozilla/5.0 (Linux; Android 8.0.0; SM-G960F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36" + }, + "imp": [ + { + "ext": { + "bidder": { + "cid": "TCID", + "crid": "1234" + } + }, + "banner": { + "w": 320, + "h": 50 + }, + "id": "imp-id" + } + ] + } + }, + "mockResponse": { + "status": 204, + "body": {} + } + } + ], + "expectedBidResponses": [] +} \ No newline at end of file diff --git a/adapters/aax/params_test.go b/adapters/aax/params_test.go new file mode 100644 index 00000000000..edf9fb6fc48 --- /dev/null +++ b/adapters/aax/params_test.go @@ -0,0 +1,54 @@ +package aax + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/openrtb_ext" +) + +// This file actually intends to test static/bidder-params/aax.json +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.BidderAax, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected aax 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.BidderAax, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{"cid":"123", "crid":"1234"}`, +} + +var invalidParams = []string{ + ``, + `null`, + `true`, + `5`, + `4.2`, + `[]`, + `{}`, + `{"cid":"", "crid":""}`, + `{"cid":"only cid is present"}`, + `{"crid":"only crid is present"}`, + `{"ccid":"123","ccrid":"123"}`, + `{"aid":123, "placementId":"123", "siteId":"321"}`, +} diff --git a/config/config.go b/config/config.go index ef200630b6d..6af509e28db 100644 --- a/config/config.go +++ b/config/config.go @@ -895,6 +895,8 @@ func SetupViper(v *viper.Viper, filename string) { // for them and specify all the parameters they need for them to work correctly. v.SetDefault("adapters.33across.endpoint", "https://ssc.33across.com/api/v1/s2s") v.SetDefault("adapters.33across.partner_id", "") + v.SetDefault("adapters.aax.endpoint", "https://prebid.aaxads.com/rtb/pb/aax-prebid") + v.SetDefault("adapters.aax.extra_info", "https://aax.golang.pbs.com") v.SetDefault("adapters.aceex.endpoint", "http://bl-us.aceex.io/?uqhash={{.AccountID}}") v.SetDefault("adapters.acuityads.endpoint", "http://{{.Host}}.admanmedia.com/bid?token={{.AccountID}}") v.SetDefault("adapters.adf.endpoint", "https://adx.adform.net/adx/openrtb") diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 12d31f0d9e3..24a2f0b84d2 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -3,6 +3,7 @@ package exchange import ( "github.com/prebid/prebid-server/adapters" ttx "github.com/prebid/prebid-server/adapters/33across" + "github.com/prebid/prebid-server/adapters/aax" "github.com/prebid/prebid-server/adapters/aceex" "github.com/prebid/prebid-server/adapters/acuityads" "github.com/prebid/prebid-server/adapters/adf" @@ -142,6 +143,7 @@ import ( func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { return map[openrtb_ext.BidderName]adapters.Builder{ openrtb_ext.Bidder33Across: ttx.Builder, + openrtb_ext.BidderAax: aax.Builder, openrtb_ext.BidderAceex: aceex.Builder, openrtb_ext.BidderAcuityAds: acuityads.Builder, openrtb_ext.BidderAdf: adf.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 524ab5e5a95..de33aa577e3 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -77,6 +77,7 @@ func IsBidderNameReserved(name string) bool { // Please keep this list alphabetized to minimize merge conflicts. const ( Bidder33Across BidderName = "33across" + BidderAax BidderName = "aax" BidderAceex BidderName = "aceex" BidderAcuityAds BidderName = "acuityads" BidderAdf BidderName = "adf" @@ -225,6 +226,7 @@ const ( func CoreBidderNames() []BidderName { return []BidderName{ Bidder33Across, + BidderAax, BidderAceex, BidderAcuityAds, BidderAdf, diff --git a/openrtb_ext/imp_aax.go b/openrtb_ext/imp_aax.go new file mode 100644 index 00000000000..dc2d68d0d5f --- /dev/null +++ b/openrtb_ext/imp_aax.go @@ -0,0 +1,6 @@ +package openrtb_ext + +type ExtImpAax struct { + Cid string `json:"cid"` + Crid string `json:"crid"` +} diff --git a/static/bidder-info/aax.yaml b/static/bidder-info/aax.yaml new file mode 100644 index 00000000000..e08cb559770 --- /dev/null +++ b/static/bidder-info/aax.yaml @@ -0,0 +1,19 @@ +maintainer: + email: product@aax.media +gvlVendorID: 720 +modifyingVastXmlAllowed: true +capabilities: + app: + mediaTypes: + - banner + - video + - native + site: + mediaTypes: + - banner + - video + - native +userSync: + redirect: + url: https://c.aaxads.com/aacxc.php?fv=1&wbsh=psa&ryvlg=setstatuscode&bidder=aax&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redirect={{.RedirectURL}} + userMacro: \ No newline at end of file diff --git a/static/bidder-params/aax.json b/static/bidder-params/aax.json new file mode 100644 index 00000000000..d13e73a0a83 --- /dev/null +++ b/static/bidder-params/aax.json @@ -0,0 +1,22 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Aax Adapter Params", + "description": "A schema which validates params accepted by the Aax adapter", + "type": "object", + "properties": { + "cid": { + "type": "string", + "minLength": 1, + "description": "The customer id provided by AAX." + }, + "crid": { + "type": "string", + "minLength": 1, + "description": "The placement id provided by AAX." + } + }, + "required": [ + "cid", + "crid" + ] +} \ No newline at end of file