diff --git a/.github/workflows/validate-merge.yml b/.github/workflows/validate-merge.yml new file mode 100644 index 00000000000..30370178ca8 --- /dev/null +++ b/.github/workflows/validate-merge.yml @@ -0,0 +1,24 @@ +name: Validate Merge + +on: + pull_request: + branches: [master] + +jobs: + validate-merge: + runs-on: ubuntu-18.04 + + steps: + - name: Install Go + uses: actions/setup-go@v2 + with: + go-version: 1.14.2 + + - name: Checkout Merged Branch + uses: actions/checkout@v2 + + - name: Validate + run: | + ./validate.sh --nofmt --cov --race 10 + env: + GO111MODULE: "on" diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml index d7bb50fbabf..3efc51d287a 100644 --- a/.github/workflows/validate.yml +++ b/.github/workflows/validate.yml @@ -1,26 +1,31 @@ +name: Validate + on: push: - branches: - - master + branches: [master] pull_request: - release: - types: - - created -name: Validate + branches: [master] + jobs: - Go: + validate: strategy: matrix: - go-version: [1.13.x, 1.14.x, 1.15.x] + go-version: [1.14.x, 1.15.x] os: [ubuntu-18.04] runs-on: ${{ matrix.os }} + steps: - name: Install Go uses: actions/setup-go@v2 with: go-version: ${{ matrix.go-version }} - - name: Checkout code + + - name: Checkout Branch uses: actions/checkout@v2 + with: + # Resolves to empty string for push events and falls back to HEAD. + ref: ${{ github.event.pull_request.head.sha }} + - name: Validate run: | ./validate.sh --nofmt --cov --race 10 diff --git a/.travis.yml b/.travis.yml index 60ee49faf68..655ea837eae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,8 @@ language: go go: - - '1.13' - '1.14.2' + - '1.15' go_import_path: github.com/PubMatic-OpenWrap/prebid-server diff --git a/Dockerfile b/Dockerfile index 2c60b9e39b0..d76398dc6d3 100644 --- a/Dockerfile +++ b/Dockerfile @@ -32,6 +32,6 @@ RUN apt-get update && \ apt-get install -y ca-certificates mtr && \ apt-get clean && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* EXPOSE 8000 -EXPOSE 8080 +EXPOSE 6060 ENTRYPOINT ["/usr/local/bin/prebid-server"] CMD ["-v", "1", "-logtostderr"] diff --git a/README.md b/README.md index 145883587fd..529629e0e2a 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ For more information, see: ## Installation -First install [Go](https://golang.org/doc/install) version 1.13 or newer. +First install [Go](https://golang.org/doc/install) version 1.14 or newer. Note that prebid-server is using [Go modules](https://blog.golang.org/using-go-modules). We officially support the most recent two major versions of the Go runtime. However, if you'd like to use a version <1.13 and are inside GOPATH `GO111MODULE` needs to be set to `GO111MODULE=on`. diff --git a/account/account.go b/account/account.go index 43ba806a6da..d5d22f4a894 100644 --- a/account/account.go +++ b/account/account.go @@ -7,7 +7,7 @@ import ( "github.com/PubMatic-OpenWrap/prebid-server/config" "github.com/PubMatic-OpenWrap/prebid-server/errortypes" - "github.com/PubMatic-OpenWrap/prebid-server/pbsmetrics" + "github.com/PubMatic-OpenWrap/prebid-server/metrics" "github.com/PubMatic-OpenWrap/prebid-server/stored_requests" jsonpatch "github.com/evanphx/json-patch" ) @@ -20,7 +20,7 @@ func GetAccount(ctx context.Context, cfg *config.Configuration, fetcher stored_r Message: fmt.Sprintf("Prebid-server has disabled Account ID: %s, please reach out to the prebid server host.", accountID), }} } - if cfg.AccountRequired && accountID == pbsmetrics.PublisherUnknown { + if cfg.AccountRequired && accountID == metrics.PublisherUnknown { return nil, []error{&errortypes.AcctRequired{ Message: fmt.Sprintf("Prebid-server has been configured to discard requests without a valid Account ID. Please reach out to the prebid server host."), }} diff --git a/account/account_test.go b/account/account_test.go index e8acdfe0f5f..0783ee0e134 100644 --- a/account/account_test.go +++ b/account/account_test.go @@ -8,7 +8,7 @@ import ( "github.com/PubMatic-OpenWrap/prebid-server/config" "github.com/PubMatic-OpenWrap/prebid-server/errortypes" - "github.com/PubMatic-OpenWrap/prebid-server/pbsmetrics" + "github.com/PubMatic-OpenWrap/prebid-server/metrics" "github.com/PubMatic-OpenWrap/prebid-server/stored_requests" "github.com/stretchr/testify/assert" ) @@ -29,7 +29,7 @@ func (af mockAccountFetcher) FetchAccount(ctx context.Context, accountID string) } func TestGetAccount(t *testing.T) { - unknown := pbsmetrics.PublisherUnknown + unknown := metrics.PublisherUnknown testCases := []struct { accountID string // account_required diff --git a/adapters/33across/33across.go b/adapters/33across/33across.go index 9b622e4f94e..7abd7ba72bd 100644 --- a/adapters/33across/33across.go +++ b/adapters/33across/33across.go @@ -7,6 +7,7 @@ import ( "github.com/PubMatic-OpenWrap/openrtb" "github.com/PubMatic-OpenWrap/prebid-server/adapters" + "github.com/PubMatic-OpenWrap/prebid-server/config" "github.com/PubMatic-OpenWrap/prebid-server/errortypes" "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" ) @@ -16,14 +17,31 @@ type TtxAdapter struct { } type Ext struct { - Ttx ext `json:"ttx"` + Ttx impTtxExt `json:"ttx"` } -type ext struct { +type impTtxExt struct { Prod string `json:"prod"` Zoneid string `json:"zoneid,omitempty"` } +type reqExt struct { + Ttx *reqTtxExt `json:"ttx,omitempty"` +} + +type reqTtxExt struct { + Caller []TtxCaller `json:"caller,omitempty"` +} + +type TtxCaller struct { + Name string `json:"name,omitempty"` + Version string `json:"version,omitempty"` +} + +// CALLER Info used to track Prebid Server +// as one of the hops in the request to exchange +var CALLER = TtxCaller{"Prebid-Server", "n/a"} + type bidExt struct { Ttx bidTtxExt `json:"ttx,omitempty"` } @@ -37,39 +55,41 @@ func (a *TtxAdapter) MakeRequests(request *openrtb.BidRequest, reqInfo *adapters var errs []error var adapterRequests []*adapters.RequestData - adapterReq, errors := a.makeRequest(request) - if adapterReq != nil { - adapterRequests = append(adapterRequests, adapterReq) + // Construct request extension common to all imps + // NOTE: not blocking adapter requests on errors + // since request extension is optional. + reqExt, err := makeReqExt(request) + if err != nil { + errs = append(errs, err) + } + request.Ext = reqExt + + // Break up multi-imp request into multiple external requests since we don't + // support SRA in our exchange server + for i := 0; i < len(request.Imp); i++ { + if adapterReq, err := a.makeRequest(*request, request.Imp[i]); err == nil { + adapterRequests = append(adapterRequests, adapterReq) + } else { + errs = append(errs, err) + } } - errs = append(errs, errors...) - return adapterRequests, errors + return adapterRequests, errs } -// Update the request object to include custom value -// site.id -func (a *TtxAdapter) makeRequest(request *openrtb.BidRequest) (*adapters.RequestData, []error) { - var errs []error +func (a *TtxAdapter) makeRequest(request openrtb.BidRequest, imp openrtb.Imp) (*adapters.RequestData, error) { + impCopy, err := makeImps(imp) - // Make a copy as we don't want to change the original request - reqCopy := *request - if err := preprocess(&reqCopy); err != nil { - errs = append(errs, err) + if err != nil { + return nil, err } - if reqCopy.Imp[0].Banner == nil && reqCopy.Imp[0].Video == nil { - errs = append(errs, &errortypes.BadInput{ - Message: "At least one of [banner, video] formats must be defined in Imp. None found", - }) - - return nil, errs - } + request.Imp = []openrtb.Imp{*impCopy} // Last Step - reqJSON, err := json.Marshal(reqCopy) + reqJSON, err := json.Marshal(request) if err != nil { - errs = append(errs, err) - return nil, errs + return nil, err } headers := http.Header{} @@ -80,22 +100,26 @@ func (a *TtxAdapter) makeRequest(request *openrtb.BidRequest) (*adapters.Request Uri: a.endpoint, Body: reqJSON, Headers: headers, - }, errs + }, nil } -// Mutate the request to get it ready to send to ttx. -func preprocess(request *openrtb.BidRequest) error { - var imp = &request.Imp[0] +func makeImps(imp openrtb.Imp) (*openrtb.Imp, error) { + if imp.Banner == nil && imp.Video == nil { + return nil, &errortypes.BadInput{ + Message: fmt.Sprintf("Imp ID %s must have at least one of [Banner, Video] defined", imp.ID), + } + } + var bidderExt adapters.ExtImpBidder if err := json.Unmarshal(imp.Ext, &bidderExt); err != nil { - return &errortypes.BadInput{ + return nil, &errortypes.BadInput{ Message: err.Error(), } } var ttxExt openrtb_ext.ExtImp33across if err := json.Unmarshal(bidderExt.Bidder, &ttxExt); err != nil { - return &errortypes.BadInput{ + return nil, &errortypes.BadInput{ Message: err.Error(), } } @@ -103,22 +127,20 @@ func preprocess(request *openrtb.BidRequest) error { var impExt Ext impExt.Ttx.Prod = ttxExt.ProductId - // Add zoneid if it's defined + impExt.Ttx.Zoneid = ttxExt.SiteId + if len(ttxExt.ZoneId) > 0 { impExt.Ttx.Zoneid = ttxExt.ZoneId } impExtJSON, err := json.Marshal(impExt) if err != nil { - return &errortypes.BadInput{ + return nil, &errortypes.BadInput{ Message: err.Error(), } } imp.Ext = impExtJSON - siteCopy := *request.Site - siteCopy.ID = ttxExt.SiteId - request.Site = &siteCopy // Validate Video if it exists if imp.Video != nil { @@ -127,13 +149,35 @@ func preprocess(request *openrtb.BidRequest) error { imp.Video = videoCopy if err != nil { - return &errortypes.BadInput{ + return nil, &errortypes.BadInput{ Message: err.Error(), } } } - return nil + return &imp, nil +} + +func makeReqExt(request *openrtb.BidRequest) ([]byte, error) { + var reqExt reqExt + + if len(request.Ext) > 0 { + if err := json.Unmarshal(request.Ext, &reqExt); err != nil { + return nil, err + } + } + + if reqExt.Ttx == nil { + reqExt.Ttx = &reqTtxExt{} + } + + if reqExt.Ttx.Caller == nil { + reqExt.Ttx.Caller = make([]TtxCaller, 0) + } + + reqExt.Ttx.Caller = append(reqExt.Ttx.Caller, CALLER) + + return json.Marshal(reqExt) } // MakeBids make the bids for the bid response. @@ -219,9 +263,10 @@ func getBidType(ext bidExt) openrtb_ext.BidType { return openrtb_ext.BidTypeBanner } -// New33AcrossBidder configures bidder endpoint -func New33AcrossBidder(endpoint string) *TtxAdapter { - return &TtxAdapter{ - endpoint: endpoint, +// Builder builds a new instance of the 33Across adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) { + bidder := &TtxAdapter{ + endpoint: config.Endpoint, } + return bidder, nil } diff --git a/adapters/33across/33across_test.go b/adapters/33across/33across_test.go index efb771c6385..08c2ff614e9 100644 --- a/adapters/33across/33across_test.go +++ b/adapters/33across/33across_test.go @@ -4,8 +4,17 @@ import ( "testing" "github.com/PubMatic-OpenWrap/prebid-server/adapters/adapterstest" + "github.com/PubMatic-OpenWrap/prebid-server/config" + "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" ) func TestJsonSamples(t *testing.T) { - adapterstest.RunJSONBidderTest(t, "33acrosstest", New33AcrossBidder("http://ssc.33across.com")) + bidder, buildErr := Builder(openrtb_ext.Bidder33Across, config.Adapter{ + Endpoint: "http://ssc.33across.com"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "33acrosstest", bidder) } diff --git a/adapters/33across/33acrosstest/exemplary/bidresponse-defaults.json b/adapters/33across/33acrosstest/exemplary/bidresponse-defaults.json index bb0e6585fd0..50fba69bde1 100644 --- a/adapters/33across/33acrosstest/exemplary/bidresponse-defaults.json +++ b/adapters/33across/33acrosstest/exemplary/bidresponse-defaults.json @@ -29,6 +29,16 @@ "expectedRequest": { "uri": "http://ssc.33across.com", "body": { + "ext": { + "ttx": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, "id": "test-request-id", "imp": [ { @@ -44,14 +54,13 @@ }, "ext": { "ttx": { - "prod": "instream" + "prod": "instream", + "zoneid": "fake-site-id" } } } ], - "site": { - "id": "fake-site-id" - } + "site": {} } }, "mockResponse": { diff --git a/adapters/33across/33acrosstest/exemplary/instream-video-defaults.json b/adapters/33across/33acrosstest/exemplary/instream-video-defaults.json index 479b197077a..c99e535cdb7 100644 --- a/adapters/33across/33acrosstest/exemplary/instream-video-defaults.json +++ b/adapters/33across/33acrosstest/exemplary/instream-video-defaults.json @@ -27,6 +27,16 @@ "expectedRequest": { "uri": "http://ssc.33across.com", "body": { + "ext": { + "ttx": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, "id": "test-request-id", "imp": [ { @@ -42,14 +52,13 @@ }, "ext": { "ttx": { - "prod": "instream" + "prod": "instream", + "zoneid": "fake-site-id" } } } ], - "site": { - "id": "fake-site-id" - } + "site": {} } }, "mockResponse": { diff --git a/adapters/33across/33acrosstest/exemplary/multi-format.json b/adapters/33across/33acrosstest/exemplary/multi-format.json index db15955ca87..3315ff72559 100644 --- a/adapters/33across/33acrosstest/exemplary/multi-format.json +++ b/adapters/33across/33acrosstest/exemplary/multi-format.json @@ -30,6 +30,16 @@ "expectedRequest": { "uri": "http://ssc.33across.com", "body": { + "ext": { + "ttx": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, "id": "test-request-id", "imp": [ { @@ -47,14 +57,13 @@ }, "ext": { "ttx": { - "prod": "inview" + "prod": "inview", + "zoneid": "fake-site-id" } } } ], - "site": { - "id": "fake-site-id" - } + "site": {} } }, "mockResponse": { diff --git a/adapters/33across/33acrosstest/exemplary/multi-imp-banner.json b/adapters/33across/33acrosstest/exemplary/multi-imp-banner.json new file mode 100644 index 00000000000..b6d19f55683 --- /dev/null +++ b/adapters/33across/33acrosstest/exemplary/multi-imp-banner.json @@ -0,0 +1,200 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id1", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "ext": { + "bidder": { + "siteId": "fake-site-id", + "productId": "inview" + } + } + }, + { + "id": "test-imp-id2", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "ext": { + "bidder": { + "siteId": "fake-site-id", + "productId": "inview" + } + } + } + ], + "site": {} + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://ssc.33across.com", + "body": { + "ext": { + "ttx": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, + "id": "test-request-id", + "imp": [ + { + "id":"test-imp-id1", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "ext": { + "ttx": { + "prod": "inview", + "zoneid": "fake-site-id" + } + } + } + ], + "site": {} + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "ttx", + "bid": [{ + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id1", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "crid_10", + "h": 90, + "w": 728, + "ext": { + "ttx": { + "mediaType": "banner" + } + } + }] + } + ], + "cur": "USD" + } + } + }, + { + "expectedRequest": { + "uri": "http://ssc.33across.com", + "body": { + "ext": { + "ttx": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, + "id": "test-request-id", + "imp": [ + { + "id":"test-imp-id2", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "ext": { + "ttx": { + "prod": "inview", + "zoneid": "fake-site-id" + } + } + } + ], + "site": {} + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "ttx", + "bid": [{ + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id2", + "price": 0.600000, + "adm": "some-test-ad", + "crid": "crid_10", + "h": 90, + "w": 728, + "ext": { + "ttx": { + "mediaType": "banner" + } + } + }] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id1", + "price": 0.5, + "adm": "some-test-ad", + "crid": "crid_10", + "w": 728, + "h": 90, + "ext": { + "ttx": { + "mediaType": "banner" + } + } + }, + "type": "banner" + } + ] + }, + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id2", + "price": 0.6, + "adm": "some-test-ad", + "crid": "crid_10", + "w": 728, + "h": 90, + "ext": { + "ttx": { + "mediaType": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/33across/33acrosstest/exemplary/optional-params.json b/adapters/33across/33acrosstest/exemplary/optional-params.json index e92958e73d7..f429f9458a7 100644 --- a/adapters/33across/33acrosstest/exemplary/optional-params.json +++ b/adapters/33across/33acrosstest/exemplary/optional-params.json @@ -24,6 +24,16 @@ "expectedRequest": { "uri": "http://ssc.33across.com", "body": { + "ext": { + "ttx": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, "id": "test-request-id", "imp": [ { @@ -39,14 +49,13 @@ } } ], - "site": { - "id": "fake-site-id" - } + "site": {} } }, "mockResponse": { "status": 204 } } - ] + ], + "expectedBidResponses": [] } diff --git a/adapters/33across/33acrosstest/exemplary/outstream-video-defaults.json b/adapters/33across/33acrosstest/exemplary/outstream-video-defaults.json index c0c31168684..fdd422c7a63 100644 --- a/adapters/33across/33acrosstest/exemplary/outstream-video-defaults.json +++ b/adapters/33across/33acrosstest/exemplary/outstream-video-defaults.json @@ -27,6 +27,16 @@ "expectedRequest": { "uri": "http://ssc.33across.com", "body": { + "ext": { + "ttx": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, "id": "test-request-id", "imp": [ { @@ -41,14 +51,13 @@ }, "ext": { "ttx": { - "prod": "siab" + "prod": "siab", + "zoneid": "fake-site-id" } } } ], - "site": { - "id": "fake-site-id" - } + "site": {} } }, "mockResponse": { diff --git a/adapters/33across/33acrosstest/exemplary/simple-banner.json b/adapters/33across/33acrosstest/exemplary/site-banner.json similarity index 85% rename from adapters/33across/33acrosstest/exemplary/simple-banner.json rename to adapters/33across/33acrosstest/exemplary/site-banner.json index d8c215c06ae..552daf25224 100644 --- a/adapters/33across/33acrosstest/exemplary/simple-banner.json +++ b/adapters/33across/33acrosstest/exemplary/site-banner.json @@ -23,6 +23,16 @@ "expectedRequest": { "uri": "http://ssc.33across.com", "body": { + "ext": { + "ttx": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, "id": "test-request-id", "imp": [ { @@ -32,14 +42,13 @@ }, "ext": { "ttx": { - "prod": "inview" + "prod": "inview", + "zoneid": "fake-site-id" } } } ], - "site": { - "id": "fake-site-id" - } + "site": {} } }, "mockResponse": { diff --git a/adapters/33across/33acrosstest/exemplary/simple-video.json b/adapters/33across/33acrosstest/exemplary/site-video.json similarity index 87% rename from adapters/33across/33acrosstest/exemplary/simple-video.json rename to adapters/33across/33acrosstest/exemplary/site-video.json index 55337b92827..3cf44775efb 100644 --- a/adapters/33across/33acrosstest/exemplary/simple-video.json +++ b/adapters/33across/33acrosstest/exemplary/site-video.json @@ -29,6 +29,16 @@ "expectedRequest": { "uri": "http://ssc.33across.com", "body": { + "ext": { + "ttx": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, "id": "test-request-id", "imp": [ { @@ -44,14 +54,13 @@ }, "ext": { "ttx": { - "prod": "instream" + "prod": "instream", + "zoneid": "fake-site-id" } } } ], - "site": { - "id": "fake-site-id" - } + "site": {} } }, "mockResponse": { diff --git a/adapters/33across/33acrosstest/supplemental/multi-imp-mixed-validation.json b/adapters/33across/33acrosstest/supplemental/multi-imp-mixed-validation.json new file mode 100644 index 00000000000..a2bc7890e96 --- /dev/null +++ b/adapters/33across/33acrosstest/supplemental/multi-imp-mixed-validation.json @@ -0,0 +1,121 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id1", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "ext": { + "bidder": { + "siteId": "fake-site-id", + "productId": "inview" + } + } + }, + { + "id": "test-imp-id2", + "ext": { + "bidder": { + "siteId": "fake-site-id", + "productId": "inview" + } + } + } + ], + "site": {} + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://ssc.33across.com", + "body": { + "ext": { + "ttx": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, + "id": "test-request-id", + "imp": [ + { + "id":"test-imp-id1", + "banner": { + "format": [{"w": 728, "h": 90}] + }, + "ext": { + "ttx": { + "prod": "inview", + "zoneid": "fake-site-id" + } + } + } + ], + "site": {} + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "ttx", + "bid": [{ + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id1", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "crid_10", + "h": 90, + "w": 728, + "ext": { + "ttx": { + "mediaType": "banner" + } + } + }] + } + ], + "cur": "USD" + } + } + } + ], + "expectedMakeRequestsErrors": [ + { + "value": "Imp ID test-imp-id2 must have at least one of [Banner, Video] defined", + "comparison": "literal" + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id1", + "price": 0.5, + "adm": "some-test-ad", + "crid": "crid_10", + "w": 728, + "h": 90, + "ext": { + "ttx": { + "mediaType": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/33across/33acrosstest/supplemental/status-not-ok.json b/adapters/33across/33acrosstest/supplemental/status-not-ok.json index 98fe01c2e50..2c7fcd013f3 100644 --- a/adapters/33across/33acrosstest/supplemental/status-not-ok.json +++ b/adapters/33across/33acrosstest/supplemental/status-not-ok.json @@ -23,6 +23,16 @@ "expectedRequest": { "uri": "http://ssc.33across.com", "body": { + "ext": { + "ttx": { + "caller": [ + { + "name": "Prebid-Server", + "version": "n/a" + } + ] + } + }, "id": "test-request-id", "imp": [ { @@ -32,14 +42,13 @@ }, "ext": { "ttx": { - "prod": "inview" + "prod": "inview", + "zoneid": "fake-invalid-site-id" } } } ], - "site": { - "id": "fake-invalid-site-id" - } + "site": {} } }, "mockResponse": { diff --git a/adapters/33across/33acrosstest/supplemental/video-validation-fail.json b/adapters/33across/33acrosstest/supplemental/video-validation-fail.json index 97cb79bd26c..f29d728c9d7 100644 --- a/adapters/33across/33acrosstest/supplemental/video-validation-fail.json +++ b/adapters/33across/33acrosstest/supplemental/video-validation-fail.json @@ -23,10 +23,6 @@ { "value": "One or more invalid or missing video field(s) w, h, protocols, mimes, playbackmethod", "comparison": "literal" - }, - { - "value": "At least one of [banner, video] formats must be defined in Imp. None found", - "comparison": "literal" } ] } diff --git a/adapters/acuityads/acuityads.go b/adapters/acuityads/acuityads.go index b123f82cbb0..ac2c6ac7c4d 100644 --- a/adapters/acuityads/acuityads.go +++ b/adapters/acuityads/acuityads.go @@ -8,23 +8,27 @@ import ( "github.com/PubMatic-OpenWrap/openrtb" "github.com/PubMatic-OpenWrap/prebid-server/adapters" + "github.com/PubMatic-OpenWrap/prebid-server/config" "github.com/PubMatic-OpenWrap/prebid-server/errortypes" "github.com/PubMatic-OpenWrap/prebid-server/macros" "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" - "github.com/golang/glog" ) type AcuityAdsAdapter struct { endpoint template.Template } -func NewAcuityAdsBidder(endpointTemplate string) *AcuityAdsAdapter { - template, err := template.New("endpointTemplate").Parse(endpointTemplate) +// Builder builds a new instance of the AcuityAds adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) { + template, err := template.New("endpointTemplate").Parse(config.Endpoint) if err != nil { - glog.Fatal("Unable to parse endpoint url template") - return nil + return nil, fmt.Errorf("unable to parse endpoint url template: %v", err) + } + + bidder := &AcuityAdsAdapter{ + endpoint: *template, } - return &AcuityAdsAdapter{endpoint: *template} + return bidder, nil } func getHeaders(request *openrtb.BidRequest) http.Header { diff --git a/adapters/acuityads/acuityads_test.go b/adapters/acuityads/acuityads_test.go index de44dba24ca..be12780a778 100644 --- a/adapters/acuityads/acuityads_test.go +++ b/adapters/acuityads/acuityads_test.go @@ -4,8 +4,25 @@ import ( "testing" "github.com/PubMatic-OpenWrap/prebid-server/adapters/adapterstest" + "github.com/PubMatic-OpenWrap/prebid-server/config" + "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" + "github.com/stretchr/testify/assert" ) func TestJsonSamples(t *testing.T) { - adapterstest.RunJSONBidderTest(t, "acuityadstest", NewAcuityAdsBidder("http://{{.Host}}.example.com/bid?token={{.AccountID}}")) + bidder, buildErr := Builder(openrtb_ext.BidderAcuityAds, config.Adapter{ + Endpoint: "http://{{.Host}}.example.com/bid?token={{.AccountID}}"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "acuityadstest", bidder) +} + +func TestEndpointTemplateMalformed(t *testing.T) { + _, buildErr := Builder(openrtb_ext.BidderAcuityAds, config.Adapter{ + Endpoint: "{{Malformed}}"}) + + assert.Error(t, buildErr) } diff --git a/adapters/acuityads/acuityadstest/exemplary/banner-app.json b/adapters/acuityads/acuityadstest/exemplary/banner-app.json index 72fbfb5711e..f4aedeb6788 100644 --- a/adapters/acuityads/acuityadstest/exemplary/banner-app.json +++ b/adapters/acuityads/acuityadstest/exemplary/banner-app.json @@ -1,150 +1,156 @@ { - "mockBidRequest": { - "id": "some-request-id", - "device": { - "ua": "test-user-agent", - "ip": "123.123.123.123", - "language": "en", - "dnt": 0 - }, - "tmax": 1000, - "user": { - "buyeruid": "awesome-user" - }, - "app": { - "publisher": { - "id": "123456789" - }, - "cat": [ - "IAB22-1" - ], - "bundle": "com.app.awesome", - "name": "Awesome App", - "domain": "awesomeapp.com", + "mockBidRequest": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "tmax": 1000, + "user": { + "buyeruid": "awesome-user" + }, + "app": { + "publisher": { "id": "123456789" }, - "imp": [ - { - "id": "some-impression-id", - "tagid": "ogTAGID", - "banner": { - "w":320, - "h":50 - }, - "ext": { - "bidder": { - "host": "ep1", - "accountid": "hash" - } - } - } - ] + "cat": [ + "IAB22-1" + ], + "bundle": "com.app.awesome", + "name": "Awesome App", + "domain": "awesomeapp.com", + "id": "123456789" }, - "httpCalls": [ + "imp": [ { - "expectedRequest": { - "headers": { - "Content-Type": [ - "application/json;charset=utf-8" - ], - "Accept": [ - "application/json" - ], - "X-Openrtb-Version": [ - "2.5" - ], - "User-Agent": [ - "test-user-agent" - ], - "X-Forwarded-For": [ - "123.123.123.123" - ] + "id": "some-impression-id", + "tagid": "ogTAGID", + "banner": { + "w": 320, + "h": 50 + }, + "ext": { + "bidder": { + "host": "ep1", + "accountid": "hash" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "headers": { + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Accept": [ + "application/json" + ], + "X-Openrtb-Version": [ + "2.5" + ], + "User-Agent": [ + "test-user-agent" + ], + "X-Forwarded-For": [ + "123.123.123.123" + ] + }, + "uri": "http://ep1.example.com/bid?token=hash", + "body": { + "id": "some-request-id", + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 }, - "uri": "http://ep1.example.com/bid?token=hash", - "body": { - "id": "some-request-id", - "device": { - "ua": "test-user-agent", - "ip": "123.123.123.123", - "language": "en", - "dnt": 0 - }, - "imp": [ - { - "id": "some-impression-id", - "banner": { - "w":320, - "h":50 - }, - "tagid": "ogTAGID" - } + "imp": [ + { + "id": "some-impression-id", + "banner": { + "w": 320, + "h": 50 + }, + "tagid": "ogTAGID" + } + ], + "app": { + "id": "123456789", + "name": "Awesome App", + "bundle": "com.app.awesome", + "domain": "awesomeapp.com", + "cat": [ + "IAB22-1" ], - "app": { - "id": "123456789", - "name": "Awesome App", - "bundle": "com.app.awesome", - "domain": "awesomeapp.com", - "cat": [ - "IAB22-1" + "publisher": { + "id": "123456789" + } + }, + "user": { + "buyeruid": "awesome-user" + }, + "tmax": 1000 + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "awesome-resp-id", + "seatbid": [ + { + "bid": [ + { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "1", + "price": 3.5, + "adm": "awesome-markup", + "adomain": [ + "awesome.com" + ], + "crid": "20", + "w": 320, + "h": 50 + } ], - "publisher": { - "id": "123456789" - } - }, - "user": { - "buyeruid": "awesome-user" - }, - "tmax": 1000 - } - }, - "mockResponse": { - "status": 200, - "body": { - "id": "awesome-resp-id", - "seatbid": [ - { - "bid": [ - { - "id": "a3ae1b4e2fc24a4fb45540082e98e161", - "impid": "1", - "price": 3.5, - "adm": "asesome-markup", - "adomain": [ - "awesome.com" - ], - "crid": "20", - "w":320, - "h":50 - } - ], "type": "banner", - "seat": "acuityads" - } - ], - "cur": "USD", - "ext": { - "responsetimemillis": { - "acuityads": 154 - }, - "tmaxrequest": 1000 + "seat": "acuityads" } + ], + "cur": "USD", + "ext": { + "responsetimemillis": { + "acuityads": 154 + }, + "tmaxrequest": 1000 } } } - ], - "expectedBids": [ - { - "id": "a3ae1b4e2fc24a4fb45540082e98e161", - "impid": "1", - "price": 3.5, - "adm": "awesome-markup", - "adomain": [ - "awesome.com" - ], - "crid": "20", - "w":320, - "h":50 - } - ] - } - \ No newline at end of file + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "1", + "price": 3.5, + "adm": "awesome-markup", + "adomain": [ + "awesome.com" + ], + "crid": "20", + "w": 320, + "h": 50 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/acuityads/acuityadstest/exemplary/banner-web.json b/adapters/acuityads/acuityadstest/exemplary/banner-web.json index 83265367562..f4616bc4030 100644 --- a/adapters/acuityads/acuityadstest/exemplary/banner-web.json +++ b/adapters/acuityads/acuityadstest/exemplary/banner-web.json @@ -96,7 +96,7 @@ "id": "a3ae1b4e2fc24a4fb45540082e98e161", "impid": "1", "price": 3.5, - "adm": "asesome-markup", + "adm": "awesome-markup", "adomain": [ "awesome.com" ], @@ -128,7 +128,7 @@ "id": "a3ae1b4e2fc24a4fb45540082e98e161", "impid": "1", "price": 3.5, - "adm": "asesome-markup", + "adm": "awesome-markup", "crid": "20", "adomain": [ "awesome.com" diff --git a/adapters/acuityads/acuityadstest/exemplary/native-app.json b/adapters/acuityads/acuityadstest/exemplary/native-app.json index a8fb92c942d..6ada3926733 100644 --- a/adapters/acuityads/acuityadstest/exemplary/native-app.json +++ b/adapters/acuityads/acuityadstest/exemplary/native-app.json @@ -108,7 +108,7 @@ "id": "a3ae1b4e2fc24a4fb45540082e98e161", "impid": "some-impression-id", "price": 3.5, - "adm": "asesome-markup", + "adm": "awesome-markup", "adomain": [ "awesome.com" ], @@ -138,7 +138,7 @@ "id": "a3ae1b4e2fc24a4fb45540082e98e161", "impid": "some-impression-id", "price": 3.5, - "adm": "asesome-markup", + "adm": "awesome-markup", "crid": "20", "adomain": [ "awesome.com" @@ -150,4 +150,4 @@ } ] } - \ No newline at end of file + diff --git a/adapters/acuityads/acuityadstest/exemplary/native-web.json b/adapters/acuityads/acuityadstest/exemplary/native-web.json index 9becd23d881..96b3ca06aec 100644 --- a/adapters/acuityads/acuityadstest/exemplary/native-web.json +++ b/adapters/acuityads/acuityadstest/exemplary/native-web.json @@ -96,7 +96,7 @@ "id": "a3ae1b4e2fc24a4fb45540082e98e161", "impid": "some-impression-id", "price": 3.5, - "adm": "asesome-markup", + "adm": "awesome-markup", "adomain": [ "awesome.com" ], @@ -125,7 +125,7 @@ "id": "a3ae1b4e2fc24a4fb45540082e98e161", "impid": "some-impression-id", "price": 3.5, - "adm": "asesome-markup", + "adm": "awesome-markup", "crid": "20", "adomain": [ "awesome.com" diff --git a/adapters/acuityads/acuityadstest/exemplary/video-app.json b/adapters/acuityads/acuityadstest/exemplary/video-app.json index c6c75d903aa..4130602db47 100644 --- a/adapters/acuityads/acuityadstest/exemplary/video-app.json +++ b/adapters/acuityads/acuityadstest/exemplary/video-app.json @@ -118,7 +118,7 @@ "id": "a3ae1b4e2fc24a4fb45540082e98e161", "impid": "some-impression-id", "price": 3.5, - "adm": "asesome-markup", + "adm": "awesome-markup", "adomain": [ "awesome.com" ], @@ -149,7 +149,7 @@ "id": "a3ae1b4e2fc24a4fb45540082e98e161", "impid": "some-impression-id", "price": 3.5, - "adm": "asesome-markup", + "adm": "awesome-markup", "crid": "20", "adomain": [ "awesome.com" diff --git a/adapters/acuityads/acuityadstest/exemplary/video-web.json b/adapters/acuityads/acuityadstest/exemplary/video-web.json index e2b9d9eb9d6..60260aa5271 100644 --- a/adapters/acuityads/acuityadstest/exemplary/video-web.json +++ b/adapters/acuityads/acuityadstest/exemplary/video-web.json @@ -104,9 +104,9 @@ "bid": [ { "id": "a3ae1b4e2fc24a4fb45540082e98e161", - "impid": "1", + "impid": "some-impression-id", "price": 3.5, - "adm": "asesome-markup", + "adm": "awesome-markup", "adomain": [ "awesome.com" ], @@ -134,23 +134,30 @@ } } ], - "expectedBids": [ + "expectedBidResponses": [ { - "id": "a3ae1b4e2fc24a4fb45540082e98e161", - "impid": "1", - "price": 3.5, - "adm": "asesome-markup", - "adomain": [ - "awesome.com" - ], - "crid": "20", - "w": 1280, - "h": 720, - "ext": { - "prebid": { - "type": "video" + "bids": [ + { + "bid": { + "id": "a3ae1b4e2fc24a4fb45540082e98e161", + "impid": "some-impression-id", + "price": 3.5, + "adm": "awesome-markup", + "adomain": [ + "awesome.com" + ], + "crid": "20", + "w": 1280, + "h": 720, + "ext": { + "prebid": { + "type": "video" + } + } + }, + "type":"video" } - } + ] } ] } diff --git a/adapters/acuityads/acuityadstest/supplemental/invalid-acuityads-ext-object.json b/adapters/acuityads/acuityadstest/supplemental/invalid-acuityads-ext-object.json new file mode 100644 index 00000000000..77752d01edf --- /dev/null +++ b/adapters/acuityads/acuityadstest/supplemental/invalid-acuityads-ext-object.json @@ -0,0 +1,29 @@ +{ + "expectedMakeRequestsErrors": [ + { + "value": "ext.bidder not provided", + "comparison": "literal" + } + ], + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "some-impression-id", + "tagid": "my-adcode", + "video": { + "mimes": ["video/mp4"], + "w": 640, + "h": 480, + "minduration": 120, + "maxduration": 150 + }, + "ext": "Awesome" + } + ], + "site": { + "page": "test.com" + } + }, + "httpCalls": [] +} diff --git a/adapters/adform/adform.go b/adapters/adform/adform.go index 5cdef257f1c..bb3f9f4d8a3 100644 --- a/adapters/adform/adform.go +++ b/adapters/adform/adform.go @@ -5,6 +5,7 @@ import ( "context" "encoding/base64" "encoding/json" + "errors" "fmt" "io/ioutil" "net/http" @@ -13,6 +14,7 @@ import ( "strings" "github.com/PubMatic-OpenWrap/prebid-server/adapters" + "github.com/PubMatic-OpenWrap/prebid-server/config" "github.com/PubMatic-OpenWrap/prebid-server/errortypes" "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" "github.com/PubMatic-OpenWrap/prebid-server/pbs" @@ -22,6 +24,8 @@ import ( "golang.org/x/net/context/ctxhttp" ) +const version = "0.1.3" + type AdformAdapter struct { http *adapters.HTTPAdapter URL *url.URL @@ -40,23 +44,11 @@ type adformRequest struct { adUnits []*adformAdUnit gdprApplies string consent string - digitrust *adformDigitrust currency string eids string url string } -type adformDigitrust struct { - Id string `json:"id"` - Version int `json:"version"` - Keyv int `json:"keyv"` - Privacy adformDigitrustPrivacy `json:"privacy"` -} - -type adformDigitrustPrivacy struct { - Optout bool `json:"optout"` -} - type adformAdUnit struct { MasterTagId json.Number `json:"mid"` PriceType string `json:"priceType,omitempty"` @@ -95,8 +87,18 @@ func isPriceTypeValid(priceType string) (string, bool) { // ADAPTER Interface -func NewAdformAdapter(config *adapters.HTTPAdapterConfig, endpointURL string) *AdformAdapter { - return NewAdformBidder(adapters.NewHTTPAdapter(config).Client, endpointURL) +// Builder builds a new instance of the Adform adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) { + uri, err := url.Parse(config.Endpoint) + if err != nil { + return nil, errors.New("unable to parse endpoint") + } + + bidder := &AdformAdapter{ + URL: uri, + version: version, + } + return bidder, nil } // used for cookies and such @@ -202,24 +204,6 @@ func pbsRequestToAdformRequest(a *AdformAdapter, request *pbs.PBSRequest, bidder gdprApplies = "" } consent := request.ParseConsent() - var digitrustData *openrtb_ext.ExtUserDigiTrust - if request.User != nil { - var extUser *openrtb_ext.ExtUser - if err := json.Unmarshal(request.User.Ext, &extUser); err == nil { - digitrustData = extUser.DigiTrust - } - } - - var digitrust *adformDigitrust = nil - if digitrustData != nil { - digitrust = new(adformDigitrust) - digitrust.Id = digitrustData.ID - digitrust.Keyv = digitrustData.KeyV - digitrust.Version = 1 - digitrust.Privacy = adformDigitrustPrivacy{ - Optout: digitrustData.Pref != 0, - } - } return &adformRequest{ adUnits: adUnits, @@ -233,7 +217,6 @@ func pbsRequestToAdformRequest(a *AdformAdapter, request *pbs.PBSRequest, bidder tid: request.Tid, gdprApplies: gdprApplies, consent: consent, - digitrust: digitrust, currency: defaultCurrency, }, nil } @@ -357,18 +340,9 @@ func (r *adformRequest) buildAdformHeaders(a *AdformAdapter) http.Header { header.Set("Referer", r.referer) } - cookie := make([]string, 0, 2) if r.userId != "" { - cookie = append(cookie, fmt.Sprintf("uid=%s", r.userId)) + header.Set("Cookie", fmt.Sprintf("uid=%s;", r.userId)) } - if r.digitrust != nil { - if digitrustBytes, err := json.Marshal(r.digitrust); err == nil { - digitrust := base64.URLEncoding.WithPadding(base64.NoPadding).EncodeToString(digitrustBytes) - // Cookie name and structure are described here: https://github.com/digi-trust/dt-cdn/wiki/Cookies-for-Platforms - cookie = append(cookie, fmt.Sprintf("DigiTrust.v1.identity=%s", digitrust)) - } - } - header.Set("Cookie", strings.Join(cookie, ";")) return header } @@ -386,8 +360,7 @@ func parseAdformBids(response []byte) ([]*adformBid, error) { // BIDDER Interface -func NewAdformBidder(client *http.Client, endpointURL string) *AdformAdapter { - a := &adapters.HTTPAdapter{Client: client} +func NewAdformLegacyAdapter(httpConfig *adapters.HTTPAdapterConfig, endpointURL string) *AdformAdapter { var uriObj *url.URL uriObj, err := url.Parse(endpointURL) if err != nil { @@ -395,9 +368,9 @@ func NewAdformBidder(client *http.Client, endpointURL string) *AdformAdapter { } return &AdformAdapter{ - http: a, + http: adapters.NewHTTPAdapter(httpConfig), URL: uriObj, - version: "0.1.3", + version: version, } } @@ -493,27 +466,14 @@ func openRtbToAdformRequest(request *openrtb.BidRequest) (*adformRequest, []erro eids := "" consent := "" - var digitrustData *openrtb_ext.ExtUserDigiTrust if request.User != nil { var extUser openrtb_ext.ExtUser if err := json.Unmarshal(request.User.Ext, &extUser); err == nil { consent = extUser.Consent - digitrustData = extUser.DigiTrust eids = encodeEids(extUser.Eids) } } - var digitrust *adformDigitrust = nil - if digitrustData != nil { - digitrust = new(adformDigitrust) - digitrust.Id = digitrustData.ID - digitrust.Keyv = digitrustData.KeyV - digitrust.Version = 1 - digitrust.Privacy = adformDigitrustPrivacy{ - Optout: digitrustData.Pref != 0, - } - } - requestCurrency := defaultCurrency if len(request.Cur) != 0 { hasDefaultCurrency := false @@ -539,7 +499,6 @@ func openRtbToAdformRequest(request *openrtb.BidRequest) (*adformRequest, []erro tid: tid, gdprApplies: gdprApplies, consent: consent, - digitrust: digitrust, currency: requestCurrency, eids: eids, url: url, diff --git a/adapters/adform/adform_test.go b/adapters/adform/adform_test.go index 76381966277..a4e519e6bc5 100644 --- a/adapters/adform/adform_test.go +++ b/adapters/adform/adform_test.go @@ -26,7 +26,21 @@ import ( ) func TestJsonSamples(t *testing.T) { - adapterstest.RunJSONBidderTest(t, "adformtest", NewAdformBidder(nil, "http://adx.adform.net/adx")) + bidder, buildErr := Builder(openrtb_ext.BidderAdform, config.Adapter{ + Endpoint: "https://adx.adform.net/adx"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "adformtest", bidder) +} + +func TestEndpointMalformed(t *testing.T) { + _, buildErr := Builder(openrtb_ext.BidderAdform, config.Adapter{ + Endpoint: ` https://malformed`}) + + assert.Error(t, buildErr) } type aTagInfo struct { @@ -193,7 +207,7 @@ func initTestData(server *httptest.Server, t *testing.T) (*AdformAdapter, contex // prepare adapter conf := *adapters.DefaultHTTPAdapterConfig - adapter := NewAdformAdapter(&conf, server.URL) + adapter := NewAdformLegacyAdapter(&conf, server.URL) prebidRequest := preparePrebidRequest(server.URL, t) ctx := context.TODO() @@ -285,7 +299,12 @@ func preparePrebidRequestBody(requestData aBidInfo, t *testing.T) *bytes.Buffer // OpenRTB auction tests func TestOpenRTBRequest(t *testing.T) { - bidder := NewAdformBidder(nil, "http://adx.adform.net") + bidder, buildErr := Builder(openrtb_ext.BidderAdform, config.Adapter{ + Endpoint: "https://adx.adform.net"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } testData := createTestData(true) request := createOpenRtbRequest(&testData) @@ -483,7 +502,7 @@ func TestOpenRTBSurpriseResponse(t *testing.T) { // Properties tests func TestAdformProperties(t *testing.T) { - adapter := NewAdformAdapter(adapters.DefaultHTTPAdapterConfig, "adx.adform.net/adx") + adapter := NewAdformLegacyAdapter(adapters.DefaultHTTPAdapterConfig, "adx.adform.net/adx") if adapter.SkipNoCookies() != false { t.Fatalf("should have been false") @@ -506,12 +525,6 @@ func getRegs() openrtb.Regs { } func getUserExt() []byte { - digitrust := openrtb_ext.ExtUserDigiTrust{ - ID: "digitrustId", - KeyV: 1, - Pref: 0, - } - eids := []openrtb_ext.ExtUserEid{ { Source: "test.com", @@ -537,9 +550,8 @@ func getUserExt() []byte { } userExt := openrtb_ext.ExtUser{ - Eids: eids, - Consent: "abc", - DigiTrust: &digitrust, + Eids: eids, + Consent: "abc", } userExtData, err := json.Marshal(userExt) if err == nil { @@ -611,7 +623,7 @@ func assertAdformServerRequest(testData aBidInfo, r *http.Request, isOpenRtb boo if ok, err := equal(testData.referrer, r.Header.Get("Referer"), "Referer"); !ok { return err } - if ok, err := equal(fmt.Sprintf("uid=%s;DigiTrust.v1.identity=eyJpZCI6ImRpZ2l0cnVzdElkIiwidmVyc2lvbiI6MSwia2V5diI6MSwicHJpdmFjeSI6eyJvcHRvdXQiOmZhbHNlfX0", testData.buyerUID), r.Header.Get("Cookie"), "Buyer ID"); !ok { + if ok, err := equal(fmt.Sprintf("uid=%s;", testData.buyerUID), r.Header.Get("Cookie"), "Buyer ID"); !ok { return err } return nil diff --git a/adapters/adform/adformtest/exemplary/multiformat-impression.json b/adapters/adform/adformtest/exemplary/multiformat-impression.json index efd4aca63e2..5b3067ab927 100644 --- a/adapters/adform/adformtest/exemplary/multiformat-impression.json +++ b/adapters/adform/adformtest/exemplary/multiformat-impression.json @@ -35,7 +35,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://adx.adform.net/adx?CC=1&fd=1&gdpr=&gdpr_consent=&ip=&rp=4&stid=&bWlkPTEyMzQ1JnJjdXI9VVNE&bWlkPTU0MzIxJnJjdXI9VVNE" + "uri": "https://adx.adform.net/adx?CC=1&fd=1&gdpr=&gdpr_consent=&ip=&rp=4&stid=&bWlkPTEyMzQ1JnJjdXI9VVNE&bWlkPTU0MzIxJnJjdXI9VVNE" }, "mockResponse": { "status": 200, diff --git a/adapters/adform/adformtest/exemplary/single-banner-impression.json b/adapters/adform/adformtest/exemplary/single-banner-impression.json index fd7f3cde526..8a5f81c8edb 100644 --- a/adapters/adform/adformtest/exemplary/single-banner-impression.json +++ b/adapters/adform/adformtest/exemplary/single-banner-impression.json @@ -23,7 +23,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://adx.adform.net/adx?CC=1&fd=1&gdpr=&gdpr_consent=&ip=&rp=4&stid=&bWlkPTEyMzQ1JnJjdXI9VVNE" + "uri": "https://adx.adform.net/adx?CC=1&fd=1&gdpr=&gdpr_consent=&ip=&rp=4&stid=&bWlkPTEyMzQ1JnJjdXI9VVNE" }, "mockResponse": { "status": 200, diff --git a/adapters/adform/adformtest/exemplary/single-video-impression.json b/adapters/adform/adformtest/exemplary/single-video-impression.json index e22977e6523..383e091b3f7 100644 --- a/adapters/adform/adformtest/exemplary/single-video-impression.json +++ b/adapters/adform/adformtest/exemplary/single-video-impression.json @@ -19,7 +19,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://adx.adform.net/adx?CC=1&fd=1&gdpr=&gdpr_consent=&ip=&rp=4&stid=&bWlkPTU0MzIxJnJjdXI9VVNE" + "uri": "https://adx.adform.net/adx?CC=1&fd=1&gdpr=&gdpr_consent=&ip=&rp=4&stid=&bWlkPTU0MzIxJnJjdXI9VVNE" }, "mockResponse": { "status": 200, diff --git a/adapters/adform/adformtest/supplemental/user-nil.json b/adapters/adform/adformtest/supplemental/user-nil.json index 96007d58bf1..5f02fe85971 100644 --- a/adapters/adform/adformtest/supplemental/user-nil.json +++ b/adapters/adform/adformtest/supplemental/user-nil.json @@ -44,11 +44,12 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://adx.adform.net/adx?CC=1&fd=1&gdpr=1&gdpr_consent=abc2&ip=&pt=gross&rp=4&stid=&bWlkPTEmcmN1cj1VU0Q" + "uri": "https://adx.adform.net/adx?CC=1&fd=1&gdpr=1&gdpr_consent=abc2&ip=&pt=gross&rp=4&stid=&bWlkPTEmcmN1cj1VU0Q" }, "mockResponse": { "status": 204 } } - ] + ], + "expectedBidResponses": [] } diff --git a/adapters/adgeneration/adgeneration.go b/adapters/adgeneration/adgeneration.go index 376933734bd..59a3ba5b6a2 100644 --- a/adapters/adgeneration/adgeneration.go +++ b/adapters/adgeneration/adgeneration.go @@ -12,6 +12,7 @@ import ( "github.com/PubMatic-OpenWrap/openrtb" "github.com/PubMatic-OpenWrap/prebid-server/adapters" + "github.com/PubMatic-OpenWrap/prebid-server/config" "github.com/PubMatic-OpenWrap/prebid-server/errortypes" "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" ) @@ -258,10 +259,12 @@ func removeWrapper(ad string) string { return str } -func NewAdgenerationAdapter(endpoint string) *AdgenerationAdapter { - return &AdgenerationAdapter{ - endpoint, +// Builder builds a new instance of the Adgeneration adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) { + bidder := &AdgenerationAdapter{ + config.Endpoint, "1.0.2", "JPY", } + return bidder, nil } diff --git a/adapters/adgeneration/adgeneration_test.go b/adapters/adgeneration/adgeneration_test.go index d6152dc760b..a4041a5a1d7 100644 --- a/adapters/adgeneration/adgeneration_test.go +++ b/adapters/adgeneration/adgeneration_test.go @@ -7,15 +7,32 @@ import ( "github.com/PubMatic-OpenWrap/openrtb" "github.com/PubMatic-OpenWrap/prebid-server/adapters" "github.com/PubMatic-OpenWrap/prebid-server/adapters/adapterstest" + "github.com/PubMatic-OpenWrap/prebid-server/config" + "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" "github.com/stretchr/testify/assert" ) func TestJsonSamples(t *testing.T) { - adapterstest.RunJSONBidderTest(t, "adgenerationtest", NewAdgenerationAdapter("https://d.socdm.com/adsv/v1")) + bidder, buildErr := Builder(openrtb_ext.BidderAdgeneration, config.Adapter{ + Endpoint: "https://d.socdm.com/adsv/v1"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "adgenerationtest", bidder) } -func TestGetRequestUri(t *testing.T) { - bidder := NewAdgenerationAdapter("https://d.socdm.com/adsv/v1") +func TestgetRequestUri(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderAdgeneration, config.Adapter{ + Endpoint: "https://d.socdm.com/adsv/v1"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + bidderAdgeneration, _ := bidder.(*AdgenerationAdapter) + // Test items failedRequest := &openrtb.BidRequest{ ID: "test-failed-bid-request", @@ -42,7 +59,7 @@ func TestGetRequestUri(t *testing.T) { numRequests := len(failedRequest.Imp) for index := 0; index < numRequests; index++ { - httpRequests, err := bidder.getRequestUri(failedRequest, index) + httpRequests, err := bidderAdgeneration.getRequestUri(failedRequest, index) if err == nil { t.Errorf("getRequestUri: %v did not throw an error", failedRequest.Imp[index]) } @@ -57,15 +74,15 @@ func TestGetRequestUri(t *testing.T) { if err != nil { t.Errorf("unmarshalExtImpAdgeneration: %v did throw an error: %v", successRequest.Imp[index], err) } - rawQuery := bidder.getRawQuery(adgExt.Id, successRequest, &successRequest.Imp[index]) + rawQuery := bidderAdgeneration.getRawQuery(adgExt.Id, successRequest, &successRequest.Imp[index]) expectQueries := map[string]string{ "posall": "SSPLOC", "id": adgExt.Id, "sdktype": "0", "hb": "true", - "currency": bidder.getCurrency(successRequest), + "currency": bidderAdgeneration.getCurrency(successRequest), "sdkname": "prebidserver", - "adapterver": bidder.version, + "adapterver": bidderAdgeneration.version, "sizes": getSizes(&successRequest.Imp[index]), "tp": successRequest.Site.Page, "transactionid": successRequest.Source.TID, @@ -78,11 +95,11 @@ func TestGetRequestUri(t *testing.T) { } // RequestUri Test. - actualUri, err := bidder.getRequestUri(successRequest, index) + actualUri, err := bidderAdgeneration.getRequestUri(successRequest, index) if err != nil { t.Errorf("getRequestUri: %v did throw an error: %v", successRequest.Imp[index], err) } - expectedUri := "https://d.socdm.com/adsv/v1?adapterver=" + bidder.version + "¤cy=JPY&hb=true&id=58278&posall=SSPLOC&sdkname=prebidserver&sdktype=0&sizes=300x250&t=json3&tp=https%3A%2F%2Fsupership.com&transactionid=SourceTID" + expectedUri := "https://d.socdm.com/adsv/v1?adapterver=" + bidderAdgeneration.version + "¤cy=JPY&hb=true&id=58278&posall=SSPLOC&sdkname=prebidserver&sdktype=0&sizes=300x250&t=json3&tp=https%3A%2F%2Fsupership.com&transactionid=SourceTID" if actualUri != expectedUri { t.Errorf("getRequestUri: does not match expected %s, actual %s", expectedUri, actualUri) } @@ -115,7 +132,15 @@ func TestGetSizes(t *testing.T) { } func TestGetCurrency(t *testing.T) { - bidder := NewAdgenerationAdapter("https://d.socdm.com/adsv/v1") + bidder, buildErr := Builder(openrtb_ext.BidderAdgeneration, config.Adapter{ + Endpoint: "https://d.socdm.com/adsv/v1"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + bidderAdgeneration, _ := bidder.(*AdgenerationAdapter) + // Test items var request *openrtb.BidRequest var currency string @@ -123,12 +148,12 @@ func TestGetCurrency(t *testing.T) { usdCur := []string{"USD", "EUR"} request = &openrtb.BidRequest{Cur: innerDefaultCur} - currency = bidder.getCurrency(request) + currency = bidderAdgeneration.getCurrency(request) if currency != "JPY" { t.Errorf("%v does not match currency.", innerDefaultCur) } request = &openrtb.BidRequest{Cur: usdCur} - currency = bidder.getCurrency(request) + currency = bidderAdgeneration.getCurrency(request) if currency != "USD" { t.Errorf("%v does not match currency.", usdCur) } @@ -178,7 +203,15 @@ func TestCreateAd(t *testing.T) { } func TestMakeBids(t *testing.T) { - bidder := NewAdgenerationAdapter("https://d.socdm.com/adsv/v1") + bidder, buildErr := Builder(openrtb_ext.BidderAdgeneration, config.Adapter{ + Endpoint: "https://d.socdm.com/adsv/v1"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + bidderAdgeneration, _ := bidder.(*AdgenerationAdapter) + internalRequest := &openrtb.BidRequest{ ID: "test-success-bid-request", Imp: []openrtb.Imp{ @@ -198,7 +231,7 @@ func TestMakeBids(t *testing.T) { if len(errs) > 0 { t.Errorf("MakeBids return errors. errors: %v", errs) } - checkBidResponse(t, defaultCurBidderResponse, bidder.defaultCurrency) + checkBidResponse(t, defaultCurBidderResponse, bidderAdgeneration.defaultCurrency) // Specified Currency InternalRequest usdCur := "USD" diff --git a/adapters/adhese/adhese.go b/adapters/adhese/adhese.go index c6a16ed051e..96a936c2276 100644 --- a/adapters/adhese/adhese.go +++ b/adapters/adhese/adhese.go @@ -12,6 +12,7 @@ import ( "github.com/PubMatic-OpenWrap/openrtb" "github.com/PubMatic-OpenWrap/prebid-server/adapters" + "github.com/PubMatic-OpenWrap/prebid-server/config" "github.com/PubMatic-OpenWrap/prebid-server/errortypes" "github.com/PubMatic-OpenWrap/prebid-server/macros" "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" @@ -267,11 +268,15 @@ func ContainsAny(raw string, keys []string) bool { } -func NewAdheseBidder(uri string) *AdheseAdapter { - template, err := template.New("endpointTemplate").Parse(uri) +// Builder builds a new instance of the Adhese adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) { + template, err := template.New("endpointTemplate").Parse(config.Endpoint) if err != nil { - glog.Fatal("Unable to parse endpoint url template") - return nil + return nil, fmt.Errorf("unable to parse endpoint url template: %v", err) } - return &AdheseAdapter{endpointTemplate: *template} + + bidder := &AdheseAdapter{ + endpointTemplate: *template, + } + return bidder, nil } diff --git a/adapters/adhese/adhese_test.go b/adapters/adhese/adhese_test.go index 6078d436cfe..40b28887c20 100644 --- a/adapters/adhese/adhese_test.go +++ b/adapters/adhese/adhese_test.go @@ -4,8 +4,25 @@ import ( "testing" "github.com/PubMatic-OpenWrap/prebid-server/adapters/adapterstest" + "github.com/PubMatic-OpenWrap/prebid-server/config" + "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" + "github.com/stretchr/testify/assert" ) func TestJsonSamples(t *testing.T) { - adapterstest.RunJSONBidderTest(t, "adhesetest", NewAdheseBidder("https://ads-{{.AccountID}}.adhese.com/json")) + bidder, buildErr := Builder(openrtb_ext.BidderAdhese, config.Adapter{ + Endpoint: "https://ads-{{.AccountID}}.adhese.com/json"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "adhesetest", bidder) +} + +func TestEndpointTemplateMalformed(t *testing.T) { + _, buildErr := Builder(openrtb_ext.BidderAdhese, config.Adapter{ + Endpoint: "{{Malformed}}"}) + + assert.Error(t, buildErr) } diff --git a/adapters/adkernel/adkernel.go b/adapters/adkernel/adkernel.go index 2c78d104839..f483ba7ce49 100644 --- a/adapters/adkernel/adkernel.go +++ b/adapters/adkernel/adkernel.go @@ -9,10 +9,10 @@ import ( "github.com/PubMatic-OpenWrap/openrtb" "github.com/PubMatic-OpenWrap/prebid-server/adapters" + "github.com/PubMatic-OpenWrap/prebid-server/config" "github.com/PubMatic-OpenWrap/prebid-server/errortypes" "github.com/PubMatic-OpenWrap/prebid-server/macros" "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" - "github.com/golang/glog" ) type adkernelAdapter struct { @@ -254,12 +254,15 @@ func newBadServerResponseError(message string) error { } } -// NewAdkernelAdapter to be called in prebid-server core to create Adkernel adapter instance -func NewAdkernelAdapter(endpointTemplate string) adapters.Bidder { - urlTemplate, err := template.New("endpointTemplate").Parse(endpointTemplate) +// Builder builds a new instance of the Adkernel adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) { + urlTemplate, err := template.New("endpointTemplate").Parse(config.Endpoint) if err != nil { - glog.Fatal("Unable to parse endpoint url template") - return nil + return nil, fmt.Errorf("unable to parse endpoint url template: %v", err) } - return &adkernelAdapter{EndpointTemplate: *urlTemplate} + + bidder := &adkernelAdapter{ + EndpointTemplate: *urlTemplate, + } + return bidder, nil } diff --git a/adapters/adkernel/adkernel_test.go b/adapters/adkernel/adkernel_test.go index f7cb9a22a9e..a85769f5565 100644 --- a/adapters/adkernel/adkernel_test.go +++ b/adapters/adkernel/adkernel_test.go @@ -4,8 +4,25 @@ import ( "testing" "github.com/PubMatic-OpenWrap/prebid-server/adapters/adapterstest" + "github.com/PubMatic-OpenWrap/prebid-server/config" + "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" + "github.com/stretchr/testify/assert" ) func TestJsonSamples(t *testing.T) { - adapterstest.RunJSONBidderTest(t, "adkerneltest", NewAdkernelAdapter("http://{{.Host}}/hb?zone={{.ZoneID}}")) + bidder, buildErr := Builder(openrtb_ext.BidderAdkernel, config.Adapter{ + Endpoint: "http://{{.Host}}/hb?zone={{.ZoneID}}"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "adkerneltest", bidder) +} + +func TestEndpointTemplateMalformed(t *testing.T) { + _, buildErr := Builder(openrtb_ext.BidderAdkernel, config.Adapter{ + Endpoint: "{{Malformed}}"}) + + assert.Error(t, buildErr) } diff --git a/adapters/adkernelAdn/adkernelAdn.go b/adapters/adkernelAdn/adkernelAdn.go index 14100d48dac..491bead4e8b 100644 --- a/adapters/adkernelAdn/adkernelAdn.go +++ b/adapters/adkernelAdn/adkernelAdn.go @@ -9,10 +9,10 @@ import ( "github.com/PubMatic-OpenWrap/openrtb" "github.com/PubMatic-OpenWrap/prebid-server/adapters" + "github.com/PubMatic-OpenWrap/prebid-server/config" "github.com/PubMatic-OpenWrap/prebid-server/errortypes" "github.com/PubMatic-OpenWrap/prebid-server/macros" "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" - "github.com/golang/glog" ) const defaultDomain string = "tag.adkernel.com" @@ -278,12 +278,15 @@ func newBadServerResponseError(message string) error { } } -// NewAdkernelAdnAdapter to be called in prebid-server core to create AdkernelAdn adapter instance -func NewAdkernelAdnAdapter(endpointTemplate string) adapters.Bidder { - template, err := template.New("endpointTemplate").Parse(endpointTemplate) +// Builder builds a new instance of the AdkernelAdn adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) { + template, err := template.New("endpointTemplate").Parse(config.Endpoint) if err != nil { - glog.Fatal("Unable to parse endpoint url template") - return nil + return nil, fmt.Errorf("unable to parse endpoint url template: %v", err) } - return &adkernelAdnAdapter{EndpointTemplate: *template} + + bidder := &adkernelAdnAdapter{ + EndpointTemplate: *template, + } + return bidder, nil } diff --git a/adapters/adkernelAdn/adkernelAdn_test.go b/adapters/adkernelAdn/adkernelAdn_test.go index e8145723822..a4311d3e550 100644 --- a/adapters/adkernelAdn/adkernelAdn_test.go +++ b/adapters/adkernelAdn/adkernelAdn_test.go @@ -4,8 +4,25 @@ import ( "testing" "github.com/PubMatic-OpenWrap/prebid-server/adapters/adapterstest" + "github.com/PubMatic-OpenWrap/prebid-server/config" + "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" + "github.com/stretchr/testify/assert" ) func TestJsonSamples(t *testing.T) { - adapterstest.RunJSONBidderTest(t, "adkerneladntest", NewAdkernelAdnAdapter("http://{{.Host}}/rtbpub?account={{.PublisherID}}")) + bidder, buildErr := Builder(openrtb_ext.BidderAdkernelAdn, config.Adapter{ + Endpoint: "http://{{.Host}}/rtbpub?account={{.PublisherID}}"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "adkerneladntest", bidder) +} + +func TestEndpointTemplateMalformed(t *testing.T) { + _, buildErr := Builder(openrtb_ext.BidderAdkernelAdn, config.Adapter{ + Endpoint: "{{Malformed}}"}) + + assert.Error(t, buildErr) } diff --git a/adapters/adman/adman.go b/adapters/adman/adman.go index b6276a9fac3..3c0342fe24f 100644 --- a/adapters/adman/adman.go +++ b/adapters/adman/adman.go @@ -7,6 +7,7 @@ import ( "github.com/PubMatic-OpenWrap/openrtb" "github.com/PubMatic-OpenWrap/prebid-server/adapters" + "github.com/PubMatic-OpenWrap/prebid-server/config" "github.com/PubMatic-OpenWrap/prebid-server/errortypes" "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" ) @@ -16,11 +17,12 @@ type AdmanAdapter struct { URI string } -// NewAdmanBidder Initializes the Bidder -func NewAdmanBidder(endpoint string) *AdmanAdapter { - return &AdmanAdapter{ - URI: endpoint, +// Builder builds a new instance of the Adman adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) { + bidder := &AdmanAdapter{ + URI: config.Endpoint, } + return bidder, nil } type admanParams struct { diff --git a/adapters/adman/adman_test.go b/adapters/adman/adman_test.go index 66d84aa8b81..5dc10df8dad 100644 --- a/adapters/adman/adman_test.go +++ b/adapters/adman/adman_test.go @@ -4,9 +4,17 @@ import ( "testing" "github.com/PubMatic-OpenWrap/prebid-server/adapters/adapterstest" + "github.com/PubMatic-OpenWrap/prebid-server/config" + "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" ) func TestJsonSamples(t *testing.T) { - admanAdapter := NewAdmanBidder("http://pub.admanmedia.com/?c=o&m=ortb") - adapterstest.RunJSONBidderTest(t, "admantest", admanAdapter) + bidder, buildErr := Builder(openrtb_ext.BidderAdman, config.Adapter{ + Endpoint: "http://pub.admanmedia.com/?c=o&m=ortb"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "admantest", bidder) } diff --git a/adapters/adman/admantest/supplemental/status-204.json b/adapters/adman/admantest/supplemental/status-204.json index 72b28bffdcf..a659754e8b0 100644 --- a/adapters/adman/admantest/supplemental/status-204.json +++ b/adapters/adman/admantest/supplemental/status-204.json @@ -1,79 +1,82 @@ { - "mockBidRequest": { - "id": "test-request-id", - "imp": [ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ { - "id": "test-imp-id", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - }, - { - "w": 300, - "h": 600 - } - ] - }, - "tagid": "17", - "ext": { - "bidder": { - "TagID": "17" - } + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "tagid": "17", + "ext": { + "bidder": { + "TagID": "17" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://pub.admanmedia.com/?c=o&m=ortb", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "tagid": "17", + "ext": { + "bidder": { + "TagID": "17" } + } } - ], - "app": { + ], + "app": { "id": "1", "bundle": "com.wls.testwlsapplication" - }, - "device": { + }, + "device": { "ip": "123.123.123.123", "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } } - }, - "httpCalls": [{ - "expectedRequest": { - "uri": "http://pub.admanmedia.com/?c=o&m=ortb", - "body": { - "id": "test-request-id", - "imp": [ - { - "id": "test-imp-id", - "banner": { - "format": [ - { - "w": 300, - "h": 250 - }, - { - "w": 300, - "h": 600 - } - ] - }, - "tagid": "17", - "ext": { - "bidder": { - "TagID": "17" - } - } - } - ], - "app": { - "id": "1", - "bundle": "com.wls.testwlsapplication" - }, - "device": { - "ip": "123.123.123.123", - "ifa": "sdjfksdf-dfsds-dsdg-dsgg" - } - } - }, - "mockResponse": { - "status": 204, - "body": {} - } - }] + }, + "mockResponse": { + "status": 204, + "body": {} + } + } + ], + "expectedBidResponses": [] } diff --git a/adapters/admixer/admixer.go b/adapters/admixer/admixer.go index 18f8331d45e..b16dc0073d4 100644 --- a/adapters/admixer/admixer.go +++ b/adapters/admixer/admixer.go @@ -3,19 +3,25 @@ package admixer import ( "encoding/json" "fmt" + "net/http" + "github.com/PubMatic-OpenWrap/openrtb" "github.com/PubMatic-OpenWrap/prebid-server/adapters" + "github.com/PubMatic-OpenWrap/prebid-server/config" "github.com/PubMatic-OpenWrap/prebid-server/errortypes" "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" - "net/http" ) type AdmixerAdapter struct { endpoint string } -func NewAdmixerBidder(endpoint string) *AdmixerAdapter { - return &AdmixerAdapter{endpoint: endpoint} +// Builder builds a new instance of the Admixer adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) { + bidder := &AdmixerAdapter{ + endpoint: config.Endpoint, + } + return bidder, nil } type admixerImpExt struct { diff --git a/adapters/admixer/admixer_test.go b/adapters/admixer/admixer_test.go index c8df05f73a7..629d4df83cd 100644 --- a/adapters/admixer/admixer_test.go +++ b/adapters/admixer/admixer_test.go @@ -1,10 +1,20 @@ package admixer import ( - "github.com/PubMatic-OpenWrap/prebid-server/adapters/adapterstest" "testing" + + "github.com/PubMatic-OpenWrap/prebid-server/adapters/adapterstest" + "github.com/PubMatic-OpenWrap/prebid-server/config" + "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" ) func TestJsonSamples(t *testing.T) { - adapterstest.RunJSONBidderTest(t, "admixertest", NewAdmixerBidder("http://inv-nets.admixer.net/pbs.aspx")) + bidder, buildErr := Builder(openrtb_ext.BidderAdmixer, config.Adapter{ + Endpoint: "http://inv-nets.admixer.net/pbs.aspx"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "admixertest", bidder) } diff --git a/adapters/admixer/admixertest/exemplary/optional-params.json b/adapters/admixer/admixertest/exemplary/optional-params.json index 42a55ec95e8..8ef112bbdb5 100644 --- a/adapters/admixer/admixertest/exemplary/optional-params.json +++ b/adapters/admixer/admixertest/exemplary/optional-params.json @@ -100,5 +100,6 @@ "status": 204 } } - ] + ], + "expectedBidResponses": [] } diff --git a/adapters/admixer/usersync_test.go b/adapters/admixer/usersync_test.go index cffe596cdce..8a43b866804 100644 --- a/adapters/admixer/usersync_test.go +++ b/adapters/admixer/usersync_test.go @@ -11,7 +11,7 @@ import ( ) func TestAdmixerSyncer(t *testing.T) { - syncURL := "https://inv-nets.admixer.net/adxcm.aspx?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&redir=1&rurl=localhost%2Fsetuid%3Fbidder%3Dadmixer%26gdpr%3D{{.GDPR}}%26gdpr_consent%3D{{.GDPRConsent}}%26uid%3D%24%24visitor_cookie%24%24" + syncURL := "http://anyHost/anyPath" syncURLTemplate := template.Must( template.New("sync-template").Parse(syncURL), ) @@ -28,7 +28,7 @@ func TestAdmixerSyncer(t *testing.T) { }) assert.NoError(t, err) - assert.Equal(t, "https://inv-nets.admixer.net/adxcm.aspx?gdpr=A&gdpr_consent=B&us_privacy=C&redir=1&rurl=localhost%2Fsetuid%3Fbidder%3Dadmixer%26gdpr%3DA%26gdpr_consent%3DB%26uid%3D%24%24visitor_cookie%24%24", syncInfo.URL) + assert.Equal(t, "http://anyHost/anyPath", syncInfo.URL) assert.Equal(t, "redirect", syncInfo.Type) assert.EqualValues(t, 511, syncer.GDPRVendorID()) assert.Equal(t, false, syncInfo.SupportCORS) diff --git a/adapters/adocean/adocean.go b/adapters/adocean/adocean.go index a70fc5ba1cb..8310626fcec 100644 --- a/adapters/adocean/adocean.go +++ b/adapters/adocean/adocean.go @@ -2,6 +2,7 @@ package adocean import ( "encoding/json" + "errors" "fmt" "math/rand" "net/http" @@ -14,10 +15,10 @@ import ( "github.com/PubMatic-OpenWrap/openrtb" "github.com/PubMatic-OpenWrap/prebid-server/adapters" + "github.com/PubMatic-OpenWrap/prebid-server/config" "github.com/PubMatic-OpenWrap/prebid-server/errortypes" "github.com/PubMatic-OpenWrap/prebid-server/macros" "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" - "github.com/golang/glog" ) const adapterVersion = "1.1.0" @@ -58,25 +59,23 @@ type requestData struct { SlaveSizes map[string]string } -func NewAdOceanBidder(client *http.Client, endpointTemplateString string) *AdOceanAdapter { - a := &adapters.HTTPAdapter{Client: client} - endpointTemplate, err := template.New("endpointTemplate").Parse(endpointTemplateString) +// Builder builds a new instance of the AdOcean adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) { + endpointTemplate, err := template.New("endpointTemplate").Parse(config.Endpoint) if err != nil { - glog.Fatal("Unable to parse endpoint template") - return nil + return nil, errors.New("Unable to parse endpoint template") } whiteSpace := regexp.MustCompile(`\s+`) - return &AdOceanAdapter{ - http: a, + bidder := &AdOceanAdapter{ endpointTemplate: *endpointTemplate, measurementCode: whiteSpace.ReplaceAllString(measurementCode, " "), } + return bidder, nil } type AdOceanAdapter struct { - http *adapters.HTTPAdapter endpointTemplate template.Template measurementCode string } diff --git a/adapters/adocean/adocean_test.go b/adapters/adocean/adocean_test.go index 1088fedd30e..b75de2a9235 100644 --- a/adapters/adocean/adocean_test.go +++ b/adapters/adocean/adocean_test.go @@ -1,12 +1,28 @@ package adocean import ( - "net/http" "testing" "github.com/PubMatic-OpenWrap/prebid-server/adapters/adapterstest" + "github.com/PubMatic-OpenWrap/prebid-server/config" + "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" + "github.com/stretchr/testify/assert" ) func TestJsonSamples(t *testing.T) { - adapterstest.RunJSONBidderTest(t, "adoceantest", NewAdOceanBidder(new(http.Client), "https://{{.Host}}")) + bidder, buildErr := Builder(openrtb_ext.BidderAdOcean, config.Adapter{ + Endpoint: "https://{{.Host}}"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "adoceantest", bidder) +} + +func TestEndpointTemplateMalformed(t *testing.T) { + _, buildErr := Builder(openrtb_ext.BidderAdOcean, config.Adapter{ + Endpoint: "{{Malformed}}"}) + + assert.Error(t, buildErr) } diff --git a/adapters/adoppler/adoppler.go b/adapters/adoppler/adoppler.go index 717ad6211d1..498bb4c7cc0 100644 --- a/adapters/adoppler/adoppler.go +++ b/adapters/adoppler/adoppler.go @@ -10,10 +10,10 @@ import ( "github.com/PubMatic-OpenWrap/openrtb" "github.com/PubMatic-OpenWrap/prebid-server/adapters" + "github.com/PubMatic-OpenWrap/prebid-server/config" "github.com/PubMatic-OpenWrap/prebid-server/errortypes" "github.com/PubMatic-OpenWrap/prebid-server/macros" "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" - "github.com/golang/glog" ) const DefaultClient = "app" @@ -36,14 +36,17 @@ type AdopplerAdapter struct { endpoint *template.Template } -func NewAdopplerBidder(endpoint string) *AdopplerAdapter { - t, err := template.New("endpoint").Parse(endpoint) +// Builder builds a new instance of the Adoppler adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) { + template, err := template.New("endpointTemplate").Parse(config.Endpoint) if err != nil { - glog.Fatalf("Unable to parse endpoint url template: %s", err) - return nil + return nil, fmt.Errorf("unable to parse endpoint url template: %v", err) } - return &AdopplerAdapter{t} + bidder := &AdopplerAdapter{ + endpoint: template, + } + return bidder, nil } func (ads *AdopplerAdapter) MakeRequests( diff --git a/adapters/adoppler/adoppler_test.go b/adapters/adoppler/adoppler_test.go index 775524b171d..eab0ac5708d 100644 --- a/adapters/adoppler/adoppler_test.go +++ b/adapters/adoppler/adoppler_test.go @@ -4,9 +4,17 @@ import ( "testing" "github.com/PubMatic-OpenWrap/prebid-server/adapters/adapterstest" + "github.com/PubMatic-OpenWrap/prebid-server/config" + "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" ) func TestJsonSamples(t *testing.T) { - bidder := NewAdopplerBidder("http://{{.AccountID}}.trustedmarketplace.com/processHeaderBid/{{.AdUnit}}") + bidder, buildErr := Builder(openrtb_ext.BidderAdoppler, config.Adapter{ + Endpoint: "http://{{.AccountID}}.trustedmarketplace.com/processHeaderBid/{{.AdUnit}}"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + adapterstest.RunJSONBidderTest(t, "adopplertest", bidder) } diff --git a/adapters/adot/adot.go b/adapters/adot/adot.go new file mode 100644 index 00000000000..fcbb5a2906d --- /dev/null +++ b/adapters/adot/adot.go @@ -0,0 +1,117 @@ +package adot + +import ( + "encoding/json" + "fmt" + "github.com/PubMatic-OpenWrap/openrtb" + "github.com/PubMatic-OpenWrap/prebid-server/adapters" + "github.com/PubMatic-OpenWrap/prebid-server/config" + "github.com/PubMatic-OpenWrap/prebid-server/errortypes" + "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" + "net/http" +) + +type adapter struct { + endpoint string +} + +type adotBidExt struct { + Adot bidExt `json:"adot"` +} + +type bidExt struct { + MediaType string `json:"media_type"` +} + +// Builder builds a new instance of the Adot adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) { + bidder := &adapter{ + endpoint: config.Endpoint, + } + return bidder, nil +} + +// MakeRequests makes the HTTP requests which should be made to fetch bids. +func (a *adapter) MakeRequests(request *openrtb.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + var reqJSON []byte + var err error + + if reqJSON, err = json.Marshal(request); err != nil { + return nil, []error{fmt.Errorf("unable to marshal openrtb request (%v)", err)} + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + + return []*adapters.RequestData{{ + Method: "POST", + Uri: a.endpoint, + Body: reqJSON, + Headers: headers, + }}, nil +} + +// MakeBids unpacks the server's response into Bids. +// The bidder return a status code 204 when it cannot delivery an ad. +func (a *adapter) MakeBids(internalRequest *openrtb.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 bidResp openrtb.BidResponse + if err := json.Unmarshal(response.Body, &bidResp); err != nil { + return nil, []error{err} + } + + bidsCapacity := 1 + if len(bidResp.SeatBid) > 0 { + bidsCapacity = len(bidResp.SeatBid[0].Bid) + } + bidResponse := adapters.NewBidderResponseWithBidsCapacity(bidsCapacity) + + for _, sb := range bidResp.SeatBid { + for i := range sb.Bid { + if bidType, err := getMediaTypeForBid(&sb.Bid[i]); err == nil { + bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ + Bid: &sb.Bid[i], + BidType: bidType, + }) + } + } + } + + return bidResponse, nil +} + +// getMediaTypeForBid determines which type of bid. +func getMediaTypeForBid(bid *openrtb.Bid) (openrtb_ext.BidType, error) { + if bid == nil { + return "", fmt.Errorf("the bid request object is nil") + } + + var impExt adotBidExt + if err := json.Unmarshal(bid.Ext, &impExt); err == nil { + switch impExt.Adot.MediaType { + case string(openrtb_ext.BidTypeBanner): + return openrtb_ext.BidTypeBanner, nil + case string(openrtb_ext.BidTypeVideo): + return openrtb_ext.BidTypeVideo, nil + case string(openrtb_ext.BidTypeNative): + return openrtb_ext.BidTypeNative, nil + } + } + + return "", fmt.Errorf("unrecognized bid type in response from adot") +} diff --git a/adapters/adot/adot_test.go b/adapters/adot/adot_test.go new file mode 100644 index 00000000000..2e6e74861d4 --- /dev/null +++ b/adapters/adot/adot_test.go @@ -0,0 +1,76 @@ +package adot + +import ( + "encoding/json" + "github.com/PubMatic-OpenWrap/openrtb" + "github.com/PubMatic-OpenWrap/prebid-server/adapters" + "github.com/PubMatic-OpenWrap/prebid-server/adapters/adapterstest" + "github.com/PubMatic-OpenWrap/prebid-server/config" + "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" + "github.com/stretchr/testify/assert" + "testing" +) + +const testsBidderEndpoint = "https://dsp.adotmob.com/headerbidding/bidrequest" + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderAdot, config.Adapter{ + Endpoint: testsBidderEndpoint}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "adottest", bidder) +} + +//Test the media type error +func TestMediaTypeError(t *testing.T) { + _, err := getMediaTypeForBid(nil) + + assert.Error(t, err) + + byteInvalid, _ := json.Marshal(&adotBidExt{Adot: bidExt{"invalid"}}) + _, err = getMediaTypeForBid(&openrtb.Bid{Ext: json.RawMessage(byteInvalid)}) + + assert.Error(t, err) +} + +//Test the bid response when the bidder return a status code 204 +func TestBidResponseNoContent(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderAdot, config.Adapter{ + Endpoint: "https://dsp.adotmob.com/headerbidding/bidrequest"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + bidResponse, err := bidder.MakeBids(nil, nil, &adapters.ResponseData{StatusCode: 204}) + if bidResponse != nil { + t.Fatalf("the bid response should be nil since the bidder status is No Content") + } else if err != nil { + t.Fatalf("the error should be nil since the bidder status is 204 : No Content") + } +} + +//Test the media type for a bid response +func TestMediaTypeForBid(t *testing.T) { + byteBanner, _ := json.Marshal(&adotBidExt{Adot: bidExt{"banner"}}) + byteVideo, _ := json.Marshal(&adotBidExt{Adot: bidExt{"video"}}) + byteNative, _ := json.Marshal(&adotBidExt{Adot: bidExt{"native"}}) + + bidTypeBanner, _ := getMediaTypeForBid(&openrtb.Bid{Ext: json.RawMessage(byteBanner)}) + if bidTypeBanner != openrtb_ext.BidTypeBanner { + t.Errorf("the type is not the valid one. actual: %v, expected: %v", bidTypeBanner, openrtb_ext.BidTypeBanner) + } + + bidTypeVideo, _ := getMediaTypeForBid(&openrtb.Bid{Ext: json.RawMessage(byteVideo)}) + if bidTypeVideo != openrtb_ext.BidTypeVideo { + t.Errorf("the type is not the valid one. actual: %v, expected: %v", bidTypeVideo, openrtb_ext.BidTypeVideo) + } + + bidTypeNative, _ := getMediaTypeForBid(&openrtb.Bid{Ext: json.RawMessage(byteNative)}) + if bidTypeNative != openrtb_ext.BidTypeNative { + t.Errorf("the type is not the valid one. actual: %v, expected: %v", bidTypeNative, openrtb_ext.BidTypeVideo) + } +} diff --git a/adapters/adot/adottest/exemplary/simple-banner.json b/adapters/adot/adottest/exemplary/simple-banner.json new file mode 100644 index 00000000000..1b8cb9867f6 --- /dev/null +++ b/adapters/adot/adottest/exemplary/simple-banner.json @@ -0,0 +1,94 @@ +{ + "mockBidRequest": { + "id": "test-request-banner-id", + "imp": [ + { + "id": "test-imp-banner-id", + "banner": { + "format": [ + { + "w": 320, + "h": 250 + } + ], + "w": 320, + "h": 250 + }, + "ext": { + "adot": {} + } + } + ] + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "https://dsp.adotmob.com/headerbidding/bidrequest", + "body": { + "id": "test-request-banner-id", + "imp": [ + { + "id": "test-imp-banner-id", + "banner": { + "format": [ + { + "w": 320, + "h": 250 + } + ], + "w": 320, + "h": 250 + }, + "ext": { + "adot": {} + } + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-banner-id", + "seatbid": [{ + "seat": "adot", + "bid": [{ + "id": "test-request-banner-id", + "impid": "test-imp-banner-id", + "price": 1.16346, + "adm": "some-test-ad", + "w": 320, + "h": 50, + "ext": { + "adot": { + "media_type": "banner" + } + } + }] + } + ], + "cur": "USD" + } + } + }], + + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "test-request-banner-id", + "impid": "test-imp-banner-id", + "price": 1.16346, + "adm": "some-test-ad", + "w": 320, + "h": 50, + "ext": { + "adot": { + "media_type": "banner" + } + } + }, + "type": "banner" + }] + }] +} + diff --git a/adapters/adot/adottest/exemplary/simple-interstitial.json b/adapters/adot/adottest/exemplary/simple-interstitial.json new file mode 100644 index 00000000000..0e9b573a530 --- /dev/null +++ b/adapters/adot/adottest/exemplary/simple-interstitial.json @@ -0,0 +1,101 @@ +{ + "mockBidRequest": { + "id": "test-request-inter-id", + "imp": [ + { + "id": "test-imp-inter-id", + "banner": { + "format": [ + { + "w": 320, + "h": 480 + } + ], + "w": 320, + "h": 480 + }, + "instl":1, + "ext": { + "adot": {} + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://dsp.adotmob.com/headerbidding/bidrequest", + "body": { + "id": "test-request-inter-id", + "imp": [ + { + "id": "test-imp-inter-id", + "banner": { + "format": [ + { + "w": 320, + "h": 480 + } + ], + "w": 320, + "h": 480 + }, + "instl":1, + "ext": { + "adot": {} + } + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "adot", + "bid": [{ + "id": "test-request-inter-id", + "impid": "test-imp-inter-id", + "adm": "some-test-ad", + "price": 1.16346, + "w": 320, + "h": 480, + "ext": { + "adot": { + "media_type": "banner" + } + } + }] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "bids": [{ + "bid": { + "id": "test-request-inter-id", + "impid": "test-imp-inter-id", + "price": 1.16346, + "adm": "some-test-ad", + "w": 320, + "h": 480, + "ext": { + "adot": { + "media_type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} + diff --git a/adapters/adot/adottest/exemplary/simple-native.json b/adapters/adot/adottest/exemplary/simple-native.json new file mode 100644 index 00000000000..5fa3c70fd73 --- /dev/null +++ b/adapters/adot/adottest/exemplary/simple-native.json @@ -0,0 +1,88 @@ +{ + "mockBidRequest": { + "id": "test-request-native-id", + "imp": [ + { + "id": "test-imp-native-id", + "native": { + "request": "test-native", + "ver": "1.1" + }, + "ext": { + "adot": {} + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://dsp.adotmob.com/headerbidding/bidrequest", + "body": { + "id": "test-request-native-id", + "imp": [ + { + "id": "test-imp-native-id", + "native": { + "request": "test-native", + "ver": "1.1" + }, + "ext": { + "adot": {} + } + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "adot", + "bid": [{ + "id": "test-request-native-id", + "impid": "test-imp-native-id", + "price": 1.16346, + "adm" : "native-ad", + "w": 300, + "h": 250, + "ext": { + "adot": { + "media_type": "native" + } + } + }] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "test-request-native-id", + "impid": "test-imp-native-id", + "price": 1.16346, + "adm" : "native-ad", + "w": 300, + "h": 250, + "ext": { + "adot": { + "media_type": "native" + } + } + }, + "type": "native" + } + ] + } + ] +} + diff --git a/adapters/adot/adottest/exemplary/simple-video.json b/adapters/adot/adottest/exemplary/simple-video.json new file mode 100644 index 00000000000..a453c4b9e18 --- /dev/null +++ b/adapters/adot/adottest/exemplary/simple-video.json @@ -0,0 +1,120 @@ +{ + "mockBidRequest": { + "id": "test-request-video-id", + "imp": [ + { + "id": "test-imp-video-id", + "video": { + "w": 300, + "h": 250, + "maxduration": 60, + "minduration": 1, + "api": [ + 1, + 2, + 5, + 6, + 7 + ], + "mimes": [ + "video\/mp4" + ], + "placement": 4, + "protocols": [ + 2 + ] + }, + "ext": { + "adot": {} + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://dsp.adotmob.com/headerbidding/bidrequest", + "body": { + "id": "test-request-video-id", + "imp": [ + { + "id": "test-imp-video-id", + "video": { + "w": 300, + "h": 250, + "maxduration": 60, + "minduration": 1, + "api": [ + 1, + 2, + 5, + 6, + 7 + ], + "mimes": [ + "video\/mp4" + ], + "placement": 4, + "protocols": [ + 2 + ] + }, + "ext": { + "adot": {} + } + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "adot", + "bid": [{ + "id": "test-request-video-id", + "impid": "test-imp-video-id", + "price": 1.16346, + "adm": "some-test-ad", + "w": 300, + "h": 250, + "ext": { + "adot": { + "media_type": "video" + } + } + }] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "test-request-video-id", + "impid": "test-imp-video-id", + "price": 1.16346, + "adm": "some-test-ad", + "w": 300, + "h": 250, + "ext": { + "adot": { + "media_type": "video" + } + } + }, + "type": "video" + } + ] + } + ] +} + diff --git a/adapters/adot/adottest/params/race/banner.json b/adapters/adot/adottest/params/race/banner.json new file mode 100644 index 00000000000..ada77aa4440 --- /dev/null +++ b/adapters/adot/adottest/params/race/banner.json @@ -0,0 +1,3 @@ +{ + "placementId": "ee234aac-113" +} \ No newline at end of file diff --git a/adapters/adot/adottest/params/race/video.json b/adapters/adot/adottest/params/race/video.json new file mode 100644 index 00000000000..37808cd2ddc --- /dev/null +++ b/adapters/adot/adottest/params/race/video.json @@ -0,0 +1,3 @@ +{ + "placementId": "ee234aac-112" +} \ No newline at end of file diff --git a/adapters/adot/adottest/supplemental/simple-audio.json b/adapters/adot/adottest/supplemental/simple-audio.json new file mode 100644 index 00000000000..9be53c4cee9 --- /dev/null +++ b/adapters/adot/adottest/supplemental/simple-audio.json @@ -0,0 +1,66 @@ +{ + "mockBidRequest": { + "id": "unsupported-audio-request", + "imp": [ + { + "id": "unsupported-audio-imp", + "audio": { + "mimes": ["video/mp4"] + }, + "ext": { + "bidder": { + "placementId": 1 + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://dsp.adotmob.com/headerbidding/bidrequest", + "body": { + "id": "unsupported-audio-request", + "imp": [ + { + "id": "unsupported-audio-imp", + "audio": { + "mimes": ["video/mp4"] + }, + "ext": { + "bidder": { + "placementId": 1 + } + } + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "adot", + "bid": [{ + "id": "test-request-audio-id", + "impid": "test-imp-audio-id", + "price": 1.16346, + "adm": "some-audio-ad", + "ext": { + "adot": { + "media_type": "audio" + } + } + }] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [] +} diff --git a/adapters/adot/adottest/supplemental/simple-parallax.json b/adapters/adot/adottest/supplemental/simple-parallax.json new file mode 100644 index 00000000000..4ee2ebc22d0 --- /dev/null +++ b/adapters/adot/adottest/supplemental/simple-parallax.json @@ -0,0 +1,103 @@ +{ + "mockBidRequest": { + "id": "test-request-parallax-id", + "imp": [ + { + "id": "test-imp-parallax-id", + "banner": { + "format": [ + { + "w": 300, + "h": 600 + } + ], + "w": 300, + "h": 600 + }, + "ext": { + "adot": { + "parallax": true + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://dsp.adotmob.com/headerbidding/bidrequest", + "body": { + "id": "test-request-parallax-id", + "imp": [ + { + "id": "test-imp-parallax-id", + "banner": { + "format": [ + { + "w": 300, + "h": 600 + } + ], + "w": 300, + "h": 600 + }, + "ext": { + "adot": { + "parallax": true + } + } + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "adot", + "bid": [{ + "id": "test-request-parallax-id", + "impid": "test-imp-parallax-id", + "price": 0.5, + "adm": "some-test-ad", + "w": 300, + "h": 600, + "ext": { + "adot": { + "media_type": "banner" + } + } + }] + } + ], + "cur": "USD" + } + } + } + ], + + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "test-request-parallax-id", + "impid": "test-imp-parallax-id", + "price": 0.5, + "adm": "some-test-ad", + "w": 300, + "h": 600, + "ext": { + "adot": { + "media_type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/adot/adottest/supplemental/status_204.json b/adapters/adot/adottest/supplemental/status_204.json new file mode 100644 index 00000000000..44a895b5c24 --- /dev/null +++ b/adapters/adot/adottest/supplemental/status_204.json @@ -0,0 +1,39 @@ +{ + "mockBidRequest": { + "id": "test-request-banner-id", + "imp": [ + { + "id": "test-imp-banner-id", + "banner": {}, + "ext": { + "adot": {} + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://dsp.adotmob.com/headerbidding/bidrequest", + "body": { + "id": "test-request-banner-id", + "imp": [ + { + "id": "test-imp-banner-id", + "banner": {}, + "ext": { + "adot": {} + } + } + ] + } + }, + "mockResponse": { + "status": 204, + "body": {} + } + } + ], + "expectedBidResponses": [] +} + diff --git a/adapters/adot/adottest/supplemental/status_400.json b/adapters/adot/adottest/supplemental/status_400.json new file mode 100644 index 00000000000..22328fd9908 --- /dev/null +++ b/adapters/adot/adottest/supplemental/status_400.json @@ -0,0 +1,62 @@ +{ + "mockBidRequest": { + "id": "test-request-banner-id", + "imp": [ + { + "id": "test-imp-banner-id", + "banner": { + "format": [ + { + "w": 320, + "h": 250 + } + ], + "w": 320, + "h": 250 + }, + "ext": { + "adot": {} + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://dsp.adotmob.com/headerbidding/bidrequest", + "body": { + "id": "test-request-banner-id", + "imp": [ + { + "id": "test-imp-banner-id", + "banner": { + "format": [ + { + "w": 320, + "h": 250 + } + ], + "w": 320, + "h": 250 + }, + "ext": { + "adot": {} + } + } + ] + } + }, + "mockResponse": { + "status": 400, + "body": {} + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} + diff --git a/adapters/adot/adottest/supplemental/status_500.json b/adapters/adot/adottest/supplemental/status_500.json new file mode 100644 index 00000000000..879bb8c5581 --- /dev/null +++ b/adapters/adot/adottest/supplemental/status_500.json @@ -0,0 +1,62 @@ +{ + "mockBidRequest": { + "id": "test-request-banner-id", + "imp": [ + { + "id": "test-imp-banner-id", + "banner": { + "format": [ + { + "w": 320, + "h": 250 + } + ], + "w": 320, + "h": 250 + }, + "ext": { + "adot": {} + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://dsp.adotmob.com/headerbidding/bidrequest", + "body": { + "id": "test-request-banner-id", + "imp": [ + { + "id": "test-imp-banner-id", + "banner": { + "format": [ + { + "w": 320, + "h": 250 + } + ], + "w": 320, + "h": 250 + }, + "ext": { + "adot": {} + } + } + ] + } + }, + "mockResponse": { + "status": 500, + "body": {} + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 500. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} + diff --git a/adapters/adot/adottest/supplemental/unmarshal_error.json b/adapters/adot/adottest/supplemental/unmarshal_error.json new file mode 100644 index 00000000000..a87e1189a62 --- /dev/null +++ b/adapters/adot/adottest/supplemental/unmarshal_error.json @@ -0,0 +1,62 @@ +{ + "mockBidRequest": { + "id": "test-request-banner-id", + "imp": [ + { + "id": "test-imp-banner-id", + "banner": { + "format": [ + { + "w": 320, + "h": 250 + } + ], + "w": 320, + "h": 250 + }, + "ext": { + "adot": {} + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://dsp.adotmob.com/headerbidding/bidrequest", + "body": { + "id": "test-request-banner-id", + "imp": [ + { + "id": "test-imp-banner-id", + "banner": { + "format": [ + { + "w": 320, + "h": 250 + } + ], + "w": 320, + "h": 250 + }, + "ext": { + "adot": {} + } + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": "fail for unmarshal" + } + }], + + "expectedMakeBidsErrors": [ + { + "value": "json: cannot unmarshal string into Go value of type openrtb.BidResponse", + "comparison": "literal" + } + ] +} + diff --git a/adapters/adot/params_test.go b/adapters/adot/params_test.go new file mode 100644 index 00000000000..2a6dc17d916 --- /dev/null +++ b/adapters/adot/params_test.go @@ -0,0 +1,53 @@ +package adot + +import ( + "encoding/json" + "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" + "testing" +) + +// This file actually intends to test static/bidder-params/adot.json +// +// These also validate the format of the external API: request.imp[i].ext.adot + +// TestValidParams makes sure that the adot 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.BidderAdot, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected adot 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.BidderAdot, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{}`, + `{"placementId": "test-114"}`, + `{"placementId": "test-113", "parallax": true}`, + `{"placementId": "test-113", "parallax": false}`, +} + +var invalidParams = []string{ + `{"parallax": 1}`, + `{"placementId": 135123}`, + `{"placementId": 113, "parallax": 1}`, + `{"placementId": 142, "parallax": true}`, + `{"placementId": "test-114", "parallax": 1}`, +} diff --git a/adapters/adpone/adpone.go b/adapters/adpone/adpone.go index 9064e971fcb..ec4cba75f87 100644 --- a/adapters/adpone/adpone.go +++ b/adapters/adpone/adpone.go @@ -5,6 +5,7 @@ import ( "fmt" "net/http" + "github.com/PubMatic-OpenWrap/prebid-server/config" "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" "github.com/PubMatic-OpenWrap/openrtb" @@ -12,8 +13,12 @@ import ( "github.com/PubMatic-OpenWrap/prebid-server/errortypes" ) -func NewAdponeBidder(endpoint string) *adponeAdapter { - return &adponeAdapter{endpoint: endpoint} +// Builder builds a new instance of the Adpone adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) { + bidder := &adponeAdapter{ + endpoint: config.Endpoint, + } + return bidder, nil } type adponeAdapter struct { diff --git a/adapters/adpone/adpone_test.go b/adapters/adpone/adpone_test.go index 2cce1d7c62c..69726e31d50 100644 --- a/adapters/adpone/adpone_test.go +++ b/adapters/adpone/adpone_test.go @@ -4,11 +4,20 @@ import ( "testing" "github.com/PubMatic-OpenWrap/prebid-server/adapters/adapterstest" + "github.com/PubMatic-OpenWrap/prebid-server/config" + "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" ) const testsDir = "adponetest" const testsBidderEndpoint = "http://localhost/prebid_server" func TestJsonSamples(t *testing.T) { - adapterstest.RunJSONBidderTest(t, testsDir, NewAdponeBidder(testsBidderEndpoint)) + bidder, buildErr := Builder(openrtb_ext.BidderAdpone, config.Adapter{ + Endpoint: testsBidderEndpoint}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, testsDir, bidder) } diff --git a/adapters/adprime/adprime.go b/adapters/adprime/adprime.go index 2ef5f26edc7..053999fd5d1 100644 --- a/adapters/adprime/adprime.go +++ b/adapters/adprime/adprime.go @@ -7,6 +7,7 @@ import ( "github.com/PubMatic-OpenWrap/openrtb" "github.com/PubMatic-OpenWrap/prebid-server/adapters" + "github.com/PubMatic-OpenWrap/prebid-server/config" "github.com/PubMatic-OpenWrap/prebid-server/errortypes" "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" "github.com/buger/jsonparser" @@ -17,11 +18,12 @@ type AdprimeAdapter struct { URI string } -// NewAdprimeBidder Initializes the Bidder -func NewAdprimeBidder(endpoint string) *AdprimeAdapter { - return &AdprimeAdapter{ - URI: endpoint, +// Builder builds a new instance of the Adprime adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) { + bidder := &AdprimeAdapter{ + URI: config.Endpoint, } + return bidder, nil } // MakeRequests create bid request for adprime demand diff --git a/adapters/adprime/adprime_test.go b/adapters/adprime/adprime_test.go index 1da70595401..cfcf255a5cc 100644 --- a/adapters/adprime/adprime_test.go +++ b/adapters/adprime/adprime_test.go @@ -4,9 +4,17 @@ import ( "testing" "github.com/PubMatic-OpenWrap/prebid-server/adapters/adapterstest" + "github.com/PubMatic-OpenWrap/prebid-server/config" + "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" ) func TestJsonSamples(t *testing.T) { - adprimeAdapter := NewAdprimeBidder("http://delta.adprime.com/?c=o&m=ortb") - adapterstest.RunJSONBidderTest(t, "adprimetest", adprimeAdapter) + bidder, buildErr := Builder(openrtb_ext.BidderAdprime, config.Adapter{ + Endpoint: "http://delta.adprime.com/?c=o&m=ortb"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "adprimetest", bidder) } diff --git a/adapters/adprime/adprimetest/supplemental/status-204.json b/adapters/adprime/adprimetest/supplemental/status-204.json index 44ee59d4d28..4fa57dcee86 100644 --- a/adapters/adprime/adprimetest/supplemental/status-204.json +++ b/adapters/adprime/adprimetest/supplemental/status-204.json @@ -75,5 +75,6 @@ "status": 204, "body": {} } - }] + }], + "expectedBidResponses": [] } diff --git a/adapters/adtarget/adtarget.go b/adapters/adtarget/adtarget.go index d3d13fd33de..070ede40feb 100644 --- a/adapters/adtarget/adtarget.go +++ b/adapters/adtarget/adtarget.go @@ -7,6 +7,7 @@ import ( "github.com/PubMatic-OpenWrap/openrtb" "github.com/PubMatic-OpenWrap/prebid-server/adapters" + "github.com/PubMatic-OpenWrap/prebid-server/config" "github.com/PubMatic-OpenWrap/prebid-server/errortypes" "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" ) @@ -182,8 +183,10 @@ func validateImpressionAndSetExt(imp *openrtb.Imp) (int, error) { return impExt.SourceId, nil } -func NewAdtargetBidder(endpoint string) *AdtargetAdapter { - return &AdtargetAdapter{ - endpoint: endpoint, +// Builder builds a new instance of the Adtarget adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) { + bidder := &AdtargetAdapter{ + endpoint: config.Endpoint, } + return bidder, nil } diff --git a/adapters/adtarget/adtarget_test.go b/adapters/adtarget/adtarget_test.go index 1fd67dfe7b1..bb20b40c286 100644 --- a/adapters/adtarget/adtarget_test.go +++ b/adapters/adtarget/adtarget_test.go @@ -4,8 +4,17 @@ import ( "testing" "github.com/PubMatic-OpenWrap/prebid-server/adapters/adapterstest" + "github.com/PubMatic-OpenWrap/prebid-server/config" + "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" ) func TestJsonSamples(t *testing.T) { - adapterstest.RunJSONBidderTest(t, "adtargettest", NewAdtargetBidder("http://ghb.console.adtarget.com.tr/pbs/ortb")) + bidder, buildErr := Builder(openrtb_ext.BidderAdtarget, config.Adapter{ + Endpoint: "http://ghb.console.adtarget.com.tr/pbs/ortb"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "adtargettest", bidder) } diff --git a/adapters/adtarget/adtargettest/exemplary/simple-banner.json b/adapters/adtarget/adtargettest/exemplary/simple-banner.json index b63739bda0f..3799612455f 100644 --- a/adapters/adtarget/adtargettest/exemplary/simple-banner.json +++ b/adapters/adtarget/adtargettest/exemplary/simple-banner.json @@ -58,5 +58,6 @@ "status": 204 } } - ] -} \ No newline at end of file + ], + "expectedBidResponses": [] +} diff --git a/adapters/adtarget/adtargettest/exemplary/simple-video.json b/adapters/adtarget/adtargettest/exemplary/simple-video.json index 4dc4547d7d1..bf6de569496 100644 --- a/adapters/adtarget/adtargettest/exemplary/simple-video.json +++ b/adapters/adtarget/adtargettest/exemplary/simple-video.json @@ -51,5 +51,6 @@ "status": 204 } } - ] -} \ No newline at end of file + ], + "expectedBidResponses": [] +} diff --git a/adapters/adtarget/adtargettest/supplemental/explicit-dimensions.json b/adapters/adtarget/adtargettest/supplemental/explicit-dimensions.json index a4e487466ea..c33b1bb2daa 100644 --- a/adapters/adtarget/adtargettest/supplemental/explicit-dimensions.json +++ b/adapters/adtarget/adtargettest/supplemental/explicit-dimensions.json @@ -54,5 +54,6 @@ "status": 204 } } - ] + ], + "expectedBidResponses": [] } diff --git a/adapters/adtelligent/adtelligent.go b/adapters/adtelligent/adtelligent.go index 60989aaa315..7d8f6099fbf 100644 --- a/adapters/adtelligent/adtelligent.go +++ b/adapters/adtelligent/adtelligent.go @@ -7,6 +7,7 @@ import ( "github.com/PubMatic-OpenWrap/openrtb" "github.com/PubMatic-OpenWrap/prebid-server/adapters" + "github.com/PubMatic-OpenWrap/prebid-server/config" "github.com/PubMatic-OpenWrap/prebid-server/errortypes" "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" ) @@ -183,8 +184,10 @@ func validateImpression(imp *openrtb.Imp) (int, error) { return impExt.SourceId, nil } -func NewAdtelligentBidder(endpoint string) *AdtelligentAdapter { - return &AdtelligentAdapter{ - endpoint: endpoint, +// Builder builds a new instance of the Adtelligent adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) { + bidder := &AdtelligentAdapter{ + endpoint: config.Endpoint, } + return bidder, nil } diff --git a/adapters/adtelligent/adtelligent_test.go b/adapters/adtelligent/adtelligent_test.go index ce8d24a3c21..6a104aa7463 100644 --- a/adapters/adtelligent/adtelligent_test.go +++ b/adapters/adtelligent/adtelligent_test.go @@ -4,8 +4,17 @@ import ( "testing" "github.com/PubMatic-OpenWrap/prebid-server/adapters/adapterstest" + "github.com/PubMatic-OpenWrap/prebid-server/config" + "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" ) func TestJsonSamples(t *testing.T) { - adapterstest.RunJSONBidderTest(t, "adtelligenttest", NewAdtelligentBidder("http://ghb.adtelligent.com/pbs/ortb")) + bidder, buildErr := Builder(openrtb_ext.BidderAdtelligent, config.Adapter{ + Endpoint: "http://ghb.adtelligent.com/pbs/ortb"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "adtelligenttest", bidder) } diff --git a/adapters/adtelligent/adtelligenttest/exemplary/simple-banner.json b/adapters/adtelligent/adtelligenttest/exemplary/simple-banner.json index a06477b4d18..8c6fe3ade1b 100644 --- a/adapters/adtelligent/adtelligenttest/exemplary/simple-banner.json +++ b/adapters/adtelligent/adtelligenttest/exemplary/simple-banner.json @@ -58,5 +58,6 @@ "status": 204 } } - ] + ], + "expectedBidResponses": [] } \ No newline at end of file diff --git a/adapters/adtelligent/adtelligenttest/exemplary/simple-video.json b/adapters/adtelligent/adtelligenttest/exemplary/simple-video.json index f108cc94b17..aabcf952f78 100644 --- a/adapters/adtelligent/adtelligenttest/exemplary/simple-video.json +++ b/adapters/adtelligent/adtelligenttest/exemplary/simple-video.json @@ -51,5 +51,6 @@ "status": 204 } } - ] + ], + "expectedBidResponses": [] } \ No newline at end of file diff --git a/adapters/adtelligent/adtelligenttest/supplemental/explicit-dimensions.json b/adapters/adtelligent/adtelligenttest/supplemental/explicit-dimensions.json index 6155e9bc56b..7d6ce5b8084 100644 --- a/adapters/adtelligent/adtelligenttest/supplemental/explicit-dimensions.json +++ b/adapters/adtelligent/adtelligenttest/supplemental/explicit-dimensions.json @@ -54,5 +54,6 @@ "status": 204 } } - ] + ], + "expectedBidResponses": [] } diff --git a/adapters/advangelists/advangelists.go b/adapters/advangelists/advangelists.go index e882a6f266a..249e3282481 100644 --- a/adapters/advangelists/advangelists.go +++ b/adapters/advangelists/advangelists.go @@ -8,10 +8,10 @@ import ( "github.com/PubMatic-OpenWrap/openrtb" "github.com/PubMatic-OpenWrap/prebid-server/adapters" + "github.com/PubMatic-OpenWrap/prebid-server/config" "github.com/PubMatic-OpenWrap/prebid-server/errortypes" "github.com/PubMatic-OpenWrap/prebid-server/macros" "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" - "github.com/golang/glog" ) type AdvangelistsAdapter struct { @@ -239,12 +239,15 @@ func getMediaTypeForImpID(impID string, imps []openrtb.Imp) openrtb_ext.BidType return openrtb_ext.BidTypeBanner } -// NewAdvangelistsAdapter to be called in prebid-server core to create advangelists adapter instance -func NewAdvangelistsBidder(endpointTemplate string) adapters.Bidder { - template, err := template.New("endpointTemplate").Parse(endpointTemplate) +// Builder builds a new instance of the Advangelists adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) { + template, err := template.New("endpointTemplate").Parse(config.Endpoint) if err != nil { - glog.Fatal("Unable to parse endpoint url template") - return nil + return nil, fmt.Errorf("unable to parse endpoint url template: %v", err) } - return &AdvangelistsAdapter{EndpointTemplate: *template} + + bidder := &AdvangelistsAdapter{ + EndpointTemplate: *template, + } + return bidder, nil } diff --git a/adapters/advangelists/advangelists_test.go b/adapters/advangelists/advangelists_test.go index d21c325d84d..49cca96a78a 100644 --- a/adapters/advangelists/advangelists_test.go +++ b/adapters/advangelists/advangelists_test.go @@ -1,10 +1,28 @@ package advangelists import ( - "github.com/PubMatic-OpenWrap/prebid-server/adapters/adapterstest" "testing" + + "github.com/PubMatic-OpenWrap/prebid-server/adapters/adapterstest" + "github.com/PubMatic-OpenWrap/prebid-server/config" + "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" + "github.com/stretchr/testify/assert" ) func TestJsonSamples(t *testing.T) { - adapterstest.RunJSONBidderTest(t, "advangeliststest", NewAdvangelistsBidder("http://nep.advangelists.com/xp/get?pubid={{.PublisherID}}")) + bidder, buildErr := Builder(openrtb_ext.BidderAdvangelists, config.Adapter{ + Endpoint: "http://nep.advangelists.com/xp/get?pubid={{.PublisherID}}"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "advangeliststest", bidder) +} + +func TestEndpointTemplateMalformed(t *testing.T) { + _, buildErr := Builder(openrtb_ext.BidderAdvangelists, config.Adapter{ + Endpoint: "{{Malformed}}"}) + + assert.Error(t, buildErr) } diff --git a/adapters/aja/aja.go b/adapters/aja/aja.go index 55de9567ff8..afd9c6d7131 100644 --- a/adapters/aja/aja.go +++ b/adapters/aja/aja.go @@ -3,11 +3,13 @@ package aja import ( "encoding/json" "fmt" + "net/http" + "github.com/PubMatic-OpenWrap/openrtb" "github.com/PubMatic-OpenWrap/prebid-server/adapters" + "github.com/PubMatic-OpenWrap/prebid-server/config" "github.com/PubMatic-OpenWrap/prebid-server/errortypes" "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" - "net/http" ) type AJAAdapter struct { @@ -125,8 +127,10 @@ func (a *AJAAdapter) MakeBids(bidReq *openrtb.BidRequest, adapterReq *adapters.R return bidderResp, errors } -func NewAJABidder(endpoint string) adapters.Bidder { - return &AJAAdapter{ - endpoint: endpoint, +// Builder builds a new instance of the AJA adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) { + bidder := &AJAAdapter{ + endpoint: config.Endpoint, } + return bidder, nil } diff --git a/adapters/aja/aja_test.go b/adapters/aja/aja_test.go index 95906b14c2a..d2d9d7fa7c1 100644 --- a/adapters/aja/aja_test.go +++ b/adapters/aja/aja_test.go @@ -4,10 +4,19 @@ import ( "testing" "github.com/PubMatic-OpenWrap/prebid-server/adapters/adapterstest" + "github.com/PubMatic-OpenWrap/prebid-server/config" + "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" ) const testsBidderEndpoint = "https://localhost/bid/4" func TestJsonSamples(t *testing.T) { - adapterstest.RunJSONBidderTest(t, "ajatest", NewAJABidder(testsBidderEndpoint)) + bidder, buildErr := Builder(openrtb_ext.BidderAJA, config.Adapter{ + Endpoint: testsBidderEndpoint}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "ajatest", bidder) } diff --git a/adapters/amx/amx.go b/adapters/amx/amx.go index 2578ab786c6..ddd0c0373da 100644 --- a/adapters/amx/amx.go +++ b/adapters/amx/amx.go @@ -9,39 +9,40 @@ import ( "github.com/PubMatic-OpenWrap/openrtb" "github.com/PubMatic-OpenWrap/prebid-server/adapters" + "github.com/PubMatic-OpenWrap/prebid-server/config" "github.com/PubMatic-OpenWrap/prebid-server/errortypes" "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" - "github.com/golang/glog" ) const vastImpressionFormat = "" const vastSearchPoint = "" const nbrHeaderName = "x-nbr" -const adapterVersion = "pbs1.0" +const adapterVersion = "pbs1.1" // AMXAdapter is the AMX bid adapter type AMXAdapter struct { endpoint string } -// NewAMXBidder creates an AMXAdapter -func NewAMXBidder(endpoint string) *AMXAdapter { - endpointURL, err := url.Parse(endpoint) +// Builder builds a new instance of the AMX adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) { + endpointURL, err := url.Parse(config.Endpoint) if err != nil { - glog.Fatalf("invalid endpoint provided to AMX: %s, error: %v", endpoint, err) - return nil + return nil, fmt.Errorf("invalid endpoint: %v", err) } qs, err := url.ParseQuery(endpointURL.RawQuery) if err != nil { - glog.Fatalf("invalid query parameters in the endpoint: %s, error: %v", endpointURL.RawQuery, err) - return nil + return nil, fmt.Errorf("invalid query parameters in the endpoint: %v", err) } qs.Add("v", adapterVersion) endpointURL.RawQuery = qs.Encode() - return &AMXAdapter{endpoint: endpointURL.String()} + bidder := &AMXAdapter{ + endpoint: endpointURL.String(), + } + return bidder, nil } type amxExt struct { @@ -148,6 +149,7 @@ func (adapter *AMXAdapter) MakeBids(request *openrtb.BidRequest, externalRequest for _, sb := range bidResp.SeatBid { for _, bid := range sb.Bid { + bid := bid bidExt, bidExtErr := getBidExt(bid.Ext) if bidExtErr != nil { errs = append(errs, bidExtErr) @@ -164,11 +166,12 @@ func (adapter *AMXAdapter) MakeBids(request *openrtb.BidRequest, externalRequest // remove the NURL so a client/player doesn't fire it twice b.Bid.NURL = "" } + bidResponse.Bids = append(bidResponse.Bids, b) } } - return bidResponse, errs + return bidResponse, errs } func getBidExt(ext json.RawMessage) (amxBidExt, error) { diff --git a/adapters/amx/amx_test.go b/adapters/amx/amx_test.go index 3d6e118772f..6fc850cb2cc 100644 --- a/adapters/amx/amx_test.go +++ b/adapters/amx/amx_test.go @@ -8,6 +8,8 @@ import ( "github.com/PubMatic-OpenWrap/openrtb" "github.com/PubMatic-OpenWrap/prebid-server/adapters" + "github.com/PubMatic-OpenWrap/prebid-server/config" + "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" "github.com/stretchr/testify/assert" "github.com/PubMatic-OpenWrap/prebid-server/adapters/adapterstest" @@ -20,13 +22,40 @@ const ( ) func TestJsonSamples(t *testing.T) { - adapterstest.RunJSONBidderTest(t, "amxtest", NewAMXBidder(amxTestEndpoint)) + bidder, buildErr := Builder(openrtb_ext.BidderAMX, config.Adapter{ + Endpoint: amxTestEndpoint}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "amxtest", bidder) +} + +func TestEndpointMalformed(t *testing.T) { + _, buildErr := Builder(openrtb_ext.BidderAMX, config.Adapter{ + Endpoint: " http://leading.space.is.invalid"}) + + assert.Error(t, buildErr) +} + +func TestEndpointQueryStringMalformed(t *testing.T) { + _, buildErr := Builder(openrtb_ext.BidderAMX, config.Adapter{ + Endpoint: "http://invalid.query.from.go.docs/page?%gh&%ij"}) + + assert.Error(t, buildErr) } func TestMakeRequestsTagID(t *testing.T) { var w, h int = 300, 250 var width, height uint64 = uint64(w), uint64(h) - adapter := NewAMXBidder(amxTestEndpoint) + + bidder, buildErr := Builder(openrtb_ext.BidderAMX, config.Adapter{ + Endpoint: amxTestEndpoint}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } type testCase struct { tagID string @@ -71,7 +100,7 @@ func TestMakeRequestsTagID(t *testing.T) { Site: &openrtb.Site{}, } - actualAdapterRequests, err := adapter.MakeRequests(&inputRequest, &adapters.ExtraRequestInfo{}) + actualAdapterRequests, err := bidder.MakeRequests(&inputRequest, &adapters.ExtraRequestInfo{}) assert.Len(t, actualAdapterRequests, 1) assert.Empty(t, err) var body openrtb.BidRequest @@ -83,7 +112,13 @@ func TestMakeRequestsTagID(t *testing.T) { func TestMakeRequestsPublisherId(t *testing.T) { var w, h int = 300, 250 var width, height uint64 = uint64(w), uint64(h) - adapter := NewAMXBidder(amxTestEndpoint) + + bidder, buildErr := Builder(openrtb_ext.BidderAMX, config.Adapter{ + Endpoint: amxTestEndpoint}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } type testCase struct { publisherID string @@ -130,7 +165,7 @@ func TestMakeRequestsPublisherId(t *testing.T) { } } - actualAdapterRequests, err := adapter.MakeRequests(&inputRequest, &adapters.ExtraRequestInfo{}) + actualAdapterRequests, err := bidder.MakeRequests(&inputRequest, &adapters.ExtraRequestInfo{}) assert.Len(t, actualAdapterRequests, 1) assert.Empty(t, err) var body openrtb.BidRequest diff --git a/adapters/amx/amxtest/exemplary/app-simple.json b/adapters/amx/amxtest/exemplary/app-simple.json index b2f538493da..c208bff9da4 100644 --- a/adapters/amx/amxtest/exemplary/app-simple.json +++ b/adapters/amx/amxtest/exemplary/app-simple.json @@ -64,7 +64,7 @@ "httpCalls": [ { "expectedRequest": { - "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.0", + "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.1", "body": { "app": { "bundle": "639881495", diff --git a/adapters/amx/amxtest/exemplary/display-multiple.json b/adapters/amx/amxtest/exemplary/display-multiple.json new file mode 100644 index 00000000000..f885bdb2c5b --- /dev/null +++ b/adapters/amx/amxtest/exemplary/display-multiple.json @@ -0,0 +1,292 @@ +{ + "mockBidRequest": { + "device": { + "dnt": 0, + "h": 1120, + "ip": "98.249.0.0", + "language": "en", + "os": "macos", + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36", + "w": 1792 + }, + "id": "TL3JS6F43CKNDQFY", + "imp": [ + { + "banner": { + "format": [ + { + "h": 600, + "w": 300 + } + ], + "h": 600, + "pos": 1, + "w": 300 + }, + "ext": { + "bidder": { + "tagId": "cHJlYmlkLm9yZw" + } + }, + "tagid": "example-tag-id", + "id": "1", + "secure": 1 + } + ], + "regs": { + "ext": { + "gdpr": 0, + "us_privacy": "1---" + } + }, + "site": { + "domain": "www.example.com", + "ext": { + "amp": 0 + }, + "publisher": { + "id": "unused_publisher_id" + }, + "page": "https://www.example.com/es6/es6_objects.htm", + "ref": "https://www.example.com/es6/es6_objects.htm" + }, + "source": { + "ext": { + "schain": { + "complete": 1, + "nodes": [ + { + "asi": "amxrtb.com", + "hp": 1, + "sid": "1234" + } + ], + "ver": "1.0" + } + } + }, + "test": 0, + "tmax": 300, + "user": { + "ext": { + "eids": [ + { + "source": "amxid", + "uids": [ + { + "atype": 1, + "id": "88de601e-3d98-48e7-81d7-00000000" + } + ] + }, + { + "source": "adserver.org", + "uids": [ + { + "id": "1234567", + "ext": { + "rtiPartner": "TDID" + } + } + ] + } + ], + "gdpr": 0, + "us_privacy": "1---" + } + } + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.1", + "body": { + "device": { + "dnt": 0, + "h": 1120, + "ip": "98.249.0.0", + "language": "en", + "os": "macos", + "ua": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/85.0.4183.102 Safari/537.36", + "w": 1792 + }, + "id": "TL3JS6F43CKNDQFY", + "imp": [ + { + "banner": { + "format": [ + { + "h": 600, + "w": 300 + } + ], + "h": 600, + "pos": 1, + "w": 300 + }, + "ext": { + "bidder": { + "tagId": "cHJlYmlkLm9yZw" + } + }, + "tagid": "example-tag-id", + "id": "1", + "secure": 1 + } + ], + "regs": { + "ext": { + "gdpr": 0, + "us_privacy": "1---" + } + }, + "site": { + "domain": "www.example.com", + "ext": { + "amp": 0 + }, + "publisher": { + "id": "cHJlYmlkLm9yZw" + }, + "page": "https://www.example.com/es6/es6_objects.htm", + "ref": "https://www.example.com/es6/es6_objects.htm" + }, + "source": { + "ext": { + "schain": { + "complete": 1, + "nodes": [ + { + "asi": "amxrtb.com", + "hp": 1, + "sid": "1234" + } + ], + "ver": "1.0" + } + } + }, + "tmax": 300, + "user": { + "ext": { + "eids": [ + { + "source": "amxid", + "uids": [ + { + "atype": 1, + "id": "88de601e-3d98-48e7-81d7-00000000" + } + ] + }, + { + "source": "adserver.org", + "uids": [ + { + "id": "1234567", + "ext": { + "rtiPartner": "TDID" + } + } + ] + } + ], + "gdpr": 0, + "us_privacy": "1---" + } + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "cur": "USD", + "id": "os4jorvupkyaa===", + "seatbid": [ + { + "bid": [ + { + "adid": "253510977", + "adm": "", + "adomain": [ + "dell.com.au" + ], + "cid": "668", + "crid": "253510977", + "ext": { + }, + "h": 250, + "id": "8911104898220857797", + "impid": "6a362d3a9db4eba300x250", + "nurl": "https://1x1.a-mo.net/hbx/bwin", + "price": 0.50, + "w": 300 + }, + { + "adid": "253510977", + "adm": "", + "adomain": [ + "dell.com.au" + ], + "cid": "668", + "crid": "253510977", + "ext": {}, + "h": 250, + "id": "430444686086263488", + "impid": "6a362d3a9db4eba300x250", + "nurl": "https://1x1.a-mo.net/hbx/bwin", + "price": 0.50, + "w": 300 + } + ], + "group": 0 + } + ] + } + } + }], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "adid": "253510977", + "adm": "", + "adomain": [ + "dell.com.au" + ], + "cid": "668", + "crid": "253510977", + "ext": {}, + "h": 250, + "id": "8911104898220857797", + "impid": "6a362d3a9db4eba300x250", + "nurl": "https://1x1.a-mo.net/hbx/bwin", + "price": 0.50, + "w": 300 + }, + "type": "banner" + }, + { + "bid": { + "adid": "253510977", + "adm": "", + "adomain": [ + "dell.com.au" + ], + "cid": "668", + "crid": "253510977", + "ext": {}, + "h": 250, + "id": "430444686086263488", + "impid": "6a362d3a9db4eba300x250", + "nurl": "https://1x1.a-mo.net/hbx/bwin", + "price": 0.50, + "w": 300 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/amx/amxtest/exemplary/video-simple.json b/adapters/amx/amxtest/exemplary/video-simple.json index 8fb3baa26d0..f8fe587ff63 100644 --- a/adapters/amx/amxtest/exemplary/video-simple.json +++ b/adapters/amx/amxtest/exemplary/video-simple.json @@ -93,7 +93,7 @@ }, "httpCalls": [{ "expectedRequest": { - "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.0", + "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.1", "body": { "device": { "dnt": 0, @@ -242,4 +242,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/adapters/amx/amxtest/exemplary/web-simple.json b/adapters/amx/amxtest/exemplary/web-simple.json index 74854f912ae..92fc4afc018 100644 --- a/adapters/amx/amxtest/exemplary/web-simple.json +++ b/adapters/amx/amxtest/exemplary/web-simple.json @@ -98,7 +98,7 @@ }, "httpCalls": [{ "expectedRequest": { - "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.0", + "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.1", "body": { "device": { "dnt": 0, @@ -243,4 +243,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/adapters/amx/amxtest/supplemental/204-response.json b/adapters/amx/amxtest/supplemental/204-response.json index 09571a03569..f51347d34d2 100644 --- a/adapters/amx/amxtest/supplemental/204-response.json +++ b/adapters/amx/amxtest/supplemental/204-response.json @@ -47,7 +47,7 @@ }, "httpCalls": [{ "expectedRequest": { - "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.0", + "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.1", "body": { "device": { "dnt": 0, diff --git a/adapters/amx/amxtest/supplemental/400-response.json b/adapters/amx/amxtest/supplemental/400-response.json index f10cea89718..bb20bc94e7c 100644 --- a/adapters/amx/amxtest/supplemental/400-response.json +++ b/adapters/amx/amxtest/supplemental/400-response.json @@ -47,7 +47,7 @@ }, "httpCalls": [{ "expectedRequest": { - "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.0", + "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.1", "body": { "device": { "dnt": 0, diff --git a/adapters/amx/amxtest/supplemental/500-response.json b/adapters/amx/amxtest/supplemental/500-response.json index fe5d89930c8..c56a217ce2e 100644 --- a/adapters/amx/amxtest/supplemental/500-response.json +++ b/adapters/amx/amxtest/supplemental/500-response.json @@ -47,7 +47,7 @@ }, "httpCalls": [{ "expectedRequest": { - "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.0", + "uri": "http://pbs-dev.amxrtb.com/auction/openrtb?v=pbs1.1", "body": { "device": { "dnt": 0, diff --git a/adapters/applogy/applogy.go b/adapters/applogy/applogy.go index 2c760bc3995..cdeafa0f426 100644 --- a/adapters/applogy/applogy.go +++ b/adapters/applogy/applogy.go @@ -8,6 +8,7 @@ import ( "github.com/PubMatic-OpenWrap/openrtb" "github.com/PubMatic-OpenWrap/prebid-server/adapters" + "github.com/PubMatic-OpenWrap/prebid-server/config" "github.com/PubMatic-OpenWrap/prebid-server/errortypes" "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" ) @@ -153,8 +154,10 @@ func (a *ApplogyAdapter) MakeBids(request *openrtb.BidRequest, _ *adapters.Reque return response, errs } -func NewApplogyBidder(endpoint string) *ApplogyAdapter { - return &ApplogyAdapter{ - endpoint: endpoint, +// Builder builds a new instance of the Applogy adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) { + bidder := &ApplogyAdapter{ + endpoint: config.Endpoint, } + return bidder, nil } diff --git a/adapters/applogy/applogy_test.go b/adapters/applogy/applogy_test.go index 4e656259f35..63e99ed5895 100644 --- a/adapters/applogy/applogy_test.go +++ b/adapters/applogy/applogy_test.go @@ -4,8 +4,17 @@ import ( "testing" "github.com/PubMatic-OpenWrap/prebid-server/adapters/adapterstest" + "github.com/PubMatic-OpenWrap/prebid-server/config" + "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" ) func TestJsonSamples(t *testing.T) { - adapterstest.RunJSONBidderTest(t, "applogytest", NewApplogyBidder("http://example.com/prebid")) + bidder, buildErr := Builder(openrtb_ext.BidderApplogy, config.Adapter{ + Endpoint: "http://example.com/prebid"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "applogytest", bidder) } diff --git a/adapters/applogy/applogytest/supplemental/status-204.json b/adapters/applogy/applogytest/supplemental/status-204.json index c3516b184b5..1c849b4fa3a 100644 --- a/adapters/applogy/applogytest/supplemental/status-204.json +++ b/adapters/applogy/applogytest/supplemental/status-204.json @@ -37,5 +37,6 @@ "status": 204, "body": {} } - }] + }], + "expectedBidResponses": [] } diff --git a/adapters/appnexus/appnexus.go b/adapters/appnexus/appnexus.go index 145c830dbb6..954fce5efb9 100644 --- a/adapters/appnexus/appnexus.go +++ b/adapters/appnexus/appnexus.go @@ -11,6 +11,7 @@ import ( "strconv" "strings" + "github.com/PubMatic-OpenWrap/prebid-server/config" "github.com/PubMatic-OpenWrap/prebid-server/pbs" "github.com/buger/jsonparser" @@ -19,10 +20,12 @@ import ( "github.com/PubMatic-OpenWrap/openrtb" "github.com/PubMatic-OpenWrap/prebid-server/adapters" "github.com/PubMatic-OpenWrap/prebid-server/errortypes" + "github.com/PubMatic-OpenWrap/prebid-server/metrics" "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" - "github.com/PubMatic-OpenWrap/prebid-server/pbsmetrics" ) +const defaultPlatformID int = 5 + type AppNexusAdapter struct { http *adapters.HTTPAdapter URI string @@ -333,9 +336,9 @@ func (a *AppNexusAdapter) MakeRequests(request *openrtb.BidRequest, reqInfo *ada // Add Appnexus request level extension var isAMP, isVIDEO int - if reqInfo.PbsEntryPoint == pbsmetrics.ReqTypeAMP { + if reqInfo.PbsEntryPoint == metrics.ReqTypeAMP { isAMP = 1 - } else if reqInfo.PbsEntryPoint == pbsmetrics.ReqTypeVideo { + } else if reqInfo.PbsEntryPoint == metrics.ReqTypeVideo { isVIDEO = 1 } @@ -601,6 +604,9 @@ func (a *AppNexusAdapter) MakeBids(internalRequest *openrtb.BidRequest, external } } } + if bidResp.Cur != "" { + bidResponse.Currency = bidResp.Cur + } return bidResponse, errs } @@ -638,42 +644,49 @@ func appendMemberId(uri string, memberId string) string { return uri + "?member_id=" + memberId } -func NewAppNexusAdapter(config *adapters.HTTPAdapterConfig, endpoint, platformID string) *AppNexusAdapter { - return NewAppNexusBidder(adapters.NewHTTPAdapter(config).Client, endpoint, platformID) +// Builder builds a new instance of the AppNexus adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) { + bidder := &AppNexusAdapter{ + URI: config.Endpoint, + iabCategoryMap: loadCategoryMapFromFileSystem(), + hbSource: resolvePlatformID(config.PlatformID), + } + return bidder, nil } -func NewAppNexusBidder(client *http.Client, endpoint, platformID string) *AppNexusAdapter { - a := &adapters.HTTPAdapter{Client: client} +// NewAppNexusLegacyAdapter builds a legacy version of the AppNexus adapter. +func NewAppNexusLegacyAdapter(httpConfig *adapters.HTTPAdapterConfig, endpoint, platformID string) *AppNexusAdapter { + return &AppNexusAdapter{ + http: adapters.NewHTTPAdapter(httpConfig), + URI: endpoint, + iabCategoryMap: loadCategoryMapFromFileSystem(), + hbSource: resolvePlatformID(platformID), + } +} +func resolvePlatformID(platformID string) int { + if len(platformID) > 0 { + if val, err := strconv.Atoi(platformID); err == nil { + return val + } + } + + return defaultPlatformID +} + +func loadCategoryMapFromFileSystem() map[string]string { // Load custom options for our adapter (currently just a lookup table to convert appnexus => iab categories) - var catmap map[string]string - var fileUri string - if client == nil { - // This is for tests - fileUri = "./static/adapter/appnexus/opts.json" - } else { - fileUri = "./home/http/GO_SERVER/dmhbserver/static/adapter/appnexus/opts.json" + opts, err := ioutil.ReadFile("./home/http/GO_SERVER/dmhbserver/static/adapter/appnexus/opts.json") + //this is for tests + if err != nil { + opts, err = ioutil.ReadFile("./static/adapter/appnexus/opts.json") } - opts, err := ioutil.ReadFile(fileUri) if err == nil { var adapterOptions appnexusAdapterOptions if err := json.Unmarshal(opts, &adapterOptions); err == nil { - catmap = adapterOptions.IabCategories - } - } - - platid := 5 - if len(platformID) > 0 { - if val, err := strconv.Atoi(platformID); err == nil { - platid = val + return adapterOptions.IabCategories } } - - return &AppNexusAdapter{ - http: a, - URI: endpoint, - iabCategoryMap: catmap, - hbSource: platid, - } + return nil } diff --git a/adapters/appnexus/appnexus_test.go b/adapters/appnexus/appnexus_test.go index 7468250b28d..e63d287a70b 100644 --- a/adapters/appnexus/appnexus_test.go +++ b/adapters/appnexus/appnexus_test.go @@ -4,7 +4,6 @@ import ( "bytes" "context" "encoding/json" - "github.com/stretchr/testify/assert" "io/ioutil" "net/http" "net/http/httptest" @@ -12,7 +11,10 @@ import ( "testing" "time" + "github.com/stretchr/testify/assert" + "github.com/PubMatic-OpenWrap/prebid-server/cache/dummycache" + "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" "github.com/PubMatic-OpenWrap/prebid-server/pbs" "github.com/PubMatic-OpenWrap/prebid-server/usersync" @@ -25,11 +27,26 @@ import ( ) func TestJsonSamples(t *testing.T) { - adapterstest.RunJSONBidderTest(t, "appnexustest", NewAppNexusBidder(nil, "http://ib.adnxs.com/openrtb2", "")) + bidder, buildErr := Builder(openrtb_ext.BidderAppnexus, config.Adapter{ + Endpoint: "http://ib.adnxs.com/openrtb2"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "appnexustest", bidder) } func TestVideoSamples(t *testing.T) { - adapterstest.RunJSONBidderTest(t, "appnexusplatformtest", NewAppNexusBidder(nil, "http://ib.adnxs.com/openrtb2", "8")) + bidder, buildErr := Builder(openrtb_ext.BidderAppnexus, config.Adapter{ + Endpoint: "http://ib.adnxs.com/openrtb2", + PlatformID: "8"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "appnexusplatformtest", bidder) } func TestMemberQueryParam(t *testing.T) { @@ -492,7 +509,7 @@ func bidTypeToInt(bidType string) int { return -1 } } -func TestAppNexusBasicResponse(t *testing.T) { +func TestAppNexusLegacyBasicResponse(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(DummyAppNexusServer)) defer server.Close() @@ -531,7 +548,7 @@ func TestAppNexusBasicResponse(t *testing.T) { } conf := *adapters.DefaultHTTPAdapterConfig - an := NewAppNexusAdapter(&conf, server.URL, "") + an := NewAppNexusLegacyAdapter(&conf, server.URL, "") pbin := pbs.PBSRequest{ AdUnits: make([]pbs.AdUnit, 2), diff --git a/adapters/appnexus/appnexustest/exemplary/optional-params.json b/adapters/appnexus/appnexustest/exemplary/optional-params.json index 626c1f2db90..ae7e9ff31a8 100644 --- a/adapters/appnexus/appnexustest/exemplary/optional-params.json +++ b/adapters/appnexus/appnexustest/exemplary/optional-params.json @@ -77,5 +77,6 @@ "status": 204 } } - ] + ], + "expectedBidResponses": [] } \ No newline at end of file diff --git a/adapters/appnexus/appnexustest/exemplary/simple-banner-foreign-currency.json b/adapters/appnexus/appnexustest/exemplary/simple-banner-foreign-currency.json new file mode 100644 index 00000000000..b46c6f5f76f --- /dev/null +++ b/adapters/appnexus/appnexustest/exemplary/simple-banner-foreign-currency.json @@ -0,0 +1,141 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "placement_id": 1 + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://ib.adnxs.com/openrtb2", + "body": { + "id": "test-request-id", + "ext": { + "appnexus": { + "hb_source": 5 + }, + "prebid": {} + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ], + "w": 300, + "h": 250 + }, + "ext": { + "appnexus": { + "placement_id": 1 + } + } + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "958", + "bid": [{ + "id": "7706636740145184841", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "29681110", + "adm": "some-test-ad", + "adomain": ["appnexus.com"], + "iurl": "http://nym1-ib.adnxs.com/cr?id=29681110", + "cid": "958", + "crid": "29681110", + "h": 250, + "w": 300, + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 8189378542222915032, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + }] + } + ], + "bidid": "5778926625248726496", + "cur": "MXN" + } + } + } + ], + + "expectedBidResponses": [ + { + "currency": "MXN", + "bids": [ + { + "bid": { + "id": "7706636740145184841", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "adid": "29681110", + "adomain": ["appnexus.com"], + "iurl": "http://nym1-ib.adnxs.com/cr?id=29681110", + "cid": "958", + "crid": "29681110", + "w": 300, + "h": 250, + "cat": ["IAB20-3"], + "ext": { + "appnexus": { + "brand_id": 1, + "brand_category_id": 1, + "auction_id": 8189378542222915032, + "bid_ad_type": 0, + "bidder_id": 2, + "ranking_price": 0.000000, + "deal_priority": 5 + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/appnexus/appnexustest/supplemental/explicit-dimensions.json b/adapters/appnexus/appnexustest/supplemental/explicit-dimensions.json index 06e7724a23b..685a908b4f7 100644 --- a/adapters/appnexus/appnexustest/supplemental/explicit-dimensions.json +++ b/adapters/appnexus/appnexustest/supplemental/explicit-dimensions.json @@ -60,5 +60,6 @@ "status": 204 } } - ] + ], + "expectedBidResponses": [] } diff --git a/adapters/audienceNetwork/audienceNetworktest/supplemental/no-bid-204.json b/adapters/audienceNetwork/audienceNetworktest/supplemental/no-bid-204.json index 642e495810a..8c97f3e9098 100644 --- a/adapters/audienceNetwork/audienceNetworktest/supplemental/no-bid-204.json +++ b/adapters/audienceNetwork/audienceNetworktest/supplemental/no-bid-204.json @@ -81,5 +81,6 @@ "status": 204 } } - ] + ], + "expectedBidResponses": [] } diff --git a/adapters/audienceNetwork/facebook.go b/adapters/audienceNetwork/facebook.go index 0759a09d80b..a74c51d9ecb 100644 --- a/adapters/audienceNetwork/facebook.go +++ b/adapters/audienceNetwork/facebook.go @@ -11,31 +11,30 @@ import ( "strings" "github.com/PubMatic-OpenWrap/prebid-server/adapters" + "github.com/PubMatic-OpenWrap/prebid-server/config" "github.com/PubMatic-OpenWrap/prebid-server/errortypes" "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" "github.com/PubMatic-OpenWrap/prebid-server/util/maputil" "github.com/PubMatic-OpenWrap/openrtb" "github.com/buger/jsonparser" - "github.com/golang/glog" ) +var supportedBannerHeights = map[uint64]bool{ + 50: true, + 250: true, +} + type FacebookAdapter struct { - URI string - nonSecureUri string - platformID string - appSecret string + URI string + platformID string + appSecret string } type facebookAdMarkup struct { BidID string `json:"bid_id"` } -var supportedBannerHeights = map[uint64]bool{ - 50: true, - 250: true, -} - type facebookReqExt struct { PlatformID string `json:"platformid"` AuthID string `json:"authentication_id"` @@ -429,30 +428,22 @@ func resolveImpType(imp *openrtb.Imp) (openrtb_ext.BidType, bool) { return openrtb_ext.BidTypeBanner, false } -func NewFacebookBidder(platformID string, appSecret string) adapters.Bidder { - if platformID == "" { - glog.Errorf("No facebook partnerID specified. Calls to the Audience Network will fail. Did you set adapters.facebook.platform_id in the app config?") - return &adapters.MisconfiguredBidder{ - Name: "audienceNetwork", - Error: errors.New("Audience Network is not configured properly on this Prebid Server deploy. If you believe this should work, contact the company hosting the service and tell them to check their configuration."), - } +// Builder builds a new instance of Facebook's Audience Network adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) { + if config.PlatformID == "" { + return nil, errors.New("PartnerID is not configured. Did you set adapters.facebook.platform_id in the app config?") } - if appSecret == "" { - glog.Errorf("No facebook app secret specified. Calls to the Audience Network will fail. Did you set adapters.facebook.app_secret in the app config?") - return &adapters.MisconfiguredBidder{ - Name: "audienceNetwork", - Error: errors.New("Audience Network is not configured properly on this Prebid Server deploy. If you believe this should work, contact the company hosting the service and tell them to check their configuration."), - } + if config.AppSecret == "" { + return nil, errors.New("AppSecret is not configured. Did you set adapters.facebook.app_secret in the app config?") } - return &FacebookAdapter{ - URI: "https://an.facebook.com/placementbid.ortb", - //for AB test - nonSecureUri: "http://an.facebook.com/placementbid.ortb", - platformID: platformID, - appSecret: appSecret, + bidder := &FacebookAdapter{ + URI: config.Endpoint, + platformID: config.PlatformID, + appSecret: config.AppSecret, } + return bidder, nil } func (fa *FacebookAdapter) MakeTimeoutNotification(req *adapters.RequestData) (*adapters.RequestData, []error) { diff --git a/adapters/audienceNetwork/facebook_test.go b/adapters/audienceNetwork/facebook_test.go index 8ff05118a35..596529dbb9a 100644 --- a/adapters/audienceNetwork/facebook_test.go +++ b/adapters/audienceNetwork/facebook_test.go @@ -1,12 +1,13 @@ package audienceNetwork import ( - "errors" "testing" "time" "github.com/PubMatic-OpenWrap/prebid-server/adapters" "github.com/PubMatic-OpenWrap/prebid-server/adapters/adapterstest" + "github.com/PubMatic-OpenWrap/prebid-server/config" + "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" "github.com/stretchr/testify/assert" ) @@ -41,16 +42,34 @@ type FacebookExt struct { } func TestJsonSamples(t *testing.T) { - adapterstest.RunJSONBidderTest(t, "audienceNetworktest", NewFacebookBidder("test-platform-id", "test-app-secret")) + bidder, buildErr := Builder(openrtb_ext.BidderAudienceNetwork, config.Adapter{ + Endpoint: "https://an.facebook.com/placementbid.ortb", + PlatformID: "test-platform-id", + AppSecret: "test-app-secret", + }) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "audienceNetworktest", bidder) } func TestMakeTimeoutNoticeApp(t *testing.T) { req := adapters.RequestData{ Body: []byte(`{"id":"1234","imp":[{"id":"1234"}],"app":{"publisher":{"id":"5678"}}}`), } - fba := NewFacebookBidder("test-platform-id", "test-app-secret") + bidder, buildErr := Builder(openrtb_ext.BidderAudienceNetwork, config.Adapter{ + Endpoint: "https://an.facebook.com/placementbid.ortb", + PlatformID: "test-platform-id", + AppSecret: "test-app-secret", + }) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } - tb, ok := fba.(adapters.TimeoutBidder) + tb, ok := bidder.(adapters.TimeoutBidder) if !ok { t.Error("Facebook adapter is not a TimeoutAdapter") } @@ -65,9 +84,17 @@ func TestMakeTimeoutNoticeBadRequest(t *testing.T) { req := adapters.RequestData{ Body: []byte(`{"imp":[{{"id":"1234"}}`), } - fba := NewFacebookBidder("test-platform-id", "test-app-secret") + bidder, buildErr := Builder(openrtb_ext.BidderAudienceNetwork, config.Adapter{ + Endpoint: "https://an.facebook.com/placementbid.ortb", + PlatformID: "test-platform-id", + AppSecret: "test-app-secret", + }) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } - tb, ok := fba.(adapters.TimeoutBidder) + tb, ok := bidder.(adapters.TimeoutBidder) if !ok { t.Error("Facebook adapter is not a TimeoutAdapter") } @@ -79,23 +106,21 @@ func TestMakeTimeoutNoticeBadRequest(t *testing.T) { } func TestNewFacebookBidderMissingPlatformID(t *testing.T) { - result := NewFacebookBidder("", "anyAppSecret") + bidder, err := Builder(openrtb_ext.BidderAudienceNetwork, config.Adapter{ + Endpoint: "https://an.facebook.com/placementbid.ortb", + AppSecret: "test-app-secret", + }) - expected := &adapters.MisconfiguredBidder{ - Name: "audienceNetwork", - Error: errors.New("Audience Network is not configured properly on this Prebid Server deploy. If you believe this should work, contact the company hosting the service and tell them to check their configuration."), - } - - assert.Equal(t, expected, result) + assert.Empty(t, bidder) + assert.EqualError(t, err, "PartnerID is not configured. Did you set adapters.facebook.platform_id in the app config?") } func TestNewFacebookBidderMissingAppSecret(t *testing.T) { - result := NewFacebookBidder("anyPlatformID", "") - - expected := &adapters.MisconfiguredBidder{ - Name: "audienceNetwork", - Error: errors.New("Audience Network is not configured properly on this Prebid Server deploy. If you believe this should work, contact the company hosting the service and tell them to check their configuration."), - } + bidder, err := Builder(openrtb_ext.BidderAudienceNetwork, config.Adapter{ + Endpoint: "https://an.facebook.com/placementbid.ortb", + PlatformID: "test-platform-id", + }) - assert.Equal(t, expected, result) + assert.Empty(t, bidder) + assert.EqualError(t, err, "AppSecret is not configured. Did you set adapters.facebook.app_secret in the app config?") } diff --git a/adapters/avocet/avocet.go b/adapters/avocet/avocet.go index ef6e1bb4344..ef2314e7ebb 100644 --- a/adapters/avocet/avocet.go +++ b/adapters/avocet/avocet.go @@ -7,6 +7,7 @@ import ( "github.com/PubMatic-OpenWrap/openrtb" "github.com/PubMatic-OpenWrap/prebid-server/adapters" + "github.com/PubMatic-OpenWrap/prebid-server/config" "github.com/PubMatic-OpenWrap/prebid-server/errortypes" "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" ) @@ -116,9 +117,10 @@ func getBidType(bid openrtb.Bid, ext avocetBidExt) openrtb_ext.BidType { } } -// NewAvocetAdapter returns a new AvocetAdapter using the provided endpoint. -func NewAvocetAdapter(endpoint string) *AvocetAdapter { - return &AvocetAdapter{ - Endpoint: endpoint, +// Builder builds a new instance of the Avocet adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) { + bidder := &AvocetAdapter{ + Endpoint: config.Endpoint, } + return bidder, nil } diff --git a/adapters/avocet/avocet_test.go b/adapters/avocet/avocet_test.go index 9c8d3d07932..f669e34492f 100644 --- a/adapters/avocet/avocet_test.go +++ b/adapters/avocet/avocet_test.go @@ -9,12 +9,20 @@ import ( "github.com/PubMatic-OpenWrap/openrtb" "github.com/PubMatic-OpenWrap/prebid-server/adapters" "github.com/PubMatic-OpenWrap/prebid-server/adapters/adapterstest" + "github.com/PubMatic-OpenWrap/prebid-server/config" "github.com/PubMatic-OpenWrap/prebid-server/errortypes" "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" ) func TestJsonSamples(t *testing.T) { - adapterstest.RunJSONBidderTest(t, "avocet", NewAvocetAdapter("https://bid.staging.avct.cloud/ortb/bid/5e722ee9bd6df11d063a8013")) + bidder, buildErr := Builder(openrtb_ext.BidderAvocet, config.Adapter{ + Endpoint: "https://bid.staging.avct.cloud/ortb/bid/5e722ee9bd6df11d063a8013"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "avocet", bidder) } func TestAvocetAdapter_MakeRequests(t *testing.T) { diff --git a/adapters/avocet/avocettest/exemplary/banner.json b/adapters/avocet/avocettest/exemplary/banner.json new file mode 100644 index 00000000000..ea5173f9137 --- /dev/null +++ b/adapters/avocet/avocettest/exemplary/banner.json @@ -0,0 +1,112 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "placement": "5ea9601ac865f911007f1b6a" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bid.staging.avct.cloud/ortb/bid/5e722ee9bd6df11d063a8013", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "placement": "5ea9601ac865f911007f1b6a" + } + } + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "bidid": "dd87f80c-16a0-43c8-a673-b94b3ea4d417", + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "adm": "", + "adomain": [ + "avocet.io" + ], + "cid": "5b51e2d689654741306813a4", + "crid": "5b51e49634f2021f127ff7c9", + "h": 250, + "id": "bc708396-9202-437b-b726-08b9864cb8b8", + "impid": "test-imp-id", + "iurl": "https://cdn.staging.avocet.io/snapshots/5b51dd1634f2021f127ff7c0/5b51e49634f2021f127ff7c9.jpeg", + "language": "en", + "price": 15.64434783, + "w": 300 + } + ], + "seat": "TEST_SEAT_ID" + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "adm": "", + "adomain": [ + "avocet.io" + ], + "cid": "5b51e2d689654741306813a4", + "crid": "5b51e49634f2021f127ff7c9", + "h": 250, + "id": "bc708396-9202-437b-b726-08b9864cb8b8", + "impid": "test-imp-id", + "iurl": "https://cdn.staging.avocet.io/snapshots/5b51dd1634f2021f127ff7c0/5b51e49634f2021f127ff7c9.jpeg", + "language": "en", + "price": 15.64434783, + "w": 300 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/avocet/avocettest/exemplary/video.json b/adapters/avocet/avocettest/exemplary/video.json new file mode 100644 index 00000000000..2398256b0dd --- /dev/null +++ b/adapters/avocet/avocettest/exemplary/video.json @@ -0,0 +1,104 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "protocols": [2, 5], + "w": 1920, + "h": 1080 + }, + "ext": { + "bidder": { + "placement": "5ea9601ac865f911007f1b6a" + } + } + } + ] + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bid.staging.avct.cloud/ortb/bid/5e722ee9bd6df11d063a8013", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": ["video/mp4"], + "protocols": [2, 5], + "w": 1920, + "h": 1080 + }, + "ext": { + "bidder": { + "placement": "5ea9601ac865f911007f1b6a" + } + } + } + ] + } + }, + "mockResponse": { + "status": 200, + "body": { + "bidid": "a0eec3aa-f9f6-42fb-9aa4-f1b5656d4f42", + "id": "749d36d7-c993-455f-aefd-ffd8a7e3ccf", + "seatbid": [ + { + "bid": [ + { + "adm": "Avocet", + "adomain": ["avocet.io"], + "cid": "5b51e2d689654741306813a4", + "crid": "5ec530e32d57fe1100f17d87", + "h": 396, + "id": "3d4c2d45-5a8c-43b8-9e15-4f48ac45204f", + "impid": "dfp-ad--top-above-nav", + "iurl": "https://cdn.staging.avocet.io/snapshots/5b51dd1634f2021f127ff7c0/5ec530e32d57fe1100f17d87.jpeg", + "language": "en", + "price": 15.64434783, + "w": 600, + "ext": { + "avocet": { + "duration": 30 + } + } + } + ], + "seat": "TEST_SEAT_ID" + } + ] + } + } + } + ], + + "expectedBids": [ + { + "bid": { + "adm": "Avocet", + "adomain": ["avocet.io"], + "cid": "5b51e2d689654741306813a4", + "crid": "5ec530e32d57fe1100f17d87", + "h": 396, + "id": "3d4c2d45-5a8c-43b8-9e15-4f48ac45204f", + "impid": "dfp-ad--top-above-nav", + "iurl": "https://cdn.staging.avocet.io/snapshots/5b51dd1634f2021f127ff7c0/5ec530e32d57fe1100f17d87.jpeg", + "language": "en", + "price": 15.64434783, + "w": 600, + "ext": { + "avocet": { + "duration": 30 + } + } + }, + "type": "video" + } + ] +} diff --git a/adapters/beachfront/beachfront.go b/adapters/beachfront/beachfront.go index c7d224c31a7..8aca4ca0427 100644 --- a/adapters/beachfront/beachfront.go +++ b/adapters/beachfront/beachfront.go @@ -11,9 +11,9 @@ import ( "github.com/PubMatic-OpenWrap/openrtb" "github.com/PubMatic-OpenWrap/prebid-server/adapters" + "github.com/PubMatic-OpenWrap/prebid-server/config" "github.com/PubMatic-OpenWrap/prebid-server/errortypes" "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" - "github.com/golang/glog" ) const Seat = "beachfront" @@ -24,7 +24,7 @@ const defaultVideoEndpoint = "https://reachms.bfmio.com/bid.json?exchange_id" const nurlVideoEndpointSuffix = "&prebidserver" const beachfrontAdapterName = "BF_PREBID_S2S" -const beachfrontAdapterVersion = "0.9.0" +const beachfrontAdapterVersion = "0.9.1" const minBidFloor = 0.01 @@ -202,8 +202,8 @@ func preprocess(request *openrtb.BidRequest) (beachfrontReqs beachfrontRequests, var bannerImps = make([]openrtb.Imp, 0) for i := 0; i < len(request.Imp); i++ { - if request.Imp[i].Banner != nil && ((request.Imp[i].Banner.Format[0].H != 0 && request.Imp[i].Banner.Format[0].W != 0) || - (request.Imp[i].Banner.H != nil && request.Imp[i].Banner.W != nil)) { + if request.Imp[i].Banner != nil && request.Imp[i].Banner.Format != nil && + request.Imp[i].Banner.Format[0].H != 0 && request.Imp[i].Banner.Format[0].W != 0 { bannerImps = append(bannerImps, request.Imp[i]) } @@ -232,11 +232,11 @@ func preprocess(request *openrtb.BidRequest) (beachfrontReqs beachfrontRequests, errs = append(errs, videoErrs...) for i := 0; i < len(videoList); i++ { - if videoList[i].VideoResponseType == "nurl" || videoList[i].VideoResponseType == "both" { + if videoList[i].VideoResponseType == "nurl" { beachfrontReqs.NurlVideo = append(beachfrontReqs.NurlVideo, videoList[i]) } - if videoList[i].VideoResponseType == "adm" || videoList[i].VideoResponseType == "both" { + if videoList[i].VideoResponseType == "adm" { beachfrontReqs.ADMVideo = append(beachfrontReqs.ADMVideo, videoList[i]) } } @@ -412,7 +412,7 @@ func getVideoRequests(request *openrtb.BidRequest) ([]beachfrontVideoRequest, [] if beachfrontExt.VideoResponseType != "" { bfReqs[i].VideoResponseType = beachfrontExt.VideoResponseType } else { - bfReqs[i].VideoResponseType = "nurl" + bfReqs[i].VideoResponseType = "adm" } bfReqs[i].Request = *request @@ -436,7 +436,7 @@ func getVideoRequests(request *openrtb.BidRequest) ([]beachfrontVideoRequest, [] } - if bfReqs[i].Request.Device.DeviceType == 0 { + if bfReqs[i].Request.Device != nil && bfReqs[i].Request.Device.DeviceType == 0 { // More fine graned deviceType methods will be added in the future bfReqs[i].Request.Device.DeviceType = fallBackDeviceType(request) } @@ -683,21 +683,39 @@ func removeVideoElement(slice []beachfrontVideoRequest, s int) []beachfrontVideo return append(slice[:s], slice[s+1:]...) } -func NewBeachfrontBidder(bannerEndpoint string, extraAdapterInfo string) adapters.Bidder { - var extraInfo ExtraInfo +// Builder builds a new instance of the Beachfront adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter) (adapters.Bidder, error) { + extraInfo, err := getExtraInfo(config.ExtraAdapterInfo) + if err != nil { + return nil, err + } - if len(extraAdapterInfo) == 0 { - extraAdapterInfo = "{\"video_endpoint\":\"" + defaultVideoEndpoint + "\"}" + bidder := &BeachfrontAdapter{ + bannerEndpoint: config.Endpoint, + extraInfo: extraInfo, } + return bidder, nil +} - if err := json.Unmarshal([]byte(extraAdapterInfo), &extraInfo); err != nil { - glog.Fatal("Invalid Beachfront extra adapter info: " + err.Error()) - return nil +func getExtraInfo(v string) (ExtraInfo, error) { + if len(v) == 0 { + return getDefaultExtraInfo(), nil + } + + var extraInfo ExtraInfo + if err := json.Unmarshal([]byte(v), &extraInfo); err != nil { + return extraInfo, fmt.Errorf("invalid extra info: %v", err) } if extraInfo.VideoEndpoint == "" { extraInfo.VideoEndpoint = defaultVideoEndpoint } - return &BeachfrontAdapter{bannerEndpoint: bannerEndpoint, extraInfo: extraInfo} + return extraInfo, nil +} + +func getDefaultExtraInfo() ExtraInfo { + return ExtraInfo{ + VideoEndpoint: defaultVideoEndpoint, + } } diff --git a/adapters/beachfront/beachfront_test.go b/adapters/beachfront/beachfront_test.go index 905fbde6c8b..aace3224534 100644 --- a/adapters/beachfront/beachfront_test.go +++ b/adapters/beachfront/beachfront_test.go @@ -4,8 +4,59 @@ import ( "testing" "github.com/PubMatic-OpenWrap/prebid-server/adapters/adapterstest" + "github.com/PubMatic-OpenWrap/prebid-server/config" + "github.com/PubMatic-OpenWrap/prebid-server/openrtb_ext" + "github.com/stretchr/testify/assert" ) func TestJsonSamples(t *testing.T) { - adapterstest.RunJSONBidderTest(t, "beachfronttest", NewBeachfrontBidder("https://display.bfmio.com/prebid_display", "{\"video_endpoint\":\"https://reachms.bfmio.com/bid.json?exchange_id\"}")) + bidder, buildErr := Builder(openrtb_ext.BidderBeachfront, config.Adapter{ + Endpoint: `https://qa.beachrtb.com/prebid_display`, + ExtraAdapterInfo: `{"video_endpoint":"https://qa.beachrtb.com/bid.json?exchange_id"}`, + }) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "beachfronttest", bidder) +} + +func TestExtraInfoDefaultWhenEmpty(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderBeachfront, config.Adapter{ + Endpoint: `https://qa.beachrtb.com/prebid_display`, + ExtraAdapterInfo: ``, + }) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + bidderBeachfront, _ := bidder.(*BeachfrontAdapter) + + assert.Equal(t, bidderBeachfront.extraInfo.VideoEndpoint, defaultVideoEndpoint) +} + +func TestExtraInfoDefaultWhenNotSpecified(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderBeachfront, config.Adapter{ + Endpoint: `https://qa.beachrtb.com/prebid_display`, + ExtraAdapterInfo: `{"video_endpoint":""}`, + }) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + bidderBeachfront, _ := bidder.(*BeachfrontAdapter) + + assert.Equal(t, bidderBeachfront.extraInfo.VideoEndpoint, defaultVideoEndpoint) +} + +func TestExtraInfoMalformed(t *testing.T) { + _, buildErr := Builder(openrtb_ext.BidderBeachfront, config.Adapter{ + Endpoint: `https://qa.beachrtb.com/prebid_display`, + ExtraAdapterInfo: `malformed`, + }) + + assert.Error(t, buildErr) } diff --git a/adapters/beachfront/beachfronttest/exemplary/adm-video-by-default.json b/adapters/beachfront/beachfronttest/exemplary/adm-video-by-default.json new file mode 100644 index 00000000000..d3fa41a23c5 --- /dev/null +++ b/adapters/beachfront/beachfronttest/exemplary/adm-video-by-default.json @@ -0,0 +1,123 @@ +{ + "mockBidRequest": { + "id": "adm-video", + "imp": [ + { + "id": "video1", + "ext": { + "bidder": { + "bidfloor": 3.01, + "appId": "videoAppId1" + } + }, + "video": { + "mimes": [ + "video/mp4" + ], + "context": "instream", + "w": 300, + "h": 250 + } + } + ], + "site": { + "page": "https://some.domain.us/some/page.html" + }, + "device":{ + "ip":"255.255.255.255" + } + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://qa.beachrtb.com/bid.json?exchange_id=videoAppId1", + "body": { + "id": "adm-video", + "imp": [ + { + "video": { + "w": 300, + "h": 250, + "mimes": [ + "video/mp4" + ] + }, + "bidfloor": 3.01, + "id": "video1", + "secure": 1 + } + ], + "site": { + "page": "https://some.domain.us/some/page.html", + "domain": "some.domain.us" + }, + "cur": [ + "USD" + ], + "device":{ + "devicetype": 2, + "ip":"255.255.255.255" + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "adm-video", + "seatBid": [ + { + "bid": [ + { + "id": "5fd7c8a6ff2f1f0d42ee6427", + "impid": "video1", + "price": 20, + "adm": "http://example.com/vast.xml", + "adid": "1088", + "adomain": [ + "beachfront.io" + ], + "cid": "277", + "crid": "532", + "w": 300, + "h": 250, + "ext": { + "duration": 30 + } + } + ], + "seat": "bfio-s-1" + } + ] + } + } + } + ], + + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "video1AdmVideo", + "impid": "video1", + "price": 20, + "adm": "http://example.com/vast.xml", + "adid": "1088", + "adomain": [ + "beachfront.io" + ], + "cid": "277", + "crid": "532", + "w": 300, + "h": 250, + "ext": { + "duration": 30 + } + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/beachfront/beachfronttest/exemplary/adm-video-by-explicit-type.json b/adapters/beachfront/beachfronttest/exemplary/adm-video-by-explicit-type.json new file mode 100644 index 00000000000..8c05d65a3b1 --- /dev/null +++ b/adapters/beachfront/beachfronttest/exemplary/adm-video-by-explicit-type.json @@ -0,0 +1,124 @@ +{ + "mockBidRequest": { + "id": "adm-video", + "imp": [ + { + "id": "video1", + "ext": { + "bidder": { + "videoResponseType": "adm", + "bidfloor": 3.01, + "appId": "videoAppId1" + } + }, + "video": { + "mimes": [ + "video/mp4" + ], + "context": "instream", + "w": 300, + "h": 250 + } + } + ], + "site": { + "page": "https://some.domain.us/some/page.html" + }, + "device":{ + "ip":"255.255.255.255" + } + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://qa.beachrtb.com/bid.json?exchange_id=videoAppId1", + "body": { + "id": "adm-video", + "imp": [ + { + "video": { + "w": 300, + "h": 250, + "mimes": [ + "video/mp4" + ] + }, + "bidfloor": 3.01, + "id": "video1", + "secure": 1 + } + ], + "site": { + "page": "https://some.domain.us/some/page.html", + "domain": "some.domain.us" + }, + "cur": [ + "USD" + ], + "device":{ + "devicetype": 2, + "ip":"255.255.255.255" + } + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "adm-video", + "seatBid": [ + { + "bid": [ + { + "id": "5fd7c8a6ff2f1f0d42ee6427", + "impid": "video1", + "price": 20, + "adm": "http://example.com/vast.xml", + "adid": "1088", + "adomain": [ + "beachfront.io" + ], + "cid": "277", + "crid": "532", + "w": 300, + "h": 250, + "ext": { + "duration": 30 + } + } + ], + "seat": "bfio-s-1" + } + ] + } + } + } + ], + + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "video1AdmVideo", + "impid": "video1", + "price": 20, + "adm": "http://example.com/vast.xml", + "adid": "1088", + "adomain": [ + "beachfront.io" + ], + "cid": "277", + "crid": "532", + "w": 300, + "h": 250, + "ext": { + "duration": 30 + } + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/beachfront/beachfronttest/exemplary/banner-and-adm-video-by-default.json b/adapters/beachfront/beachfronttest/exemplary/banner-and-adm-video-by-default.json new file mode 100644 index 00000000000..bff1b76a688 --- /dev/null +++ b/adapters/beachfront/beachfronttest/exemplary/banner-and-adm-video-by-default.json @@ -0,0 +1,187 @@ +{ + "mockBidRequest": { + "id": "banner-and-video", + "imp": [ + { + "id": "mix1", + "ext": { + "bidder": { + "bidfloor": 0.41, + "appIds": { + "banner": "bannerAppId1", + "video": "videoAppId1" + } + } + }, + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "video": { + "mimes": [ + "video/mp4" + ], + "context": "instream", + "w": 300, + "h": 250 + } + } + ], + "site": { + "page": "https://some.domain.us/some/page.html" + } + }, + + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://qa.beachrtb.com/prebid_display", + "body": { + "slots": [ + { + "slot": "mix1", + "id": "bannerAppId1", + "bidfloor": 0.41, + "sizes": [ + { + "w": 300, + "h": 250 + } + ] + } + ], + "domain": "some.domain.us", + "page": "https://some.domain.us/some/page.html", + "referrer": "", + "search": "", + "secure": 1, + "deviceOs": "", + "deviceModel": "", + "isMobile": 0, + "ua": "", + "ip": "", + "dnt": 0, + "user": {}, + "adapterName": "BF_PREBID_S2S", + "adapterVersion": "0.9.1", + "requestId": "banner-and-video" + } + }, + "mockResponse": { + "status": 200, + "body": [ + { + "crid": "crid_1", + "price": 9.5019655, + "w": 300, + "h": 250, + "slot": "mix1", + "adm": "
", - "id": "some_test_ad_id_1", - "impid": "some_test_ad_id_1", - "ttl": 300, - "crid": "94395500", - "w": 300, - "price": 2.942808, - "adid": "94395500", - "h": 250 - }, - "type": "banner" - }, + "expectedBidResponses": [ { - "bid": { - "adm": "00:00:15", - "id": "some_test_ad_id_2", - "impid": "some_test_ad_id_2", - "ttl": 300, - "crid": "9999999", - "w": 1020, - "price": 1, - "adid": "9999999", - "h": 1000 + "bids": [{ + "bid": { + "adm": "
", + "id": "some_test_ad_id_1", + "impid": "some_test_ad_id_1", + "crid": "94395500", + "w": 300, + "price": 2.942808, + "adid": "94395500", + "h": 250 + }, + "type": "banner" }, - "type": "video" + { + "bid": { + "adm": "00:00:15", + "id": "some_test_ad_id_2", + "impid": "some_test_ad_id_2", + "crid": "9999999", + "w": 1020, + "price": 1, + "adid": "9999999", + "h": 1000 + }, + "type": "video" + }] } ] } - \ No newline at end of file + diff --git a/adapters/emx_digital/emx_digitaltest/exemplary/banner-and-video-site.json b/adapters/emx_digital/emx_digitaltest/exemplary/banner-and-video-site.json index c2b20cf1c5d..15ae05d7835 100644 --- a/adapters/emx_digital/emx_digitaltest/exemplary/banner-and-video-site.json +++ b/adapters/emx_digital/emx_digitaltest/exemplary/banner-and-video-site.json @@ -167,34 +167,34 @@ } }], - "expectedBids": [{ - "bid": { - "adm": "
", - "id": "some_test_ad_id_1", - "impid": "some_test_ad_id_1", - "ttl": 300, - "crid": "94395500", - "w": 300, - "price": 2.942808, - "adid": "94395500", - "h": 250 - }, - "type": "banner" - }, - { - "bid": { - "adm": "00:00:15", - "id": "some_test_ad_id_2", - "impid": "some_test_ad_id_2", - "ttl": 300, - "crid": "9999999", - "w": 1020, - "price": 1, - "adid": "9999999", - "h": 1000 + "expectedBidResponses": [{ + "bids": [{ + "bid": { + "adm": "
", + "id": "some_test_ad_id_1", + "impid": "some_test_ad_id_1", + "crid": "94395500", + "w": 300, + "price": 2.942808, + "adid": "94395500", + "h": 250 + }, + "type": "banner" }, - "type": "video" + { + "bid": { + "adm": "00:00:15", + "id": "some_test_ad_id_2", + "impid": "some_test_ad_id_2", + "crid": "9999999", + "w": 1020, + "price": 1, + "adid": "9999999", + "h": 1000 + }, + "type": "video" + }] } ] } - \ No newline at end of file + diff --git a/adapters/emx_digital/emx_digitaltest/exemplary/banner-app.json b/adapters/emx_digital/emx_digitaltest/exemplary/banner-app.json index 8de90f52192..20c62402fc1 100644 --- a/adapters/emx_digital/emx_digitaltest/exemplary/banner-app.json +++ b/adapters/emx_digital/emx_digitaltest/exemplary/banner-app.json @@ -102,18 +102,19 @@ } }], - "expectedBids": [{ - "bid": { - "adm": "