From 950b76f678adc19663919c44f0d42a5ae6179d69 Mon Sep 17 00:00:00 2001 From: Tommy Pettersen <42890605+TommyHPettersen@users.noreply.github.com> Date: Wed, 8 Jan 2025 18:59:27 +0100 Subject: [PATCH] New Adapter: Kobler (#3904) Co-authored-by: acsbendi --- adapters/kobler/kobler.go | 159 ++++++++++++++++++ adapters/kobler/kobler_test.go | 20 +++ .../koblertest/exemplary/simple_banner.json | 120 +++++++++++++ .../convert-currency-invalid-currency.json | 51 ++++++ .../supplemental/convert-currency.json | 148 ++++++++++++++++ .../correct-endpoint-when-testing.json | 130 ++++++++++++++ .../supplemental/no-bid-media-type.json | 110 ++++++++++++ .../supplemental/no-response-body.json | 69 ++++++++ .../koblertest/supplemental/status-204.json | 70 ++++++++ .../koblertest/supplemental/status-404.json | 75 +++++++++ .../wrong-response-body-type.json | 75 +++++++++ adapters/kobler/params_test.go | 51 ++++++ exchange/adapter_builders.go | 2 + openrtb_ext/bidders.go | 2 + openrtb_ext/imp_kobler.go | 5 + static/bidder-info/kobler.yaml | 12 ++ static/bidder-params/kobler.json | 13 ++ 17 files changed, 1112 insertions(+) create mode 100644 adapters/kobler/kobler.go create mode 100644 adapters/kobler/kobler_test.go create mode 100644 adapters/kobler/koblertest/exemplary/simple_banner.json create mode 100644 adapters/kobler/koblertest/supplemental/convert-currency-invalid-currency.json create mode 100644 adapters/kobler/koblertest/supplemental/convert-currency.json create mode 100644 adapters/kobler/koblertest/supplemental/correct-endpoint-when-testing.json create mode 100644 adapters/kobler/koblertest/supplemental/no-bid-media-type.json create mode 100644 adapters/kobler/koblertest/supplemental/no-response-body.json create mode 100644 adapters/kobler/koblertest/supplemental/status-204.json create mode 100644 adapters/kobler/koblertest/supplemental/status-404.json create mode 100644 adapters/kobler/koblertest/supplemental/wrong-response-body-type.json create mode 100644 adapters/kobler/params_test.go create mode 100644 openrtb_ext/imp_kobler.go create mode 100644 static/bidder-info/kobler.yaml create mode 100644 static/bidder-params/kobler.json diff --git a/adapters/kobler/kobler.go b/adapters/kobler/kobler.go new file mode 100644 index 00000000000..0a501eca46a --- /dev/null +++ b/adapters/kobler/kobler.go @@ -0,0 +1,159 @@ +package kobler + +import ( + "fmt" + "net/http" + "slices" + "strings" + + "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" + "github.com/prebid/prebid-server/v3/util/jsonutil" +) + +type adapter struct { + endpoint string + devEndpoint string +} + +const ( + devBidderEndpoint = "https://bid-service.dev.essrtb.com/bid/prebid_server_rtb_call" + supportedCurrency = "USD" +) + +func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server config.Server) (adapters.Bidder, error) { + bidder := &adapter{ + endpoint: config.Endpoint, + devEndpoint: devBidderEndpoint, + } + + return bidder, nil +} + +func (a adapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { + var requestData []*adapters.RequestData + var errors []error + + testMode := false + + if !slices.Contains(request.Cur, supportedCurrency) { + request.Cur = append(request.Cur, supportedCurrency) + } + + for i := range request.Imp { + if err := convertImpCurrency(&request.Imp[i], reqInfo); err != nil { + errors = append(errors, err) + return nil, errors + } + + // Check the first Imp for test mode, which decides the endpoint. + if i == 0 && request.Imp[i].Ext != nil { + var bidderExt adapters.ExtImpBidder + if err := jsonutil.Unmarshal(request.Imp[i].Ext, &bidderExt); err != nil { + errors = append(errors, &errortypes.BadInput{ + Message: "Error parsing bidderExt object", + }) + continue + } + + var impExt openrtb_ext.ExtImpKobler + if err := jsonutil.Unmarshal(bidderExt.Bidder, &impExt); err != nil { + errors = append(errors, &errortypes.BadInput{ + Message: "Error parsing impExt object", + }) + continue + } + + testMode = impExt.Test + } + } + + requestJSON, err := jsonutil.Marshal(request) + if err != nil { + errors = append(errors, err) + return nil, errors + } + + // Use a separate endpoint for testing purposes in the DEV environment. + // Required due to Kobler's internal test campaign setup. + endpoint := a.endpoint + if testMode { + endpoint = a.devEndpoint + } + + headers := http.Header{} + headers.Add("Content-Type", "application/json;charset=utf-8") + + requestData = append(requestData, &adapters.RequestData{ + Method: "POST", + Uri: endpoint, + Body: requestJSON, + ImpIDs: openrtb_ext.GetImpIDs(request.Imp), + Headers: headers, + }) + + return requestData, nil +} + +func (a adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.RequestData, responseData *adapters.ResponseData) (*adapters.BidderResponse, []error) { + if responseData.StatusCode == http.StatusNoContent || responseData.Body == nil { + return nil, nil + } + + if responseData.StatusCode != http.StatusOK { + return nil, []error{&errortypes.BadServerResponse{ + Message: fmt.Sprintf("Unexpected status code: %d. Run with request.debug = 1 for more info.", responseData.StatusCode), + }} + } + + var response openrtb2.BidResponse + if err := jsonutil.Unmarshal(responseData.Body, &response); err != nil { + return nil, []error{err} + } + + bidResponse := adapters.NewBidderResponseWithBidsCapacity(len(request.Imp)) + bidResponse.Currency = response.Cur + + for _, seatBid := range response.SeatBid { + for i, bid := range seatBid.Bid { + bidResponse.Bids = append(bidResponse.Bids, &adapters.TypedBid{ + Bid: &seatBid.Bid[i], + BidType: getMediaTypeForBid(bid), + }) + } + } + + return bidResponse, nil +} + +func getMediaTypeForBid(bid openrtb2.Bid) openrtb_ext.BidType { + if bid.Ext != nil { + var bidExt openrtb_ext.ExtBid + err := jsonutil.Unmarshal(bid.Ext, &bidExt) + if err == nil && bidExt.Prebid != nil { + mediaType, err := openrtb_ext.ParseBidType(string(bidExt.Prebid.Type)) + if err == nil { + return mediaType + } + } + } + + return openrtb_ext.BidTypeBanner +} + +func convertImpCurrency(imp *openrtb2.Imp, reqInfo *adapters.ExtraRequestInfo) error { + if imp.BidFloor > 0 && imp.BidFloorCur != "" && strings.ToUpper(imp.BidFloorCur) != supportedCurrency { + convertedValue, err := reqInfo.ConvertCurrency(imp.BidFloor, imp.BidFloorCur, supportedCurrency) + if err != nil { + return err + } + + imp.BidFloor = convertedValue + imp.BidFloorCur = supportedCurrency + } + + return nil +} diff --git a/adapters/kobler/kobler_test.go b/adapters/kobler/kobler_test.go new file mode 100644 index 00000000000..0cd924b8ba5 --- /dev/null +++ b/adapters/kobler/kobler_test.go @@ -0,0 +1,20 @@ +package kobler + +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.BidderKargo, config.Adapter{ + Endpoint: "http://fake.endpoint"}, config.Server{ExternalUrl: "http://hosturl.com", GvlID: 1, DataCenter: "2"}) + + if buildErr != nil { + t.Fatalf("Builder returned unexpected error %v", buildErr) + } + + adapterstest.RunJSONBidderTest(t, "koblertest", bidder) +} diff --git a/adapters/kobler/koblertest/exemplary/simple_banner.json b/adapters/kobler/koblertest/exemplary/simple_banner.json new file mode 100644 index 00000000000..cd3ca2a4084 --- /dev/null +++ b/adapters/kobler/koblertest/exemplary/simple_banner.json @@ -0,0 +1,120 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "devicetype": 2 + }, + "site": { + "page": "http://example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 320, + "h": 100 + } + ] + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://fake.endpoint", + "body": { + "id": "test-request-id", + "device": { + "devicetype": 2 + }, + "site": { + "page": "http://example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 320, + "h": 100 + } + ] + } + } + ], + "cur": ["USD"] + }, + "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": { + "prebid": { + "type": "banner" + } + } + } + ], + "seat": "kobler" + } + ], + "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", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/kobler/koblertest/supplemental/convert-currency-invalid-currency.json b/adapters/kobler/koblertest/supplemental/convert-currency-invalid-currency.json new file mode 100644 index 00000000000..d6cca2ed00d --- /dev/null +++ b/adapters/kobler/koblertest/supplemental/convert-currency-invalid-currency.json @@ -0,0 +1,51 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "devicetype": 2 + }, + "site": { + "page": "http://example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "bidfloor": 1, + "bidfloorcur": "GBP", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 320, + "h": 100 + } + ] + } + } + ], + "ext": { + "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.11 + } + }, + "usepbsrates": false + } + } + } + }, + "httpCalls": [], + "expectedBidResponses": [], + "expectedMakeRequestsErrors": [ + { + "value": "Currency conversion rate not found: 'GBP' => 'USD'", + "comparison": "literal" + } + ] +} diff --git a/adapters/kobler/koblertest/supplemental/convert-currency.json b/adapters/kobler/koblertest/supplemental/convert-currency.json new file mode 100644 index 00000000000..90561d75dcd --- /dev/null +++ b/adapters/kobler/koblertest/supplemental/convert-currency.json @@ -0,0 +1,148 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "devicetype": 2 + }, + "site": { + "page": "http://example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "bidfloor": 1, + "bidfloorcur": "EUR", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 320, + "h": 100 + } + ] + } + } + ], + "ext": { + "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.11 + } + }, + "usepbsrates": false + } + } + } + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://fake.endpoint", + "body": { + "id": "test-request-id", + "device": { + "devicetype": 2 + }, + "site": { + "page": "http://example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "bidfloor": 1.11, + "bidfloorcur": "USD", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 320, + "h": 100 + } + ] + } + } + ], + "ext": { + "prebid": { + "currency": { + "rates": { + "EUR": { + "USD": 1.11 + } + }, + "usepbsrates": false + } + } + }, + "cur": ["USD"] + }, + "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": { + "prebid": { + "type": "banner" + } + } + } + ], + "seat": "kobler" + } + ], + "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", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/kobler/koblertest/supplemental/correct-endpoint-when-testing.json b/adapters/kobler/koblertest/supplemental/correct-endpoint-when-testing.json new file mode 100644 index 00000000000..53c546d86fa --- /dev/null +++ b/adapters/kobler/koblertest/supplemental/correct-endpoint-when-testing.json @@ -0,0 +1,130 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "devicetype": 2 + }, + "site": { + "page": "http://example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 320, + "h": 100 + } + ] + }, + "ext": { + "bidder": { + "test": true + } + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "https://bid-service.dev.essrtb.com/bid/prebid_server_rtb_call", + "body": { + "id": "test-request-id", + "device": { + "devicetype": 2 + }, + "site": { + "page": "http://example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 320, + "h": 100 + } + ] + }, + "ext": { + "bidder": { + "test": true + } + } + } + ], + "cur": ["USD"] + }, + "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": { + "prebid": { + "type": "banner" + } + } + } + ], + "seat": "kobler" + } + ], + "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", + "w": 300, + "h": 250, + "ext": { + "prebid": { + "type": "banner" + } + } + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/kobler/koblertest/supplemental/no-bid-media-type.json b/adapters/kobler/koblertest/supplemental/no-bid-media-type.json new file mode 100644 index 00000000000..588345f66a1 --- /dev/null +++ b/adapters/kobler/koblertest/supplemental/no-bid-media-type.json @@ -0,0 +1,110 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "devicetype": 2 + }, + "site": { + "page": "http://example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 320, + "h": 100 + } + ] + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://fake.endpoint", + "body": { + "id": "test-request-id", + "device": { + "devicetype": 2 + }, + "site": { + "page": "http://example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 320, + "h": 100 + } + ] + } + } + ], + "cur": ["USD"] + }, + "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 + } + ], + "seat": "kobler" + } + ], + "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", + "w": 300, + "h": 250 + }, + "type": "banner" + } + ] + } + ] +} diff --git a/adapters/kobler/koblertest/supplemental/no-response-body.json b/adapters/kobler/koblertest/supplemental/no-response-body.json new file mode 100644 index 00000000000..b6d2b4dda2b --- /dev/null +++ b/adapters/kobler/koblertest/supplemental/no-response-body.json @@ -0,0 +1,69 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "devicetype": 2 + }, + "site": { + "page": "http://example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 320, + "h": 100 + } + ] + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://fake.endpoint", + "body": { + "id": "test-request-id", + "device": { + "devicetype": 2 + }, + "site": { + "page": "http://example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 320, + "h": 100 + } + ] + } + } + ], + "cur": ["USD"] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200 + } + } + ], + "expectedBidResponses": [] +} diff --git a/adapters/kobler/koblertest/supplemental/status-204.json b/adapters/kobler/koblertest/supplemental/status-204.json new file mode 100644 index 00000000000..3b26c69c14e --- /dev/null +++ b/adapters/kobler/koblertest/supplemental/status-204.json @@ -0,0 +1,70 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "devicetype": 2 + }, + "site": { + "page": "http://example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 320, + "h": 100 + } + ] + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://fake.endpoint", + "body": { + "id": "test-request-id", + "device": { + "devicetype": 2 + }, + "site": { + "page": "http://example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 320, + "h": 100 + } + ] + } + } + ], + "cur": ["USD"] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 204, + "body": {} + } + } + ], + "expectedBidResponses": [] +} diff --git a/adapters/kobler/koblertest/supplemental/status-404.json b/adapters/kobler/koblertest/supplemental/status-404.json new file mode 100644 index 00000000000..85d5db94ea7 --- /dev/null +++ b/adapters/kobler/koblertest/supplemental/status-404.json @@ -0,0 +1,75 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "devicetype": 2 + }, + "site": { + "page": "http://example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 320, + "h": 100 + } + ] + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://fake.endpoint", + "body": { + "id": "test-request-id", + "device": { + "devicetype": 2 + }, + "site": { + "page": "http://example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 320, + "h": 100 + } + ] + } + } + ], + "cur": ["USD"] + }, + "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/adapters/kobler/koblertest/supplemental/wrong-response-body-type.json b/adapters/kobler/koblertest/supplemental/wrong-response-body-type.json new file mode 100644 index 00000000000..84e4741162b --- /dev/null +++ b/adapters/kobler/koblertest/supplemental/wrong-response-body-type.json @@ -0,0 +1,75 @@ +{ + "mockBidRequest": { + "id": "test-request-id", + "device": { + "devicetype": 2 + }, + "site": { + "page": "http://example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 320, + "h": 100 + } + ] + } + } + ] + }, + "httpCalls": [ + { + "expectedRequest": { + "uri": "http://fake.endpoint", + "body": { + "id": "test-request-id", + "device": { + "devicetype": 2 + }, + "site": { + "page": "http://example.com" + }, + "imp": [ + { + "id": "test-imp-id", + "tagid": "test", + "banner": { + "format": [ + { + "w": 300, + "h": 250 + }, + { + "w": 320, + "h": 100 + } + ] + } + } + ], + "cur": ["USD"] + }, + "impIDs": ["test-imp-id"] + }, + "mockResponse": { + "status": 200, + "body": "" + } + } + ], + "expectedMakeBidsErrors": [ + { + "value": "expect { or n, but found \"", + "comparison": "literal" + } + ] +} diff --git a/adapters/kobler/params_test.go b/adapters/kobler/params_test.go new file mode 100644 index 00000000000..bc8b3ec9bf7 --- /dev/null +++ b/adapters/kobler/params_test.go @@ -0,0 +1,51 @@ +package kobler + +import ( + "encoding/json" + "testing" + + "github.com/prebid/prebid-server/v3/openrtb_ext" +) + +var validParams = []string{ + `{}`, + `{ "test": true }`, + `{ "test": false }`, +} + +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.BidderKobler, json.RawMessage(validParam)); err != nil { + t.Errorf("Schema rejected Kobler params: %s", validParam) + } + } +} + +var invalidParams = []string{ + ``, + `null`, + `true`, + `5`, + `4.2`, + `[]`, + `{ "key": 2 }`, + `{ "anyparam": "anyvalue" }`, +} + +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.BidderKrushmedia, json.RawMessage(invalidParam)); err == nil { + t.Errorf("Schema allowed unexpected params: %s", invalidParam) + } + } +} diff --git a/exchange/adapter_builders.go b/exchange/adapter_builders.go index d1d6a87fb29..477adddc5c2 100755 --- a/exchange/adapter_builders.go +++ b/exchange/adapter_builders.go @@ -121,6 +121,7 @@ import ( "github.com/prebid/prebid-server/v3/adapters/kayzen" "github.com/prebid/prebid-server/v3/adapters/kidoz" "github.com/prebid/prebid-server/v3/adapters/kiviads" + "github.com/prebid/prebid-server/v3/adapters/kobler" "github.com/prebid/prebid-server/v3/adapters/krushmedia" "github.com/prebid/prebid-server/v3/adapters/lemmadigital" "github.com/prebid/prebid-server/v3/adapters/limelightDigital" @@ -355,6 +356,7 @@ func newAdapterBuilders() map[openrtb_ext.BidderName]adapters.Builder { openrtb_ext.BidderKidoz: kidoz.Builder, openrtb_ext.BidderKiviads: kiviads.Builder, openrtb_ext.BidderLmKiviads: lmkiviads.Builder, + openrtb_ext.BidderKobler: kobler.Builder, openrtb_ext.BidderKrushmedia: krushmedia.Builder, openrtb_ext.BidderLemmadigital: lemmadigital.Builder, openrtb_ext.BidderVungle: vungle.Builder, diff --git a/openrtb_ext/bidders.go b/openrtb_ext/bidders.go index 3f6b0a67037..c0444950f1e 100644 --- a/openrtb_ext/bidders.go +++ b/openrtb_ext/bidders.go @@ -139,6 +139,7 @@ var coreBidderNames []BidderName = []BidderName{ BidderKidoz, BidderKiviads, BidderLmKiviads, + BidderKobler, BidderKrushmedia, BidderLemmadigital, BidderLimelightDigital, @@ -478,6 +479,7 @@ const ( BidderKidoz BidderName = "kidoz" BidderKiviads BidderName = "kiviads" BidderLmKiviads BidderName = "lm_kiviads" + BidderKobler BidderName = "kobler" BidderKrushmedia BidderName = "krushmedia" BidderLemmadigital BidderName = "lemmadigital" BidderLimelightDigital BidderName = "limelightDigital" diff --git a/openrtb_ext/imp_kobler.go b/openrtb_ext/imp_kobler.go new file mode 100644 index 00000000000..2ebce9d9966 --- /dev/null +++ b/openrtb_ext/imp_kobler.go @@ -0,0 +1,5 @@ +package openrtb_ext + +type ExtImpKobler struct { + Test bool `json:"test"` +} diff --git a/static/bidder-info/kobler.yaml b/static/bidder-info/kobler.yaml new file mode 100644 index 00000000000..8429aaa4bb2 --- /dev/null +++ b/static/bidder-info/kobler.yaml @@ -0,0 +1,12 @@ +endpoint: "https://bid.essrtb.com/bid/prebid_server_rtb_call" +endpointCompression: gzip +maintainer: + email: bidding-support@kobler.no +geoscope: + - NOR + - SWE + - DNK +capabilities: + site: + mediaTypes: + - banner diff --git a/static/bidder-params/kobler.json b/static/bidder-params/kobler.json new file mode 100644 index 00000000000..7e85601bfe8 --- /dev/null +++ b/static/bidder-params/kobler.json @@ -0,0 +1,13 @@ +{ + "$schema": "http://json-schema.org/draft-04/schema#", + "title": "Kobler Adapter Params", + "description": "A schema which validates params accepted by the Kobler adapter", + "type": "object", + + "properties": { + "test": { + "type": "boolean", + "description": "Whether the request is for testing only. When multiple ad units are submitted together, it is enough to set this parameter on the first one." + } + } +}