diff --git a/.github/workflows/code-path-changes.yml b/.github/workflows/code-path-changes.yml index 04b49c4a1f4..23e0c19db6d 100644 --- a/.github/workflows/code-path-changes.yml +++ b/.github/workflows/code-path-changes.yml @@ -14,6 +14,9 @@ env: GITHUB_PR_NUMBER: ${{ github.event.pull_request.number }} GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} +permissions: + contents: read + jobs: notify: runs-on: ubuntu-latest diff --git a/adapters/connatix/connatix.go b/adapters/connatix/connatix.go index 74ff5956848..d2f900d9c22 100644 --- a/adapters/connatix/connatix.go +++ b/adapters/connatix/connatix.go @@ -199,7 +199,8 @@ func buildRequestImp(imp *openrtb2.Imp, ext impExtIncoming, displayManagerVer st impExt := impExt{ Connatix: impExtConnatix{ - PlacementId: ext.Bidder.PlacementId, + PlacementId: ext.Bidder.PlacementId, + ViewabilityPercentage: ext.Bidder.ViewabilityPercentage, }, } diff --git a/adapters/connatix/connatixtest/supplemental/success-build-display-manager-version.json b/adapters/connatix/connatixtest/supplemental/success-build-display-manager-version.json index 7baffa28ac7..bf74b77a03a 100644 --- a/adapters/connatix/connatixtest/supplemental/success-build-display-manager-version.json +++ b/adapters/connatix/connatixtest/supplemental/success-build-display-manager-version.json @@ -43,7 +43,8 @@ }, "ext": { "bidder": { - "placementId": "some-placement-id" + "placementId": "some-placement-id", + "viewabilityPercentage": 0.6 } } } @@ -78,7 +79,8 @@ "displaymanagerver": "test-1.0.0", "ext": { "connatix": { - "placementId": "some-placement-id" + "placementId": "some-placement-id", + "viewabilityPercentage": 0.6 } } } diff --git a/adapters/connatix/models.go b/adapters/connatix/models.go index 55d475f9638..95317d7e23a 100644 --- a/adapters/connatix/models.go +++ b/adapters/connatix/models.go @@ -17,7 +17,8 @@ type impExt struct { } type impExtConnatix struct { - PlacementId string `json:"placementId,omitempty"` + PlacementId string `json:"placementId,omitempty"` + ViewabilityPercentage float64 `json:"viewabilityPercentage,omitempty"` } type bidExt struct { diff --git a/adapters/loopme/loopme.go b/adapters/loopme/loopme.go new file mode 100644 index 00000000000..d4b9d7906fc --- /dev/null +++ b/adapters/loopme/loopme.go @@ -0,0 +1,116 @@ +package loopme + +import ( + "encoding/json" + "fmt" + "net/http" + + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v3/adapters" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/errortypes" + "github.com/prebid/prebid-server/v3/openrtb_ext" +) + +type adapter struct { + endpoint string +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + errs := make([]error, 0, len(request.Imp)) + + reqDatas := make([]*adapters.RequestData, 0, len(request.Imp)) + + for _, imp := range request.Imp { + requestCopy := *request + requestCopy.Imp = []openrtb2.Imp{imp} + reqJSON, err := json.Marshal(requestCopy) + if err != nil { + errs = append(errs, err) + continue + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + reqDatas = append(reqDatas, &adapters.RequestData{ + Method: http.MethodPost, + Uri: a.endpoint, + Body: reqJSON, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(requestCopy.Imp), + }) + + } + return reqDatas, errs +} + +func (a *adapter) MakeBids(bidReq *openrtb2.BidRequest, reqData *adapters.RequestData, respData *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(respData) { + return nil, nil + } + + if err := adapters.CheckResponseStatusCodeForErrors(respData); err != nil { + return nil, []error{err} + } + + var bidResp openrtb2.BidResponse + if err := json.Unmarshal(respData.Body, &bidResp); err != nil { + return nil, []error{err} + } + + if len(bidResp.SeatBid) == 0 || len(bidResp.SeatBid[0].Bid) == 0 { + return nil, nil + } + + errs := make([]error, 0, len(bidResp.SeatBid[0].Bid)) + resp := adapters.NewBidderResponseWithBidsCapacity(len(bidResp.SeatBid[0].Bid)) + + for _, sb := range bidResp.SeatBid { + for i := range sb.Bid { + bid := &sb.Bid[i] + bidType, err := getBidType(bid) + if err != nil { + errs = append(errs, err) + continue + } + resp.Bids = append(resp.Bids, &adapters.TypedBid{ + Bid: bid, + BidType: bidType, + }) + } + } + + if len(resp.Bids) == 0 { + return nil, errs + } + if len(bidResp.Cur) != 0 { + resp.Currency = bidResp.Cur + } + return resp, errs +} + +func getBidType(bid *openrtb2.Bid) (openrtb_ext.BidType, error) { + switch bid.MType { + case openrtb2.MarkupBanner: + return openrtb_ext.BidTypeBanner, nil + case openrtb2.MarkupVideo: + return openrtb_ext.BidTypeVideo, nil + case openrtb2.MarkupNative: + return openrtb_ext.BidTypeNative, nil + case openrtb2.MarkupAudio: + return openrtb_ext.BidTypeAudio, nil + default: + return "", &errortypes.BadServerResponse{ + Message: fmt.Sprintf("Unsupported MType %d", bid.MType), + } + } +} + +// Builder builds a new instance of the Loopme adapter for the given bidder with the given config. +func Builder(bidderName openrtb_ext.BidderName, cfg config.Adapter, serverCfg config.Server) (adapters.Bidder, error) { + bidder := &adapter{ + endpoint: cfg.Endpoint, + } + return bidder, nil +} diff --git a/adapters/loopme/loopme_test.go b/adapters/loopme/loopme_test.go new file mode 100644 index 00000000000..ca293c45cee --- /dev/null +++ b/adapters/loopme/loopme_test.go @@ -0,0 +1,29 @@ +package loopme + +import ( + "testing" + + "github.com/prebid/prebid-server/v3/adapters/adapterstest" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/openrtb_ext" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder( + openrtb_ext.BidderLoopme, + config.Adapter{ + Endpoint: "http://loopme.example.com", + }, + config.Server{ + ExternalUrl: "http://hosturl.com", + GvlID: 109, + DataCenter: "2", + }, + ) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "loopmetest", bidder) +} diff --git a/adapters/loopme/loopmetest/exemplary/app-formats.json b/adapters/loopme/loopmetest/exemplary/app-formats.json new file mode 100644 index 00000000000..4c70a4b5536 --- /dev/null +++ b/adapters/loopme/loopmetest/exemplary/app-formats.json @@ -0,0 +1,152 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 3, + 5, + 6 + ], + "w": 1024, + "h": 576 + }, + "native": { + "request": "{json string 1}", + "ver": "1.2" + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://loopme.example.com", + "body": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 3, + 5, + 6 + ], + "w": 1024, + "h": 576 + }, + "native": { + "request": "{json string 1}", + "ver": "1.2" + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "loopme", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 728, + "h": 90, + "mtype": 1 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 728, + "h": 90, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/loopme/loopmetest/exemplary/app-imps.json b/adapters/loopme/loopmetest/exemplary/app-imps.json new file mode 100644 index 00000000000..477639d9305 --- /dev/null +++ b/adapters/loopme/loopmetest/exemplary/app-imps.json @@ -0,0 +1,343 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "imp-1", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 3, + 5, + 6 + ], + "w": 1024, + "h": 576 + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + }, + { + "id": "imp-2", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 3, + 5, + 6 + ], + "w": 1024, + "h": 576 + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + }, + { + "id": "imp-3", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://loopme.example.com", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "body": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "imp-1", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 3, + 5, + 6 + ], + "w": 1024, + "h": 576 + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "impIDs": [ + "imp-1" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "loopme", + "bid": [ + { + "id": "bid-1", + "impid": "imp-1", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 1024, + "h": 576, + "mtype": 2 + } + ] + } + ] + } + } + }, + { + "expectedRequest": { + "uri": "http://loopme.example.com", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "body": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "imp-2", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 3, + 5, + 6 + ], + "w": 1024, + "h": 576 + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "impIDs": [ + "imp-2" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "loopme", + "bid": [ + { + "id": "bid-2", + "impid": "imp-2", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 1024, + "h": 576, + "mtype": 2 + } + ] + } + ] + } + } + }, + { + "expectedRequest": { + "uri": "http://loopme.example.com", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "body": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "imp-3", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "impIDs": [ + "imp-3" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "loopme", + "bid": [ + { + "id": "bid-3", + "impid": "imp-3", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 728, + "h": 90, + "mtype": 1 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-1", + "impid": "imp-1", + "price": 0.5, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 1024, + "h": 576, + "mtype": 2 + }, + "type": "video" + } + ] + }, + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-2", + "impid": "imp-2", + "price": 0.5, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 1024, + "h": 576, + "mtype": 2 + }, + "type": "video" + } + ] + }, + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "bid-3", + "impid": "imp-3", + "price": 0.5, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 728, + "h": 90, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} + + + diff --git a/adapters/loopme/loopmetest/exemplary/no-bid.json b/adapters/loopme/loopmetest/exemplary/no-bid.json new file mode 100644 index 00000000000..a35004eb6a7 --- /dev/null +++ b/adapters/loopme/loopmetest/exemplary/no-bid.json @@ -0,0 +1,90 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 3, + 5, + 6 + ], + "w": 1024, + "h": 576 + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://loopme.example.com", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "body": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 3, + 5, + 6 + ], + "w": 1024, + "h": 576 + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 204, + "body": { + } + } + } + ], + "expectedBidResponses": [] +} diff --git a/adapters/loopme/loopmetest/exemplary/no-seat-bid.json b/adapters/loopme/loopmetest/exemplary/no-seat-bid.json new file mode 100644 index 00000000000..054a1d8a298 --- /dev/null +++ b/adapters/loopme/loopmetest/exemplary/no-seat-bid.json @@ -0,0 +1,97 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 3, + 5, + 6 + ], + "w": 1024, + "h": 576 + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://loopme.example.com", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "body": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 3, + 5, + 6 + ], + "w": 1024, + "h": 576 + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "loopme", + "bid": [] + } + ] + } + } + } + ], + "expectedBidResponses": [] +} \ No newline at end of file diff --git a/adapters/loopme/loopmetest/exemplary/no-seat.json b/adapters/loopme/loopmetest/exemplary/no-seat.json new file mode 100644 index 00000000000..c5497b3957e --- /dev/null +++ b/adapters/loopme/loopmetest/exemplary/no-seat.json @@ -0,0 +1,92 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 3, + 5, + 6 + ], + "w": 1024, + "h": 576 + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://loopme.example.com", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "body": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 3, + 5, + 6 + ], + "w": 1024, + "h": 576 + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [] + } + } + } + ], + "expectedBidResponses": [] +} \ No newline at end of file diff --git a/adapters/loopme/loopmetest/exemplary/simple-app-audio.json b/adapters/loopme/loopmetest/exemplary/simple-app-audio.json new file mode 100644 index 00000000000..7c51d8cd063 --- /dev/null +++ b/adapters/loopme/loopmetest/exemplary/simple-app-audio.json @@ -0,0 +1,108 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "test-imp-id", + "audio": { + "mimes": [ + "audio/mp4" + ], + "protocols": [ + 9, + 10 + ] + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://loopme.example.com", + "body": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "test-imp-id", + "audio": { + "mimes": [ + "audio/mp4" + ], + "protocols": [ + 9, + 10 + ] + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "loopme", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "test-crid", + "mtype": 3 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "crid": "test-crid", + "mtype": 3 + }, + "type": "audio" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/loopme/loopmetest/exemplary/simple-app-banner.json b/adapters/loopme/loopmetest/exemplary/simple-app-banner.json new file mode 100644 index 00000000000..6b3ab6c9752 --- /dev/null +++ b/adapters/loopme/loopmetest/exemplary/simple-app-banner.json @@ -0,0 +1,118 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://loopme.example.com", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "body": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "loopme", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 728, + "h": 90, + "mtype": 1 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 728, + "h": 90, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/loopme/loopmetest/exemplary/simple-app-native.json b/adapters/loopme/loopmetest/exemplary/simple-app-native.json new file mode 100644 index 00000000000..629d07c2f70 --- /dev/null +++ b/adapters/loopme/loopmetest/exemplary/simple-app-native.json @@ -0,0 +1,97 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "test-imp-id", + "native": { + "request": "{\"ver\":\"1.2\",\"context\":2,\"contextsubtype\":20,\"plcmttype\":11,\"plcmtcnt\":1,\"aurlsupport\":1,\"durlsupport\":1,\"assets\":[{\"id\":123,\"required\":1,\"title\":{\"len\":140}},{\"id\":128,\"required\":0,\"img\":{\"wmin\":836,\"hmin\":627,\"type\":3}}]}" + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "http://loopme.example.com", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "body": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "test-imp-id", + "native": { + "request": "{\"ver\":\"1.2\",\"context\":2,\"contextsubtype\":20,\"plcmttype\":11,\"plcmtcnt\":1,\"aurlsupport\":1,\"durlsupport\":1,\"assets\":[{\"id\":123,\"required\":1,\"title\":{\"len\":140}},{\"id\":128,\"required\":0,\"img\":{\"wmin\":836,\"hmin\":627,\"type\":3}}]}" + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "native-json", + "crid": "test-crid", + "mtype": 4 + } + ] + } + ] + } + } + }], + + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "native-json", + "crid": "test-crid", + "mtype": 4 + }, + "type": "native" + }] + }] +} diff --git a/adapters/loopme/loopmetest/exemplary/simple-app-video.json b/adapters/loopme/loopmetest/exemplary/simple-app-video.json new file mode 100644 index 00000000000..d90c7f2733a --- /dev/null +++ b/adapters/loopme/loopmetest/exemplary/simple-app-video.json @@ -0,0 +1,128 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 3, + 5, + 6 + ], + "w": 1024, + "h": 576 + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://loopme.example.com", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "body": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid" + }, + "device": { + "ifa": "ec943cb9-61ec-460f-a925-6489c3fcc4e3" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 3, + 5, + 6 + ], + "w": 1024, + "h": 576 + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "loopme", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 1024, + "h": 576, + "mtype": 2 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 1024, + "h": 576, + "mtype": 2 + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/loopme/loopmetest/exemplary/simple-site-audio.json b/adapters/loopme/loopmetest/exemplary/simple-site-audio.json new file mode 100644 index 00000000000..8e586afd1de --- /dev/null +++ b/adapters/loopme/loopmetest/exemplary/simple-site-audio.json @@ -0,0 +1,108 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "audio": { + "mimes": [ + "audio/mp4" + ], + "protocols": [ + 9, + 10 + ] + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://loopme.example.com", + "body": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "audio": { + "mimes": [ + "audio/mp4" + ], + "protocols": [ + 9, + 10 + ] + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "loopme", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "test-crid", + "mtype": 3 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "crid": "test-crid", + "mtype": 3 + }, + "type": "audio" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/loopme/loopmetest/exemplary/simple-site-banner.json b/adapters/loopme/loopmetest/exemplary/simple-site-banner.json new file mode 100644 index 00000000000..d3d87e813af --- /dev/null +++ b/adapters/loopme/loopmetest/exemplary/simple-site-banner.json @@ -0,0 +1,118 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://loopme.example.com", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "body": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "loopme", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 728, + "h": 90, + "mtype": 1 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 728, + "h": 90, + "mtype": 1 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/loopme/loopmetest/exemplary/simple-site-native.json b/adapters/loopme/loopmetest/exemplary/simple-site-native.json new file mode 100644 index 00000000000..ef8cf46b820 --- /dev/null +++ b/adapters/loopme/loopmetest/exemplary/simple-site-native.json @@ -0,0 +1,97 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "native": { + "request": "{\"ver\":\"1.2\",\"context\":2,\"contextsubtype\":20,\"plcmttype\":11,\"plcmtcnt\":1,\"aurlsupport\":1,\"durlsupport\":1,\"assets\":[{\"id\":123,\"required\":1,\"title\":{\"len\":140}},{\"id\":128,\"required\":0,\"img\":{\"wmin\":836,\"hmin\":627,\"type\":3}}]}" + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "httpCalls": [{ + "expectedRequest": { + "uri": "http://loopme.example.com", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "body": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "native": { + "request": "{\"ver\":\"1.2\",\"context\":2,\"contextsubtype\":20,\"plcmttype\":11,\"plcmtcnt\":1,\"aurlsupport\":1,\"durlsupport\":1,\"assets\":[{\"id\":123,\"required\":1,\"title\":{\"len\":140}},{\"id\":128,\"required\":0,\"img\":{\"wmin\":836,\"hmin\":627,\"type\":3}}]}" + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "native-json", + "crid": "test-crid", + "mtype": 4 + } + ] + } + ] + } + } + }], + + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "native-json", + "crid": "test-crid", + "mtype": 4 + }, + "type": "native" + }] + }] +} diff --git a/adapters/loopme/loopmetest/exemplary/simple-site-video.json b/adapters/loopme/loopmetest/exemplary/simple-site-video.json new file mode 100644 index 00000000000..b5b70d2cc46 --- /dev/null +++ b/adapters/loopme/loopmetest/exemplary/simple-site-video.json @@ -0,0 +1,128 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 3, + 5, + 6 + ], + "w": 1024, + "h": 576 + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://loopme.example.com", + "headers": { + "Accept": [ + "application/json" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ] + }, + "body": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "video": { + "mimes": [ + "video/mp4" + ], + "protocols": [ + 2, + 3, + 5, + 6 + ], + "w": 1024, + "h": 576 + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "cur": "USD", + "seatbid": [ + { + "seat": "loopme", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 1024, + "h": 576, + "mtype": 2 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 1024, + "h": 576, + "mtype": 2 + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/loopme/loopmetest/supplemental/resp-bad-json.json b/adapters/loopme/loopmetest/supplemental/resp-bad-json.json new file mode 100644 index 00000000000..0c73aa4a431 --- /dev/null +++ b/adapters/loopme/loopmetest/supplemental/resp-bad-json.json @@ -0,0 +1,76 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://loopme.example.com", + "body": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": "this is not a valid json" + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "json: cannot unmarshal*", + "comparison": "regex" + } + ] +} diff --git a/adapters/loopme/loopmetest/supplemental/resp-bad-markuptype.json b/adapters/loopme/loopmetest/supplemental/resp-bad-markuptype.json new file mode 100644 index 00000000000..58a6b438b79 --- /dev/null +++ b/adapters/loopme/loopmetest/supplemental/resp-bad-markuptype.json @@ -0,0 +1,96 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://loopme.example.com", + "body": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "seat": "loopme", + "bid": [ + { + "id": "8ee514f1-b2b8-4abb-89fd-084437d1e800", + "impid": "test-imp-id", + "price": 0.500000, + "adm": "some-test-ad", + "crid": "test-crid", + "w": 728, + "h": 90, + "mtype": 0 + } + ] + } + ], + "cur": "USD" + } + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unsupported MType 0", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/loopme/loopmetest/supplemental/status-400.json b/adapters/loopme/loopmetest/supplemental/status-400.json new file mode 100644 index 00000000000..e112103abb0 --- /dev/null +++ b/adapters/loopme/loopmetest/supplemental/status-400.json @@ -0,0 +1,76 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://loopme.example.com", + "body": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 400, + "body": "invalid params" + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 400. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} diff --git a/adapters/loopme/loopmetest/supplemental/status-500.json b/adapters/loopme/loopmetest/supplemental/status-500.json new file mode 100644 index 00000000000..f25c9f321d1 --- /dev/null +++ b/adapters/loopme/loopmetest/supplemental/status-500.json @@ -0,0 +1,76 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://loopme.example.com", + "body": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 500, + "body": "Internal Server Error" + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 500. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/loopme/loopmetest/supplemental/status-503.json b/adapters/loopme/loopmetest/supplemental/status-503.json new file mode 100644 index 00000000000..97bd77753c7 --- /dev/null +++ b/adapters/loopme/loopmetest/supplemental/status-503.json @@ -0,0 +1,76 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://loopme.example.com", + "body": { + "id": "test-request-id", + "site": { + "page": "prebid.org" + }, + "user": { + "buyeruid": "be5e209ad46927520000000000000000" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 728, + "h": 90 + } + ] + }, + "ext": { + "bidder": { + "publisherId": "10000000" + } + } + } + ] + }, + "impIDs": [ + "test-imp-id" + ] + }, + "mockResponse": { + "status": 503, + "body": "" + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 503. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} \ No newline at end of file diff --git a/adapters/loopme/params_test.go b/adapters/loopme/params_test.go new file mode 100644 index 00000000000..12ddf8e9856 --- /dev/null +++ b/adapters/loopme/params_test.go @@ -0,0 +1,84 @@ +package loopme + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v3/openrtb_ext" +) + +// This file actually intends to test static/bidder-params/loopme.json +// +// These also validate the format of the external API: request.imp[i].ext.prebid.bidder.loopme + +// TestValidParams makes sure that the loopme 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.BidderLoopme, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected loopme params: %s", validParam) + } + } +} + +// TestInvalidParams makes sure that the loopme schema rejects all the imp.ext fields we don't support. +func TestInvalidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + if err != nil { + t.Fatalf("Failed to fetch the json-schemas. %v", err) + } + + for _, invalidParam := range invalidParams { + if err := validator.Validate(openrtb_ext.BidderLoopme, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} + +var validParams = []string{ + `{"publisherId": "10000000"}`, + `{"publisherId": "10000001", "bundleId": "4321"}`, + `{"publisherId": "10000002", "placementId": "8888"}`, + `{"publisherId": "10000003", "bundleId": "5432", "placementId": "7777"}`, +} + +var invalidParams = []string{ + ``, + `null`, + `undefined`, + `0`, + `{}`, + `[]`, + `{"publisherId": ""}`, + `{"placementId": ""}`, + `{"bundleId": ""}`, + `{"publisherId": "", "placementId": ""}`, + `{"publisherId": "", "bundleId": ""}`, + `{"placementId": "", "bundleId": ""}`, + `{"publisherId": "", "placementId": "", "bundleId": ""}`, + `{"publisherId": 0}`, + `{"placementId": 0}`, + `{"bundleId": 0}`, + `{"publisherId": 0, "placementId": 0}`, + `{"publisherId": 0, "bundleId": 0}`, + `{"placementId": 0, "bundleId": 0}`, + `{"publisherId": 0, "placementId": 0, "bundleId": 0}`, + `{"publisherId": "10000000", "placementId": 0}`, + `{"publisherId": "10000000", "placementId": 100000}`, + `{"publisherId": "10000000", "bundleId": 0}`, + `{"publisherId": "10000000", "bundleId": 100000}`, + `{"placementId": "10000000", "bundleId": 0}`, + `{"placementId": "10000000", "bundleId": 100000}`, + `{"publisherId": "10000000", "placementId": "", "bundleId": ""}`, + `{"publisherId": "", "placementId": "100000", "bundleId": ""}`, + `{"publisherId": "", "placementId": "", "bundleId": "bundle_id_test"}`, + `{"unknownField": "value"}`, + `{"bundleId": []}`, + `{"placementId": {}}`, + `{"publisherId": null}`, + `{"bundleId": null}`, +} diff --git a/adapters/nextmillennium/nextmillennium.go b/adapters/nextmillennium/nextmillennium.go index cae3e03be19..1b3cdeefdd3 100644 --- a/adapters/nextmillennium/nextmillennium.go +++ b/adapters/nextmillennium/nextmillennium.go @@ -11,8 +11,11 @@ import ( "github.com/prebid/prebid-server/v3/errortypes" "github.com/prebid/prebid-server/v3/openrtb_ext" "github.com/prebid/prebid-server/v3/util/jsonutil" + "github.com/prebid/prebid-server/v3/version" ) +const NM_ADAPTER_VERSION = "v1.0.0" + type adapter struct { endpoint string nmmFlags []string @@ -33,7 +36,9 @@ type nmExtPrebid struct { Server *server `json:"server,omitempty"` } type nmExtNMM struct { - NmmFlags []string `json:"nmmFlags,omitempty"` + NmmFlags []string `json:"nmmFlags,omitempty"` + ServerVersion string `json:"server_version,omitempty"` + AdapterVersion string `json:"nm_version,omitempty"` } type nextMillJsonExt struct { Prebid nmExtPrebid `json:"prebid"` @@ -149,6 +154,8 @@ func createBidRequest(prebidBidRequest *openrtb2.BidRequest, params *openrtb_ext DataCenter: serverParams.DataCenter, ExternalUrl: serverParams.ExternalUrl, } + ext.NextMillennium.AdapterVersion = NM_ADAPTER_VERSION + ext.NextMillennium.ServerVersion = version.Ver jsonExt, err := json.Marshal(ext) if err != nil { return &bidRequest diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-empty-group-id.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-empty-group-id.json index 9b54c58a0bf..f44bf6b01f7 100644 --- a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-empty-group-id.json +++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-empty-group-id.json @@ -33,7 +33,9 @@ "body":{ "id": "testid", "ext": { - "nextMillennium": {}, + "nextMillennium": { + "nm_version": "v1.0.0" + }, "prebid": { "storedrequest": { "id": "7819" diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-group-id.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-group-id.json index d8f6915bf28..4962cb01b32 100644 --- a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-group-id.json +++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-group-id.json @@ -44,7 +44,9 @@ "body":{ "id": "testid", "ext": { - "nextMillennium": {}, + "nextMillennium": { + "nm_version": "v1.0.0" + }, "prebid": { "storedrequest": { "id": "g7819;320x250;www.example.com" diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-group-id_app.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-group-id_app.json index 2f0d9789b0c..97152efd359 100644 --- a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-group-id_app.json +++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-group-id_app.json @@ -40,7 +40,9 @@ "domain": "www.example.com" }, "ext": { - "nextMillennium": {}, + "nextMillennium": { + "nm_version": "v1.0.0" + }, "prebid": { "storedrequest": { "id": "g7819;320x250;www.example.com" diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-only-width.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-only-width.json index 35cb9bb7581..42f148ce836 100644 --- a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-only-width.json +++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-only-width.json @@ -29,7 +29,9 @@ "domain": "www.example.com" }, "ext": { - "nextMillennium": {}, + "nextMillennium": { + "nm_version": "v1.0.0" + }, "prebid": { "storedrequest": { "id": "g7819;;www.example.com" diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-wh.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-wh.json index 6206b4a2828..81fef905bfd 100644 --- a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-wh.json +++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-with-wh.json @@ -30,7 +30,9 @@ "domain": "www.example.com" }, "ext": { - "nextMillennium": {}, + "nextMillennium": { + "nm_version": "v1.0.0" + }, "prebid": { "storedrequest": { "id": "g7819;320x250;www.example.com" diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-wo-domain.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-wo-domain.json index ddefb32fa90..ab4d9682045 100644 --- a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-wo-domain.json +++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-wo-domain.json @@ -34,7 +34,9 @@ "body":{ "id": "testid", "ext": { - "nextMillennium": {}, + "nextMillennium": { + "nm_version": "v1.0.0" + }, "prebid": { "storedrequest": { "id": "g7819;320x250;" diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-wo-size.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-wo-size.json index 337876ad0e5..da8bd4bcbea 100644 --- a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-wo-size.json +++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner-wo-size.json @@ -32,7 +32,9 @@ "body":{ "id": "testid", "ext": { - "nextMillennium": {}, + "nextMillennium": { + "nm_version": "v1.0.0" + }, "prebid": { "storedrequest": { "id": "g7819;320x250;" diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner.json index 2f60bb95916..f28d4ab15b1 100644 --- a/adapters/nextmillennium/nextmillenniumtest/exemplary/banner.json +++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/banner.json @@ -34,7 +34,9 @@ "body":{ "id": "testid", "ext": { - "nextMillennium": {}, + "nextMillennium": { + "nm_version": "v1.0.0" + }, "prebid": { "storedrequest": { "id": "7819" diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/empty-banner-obj.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/empty-banner-obj.json index cadef9cdb5c..f3eb360e2e0 100644 --- a/adapters/nextmillennium/nextmillenniumtest/exemplary/empty-banner-obj.json +++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/empty-banner-obj.json @@ -21,7 +21,9 @@ "body":{ "id": "testid", "ext": { - "nextMillennium": {}, + "nextMillennium": { + "nm_version": "v1.0.0" + }, "prebid": { "storedrequest": { "id": "g7819;;" diff --git a/adapters/nextmillennium/nextmillenniumtest/exemplary/video.json b/adapters/nextmillennium/nextmillenniumtest/exemplary/video.json index ff96522166a..e31aa1e0ac2 100644 --- a/adapters/nextmillennium/nextmillenniumtest/exemplary/video.json +++ b/adapters/nextmillennium/nextmillenniumtest/exemplary/video.json @@ -30,7 +30,9 @@ "body":{ "id": "testid", "ext": { - "nextMillennium": {}, + "nextMillennium": { + "nm_version": "v1.0.0" + }, "prebid": { "storedrequest": { "id": "7819" diff --git a/adapters/nextmillennium/nextmillenniumtest/supplemental/empty-seatbid.json b/adapters/nextmillennium/nextmillenniumtest/supplemental/empty-seatbid.json index e75d787e28a..02331a1d931 100644 --- a/adapters/nextmillennium/nextmillenniumtest/supplemental/empty-seatbid.json +++ b/adapters/nextmillennium/nextmillenniumtest/supplemental/empty-seatbid.json @@ -33,7 +33,9 @@ "body": { "id": "testid", "ext": { - "nextMillennium": {}, + "nextMillennium": { + "nm_version": "v1.0.0" + }, "prebid": { "storedrequest": { "id": "7819" diff --git a/adapters/nextmillennium/nextmillenniumtest/supplemental/error-response.json b/adapters/nextmillennium/nextmillenniumtest/supplemental/error-response.json index b2d69c3ebc7..fdf6d11943e 100644 --- a/adapters/nextmillennium/nextmillenniumtest/supplemental/error-response.json +++ b/adapters/nextmillennium/nextmillenniumtest/supplemental/error-response.json @@ -29,7 +29,9 @@ "body": { "id": "testid", "ext": { - "nextMillennium": {}, + "nextMillennium": { + "nm_version": "v1.0.0" + }, "prebid": { "storedrequest": { "id": "7819" diff --git a/adapters/nextmillennium/nextmillenniumtest/supplemental/no-content.json b/adapters/nextmillennium/nextmillenniumtest/supplemental/no-content.json index d7ad3f64fcd..d2641f62eab 100644 --- a/adapters/nextmillennium/nextmillenniumtest/supplemental/no-content.json +++ b/adapters/nextmillennium/nextmillenniumtest/supplemental/no-content.json @@ -29,7 +29,9 @@ "body": { "id": "testid", "ext": { - "nextMillennium": {}, + "nextMillennium": { + "nm_version": "v1.0.0" + }, "prebid": { "storedrequest": { "id": "7819" diff --git a/adapters/smoot/params_test.go b/adapters/smoot/params_test.go new file mode 100644 index 00000000000..ef0ec2149ba --- /dev/null +++ b/adapters/smoot/params_test.go @@ -0,0 +1,57 @@ +package smoot + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v3/openrtb_ext" +) + +func TestValidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + if err != nil { + t.Fatalf("Failed to fetch the json schema. %v", err) + } + + for _, p := range validParams { + if err := validator.Validate(openrtb_ext.BidderSmoot, json.RawMessage(p)); err != nil { + t.Errorf("Schema rejected valid params: %s", p) + } + } +} + +func TestInvalidParams(t *testing.T) { + validator, err := openrtb_ext.NewBidderParamsValidator("../../static/bidder-params") + if err != nil { + t.Fatalf("Failed to fetch the json schema. %v", err) + } + + for _, p := range invalidParams { + if err := validator.Validate(openrtb_ext.BidderSmoot, json.RawMessage(p)); err == nil { + t.Errorf("Schema allowed invalid params: %s", p) + } + } +} + +var validParams = []string{ + `{"placementId": "test"}`, + `{"placementId": "1"}`, + `{"endpointId": "test"}`, + `{"endpointId": "1"}`, +} + +var invalidParams = []string{ + `{"placementId": 42}`, + `{"endpointId": 42}`, + `{"placementId": "1", "endpointId": "1"}`, + ``, + `null`, + `true`, + `5`, + `4.2`, + `[]`, + `{}`, + `{"placementId": ""}`, + `{"endpointId": ""}`, + `{"placementId": "", "endpointId": ""}`, +} diff --git a/adapters/smoot/smoot.go b/adapters/smoot/smoot.go new file mode 100644 index 00000000000..e23c2de602d --- /dev/null +++ b/adapters/smoot/smoot.go @@ -0,0 +1,152 @@ +package smoot + +import ( + "encoding/json" + "fmt" + "net/http" + + "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v3/adapters" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/openrtb_ext" + "github.com/prebid/prebid-server/v3/util/jsonutil" +) + +type adapter struct { + endpoint string +} + +type reqBodyExt struct { + SmootBidderExt reqBodyExtBidder `json:"bidder"` +} + +type reqBodyExtBidder struct { + Type string `json:"type"` + PlacementID string `json:"placementId,omitempty"` + EndpointID string `json:"endpointId,omitempty"` +} + +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + bidder := &adapter{ + endpoint: config.Endpoint, + } + return bidder, nil +} + +func (a *adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + var errs []error + var adapterRequests []*adapters.RequestData + + reqCopy := *request + for _, imp := range request.Imp { + reqCopy.Imp = []openrtb2.Imp{imp} + + var bidderExt adapters.ExtImpBidder + var smootExt openrtb_ext.ImpExtSmoot + + if err := jsonutil.Unmarshal(imp.Ext, &bidderExt); err != nil { + errs = append(errs, err) + continue + } + if err := jsonutil.Unmarshal(bidderExt.Bidder, &smootExt); err != nil { + errs = append(errs, err) + continue + } + + impExt := reqBodyExt{SmootBidderExt: reqBodyExtBidder{}} + + if smootExt.PlacementID != "" { + impExt.SmootBidderExt.PlacementID = smootExt.PlacementID + impExt.SmootBidderExt.Type = "publisher" + } else { + impExt.SmootBidderExt.EndpointID = smootExt.EndpointID + impExt.SmootBidderExt.Type = "network" + } + + finalyImpExt, err := json.Marshal(impExt) + if err != nil { + errs = append(errs, err) + continue + } + + reqCopy.Imp[0].Ext = finalyImpExt + + adapterReq, err := a.makeRequest(&reqCopy) + if err != nil { + errs = append(errs, err) + continue + } + + adapterRequests = append(adapterRequests, adapterReq) + } + + return adapterRequests, errs +} + +func (a *adapter) makeRequest(request *openrtb2.BidRequest) (*adapters.RequestData, error) { + reqJSON, err := json.Marshal(request) + if err != nil { + return nil, err + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + headers.Add("Accept", "application/json") + return &adapters.RequestData{ + Method: http.MethodPost, + Uri: a.endpoint, + Body: reqJSON, + Headers: headers, + ImpIDs: openrtb_ext.GetImpIDs(request.Imp), + }, nil +} + +func (a *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if adapters.IsResponseStatusCodeNoContent(responseData) { + return nil, nil + } + + if err := adapters.CheckResponseStatusCodeForErrors(responseData); err != nil { + return nil, []error{err} + } + + var response openrtb2.BidResponse + if err := jsonutil.Unmarshal(responseData.Body, &response); err != nil { + return nil, []error{err} + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) + if len(response.Cur) != 0 { + bidResponse.Currency = response.Cur + } + + for _, seatBid := range response.SeatBid { + for i := range seatBid.Bid { + bidType, err := getBidType(&seatBid.Bid[i]) + if err != nil { + return nil, []error{err} + } + + b := &adapters.TypedBid{ + Bid: &seatBid.Bid[i], + BidType: bidType, + } + bidResponse.Bids = append(bidResponse.Bids, b) + } + } + return bidResponse, nil +} + +func getBidType(bid *openrtb2.Bid) (openrtb_ext.BidType, error) { + // determinate media type by bid response field mtype + switch bid.MType { + case openrtb2.MarkupBanner: + return openrtb_ext.BidTypeBanner, nil + case openrtb2.MarkupVideo: + return openrtb_ext.BidTypeVideo, nil + case openrtb2.MarkupNative: + return openrtb_ext.BidTypeNative, nil + } + + return "", fmt.Errorf("could not define media type for impression: %s", bid.ImpID) +} diff --git a/adapters/smoot/smoot_test.go b/adapters/smoot/smoot_test.go new file mode 100644 index 00000000000..46c65862414 --- /dev/null +++ b/adapters/smoot/smoot_test.go @@ -0,0 +1,20 @@ +package smoot + +import ( + "testing" + + "github.com/prebid/prebid-server/v3/adapters/adapterstest" + "github.com/prebid/prebid-server/v3/config" + "github.com/prebid/prebid-server/v3/openrtb_ext" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderSmoot, config.Adapter{ + Endpoint: "https://fake.test.io/pserver"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "smoottest", bidder) +} diff --git a/adapters/smoot/smoottest/exemplary/endpointId.json b/adapters/smoot/smoottest/exemplary/endpointId.json new file mode 100644 index 00000000000..ddfdba67c1d --- /dev/null +++ b/adapters/smoot/smoottest/exemplary/endpointId.json @@ -0,0 +1,136 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + }, + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "endpointId": "test" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "endpointId": "test", + "type": "network" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 1, + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ], + "seat": "smoot" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 1, + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/smoot/smoottest/exemplary/multi-format.json b/adapters/smoot/smoottest/exemplary/multi-format.json new file mode 100644 index 00000000000..b928d00429f --- /dev/null +++ b/adapters/smoot/smoottest/exemplary/multi-format.json @@ -0,0 +1,95 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + }, + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "video": { + "mimes": ["video/mp4"], + "protocols": [2, 5], + "w": 1024, + "h": 576 + }, + "ext": { + "bidder": { + "endpointId": "test" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "video": { + "mimes": ["video/mp4"], + "protocols": [2, 5], + "w": 1024, + "h": 576 + }, + "ext": { + "bidder": { + "endpointId": "test", + "type": "network" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 204 + } + } + ], + "expectedBidResponses": [] +} diff --git a/adapters/smoot/smoottest/exemplary/multi-imp.json b/adapters/smoot/smoottest/exemplary/multi-imp.json new file mode 100644 index 00000000000..e47253c35d8 --- /dev/null +++ b/adapters/smoot/smoottest/exemplary/multi-imp.json @@ -0,0 +1,253 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + }, + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "imp": [ + { + "id": "test-imp-id1", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "endpointId": "test" + } + } + }, + { + "id": "test-imp-id2", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "endpointId": "test" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id1", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "endpointId": "test", + "type": "network" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + } + }, + "impIDs": ["test-imp-id1"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id1", + "price": 0.27543, + "adm": "", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 1, + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ], + "seat": "smoot" + } + ], + "cur": "USD" + } + } + }, + { + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id2", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "endpointId": "test", + "type": "network" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + } + }, + "impIDs": ["test-imp-id2"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id2", + "price": 0.27543, + "adm": "", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 1, + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ], + "seat": "smoot" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "test_bid_id", + "impid": "test-imp-id1", + "price": 0.27543, + "adm": "", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 1, + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + }, + { + "bids": [ + { + "bid": { + "id": "test_bid_id", + "impid": "test-imp-id2", + "price": 0.27543, + "adm": "", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 1, + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/smoot/smoottest/exemplary/simple-app-banner.json b/adapters/smoot/smoottest/exemplary/simple-app-banner.json new file mode 100644 index 00000000000..14f1d9e4b9d --- /dev/null +++ b/adapters/smoot/smoottest/exemplary/simple-app-banner.json @@ -0,0 +1,136 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + }, + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "placementId": "test" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "placementId": "test", + "type": "publisher" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 1, + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ], + "seat": "smoot" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 1, + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/smoot/smoottest/exemplary/simple-native.json b/adapters/smoot/smoottest/exemplary/simple-native.json new file mode 100644 index 00000000000..26cdbf45efb --- /dev/null +++ b/adapters/smoot/smoottest/exemplary/simple-native.json @@ -0,0 +1,120 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + }, + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "native": { + "request": "{\"ver\":\"1.1\",\"layout\":1,\"adunit\":2,\"plcmtcnt\":6,\"plcmttype\":4,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"wmin\":492,\"hmin\":328,\"type\":3,\"mimes\":[\"image/jpeg\",\"image/jpg\",\"image/png\"]}},{\"id\":4,\"required\":0,\"data\":{\"type\":6}},{\"id\":5,\"required\":0,\"data\":{\"type\":7}},{\"id\":6,\"required\":0,\"data\":{\"type\":1,\"len\":20}}]}", + "ver": "1.1" + }, + "ext": { + "bidder": { + "placementId": "test" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "native": { + "request": "{\"ver\":\"1.1\",\"layout\":1,\"adunit\":2,\"plcmtcnt\":6,\"plcmttype\":4,\"assets\":[{\"id\":1,\"required\":1,\"title\":{\"len\":75}},{\"id\":2,\"required\":1,\"img\":{\"wmin\":492,\"hmin\":328,\"type\":3,\"mimes\":[\"image/jpeg\",\"image/jpg\",\"image/png\"]}},{\"id\":4,\"required\":0,\"data\":{\"type\":6}},{\"id\":5,\"required\":0,\"data\":{\"type\":7}},{\"id\":6,\"required\":0,\"data\":{\"type\":1,\"len\":20}}]}", + "ver": "1.1" + }, + "ext": { + "bidder": { + "placementId": "test", + "type": "publisher" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 4, + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "native" + } + } + } + ], + "seat": "smoot" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 4, + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "native" + } + } + }, + "type": "native" + } + ] + } + ] +} diff --git a/adapters/smoot/smoottest/exemplary/simple-video.json b/adapters/smoot/smoottest/exemplary/simple-video.json new file mode 100644 index 00000000000..cef316585da --- /dev/null +++ b/adapters/smoot/smoottest/exemplary/simple-video.json @@ -0,0 +1,121 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + }, + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "video": { + "mimes": ["video/mp4"], + "protocols": [2, 5], + "w": 1024, + "h": 576 + }, + "ext": { + "bidder": { + "placementId": "test" + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "device": { + "ip": "123.123.123.123", + "ua": "iPad" + }, + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "video": { + "mimes": ["video/mp4"], + "protocols": [2, 5], + "w": 1024, + "h": 576 + }, + "ext": { + "bidder": { + "placementId": "test", + "type": "publisher" + } + } + } + ] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "00:01:00", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 2, + "ext": { + "prebid": { + "type": "video" + } + } + } + ], + "seat": "smoot" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "00:01:00", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 2, + "ext": { + "prebid": { + "type": "video" + } + } + }, + "type": "video" + } + ] + } + ] +} diff --git a/adapters/smoot/smoottest/exemplary/simple-web-banner.json b/adapters/smoot/smoottest/exemplary/simple-web-banner.json new file mode 100644 index 00000000000..6494b15ef37 --- /dev/null +++ b/adapters/smoot/smoottest/exemplary/simple-web-banner.json @@ -0,0 +1,136 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "placementId": "test" + } + } + } + ], + "site": { + "id": "1", + "domain": "test.com" + }, + "device": { + "ip": "123.123.123.123", + "ua": "Ubuntu" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "placementId": "test", + "type": "publisher" + } + } + } + ], + "site": { + "id": "1", + "domain": "test.com" + }, + "device": { + "ip": "123.123.123.123", + "ua": "Ubuntu" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 1, + "w": 468, + "h": 60, + "ext": { + "prebid": { + "type": "banner" + } + } + } + ], + "seat": "smoot" + } + ], + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "mtype": 1, + "w": 468, + "h": 60, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/smoot/smoottest/supplemental/bad-media-type.json b/adapters/smoot/smoottest/supplemental/bad-media-type.json new file mode 100644 index 00000000000..4fb67fe5187 --- /dev/null +++ b/adapters/smoot/smoottest/supplemental/bad-media-type.json @@ -0,0 +1,85 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "ext": { + "bidder": { + "placementId": "test" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "ext": { + "bidder": { + "placementId": "test", + "type": "publisher" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [ + { + "bid": [ + { + "id": "test_bid_id", + "impid": "test-imp-id", + "price": 0.27543, + "adm": "", + "cid": "test_cid", + "crid": "test_crid", + "dealid": "test_dealid", + "w": 300, + "h": 250, + "ext": {} + } + ], + "seat": "smoot" + } + ], + "cur": "USD" + } + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "could not define media type for impression: test-imp-id", + "comparison": "literal" + } + ] +} diff --git a/adapters/smoot/smoottest/supplemental/bad-response.json b/adapters/smoot/smoottest/supplemental/bad-response.json new file mode 100644 index 00000000000..74b209d4ca8 --- /dev/null +++ b/adapters/smoot/smoottest/supplemental/bad-response.json @@ -0,0 +1,87 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "placementId": "test" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "placementId": "test", + "type": "publisher" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": "" + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "expect { or n, but found \"", + "comparison": "literal" + } + ] +} diff --git a/adapters/smoot/smoottest/supplemental/invalid-bidder.json b/adapters/smoot/smoottest/supplemental/invalid-bidder.json new file mode 100644 index 00000000000..27588a6c340 --- /dev/null +++ b/adapters/smoot/smoottest/supplemental/invalid-bidder.json @@ -0,0 +1,31 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": { + "bidder": 999 + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + } + }, + "expectedMakeRequestsErrors": [ + { + "value": "expect { or n, but found 9", + "comparison": "literal" + } + ] +} diff --git a/adapters/smoot/smoottest/supplemental/invalid-ext.json b/adapters/smoot/smoottest/supplemental/invalid-ext.json new file mode 100644 index 00000000000..237eb4d9e27 --- /dev/null +++ b/adapters/smoot/smoottest/supplemental/invalid-ext.json @@ -0,0 +1,29 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + } + ] + }, + "ext": 123 + } + ] + }, + "expectedMakeRequestsErrors": [ + { + "value": "expect { or n, but found 1", + "comparison": "literal" + } + ] +} diff --git a/adapters/smoot/smoottest/supplemental/status-204.json b/adapters/smoot/smoottest/supplemental/status-204.json new file mode 100644 index 00000000000..4387effb5d5 --- /dev/null +++ b/adapters/smoot/smoottest/supplemental/status-204.json @@ -0,0 +1,82 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "placementId": "test" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "placementId": "test", + "type": "publisher" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 204, + "body": {} + } + } + ], + "expectedBidResponses": [] +} diff --git a/adapters/smoot/smoottest/supplemental/status-not-200.json b/adapters/smoot/smoottest/supplemental/status-not-200.json new file mode 100644 index 00000000000..bb4b627bf77 --- /dev/null +++ b/adapters/smoot/smoottest/supplemental/status-not-200.json @@ -0,0 +1,87 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "placementId": "test" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://fake.test.io/pserver", + "body": { + "id": "test-request-id", + "imp": [ + { + "id": "test-imp-id", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "placementId": "test", + "type": "publisher" + } + } + } + ], + "app": { + "id": "1", + "bundle": "com.wls.testwlsapplication" + }, + "device": { + "ip": "123.123.123.123", + "ifa": "sdjfksdf-dfsds-dsdg-dsgg" + } + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 404, + "body": {} + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code: 404. Run with request.debug = 1 for more info", + "comparison": "literal" + } + ] +} diff --git a/adservertargeting/requestlookup.go b/adservertargeting/requestlookup.go index 31c1a9d939e..68299716515 100644 --- a/adservertargeting/requestlookup.go +++ b/adservertargeting/requestlookup.go @@ -7,7 +7,6 @@ import ( "strings" "github.com/buger/jsonparser" - "github.com/pkg/errors" "github.com/prebid/prebid-server/v3/openrtb_ext" ) @@ -93,7 +92,7 @@ func getValueFromQueryParam(path string, queryParams url.Values) (json.RawMessag if val != "" { return json.RawMessage(val), nil } else { - return nil, errors.Errorf("value not found for path: %s", path) + return nil, fmt.Errorf("value not found for path: %s", path) } } return nil, nil diff --git a/adservertargeting/respdataprocessor.go b/adservertargeting/respdataprocessor.go index 4b18d64b44b..c3ad25aa62a 100644 --- a/adservertargeting/respdataprocessor.go +++ b/adservertargeting/respdataprocessor.go @@ -5,7 +5,6 @@ import ( "fmt" "strings" - "github.com/pkg/errors" "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v3/openrtb_ext" "github.com/prebid/prebid-server/v3/util/jsonutil" @@ -170,7 +169,7 @@ func getRespData(bidderResp *openrtb2.BidResponse, field string) (string, error) return fmt.Sprint(bidderResp.NBR.Val()), nil default: - return "", errors.Errorf("key not found for field in bid response: %s", field) + return "", fmt.Errorf("key not found for field in bid response: %s", field) } } diff --git a/adservertargeting/utils.go b/adservertargeting/utils.go index dd70bf1b667..7cd4a826b98 100644 --- a/adservertargeting/utils.go +++ b/adservertargeting/utils.go @@ -1,10 +1,10 @@ package adservertargeting import ( + "fmt" "strings" "github.com/buger/jsonparser" - "github.com/pkg/errors" "github.com/prebid/prebid-server/v3/errortypes" "github.com/prebid/prebid-server/v3/openrtb_ext" ) @@ -40,12 +40,12 @@ func typedLookup(data []byte, path string, keys ...string) ([]byte, error) { if err != nil && err != jsonparser.KeyPathNotFoundError { return nil, err } else if err != nil && err == jsonparser.KeyPathNotFoundError { - return nil, errors.Errorf("value not found for path: %s", path) + return nil, fmt.Errorf("value not found for path: %s", path) } if verifyType(dataType) { return value, nil } - return nil, errors.Errorf("incorrect value type for path: %s, value can only be string or number", path) + return nil, fmt.Errorf("incorrect value type for path: %s, value can only be string or number", path) } func verifyType(dataType jsonparser.ValueType) bool { diff --git a/config/account.go b/config/account.go index a54da82d212..310fd021dce 100644 --- a/config/account.go +++ b/config/account.go @@ -159,6 +159,7 @@ type AccountGDPR struct { PurposeConfigs map[consentconstants.Purpose]*AccountGDPRPurpose PurposeOneTreatment AccountGDPRPurposeOneTreatment `mapstructure:"purpose_one_treatment" json:"purpose_one_treatment"` SpecialFeature1 AccountGDPRSpecialFeature `mapstructure:"special_feature1" json:"special_feature1"` + EEACountries []string `mapstructure:"eea_countries" json:"eea_countries"` } // EnabledForChannelType indicates whether GDPR is turned on at the account level for the specified channel type diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index 41dd58ff4d2..1c2907a2454 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -136,6 +136,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/lockerdome" "github.com/prebid/prebid-server/v3/adapters/logan" "github.com/prebid/prebid-server/v3/adapters/logicad" + "github.com/prebid/prebid-server/v3/adapters/loopme" "github.com/prebid/prebid-server/v3/adapters/loyal" "github.com/prebid/prebid-server/v3/adapters/lunamedia" "github.com/prebid/prebid-server/v3/adapters/mabidder" @@ -196,6 +197,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/smartx" "github.com/prebid/prebid-server/v3/adapters/smartyads" "github.com/prebid/prebid-server/v3/adapters/smilewanted" + "github.com/prebid/prebid-server/v3/adapters/smoot" "github.com/prebid/prebid-server/v3/adapters/smrtconnect" "github.com/prebid/prebid-server/v3/adapters/sonobi" "github.com/prebid/prebid-server/v3/adapters/sovrn" @@ -381,6 +383,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderLockerDome: lockerdome.Builder, openrtb_ext.BidderLogan: logan.Builder, openrtb_ext.BidderLogicad: logicad.Builder, + openrtb_ext.BidderLoopme: loopme.Builder, openrtb_ext.BidderLoyal: loyal.Builder, openrtb_ext.BidderLunaMedia: lunamedia.Builder, openrtb_ext.BidderMabidder: mabidder.Builder, @@ -442,6 +445,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderSmartx: smartx.Builder, openrtb_ext.BidderSmartyAds: smartyads.Builder, openrtb_ext.BidderSmileWanted: smilewanted.Builder, + openrtb_ext.BidderSmoot: smoot.Builder, openrtb_ext.BidderSmrtconnect: smrtconnect.Builder, openrtb_ext.BidderSonobi: sonobi.Builder, openrtb_ext.BidderSovrn: sovrn.Builder, diff --git a/exchange/exchange.go b/exchange/exchange.go index 9ab91ee9ea3..daddf9debc2 100644 --- a/exchange/exchange.go +++ b/exchange/exchange.go @@ -316,8 +316,11 @@ func (e *exchange) HoldAuction(ctx context.Context, r *AuctionRequest, debugLog recordImpMetrics(r.BidRequestWrapper, e.me) + // Retrieve EEA countries configuration from either host or account settings + eeaCountries := selectEEACountries(e.privacyConfig.GDPR.EEACountries, r.Account.GDPR.EEACountries) + // Make our best guess if GDPR applies - gdprDefaultValue := e.parseGDPRDefaultValue(r.BidRequestWrapper) + gdprDefaultValue := e.parseGDPRDefaultValue(r.BidRequestWrapper, eeaCountries) gdprSignal, err := getGDPR(r.BidRequestWrapper) if err != nil { return nil, err @@ -571,7 +574,7 @@ func buildMultiBidMap(prebid *openrtb_ext.ExtRequestPrebid) map[string]openrtb_e return multiBidMap } -func (e *exchange) parseGDPRDefaultValue(r *openrtb_ext.RequestWrapper) gdpr.Signal { +func (e *exchange) parseGDPRDefaultValue(r *openrtb_ext.RequestWrapper, eeaCountries []string) gdpr.Signal { gdprDefaultValue := e.gdprDefaultValue var geo *openrtb2.Geo @@ -582,12 +585,11 @@ func (e *exchange) parseGDPRDefaultValue(r *openrtb_ext.RequestWrapper) gdpr.Sig } if geo != nil { - // If we have a country set, and it is on the list, we assume GDPR applies if not set on the request. - // Otherwise we assume it does not apply as long as it appears "valid" (is 3 characters long). - if _, found := e.privacyConfig.GDPR.EEACountriesMap[strings.ToUpper(geo.Country)]; found { + // If the country is in the EEA list, GDPR applies. + // Otherwise, if the country code is properly formatted (3 characters), GDPR does not apply. + if isEEACountry(geo.Country, eeaCountries) { gdprDefaultValue = gdpr.SignalYes } else if len(geo.Country) == 3 { - // The country field is formatted properly as a three character country code gdprDefaultValue = gdpr.SignalNo } } @@ -1622,3 +1624,17 @@ func setSeatNonBid(bidResponseExt *openrtb_ext.ExtBidResponse, seatNonBidBuilder bidResponseExt.Prebid.SeatNonBid = seatNonBidBuilder.Slice() return bidResponseExt } + +func isEEACountry(country string, eeaCountries []string) bool { + if len(eeaCountries) == 0 { + return false + } + + country = strings.ToUpper(country) + for _, c := range eeaCountries { + if strings.ToUpper(c) == country { + return true + } + } + return false +} diff --git a/exchange/exchange_test.go b/exchange/exchange_test.go index 87b53b101e0..7edbec64d7e 100644 --- a/exchange/exchange_test.go +++ b/exchange/exchange_test.go @@ -2114,9 +2114,10 @@ func runSpec(t *testing.T, filename string, spec *exchangeSpec) { } var s struct{} - eeac := make(map[string]struct{}) - for _, c := range []string{"FIN", "FRA", "GUF"} { - eeac[c] = s + eeacMap := make(map[string]struct{}) + eeac := []string{"FIN", "FRA", "GUF"} + for _, c := range eeac { + eeacMap[c] = s } var gdprDefaultValue string @@ -2136,7 +2137,8 @@ func runSpec(t *testing.T, filename string, spec *exchangeSpec) { GDPR: config.GDPR{ Enabled: spec.GDPREnabled, DefaultValue: gdprDefaultValue, - EEACountriesMap: eeac, + EEACountries: eeac, + EEACountriesMap: eeacMap, TCF2: config.TCF2{ Enabled: spec.GDPREnabled, }, @@ -2192,6 +2194,7 @@ func runSpec(t *testing.T, filename string, spec *exchangeSpec) { PriceFloors: config.AccountPriceFloors{Enabled: spec.AccountFloorsEnabled, EnforceDealFloors: spec.AccountEnforceDealFloors}, Privacy: spec.AccountPrivacy, Validations: spec.AccountConfigBidValidation, + GDPR: config.AccountGDPR{EEACountries: spec.AccountEEACountries}, }, UserSyncs: mockIdFetcher(spec.IncomingRequest.Usersyncs), ImpExtInfoMap: impExtInfoMap, @@ -5518,6 +5521,7 @@ type exchangeSpec struct { Server exchangeServer `json:"server,omitempty"` AccountPrivacy config.AccountPrivacy `json:"accountPrivacy,omitempty"` ORTBVersion map[string]string `json:"ortbversion"` + AccountEEACountries []string `json:"account_eea_countries"` } type multiBidSpec struct { @@ -6351,6 +6355,61 @@ func TestBidsToUpdate(t *testing.T) { } } +func TestIsEEACountry(t *testing.T) { + eeaCountries := []string{"FRA", "DEU", "ITA", "ESP", "NLD"} + + tests := []struct { + name string + country string + eeaList []string + expected bool + }{ + { + name: "Country_in_EEA", + country: "FRA", + eeaList: eeaCountries, + expected: true, + }, + { + name: "Country_in_EEA_lowercase", + country: "fra", + eeaList: eeaCountries, + expected: true, + }, + { + name: "Country_not_in_EEA", + country: "USA", + eeaList: eeaCountries, + expected: false, + }, + { + name: "Empty_country_string", + country: "", + eeaList: eeaCountries, + expected: false, + }, + { + name: "EEA_list_is_empty", + country: "FRA", + eeaList: []string{}, + expected: false, + }, + { + name: "EEA_list_is_nil", + country: "FRA", + eeaList: nil, + expected: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + result := isEEACountry(tt.country, tt.eeaList) + assert.Equal(t, tt.expected, result) + }) + } +} + type mockRequestValidator struct { errors []error } diff --git a/exchange/exchangetest/gdpr-geo-eu-on-with-account-eea-countries.json b/exchange/exchangetest/gdpr-geo-eu-on-with-account-eea-countries.json new file mode 100644 index 00000000000..a9b469fb11a --- /dev/null +++ b/exchange/exchangetest/gdpr-geo-eu-on-with-account-eea-countries.json @@ -0,0 +1,75 @@ +{ + "assume_gdpr_applies": true, + "account_eea_countries": ["POL"], + "gdpr_enabled": true, + "incomingRequest": { + "ortbRequest": { + "id": "some-request-id", + "site": { + "page": "test.somepage.com" + }, + "imp": [ + { + "id": "my-imp-id", + "video": { + "mimes": [ + "video/mp4" + ] + }, + "ext": { + "prebid": { + "bidder": { + "appnexus": { + "placementId": 1 + } + } + } + } + } + ], + "user": { + "buyeruid": "some-buyer-id", + "geo": { + "country": "POL" + } + } + } + }, + "outgoingRequests": { + "appnexus": { + "expectRequest": { + "ortbRequest": { + "id": "some-request-id", + "site": { + "page": "test.somepage.com" + }, + "imp": [ + { + "id": "my-imp-id", + "video": { + "mimes": [ + "video/mp4" + ] + }, + "ext": { + "bidder": { + "placementId": 1 + } + } + } + ], + "user": { + "geo": { + "country": "POL" + } + } + } + }, + "mockResponse": { + "errors": [ + "appnexus-error" + ] + } + } + } +} \ No newline at end of file diff --git a/exchange/gdpr.go b/exchange/gdpr.go index 866f33baed2..8c58a77b468 100644 --- a/exchange/gdpr.go +++ b/exchange/gdpr.go @@ -40,3 +40,12 @@ func enforceGDPR(signal gdpr.Signal, defaultValue gdpr.Signal, channelEnabled bo gdprApplies := signal == gdpr.SignalYes || (signal == gdpr.SignalAmbiguous && defaultValue == gdpr.SignalYes) return gdprApplies && channelEnabled } + +// SelectEEACountries selects the EEA countries based on host and account configurations. +// Account-level configuration takes precedence over the host-level configuration. +func selectEEACountries(hostEEACountries []string, accountEEACountries []string) []string { + if accountEEACountries != nil { + return accountEEACountries + } + return hostEEACountries +} diff --git a/exchange/gdpr_test.go b/exchange/gdpr_test.go index b2d175c2ad0..1ef69d498b1 100644 --- a/exchange/gdpr_test.go +++ b/exchange/gdpr_test.go @@ -148,6 +148,65 @@ func TestGetConsent(t *testing.T) { } } +func TestSelectEEACountries(t *testing.T) { + tests := []struct { + description string + hostEEACountries []string + accountEEACountries []string + expected []string + }{ + { + description: "Account_EEA_countries_provided", + hostEEACountries: []string{"UK", "DE"}, + accountEEACountries: []string{"FR", "IT"}, + expected: []string{"FR", "IT"}, + }, + { + description: "Account_is_nil", + hostEEACountries: []string{"UK"}, + accountEEACountries: nil, + expected: []string{"UK"}, + }, + { + description: "Both_nil", + hostEEACountries: nil, + accountEEACountries: nil, + expected: nil, + }, + { + description: "Account_is_empty_slice", + hostEEACountries: []string{"UK"}, + accountEEACountries: []string{}, + expected: []string{}, + }, + { + description: "Host_is_nil", + hostEEACountries: nil, + accountEEACountries: []string{"DE"}, + expected: []string{"DE"}, + }, + { + description: "Host_and_account_both_non-nil", + hostEEACountries: []string{"UK"}, + accountEEACountries: []string{"FR"}, + expected: []string{"FR"}, + }, + { + description: "Host_is_empty_slice,_account_is_nil", + hostEEACountries: []string{}, + accountEEACountries: nil, + expected: []string{}, + }, + } + + for _, tt := range tests { + t.Run(tt.description, func(t *testing.T) { + result := selectEEACountries(tt.hostEEACountries, tt.accountEEACountries) + assert.Equal(t, tt.expected, result) + }) + } +} + var upsv1Section mockGPPSection = mockGPPSection{sectionID: 6, value: "1YNY"} var tcf1Section mockGPPSection = mockGPPSection{sectionID: 2, value: "BOS2bx5OS2bx5ABABBAAABoAAAAAFA"} diff --git a/go.mod b/go.mod index c7069e32b0f..ef05f217116 100644 --- a/go.mod +++ b/go.mod @@ -25,7 +25,6 @@ require ( github.com/lib/pq v1.10.4 github.com/mitchellh/copystructure v1.2.0 github.com/modern-go/reflect2 v1.0.2 - github.com/pkg/errors v0.9.1 github.com/prebid/go-gdpr v1.12.0 github.com/prebid/go-gpp v0.2.0 github.com/prebid/openrtb/v20 v20.3.0 @@ -63,6 +62,7 @@ require ( github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.1 // indirect + github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/prometheus/common v0.32.1 // indirect github.com/prometheus/procfs v0.7.3 // indirect diff --git a/modules/fiftyonedegrees/devicedetection/config.go b/modules/fiftyonedegrees/devicedetection/config.go index a5c302bcff5..7a29812d35a 100644 --- a/modules/fiftyonedegrees/devicedetection/config.go +++ b/modules/fiftyonedegrees/devicedetection/config.go @@ -2,11 +2,10 @@ package devicedetection import ( "encoding/json" + "fmt" "os" "github.com/51Degrees/device-detection-go/v4/dd" - "github.com/pkg/errors" - "github.com/prebid/prebid-server/v3/util/jsonutil" ) @@ -65,7 +64,7 @@ func (c *config) getPerformanceProfile() dd.PerformanceProfile { func parseConfig(data json.RawMessage) (config, error) { var cfg config if err := jsonutil.UnmarshalValid(data, &cfg); err != nil { - return cfg, errors.Wrap(err, "failed to parse config") + return cfg, fmt.Errorf("failed to parse config: %w", err) } return cfg, nil } @@ -73,7 +72,7 @@ func parseConfig(data json.RawMessage) (config, error) { func validateConfig(cfg config) error { _, err := os.Stat(cfg.DataFile.Path) if err != nil { - return errors.Wrap(err, "error opening hash file path") + return fmt.Errorf("error opening hash file path: %w", err) } return nil diff --git a/modules/fiftyonedegrees/devicedetection/device_detector.go b/modules/fiftyonedegrees/devicedetection/device_detector.go index 8369d343d34..5c23deb9637 100644 --- a/modules/fiftyonedegrees/devicedetection/device_detector.go +++ b/modules/fiftyonedegrees/devicedetection/device_detector.go @@ -1,9 +1,10 @@ package devicedetection import ( + "fmt" + "github.com/51Degrees/device-detection-go/v4/dd" "github.com/51Degrees/device-detection-go/v4/onpremise" - "github.com/pkg/errors" ) type engine interface { @@ -28,7 +29,7 @@ func newDeviceDetector(cfg *dd.ConfigHash, moduleConfig *config) (*defaultDevice engineOptions..., ) if err != nil { - return nil, errors.Wrap(err, "Failed to create onpremise engine.") + return nil, fmt.Errorf("failed to create onpremise engine: %w", err) } deviceDetector := &defaultDeviceDetector{ @@ -147,7 +148,7 @@ func (x defaultDeviceDetector) getSupportedHeaders() []dd.EvidenceKey { func (x defaultDeviceDetector) getDeviceInfo(evidence []onpremise.Evidence, ua string) (*deviceInfo, error) { results, err := x.engine.Process(evidence) if err != nil { - return nil, errors.Wrap(err, "Failed to process evidence") + return nil, fmt.Errorf("failed to process evidence: %w", err) } defer results.Free() diff --git a/modules/fiftyonedegrees/devicedetection/device_info_extractor.go b/modules/fiftyonedegrees/devicedetection/device_info_extractor.go index 1c913e21696..89ff3714eea 100644 --- a/modules/fiftyonedegrees/devicedetection/device_info_extractor.go +++ b/modules/fiftyonedegrees/devicedetection/device_info_extractor.go @@ -1,10 +1,10 @@ package devicedetection import ( + "fmt" "strconv" "github.com/golang/glog" - "github.com/pkg/errors" ) // deviceInfoExtractor is a struct that contains the methods to extract device information @@ -61,7 +61,7 @@ func (x deviceInfoExtractor) extract(results Results, ua string) (*deviceInfo, e geoLocation, _ := strconv.ParseBool(x.getValue(results, deviceInfoGeoLocation)) deviceId, err := results.DeviceId() if err != nil { - return nil, errors.Wrap(err, "Failed to get device id.") + return nil, fmt.Errorf("failed to get device id: %w", err) } hardwareModel := x.getValue(results, deviceInfoHardwareModel) hardwareFamily := x.getValue(results, deviceInfoHardwareFamily) diff --git a/modules/fiftyonedegrees/devicedetection/evidence_extractor.go b/modules/fiftyonedegrees/devicedetection/evidence_extractor.go index a99a921e75f..5bec2f4a79b 100644 --- a/modules/fiftyonedegrees/devicedetection/evidence_extractor.go +++ b/modules/fiftyonedegrees/devicedetection/evidence_extractor.go @@ -1,12 +1,12 @@ package devicedetection import ( + "errors" + "fmt" "net/http" - "github.com/51Degrees/device-detection-go/v4/onpremise" - "github.com/pkg/errors" - "github.com/51Degrees/device-detection-go/v4/dd" + "github.com/51Degrees/device-detection-go/v4/onpremise" "github.com/prebid/prebid-server/v3/hooks/hookstage" ) @@ -62,11 +62,11 @@ func (x *defaultEvidenceExtractor) extract(ctx hookstage.ModuleContext) ([]onpre suaStrings, err := x.getEvidenceStrings(ctx[evidenceFromSuaCtxKey]) if err != nil { - return nil, "", errors.Wrap(err, "error extracting sua evidence") + return nil, "", fmt.Errorf("error extracting sua evidence: %w", err) } headerString, err := x.getEvidenceStrings(ctx[evidenceFromHeadersCtxKey]) if err != nil { - return nil, "", errors.Wrap(err, "error extracting header evidence") + return nil, "", fmt.Errorf("error extracting header evidence: %w", err) } // Merge evidence from headers and SUA, sua has higher priority diff --git a/modules/fiftyonedegrees/devicedetection/module.go b/modules/fiftyonedegrees/devicedetection/module.go index 80eed36efda..78537f999d5 100644 --- a/modules/fiftyonedegrees/devicedetection/module.go +++ b/modules/fiftyonedegrees/devicedetection/module.go @@ -3,11 +3,11 @@ package devicedetection import ( "context" "encoding/json" + "fmt" "net/http" "github.com/51Degrees/device-detection-go/v4/dd" "github.com/51Degrees/device-detection-go/v4/onpremise" - "github.com/pkg/errors" "github.com/prebid/prebid-server/v3/hooks/hookstage" "github.com/prebid/prebid-server/v3/modules/moduledeps" ) @@ -35,12 +35,12 @@ func configHashFromConfig(cfg *config) *dd.ConfigHash { func Builder(rawConfig json.RawMessage, _ moduledeps.ModuleDeps) (interface{}, error) { cfg, err := parseConfig(rawConfig) if err != nil { - return Module{}, errors.Wrap(err, "failed to parse config") + return Module{}, fmt.Errorf("failed to parse config: %w", err) } err = validateConfig(cfg) if err != nil { - return nil, errors.Wrap(err, "invalid config") + return nil, fmt.Errorf("invalid config: %w", err) } configHash := configHashFromConfig(&cfg) @@ -50,7 +50,7 @@ func Builder(rawConfig json.RawMessage, _ moduledeps.ModuleDeps) (interface{}, e &cfg, ) if err != nil { - return nil, errors.Wrap(err, "failed to create device detector") + return nil, fmt.Errorf("failed to create device detector: %w", err) } return Module{ diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index d647e6b9d24..44c0a306486 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -153,6 +153,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderLockerDome, BidderLogan, BidderLogicad, + BidderLoopme, BidderLoyal, BidderLunaMedia, BidderMabidder, @@ -214,6 +215,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderSmartx, BidderSmartyAds, BidderSmileWanted, + BidderSmoot, BidderSmrtconnect, BidderSonobi, BidderSovrn, @@ -503,6 +505,7 @@ const ( BidderLockerDome BidderName = "lockerdome" BidderLogan BidderName = "logan" BidderLogicad BidderName = "logicad" + BidderLoopme BidderName = "loopme" BidderLoyal BidderName = "loyal" BidderLunaMedia BidderName = "lunamedia" BidderMabidder BidderName = "mabidder" @@ -564,6 +567,7 @@ const ( BidderSmartx BidderName = "smartx" BidderSmartyAds BidderName = "smartyads" BidderSmileWanted BidderName = "smilewanted" + BidderSmoot BidderName = "smoot" BidderSmrtconnect BidderName = "smrtconnect" BidderSonobi BidderName = "sonobi" BidderSovrn BidderName = "sovrn" diff --git a/openrtb_ext/imp_connatix.go b/openrtb_ext/imp_connatix.go index 18d7a713237..7649d6db143 100644 --- a/openrtb_ext/imp_connatix.go +++ b/openrtb_ext/imp_connatix.go @@ -1,5 +1,6 @@ package openrtb_ext type ExtImpConnatix struct { - PlacementId string `json:"placementId"` + PlacementId string `json:"placementId"` + ViewabilityPercentage float64 `json:"viewabilityPercentage"` } diff --git a/openrtb_ext/imp_loopme.go b/openrtb_ext/imp_loopme.go new file mode 100644 index 00000000000..b99ffc2556f --- /dev/null +++ b/openrtb_ext/imp_loopme.go @@ -0,0 +1,8 @@ +package openrtb_ext + +// ExtImpLoopme defines the contract for bidrequest.imp[i].ext.prebid.bidder.loopme +type ExtImpLoopme struct { + PublisherId string `json:"publisherId"` + BundleId string `json:"bundleId"` + PlacementId string `json:"placementId"` +} diff --git a/openrtb_ext/imp_smoot.go b/openrtb_ext/imp_smoot.go new file mode 100644 index 00000000000..3ecc4f4001b --- /dev/null +++ b/openrtb_ext/imp_smoot.go @@ -0,0 +1,6 @@ +package openrtb_ext + +type ImpExtSmoot struct { + PlacementID string `json:"placementId"` + EndpointID string `json:"endpointId"` +} diff --git a/server/server.go b/server/server.go index 9461f3f451d..257ccea8821 100644 --- a/server/server.go +++ b/server/server.go @@ -27,6 +27,7 @@ func Listen(cfg *config.Configuration, handler http.Handler, adminHandler http.H stopAdmin := make(chan os.Signal) stopMain := make(chan os.Signal) stopPrometheus := make(chan os.Signal) + stopChannels := []chan<- os.Signal{stopMain} done := make(chan struct{}) if cfg.UnixSocketEnable && len(cfg.UnixSocketName) > 0 { // start the unix_socket server if config enable-it. @@ -54,6 +55,7 @@ func Listen(cfg *config.Configuration, handler http.Handler, adminHandler http.H } if cfg.Admin.Enabled { + stopChannels = append(stopChannels, stopAdmin) adminServer := newAdminServer(cfg, adminHandler) go shutdownAfterSignals(adminServer, stopAdmin, done) @@ -70,6 +72,7 @@ func Listen(cfg *config.Configuration, handler http.Handler, adminHandler http.H prometheusListener net.Listener prometheusServer = newPrometheusServer(cfg, metrics) ) + stopChannels = append(stopChannels, stopPrometheus) go shutdownAfterSignals(prometheusServer, stopPrometheus, done) if prometheusListener, err = newTCPListener(prometheusServer.Addr, nil); err != nil { glog.Errorf("Error listening for TCP connections on %s: %v for prometheus server", prometheusServer.Addr, err) @@ -77,11 +80,10 @@ func Listen(cfg *config.Configuration, handler http.Handler, adminHandler http.H } go runServer(prometheusServer, "Prometheus", prometheusListener) - wait(stopSignals, done, stopMain, stopAdmin, stopPrometheus) - } else { - wait(stopSignals, done, stopMain, stopAdmin) } + wait(stopSignals, done, stopChannels...) + return } diff --git a/static/bidder-info/addigi.yaml b/static/bidder-info/addigi.yaml new file mode 100644 index 00000000000..8514d5c5500 --- /dev/null +++ b/static/bidder-info/addigi.yaml @@ -0,0 +1,2 @@ +endpoint: "https://addigi-prebid.attekmi.com/pbserver/?seat={{.AccountID}}&token={{.SourceId}}" +aliasOf: "smarthub" diff --git a/static/bidder-info/adt.yaml b/static/bidder-info/adt.yaml new file mode 100644 index 00000000000..29520d5e515 --- /dev/null +++ b/static/bidder-info/adt.yaml @@ -0,0 +1,4 @@ +aliasOf: "admatic" +maintainer: + email: "publisher@adtarget.com.tr" +gvlVendorID: 779 \ No newline at end of file diff --git a/static/bidder-info/copper6ssp.yaml b/static/bidder-info/copper6ssp.yaml index d1b3186dc2d..2f3ef14c768 100644 --- a/static/bidder-info/copper6ssp.yaml +++ b/static/bidder-info/copper6ssp.yaml @@ -1,4 +1,4 @@ -endpoint: "https://endpoint.copper6.com/" +endpoint: "https://endpoint.copper6.com/pserver" gvlVendorID: 1356 maintainer: email: "info@copper6.com" diff --git a/static/bidder-info/loopme.yaml b/static/bidder-info/loopme.yaml new file mode 100644 index 00000000000..8a7e019382b --- /dev/null +++ b/static/bidder-info/loopme.yaml @@ -0,0 +1,20 @@ +endpoint: http://prebid.loopmertb.com +geoscope: + - global +maintainer: + email: "prebid@loopme.com" +gvlVendorID: 109 +capabilities: + app: + mediaTypes: + - banner + - video + - native + - audio + site: + mediaTypes: + - banner + - video + - native + - audio + diff --git a/static/bidder-info/pubrise.yaml b/static/bidder-info/pubrise.yaml index fe5e6cd6d40..6d6b070ab38 100644 --- a/static/bidder-info/pubrise.yaml +++ b/static/bidder-info/pubrise.yaml @@ -1,4 +1,4 @@ -endpoint: "https://backend.pubrise.ai/" +endpoint: "https://backend.pubrise.ai/pserver" maintainer: email: "prebid@pubrise.ai" capabilities: diff --git a/static/bidder-info/smoot.yaml b/static/bidder-info/smoot.yaml new file mode 100644 index 00000000000..43a3381f6db --- /dev/null +++ b/static/bidder-info/smoot.yaml @@ -0,0 +1,18 @@ +endpoint: 'https://endpoint1.smoot.ai/pserver' +maintainer: + email: 'info@smoot.ai' +capabilities: + site: + mediaTypes: + - banner + - video + - native + app: + mediaTypes: + - banner + - video + - native +userSync: + redirect: + url: 'https://usync.smxconv.com/pbserver?gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&us_privacy={{.USPrivacy}}&gpp={{.GPP}}&gpp_sid={{.GPPSID}}&redir={{.RedirectURL}}' + userMacro: '[UID]' diff --git a/static/bidder-info/sspBC.yaml b/static/bidder-info/sspBC.yaml index 572105d2407..97da8b497cd 100644 --- a/static/bidder-info/sspBC.yaml +++ b/static/bidder-info/sspBC.yaml @@ -1,4 +1,4 @@ -endpoint: "https://ssp.wp.pl/bidder/" +endpoint: "https://ssp.wp.pl/v1/bidder/prebidserver" maintainer: email: "prebid-dev@grupawp.pl" gvlVendorID: 676 diff --git a/static/bidder-params/connatix.json b/static/bidder-params/connatix.json index 4003b0583b1..86ca65273f0 100644 --- a/static/bidder-params/connatix.json +++ b/static/bidder-params/connatix.json @@ -8,6 +8,10 @@ "type": "string", "minLength": 1, "description": "Placement ID" + }, + "viewabilityPercentage": { + "type": "number", + "description": "Declared viewability percentage (values from 0 to 1, where 1 = 100%)" } }, "required": ["placementId"] diff --git a/static/bidder-params/loopme.json b/static/bidder-params/loopme.json new file mode 100644 index 00000000000..5ea22ec7ba5 --- /dev/null +++ b/static/bidder-params/loopme.json @@ -0,0 +1,24 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Loopme Adapter Params", + "description": "A schema which validates params accepted by the Loopme adapter", + "type": "object", + "properties": { + "publisherId": { + "type": "string", + "description": "An id which identifies Loopme partner", + "minLength": 1 + }, + "bundleId": { + "type": "string", + "description": "An id which identifies app/site in Loopme", + "minLength": 1 + }, + "placementId": { + "type": "string", + "description": "A placement id in Loopme", + "minLength": 1 + } + }, + "required": ["publisherId"] +} diff --git a/static/bidder-params/smoot.json b/static/bidder-params/smoot.json new file mode 100644 index 00000000000..46027757776 --- /dev/null +++ b/static/bidder-params/smoot.json @@ -0,0 +1,19 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Smoot Adapter Params", + "description": "A schema which validates params accepted by the Smoot adapter", + "type": "object", + "properties": { + "placementId": { + "type": "string", + "minLength": 1, + "description": "Placement ID" + }, + "endpointId": { + "type": "string", + "minLength": 1, + "description": "Endpoint ID" + } + }, + "oneOf": [{ "required": ["placementId"] }, { "required": ["endpointId"] }] +}