diff --git a/endpoints/openrtb2/auction.go b/endpoints/openrtb2/auction.go index 29f9e98ee5e..fd1803597c3 100644 --- a/endpoints/openrtb2/auction.go +++ b/endpoints/openrtb2/auction.go @@ -256,6 +256,11 @@ func (deps *endpointDeps) validateRequest(req *openrtb.BidRequest) []error { return []error{errors.New("request.imp must contain at least one element.")} } + if len(req.Cur) > 1 { + req.Cur = req.Cur[0:1] + errL = append(errL, &errortypes.Warning{Message: fmt.Sprintf("A prebid request can only process one currency. Taking the first currency in the list, %s, as the active currency", req.Cur[0])}) + } + var aliases map[string]string if bidExt, err := deps.parseBidExt(req.Ext); err != nil { return []error{err} @@ -1172,7 +1177,7 @@ func writeError(errs []error, w http.ResponseWriter, labels *pbsmetrics.Labels) func fatalError(errL []error) bool { for _, err := range errL { errCode := errortypes.DecodeError(err) - if errCode != errortypes.BidderTemporarilyDisabledCode || errCode == errortypes.BlacklistedAppCode || errCode == errortypes.BlacklistedAcctCode { + if errCode != errortypes.BidderTemporarilyDisabledCode && errCode != errortypes.WarningCode { return true } } diff --git a/endpoints/openrtb2/auction_test.go b/endpoints/openrtb2/auction_test.go index de330ed617e..4818c556661 100644 --- a/endpoints/openrtb2/auction_test.go +++ b/endpoints/openrtb2/auction_test.go @@ -865,6 +865,54 @@ func validRequest(t *testing.T, filename string) string { return string(requestData) } +func TestCurrencyTrunc(t *testing.T) { + deps := &endpointDeps{ + &nobidExchange{}, + newParamsValidator(t), + &mockStoredReqFetcher{}, + empty_fetcher.EmptyFetcher{}, + empty_fetcher.EmptyFetcher{}, + &config.Configuration{}, + pbsmetrics.NewMetrics(metrics.NewRegistry(), openrtb_ext.BidderList(), config.DisabledMetrics{}), + analyticsConf.NewPBSAnalytics(&config.Analytics{}), + map[string]string{}, + false, + []byte{}, + openrtb_ext.BidderMap, + } + + ui := uint64(1) + req := openrtb.BidRequest{ + ID: "someID", + Imp: []openrtb.Imp{ + { + ID: "imp-ID", + Banner: &openrtb.Banner{ + W: &ui, + H: &ui, + }, + Ext: json.RawMessage("{\"appnexus\": {\"placementId\": 5667}}"), + }, + }, + Site: &openrtb.Site{ + ID: "myID", + }, + Cur: []string{"USD", "EUR"}, + } + + errL := deps.validateRequest(&req) + for _, err := range errL { + if err.Error() != "A prebid request can only process one currency. Taking the first currency in the list, USD, as the active currency" { + t.Errorf(err.Error()) + } else { + if errortypes.DecodeError(err) != errortypes.WarningCode { + t.Errorf("The expected warning has the wrong error type/code") + } + } + } + assert.Len(t, req.Cur, 1) +} + // nobidExchange is a well-behaved exchange which always bids "no bid". type nobidExchange struct { gotRequest *openrtb.BidRequest diff --git a/errortypes/errortypes.go b/errortypes/errortypes.go index 731bf59df07..4bcea24f737 100644 --- a/errortypes/errortypes.go +++ b/errortypes/errortypes.go @@ -12,6 +12,7 @@ const ( BidderTemporarilyDisabledCode BlacklistedAcctCode AcctRequiredCode + WarningCode ) // We should use this code for any Error interface that is not in this package @@ -155,6 +156,20 @@ func (err *BidderTemporarilyDisabled) Code() int { return BidderTemporarilyDisabledCode } +// Warning is a generic warning type, not a serious error +type Warning struct { + Message string +} + +func (err *Warning) Error() string { + return err.Message +} + +// Code returns the error code +func (err *Warning) Code() int { + return WarningCode +} + // DecodeError provides the error code for an error, as defined above func DecodeError(err error) int { if ce, ok := err.(Coder); ok {