diff --git a/adapters/bidder.go b/adapters/bidder.go index b7bde4bc55d..dbe56f8eb91 100644 --- a/adapters/bidder.go +++ b/adapters/bidder.go @@ -139,12 +139,12 @@ func (r *RequestData) SetBasicAuth(username string, password string) { type ExtraRequestInfo struct { PbsEntryPoint metrics.RequestType GlobalPrivacyControlHeader string - currencyConversions currency.Conversions + CurrencyConversions currency.Conversions } func NewExtraRequestInfo(c currency.Conversions) ExtraRequestInfo { return ExtraRequestInfo{ - currencyConversions: c, + CurrencyConversions: c, } } @@ -153,7 +153,7 @@ func NewExtraRequestInfo(c currency.Conversions) ExtraRequestInfo { // - ConversionNotFoundError if the conversion mapping is unknown to Prebid Server // and not provided in the bid request. func (r ExtraRequestInfo) ConvertCurrency(value float64, from, to string) (float64, error) { - if rate, err := r.currencyConversions.GetRate(from, to); err == nil { + if rate, err := r.CurrencyConversions.GetRate(from, to); err == nil { return value * rate, nil } else { return 0, err diff --git a/adapters/rubicon/rubicon.go b/adapters/rubicon/rubicon.go index 84200431992..e9627916cc6 100644 --- a/adapters/rubicon/rubicon.go +++ b/adapters/rubicon/rubicon.go @@ -676,7 +676,6 @@ func (a *RubiconAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *ada numRequests := len(request.Imp) errs := make([]error, 0, len(request.Imp)) var err error - requestData := make([]*adapters.RequestData, 0, numRequests) headers := http.Header{} headers.Add("Content-Type", "application/json;charset=utf-8") @@ -750,9 +749,19 @@ func (a *RubiconAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *ada continue } - resolvedBidFloor, resolvedBidFloorCur := resolveBidFloorAttributes(thisImp.BidFloor, thisImp.BidFloorCur) - thisImp.BidFloorCur = resolvedBidFloorCur - thisImp.BidFloor = resolvedBidFloor + resolvedBidFloor, err := resolveBidFloor(thisImp.BidFloor, thisImp.BidFloorCur, reqInfo) + if err != nil { + errs = append(errs, &errortypes.BadInput{ + Message: fmt.Sprintf("Unable to convert provided bid floor currency from %s to USD", + thisImp.BidFloorCur), + }) + continue + } + + if resolvedBidFloor > 0 { + thisImp.BidFloorCur = "USD" + thisImp.BidFloor = resolvedBidFloor + } if request.User != nil { userCopy := *request.User @@ -908,15 +917,12 @@ func (a *RubiconAdapter) MakeRequests(request *openrtb2.BidRequest, reqInfo *ada return requestData, errs } -// Will be replaced after https://github.com/prebid/prebid-server/issues/1482 resolution -func resolveBidFloorAttributes(bidFloor float64, bidFloorCur string) (float64, string) { - if bidFloor > 0 { - if strings.ToUpper(bidFloorCur) == "EUR" { - return bidFloor * 1.2, "USD" - } +func resolveBidFloor(bidFloor float64, bidFloorCur string, reqInfo *adapters.ExtraRequestInfo) (float64, error) { + if bidFloor > 0 && bidFloorCur != "" && strings.ToUpper(bidFloorCur) != "USD" { + return reqInfo.ConvertCurrency(bidFloor, bidFloorCur, "USD") } - return bidFloor, bidFloorCur + return bidFloor, nil } func updateExtWithIabAttribute(target json.RawMessage, data []openrtb2.Data, segTaxes []int) (json.RawMessage, error) { diff --git a/adapters/rubicon/rubicon_test.go b/adapters/rubicon/rubicon_test.go index 76904a42137..28ddebbf5e3 100644 --- a/adapters/rubicon/rubicon_test.go +++ b/adapters/rubicon/rubicon_test.go @@ -4,6 +4,8 @@ import ( "bytes" "context" "encoding/json" + "errors" + "github.com/stretchr/testify/mock" "io/ioutil" "net/http" "net/http/httptest" @@ -572,52 +574,125 @@ func TestResolveVideoSizeId(t *testing.T) { } } -func TestResolveBidFloorAttributes(t *testing.T) { +func TestOpenRTBRequestWithDifferentBidFloorAttributes(t *testing.T) { testScenarios := []struct { - bidFloor float64 - bidFloorCur string - expectedBidFloor float64 - expectedBidFloorCur string + bidFloor float64 + bidFloorCur string + setMock func(m *mock.Mock) + expectedBidFloor float64 + expectedBidCur string + expectedErrors []error }{ { - bidFloor: 1, - bidFloorCur: "EUR", - expectedBidFloor: 1.2, - expectedBidFloorCur: "USD", + bidFloor: 1, + bidFloorCur: "WRONG", + setMock: func(m *mock.Mock) { m.On("GetRate", "WRONG", "USD").Return(2.5, errors.New("some error")) }, + expectedBidFloor: 0, + expectedBidCur: "", + expectedErrors: []error{ + &errortypes.BadInput{Message: "Unable to convert provided bid floor currency from WRONG to USD"}, + }, }, { - bidFloor: 1, - bidFloorCur: "Eur", - expectedBidFloor: 1.2, - expectedBidFloorCur: "USD", + bidFloor: 1, + bidFloorCur: "USD", + setMock: func(m *mock.Mock) {}, + expectedBidFloor: 1, + expectedBidCur: "USD", + expectedErrors: nil, }, { - bidFloor: 0, - bidFloorCur: "EUR", - expectedBidFloor: 0, - expectedBidFloorCur: "EUR", + bidFloor: 1, + bidFloorCur: "EUR", + setMock: func(m *mock.Mock) { m.On("GetRate", "EUR", "USD").Return(1.2, nil) }, + expectedBidFloor: 1.2, + expectedBidCur: "USD", + expectedErrors: nil, }, { - bidFloor: -1, - bidFloorCur: "EUR", - expectedBidFloor: -1, - expectedBidFloorCur: "EUR", + bidFloor: 0, + bidFloorCur: "", + setMock: func(m *mock.Mock) {}, + expectedBidFloor: 0, + expectedBidCur: "", + expectedErrors: nil, }, { - bidFloor: 1, - bidFloorCur: "USD", - expectedBidFloor: 1, - expectedBidFloorCur: "USD", + bidFloor: -1, + bidFloorCur: "CZK", + setMock: func(m *mock.Mock) {}, + expectedBidFloor: -1, + expectedBidCur: "CZK", + expectedErrors: nil, }, } for _, scenario := range testScenarios { - bidFloor, bidFloorCur := resolveBidFloorAttributes(scenario.bidFloor, scenario.bidFloorCur) - assert.Equal(t, scenario.expectedBidFloor, bidFloor) - assert.Equal(t, scenario.expectedBidFloorCur, bidFloorCur) + mockConversions := &mockCurrencyConversion{} + scenario.setMock(&mockConversions.Mock) + + extraRequestInfo := adapters.ExtraRequestInfo{ + CurrencyConversions: mockConversions, + } + + SIZE_ID := getTestSizes() + bidder := new(RubiconAdapter) + + request := &openrtb2.BidRequest{ + ID: "test-request-id", + Imp: []openrtb2.Imp{{ + ID: "test-imp-id", + BidFloorCur: scenario.bidFloorCur, + BidFloor: scenario.bidFloor, + Banner: &openrtb2.Banner{ + Format: []openrtb2.Format{ + SIZE_ID[15], + SIZE_ID[10], + }, + }, + Ext: json.RawMessage(`{"bidder": { + "zoneId": 8394, + "siteId": 283282, + "accountId": 7891 + }}`), + }}, + App: &openrtb2.App{ + ID: "com.test", + Name: "testApp", + }, + } + + reqs, errs := bidder.MakeRequests(request, &extraRequestInfo) + + mockConversions.AssertExpectations(t) + + if scenario.expectedErrors == nil { + rubiconReq := &openrtb2.BidRequest{} + if err := json.Unmarshal(reqs[0].Body, rubiconReq); err != nil { + t.Fatalf("Unexpected error while decoding request: %s", err) + } + assert.Equal(t, scenario.expectedBidFloor, rubiconReq.Imp[0].BidFloor) + assert.Equal(t, scenario.expectedBidCur, rubiconReq.Imp[0].BidFloorCur) + } else { + assert.Equal(t, scenario.expectedErrors, errs) + } } } +type mockCurrencyConversion struct { + mock.Mock +} + +func (m mockCurrencyConversion) GetRate(from string, to string) (float64, error) { + args := m.Called(from, to) + return args.Get(0).(float64), args.Error(1) +} + +func (m mockCurrencyConversion) GetRates() *map[string]map[string]float64 { + args := m.Called() + return args.Get(0).(*map[string]map[string]float64) +} + func TestNoContentResponse(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusNoContent) diff --git a/adapters/rubicon/rubicontest/exemplary/simple-video.json b/adapters/rubicon/rubicontest/exemplary/simple-video.json index 11afdd50d2b..1daffe9b386 100644 --- a/adapters/rubicon/rubicontest/exemplary/simple-video.json +++ b/adapters/rubicon/rubicontest/exemplary/simple-video.json @@ -120,8 +120,6 @@ "w": 1024, "h": 576 }, - "bidfloor": 1, - "bidfloorcur": "EuR", "ext": { "bidder": { "video": { @@ -298,8 +296,6 @@ "w": 1024, "h": 576 }, - "bidfloor": 1.2, - "bidfloorcur": "USD", "ext": { "rp": { "track": { diff --git a/adapters/rubicon/rubicontest/supplemental/no-site-content-data.json b/adapters/rubicon/rubicontest/supplemental/no-site-content-data.json index f67788a3154..0be214da4bc 100644 --- a/adapters/rubicon/rubicontest/supplemental/no-site-content-data.json +++ b/adapters/rubicon/rubicontest/supplemental/no-site-content-data.json @@ -85,8 +85,6 @@ "w": 1024, "h": 576 }, - "bidfloor": 1, - "bidfloorcur": "EuR", "ext": { "bidder": { "video": { @@ -221,8 +219,6 @@ "w": 1024, "h": 576 }, - "bidfloor": 1.2, - "bidfloorcur": "USD", "ext": { "rp": { "track": { diff --git a/adapters/rubicon/rubicontest/supplemental/no-site-content.json b/adapters/rubicon/rubicontest/supplemental/no-site-content.json index d3b8f8b7454..2e830a2dd00 100644 --- a/adapters/rubicon/rubicontest/supplemental/no-site-content.json +++ b/adapters/rubicon/rubicontest/supplemental/no-site-content.json @@ -83,8 +83,6 @@ "w": 1024, "h": 576 }, - "bidfloor": 1, - "bidfloorcur": "EuR", "ext": { "bidder": { "video": { @@ -217,8 +215,6 @@ "w": 1024, "h": 576 }, - "bidfloor": 1.2, - "bidfloorcur": "USD", "ext": { "rp": { "track": {