diff --git a/.github/workflows/adapter-code-coverage.yml b/.github/workflows/adapter-code-coverage.yml index b4c3f0745d6..b5fbd557bb7 100644 --- a/.github/workflows/adapter-code-coverage.yml +++ b/.github/workflows/adapter-code-coverage.yml @@ -36,8 +36,9 @@ jobs: return "" } const helper = utils.diffHelper({github, context}) - const files = await helper.getDirectories(directoryExtractor) - return files.length == 0 ? "" : JSON.stringify(files); + const directories = await helper.getDirectories(directoryExtractor) + // run coverage for maximum of 2 directories + return (directories.length == 0 || directories.length > 2) ? "" : JSON.stringify(directories) - name: Run coverage tests id: run_coverage diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/app_banner.json b/adapters/rtbhouse/rtbhousetest/exemplary/app_banner.json new file mode 100644 index 00000000000..733d4b73592 --- /dev/null +++ b/adapters/rtbhouse/rtbhousetest/exemplary/app_banner.json @@ -0,0 +1,98 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "app": { + "bundle": "com.prebid" + }, + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 300, + "h": 250 + }] + }, + "ext": { + "bidder": {} + } + }] + }, + + "httpCalls": [{ + "expectedRequest": { + "uri": "http://localhost/prebid_server", + "body": { + "id": "test-request-id", + "cur": ["USD"], + "app": { + "bundle": "com.prebid" + }, + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "imp": [{ + "id": "test-imp-id", + "banner": { + "format": [{ + "w": 300, + "h": 250 + }] + }, + "ext": { + "bidder": {} + } + }] + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-request-id", + "seatbid": [{ + "seat": "rtbhouse", + "bid": [{ + "id": "randomid", + "impid": "test-imp-id", + "price": 0.500000, + "adid": "12345678", + "adm": "some-test-ad", + "cid": "987", + "crid": "12345678", + "h": 250, + "w": 300, + "mtype": 1 + }] + }], + "cur": "USD" + } + } + }], + + "expectedBidResponses": [{ + "currency": "USD", + "bids": [{ + "bid": { + "id": "randomid", + "impid": "test-imp-id", + "price": 0.5, + "adm": "some-test-ad", + "adid": "12345678", + "cid": "987", + "crid": "12345678", + "w": 300, + "h": 250, + "mtype": 1 + }, + "type": "banner" + }] + }] +} diff --git a/adapters/rtbhouse/rtbhousetest/exemplary/app_native.json b/adapters/rtbhouse/rtbhousetest/exemplary/app_native.json new file mode 100644 index 00000000000..705e89d8955 --- /dev/null +++ b/adapters/rtbhouse/rtbhousetest/exemplary/app_native.json @@ -0,0 +1,112 @@ +{ + "mockBidRequest": { + "imp": [ + { + "ext": { + "bidder": {} + }, + "id": "test-native-imp", + "native": { + "request": "{\"eventtrackers\":[{\"event\":1,\"methods\":[1,2]}],\"ver\":\"1.2\",\"assets\":[{\"id\":0,\"required\":1,\"title\":{\"len\":140}},{\"id\":1,\"required\":1,\"data\":{\"type\":2}},{\"id\":2,\"required\":1,\"img\":{\"type\":3}}]}", + "ver": "1.2" + } + } + ], + "app": { + "bundle": "com.prebid" + }, + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "id": "test-native-request", + "ext": {}, + "debug": 1 + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://localhost/prebid_server", + "body": { + "id": "test-native-request", + "cur": [ + "USD" + ], + "imp": [ + { + "id": "test-native-imp", + "native": { + "request": "{\"eventtrackers\":[{\"event\":1,\"methods\":[1,2]}],\"ver\":\"1.2\",\"assets\":[{\"id\":0,\"required\":1,\"title\":{\"len\":140}},{\"id\":1,\"required\":1,\"data\":{\"type\":2}},{\"id\":2,\"required\":1,\"img\":{\"type\":3}}]}", + "ver": "1.2" + }, + "ext": { + "bidder": {} + } + } + ], + "app": { + "bundle": "com.prebid" + }, + "device": { + "ua": "test-user-agent", + "ip": "123.123.123.123", + "language": "en", + "dnt": 0 + }, + "ext": {} + } + }, + "mockResponse": { + "status": 200, + "body": { + "id": "test-native-request", + "bidid": "test-bidid", + "cur": "USD", + "seatbid": [ + { + "seat": "rtbhouse", + "bid": [ + { + "id": "test-native-request", + "impid": "test-native-imp", + "price": 0.5, + "adid": "test-adid", + "adm": "{\"ver\":\"1.2\",\"assets\":[{\"id\":0,\"title\":{\"text\":\"title text\"}},{\"id\":1,\"data\":{\"value\":\"data value\"}},{\"id\":2,\"img\":{\"url\":\"image.url\",\"w\":1200,\"h\":628}}],\"link\":{\"url\":\"link.url\"},\"imptrackers\":[\"imp.tracker.url\"],\"eventtrackers\":[{\"event\":1,\"method\":1,\"url\":\"event.tracker.url\"}]}", + "adomain": [ "adomain.com" ], + "cid": "test-cid", + "crid": "test-crid", + "dealid": "test-dealid", + "mtype": 4 + } + ] + } + ] + } + } + } + ], + "expectedBidResponses": [ + { + "currency": "USD", + "bids": [ + { + "bid": { + "id": "test-native-request", + "impid": "test-native-imp", + "price": 0.5, + "adid": "test-adid", + "adm": "{\"ver\":\"1.2\",\"assets\":[{\"id\":0,\"title\":{\"text\":\"title text\"}},{\"id\":1,\"data\":{\"value\":\"data value\"}},{\"id\":2,\"img\":{\"url\":\"image.url\",\"w\":1200,\"h\":628}}],\"link\":{\"url\":\"link.url\"},\"imptrackers\":[\"imp.tracker.url\"],\"eventtrackers\":[{\"event\":1,\"method\":1,\"url\":\"event.tracker.url\"}]}", + "adomain": [ "adomain.com" ], + "cid": "test-cid", + "crid": "test-crid", + "dealid": "test-dealid", + "mtype": 4 + }, + "type": "native" + } + ] + } + ] +} diff --git a/adapters/yandex/params_test.go b/adapters/yandex/params_test.go new file mode 100644 index 00000000000..e65c82ff159 --- /dev/null +++ b/adapters/yandex/params_test.go @@ -0,0 +1,87 @@ +package yandex + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v2/openrtb_ext" + "github.com/stretchr/testify/assert" +) + +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.BidderYandex, 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.BidderYandex, json.RawMessage(p)); err == nil { + t.Errorf("Schema allowed invalid params: %s", p) + } + } +} + +var validParams = []string{ + `{"page_id": 123123, "imp_id": 123}`, + `{"placement_id": "A-123123-123"}`, + `{"placement_id": "B-A-123123-123"}`, + `{"placement_id": "123123-123"}`, +} + +var invalidParams = []string{ + `{"pageId": 123123, "impId": 123}`, + `{"page_id": 0, "imp_id": 0}`, + `{"page_id": "123123", "imp_id": "123"}`, + `{"page_id": "123123", "imp_id": "123", "placement_id": "123123"}`, + `{"page_id": "123123"}`, + `{"imp_id": "123"}`, + `{"placement_id": 123123}`, + `{"placement_id": "123123"}`, + `{"placement_id": "A-123123"}`, + `{"placement_id": "B-A-123123"}`, + `{}`, +} + +func TestValidPlacementIdMapper(t *testing.T) { + for ext, expectedPlacementId := range validPlacementIds { + val, err := mapExtToPlacementID(ext) + + assert.Equal(t, &expectedPlacementId, val) + assert.NoError(t, err) + } +} + +func TestInvalidPlacementIdMapper(t *testing.T) { + for _, ext := range invalidPlacementIds { + _, err := mapExtToPlacementID(ext) + + assert.Error(t, err) + } +} + +var validPlacementIds = map[openrtb_ext.ExtImpYandex]yandexPlacementID{ + {PlacementID: "A-12345-1"}: {PageID: "12345", ImpID: "1"}, + {PlacementID: "B-A-123123-123"}: {PageID: "123123", ImpID: "123"}, + {PlacementID: "111-222"}: {PageID: "111", ImpID: "222"}, + {PageID: 111, ImpID: 222}: {PageID: "111", ImpID: "222"}, +} + +var invalidPlacementIds = []openrtb_ext.ExtImpYandex{ + {PlacementID: "123123"}, + {PlacementID: "A-123123"}, + {PlacementID: "B-A-123123"}, + {PlacementID: "C-B-A-123123"}, +} diff --git a/adapters/yandex/yandex.go b/adapters/yandex/yandex.go new file mode 100644 index 00000000000..23f90f7954e --- /dev/null +++ b/adapters/yandex/yandex.go @@ -0,0 +1,339 @@ +package yandex + +import ( + "encoding/json" + "fmt" + "net/http" + "net/url" + "strconv" + "strings" + "text/template" + + "github.com/prebid/openrtb/v19/openrtb2" + "github.com/prebid/prebid-server/v2/adapters" + "github.com/prebid/prebid-server/v2/config" + "github.com/prebid/prebid-server/v2/errortypes" + "github.com/prebid/prebid-server/v2/macros" + "github.com/prebid/prebid-server/v2/openrtb_ext" +) + +const ( + refererQueryKey = "target-ref" + currencyQueryKey = "ssp-cur" + impIdQueryKey = "imp-id" +) + +// Composite id of an ad placement +type yandexPlacementID struct { + PageID string + ImpID string +} + +type adapter struct { + endpoint *template.Template +} + +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + template, err := template.New("endpointTemplate").Parse(config.Endpoint) + if err != nil { + return nil, fmt.Errorf("unable to parse endpoint url template: %v", err) + } + + bidder := &adapter{ + endpoint: template, + } + + return bidder, nil +} + +func (a *adapter) MakeRequests(requestData *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + var ( + requests []*adapters.RequestData + errors []error + ) + + referer := getReferer(requestData) + currency := getCurrency(requestData) + + for i := range requestData.Imp { + imp := requestData.Imp[i] + + placementId, err := getYandexPlacementId(imp) + if err != nil { + errors = append(errors, err) + continue + } + + if err := modifyImp(&imp); err != nil { + errors = append(errors, err) + continue + } + + resolvedUrl, err := a.resolveUrl(*placementId, referer, currency) + if err != nil { + errors = append(errors, err) + continue + } + + splittedRequestData := splitRequestDataByImp(requestData, imp) + + requestBody, err := json.Marshal(splittedRequestData) + if err != nil { + errors = append(errors, err) + continue + } + + requests = append(requests, &adapters.RequestData{ + Method: "POST", + Uri: resolvedUrl, + Body: requestBody, + Headers: getHeaders(&splittedRequestData), + }) + } + + return requests, errors +} + +func getHeaders(request *openrtb2.BidRequest) http.Header { + headers := http.Header{} + + if request.Device != nil && request.Site != nil { + addNonEmptyHeaders(&headers, map[string]string{ + "Referer": request.Site.Page, + "Accept-Language": request.Device.Language, + "User-Agent": request.Device.UA, + "X-Forwarded-For": request.Device.IP, + "X-Real-Ip": request.Device.IP, + "Content-Type": "application/json;charset=utf-8", + "Accept": "application/json", + }) + } + + return headers +} + +func addNonEmptyHeaders(headers *http.Header, headerValues map[string]string) { + for key, value := range headerValues { + if len(value) > 0 { + headers.Add(key, value) + } + } +} + +// Request is in shared memory, so we have to make a shallow copy for further modification (imp is already a shallow copy) +func splitRequestDataByImp(request *openrtb2.BidRequest, imp openrtb2.Imp) openrtb2.BidRequest { + requestCopy := *request + requestCopy.Imp = []openrtb2.Imp{imp} + + return requestCopy +} + +func getYandexPlacementId(imp openrtb2.Imp) (*yandexPlacementID, error) { + var ext adapters.ExtImpBidder + if err := json.Unmarshal(imp.Ext, &ext); err != nil { + return nil, &errortypes.BadInput{ + Message: fmt.Sprintf("imp %s: unable to unmarshal ext", imp.ID), + } + } + + var yandexExt openrtb_ext.ExtImpYandex + if err := json.Unmarshal(ext.Bidder, &yandexExt); err != nil { + return nil, &errortypes.BadInput{ + Message: fmt.Sprintf("imp %s: unable to unmarshal ext.bidder: %v", imp.ID, err), + } + } + + placementID, err := mapExtToPlacementID(yandexExt) + if err != nil { + return nil, err + } + + return placementID, nil +} + +func mapExtToPlacementID(yandexExt openrtb_ext.ExtImpYandex) (*yandexPlacementID, error) { + var placementID yandexPlacementID + + if len(yandexExt.PlacementID) == 0 { + placementID.ImpID = strconv.Itoa(int(yandexExt.ImpID)) + placementID.PageID = strconv.Itoa(int(yandexExt.PageID)) + return &placementID, nil + } + + idParts := strings.Split(yandexExt.PlacementID, "-") + + numericIdParts := []string{} + + for _, idPart := range idParts { + if _, err := strconv.Atoi(idPart); err == nil { + numericIdParts = append(numericIdParts, idPart) + } + } + + if len(numericIdParts) < 2 { + return nil, &errortypes.BadInput{ + Message: fmt.Sprintf("invalid placement id, it must contain two parts: %s", yandexExt.PlacementID), + } + } + + placementID.ImpID = numericIdParts[len(numericIdParts)-1] + placementID.PageID = numericIdParts[len(numericIdParts)-2] + + return &placementID, nil +} + +func modifyImp(imp *openrtb2.Imp) error { + if imp.Banner != nil { + banner, err := modifyBanner(*imp.Banner) + if banner != nil { + imp.Banner = banner + } + return err + } + + if imp.Native != nil { + return nil + } + + return &errortypes.BadInput{ + Message: fmt.Sprintf("Unsupported format. Yandex only supports banner and native types. Ignoring imp id #%s", imp.ID), + } +} + +func modifyBanner(banner openrtb2.Banner) (*openrtb2.Banner, error) { + format := banner.Format + + if banner.W == nil || banner.H == nil || *banner.W == 0 || *banner.H == 0 { + if len(format) == 0 { + return nil, &errortypes.BadInput{ + Message: "Invalid size provided for Banner", + } + } + + firstFormat := format[0] + banner.H = &firstFormat.H + banner.W = &firstFormat.W + } + + return &banner, nil +} + +// "Un-templates" the endpoint by replacing macroses and adding the required query parameters +func (a *adapter) resolveUrl(placementID yandexPlacementID, referer string, currency string) (string, error) { + params := macros.EndpointTemplateParams{PageID: placementID.PageID} + + endpointStr, err := macros.ResolveMacros(a.endpoint, params) + if err != nil { + return "", err + } + + parsedUrl, err := url.Parse(endpointStr) + if err != nil { + return "", err + } + + addNonEmptyQueryParams(parsedUrl, map[string]string{ + refererQueryKey: referer, + currencyQueryKey: currency, + impIdQueryKey: placementID.ImpID, + }) + + return parsedUrl.String(), nil +} + +func addNonEmptyQueryParams(url *url.URL, queryMap map[string]string) { + query := url.Query() + for key, value := range queryMap { + if len(value) > 0 { + query.Add(key, value) + } + } + + url.RawQuery = query.Encode() +} + +func getReferer(request *openrtb2.BidRequest) string { + if request.Site == nil { + return "" + } + + return request.Site.Domain +} + +func getCurrency(request *openrtb2.BidRequest) string { + if len(request.Cur) == 0 { + return "" + } + + return request.Cur[0] +} + +func (a *adapter) MakeBids(request *openrtb2.BidRequest, _ *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 bidResponse openrtb2.BidResponse + if err := json.Unmarshal(responseData.Body, &bidResponse); err != nil { + return nil, []error{&errortypes.BadServerResponse{ + Message: fmt.Sprintf("Bad server response: %d", err), + }} + } + + bidResponseWithCapacity := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) + + var errors []error + + impMap := map[string]*openrtb2.Imp{} + for i := range request.Imp { + imp := request.Imp[i] + + impMap[imp.ID] = &imp + } + + for _, seatBid := range bidResponse.SeatBid { + for i := range seatBid.Bid { + bid := seatBid.Bid[i] + + imp, exists := impMap[bid.ImpID] + if !exists { + errors = append(errors, &errortypes.BadInput{ + Message: fmt.Sprintf("Invalid bid imp ID #%s does not match any imp IDs from the original bid request", bid.ImpID), + }) + continue + } + + bidType, err := getBidType(*imp) + if err != nil { + errors = append(errors, err) + continue + } + + bidResponseWithCapacity.Bids = append(bidResponseWithCapacity.Bids, &adapters.TypedBid{ + Bid: &bid, + BidType: bidType, + }) + } + } + + return bidResponseWithCapacity, errors +} + +func getBidType(imp openrtb2.Imp) (openrtb_ext.BidType, error) { + if imp.Native != nil { + return openrtb_ext.BidTypeNative, nil + } + + if imp.Banner != nil { + return openrtb_ext.BidTypeBanner, nil + } + + return "", &errortypes.BadInput{ + Message: fmt.Sprintf("Processing an invalid impression; cannot resolve impression type for imp #%s", imp.ID), + } +} diff --git a/adapters/yandex/yandex_test.go b/adapters/yandex/yandex_test.go new file mode 100644 index 00000000000..6978cd8bb54 --- /dev/null +++ b/adapters/yandex/yandex_test.go @@ -0,0 +1,29 @@ +package yandex + +import ( + "testing" + + "github.com/prebid/prebid-server/v2/adapters/adapterstest" + "github.com/prebid/prebid-server/v2/config" + "github.com/prebid/prebid-server/v2/openrtb_ext" + "github.com/stretchr/testify/assert" +) + +func TestJsonSamples(t *testing.T) { + bidder, buildErr := Builder(openrtb_ext.BidderYandex, + config.Adapter{Endpoint: "https://bs-metadsp.yandex.ru/prebid/{{.PageID}}?ssp-id=10500"}, + config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "yandextest", bidder) +} + +func TestEndpointTemplateMalformed(t *testing.T) { + _, buildErr := Builder(openrtb_ext.BidderYandex, config.Adapter{ + Endpoint: "{{Malformed}}"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + assert.Error(t, buildErr) +} diff --git a/adapters/yandex/yandextest/exemplary/native.json b/adapters/yandex/yandextest/exemplary/native.json new file mode 100644 index 00000000000..f9b3888593b --- /dev/null +++ b/adapters/yandex/yandextest/exemplary/native.json @@ -0,0 +1,134 @@ +{ + "mockBidRequest": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "native": { + "request": "{}", + "ver": "1" + }, + "ext": { + "bidder": { + "placement_id": "R-134001-1" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "cur": [ + "USD" + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", + "ip": "127.0.0.1", + "language": "EN" + }, + "tmax": 500 + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bs-metadsp.yandex.ru/prebid/134001?imp-id=1&ssp-cur=USD&ssp-id=10500&target-ref=www.example.com", + "headers": { + "User-Agent": [ + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Real-Ip": [ + "127.0.0.1" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Referer": [ + "http://www.example.com" + ], + "Accept": [ + "application/json" + ], + "Accept-Language": [ + "EN" + ] + }, + "body": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "native": { + "request": "{}", + "ver": "1" + }, + "ext": { + "bidder": { + "placement_id": "R-134001-1" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "cur": [ + "USD" + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", + "ip": "127.0.0.1", + "language": "EN" + }, + "tmax": 500 + } + }, + "mockResponse": { + "status": 200, + "headers": {}, + "body": { + "id": "request_id", + "seatbid": [ + { + "bid": [ + { + "id": "bid_id", + "impid": "imp_id", + "price": 1.25, + "crid": "crid", + "adm": "adm_content", + "h": 600, + "w": 300 + } + ] + } + ], + "bidid": "bid_id", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "bid_id", + "impid": "imp_id", + "price": 1.25, + "adm": "adm_content", + "crid": "crid", + "w": 300, + "h": 600 + }, + "type": "native" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/yandex/yandextest/exemplary/simple-banner.json b/adapters/yandex/yandextest/exemplary/simple-banner.json new file mode 100644 index 00000000000..477e4ef5848 --- /dev/null +++ b/adapters/yandex/yandextest/exemplary/simple-banner.json @@ -0,0 +1,134 @@ +{ + "mockBidRequest": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 300, + "h": 600 + }, + "ext": { + "bidder": { + "placement_id": "134001-1" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "cur": [ + "USD" + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", + "ip": "127.0.0.1", + "language": "EN" + }, + "tmax": 500 + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bs-metadsp.yandex.ru/prebid/134001?imp-id=1&ssp-cur=USD&ssp-id=10500&target-ref=www.example.com", + "headers": { + "User-Agent": [ + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Real-Ip": [ + "127.0.0.1" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Referer": [ + "http://www.example.com" + ], + "Accept": [ + "application/json" + ], + "Accept-Language": [ + "EN" + ] + }, + "body": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 300, + "h": 600 + }, + "ext": { + "bidder": { + "placement_id": "134001-1" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "cur": [ + "USD" + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", + "ip": "127.0.0.1", + "language": "EN" + }, + "tmax": 500 + } + }, + "mockResponse": { + "status": 200, + "headers": {}, + "body": { + "id": "request_id", + "seatbid": [ + { + "bid": [ + { + "id": "bid_id", + "impid": "imp_id", + "price": 1.25, + "crid": "crid", + "adm": "content", + "h": 600, + "w": 300 + } + ] + } + ], + "bidid": "bid_id", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "bid_id", + "impid": "imp_id", + "price": 1.25, + "adm": "content", + "crid": "crid", + "w": 300, + "h": 600 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/yandex/yandextest/supplemental/multiple-imps-some-malformed.json b/adapters/yandex/yandextest/supplemental/multiple-imps-some-malformed.json new file mode 100644 index 00000000000..299f4013392 --- /dev/null +++ b/adapters/yandex/yandextest/supplemental/multiple-imps-some-malformed.json @@ -0,0 +1,145 @@ +{ + "mockBidRequest": { + "id": "request_id", + "imp": [ + { + "id": "imp_id1", + "banner": { + "w": 300, + "h": 600 + }, + "ext": { + "bidder": { + "page_id": 111, + "imp_id": 1 + } + } + }, + { + "id": "imp_id2", + "ext": { + "bidder": { + "page_id": 222, + "imp_id": 2 + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "cur": [ + "USD" + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", + "ip": "127.0.0.1" + }, + "tmax": 500 + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bs-metadsp.yandex.ru/prebid/111?imp-id=1&ssp-cur=USD&ssp-id=10500&target-ref=www.example.com", + "headers": { + "User-Agent": [ + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Real-Ip": [ + "127.0.0.1" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Referer": [ + "http://www.example.com" + ], + "Accept": [ + "application/json" + ] + }, + "body": { + "id": "request_id", + "imp": [ + { + "id": "imp_id1", + "banner": { + "w": 300, + "h": 600 + }, + "ext": { + "bidder": { + "page_id": 111, + "imp_id": 1 + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "cur": [ + "USD" + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", + "ip": "127.0.0.1" + }, + "tmax": 500 + } + }, + "mockResponse": { + "status": 200, + "headers": {}, + "body": { + "id": "request_id", + "seatbid": [ + { + "bid": [ + { + "id": "bid_id1", + "impid": "imp_id1", + "price": 1.25, + "crid": "crid", + "adm": "adm001", + "h": 600, + "w": 300 + } + ] + } + ], + "bidid": "bid_id" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "bid_id1", + "impid": "imp_id1", + "price": 1.25, + "adm": "adm001", + "crid": "crid", + "w": 300, + "h": 600 + }, + "type": "banner" + } + ] + } + ], + "expectedMakeRequestsErrors": [ + { + "value": "Unsupported format", + "comparison": "regex" + } + ] +} \ No newline at end of file diff --git a/adapters/yandex/yandextest/supplemental/multiple-imps.json b/adapters/yandex/yandextest/supplemental/multiple-imps.json new file mode 100644 index 00000000000..b83f51ebc3c --- /dev/null +++ b/adapters/yandex/yandextest/supplemental/multiple-imps.json @@ -0,0 +1,235 @@ +{ + "mockBidRequest": { + "id": "request_id", + "imp": [ + { + "id": "imp_id1", + "banner": { + "w": 300, + "h": 600 + }, + "ext": { + "bidder": { + "page_id": 111, + "imp_id": 1 + } + } + }, + { + "id": "imp_id2", + "banner": { + "w": 400, + "h": 800 + }, + "ext": { + "bidder": { + "placement_id": "222-2" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "cur": [ + "USD" + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", + "ip": "127.0.0.1" + }, + "tmax": 500 + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bs-metadsp.yandex.ru/prebid/111?imp-id=1&ssp-cur=USD&ssp-id=10500&target-ref=www.example.com", + "headers": { + "User-Agent": [ + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Real-Ip": [ + "127.0.0.1" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Referer": [ + "http://www.example.com" + ], + "Accept": [ + "application/json" + ] + }, + "body": { + "id": "request_id", + "imp": [ + { + "id": "imp_id1", + "banner": { + "w": 300, + "h": 600 + }, + "ext": { + "bidder": { + "page_id": 111, + "imp_id": 1 + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "cur": [ + "USD" + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", + "ip": "127.0.0.1" + }, + "tmax": 500 + } + }, + "mockResponse": { + "status": 200, + "headers": {}, + "body": { + "id": "request_id", + "seatbid": [ + { + "bid": [ + { + "id": "bid_id1", + "impid": "imp_id1", + "price": 1.25, + "crid": "crid", + "adm": "adm001", + "h": 600, + "w": 300 + } + ] + } + ], + "bidid": "bid_id" + } + } + }, + { + "expectedRequest": { + "uri": "https://bs-metadsp.yandex.ru/prebid/222?imp-id=2&ssp-cur=USD&ssp-id=10500&target-ref=www.example.com", + "headers": { + "User-Agent": [ + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Real-Ip": [ + "127.0.0.1" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Referer": [ + "http://www.example.com" + ], + "Accept": [ + "application/json" + ] + }, + "body": { + "id": "request_id", + "imp": [ + { + "id": "imp_id2", + "banner": { + "w": 400, + "h": 800 + }, + "ext": { + "bidder": { + "placement_id": "222-2" + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "cur": [ + "USD" + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", + "ip": "127.0.0.1" + }, + "tmax": 500 + } + }, + "mockResponse": { + "status": 200, + "headers": {}, + "body": { + "id": "request_id", + "seatbid": [ + { + "bid": [ + { + "id": "bid_id2", + "impid": "imp_id2", + "price": 1.25, + "crid": "crid", + "adm": "adm001", + "h": 800, + "w": 400 + } + ] + } + ], + "bidid": "bid_id" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "bid_id1", + "impid": "imp_id1", + "price": 1.25, + "adm": "adm001", + "crid": "crid", + "w": 300, + "h": 600 + }, + "type": "banner" + } + ] + }, + { + "bids": [ + { + "bid": { + "id": "bid_id2", + "impid": "imp_id2", + "price": 1.25, + "adm": "adm001", + "crid": "crid", + "w": 400, + "h": 800 + }, + "type": "banner" + } + ] + } + ] +} \ No newline at end of file diff --git a/adapters/yandex/yandextest/supplemental/simple-banner-empty-response.json b/adapters/yandex/yandextest/supplemental/simple-banner-empty-response.json new file mode 100644 index 00000000000..ffc067ebe7a --- /dev/null +++ b/adapters/yandex/yandextest/supplemental/simple-banner-empty-response.json @@ -0,0 +1,100 @@ +{ + "mockBidRequest": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 300, + "h": 600 + }, + "ext": { + "bidder": { + "page_id": 134001, + "imp_id": 1 + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "cur": [ + "USD" + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", + "ip": "127.0.0.1" + }, + "tmax": 500 + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bs-metadsp.yandex.ru/prebid/134001?imp-id=1&ssp-cur=USD&ssp-id=10500&target-ref=www.example.com", + "headers": { + "User-Agent": [ + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Real-Ip": [ + "127.0.0.1" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Referer": [ + "http://www.example.com" + ], + "Accept": [ + "application/json" + ] + }, + "body": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 300, + "h": 600 + }, + "ext": { + "bidder": { + "page_id": 134001, + "imp_id": 1 + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "cur": [ + "USD" + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", + "ip": "127.0.0.1" + }, + "tmax": 500 + } + }, + "mockResponse": { + "status": 200, + "headers": {} + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "Bad server response", + "comparison": "regex" + } + ] +} \ No newline at end of file diff --git a/adapters/yandex/yandextest/supplemental/simple-banner-empty-seatbid.json b/adapters/yandex/yandextest/supplemental/simple-banner-empty-seatbid.json new file mode 100644 index 00000000000..eafb27a41ca --- /dev/null +++ b/adapters/yandex/yandextest/supplemental/simple-banner-empty-seatbid.json @@ -0,0 +1,105 @@ +{ + "mockBidRequest": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 300, + "h": 600 + }, + "ext": { + "bidder": { + "page_id": 134001, + "imp_id": 1 + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "cur": [ + "USD" + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", + "ip": "127.0.0.1" + }, + "tmax": 500 + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bs-metadsp.yandex.ru/prebid/134001?imp-id=1&ssp-cur=USD&ssp-id=10500&target-ref=www.example.com", + "headers": { + "User-Agent": [ + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Real-Ip": [ + "127.0.0.1" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Referer": [ + "http://www.example.com" + ], + "Accept": [ + "application/json" + ] + }, + "body": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 300, + "h": 600 + }, + "ext": { + "bidder": { + "page_id": 134001, + "imp_id": 1 + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "cur": [ + "USD" + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", + "ip": "127.0.0.1" + }, + "tmax": 500 + } + }, + "mockResponse": { + "status": 200, + "headers": {}, + "body": { + "id": "request_id", + "seatbid": null, + "bidid": "bid_id", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [] + } + ], + "expectedMakeBidsErrors": [] +} \ No newline at end of file diff --git a/adapters/yandex/yandextest/supplemental/simple-banner-sizes.json b/adapters/yandex/yandextest/supplemental/simple-banner-sizes.json new file mode 100644 index 00000000000..23a142887db --- /dev/null +++ b/adapters/yandex/yandextest/supplemental/simple-banner-sizes.json @@ -0,0 +1,232 @@ +{ + "mockBidRequest": { + "id": "request_id", + "imp": [ + { + "id": "invalid_width", + "banner": { + "w": 0, + "h": 600 + }, + "ext": { + "bidder": { + "page_id": 111, + "imp_id": 1 + } + } + }, + { + "id": "invalid_height", + "banner": { + "w": 400, + "h": 0 + }, + "ext": { + "bidder": { + "page_id": 222, + "imp_id": 2 + } + } + }, + { + "id": "invalid_size", + "banner": { + "w": 0, + "h": 0 + }, + "ext": { + "bidder": { + "page_id": 222, + "imp_id": 3 + } + } + }, + { + "id": "invalid_no_size_no_formats", + "banner": {}, + "ext": { + "bidder": { + "page_id": 222, + "imp_id": 5 + } + } + }, + { + "id": "invalid_size", + "banner": { + "w": 0, + "h": 0 + }, + "ext": { + "bidder": { + "page_id": 222, + "imp_id": 3 + } + } + }, + { + "id": "no_size_but_valid_formats", + "banner": { + "format": [ + { + "w": 600, + "h": 500 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "page_id": 222, + "imp_id": 4 + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "cur": [ + "USD" + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", + "ip": "127.0.0.1" + }, + "tmax": 500 + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bs-metadsp.yandex.ru/prebid/222?imp-id=4&ssp-cur=USD&ssp-id=10500&target-ref=www.example.com", + "headers": { + "User-Agent": [ + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Real-Ip": [ + "127.0.0.1" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Referer": [ + "http://www.example.com" + ], + "Accept": [ + "application/json" + ] + }, + "body": { + "id": "request_id", + "imp": [ + { + "id": "no_size_but_valid_formats", + "banner": { + "w": 600, + "h": 500, + "format": [ + { + "w": 600, + "h": 500 + }, + { + "w": 300, + "h": 600 + } + ] + }, + "ext": { + "bidder": { + "page_id": 222, + "imp_id": 4 + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "cur": [ + "USD" + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", + "ip": "127.0.0.1" + }, + "tmax": 500 + } + }, + "mockResponse": { + "status": 200, + "headers": {}, + "body": { + "id": "request_id", + "seatbid": [ + { + "bid": [ + { + "id": "bid_id4", + "impid": "no_size_but_valid_formats", + "price": 1.25, + "crid": "crid", + "adm": "adm001", + "h": 800, + "w": 400 + } + ] + } + ], + "bidid": "bid_id" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [ + { + "bid": { + "id": "bid_id4", + "impid": "no_size_but_valid_formats", + "price": 1.25, + "adm": "adm001", + "crid": "crid", + "w": 400, + "h": 800 + }, + "type": "banner" + } + ] + } + ], + "expectedMakeRequestsErrors": [ + { + "value": "Invalid size", + "comparison": "regex" + }, + { + "value": "Invalid size", + "comparison": "regex" + }, + { + "value": "Invalid size", + "comparison": "regex" + }, + { + "value": "Invalid size", + "comparison": "regex" + }, + { + "value": "Invalid size", + "comparison": "regex" + } + ] +} \ No newline at end of file diff --git a/adapters/yandex/yandextest/supplemental/simple-banner-status-400.json b/adapters/yandex/yandextest/supplemental/simple-banner-status-400.json new file mode 100644 index 00000000000..78d2813bb4f --- /dev/null +++ b/adapters/yandex/yandextest/supplemental/simple-banner-status-400.json @@ -0,0 +1,101 @@ +{ + "mockBidRequest": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 300, + "h": 600 + }, + "ext": { + "bidder": { + "page_id": 134001, + "imp_id": 1 + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "cur": [ + "USD" + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", + "ip": "127.0.0.1" + }, + "tmax": 500 + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bs-metadsp.yandex.ru/prebid/134001?imp-id=1&ssp-cur=USD&ssp-id=10500&target-ref=www.example.com", + "headers": { + "User-Agent": [ + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Real-Ip": [ + "127.0.0.1" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Referer": [ + "http://www.example.com" + ], + "Accept": [ + "application/json" + ] + }, + "body": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 300, + "h": 600 + }, + "ext": { + "bidder": { + "page_id": 134001, + "imp_id": 1 + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "cur": [ + "USD" + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", + "ip": "127.0.0.1" + }, + "tmax": 500 + } + }, + "mockResponse": { + "status": 400, + "headers": {}, + "body": {} + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "Unexpected status code", + "comparison": "regex" + } + ] +} \ No newline at end of file diff --git a/adapters/yandex/yandextest/supplemental/simple-banner-unknown-imp.json b/adapters/yandex/yandextest/supplemental/simple-banner-unknown-imp.json new file mode 100644 index 00000000000..5c94be30605 --- /dev/null +++ b/adapters/yandex/yandextest/supplemental/simple-banner-unknown-imp.json @@ -0,0 +1,124 @@ +{ + "mockBidRequest": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 300, + "h": 600 + }, + "ext": { + "bidder": { + "page_id": 134001, + "imp_id": 1 + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "cur": [ + "USD" + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", + "ip": "127.0.0.1" + }, + "tmax": 500 + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bs-metadsp.yandex.ru/prebid/134001?imp-id=1&ssp-cur=USD&ssp-id=10500&target-ref=www.example.com", + "headers": { + "User-Agent": [ + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Real-Ip": [ + "127.0.0.1" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Referer": [ + "http://www.example.com" + ], + "Accept": [ + "application/json" + ] + }, + "body": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 300, + "h": 600 + }, + "ext": { + "bidder": { + "page_id": 134001, + "imp_id": 1 + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "cur": [ + "USD" + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", + "ip": "127.0.0.1" + }, + "tmax": 500 + } + }, + "mockResponse": { + "status": 200, + "headers": {}, + "body": { + "id": "request_id", + "seatbid": [ + { + "bid": [ + { + "id": "bid_id", + "impid": "imp_id_unknown", + "price": 1.25, + "crid": "crid", + "adm": "content", + "h": 600, + "w": 300 + } + ] + } + ], + "bidid": "bid_id", + "cur": "USD" + } + } + } + ], + "expectedBidResponses": [ + { + "bids": [] + } + ], + "expectedMakeBidsErrors": [ + { + "value": "Invalid bid imp", + "comparison": "regex" + } + ] +} \ No newline at end of file diff --git a/adapters/yandex/yandextest/supplemental/simple-banner-unparsable-body.json b/adapters/yandex/yandextest/supplemental/simple-banner-unparsable-body.json new file mode 100644 index 00000000000..0adfdb40acf --- /dev/null +++ b/adapters/yandex/yandextest/supplemental/simple-banner-unparsable-body.json @@ -0,0 +1,101 @@ +{ + "mockBidRequest": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 300, + "h": 600 + }, + "ext": { + "bidder": { + "page_id": 134001, + "imp_id": 1 + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "cur": [ + "USD" + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", + "ip": "127.0.0.1" + }, + "tmax": 500 + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bs-metadsp.yandex.ru/prebid/134001?imp-id=1&ssp-cur=USD&ssp-id=10500&target-ref=www.example.com", + "headers": { + "User-Agent": [ + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36" + ], + "X-Forwarded-For": [ + "127.0.0.1" + ], + "X-Real-Ip": [ + "127.0.0.1" + ], + "Content-Type": [ + "application/json;charset=utf-8" + ], + "Referer": [ + "http://www.example.com" + ], + "Accept": [ + "application/json" + ] + }, + "body": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "banner": { + "w": 300, + "h": 600 + }, + "ext": { + "bidder": { + "page_id": 134001, + "imp_id": 1 + } + } + } + ], + "site": { + "domain": "www.example.com", + "page": "http://www.example.com" + }, + "cur": [ + "USD" + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", + "ip": "127.0.0.1" + }, + "tmax": 500 + } + }, + "mockResponse": { + "status": 200, + "headers": {}, + "body": "invalid" + } + } + ], + "expectedBidResponses": [], + "expectedMakeBidsErrors": [ + { + "value": "Bad server response", + "comparison": "regex" + } + ] +} \ No newline at end of file diff --git a/adapters/yandex/yandextest/supplemental/unknown-banner.json b/adapters/yandex/yandextest/supplemental/unknown-banner.json new file mode 100644 index 00000000000..a01b9037180 --- /dev/null +++ b/adapters/yandex/yandextest/supplemental/unknown-banner.json @@ -0,0 +1,32 @@ +{ + "mockBidRequest": { + "id": "request_id", + "imp": [ + { + "id": "imp_id", + "video": { + "w": 100, + "h": 200 + }, + "ext": { + "bidder": { + "page_id": 134001, + "imp_id": 1 + } + } + } + ], + "device": { + "ua": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/72.0.3626.121 Safari/537.36", + "ip": "127.0.0.1" + }, + "tmax": 500 + }, + "httpCalls": [], + "expectedMakeRequestsErrors": [ + { + "value": "Unsupported format", + "comparison": "regex" + } + ] +} \ No newline at end of file diff --git a/analytics/build/build.go b/analytics/build/build.go index 7fc577daedf..cd0b870f793 100644 --- a/analytics/build/build.go +++ b/analytics/build/build.go @@ -8,6 +8,8 @@ import ( "github.com/prebid/prebid-server/v2/analytics/filesystem" "github.com/prebid/prebid-server/v2/analytics/pubstack" "github.com/prebid/prebid-server/v2/config" + "github.com/prebid/prebid-server/v2/openrtb_ext" + "github.com/prebid/prebid-server/v2/ortb" "github.com/prebid/prebid-server/v2/privacy" ) @@ -46,8 +48,10 @@ type enabledAnalytics map[string]analytics.Module func (ea enabledAnalytics) LogAuctionObject(ao *analytics.AuctionObject, ac privacy.ActivityControl) { for name, module := range ea { - component := privacy.Component{Type: privacy.ComponentTypeAnalytics, Name: name} - if ac.Allow(privacy.ActivityReportAnalytics, component, privacy.ActivityRequest{}) { + if isAllowed, cloneBidderReq := evaluateActivities(ao.RequestWrapper, ac, name); isAllowed { + if cloneBidderReq != nil { + ao.RequestWrapper = cloneBidderReq + } module.LogAuctionObject(ao) } } @@ -55,10 +59,13 @@ func (ea enabledAnalytics) LogAuctionObject(ao *analytics.AuctionObject, ac priv func (ea enabledAnalytics) LogVideoObject(vo *analytics.VideoObject, ac privacy.ActivityControl) { for name, module := range ea { - component := privacy.Component{Type: privacy.ComponentTypeAnalytics, Name: name} - if ac.Allow(privacy.ActivityReportAnalytics, component, privacy.ActivityRequest{}) { + if isAllowed, cloneBidderReq := evaluateActivities(vo.RequestWrapper, ac, name); isAllowed { + if cloneBidderReq != nil { + vo.RequestWrapper = cloneBidderReq + } module.LogVideoObject(vo) } + } } @@ -76,8 +83,10 @@ func (ea enabledAnalytics) LogSetUIDObject(so *analytics.SetUIDObject) { func (ea enabledAnalytics) LogAmpObject(ao *analytics.AmpObject, ac privacy.ActivityControl) { for name, module := range ea { - component := privacy.Component{Type: privacy.ComponentTypeAnalytics, Name: name} - if ac.Allow(privacy.ActivityReportAnalytics, component, privacy.ActivityRequest{}) { + if isAllowed, cloneBidderReq := evaluateActivities(ao.RequestWrapper, ac, name); isAllowed { + if cloneBidderReq != nil { + ao.RequestWrapper = cloneBidderReq + } module.LogAmpObject(ao) } } @@ -91,3 +100,31 @@ func (ea enabledAnalytics) LogNotificationEventObject(ne *analytics.Notification } } } + +func evaluateActivities(rw *openrtb_ext.RequestWrapper, ac privacy.ActivityControl, componentName string) (bool, *openrtb_ext.RequestWrapper) { + // returned nil request wrapper means that request wrapper was not modified by activities and doesn't have to be changed in analytics object + // it is needed in order to use one function for all analytics objects with RequestWrapper + component := privacy.Component{Type: privacy.ComponentTypeAnalytics, Name: componentName} + if !ac.Allow(privacy.ActivityReportAnalytics, component, privacy.ActivityRequest{}) { + return false, nil + } + blockUserFPD := !ac.Allow(privacy.ActivityTransmitUserFPD, component, privacy.ActivityRequest{}) + blockPreciseGeo := !ac.Allow(privacy.ActivityTransmitPreciseGeo, component, privacy.ActivityRequest{}) + + if !blockUserFPD && !blockPreciseGeo { + return true, nil + } + + cloneReq := ortb.CloneBidderReq(rw.BidRequest) + + if blockUserFPD { + privacy.ScrubUserFPD(cloneReq) + } + if blockPreciseGeo { + ipConf := privacy.IPConf{IPV6: ac.IPv6Config, IPV4: ac.IPv4Config} + privacy.ScrubGeoAndDeviceIP(cloneReq, ipConf) + } + + cloneReq.RebuildRequest() + return true, cloneReq +} diff --git a/analytics/build/build_test.go b/analytics/build/build_test.go index efc0c862564..d6fea975eda 100644 --- a/analytics/build/build_test.go +++ b/analytics/build/build_test.go @@ -1,6 +1,9 @@ package build import ( + "github.com/prebid/prebid-server/v2/openrtb_ext" + "github.com/prebid/prebid-server/v2/util/iputil" + "net/http" "os" "testing" @@ -143,7 +146,7 @@ func TestSampleModuleActivitiesAllowed(t *testing.T) { var count int am := initAnalytics(&count) - acAllowed := privacy.NewActivityControl(getDefaultActivityConfig("sampleModule", true)) + acAllowed := privacy.NewActivityControl(getActivityConfig("sampleModule", true, true, true)) ao := &analytics.AuctionObject{ Status: http.StatusOK, @@ -172,11 +175,46 @@ func TestSampleModuleActivitiesAllowed(t *testing.T) { } } +func TestSampleModuleActivitiesAllowedAndDenied(t *testing.T) { + var count int + am := initAnalytics(&count) + + acAllowed := privacy.NewActivityControl(getActivityConfig("sampleModule", true, false, true)) + + rw := &openrtb_ext.RequestWrapper{BidRequest: getDefaultBidRequest()} + ao := &analytics.AuctionObject{ + RequestWrapper: rw, + Status: http.StatusOK, + Errors: nil, + Response: &openrtb2.BidResponse{}, + } + + am.LogAuctionObject(ao, acAllowed) + if count != 1 { + t.Errorf("PBSAnalyticsModule failed at LogAuctionObject") + } + + am.LogAmpObject(&analytics.AmpObject{RequestWrapper: rw}, acAllowed) + if count != 2 { + t.Errorf("PBSAnalyticsModule failed at LogAmpObject") + } + + am.LogVideoObject(&analytics.VideoObject{RequestWrapper: rw}, acAllowed) + if count != 3 { + t.Errorf("PBSAnalyticsModule failed at LogVideoObject") + } + + am.LogNotificationEventObject(&analytics.NotificationEvent{}, acAllowed) + if count != 4 { + t.Errorf("PBSAnalyticsModule failed at LogNotificationEventObject") + } +} + func TestSampleModuleActivitiesDenied(t *testing.T) { var count int am := initAnalytics(&count) - acDenied := privacy.NewActivityControl(getDefaultActivityConfig("sampleModule", false)) + acDenied := privacy.NewActivityControl(getActivityConfig("sampleModule", false, true, true)) ao := &analytics.AuctionObject{ Status: http.StatusOK, @@ -205,14 +243,102 @@ func TestSampleModuleActivitiesDenied(t *testing.T) { } } -func getDefaultActivityConfig(componentName string, allow bool) *config.AccountPrivacy { +func TestEvaluateActivities(t *testing.T) { + testCases := []struct { + description string + givenActivityControl privacy.ActivityControl + expectedRequest *openrtb_ext.RequestWrapper + expectedAllowActivities bool + }{ + { + description: "all blocked", + givenActivityControl: privacy.NewActivityControl(getActivityConfig("sampleModule", false, false, false)), + expectedRequest: nil, + expectedAllowActivities: false, + }, + { + description: "all allowed", + givenActivityControl: privacy.NewActivityControl(getActivityConfig("sampleModule", true, true, true)), + expectedRequest: nil, + expectedAllowActivities: true, + }, + + { + description: "ActivityTransmitUserFPD and ActivityTransmitPreciseGeo disabled", + givenActivityControl: privacy.NewActivityControl(getActivityConfig("sampleModule", true, false, false)), + expectedRequest: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ID: "test_request", User: &openrtb2.User{ID: ""}, Device: &openrtb2.Device{IFA: "", IP: "127.0.0.0"}}, + }, + expectedAllowActivities: true, + }, + { + description: "ActivityTransmitUserFPD enabled, ActivityTransmitPreciseGeo disabled", + givenActivityControl: privacy.NewActivityControl(getActivityConfig("sampleModule", true, true, false)), + expectedRequest: &openrtb_ext.RequestWrapper{ + BidRequest: &openrtb2.BidRequest{ID: "test_request", User: &openrtb2.User{ID: "user-id"}, Device: &openrtb2.Device{IFA: "device-ifa", IP: "127.0.0.0"}}, + }, + expectedAllowActivities: true, + }, + } + + for _, test := range testCases { + t.Run(test.description, func(t *testing.T) { + rw := &openrtb_ext.RequestWrapper{BidRequest: getDefaultBidRequest()} + resActivityAllowed, resRequest := evaluateActivities(rw, test.givenActivityControl, "sampleModule") + assert.Equal(t, test.expectedAllowActivities, resActivityAllowed) + if test.expectedRequest != nil { + assert.Equal(t, test.expectedRequest.User.ID, resRequest.User.ID) + assert.Equal(t, test.expectedRequest.Device.IFA, resRequest.Device.IFA) + assert.Equal(t, test.expectedRequest.Device.IP, resRequest.Device.IP) + } else { + assert.Nil(t, resRequest) + } + + }) + } + +} + +func getDefaultBidRequest() *openrtb2.BidRequest { + return &openrtb2.BidRequest{ + ID: "test_request", + User: &openrtb2.User{ID: "user-id"}, + Device: &openrtb2.Device{IFA: "device-ifa", IP: "127.0.0.1"}} + +} + +func getActivityConfig(componentName string, allowReportAnalytics, allowTransmitUserFPD, allowTransmitPreciseGeo bool) *config.AccountPrivacy { return &config.AccountPrivacy{ AllowActivities: &config.AllowActivities{ ReportAnalytics: config.Activity{ Default: ptrutil.ToPtr(true), Rules: []config.ActivityRule{ { - Allow: allow, + Allow: allowReportAnalytics, + Condition: config.ActivityCondition{ + ComponentName: []string{componentName}, + ComponentType: []string{"analytics"}, + }, + }, + }, + }, + TransmitUserFPD: config.Activity{ + Default: ptrutil.ToPtr(true), + Rules: []config.ActivityRule{ + { + Allow: allowTransmitUserFPD, + Condition: config.ActivityCondition{ + ComponentName: []string{componentName}, + ComponentType: []string{"analytics"}, + }, + }, + }, + }, + TransmitPreciseGeo: config.Activity{ + Default: ptrutil.ToPtr(true), + Rules: []config.ActivityRule{ + { + Allow: allowTransmitPreciseGeo, Condition: config.ActivityCondition{ ComponentName: []string{componentName}, ComponentType: []string{"analytics"}, @@ -221,5 +347,11 @@ func getDefaultActivityConfig(componentName string, allow bool) *config.AccountP }, }, }, + IPv4Config: config.IPv4{ + AnonKeepBits: iputil.IPv4DefaultMaskingBitSize, + }, + IPv6Config: config.IPv6{ + AnonKeepBits: iputil.IPv6DefaultMaskingBitSize, + }, } } diff --git a/endpoints/openrtb2/video_auction_test.go b/endpoints/openrtb2/video_auction_test.go index 70a37aab5df..34606c1d051 100644 --- a/endpoints/openrtb2/video_auction_test.go +++ b/endpoints/openrtb2/video_auction_test.go @@ -1250,7 +1250,8 @@ func (m *mockAnalyticsModule) LogCookieSyncObject(cso *analytics.CookieSyncObjec func (m *mockAnalyticsModule) LogSetUIDObject(so *analytics.SetUIDObject) {} -func (m *mockAnalyticsModule) LogAmpObject(ao *analytics.AmpObject, _ privacy.ActivityControl) {} +func (m *mockAnalyticsModule) LogAmpObject(ao *analytics.AmpObject, _ privacy.ActivityControl) { +} func (m *mockAnalyticsModule) LogNotificationEventObject(ne *analytics.NotificationEvent, _ privacy.ActivityControl) { } diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index cfdc25ed467..7d998a77bd8 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -186,6 +186,7 @@ import ( "github.com/prebid/prebid-server/v2/adapters/vrtcal" "github.com/prebid/prebid-server/v2/adapters/xeworks" "github.com/prebid/prebid-server/v2/adapters/yahooAds" + "github.com/prebid/prebid-server/v2/adapters/yandex" "github.com/prebid/prebid-server/v2/adapters/yeahmobi" "github.com/prebid/prebid-server/v2/adapters/yieldlab" "github.com/prebid/prebid-server/v2/adapters/yieldmo" @@ -387,6 +388,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderVrtcal: vrtcal.Builder, openrtb_ext.BidderXeworks: xeworks.Builder, openrtb_ext.BidderYahooAds: yahooAds.Builder, + openrtb_ext.BidderYandex: yandex.Builder, openrtb_ext.BidderYeahmobi: yeahmobi.Builder, openrtb_ext.BidderYieldlab: yieldlab.Builder, openrtb_ext.BidderYieldmo: yieldmo.Builder, diff --git a/exchange/bidder.go b/exchange/bidder.go index ce502e53d84..ebe1d5d384b 100644 --- a/exchange/bidder.go +++ b/exchange/bidder.go @@ -13,6 +13,7 @@ import ( "net/http/httptrace" "regexp" "strings" + "sync" "time" "github.com/golang/glog" @@ -523,12 +524,12 @@ func (bidder *bidderAdapter) doRequest(ctx context.Context, req *adapters.Reques func (bidder *bidderAdapter) doRequestImpl(ctx context.Context, req *adapters.RequestData, logger util.LogMsg, bidderRequestStartTime time.Time, tmaxAdjustments *TmaxAdjustmentsPreprocessed) *httpCallInfo { var requestBody []byte - switch strings.ToUpper(bidder.config.EndpointCompression) { - case Gzip: - requestBody = compressToGZIP(req.Body) - req.Headers.Set("Content-Encoding", "gzip") - default: - requestBody = req.Body + requestBody, err := getRequestBody(req, bidder.config.EndpointCompression) + if err != nil { + return &httpCallInfo{ + request: req, + err: err, + } } httpReq, err := http.NewRequest(req.Method, req.Uri, bytes.NewBuffer(requestBody)) if err != nil { @@ -716,14 +717,6 @@ func prepareStoredResponse(impId string, bidResp json.RawMessage) *httpCallInfo return respData } -func compressToGZIP(requestBody []byte) []byte { - var b bytes.Buffer - w := gzip.NewWriter(&b) - w.Write([]byte(requestBody)) - w.Close() - return b.Bytes() -} - func getBidTypeForAdjustments(bidType openrtb_ext.BidType, impID string, imp []openrtb2.Imp) string { if bidType == openrtb_ext.BidTypeVideo { for _, imp := range imp { @@ -751,3 +744,40 @@ func hasShorterDurationThanTmax(ctx bidderTmaxContext, tmaxAdjustments TmaxAdjus } return false } + +func getRequestBody(req *adapters.RequestData, endpointCompression string) ([]byte, error) { + var requestBody []byte + + switch strings.ToUpper(endpointCompression) { + case Gzip: + // Compress to GZIP + var b bytes.Buffer + + w := gzipWriterPool.Get().(*gzip.Writer) + defer gzipWriterPool.Put(w) + + w.Reset(&b) + _, err := w.Write(req.Body) + if err != nil { + return nil, err + } + err = w.Close() + if err != nil { + return nil, err + } + requestBody = b.Bytes() + + // Set Header + req.Headers.Set("Content-Encoding", "gzip") + + return requestBody, nil + default: + return req.Body, nil + } +} + +var gzipWriterPool = sync.Pool{ + New: func() interface{} { + return gzip.NewWriter(nil) + }, +} diff --git a/exchange/bidder_test.go b/exchange/bidder_test.go index b2314c8c428..d3af2a46e91 100644 --- a/exchange/bidder_test.go +++ b/exchange/bidder_test.go @@ -2,6 +2,7 @@ package exchange import ( "bytes" + "compress/gzip" "context" "crypto/tls" "encoding/json" @@ -3347,3 +3348,77 @@ func TestDoRequestImplWithTmaxTimeout(t *testing.T) { test.assertFn(httpCallInfo.err) } } + +func TestGetRequestBody(t *testing.T) { + tests := []struct { + name string + endpointCompression string + givenReqBody []byte + }{ + { + name: "No-Compression", + endpointCompression: "", + givenReqBody: []byte("test body"), + }, + { + name: "GZIP-Compression", + endpointCompression: "GZIP", + givenReqBody: []byte("test body"), + }, + } + + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + req := &adapters.RequestData{Body: test.givenReqBody, Headers: http.Header{}} + requestBody, err := getRequestBody(req, test.endpointCompression) + assert.NoError(t, err) + + if test.endpointCompression == "GZIP" { + assert.Equal(t, "gzip", req.Headers.Get("Content-Encoding")) + + decompressedReqBody, err := decompressGzip(requestBody) + assert.NoError(t, err) + assert.Equal(t, test.givenReqBody, decompressedReqBody) + } else { + assert.Equal(t, test.givenReqBody, requestBody) + } + }) + } +} + +func decompressGzip(input []byte) ([]byte, error) { + r, err := gzip.NewReader(bytes.NewReader(input)) + if err != nil { + return nil, err + } + defer r.Close() + + decompressed, err := io.ReadAll(r) + if err != nil { + return nil, err + } + + return decompressed, nil +} + +func BenchmarkCompressToGZIPOptimized(b *testing.B) { + // Setup the mock server + respBody := "{\"bid\":false}" + respStatus := 200 + server := httptest.NewServer(mockHandler(respStatus, "getBody", respBody)) + defer server.Close() + + // Prepare the request data + req := &adapters.RequestData{ + Method: "POST", + Uri: server.URL, + Body: []byte("{\"key\":\"val\"}"), + Headers: http.Header{}, + } + + // Run the benchmark + b.ResetTimer() + for i := 0; i < b.N; i++ { + getRequestBody(req, "GZIP") + } +} diff --git a/macros/macros.go b/macros/macros.go index 609e72cdec7..bbee7271d8a 100644 --- a/macros/macros.go +++ b/macros/macros.go @@ -15,6 +15,7 @@ type EndpointTemplateParams struct { AdUnit string MediaType string GvlID string + PageID string } // UserSyncPrivacy specifies privacy policy macros, represented as strings, for user sync urls. diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index e903736d301..438d2281253 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -204,6 +204,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderVrtcal, BidderXeworks, BidderYahooAds, + BidderYandex, BidderYeahmobi, BidderYieldlab, BidderYieldmo, @@ -481,6 +482,7 @@ const ( BidderVrtcal BidderName = "vrtcal" BidderXeworks BidderName = "xeworks" BidderYahooAds BidderName = "yahooAds" + BidderYandex BidderName = "yandex" BidderYeahmobi BidderName = "yeahmobi" BidderYieldlab BidderName = "yieldlab" BidderYieldmo BidderName = "yieldmo" diff --git a/openrtb_ext/imp_yandex.go b/openrtb_ext/imp_yandex.go new file mode 100644 index 00000000000..8439d95f845 --- /dev/null +++ b/openrtb_ext/imp_yandex.go @@ -0,0 +1,16 @@ +package openrtb_ext + +type ExtImpYandex struct { + /* + Possible formats + - `R-I-123456-2` + - `R-123456-1` + - `123456-789` + */ + PlacementID string `json:"placement_id"` + + // Deprecated: in favor of `PlacementID` + PageID int64 `json:"page_id"` + // Deprecated: in favor of `PlacementID` + ImpID int64 `json:"imp_id"` +} diff --git a/privacy/activitycontrol.go b/privacy/activitycontrol.go index 1bb3fc6cdf6..7d1e16e99a5 100644 --- a/privacy/activitycontrol.go +++ b/privacy/activitycontrol.go @@ -37,7 +37,9 @@ func (r ActivityRequest) IsBidRequest() bool { } type ActivityControl struct { - plans map[Activity]ActivityPlan + plans map[Activity]ActivityPlan + IPv6Config config.IPv6 + IPv4Config config.IPv4 } func NewActivityControl(cfg *config.AccountPrivacy) ActivityControl { @@ -58,6 +60,9 @@ func NewActivityControl(cfg *config.AccountPrivacy) ActivityControl { plans[ActivityTransmitTIDs] = buildPlan(cfg.AllowActivities.TransmitTids) ac.plans = plans + ac.IPv4Config = cfg.IPv4Config + ac.IPv6Config = cfg.IPv6Config + return ac } diff --git a/privacy/activitycontrol_test.go b/privacy/activitycontrol_test.go index b8b06ee8886..5cd9f38b011 100644 --- a/privacy/activitycontrol_test.go +++ b/privacy/activitycontrol_test.go @@ -33,17 +33,23 @@ func TestNewActivityControl(t *testing.T) { TransmitUniqueRequestIds: getTestActivityConfig(true), TransmitTids: getTestActivityConfig(true), }, + IPv6Config: config.IPv6{AnonKeepBits: 32}, + IPv4Config: config.IPv4{AnonKeepBits: 16}, + }, + activityControl: ActivityControl{ + plans: map[Activity]ActivityPlan{ + ActivitySyncUser: getTestActivityPlan(ActivityAllow), + ActivityFetchBids: getTestActivityPlan(ActivityAllow), + ActivityEnrichUserFPD: getTestActivityPlan(ActivityAllow), + ActivityReportAnalytics: getTestActivityPlan(ActivityAllow), + ActivityTransmitUserFPD: getTestActivityPlan(ActivityAllow), + ActivityTransmitPreciseGeo: getTestActivityPlan(ActivityDeny), + ActivityTransmitUniqueRequestIDs: getTestActivityPlan(ActivityAllow), + ActivityTransmitTIDs: getTestActivityPlan(ActivityAllow), + }, + IPv6Config: config.IPv6{AnonKeepBits: 32}, + IPv4Config: config.IPv4{AnonKeepBits: 16}, }, - activityControl: ActivityControl{plans: map[Activity]ActivityPlan{ - ActivitySyncUser: getTestActivityPlan(ActivityAllow), - ActivityFetchBids: getTestActivityPlan(ActivityAllow), - ActivityEnrichUserFPD: getTestActivityPlan(ActivityAllow), - ActivityReportAnalytics: getTestActivityPlan(ActivityAllow), - ActivityTransmitUserFPD: getTestActivityPlan(ActivityAllow), - ActivityTransmitPreciseGeo: getTestActivityPlan(ActivityDeny), - ActivityTransmitUniqueRequestIDs: getTestActivityPlan(ActivityAllow), - ActivityTransmitTIDs: getTestActivityPlan(ActivityAllow), - }}, }, } diff --git a/static/bidder-info/rtbhouse.yaml b/static/bidder-info/rtbhouse.yaml index b80cc0ff4f8..1f8b131678d 100644 --- a/static/bidder-info/rtbhouse.yaml +++ b/static/bidder-info/rtbhouse.yaml @@ -4,6 +4,10 @@ maintainer: endpointCompression: gzip gvlVendorID: 16 capabilities: + app: + mediaTypes: + - banner + - native site: mediaTypes: - banner diff --git a/static/bidder-info/yandex.yaml b/static/bidder-info/yandex.yaml new file mode 100644 index 00000000000..8c5be2f70d4 --- /dev/null +++ b/static/bidder-info/yandex.yaml @@ -0,0 +1,13 @@ +endpoint: "https://bs-metadsp.yandex.ru/prebid/{{.PageID}}?ssp-id=10500" +endpointCompression: gzip +maintainer: + email: "prebid@yandex-team.ru" +capabilities: + site: + mediaTypes: + - banner + - native +userSync: + redirect: + url: https://yandex.ru/an/mapuid/yandex/?ssp-id=10500&gdpr={{.GDPR}}&gdpr_consent={{.GDPRConsent}}&location={{.RedirectURL}} + userMacro: "{YANDEXUID}" diff --git a/static/bidder-params/yandex.json b/static/bidder-params/yandex.json new file mode 100644 index 00000000000..ca777077611 --- /dev/null +++ b/static/bidder-params/yandex.json @@ -0,0 +1,43 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Yandex Adapter Params", + "description": "A schema which validates params accepted by the Yandex adapter", + "type": "object", + "oneOf": [ + { + "type": "object", + "description": "Deprecated composite ad placement identifier", + "properties": { + "page_id": { + "type": "integer", + "minLength": 1, + "minimum": 1, + "description": "Special Page Id provided by Yandex Manager" + }, + "imp_id": { + "type": "integer", + "minLength": 1, + "minimum": 1, + "description": "Special identifier provided by Yandex Manager" + } + }, + "required": [ + "page_id", + "imp_id" + ] + }, + { + "type": "object", + "properties": { + "placement_id": { + "type": "string", + "description": "Ad placement identifier", + "pattern": "(\\S+-)?\\d+-\\d+" + } + }, + "required": [ + "placement_id" + ] + } + ] +} \ No newline at end of file