diff --git a/adapters/ortbbidder/errors.go b/adapters/ortbbidder/errors.go deleted file mode 100644 index 56fd2d8ec7a..00000000000 --- a/adapters/ortbbidder/errors.go +++ /dev/null @@ -1,32 +0,0 @@ -package ortbbidder - -import ( - "errors" - "fmt" - - "github.com/prebid/prebid-server/v2/errortypes" -) - -// list of constant errors -var ( - errImpMissing error = errors.New("imp object not found in request") - errNilBidderParamCfg error = errors.New("found nil bidderParamsConfig") -) - -func newBadInputError(message string, args ...any) error { - return &errortypes.BadServerResponse{ - Message: fmt.Sprintf(message, args...), - } -} - -func newBadServerResponseError(message string, args ...any) error { - return &errortypes.BadServerResponse{ - Message: fmt.Sprintf(message, args...), - } -} - -func newWarning(message string, args ...any) error { - return &errortypes.Warning{ - Message: fmt.Sprintf(message, args...), - } -} diff --git a/adapters/ortbbidder/multi_request_builder.go b/adapters/ortbbidder/multi_request_builder.go index 1257feb47ff..3f6a1d1f3bf 100644 --- a/adapters/ortbbidder/multi_request_builder.go +++ b/adapters/ortbbidder/multi_request_builder.go @@ -5,6 +5,7 @@ import ( "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v2/adapters" + "github.com/prebid/prebid-server/v2/adapters/ortbbidder/util" "github.com/prebid/prebid-server/v2/util/jsonutil" ) @@ -17,7 +18,7 @@ type multiRequestBuilder struct { // parseRequest parse the incoming request and populates intermediate fields required for building requestData object func (rb *multiRequestBuilder) parseRequest(request *openrtb2.BidRequest) (err error) { if len(request.Imp) == 0 { - return errImpMissing + return util.ErrImpMissing } //get rawrequests without impression objects @@ -56,7 +57,7 @@ func (rb *multiRequestBuilder) makeRequest() (requestData []*adapters.RequestDat //step 1: clone request if requestCloneRequired { if newRequest, err = cloneRequest(rb.rawRequest); err != nil { - errs = append(errs, newBadInputError(err.Error())) + errs = append(errs, util.NewBadInputError(err.Error())) continue } } @@ -67,7 +68,7 @@ func (rb *multiRequestBuilder) makeRequest() (requestData []*adapters.RequestDat //step 3: get endpoint if endpoint, err = rb.getEndpoint(bidderParams); err != nil { - errs = append(errs, newBadInputError(err.Error())) + errs = append(errs, util.NewBadInputError(err.Error())) continue } @@ -81,7 +82,7 @@ func (rb *multiRequestBuilder) makeRequest() (requestData []*adapters.RequestDat } //step 5: append new request data if requestData, err = appendRequestData(requestData, newRequest, endpoint, []string{imp[idKey].(string)}); err != nil { - errs = append(errs, newBadInputError(err.Error())) + errs = append(errs, util.NewBadInputError(err.Error())) } } return requestData, errs diff --git a/adapters/ortbbidder/multi_request_builder_test.go b/adapters/ortbbidder/multi_request_builder_test.go index 637413be8dd..37f616e33e5 100644 --- a/adapters/ortbbidder/multi_request_builder_test.go +++ b/adapters/ortbbidder/multi_request_builder_test.go @@ -10,6 +10,7 @@ import ( "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v2/adapters" "github.com/prebid/prebid-server/v2/adapters/ortbbidder/bidderparams" + "github.com/prebid/prebid-server/v2/adapters/ortbbidder/util" "github.com/stretchr/testify/assert" ) @@ -35,7 +36,7 @@ func TestMultiRequestBuilderParseRequest(t *testing.T) { }, }, want: want{ - err: errImpMissing, + err: util.ErrImpMissing, rawRequest: nil, imps: nil, }, @@ -214,7 +215,7 @@ func TestMultiRequestBuilderMakeRequest(t *testing.T) { want: want{ requestData: nil, - errs: []error{newBadInputError("failed to replace macros in endpoint, err:template: endpointTemplate:1:2: " + + errs: []error{util.NewBadInputError("failed to replace macros in endpoint, err:template: endpointTemplate:1:2: " + "executing \"endpointTemplate\" at : error calling errorFunc: intentional error")}, }, }, diff --git a/adapters/ortbbidder/ortbbidder.go b/adapters/ortbbidder/ortbbidder.go index 5008f23cdb5..df8b175c772 100644 --- a/adapters/ortbbidder/ortbbidder.go +++ b/adapters/ortbbidder/ortbbidder.go @@ -10,6 +10,7 @@ import ( "github.com/prebid/prebid-server/v2/adapters/ortbbidder/bidderparams" "github.com/prebid/prebid-server/v2/adapters/ortbbidder/util" "github.com/prebid/prebid-server/v2/config" + "github.com/prebid/prebid-server/v2/errortypes" "github.com/prebid/prebid-server/v2/openrtb_ext" "github.com/prebid/prebid-server/v2/util/jsonutil" ) @@ -62,7 +63,7 @@ func Builder(bidderName openrtb_ext.BidderName, config config.Adapter, server co // MakeRequests prepares oRTB bidder-specific request information using which prebid server make call(s) to bidder. func (o *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapters.ExtraRequestInfo) ([]*adapters.RequestData, []error) { if o.bidderParamsConfig == nil { - return nil, []error{newBadInputError(errNilBidderParamCfg.Error())} + return nil, []error{util.NewBadInputError(util.ErrNilBidderParamCfg.Error())} } requestBuilder := newRequestBuilder( @@ -72,7 +73,7 @@ func (o *adapter) MakeRequests(request *openrtb2.BidRequest, requestInfo *adapte o.bidderParamsConfig.GetRequestParams(o.bidderName.String())) if err := requestBuilder.parseRequest(request); err != nil { - return nil, []error{newBadInputError(err.Error())} + return nil, []error{util.NewBadInputError(err.Error())} } return requestBuilder.makeRequest() @@ -88,25 +89,24 @@ func (o *adapter) MakeBids(request *openrtb2.BidRequest, requestData *adapters.R return nil, []error{err} } - response, err := o.makeBids(request, responseData.Body) - if err != nil { - return nil, []error{newBadServerResponseError(err.Error())} - } - - return response, nil + return o.makeBids(request, responseData.Body) } // makeBids converts the bidderResponseBytes to a BidderResponse // It retrieves response parameters, creates a response builder, parses the response, and builds the response. // Finally, it converts the response builder's internal representation to an AdapterResponse and returns it. -func (o *adapter) makeBids(request *openrtb2.BidRequest, bidderResponseBytes json.RawMessage) (*adapters.BidderResponse, error) { +func (o *adapter) makeBids(request *openrtb2.BidRequest, bidderResponseBytes json.RawMessage) (*adapters.BidderResponse, []error) { responseParmas := o.bidderParamsConfig.GetResponseParams(o.bidderName.String()) rb := newResponseBuilder(responseParmas, request) - err := rb.setPrebidBidderResponse(bidderResponseBytes) - if err != nil { - return nil, err + errs := rb.setPrebidBidderResponse(bidderResponseBytes) + if errortypes.ContainsFatalError(errs) { + return nil, errs } - return rb.buildAdapterResponse() + bidderResponse, err := rb.buildAdapterResponse() + if err != nil { + errs = append(errs, err) + } + return bidderResponse, errs } diff --git a/adapters/ortbbidder/ortbbidder_test.go b/adapters/ortbbidder/ortbbidder_test.go index 67505e971c1..0606ec82c82 100644 --- a/adapters/ortbbidder/ortbbidder_test.go +++ b/adapters/ortbbidder/ortbbidder_test.go @@ -10,6 +10,7 @@ import ( "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v2/adapters" "github.com/prebid/prebid-server/v2/adapters/ortbbidder/bidderparams" + "github.com/prebid/prebid-server/v2/adapters/ortbbidder/util" "github.com/prebid/prebid-server/v2/config" "github.com/prebid/prebid-server/v2/errortypes" "github.com/prebid/prebid-server/v2/openrtb_ext" @@ -148,7 +149,7 @@ func TestMakeRequests(t *testing.T) { bidderCfg: bidderparams.NewBidderConfig(), }, want: want{ - errors: []error{newBadInputError(errImpMissing.Error())}, + errors: []error{util.NewBadInputError(util.ErrImpMissing.Error())}, }, }, { @@ -162,7 +163,7 @@ func TestMakeRequests(t *testing.T) { bidderCfg: nil, }, want: want{ - errors: []error{newBadInputError("found nil bidderParamsConfig")}, + errors: []error{util.NewBadInputError("found nil bidderParamsConfig")}, }, }, { diff --git a/adapters/ortbbidder/resolver/bidVideo_resolver.go b/adapters/ortbbidder/resolver/bidVideo_resolver.go index ed246153123..77dd9d83857 100644 --- a/adapters/ortbbidder/resolver/bidVideo_resolver.go +++ b/adapters/ortbbidder/resolver/bidVideo_resolver.go @@ -12,37 +12,41 @@ type bidVideoResolver struct { paramResolver } -func (b *bidVideoResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, bool) { +func (b *bidVideoResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, error) { value, found := util.GetValueFromLocation(responseNode, path) if !found { - return nil, false + return nil, nil } - return validateBidVideo(value) + video, err := validateBidVideo(value) + if err != nil { + return nil, util.NewWarning("failed to map response-param:[bidVideo] value:[%v]", value) + } + return video, nil } -func validateBidVideo(value any) (any, bool) { +func validateBidVideo(value any) (any, error) { bidVideoBytes, err := jsonutil.Marshal(value) if err != nil { - return nil, false + return nil, err } var bidVideo openrtb_ext.ExtBidPrebidVideo err = jsonutil.UnmarshalValid(bidVideoBytes, &bidVideo) if err != nil { - return nil, false + return nil, err } var bidVideoMap map[string]any err = jsonutil.UnmarshalValid(bidVideoBytes, &bidVideoMap) if err != nil { - return nil, false + return nil, err } - return bidVideoMap, true + return bidVideoMap, nil } -func (b *bidVideoResolver) setValue(adapterBid map[string]any, value any) bool { +func (b *bidVideoResolver) setValue(adapterBid map[string]any, value any) error { adapterBid[bidVideoKey] = value - return true + return nil } // bidVideoDurationResolver determines the duration of the bid based on the following hierarchy: @@ -53,24 +57,31 @@ type bidVideoDurationResolver struct { paramResolver } -func (b *bidVideoDurationResolver) getFromORTBObject(bid map[string]any) (any, bool) { - dur, ok := bid[ortbFieldDuration].(float64) - if !ok || dur == 0 { - return nil, false +func (b *bidVideoDurationResolver) getFromORTBObject(bid map[string]any) (any, error) { + value, ok := bid[ortbFieldDuration] + if !ok || value == 0 { + return nil, nil + } + duration, ok := validateNumber[int64](value) + if !ok { + return nil, util.NewWarning("failed to map response-param:[bidVideoDuration] method:[standard_oRTB_param] value:[%v]", value) } - return int64(dur), true + return duration, nil } -func (b *bidVideoDurationResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, bool) { +func (b *bidVideoDurationResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, error) { value, found := util.GetValueFromLocation(responseNode, path) if !found { - return nil, false + return nil, nil } - dur, ok := value.(float64) - return int64(dur), ok + duration, ok := validateNumber[int64](value) + if !ok { + return nil, util.NewWarning("failed to map response-param:[bidVideoDuration] method:[response_param_location] value:[%v]", value) + } + return duration, nil } -func (b *bidVideoDurationResolver) setValue(adapterBid map[string]any, value any) bool { +func (b *bidVideoDurationResolver) setValue(adapterBid map[string]any, value any) error { return setKeyValueInBidVideo(adapterBid, bidVideoDurationKey, value) } @@ -82,32 +93,46 @@ type bidVideoPrimaryCategoryResolver struct { paramResolver } -func (b *bidVideoPrimaryCategoryResolver) getFromORTBObject(bid map[string]any) (any, bool) { - cat, _ := bid[ortbFieldCategory].([]any) - if len(cat) == 0 { - return nil, false +func (b *bidVideoPrimaryCategoryResolver) getFromORTBObject(bid map[string]any) (any, error) { + value, found := bid[ortbFieldCategory] + if !found { + return nil, nil + } + + categories, ok := value.([]any) + if !ok { + return nil, util.NewWarning("failed to map response-param:[bidVideoPrimaryCategory] method:[standard_oRTB_param] value:[%v]", value) + } + + if len(categories) == 0 { + return nil, nil } - typedCat, _ := cat[0].(string) - if len(typedCat) == 0 { - return nil, false + + category, _ := categories[0].(string) + if len(category) == 0 { + return nil, util.NewWarning("failed to map response-param:[bidVideoPrimaryCategory] method:[standard_oRTB_param] value:[%v]", value) } - return typedCat, true + + return category, nil } -func (b *bidVideoPrimaryCategoryResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, bool) { +func (b *bidVideoPrimaryCategoryResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, error) { value, found := util.GetValueFromLocation(responseNode, path) if !found { - return nil, false + return nil, nil + } + category, ok := value.(string) + if !ok { + return nil, util.NewWarning("failed to map response-param:[bidVideoPrimaryCategory] method:[response_param_location] value:[%v]", value) } - cat, ok := value.(string) - return cat, ok + return category, nil } -func (b *bidVideoPrimaryCategoryResolver) setValue(adapterBid map[string]any, value any) bool { +func (b *bidVideoPrimaryCategoryResolver) setValue(adapterBid map[string]any, value any) error { return setKeyValueInBidVideo(adapterBid, bidVideoPrimaryCategoryKey, value) } -func setKeyValueInBidVideo(adapterBid map[string]any, key string, value any) bool { +func setKeyValueInBidVideo(adapterBid map[string]any, key string, value any) error { video, found := adapterBid[bidVideoKey] if !found { video = map[string]any{} @@ -115,8 +140,8 @@ func setKeyValueInBidVideo(adapterBid map[string]any, key string, value any) boo } videoTyped, ok := video.(map[string]any) if !ok || videoTyped == nil { - return false + return util.NewWarning("failed to set key:[%s] in BidVideo, value:[%v] error:[incorrect data type]", key, value) } videoTyped[key] = value - return true + return nil } diff --git a/adapters/ortbbidder/resolver/bidVideo_resolver_test.go b/adapters/ortbbidder/resolver/bidVideo_resolver_test.go index 83c1b73f181..198a4381d30 100644 --- a/adapters/ortbbidder/resolver/bidVideo_resolver_test.go +++ b/adapters/ortbbidder/resolver/bidVideo_resolver_test.go @@ -15,7 +15,7 @@ func TestBidVideoRetrieveFromLocation(t *testing.T) { responseNode map[string]any path string expectedValue any - expectedFound bool + expectedError bool }{ { name: "Found bidVideo in location", @@ -43,7 +43,7 @@ func TestBidVideoRetrieveFromLocation(t *testing.T) { "primary_category": "sport", "extra_key": "extra_value", }, - expectedFound: true, + expectedError: false, }, { name: "bidVideo found but few fields are invalid", @@ -67,7 +67,7 @@ func TestBidVideoRetrieveFromLocation(t *testing.T) { }, path: "seatbid.0.bid.0.ext.video", expectedValue: nil, - expectedFound: false, + expectedError: true, }, { name: "bidVideo not found in location", @@ -78,24 +78,24 @@ func TestBidVideoRetrieveFromLocation(t *testing.T) { }, path: "seatbid.0.bid.0.ext.video", expectedValue: nil, - expectedFound: false, + expectedError: false, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - value, found := resolver.retrieveFromBidderParamLocation(tc.responseNode, tc.path) + value, err := resolver.retrieveFromBidderParamLocation(tc.responseNode, tc.path) assert.Equal(t, tc.expectedValue, value) - assert.Equal(t, tc.expectedFound, found) + assert.Equal(t, tc.expectedError, err != nil) }) } } func TestValidateBidVideo(t *testing.T) { testCases := []struct { - name string - video any - expectedVideo any - expectedIsValid bool + name string + video any + expectedVideo any + expectedError bool }{ { name: "Valid video map", @@ -109,7 +109,7 @@ func TestValidateBidVideo(t *testing.T) { "primary_category": "sports", "extra_key": "extra_value", }, - expectedIsValid: true, + expectedError: false, }, { name: "Invalid duration type", @@ -117,8 +117,8 @@ func TestValidateBidVideo(t *testing.T) { "duration": "30", "primary_category": "sports", }, - expectedVideo: nil, - expectedIsValid: false, + expectedVideo: nil, + expectedError: true, }, { name: "Invalid primary category type", @@ -126,21 +126,21 @@ func TestValidateBidVideo(t *testing.T) { "duration": 30.0, "primary_category": 123, }, - expectedVideo: nil, - expectedIsValid: false, + expectedVideo: nil, + expectedError: true, }, { - name: "Invalid type (not a map)", - video: make(chan int), - expectedVideo: nil, - expectedIsValid: false, + name: "Invalid type (not a map)", + video: make(chan int), + expectedVideo: nil, + expectedError: true, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - validatedVideo, isValid := validateBidVideo(tc.video) + validatedVideo, err := validateBidVideo(tc.video) assert.Equal(t, tc.expectedVideo, validatedVideo) - assert.Equal(t, tc.expectedIsValid, isValid) + assert.Equal(t, tc.expectedError, err != nil) }) } } @@ -170,7 +170,7 @@ func TestBidVideoSetValue(t *testing.T) { } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - resolver.setValue(tc.adapterBid, tc.value) + _ = resolver.setValue(tc.adapterBid, tc.value) assert.Equal(t, tc.expectedAdapter, tc.adapterBid) }) } @@ -182,15 +182,21 @@ func TestBidVideoDurationGetFromORTBObject(t *testing.T) { name string responseNode map[string]any expectedValue any - expectedFound bool + expectedError bool }{ + { + name: "Not found dur in location", + responseNode: map[string]any{}, + expectedValue: nil, + expectedError: false, + }, { name: "Found dur in location", responseNode: map[string]any{ "dur": 11.0, }, expectedValue: int64(11), - expectedFound: true, + expectedError: false, }, { name: "Found dur in location but type is invalid", @@ -198,14 +204,14 @@ func TestBidVideoDurationGetFromORTBObject(t *testing.T) { "dur": "invalid", }, expectedValue: nil, - expectedFound: false, + expectedError: true, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - value, found := resolver.getFromORTBObject(tc.responseNode) + value, err := resolver.getFromORTBObject(tc.responseNode) assert.Equal(t, tc.expectedValue, value) - assert.Equal(t, tc.expectedFound, found) + assert.Equal(t, tc.expectedError, err != nil) }) } } @@ -217,7 +223,7 @@ func TestBidVideoDurarionRetrieveFromLocation(t *testing.T) { responseNode map[string]any path string expectedValue any - expectedFound bool + expectedError bool }{ { name: "Found dur in location", @@ -234,7 +240,7 @@ func TestBidVideoDurarionRetrieveFromLocation(t *testing.T) { }, path: "seatbid.0.bid.0.duration", expectedValue: int64(100), - expectedFound: true, + expectedError: false, }, { name: "Found dur in location but type is invalid", @@ -250,22 +256,22 @@ func TestBidVideoDurarionRetrieveFromLocation(t *testing.T) { }, }, path: "seatbid.0.bid.0.duration", - expectedValue: int64(0), - expectedFound: false, + expectedValue: nil, + expectedError: true, }, { name: "dur not found in location", responseNode: map[string]any{}, path: "seat", expectedValue: nil, - expectedFound: false, + expectedError: false, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - value, found := resolver.retrieveFromBidderParamLocation(tc.responseNode, tc.path) + value, err := resolver.retrieveFromBidderParamLocation(tc.responseNode, tc.path) assert.Equal(t, tc.expectedValue, value) - assert.Equal(t, tc.expectedFound, found) + assert.Equal(t, tc.expectedError, err != nil) }) } } @@ -277,7 +283,7 @@ func TestSetValueBidVideoDuration(t *testing.T) { adapterBid map[string]any value any expectedAdapter map[string]any - expectedResult bool + expectedError bool }{ { name: "Set video duration when video is absent", @@ -288,7 +294,7 @@ func TestSetValueBidVideoDuration(t *testing.T) { bidVideoDurationKey: 10, }, }, - expectedResult: true, + expectedError: false, }, { name: "Set videoduration when video is present", @@ -304,13 +310,13 @@ func TestSetValueBidVideoDuration(t *testing.T) { bidVideoPrimaryCategoryKey: "IAB-1", }, }, - expectedResult: true, + expectedError: false, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { result := resolver.setValue(tc.adapterBid, tc.value) - assert.Equal(t, tc.expectedResult, result) + assert.Equal(t, tc.expectedError, result != nil) assert.Equal(t, tc.expectedAdapter, tc.adapterBid) }) } @@ -323,7 +329,7 @@ func TestBidVideoPrimaryCategoryRetrieveFromLocation(t *testing.T) { responseNode map[string]any path string expectedValue any - expectedFound bool + expectedError bool }{ { name: "Found category in location", @@ -332,7 +338,7 @@ func TestBidVideoPrimaryCategoryRetrieveFromLocation(t *testing.T) { }, path: "cat.1", expectedValue: "IAB-2", - expectedFound: true, + expectedError: false, }, { name: "Found category in location but type is invalid", @@ -340,22 +346,22 @@ func TestBidVideoPrimaryCategoryRetrieveFromLocation(t *testing.T) { "cat": []any{"IAB-1", 100}, }, path: "cat.1", - expectedValue: "", - expectedFound: false, + expectedValue: nil, + expectedError: true, }, { name: "Category not found in location", responseNode: map[string]any{}, path: "seat", expectedValue: nil, - expectedFound: false, + expectedError: false, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - value, found := resolver.retrieveFromBidderParamLocation(tc.responseNode, tc.path) + value, err := resolver.retrieveFromBidderParamLocation(tc.responseNode, tc.path) assert.Equal(t, tc.expectedValue, value) - assert.Equal(t, tc.expectedFound, found) + assert.Equal(t, tc.expectedError, err != nil) }) } } @@ -366,7 +372,7 @@ func TestBidVideoPrimaryCategoryGetFromORTBObject(t *testing.T) { name string responseNode map[string]any expectedValue any - expectedFound bool + expectedError bool }{ { name: "Found category in location", @@ -374,7 +380,23 @@ func TestBidVideoPrimaryCategoryGetFromORTBObject(t *testing.T) { "cat": []any{"IAB-1", "IAB-2"}, }, expectedValue: "IAB-1", - expectedFound: true, + expectedError: false, + }, + { + name: "Found empty category in location", + responseNode: map[string]any{ + "cat": []any{}, + }, + expectedValue: nil, + expectedError: false, + }, + { + name: "Not found category in location", + responseNode: map[string]any{ + "field": []any{}, + }, + expectedValue: nil, + expectedError: false, }, { name: "Found category in location but type is invalid", @@ -382,7 +404,7 @@ func TestBidVideoPrimaryCategoryGetFromORTBObject(t *testing.T) { "cat": "invalid", }, expectedValue: nil, - expectedFound: false, + expectedError: true, }, { name: "Found category in location but first category type is invalid", @@ -390,14 +412,14 @@ func TestBidVideoPrimaryCategoryGetFromORTBObject(t *testing.T) { "cat": []any{1, 2}, }, expectedValue: nil, - expectedFound: false, + expectedError: true, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - value, found := resolver.getFromORTBObject(tc.responseNode) + value, err := resolver.getFromORTBObject(tc.responseNode) assert.Equal(t, tc.expectedValue, value) - assert.Equal(t, tc.expectedFound, found) + assert.Equal(t, tc.expectedError, err != nil) }) } } @@ -409,7 +431,7 @@ func TestSetValuePrimaryCategory(t *testing.T) { adapterBid map[string]any value any expectedAdapter map[string]any - expectedResult bool + expectedError bool }{ { name: "Set video key-value when video is absent", @@ -420,7 +442,7 @@ func TestSetValuePrimaryCategory(t *testing.T) { bidVideoPrimaryCategoryKey: "IAB-1", }, }, - expectedResult: true, + expectedError: false, }, { name: "Set video key-value when video is present", @@ -436,13 +458,13 @@ func TestSetValuePrimaryCategory(t *testing.T) { bidVideoPrimaryCategoryKey: "IAB-1", }, }, - expectedResult: true, + expectedError: false, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - result := resolver.setValue(tc.adapterBid, tc.value) - assert.Equal(t, tc.expectedResult, result) + err := resolver.setValue(tc.adapterBid, tc.value) + assert.Equal(t, tc.expectedError, err != nil) assert.Equal(t, tc.expectedAdapter, tc.adapterBid) }) } @@ -455,7 +477,7 @@ func TestSetKeyValueInBidVideo(t *testing.T) { key string value any expectedAdapter map[string]any - expectedResult bool + expectedError bool }{ { name: "Set video key-value when video is absent", @@ -467,7 +489,7 @@ func TestSetKeyValueInBidVideo(t *testing.T) { "duration": 30, }, }, - expectedResult: true, + expectedError: false, }, { name: "Set video key-value when video is present", @@ -481,7 +503,7 @@ func TestSetKeyValueInBidVideo(t *testing.T) { "duration": 30, }, }, - expectedResult: true, + expectedError: false, }, { name: "Override existing video key-value", @@ -497,7 +519,7 @@ func TestSetKeyValueInBidVideo(t *testing.T) { "duration": 30, }, }, - expectedResult: true, + expectedError: false, }, { name: "Invalid video type", @@ -507,13 +529,13 @@ func TestSetKeyValueInBidVideo(t *testing.T) { key: "duration", value: 30, expectedAdapter: map[string]any{"BidVideo": "invalid"}, - expectedResult: false, + expectedError: true, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - result := setKeyValueInBidVideo(tc.adapterBid, tc.key, tc.value) - assert.Equal(t, tc.expectedResult, result) + err := setKeyValueInBidVideo(tc.adapterBid, tc.key, tc.value) + assert.Equal(t, tc.expectedError, err != nil) assert.Equal(t, tc.expectedAdapter, tc.adapterBid) }) } @@ -531,5 +553,8 @@ func TestExtBidPrebidVideoFields(t *testing.T) { } structType := reflect.TypeOf(openrtb_ext.ExtBidPrebidVideo{}) - validateStructFields(t, expectedFields, structType) + err := ValidateStructFields(expectedFields, structType) + if err != nil { + t.Error(err) + } } diff --git a/adapters/ortbbidder/resolver/bidmeta_resolver.go b/adapters/ortbbidder/resolver/bidmeta_resolver.go index e0b785d2314..aa9d517dc05 100644 --- a/adapters/ortbbidder/resolver/bidmeta_resolver.go +++ b/adapters/ortbbidder/resolver/bidmeta_resolver.go @@ -12,37 +12,41 @@ type bidMetaResolver struct { paramResolver } -func (b *bidMetaResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, bool) { +func (b *bidMetaResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, error) { value, found := util.GetValueFromLocation(responseNode, path) if !found { - return nil, false + return nil, nil } - return validateBidMeta(value) + bidMeta, err := validateBidMeta(value) + if err != nil { + return nil, util.NewWarning("failed to map response-param:[bidMeta] method:[response_param_location] value:[%v]", value) + } + return bidMeta, nil } -func validateBidMeta(value any) (any, bool) { +func validateBidMeta(value any) (any, error) { bidMetaBytes, err := jsonutil.Marshal(value) if err != nil { - return nil, false + return nil, err } var bidMeta openrtb_ext.ExtBidPrebidMeta err = jsonutil.UnmarshalValid(bidMetaBytes, &bidMeta) if err != nil { - return nil, false + return nil, err } var bidMetaMap map[string]any err = jsonutil.UnmarshalValid(bidMetaBytes, &bidMetaMap) if err != nil { - return nil, false + return nil, err } - return bidMetaMap, true + return bidMetaMap, nil } -func (b *bidMetaResolver) setValue(adapterBid map[string]any, value any) bool { +func (b *bidMetaResolver) setValue(adapterBid map[string]any, value any) error { adapterBid[bidMetaKey] = value - return true + return nil } // bidMetaAdvDomainsResolver retrieves the advertiserDomains of the bid using the bidder param location. @@ -51,15 +55,20 @@ type bidMetaAdvDomainsResolver struct { paramResolver } -func (b *bidMetaAdvDomainsResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, bool) { +func (b *bidMetaAdvDomainsResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, error) { value, ok := util.GetValueFromLocation(responseNode, path) if !ok { - return nil, false + return nil, nil + } + + adomains, ok := validateDataTypeSlice[string](value) + if !ok { + return nil, util.NewWarning("failed to map response-param:[bidMetaAdvertiserDomains] method:[response_param_location] value:[%v]", value) } - return validateDataTypeSlice[string](value) + return adomains, nil } -func (b *bidMetaAdvDomainsResolver) setValue(adapterBid map[string]any, value any) bool { +func (b *bidMetaAdvDomainsResolver) setValue(adapterBid map[string]any, value any) error { return setKeyValueInBidMeta(adapterBid, bidMetaAdvertiserDomainsKey, value) } @@ -69,15 +78,19 @@ type bidMetaAdvIDResolver struct { paramResolver } -func (b *bidMetaAdvIDResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, bool) { +func (b *bidMetaAdvIDResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, error) { value, found := util.GetValueFromLocation(responseNode, path) if !found { - return nil, false + return nil, nil } - return validateNumber[int](value) + advId, ok := validateNumber[int](value) + if !ok { + return nil, util.NewWarning("failed to map response-param:[bidMetaAdvertiserId] method:[response_param_location] value:[%v]", value) + } + return advId, nil } -func (b *bidMetaAdvIDResolver) setValue(adapterBid map[string]any, value any) bool { +func (b *bidMetaAdvIDResolver) setValue(adapterBid map[string]any, value any) error { return setKeyValueInBidMeta(adapterBid, bidMetaAdvertiserIdKey, value) } @@ -87,15 +100,19 @@ type bidMetaAdvNameResolver struct { paramResolver } -func (b *bidMetaAdvNameResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, bool) { +func (b *bidMetaAdvNameResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, error) { value, found := util.GetValueFromLocation(responseNode, path) if !found { - return nil, false + return nil, nil } - return validateString(value) + advName, ok := validateString(value) + if !ok { + return nil, util.NewWarning("failed to map response-param:[bidMetaAdvertiserName] method:[response_param_location] value:[%v]", value) + } + return advName, nil } -func (b *bidMetaAdvNameResolver) setValue(adapterBid map[string]any, value any) bool { +func (b *bidMetaAdvNameResolver) setValue(adapterBid map[string]any, value any) error { return setKeyValueInBidMeta(adapterBid, bidMetaAdvertiserNameKey, value) } @@ -105,15 +122,19 @@ type bidMetaAgencyIDResolver struct { paramResolver } -func (b *bidMetaAgencyIDResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, bool) { +func (b *bidMetaAgencyIDResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, error) { value, found := util.GetValueFromLocation(responseNode, path) if !found { - return nil, false + return nil, nil + } + agencyId, ok := validateNumber[int](value) + if !ok { + return nil, util.NewWarning("failed to map response-param:[bidMetaAgencyId] method:[response_param_location] value:[%v]", value) } - return validateNumber[int](value) + return agencyId, nil } -func (b *bidMetaAgencyIDResolver) setValue(adapterBid map[string]any, value any) bool { +func (b *bidMetaAgencyIDResolver) setValue(adapterBid map[string]any, value any) error { return setKeyValueInBidMeta(adapterBid, bidMetaAgencyIdKey, value) } @@ -123,15 +144,19 @@ type bidMetaAgencyNameResolver struct { paramResolver } -func (b *bidMetaAgencyNameResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, bool) { +func (b *bidMetaAgencyNameResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, error) { value, found := util.GetValueFromLocation(responseNode, path) if !found { - return nil, false + return nil, nil + } + agencyName, ok := validateString(value) + if !ok { + return nil, util.NewWarning("failed to map response-param:[bidMetaAgencyName] method:[response_param_location] value:[%v]", value) } - return validateString(value) + return agencyName, nil } -func (b *bidMetaAgencyNameResolver) setValue(adapterBid map[string]any, value any) bool { +func (b *bidMetaAgencyNameResolver) setValue(adapterBid map[string]any, value any) error { return setKeyValueInBidMeta(adapterBid, bidMetaAgencyNameKey, value) } @@ -141,15 +166,19 @@ type bidMetaBrandIDResolver struct { paramResolver } -func (b *bidMetaBrandIDResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, bool) { +func (b *bidMetaBrandIDResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, error) { value, found := util.GetValueFromLocation(responseNode, path) if !found { - return nil, false + return nil, nil + } + brandId, ok := validateNumber[int](value) + if !ok { + return nil, util.NewWarning("failed to map response-param:[bidMetaBrandId] method:[response_param_location] value:[%v]", value) } - return validateNumber[int](value) + return brandId, nil } -func (b *bidMetaBrandIDResolver) setValue(adapterBid map[string]any, value any) bool { +func (b *bidMetaBrandIDResolver) setValue(adapterBid map[string]any, value any) error { return setKeyValueInBidMeta(adapterBid, bidMetaBrandIdKey, value) } @@ -159,15 +188,19 @@ type bidMetaBrandNameResolver struct { paramResolver } -func (b *bidMetaBrandNameResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, bool) { +func (b *bidMetaBrandNameResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, error) { value, found := util.GetValueFromLocation(responseNode, path) if !found { - return nil, false + return nil, nil } - return validateString(value) + brandName, ok := validateString(value) + if !ok { + return nil, util.NewWarning("failed to map response-param:[bidMetaBrandName] method:[response_param_location] value:[%v]", value) + } + return brandName, nil } -func (b *bidMetaBrandNameResolver) setValue(adapterBid map[string]any, value any) bool { +func (b *bidMetaBrandNameResolver) setValue(adapterBid map[string]any, value any) error { return setKeyValueInBidMeta(adapterBid, bidMetaBrandNameKey, value) } @@ -177,15 +210,19 @@ type bidMetaDChainResolver struct { paramResolver } -func (b *bidMetaDChainResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, bool) { +func (b *bidMetaDChainResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, error) { value, found := util.GetValueFromLocation(responseNode, path) if !found { - return nil, false + return nil, nil } - return validateMap(value) + dChain, ok := validateMap(value) + if !ok { + return nil, util.NewWarning("failed to map response-param:[bidMetaDchain] method:[response_param_location] value:[%v]", value) + } + return dChain, nil } -func (b *bidMetaDChainResolver) setValue(adapterBid map[string]any, value any) bool { +func (b *bidMetaDChainResolver) setValue(adapterBid map[string]any, value any) error { return setKeyValueInBidMeta(adapterBid, bidMetaDChainKey, value) } @@ -195,15 +232,19 @@ type bidMetaDemandSourceResolver struct { paramResolver } -func (b *bidMetaDemandSourceResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, bool) { +func (b *bidMetaDemandSourceResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, error) { value, found := util.GetValueFromLocation(responseNode, path) if !found { - return nil, false + return nil, nil } - return validateString(value) + demandSource, ok := validateString(value) + if !ok { + return nil, util.NewWarning("failed to map response-param:[bidMetaDemandSource] method:[response_param_location] value:[%v]", value) + } + return demandSource, nil } -func (b *bidMetaDemandSourceResolver) setValue(adapterBid map[string]any, value any) bool { +func (b *bidMetaDemandSourceResolver) setValue(adapterBid map[string]any, value any) error { return setKeyValueInBidMeta(adapterBid, bidMetaDemandSourceKey, value) } @@ -213,15 +254,19 @@ type bidMetaMediaTypeResolver struct { paramResolver } -func (b *bidMetaMediaTypeResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, bool) { +func (b *bidMetaMediaTypeResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, error) { value, found := util.GetValueFromLocation(responseNode, path) if !found { - return nil, false + return nil, nil + } + mediaType, ok := validateString(value) + if !ok { + return nil, util.NewWarning("failed to map response-param:[bidMetaMediaType] method:[response_param_location] value:[%v]", value) } - return validateString(value) + return mediaType, nil } -func (b *bidMetaMediaTypeResolver) setValue(adapterBid map[string]any, value any) bool { +func (b *bidMetaMediaTypeResolver) setValue(adapterBid map[string]any, value any) error { return setKeyValueInBidMeta(adapterBid, bidMetaMediaTypeKey, value) } @@ -231,15 +276,19 @@ type bidMetaNetworkIDResolver struct { paramResolver } -func (b *bidMetaNetworkIDResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, bool) { +func (b *bidMetaNetworkIDResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, error) { value, found := util.GetValueFromLocation(responseNode, path) if !found { - return nil, false + return nil, nil + } + networkId, ok := validateNumber[int](value) + if !ok { + return nil, util.NewWarning("failed to map response-param:[bidMetaNetworkId] method:[response_param_location] value:[%v]", value) } - return validateNumber[int](value) + return networkId, nil } -func (b *bidMetaNetworkIDResolver) setValue(adapterBid map[string]any, value any) bool { +func (b *bidMetaNetworkIDResolver) setValue(adapterBid map[string]any, value any) error { return setKeyValueInBidMeta(adapterBid, bidMetaNetworkIdKey, value) } @@ -249,15 +298,19 @@ type bidMetaNetworkNameResolver struct { paramResolver } -func (b *bidMetaNetworkNameResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, bool) { +func (b *bidMetaNetworkNameResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, error) { value, found := util.GetValueFromLocation(responseNode, path) if !found { - return nil, false + return nil, nil } - return validateString(value) + networkName, ok := validateString(value) + if !ok { + return nil, util.NewWarning("failed to map response-param:[bidMetaNetworkName] method:[response_param_location] value:[%v]", value) + } + return networkName, nil } -func (b *bidMetaNetworkNameResolver) setValue(adapterBid map[string]any, value any) bool { +func (b *bidMetaNetworkNameResolver) setValue(adapterBid map[string]any, value any) error { return setKeyValueInBidMeta(adapterBid, bidMetaNetworkNameKey, value) } @@ -267,15 +320,19 @@ type bidMetaPrimaryCategoryIDResolver struct { paramResolver } -func (b *bidMetaPrimaryCategoryIDResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, bool) { +func (b *bidMetaPrimaryCategoryIDResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, error) { value, found := util.GetValueFromLocation(responseNode, path) if !found { - return nil, false + return nil, nil } - return validateString(value) + categoryId, ok := validateString(value) + if !ok { + return nil, util.NewWarning("failed to map response-param:[bidMetaPrimaryCatId] method:[response_param_location] value:[%v]", value) + } + return categoryId, nil } -func (b *bidMetaPrimaryCategoryIDResolver) setValue(adapterBid map[string]any, value any) bool { +func (b *bidMetaPrimaryCategoryIDResolver) setValue(adapterBid map[string]any, value any) error { return setKeyValueInBidMeta(adapterBid, bidMetaPrimaryCatIdKey, value) } @@ -285,15 +342,19 @@ type bidMetaRendererNameResolver struct { paramResolver } -func (b *bidMetaRendererNameResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, bool) { +func (b *bidMetaRendererNameResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, error) { value, found := util.GetValueFromLocation(responseNode, path) if !found { - return nil, false + return nil, nil } - return validateString(value) + rendererName, ok := validateString(value) + if !ok { + return nil, util.NewWarning("failed to map response-param:[bidMetaRendererName] method:[response_param_location] value:[%v]", value) + } + return rendererName, nil } -func (b *bidMetaRendererNameResolver) setValue(adapterBid map[string]any, value any) bool { +func (b *bidMetaRendererNameResolver) setValue(adapterBid map[string]any, value any) error { return setKeyValueInBidMeta(adapterBid, bidMetaRendererNameKey, value) } @@ -303,15 +364,19 @@ type bidMetaRendererVersionResolver struct { paramResolver } -func (b *bidMetaRendererVersionResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, bool) { +func (b *bidMetaRendererVersionResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, error) { value, found := util.GetValueFromLocation(responseNode, path) if !found { - return nil, false + return nil, nil + } + rendererVersion, ok := validateString(value) + if !ok { + return nil, util.NewWarning("failed to map response-param:[bidMetaRendererVersion] method:[response_param_location] value:[%v]", value) } - return validateString(value) + return rendererVersion, nil } -func (b *bidMetaRendererVersionResolver) setValue(adapterBid map[string]any, value any) bool { +func (b *bidMetaRendererVersionResolver) setValue(adapterBid map[string]any, value any) error { return setKeyValueInBidMeta(adapterBid, bidMetaRendererVersionKey, value) } @@ -321,15 +386,19 @@ type bidMetaRendererDataResolver struct { paramResolver } -func (b *bidMetaRendererDataResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, bool) { +func (b *bidMetaRendererDataResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, error) { value, found := util.GetValueFromLocation(responseNode, path) if !found { - return nil, false + return nil, nil + } + rendererData, ok := validateMap(value) + if !ok { + return nil, util.NewWarning("failed to map response-param:[bidMetaRendererData] method:[response_param_location] value:[%v]", value) } - return validateMap(value) + return rendererData, nil } -func (b *bidMetaRendererDataResolver) setValue(adapterBid map[string]any, value any) bool { +func (b *bidMetaRendererDataResolver) setValue(adapterBid map[string]any, value any) error { return setKeyValueInBidMeta(adapterBid, bidMetaRenderedDataKey, value) } @@ -339,15 +408,19 @@ type bidMetaRendererUrlResolver struct { paramResolver } -func (b *bidMetaRendererUrlResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, bool) { +func (b *bidMetaRendererUrlResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, error) { value, found := util.GetValueFromLocation(responseNode, path) if !found { - return nil, false + return nil, nil } - return validateString(value) + rendererUrl, ok := validateString(value) + if !ok { + return nil, util.NewWarning("failed to map response-param:[bidMetaRendererUrl] method:[response_param_location] value:[%v]", value) + } + return rendererUrl, nil } -func (b *bidMetaRendererUrlResolver) setValue(adapterBid map[string]any, value any) bool { +func (b *bidMetaRendererUrlResolver) setValue(adapterBid map[string]any, value any) error { return setKeyValueInBidMeta(adapterBid, bidMetaRenderedUrlKey, value) } @@ -357,21 +430,25 @@ type bidMetaSecondaryCategoryIDsResolver struct { paramResolver } -func (b *bidMetaSecondaryCategoryIDsResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, bool) { +func (b *bidMetaSecondaryCategoryIDsResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, error) { value, found := util.GetValueFromLocation(responseNode, path) if !found { - return nil, false + return nil, nil + } + secondaryCategories, ok := validateDataTypeSlice[string](value) + if !ok { + return nil, util.NewWarning("failed to map response-param:[bidMetaSecondaryCatIds] method:[response_param_location] value:[%v]", value) } - return validateDataTypeSlice[string](value) + return secondaryCategories, nil } -func (b *bidMetaSecondaryCategoryIDsResolver) setValue(adapterBid map[string]any, value any) bool { +func (b *bidMetaSecondaryCategoryIDsResolver) setValue(adapterBid map[string]any, value any) error { return setKeyValueInBidMeta(adapterBid, bidMetaSecondaryCatIdKey, value) } // setKeyValueInBidMeta sets the key and value in bidMeta object // it creates the bidMeta object if required. -func setKeyValueInBidMeta(adapterBid map[string]any, key string, value any) bool { +func setKeyValueInBidMeta(adapterBid map[string]any, key string, value any) error { meta, found := adapterBid[bidMetaKey] if !found { meta = map[string]any{} @@ -379,8 +456,8 @@ func setKeyValueInBidMeta(adapterBid map[string]any, key string, value any) bool } typedMeta, ok := meta.(map[string]any) if !ok || typedMeta == nil { - return false + return util.NewWarning("failed to set key:[%s] in BidMeta, value:[%+v] error:[incorrect data type]", key, value) } typedMeta[key] = value - return true + return nil } diff --git a/adapters/ortbbidder/resolver/bidmeta_resolver_test.go b/adapters/ortbbidder/resolver/bidmeta_resolver_test.go index 9f887c5ba23..1a6230b91ca 100644 --- a/adapters/ortbbidder/resolver/bidmeta_resolver_test.go +++ b/adapters/ortbbidder/resolver/bidmeta_resolver_test.go @@ -15,7 +15,7 @@ func TestBidMetaRetrieveFromLocation(t *testing.T) { ortbResponse map[string]any path string expectedValue any - expectedFound bool + expectedError bool }{ { name: "Found in location", @@ -42,7 +42,7 @@ func TestBidMetaRetrieveFromLocation(t *testing.T) { "advertiserDomains": []any{"abc.com", "xyz.com"}, "brandId": 1.0, }, - expectedFound: true, + expectedError: false, }, { name: "Found invalid meta object in location", @@ -66,7 +66,7 @@ func TestBidMetaRetrieveFromLocation(t *testing.T) { }, path: "seatbid.0.bid.0.ext.metaObject", expectedValue: nil, - expectedFound: false, + expectedError: true, }, { name: "Not found in location", @@ -84,25 +84,25 @@ func TestBidMetaRetrieveFromLocation(t *testing.T) { }, path: "seatbid.0.bid.0.ext.nonexistent", expectedValue: nil, - expectedFound: false, + expectedError: false, }, } resolver := &bidMetaResolver{} for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - value, found := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) + value, err := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) assert.Equal(t, tc.expectedValue, value) - assert.Equal(t, tc.expectedFound, found) + assert.Equal(t, tc.expectedError, err != nil) }) } } func TestValidateBidMeta(t *testing.T) { tests := []struct { - name string - value any - expected any - valid bool + name string + value any + expected any + expectedError bool }{ { name: "Metadata with all valid fields", @@ -122,7 +122,7 @@ func TestValidateBidMeta(t *testing.T) { }, "customField": "customValue", }, - valid: true, + expectedError: false, }, { name: "Metadata with wrong type", @@ -130,21 +130,21 @@ func TestValidateBidMeta(t *testing.T) { bidMetaAdvertiserDomainsKey: "example.com", // should be a slice bidMetaAdvertiserIdKey: "123", // should be an float }, - expected: nil, - valid: false, + expected: nil, + expectedError: true, }, { - name: "Invalid type for value", - value: make(chan int), - expected: nil, - valid: false, + name: "Invalid type for value", + value: make(chan int), + expected: nil, + expectedError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - result, valid := validateBidMeta(tt.value) - assert.Equal(t, tt.valid, valid) + result, err := validateBidMeta(tt.value) + assert.Equal(t, tt.expectedError, err != nil) assert.Equal(t, tt.expected, result) }) } @@ -176,7 +176,7 @@ func TestBidMetaSetValue(t *testing.T) { } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - resolver.setValue(tc.typeBid, tc.value) + _ = resolver.setValue(tc.typeBid, tc.value) assert.Equal(t, tc.expectedTypeBid, tc.typeBid) }) } @@ -188,7 +188,7 @@ func TestBidMetaAdvDomainsRetrieveFromLocation(t *testing.T) { ortbResponse map[string]any path string expectedValue any - expectedFound bool + expectedError bool }{ { name: "Found in location", @@ -209,7 +209,7 @@ func TestBidMetaAdvDomainsRetrieveFromLocation(t *testing.T) { }, path: "seatbid.0.bid.0.ext.adomains", expectedValue: []string{"abc.com", "xyz.com"}, - expectedFound: true, + expectedError: false, }, { name: "Found in location but data type is invalid", @@ -229,8 +229,8 @@ func TestBidMetaAdvDomainsRetrieveFromLocation(t *testing.T) { }, }, path: "seatbid.0.bid.0.ext.adomains", - expectedValue: []string(nil), - expectedFound: false, + expectedValue: nil, + expectedError: true, }, { name: "Not found in location", @@ -248,15 +248,15 @@ func TestBidMetaAdvDomainsRetrieveFromLocation(t *testing.T) { }, path: "seatbid.0.bid.0.ext.nonexistent", expectedValue: nil, - expectedFound: false, + expectedError: false, }, } resolver := &bidMetaAdvDomainsResolver{} for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - value, found := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) + value, err := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) assert.Equal(t, tc.expectedValue, value) - assert.Equal(t, tc.expectedFound, found) + assert.Equal(t, tc.expectedError, err != nil) }) } } @@ -286,7 +286,7 @@ func TestBidMetaAdvDomainsResolverSetValue(t *testing.T) { } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - resolver.setValue(tc.typeBid, tc.value) + _ = resolver.setValue(tc.typeBid, tc.value) assert.Equal(t, tc.expectedTypeBid, tc.typeBid) }) } @@ -298,7 +298,7 @@ func TestBidMetaAdvIdRetrieveFromLocation(t *testing.T) { ortbResponse map[string]any path string expectedValue any - expectedFound bool + expectedError bool }{ { name: "Found in location", @@ -319,7 +319,7 @@ func TestBidMetaAdvIdRetrieveFromLocation(t *testing.T) { }, path: "seatbid.0.bid.0.ext.advid", expectedValue: 10, - expectedFound: true, + expectedError: false, }, { name: "Found in location but data type is other than float", @@ -339,8 +339,8 @@ func TestBidMetaAdvIdRetrieveFromLocation(t *testing.T) { }, }, path: "seatbid.0.bid.0.ext.advid", - expectedValue: 0, - expectedFound: false, + expectedValue: nil, + expectedError: true, }, { name: "Not found in location", @@ -358,15 +358,15 @@ func TestBidMetaAdvIdRetrieveFromLocation(t *testing.T) { }, path: "seatbid.0.bid.0.ext.nonexistent", expectedValue: nil, - expectedFound: false, + expectedError: false, }, } resolver := &bidMetaAdvIDResolver{} for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - value, found := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) + value, err := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) assert.Equal(t, tc.expectedValue, value) - assert.Equal(t, tc.expectedFound, found) + assert.Equal(t, tc.expectedError, err != nil) }) } } @@ -395,7 +395,7 @@ func TestBidMetaAdvIdResolverSetValue(t *testing.T) { } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - resolver.setValue(tc.typeBid, tc.value) + _ = resolver.setValue(tc.typeBid, tc.value) assert.Equal(t, tc.expectedTypeBid, tc.typeBid) }) } @@ -407,7 +407,7 @@ func TestBidMetaAdvNameRetrieveFromLocation(t *testing.T) { ortbResponse map[string]any path string expectedValue any - expectedFound bool + expectedError bool }{ { name: "Found in location", @@ -417,7 +417,7 @@ func TestBidMetaAdvNameRetrieveFromLocation(t *testing.T) { }, path: "advname", expectedValue: "Acme Corp", - expectedFound: true, + expectedError: false, }, { name: "Found in location but data type is other than string", @@ -427,8 +427,8 @@ func TestBidMetaAdvNameRetrieveFromLocation(t *testing.T) { }, }, path: "ext.advname", - expectedValue: "", - expectedFound: false, + expectedValue: nil, + expectedError: true, }, { name: "Not found in location", @@ -437,15 +437,15 @@ func TestBidMetaAdvNameRetrieveFromLocation(t *testing.T) { }, path: "seatbid.0.bid.0.ext.nonexistent", expectedValue: nil, - expectedFound: false, + expectedError: false, }, } resolver := &bidMetaAdvNameResolver{} for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - value, found := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) + value, err := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) assert.Equal(t, tc.expectedValue, value) - assert.Equal(t, tc.expectedFound, found) + assert.Equal(t, tc.expectedError, err != nil) }) } } @@ -487,7 +487,7 @@ func TestBidMetaAgencyIDRetrieveFromLocation(t *testing.T) { ortbResponse map[string]any path string expectedValue any - expectedFound bool + expectedError bool }{ { name: "Found in location", @@ -499,7 +499,7 @@ func TestBidMetaAgencyIDRetrieveFromLocation(t *testing.T) { }, path: "ext.agencyid", expectedValue: 10, - expectedFound: true, + expectedError: false, }, { name: "Found in location but data type is other than float", @@ -508,8 +508,8 @@ func TestBidMetaAgencyIDRetrieveFromLocation(t *testing.T) { "agencyid": 10, }, path: "agencyid", - expectedValue: 0, - expectedFound: false, + expectedValue: nil, + expectedError: true, }, { name: "Not found in location", @@ -519,15 +519,15 @@ func TestBidMetaAgencyIDRetrieveFromLocation(t *testing.T) { }, path: "ext.nonexistent", expectedValue: nil, - expectedFound: false, + expectedError: false, }, } resolver := &bidMetaAgencyIDResolver{} for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - value, found := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) + value, err := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) assert.Equal(t, tc.expectedValue, value) - assert.Equal(t, tc.expectedFound, found) + assert.Equal(t, tc.expectedError, err != nil) }) } } @@ -569,7 +569,7 @@ func TestBidMetaAgencyNameRetrieveFromLocation(t *testing.T) { ortbResponse map[string]any path string expectedValue any - expectedFound bool + expectedError bool }{ { name: "Found in location", @@ -581,7 +581,7 @@ func TestBidMetaAgencyNameRetrieveFromLocation(t *testing.T) { }, path: "ext.agencyName", expectedValue: "TestAgency", - expectedFound: true, + expectedError: false, }, { name: "Found in location but data type is other than string", @@ -592,22 +592,22 @@ func TestBidMetaAgencyNameRetrieveFromLocation(t *testing.T) { }, }, path: "ext.agencyName", - expectedValue: "", - expectedFound: false, + expectedValue: nil, + expectedError: true, }, { name: "Not found in location", ortbResponse: map[string]any{}, path: "ext.nonexistent", expectedValue: nil, - expectedFound: false, + expectedError: false, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - value, found := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) + value, err := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) assert.Equal(t, tc.expectedValue, value) - assert.Equal(t, tc.expectedFound, found) + assert.Equal(t, tc.expectedError, err != nil) }) } } @@ -648,7 +648,7 @@ func TestBidMetaBrandIDRetrieveFromLocation(t *testing.T) { ortbResponse map[string]any path string expectedValue any - expectedFound bool + expectedError bool }{ { name: "Found in location", @@ -669,7 +669,7 @@ func TestBidMetaBrandIDRetrieveFromLocation(t *testing.T) { }, path: "seatbid.0.bid.0.ext.brandid", expectedValue: 10, - expectedFound: true, + expectedError: false, }, { name: "Found in location but data type is other than float", @@ -689,8 +689,8 @@ func TestBidMetaBrandIDRetrieveFromLocation(t *testing.T) { }, }, path: "seatbid.0.bid.0.ext.brandid", - expectedValue: 0, - expectedFound: false, + expectedValue: nil, + expectedError: true, }, { name: "Not found in location", @@ -708,15 +708,15 @@ func TestBidMetaBrandIDRetrieveFromLocation(t *testing.T) { }, path: "seatbid.0.bid.0.ext.nonexistent", expectedValue: nil, - expectedFound: false, + expectedError: false, }, } resolver := &bidMetaBrandIDResolver{} for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - value, found := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) + value, err := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) assert.Equal(t, tc.expectedValue, value) - assert.Equal(t, tc.expectedFound, found) + assert.Equal(t, tc.expectedError, err != nil) }) } } @@ -759,7 +759,7 @@ func TestBidMetaBrandNameRetrieveFromLocation(t *testing.T) { ortbResponse map[string]any path string expectedValue any - expectedFound bool + expectedError bool }{ { name: "Found in location", @@ -771,7 +771,7 @@ func TestBidMetaBrandNameRetrieveFromLocation(t *testing.T) { }, path: "ext.brandname", expectedValue: "TestBrand", - expectedFound: true, + expectedError: false, }, { name: "Found in location but data type is other than string", @@ -782,8 +782,8 @@ func TestBidMetaBrandNameRetrieveFromLocation(t *testing.T) { }, }, path: "ext.brandname", - expectedValue: "", - expectedFound: false, + expectedValue: nil, + expectedError: true, }, { name: "Not found in location", @@ -792,14 +792,14 @@ func TestBidMetaBrandNameRetrieveFromLocation(t *testing.T) { }, path: "seatbid.0.bid.0.ext.nonexistent", expectedValue: nil, - expectedFound: false, + expectedError: false, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - value, found := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) + value, err := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) assert.Equal(t, tc.expectedValue, value) - assert.Equal(t, tc.expectedFound, found) + assert.Equal(t, tc.expectedError, err != nil) }) } } @@ -842,7 +842,7 @@ func TestBidMetaDChainRetrieveFromLocation(t *testing.T) { ortbResponse map[string]any path string expectedValue any - expectedFound bool + expectedError bool }{ { name: "Found in location", @@ -864,7 +864,7 @@ func TestBidMetaDChainRetrieveFromLocation(t *testing.T) { "t": 1, }, }, - expectedFound: true, + expectedError: false, }, { name: "Found in location but data type is other than json.RawMessage", @@ -875,23 +875,23 @@ func TestBidMetaDChainRetrieveFromLocation(t *testing.T) { }, }, path: "ext.dchain", - expectedValue: map[string]any(nil), - expectedFound: false, + expectedValue: nil, + expectedError: true, }, { name: "Not found in location", ortbResponse: map[string]any{}, path: "seatbid.0.bid.0.ext.nonexistent", expectedValue: nil, - expectedFound: false, + expectedError: false, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - value, found := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) + value, err := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) assert.Equal(t, tc.expectedValue, value) - assert.Equal(t, tc.expectedFound, found) + assert.Equal(t, tc.expectedError, err != nil) }) } } @@ -935,7 +935,7 @@ func TestBidMetaDemandSourceRetrieveFromLocation(t *testing.T) { ortbResponse map[string]any path string expectedValue any - expectedFound bool + expectedError bool }{ { name: "Found in location", @@ -956,7 +956,7 @@ func TestBidMetaDemandSourceRetrieveFromLocation(t *testing.T) { }, path: "seatbid.0.ext.demandSource", expectedValue: "Direct", - expectedFound: true, + expectedError: false, }, { name: "Found in location but data type is other than string", @@ -976,8 +976,8 @@ func TestBidMetaDemandSourceRetrieveFromLocation(t *testing.T) { }, }, path: "seatbid.0.bid.0.ext.demandSource", - expectedValue: "", - expectedFound: false, + expectedValue: nil, + expectedError: true, }, { name: "Not found in location", @@ -995,14 +995,14 @@ func TestBidMetaDemandSourceRetrieveFromLocation(t *testing.T) { }, path: "seatbid.0.bid.0.ext.nonexistent", expectedValue: nil, - expectedFound: false, + expectedError: false, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - value, found := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) + value, err := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) assert.Equal(t, tc.expectedValue, value) - assert.Equal(t, tc.expectedFound, found) + assert.Equal(t, tc.expectedError, err != nil) }) } } @@ -1044,7 +1044,7 @@ func TestBidMetaMediaTypeRetrieveFromLocation(t *testing.T) { ortbResponse map[string]any path string expectedValue any - expectedFound bool + expectedError bool }{ { name: "Found in location", @@ -1067,7 +1067,7 @@ func TestBidMetaMediaTypeRetrieveFromLocation(t *testing.T) { }, path: "seatbid.0.bid.0.ext.bidder.mediaType", expectedValue: "banner", - expectedFound: true, + expectedError: false, }, { name: "Found in location but data type is other than string", @@ -1087,8 +1087,8 @@ func TestBidMetaMediaTypeRetrieveFromLocation(t *testing.T) { }, }, path: "seatbid.0.bid.0.ext.mediaType", - expectedValue: "", - expectedFound: false, + expectedValue: nil, + expectedError: true, }, { name: "Not found in location", @@ -1106,14 +1106,14 @@ func TestBidMetaMediaTypeRetrieveFromLocation(t *testing.T) { }, path: "seatbid.0.bid.0.ext.nonexistent", expectedValue: nil, - expectedFound: false, + expectedError: false, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - value, found := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) + value, err := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) assert.Equal(t, tc.expectedValue, value) - assert.Equal(t, tc.expectedFound, found) + assert.Equal(t, tc.expectedError, err != nil) }) } } @@ -1158,7 +1158,7 @@ func TestBidMetaNetworkIDRetrieveFromLocation(t *testing.T) { ortbResponse map[string]any path string expectedValue any - expectedFound bool + expectedError bool }{ { name: "Found in location", @@ -1179,7 +1179,7 @@ func TestBidMetaNetworkIDRetrieveFromLocation(t *testing.T) { }, path: "seatbid.0.bid.0.ext.networkID", expectedValue: 100, - expectedFound: true, + expectedError: false, }, { name: "Found in location but data type is other than int", @@ -1199,8 +1199,8 @@ func TestBidMetaNetworkIDRetrieveFromLocation(t *testing.T) { }, }, path: "seatbid.0.bid.0.ext.networkID", - expectedValue: 0, - expectedFound: false, + expectedValue: nil, + expectedError: true, }, { name: "Not found in location", @@ -1210,14 +1210,14 @@ func TestBidMetaNetworkIDRetrieveFromLocation(t *testing.T) { }, path: "seatbid.0.bid.0.ext.nonexistent", expectedValue: nil, - expectedFound: false, + expectedError: false, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - value, found := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) + value, err := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) assert.Equal(t, tc.expectedValue, value) - assert.Equal(t, tc.expectedFound, found) + assert.Equal(t, tc.expectedError, err != nil) }) } } @@ -1259,7 +1259,7 @@ func TestBidMetaNetworkNameRetrieveFromLocation(t *testing.T) { ortbResponse map[string]any path string expectedValue any - expectedFound bool + expectedError bool }{ { name: "Found in location", @@ -1274,7 +1274,7 @@ func TestBidMetaNetworkNameRetrieveFromLocation(t *testing.T) { }, path: "networkName", expectedValue: "TestNetwork", - expectedFound: true, + expectedError: false, }, { name: "Found in location but data type is other than string", @@ -1288,8 +1288,8 @@ func TestBidMetaNetworkNameRetrieveFromLocation(t *testing.T) { }, }, path: "networkName", - expectedValue: "", - expectedFound: false, + expectedValue: nil, + expectedError: true, }, { name: "Not found in location", @@ -1298,14 +1298,14 @@ func TestBidMetaNetworkNameRetrieveFromLocation(t *testing.T) { }, path: "seatbid.0.bid.0.ext.nonexistent", expectedValue: nil, - expectedFound: false, + expectedError: false, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - value, found := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) + value, err := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) assert.Equal(t, tc.expectedValue, value) - assert.Equal(t, tc.expectedFound, found) + assert.Equal(t, tc.expectedError, err != nil) }) } } @@ -1347,7 +1347,7 @@ func TestBidMetaPrimaryCatIdRetrieveFromLocation(t *testing.T) { ortbResponse map[string]any path string expectedValue any - expectedFound bool + expectedError bool }{ { name: "Found in location", @@ -1357,7 +1357,7 @@ func TestBidMetaPrimaryCatIdRetrieveFromLocation(t *testing.T) { }, path: "primaryCatId", expectedValue: "testCategory", - expectedFound: true, + expectedError: false, }, { name: "Found in location but data type is other than string", @@ -1366,8 +1366,8 @@ func TestBidMetaPrimaryCatIdRetrieveFromLocation(t *testing.T) { "primaryCatId": 12345, }, path: "primaryCatId", - expectedValue: "", - expectedFound: false, + expectedValue: nil, + expectedError: true, }, { name: "Not found in location", @@ -1376,14 +1376,14 @@ func TestBidMetaPrimaryCatIdRetrieveFromLocation(t *testing.T) { }, path: "nonexistent", expectedValue: nil, - expectedFound: false, + expectedError: false, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - value, found := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) + value, err := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) assert.Equal(t, tc.expectedValue, value) - assert.Equal(t, tc.expectedFound, found) + assert.Equal(t, tc.expectedError, err != nil) }) } } @@ -1426,7 +1426,7 @@ func TestBidMetaRendererNameRetrieveFromLocation(t *testing.T) { ortbResponse map[string]any path string expectedValue any - expectedFound bool + expectedError bool }{ { name: "Found in location", @@ -1438,7 +1438,7 @@ func TestBidMetaRendererNameRetrieveFromLocation(t *testing.T) { }, path: "ext.rendererName", expectedValue: "testRenderer", - expectedFound: true, + expectedError: false, }, { name: "Found in location but data type is other than string", @@ -1449,22 +1449,22 @@ func TestBidMetaRendererNameRetrieveFromLocation(t *testing.T) { }, }, path: "ext.rendererName", - expectedValue: "", - expectedFound: false, + expectedValue: nil, + expectedError: true, }, { name: "Not found in location", ortbResponse: map[string]any{}, path: "seatbid.0.bid.0.ext.nonexistent", expectedValue: nil, - expectedFound: false, + expectedError: false, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - value, found := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) + value, err := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) assert.Equal(t, tc.expectedValue, value) - assert.Equal(t, tc.expectedFound, found) + assert.Equal(t, tc.expectedError, err != nil) }) } } @@ -1506,7 +1506,7 @@ func TestBidMetaRendererVersionRetrieveFromLocation(t *testing.T) { ortbResponse map[string]any path string expectedValue any - expectedFound bool + expectedError bool }{ { name: "Found in location", @@ -1518,7 +1518,7 @@ func TestBidMetaRendererVersionRetrieveFromLocation(t *testing.T) { }, path: "ext.rendererVersion", expectedValue: "1.0.0", - expectedFound: true, + expectedError: false, }, { name: "Found in location but data type is other than string", @@ -1529,22 +1529,22 @@ func TestBidMetaRendererVersionRetrieveFromLocation(t *testing.T) { }, }, path: "ext.rendererVersion", - expectedValue: "", - expectedFound: false, + expectedValue: nil, + expectedError: true, }, { name: "Not found in location", ortbResponse: map[string]any{}, path: "seatbid.0.bid.0.ext.nonexistent", expectedValue: nil, - expectedFound: false, + expectedError: false, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - value, found := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) + value, err := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) assert.Equal(t, tc.expectedValue, value) - assert.Equal(t, tc.expectedFound, found) + assert.Equal(t, tc.expectedError, err != nil) }) } } @@ -1586,7 +1586,7 @@ func TestBidMetaRendererDataRetrieveFromLocation(t *testing.T) { ortbResponse map[string]any path string expectedValue any - expectedFound bool + expectedError bool }{ { name: "Found in location", @@ -1598,7 +1598,7 @@ func TestBidMetaRendererDataRetrieveFromLocation(t *testing.T) { }, path: "ext.rendererData", expectedValue: map[string]any{"key": "value"}, - expectedFound: true, + expectedError: false, }, { name: "Found in location but data type is other than json.RawMessage", @@ -1609,22 +1609,22 @@ func TestBidMetaRendererDataRetrieveFromLocation(t *testing.T) { }, }, path: "ext.rendererData", - expectedValue: map[string]any(nil), - expectedFound: false, + expectedValue: nil, + expectedError: true, }, { name: "Not found in location", ortbResponse: map[string]any{}, path: "seatbid.0.bid.0.ext.nonexistent", expectedValue: nil, - expectedFound: false, + expectedError: false, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - value, found := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) + value, err := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) assert.Equal(t, tc.expectedValue, value) - assert.Equal(t, tc.expectedFound, found) + assert.Equal(t, tc.expectedError, err != nil) }) } } @@ -1666,7 +1666,7 @@ func TestBidMetaRendererUrlRetrieveFromLocation(t *testing.T) { ortbResponse map[string]any path string expectedValue any - expectedFound bool + expectedError bool }{ { name: "Found in location", @@ -1678,7 +1678,7 @@ func TestBidMetaRendererUrlRetrieveFromLocation(t *testing.T) { }, path: "ext.rendererUrl", expectedValue: "https://example.com/renderer", - expectedFound: true, + expectedError: false, }, { name: "Found in location but data type is other than string", @@ -1689,22 +1689,22 @@ func TestBidMetaRendererUrlRetrieveFromLocation(t *testing.T) { }, }, path: "ext.rendererUrl", - expectedValue: "", - expectedFound: false, + expectedValue: nil, + expectedError: true, }, { name: "Not found in location", ortbResponse: map[string]any{}, path: "seatbid.0.bid.0.ext.nonexistent", expectedValue: nil, - expectedFound: false, + expectedError: false, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - value, found := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) + value, err := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) assert.Equal(t, tc.expectedValue, value) - assert.Equal(t, tc.expectedFound, found) + assert.Equal(t, tc.expectedError, err != nil) }) } } @@ -1746,7 +1746,7 @@ func TestBidMetaSecCatIdsRetrieveFromLocation(t *testing.T) { ortbResponse map[string]any path string expectedValue any - expectedFound bool + expectedError bool }{ { name: "Found in location", @@ -1758,7 +1758,7 @@ func TestBidMetaSecCatIdsRetrieveFromLocation(t *testing.T) { }, path: "ext.secondaryCatIds", expectedValue: []string{"cat1", "cat2"}, - expectedFound: true, + expectedError: false, }, { name: "Found in location but data type is other than []string", @@ -1769,22 +1769,22 @@ func TestBidMetaSecCatIdsRetrieveFromLocation(t *testing.T) { }, }, path: "ext.secondaryCatIds", - expectedValue: []string(nil), - expectedFound: false, + expectedValue: nil, + expectedError: true, }, { name: "Not found in location", ortbResponse: map[string]any{}, path: "ext.nonexistent", expectedValue: nil, - expectedFound: false, + expectedError: false, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - value, found := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) + value, err := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) assert.Equal(t, tc.expectedValue, value) - assert.Equal(t, tc.expectedFound, found) + assert.Equal(t, tc.expectedError, err != nil) }) } } @@ -1826,7 +1826,7 @@ func TestSetKeyValueInBidMeta(t *testing.T) { key string value any expectedBid map[string]any - expectedFound bool + expectedError bool }{ { name: "Set new key-value pair when meta object is absent", @@ -1838,7 +1838,7 @@ func TestSetKeyValueInBidMeta(t *testing.T) { "testKey": "testValue", }, }, - expectedFound: true, + expectedError: false, }, { name: "Update existing key-value pair in meta object", @@ -1854,7 +1854,7 @@ func TestSetKeyValueInBidMeta(t *testing.T) { "existingKey": "newValue", }, }, - expectedFound: true, + expectedError: false, }, { name: "Fail to set value when meta object is invalid", @@ -1866,14 +1866,14 @@ func TestSetKeyValueInBidMeta(t *testing.T) { expectedBid: map[string]any{ "BidMeta": "", }, - expectedFound: false, + expectedError: true, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - found := setKeyValueInBidMeta(tt.adapterBid, tt.key, tt.value) - assert.Equal(t, tt.expectedFound, found) + err := setKeyValueInBidMeta(tt.adapterBid, tt.key, tt.value) + assert.Equal(t, tt.expectedError, err != nil) assert.Equal(t, tt.expectedBid, tt.adapterBid) }) } @@ -1906,5 +1906,8 @@ func TestExtBidPrebidMetaFields(t *testing.T) { "SecondaryCategoryIDs": reflect.TypeOf([]string{}), } structType := reflect.TypeOf(openrtb_ext.ExtBidPrebidMeta{}) - validateStructFields(t, expectedFields, structType) + err := ValidateStructFields(expectedFields, structType) + if err != nil { + t.Error(err) + } } diff --git a/adapters/ortbbidder/resolver/bidtype_resolver.go b/adapters/ortbbidder/resolver/bidtype_resolver.go index 79591093831..14aa7d98382 100644 --- a/adapters/ortbbidder/resolver/bidtype_resolver.go +++ b/adapters/ortbbidder/resolver/bidtype_resolver.go @@ -22,43 +22,51 @@ type bidTypeResolver struct { paramResolver } -func (r *bidTypeResolver) getFromORTBObject(bid map[string]any) (any, bool) { - mtype, ok := bid[ortbFieldMtype].(float64) +func (r *bidTypeResolver) getFromORTBObject(bid map[string]any) (any, error) { + value, ok := bid[ortbFieldMtype] + if !ok { + return nil, nil + } + + mtype, ok := value.(float64) if !ok || mtype == 0 { - return nil, false + return nil, util.NewWarning("failed to map response-param:[bidType] method:[standard_oRTB_param] value:[%v]", value) } if bidType := convertToBidType(openrtb2.MarkupType(mtype)); bidType != openrtb_ext.BidType("") { - return bidType, true + return bidType, nil } - return nil, false + return nil, util.NewWarning("failed to map response-param:[bidType] method:[standard_oRTB_param] value:[%v]", value) } -func (r *bidTypeResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, bool) { +func (r *bidTypeResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, error) { value, found := util.GetValueFromLocation(responseNode, path) if !found { - return nil, false + return nil, nil } bidType, ok := value.(string) - return openrtb_ext.BidType(bidType), ok + if !ok { + return nil, util.NewWarning("failed to map response-param:[bidType] method:[response_param_location] value:[%v]", value) + } + return openrtb_ext.BidType(bidType), nil } -func (r *bidTypeResolver) autoDetect(request *openrtb2.BidRequest, bid map[string]any) (any, bool) { +func (r *bidTypeResolver) autoDetect(request *openrtb2.BidRequest, bid map[string]any) (any, error) { adm, ok := bid[ortbFieldAdM].(string) if ok && adm != "" { - return getMediaTypeFromAdm(adm), true // Adm is present, get media type from adm + return getMediaTypeFromAdm(adm), nil // Adm is present, get media type from adm } impId, ok := bid[ortbFieldImpId].(string) if !ok { - return nil, false + return nil, util.ErrBidTypeMissingImpID } // Adm is not present, get media type from imp - return getMediaTypeFromImp(request.Imp, impId), true + return getMediaTypeFromImp(request.Imp, impId), nil } -func (r *bidTypeResolver) setValue(adapterBid map[string]any, value any) bool { +func (r *bidTypeResolver) setValue(adapterBid map[string]any, value any) error { adapterBid[bidTypeKey] = value - return true + return nil } func getMediaTypeFromAdm(adm string) openrtb_ext.BidType { diff --git a/adapters/ortbbidder/resolver/bidtype_resolver_test.go b/adapters/ortbbidder/resolver/bidtype_resolver_test.go index 1263b30992a..ca267ac810b 100644 --- a/adapters/ortbbidder/resolver/bidtype_resolver_test.go +++ b/adapters/ortbbidder/resolver/bidtype_resolver_test.go @@ -16,7 +16,7 @@ func TestBidtypeResolverGetFromORTBObject(t *testing.T) { name string bid map[string]any expectedValue any - expectedFound bool + expectedError bool }{ { name: "mtype found in bid", @@ -24,7 +24,7 @@ func TestBidtypeResolverGetFromORTBObject(t *testing.T) { "mtype": 2.0, }, expectedValue: openrtb_ext.BidTypeVideo, - expectedFound: true, + expectedError: false, }, { name: "mtype found in bid - invalid type", @@ -32,7 +32,7 @@ func TestBidtypeResolverGetFromORTBObject(t *testing.T) { "mtype": "vide0", }, expectedValue: nil, - expectedFound: false, + expectedError: true, }, { name: "mtype found in bid - invalid value", @@ -40,21 +40,21 @@ func TestBidtypeResolverGetFromORTBObject(t *testing.T) { "mtype": 11.0, }, expectedValue: nil, - expectedFound: false, + expectedError: true, }, { name: "mtype not found in bid", bid: map[string]any{}, expectedValue: nil, - expectedFound: false, + expectedError: false, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - value, found := resolver.getFromORTBObject(tc.bid) + value, err := resolver.getFromORTBObject(tc.bid) assert.Equal(t, tc.expectedValue, value) - assert.Equal(t, tc.expectedFound, found) + assert.Equal(t, tc.expectedError, err != nil) }) } }) @@ -67,7 +67,7 @@ func TestBidTypeResolverRetrieveFromBidderParamLocation(t *testing.T) { ortbResponse map[string]any path string expectedValue any - expectedFound bool + expectedError bool }{ { name: "Found in location", @@ -88,7 +88,7 @@ func TestBidTypeResolverRetrieveFromBidderParamLocation(t *testing.T) { }, path: "seatbid.0.bid.0.ext.mtype", expectedValue: openrtb_ext.BidType("video"), - expectedFound: true, + expectedError: false, }, { name: "Found invalid bidtype in location", @@ -108,8 +108,8 @@ func TestBidTypeResolverRetrieveFromBidderParamLocation(t *testing.T) { }, }, path: "seatbid.0.bid.0.ext.mtype", - expectedValue: openrtb_ext.BidType(""), - expectedFound: false, + expectedValue: nil, + expectedError: true, }, { name: "Not found in location", @@ -130,15 +130,15 @@ func TestBidTypeResolverRetrieveFromBidderParamLocation(t *testing.T) { }, path: "seatbid.0.bid.0.ext.nonexistent", expectedValue: nil, - expectedFound: false, + expectedError: false, }, } resolver := &bidTypeResolver{} for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - value, found := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) + value, err := resolver.retrieveFromBidderParamLocation(tc.ortbResponse, tc.path) assert.Equal(t, tc.expectedValue, value) - assert.Equal(t, tc.expectedFound, found) + assert.Equal(t, tc.expectedError, err != nil) }) } } @@ -152,7 +152,7 @@ func TestBidTypeResolverAutoDetect(t *testing.T) { bid map[string]any request *openrtb2.BidRequest expectedValue any - expectedFound bool + expectedError bool }{ { name: "Auto detect from imp - Video", @@ -169,7 +169,7 @@ func TestBidTypeResolverAutoDetect(t *testing.T) { }, }, expectedValue: openrtb_ext.BidTypeVideo, - expectedFound: true, + expectedError: false, }, { name: "Auto detect from imp - banner", @@ -186,7 +186,7 @@ func TestBidTypeResolverAutoDetect(t *testing.T) { }, }, expectedValue: openrtb_ext.BidTypeBanner, - expectedFound: true, + expectedError: false, }, { name: "Auto detect from imp - native", @@ -203,7 +203,7 @@ func TestBidTypeResolverAutoDetect(t *testing.T) { }, }, expectedValue: openrtb_ext.BidTypeNative, - expectedFound: true, + expectedError: false, }, { name: "Auto detect from imp - multi format", @@ -221,7 +221,7 @@ func TestBidTypeResolverAutoDetect(t *testing.T) { }, }, expectedValue: openrtb_ext.BidType(""), - expectedFound: true, + expectedError: false, }, { name: "Auto detect with Video Adm", @@ -229,7 +229,7 @@ func TestBidTypeResolverAutoDetect(t *testing.T) { "adm": "", }, expectedValue: openrtb_ext.BidTypeVideo, - expectedFound: true, + expectedError: false, }, { name: "Auto detect with Native Adm", @@ -237,7 +237,7 @@ func TestBidTypeResolverAutoDetect(t *testing.T) { "adm": "{\"native\":{\"link\":{},\"assets\":[]}}", }, expectedValue: openrtb_ext.BidTypeNative, - expectedFound: true, + expectedError: false, }, { name: "Auto detect with Banner Adm", @@ -245,13 +245,13 @@ func TestBidTypeResolverAutoDetect(t *testing.T) { "adm": "
Some HTML content
", }, expectedValue: openrtb_ext.BidTypeBanner, - expectedFound: true, + expectedError: false, }, { name: "Auto detect with no Adm", bid: map[string]any{}, expectedValue: nil, - expectedFound: false, + expectedError: true, }, { name: "Auto detect with empty Adm", @@ -259,14 +259,14 @@ func TestBidTypeResolverAutoDetect(t *testing.T) { "adm": "", }, expectedValue: nil, - expectedFound: false, + expectedError: true, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - value, found := resolver.autoDetect(tc.request, tc.bid) + value, err := resolver.autoDetect(tc.request, tc.bid) assert.Equal(t, tc.expectedValue, value) - assert.Equal(t, tc.expectedFound, found) + assert.Equal(t, tc.expectedError, err != nil) }) } }) diff --git a/adapters/ortbbidder/resolver/dealPriority_resolver.go b/adapters/ortbbidder/resolver/dealPriority_resolver.go index 8f7bc442b76..4db79f8f1fd 100644 --- a/adapters/ortbbidder/resolver/dealPriority_resolver.go +++ b/adapters/ortbbidder/resolver/dealPriority_resolver.go @@ -1,6 +1,8 @@ package resolver -import "github.com/prebid/prebid-server/v2/adapters/ortbbidder/util" +import ( + "github.com/prebid/prebid-server/v2/adapters/ortbbidder/util" +) // bidDealPriorityResolver retrieves the priority of the deal bid using the bidder param location. // The determined dealPriority is subsequently assigned to adapterresponse.typedbid.dealPriority @@ -8,15 +10,19 @@ type bidDealPriorityResolver struct { paramResolver } -func (b *bidDealPriorityResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, bool) { +func (b *bidDealPriorityResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, error) { value, found := util.GetValueFromLocation(responseNode, path) if !found { - return nil, false + return nil, nil } - return validateNumber[int](value) + val, ok := validateNumber[int](value) + if !ok { + return nil, util.NewWarning("failed to map response-param:[bidDealPriority] value:[%v]", value) + } + return val, nil } -func (b *bidDealPriorityResolver) setValue(adapterBid map[string]any, value any) bool { +func (b *bidDealPriorityResolver) setValue(adapterBid map[string]any, value any) (err error) { adapterBid[bidDealPriorityKey] = value - return true + return } diff --git a/adapters/ortbbidder/resolver/dealPriority_resolver_test.go b/adapters/ortbbidder/resolver/dealPriority_resolver_test.go index 3321dbe59b3..93021a96989 100644 --- a/adapters/ortbbidder/resolver/dealPriority_resolver_test.go +++ b/adapters/ortbbidder/resolver/dealPriority_resolver_test.go @@ -13,7 +13,7 @@ func TestBidDealPriorityFromLocation(t *testing.T) { responseNode map[string]any path string expectedValue any - expectedFound bool + expectedError bool }{ { name: "Found dealPriority in location", @@ -23,7 +23,7 @@ func TestBidDealPriorityFromLocation(t *testing.T) { }, path: "dp", expectedValue: 10, - expectedFound: true, + expectedError: false, }, { name: "Found invalid dealPriority in location", @@ -32,22 +32,22 @@ func TestBidDealPriorityFromLocation(t *testing.T) { "dp": "invalid", }, path: "dp", - expectedValue: 0, - expectedFound: false, + expectedValue: nil, + expectedError: true, }, { name: "Not found dealPriority in location", responseNode: map[string]any{}, path: "seat", expectedValue: nil, - expectedFound: false, + expectedError: false, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - value, found := resolver.retrieveFromBidderParamLocation(tc.responseNode, tc.path) + value, err := resolver.retrieveFromBidderParamLocation(tc.responseNode, tc.path) assert.Equal(t, tc.expectedValue, value) - assert.Equal(t, tc.expectedFound, found) + assert.Equal(t, tc.expectedError, err != nil) }) } } diff --git a/adapters/ortbbidder/resolver/fledgeconfig_resolver.go b/adapters/ortbbidder/resolver/fledgeconfig_resolver.go index 07570dd1025..d5086050001 100644 --- a/adapters/ortbbidder/resolver/fledgeconfig_resolver.go +++ b/adapters/ortbbidder/resolver/fledgeconfig_resolver.go @@ -12,29 +12,34 @@ type fledgeResolver struct { paramResolver } -func (f *fledgeResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, bool) { +func (f *fledgeResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, error) { value, found := util.GetValueFromLocation(responseNode, path) if !found { - return nil, false + return nil, nil } - return validateFledgeConfig(value) + fledgeCfg, err := validateFledgeConfig(value) + if err != nil { + return nil, util.NewWarning("failed to map response-param:[fledgeAuctionConfig] value:[%+v]", value) + } + return fledgeCfg, nil } -func validateFledgeConfig(value any) (any, bool) { +func validateFledgeConfig(value any) (any, error) { fledgeCfgBytes, err := jsonutil.Marshal(value) if err != nil { - return nil, false + return nil, err } var fledgeCfg []*openrtb_ext.FledgeAuctionConfig err = jsonutil.UnmarshalValid(fledgeCfgBytes, &fledgeCfg) if err != nil { - return nil, false + return nil, err } - return fledgeCfg, len(fledgeCfg) != 0 + + return fledgeCfg, nil } -func (f *fledgeResolver) setValue(adapterBid map[string]any, value any) bool { +func (f *fledgeResolver) setValue(adapterBid map[string]any, value any) error { adapterBid[fledgeAuctionConfigKey] = value - return true + return nil } diff --git a/adapters/ortbbidder/resolver/fledgeconfig_resolver_test.go b/adapters/ortbbidder/resolver/fledgeconfig_resolver_test.go index a04ef30a113..add31b9e9c8 100644 --- a/adapters/ortbbidder/resolver/fledgeconfig_resolver_test.go +++ b/adapters/ortbbidder/resolver/fledgeconfig_resolver_test.go @@ -4,6 +4,7 @@ import ( "encoding/json" "testing" + "github.com/prebid/prebid-server/v2/adapters/ortbbidder/util" "github.com/prebid/prebid-server/v2/openrtb_ext" "github.com/stretchr/testify/assert" ) @@ -15,7 +16,7 @@ func TestFledgeConfigRetrieveFromLocation(t *testing.T) { responseNode map[string]any path string expectedValue any - expectedFound bool + expectedError error }{ { name: "Found fledgeConfig in location", @@ -41,7 +42,7 @@ func TestFledgeConfigRetrieveFromLocation(t *testing.T) { Config: json.RawMessage(`{"key":"value"}`), }, }, - expectedFound: true, + expectedError: nil, }, { name: "Found invalid fledgeConfig in location", @@ -61,31 +62,31 @@ func TestFledgeConfigRetrieveFromLocation(t *testing.T) { }, path: "ext.fledgeCfg", expectedValue: nil, - expectedFound: false, + expectedError: util.NewWarning("failed to map response-param:[fledgeAuctionConfig] value:[[map[bidder:magnite config:map[key:value] impid:1]]]"), }, { name: "Not found fledge config in location", responseNode: map[string]any{}, path: "seat", expectedValue: nil, - expectedFound: false, + expectedError: nil, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - value, found := resolver.retrieveFromBidderParamLocation(tc.responseNode, tc.path) + value, err := resolver.retrieveFromBidderParamLocation(tc.responseNode, tc.path) assert.Equal(t, tc.expectedValue, value) - assert.Equal(t, tc.expectedFound, found) + assert.Equal(t, tc.expectedError, err) }) } } func TestValidateFledgeConfigs(t *testing.T) { testCases := []struct { - name string - input any - expectedOutput any - expectedValidation bool + name string + input any + expectedOutput any + expectedError bool }{ { name: "Valid fledge configs", @@ -108,7 +109,7 @@ func TestValidateFledgeConfigs(t *testing.T) { Config: json.RawMessage(`{"key1":"value1","key2":"value2"}`), }, }, - expectedValidation: true, + expectedError: false, }, { name: "Invalid fledge config with non-map entry", @@ -124,27 +125,27 @@ func TestValidateFledgeConfigs(t *testing.T) { }, "invalidEntry", }, - expectedOutput: nil, - expectedValidation: false, + expectedOutput: nil, + expectedError: true, }, { - name: "nil fledge configs", - input: nil, - expectedOutput: []*openrtb_ext.FledgeAuctionConfig(nil), - expectedValidation: false, + name: "nil fledge configs", + input: nil, + expectedOutput: []*openrtb_ext.FledgeAuctionConfig(nil), + expectedError: false, }, { - name: "Non-slice input", - input: make(chan int), - expectedOutput: nil, - expectedValidation: false, + name: "Non-slice input", + input: make(chan int), + expectedOutput: nil, + expectedError: true, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - output, valid := validateFledgeConfig(tc.input) + output, err := validateFledgeConfig(tc.input) assert.Equal(t, tc.expectedOutput, output) - assert.Equal(t, tc.expectedValidation, valid) + assert.Equal(t, tc.expectedError, err != nil) }) } } diff --git a/adapters/ortbbidder/resolver/param_resolver.go b/adapters/ortbbidder/resolver/param_resolver.go index e5e0fb8536a..73b08da826a 100644 --- a/adapters/ortbbidder/resolver/param_resolver.go +++ b/adapters/ortbbidder/resolver/param_resolver.go @@ -9,6 +9,7 @@ var ( fledgeAuctionConfig: &fledgeResolver{}, bidType: &bidTypeResolver{}, bidDealPriority: &bidDealPriorityResolver{}, + bidVideo: &bidVideoResolver{}, bidVideoDuration: &bidVideoDurationResolver{}, bidVideoPrimaryCategory: &bidVideoPrimaryCategoryResolver{}, bidMeta: &bidMetaResolver{}, @@ -34,10 +35,10 @@ var ( ) type resolver interface { - getFromORTBObject(sourceNode map[string]any) (any, bool) - retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, bool) - autoDetect(request *openrtb2.BidRequest, sourceNode map[string]any) (any, bool) - setValue(targetNode map[string]any, value any) bool + getFromORTBObject(sourceNode map[string]any) (any, error) + retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, error) + autoDetect(request *openrtb2.BidRequest, sourceNode map[string]any) (any, error) + setValue(targetNode map[string]any, value any) error } type resolverMap map[parameter]resolver @@ -55,16 +56,16 @@ func New(request *openrtb2.BidRequest, bidderResponse map[string]any) *paramReso } } -func (r *paramResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, bool) { - return nil, false +func (r *paramResolver) retrieveFromBidderParamLocation(responseNode map[string]any, path string) (any, error) { + return nil, nil } -func (r *paramResolver) getFromORTBObject(bid map[string]any) (any, bool) { - return nil, false +func (r *paramResolver) getFromORTBObject(bid map[string]any) (any, error) { + return nil, nil } -func (r *paramResolver) autoDetect(request *openrtb2.BidRequest, bid map[string]any) (any, bool) { - return nil, false +func (r *paramResolver) autoDetect(request *openrtb2.BidRequest, bid map[string]any) (any, error) { + return nil, nil } // Resolve fetches a parameter value from sourceNode or bidderResponse and sets it in targetNode. @@ -73,30 +74,44 @@ func (r *paramResolver) autoDetect(request *openrtb2.BidRequest, bid map[string] // 2) Location from JSON file (bidder params) // 3) Auto-detection // If the value is found, it is set in the targetNode. -func (pr *paramResolver) Resolve(sourceNode, targetNode map[string]any, path string, param parameter) bool { +func (pr *paramResolver) Resolve(sourceNode, targetNode map[string]any, path string, param parameter) (errs []error) { if sourceNode == nil || targetNode == nil || pr.bidderResponse == nil { - return false + return } resolver, ok := resolvers[param] if !ok { - return false + return } - // get the value from the ORTB object - value, found := resolver.getFromORTBObject(sourceNode) - if !found { - // get the value from the bidder response using the location - value, found = resolver.retrieveFromBidderParamLocation(pr.bidderResponse, path) - if !found { - // auto detect value - value, found = resolver.autoDetect(pr.request, sourceNode) - if !found { - return false - } + value, err := resolver.getFromORTBObject(sourceNode) // get the value from the ORTB object + if err != nil { + errs = append(errs, err) + } + + if value == nil { + value, err = resolver.retrieveFromBidderParamLocation(pr.bidderResponse, path) // get the value from the bidder response using the location + if err != nil { + errs = append(errs, err) + } + } + + if value == nil { + value, err = resolver.autoDetect(pr.request, sourceNode) // auto detect value + if err != nil { + errs = append(errs, err) } } - return resolver.setValue(targetNode, value) + // return if value not found + if value == nil { + return errs + } + + err = resolver.setValue(targetNode, value) + if err != nil { + errs = append(errs, err) + } + return errs } // list of parameters to be resolved at typedBid level. diff --git a/adapters/ortbbidder/resolver/param_resolver_test.go b/adapters/ortbbidder/resolver/param_resolver_test.go index 29dba2b61e7..d26bb8d565d 100644 --- a/adapters/ortbbidder/resolver/param_resolver_test.go +++ b/adapters/ortbbidder/resolver/param_resolver_test.go @@ -4,6 +4,7 @@ import ( "testing" "github.com/prebid/openrtb/v20/openrtb2" + "github.com/prebid/prebid-server/v2/adapters/ortbbidder/util" "github.com/prebid/prebid-server/v2/openrtb_ext" "github.com/stretchr/testify/assert" ) @@ -17,6 +18,7 @@ func TestResolveTypeBid(t *testing.T) { location string paramName parameter expectedTypeBid map[string]any + expectedErrs []error request *openrtb2.BidRequest }{ { @@ -95,7 +97,7 @@ func TestResolveTypeBid(t *testing.T) { }, }, { - name: "Get paramName from the ortb bid object", + name: "Get param from the ortb bid object", bid: map[string]any{ "id": "123", "mtype": float64(2), @@ -130,7 +132,48 @@ func TestResolveTypeBid(t *testing.T) { }, }, { - name: "Get paramName from the bidder paramName location", + name: "fail to get param from the ortb bid object, fallback to get from bidder param location", + bid: map[string]any{ + "id": "123", + "mtype": float64(0), + }, + typeBid: map[string]any{ + "Bid": map[string]any{ + "id": "123", + "mtype": float64(0), + }, + }, + bidderResponse: map[string]any{ + "cur": "USD", + "seatbid": []any{ + map[string]any{ + "bid": []any{ + map[string]any{ + "id": "123", + "mtype": float64(0), + "ext": map[string]any{ + "bidtype": "banner", + }, + }, + }, + }, + }, + }, + location: "seatbid.0.bid.0.ext.bidtype", + paramName: "bidType", + expectedTypeBid: map[string]any{ + "Bid": map[string]any{ + "id": "123", + "mtype": float64(0), + }, + "BidType": openrtb_ext.BidType("banner"), + }, + expectedErrs: []error{ + util.NewWarning("failed to map response-param:[bidType] method:[standard_oRTB_param] value:[0]"), + }, + }, + { + name: "Get param from the bidder paramName location", bid: map[string]any{ "id": "123", "ext": map[string]any{ @@ -172,6 +215,45 @@ func TestResolveTypeBid(t *testing.T) { "BidType": openrtb_ext.BidType("video"), }, }, + { + name: "fail to detect from location, fallback to Auto detect", + bid: map[string]any{ + "id": "123", + "adm": "", + }, + typeBid: map[string]any{ + "Bid": map[string]any{ + "id": "123", + "adm": "", + }, + }, + bidderResponse: map[string]any{ + "cur": "USD", + "bidtype": 1, + "seatbid": []any{ + map[string]any{ + "bid": []any{ + map[string]any{ + "id": "123", + "adm": "", + }, + }, + }, + }, + }, + location: "bidtype", + paramName: "bidType", + expectedTypeBid: map[string]any{ + "Bid": map[string]any{ + "id": "123", + "adm": "", + }, + "BidType": openrtb_ext.BidType("video"), + }, + expectedErrs: []error{ + util.NewWarning("failed to map response-param:[bidType] method:[response_param_location] value:[1]"), + }, + }, { name: "Auto detect", bid: map[string]any{ @@ -236,13 +318,17 @@ func TestResolveTypeBid(t *testing.T) { "id": "123", }, }, + expectedErrs: []error{ + util.NewWarning("failed to map response-param:[bidType] method:[auto_detect] error:[bid.impid is missing]"), + }, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { pr := New(tc.request, tc.bidderResponse) - pr.Resolve(tc.bid, tc.typeBid, tc.location, tc.paramName) + errs := pr.Resolve(tc.bid, tc.typeBid, tc.location, tc.paramName) assert.Equal(t, tc.expectedTypeBid, tc.typeBid) + assert.Equal(t, tc.expectedErrs, errs) }) } } @@ -251,27 +337,27 @@ func TestDefaultvalueResolver(t *testing.T) { tests := []struct { name string wantValue any - wantFound bool + wantErr error }{ { name: "test default values", wantValue: nil, - wantFound: false, + wantErr: nil, }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { r := ¶mResolver{} value, found := r.retrieveFromBidderParamLocation(map[string]any{}, "any.path") - assert.Equal(t, tt.wantFound, found) + assert.Equal(t, tt.wantErr, found) assert.Equal(t, tt.wantValue, value) value, found = r.getFromORTBObject(map[string]any{}) - assert.Equal(t, tt.wantFound, found) + assert.Equal(t, tt.wantErr, found) assert.Equal(t, tt.wantValue, value) value, found = r.autoDetect(&openrtb2.BidRequest{}, map[string]any{}) - assert.Equal(t, tt.wantFound, found) + assert.Equal(t, tt.wantErr, found) assert.Equal(t, tt.wantValue, value) }) } diff --git a/adapters/ortbbidder/resolver/testutil.go b/adapters/ortbbidder/resolver/testutil.go new file mode 100644 index 00000000000..34ef735a49e --- /dev/null +++ b/adapters/ortbbidder/resolver/testutil.go @@ -0,0 +1,28 @@ +package resolver + +import ( + "fmt" + "reflect" +) + +func ValidateStructFields(expectedFields map[string]reflect.Type, structType reflect.Type) error { + fieldCount := structType.NumField() + + // Check if the number of fields matches the expected count + if fieldCount != len(expectedFields) { + return fmt.Errorf("Expected %d fields, but got %d fields", len(expectedFields), fieldCount) + } + + // Check if the field types match the expected types + for i := 0; i < fieldCount; i++ { + field := structType.Field(i) + expectedType, ok := expectedFields[field.Name] + if !ok { + return fmt.Errorf("Unexpected field: %s", field.Name) + } + if field.Type != expectedType { + return fmt.Errorf("Field %s: expected type %v, but got %v", field.Name, expectedType, field.Type) + } + } + return nil +} diff --git a/adapters/ortbbidder/resolver/testutil_test.go b/adapters/ortbbidder/resolver/testutil_test.go index 9371c4b99b1..90d83906832 100644 --- a/adapters/ortbbidder/resolver/testutil_test.go +++ b/adapters/ortbbidder/resolver/testutil_test.go @@ -4,53 +4,75 @@ import ( "reflect" "testing" - "github.com/prebid/openrtb/v20/openrtb2" - "github.com/prebid/prebid-server/v2/adapters" "github.com/prebid/prebid-server/v2/openrtb_ext" ) -func validateStructFields(t *testing.T, expectedFields map[string]reflect.Type, structType reflect.Type) { - fieldCount := structType.NumField() - - // Check if the number of fields matches the expected count - if fieldCount != len(expectedFields) { - t.Errorf("Expected %d fields, but got %d fields", len(expectedFields), fieldCount) - } - - // Check if the field types match the expected types - for i := 0; i < fieldCount; i++ { - field := structType.Field(i) - expectedType, ok := expectedFields[field.Name] - if !ok { - t.Errorf("Unexpected field: %s", field.Name) - } - if field.Type != expectedType { - t.Errorf("Field %s: expected type %v, but got %v", field.Name, expectedType, field.Type) - } +func TestValidateStructFields(t *testing.T) { + type args struct { + expectedFields map[string]reflect.Type + structType reflect.Type } -} - -func TestTypedBidFields(t *testing.T) { - expectedFields := map[string]reflect.Type{ - "Bid": reflect.TypeOf(&openrtb2.Bid{}), - "BidMeta": reflect.TypeOf(&openrtb_ext.ExtBidPrebidMeta{}), - "BidType": reflect.TypeOf(openrtb_ext.BidTypeBanner), - "BidVideo": reflect.TypeOf(&openrtb_ext.ExtBidPrebidVideo{}), - "BidTargets": reflect.TypeOf(map[string]string{}), - "DealPriority": reflect.TypeOf(0), - "Seat": reflect.TypeOf(openrtb_ext.BidderName("")), + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "mismatch between count of fields", + args: args{ + expectedFields: map[string]reflect.Type{}, + structType: reflect.TypeOf(openrtb_ext.ExtBidPrebidVideo{}), + }, + wantErr: true, + }, + { + name: "found unexpected field", + args: args{ + expectedFields: map[string]reflect.Type{ + "Duration_1": reflect.TypeOf(0.0), + "field2": reflect.TypeOf(""), + "field3": reflect.TypeOf(""), + }, + structType: reflect.TypeOf(openrtb_ext.ExtBidPrebidVideo{ + Duration: 0, + }), + }, + wantErr: true, + }, + { + name: "found field with incorrect data type", + args: args{ + expectedFields: map[string]reflect.Type{ + "Duration": reflect.TypeOf(0.0), + "PrimaryCategory": reflect.TypeOf(""), + "VASTTagID": reflect.TypeOf(""), + }, + structType: reflect.TypeOf(openrtb_ext.ExtBidPrebidVideo{ + Duration: 0, + }), + }, + wantErr: true, + }, + { + name: "found valid fields", + args: args{ + expectedFields: map[string]reflect.Type{ + "Duration": reflect.TypeOf(0), + "PrimaryCategory": reflect.TypeOf(""), + "VASTTagID": reflect.TypeOf(""), + }, + structType: reflect.TypeOf(openrtb_ext.ExtBidPrebidVideo{ + Duration: 0, + }), + }, + wantErr: false, + }, } - - structType := reflect.TypeOf(adapters.TypedBid{}) - validateStructFields(t, expectedFields, structType) -} - -func TestBidderResponseFields(t *testing.T) { - expectedFields := map[string]reflect.Type{ - "Currency": reflect.TypeOf(""), - "Bids": reflect.TypeOf([]*adapters.TypedBid{nil}), - "FledgeAuctionConfigs": reflect.TypeOf([]*openrtb_ext.FledgeAuctionConfig{}), + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := ValidateStructFields(tt.args.expectedFields, tt.args.structType); (err != nil) != tt.wantErr { + t.Errorf("ValidateStructFields() error = %v, wantErr %v", err, tt.wantErr) + } + }) } - structType := reflect.TypeOf(adapters.BidderResponse{}) - validateStructFields(t, expectedFields, structType) } diff --git a/adapters/ortbbidder/response_builder.go b/adapters/ortbbidder/response_builder.go index 304843f8ff0..cb1b3165d97 100644 --- a/adapters/ortbbidder/response_builder.go +++ b/adapters/ortbbidder/response_builder.go @@ -27,11 +27,11 @@ func newResponseBuilder(responseParams map[string]bidderparams.BidderParamMapper // setPrebidBidderResponse determines and construct adapters.BidderResponse and adapters.TypedBid object with the help // of response parameter mappings defined in static/bidder-response-params -func (rb *responseBuilder) setPrebidBidderResponse(bidderResponseBytes json.RawMessage) error { +func (rb *responseBuilder) setPrebidBidderResponse(bidderResponseBytes json.RawMessage) (errs []error) { err := jsonutil.UnmarshalValid(bidderResponseBytes, &rb.bidderResponse) if err != nil { - return err + return []error{util.NewBadServerResponseError(err.Error())} } // Create a new ParamResolver with the bidder response. paramResolver := resolver.New(rb.request, rb.bidderResponse) @@ -42,28 +42,29 @@ func (rb *responseBuilder) setPrebidBidderResponse(bidderResponseBytes json.RawM // Resolve the adapter response level parameters. for _, param := range resolver.ResponseParams { bidderParam := rb.responseParams[param.String()] - paramResolver.Resolve(rb.bidderResponse, adapterResponse, bidderParam.Location, param) + resolverErrors := paramResolver.Resolve(rb.bidderResponse, adapterResponse, bidderParam.Location, param) + errs = append(errs, resolverErrors...) } // Extract the seat bids from the bidder response. seatBids, ok := rb.bidderResponse[seatBidKey].([]any) if !ok { - return newBadServerResponseError("invalid seatbid array found in response, seatbids:[%v]", rb.bidderResponse[seatBidKey]) + return []error{util.NewBadServerResponseError("invalid seatbid array found in response, seatbids:[%v]", rb.bidderResponse[seatBidKey])} } // Initialize the list of typed bids. typedBids := make([]any, 0) for seatIndex, seatBid := range seatBids { seatBid, ok := seatBid.(map[string]any) if !ok { - return newBadServerResponseError("invalid seatbid found in seatbid array, seatbid:[%v]", seatBids[seatIndex]) + return []error{util.NewBadServerResponseError("invalid seatbid found in seatbid array, seatbid:[%v]", seatBids[seatIndex])} } bids, ok := seatBid[bidKey].([]any) if !ok { - return newBadServerResponseError("invalid bid array found in seatbid, bids:[%v]", seatBid[bidKey]) + return []error{util.NewBadServerResponseError("invalid bid array found in seatbid, bids:[%v]", seatBid[bidKey])} } for bidIndex, bid := range bids { bid, ok := bid.(map[string]any) if !ok { - return newBadServerResponseError("invalid bid found in bids array, bid:[%v]", bids[bidIndex]) + return []error{util.NewBadServerResponseError("invalid bid found in bids array, bid:[%v]", bids[bidIndex])} } // Initialize the typed bid with the bid. typedBid := map[string]any{ @@ -73,7 +74,8 @@ func (rb *responseBuilder) setPrebidBidderResponse(bidderResponseBytes json.RawM for _, params := range resolver.TypedBidParams { paramMapper := rb.responseParams[params.String()] location := util.ReplaceLocationMacro(paramMapper.Location, []int{seatIndex, bidIndex}) - paramResolver.Resolve(bid, typedBid, location, params) + resolverErrors := paramResolver.Resolve(bid, typedBid, location, params) + errs = append(errs, resolverErrors...) } // Add the type bid to the list of typed bids. typedBids = append(typedBids, typedBid) @@ -83,7 +85,7 @@ func (rb *responseBuilder) setPrebidBidderResponse(bidderResponseBytes json.RawM adapterResponse[bidsKey] = typedBids // Set the adapter response in the response builder. rb.adapterRespone = adapterResponse - return nil + return errs } // buildAdapterResponse converts the responseBuilder's adapter response to a prebid format. @@ -92,12 +94,12 @@ func (rb *responseBuilder) buildAdapterResponse() (resp *adapters.BidderResponse var adapterResponeBytes json.RawMessage adapterResponeBytes, err = jsonutil.Marshal(rb.adapterRespone) if err != nil { - return + return nil, util.NewBadServerResponseError(err.Error()) } err = jsonutil.UnmarshalValid(adapterResponeBytes, &resp) if err != nil { - return nil, err + return nil, util.NewBadServerResponseError(err.Error()) } return } diff --git a/adapters/ortbbidder/response_builder_test.go b/adapters/ortbbidder/response_builder_test.go index 71f66d9daaf..804177667a7 100644 --- a/adapters/ortbbidder/response_builder_test.go +++ b/adapters/ortbbidder/response_builder_test.go @@ -1,11 +1,14 @@ package ortbbidder import ( + "reflect" "testing" "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v2/adapters" "github.com/prebid/prebid-server/v2/adapters/ortbbidder/bidderparams" + "github.com/prebid/prebid-server/v2/adapters/ortbbidder/resolver" + "github.com/prebid/prebid-server/v2/adapters/ortbbidder/util" "github.com/prebid/prebid-server/v2/errortypes" "github.com/prebid/prebid-server/v2/openrtb_ext" "github.com/stretchr/testify/assert" @@ -89,7 +92,7 @@ func TestBuildAdapterResponse(t *testing.T) { }, }, expectedResponse: nil, - expectedError: &errortypes.FailedToUnmarshal{ + expectedError: &errortypes.BadServerResponse{ Message: "cannot unmarshal adapters.BidderResponse.Bids: decode slice: expect [ or n, but found {", }, }, @@ -105,7 +108,7 @@ func TestBuildAdapterResponse(t *testing.T) { }, }, expectedResponse: nil, - expectedError: &errortypes.FailedToMarshal{Message: "chan int is unsupported type"}, + expectedError: &errortypes.BadServerResponse{Message: "chan int is unsupported type"}, }, } for _, tc := range testCases { @@ -126,7 +129,7 @@ func TestSetPrebidBidderResponse(t *testing.T) { bidderResponse map[string]any bidderResponseBytes []byte responseParams map[string]bidderparams.BidderParamMapper - expectedError error + expectedError []error expectedResponse map[string]any }{ { @@ -137,7 +140,7 @@ func TestSetPrebidBidderResponse(t *testing.T) { Location: "cur", }, }, - expectedError: &errortypes.FailedToUnmarshal{Message: "expect ] in the end, but found \x00"}, + expectedError: []error{&errortypes.BadServerResponse{Message: "expect ] in the end, but found \x00"}}, }, { name: "Invalid seatbid object in response", @@ -147,7 +150,7 @@ func TestSetPrebidBidderResponse(t *testing.T) { Location: "cur", }, }, - expectedError: &errortypes.BadServerResponse{Message: "invalid seatbid array found in response, seatbids:[invalid]"}, + expectedError: []error{&errortypes.BadServerResponse{Message: "invalid seatbid array found in response, seatbids:[invalid]"}}, }, { name: "Invalid seatbid is seatbid arrays", @@ -157,7 +160,7 @@ func TestSetPrebidBidderResponse(t *testing.T) { Location: "cur", }, }, - expectedError: &errortypes.BadServerResponse{Message: "invalid seatbid found in seatbid array, seatbid:[invalid]"}, + expectedError: []error{&errortypes.BadServerResponse{Message: "invalid seatbid found in seatbid array, seatbid:[invalid]"}}, }, { name: "Invalid bid in seatbid", @@ -167,7 +170,7 @@ func TestSetPrebidBidderResponse(t *testing.T) { Location: "cur", }, }, - expectedError: &errortypes.BadServerResponse{Message: "invalid bid array found in seatbid, bids:[invalid]"}, + expectedError: []error{&errortypes.BadServerResponse{Message: "invalid bid array found in seatbid, bids:[invalid]"}}, }, { name: "Invalid bid in bids array", @@ -177,13 +180,13 @@ func TestSetPrebidBidderResponse(t *testing.T) { Location: "cur", }, }, - expectedError: &errortypes.BadServerResponse{Message: "invalid bid found in bids array, bid:[invalid]"}, + expectedError: []error{&errortypes.BadServerResponse{Message: "invalid bid found in bids array, bid:[invalid]"}}, }, { name: "Valid bidder respone, no bidder params", bidderResponseBytes: []byte(`{"id":"bid-resp-id","cur":"USD","seatbid":[{"seat":"test_bidder","bid":[{"id":"123"}]}]}`), responseParams: map[string]bidderparams.BidderParamMapper{}, - expectedError: nil, + expectedError: []error{util.ErrBidTypeMissingImpID}, expectedResponse: map[string]any{ "Currency": "USD", "Bids": []any{ @@ -253,7 +256,7 @@ func TestSetPrebidBidderResponse(t *testing.T) { "bidMetaAdvertiserId": {Location: "seatbid.#.bid.#.ext.advertiserId"}, "bidMetaNetworkId": {Location: "seatbid.#.bid.#.ext.networkId"}, }, - expectedError: nil, + expectedError: []error{util.NewWarning("failed to map response-param:[bidMetaAdvertiserId] method:[response_param_location] value:[5]")}, expectedResponse: map[string]any{ "Currency": "USD", "Bids": []any{ @@ -300,3 +303,41 @@ func TestSetPrebidBidderResponse(t *testing.T) { }) } } + +// TestTypedBidFields notifies us of any changes in the adapters.TypedBid struct. +// If a new field is added in adapters.TypedBid, then add the support to resolve the new field and update the test case. +// If the data type of an existing field changes then update the resolver of the respective field. +func TestTypedBidFields(t *testing.T) { + expectedFields := map[string]reflect.Type{ + "Bid": reflect.TypeOf(&openrtb2.Bid{}), + "BidMeta": reflect.TypeOf(&openrtb_ext.ExtBidPrebidMeta{}), + "BidType": reflect.TypeOf(openrtb_ext.BidTypeBanner), + "BidVideo": reflect.TypeOf(&openrtb_ext.ExtBidPrebidVideo{}), + "BidTargets": reflect.TypeOf(map[string]string{}), + "DealPriority": reflect.TypeOf(0), + "Seat": reflect.TypeOf(openrtb_ext.BidderName("")), + } + + structType := reflect.TypeOf(adapters.TypedBid{}) + err := resolver.ValidateStructFields(expectedFields, structType) + if err != nil { + t.Error(err) + } +} + +// TestBidderResponseFields notifies us of any changes in the adapters.BidderResponse struct. +// If a new field is added in adapters.BidderResponse, then add the support to resolve the new field and update the test case. +// If the data type of an existing field changes then update the resolver of the respective field. +func TestBidderResponseFields(t *testing.T) { + expectedFields := map[string]reflect.Type{ + "Currency": reflect.TypeOf(""), + "Bids": reflect.TypeOf([]*adapters.TypedBid{nil}), + "FledgeAuctionConfigs": reflect.TypeOf([]*openrtb_ext.FledgeAuctionConfig{}), + "FastXMLMetrics": reflect.TypeOf(&openrtb_ext.FastXMLMetrics{}), + } + structType := reflect.TypeOf(adapters.BidderResponse{}) + err := resolver.ValidateStructFields(expectedFields, structType) + if err != nil { + t.Error(err) + } +} diff --git a/adapters/ortbbidder/single_request_builder.go b/adapters/ortbbidder/single_request_builder.go index 6b7b703648f..3486ced5e98 100644 --- a/adapters/ortbbidder/single_request_builder.go +++ b/adapters/ortbbidder/single_request_builder.go @@ -5,6 +5,7 @@ import ( "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v2/adapters" + "github.com/prebid/prebid-server/v2/adapters/ortbbidder/util" "github.com/prebid/prebid-server/v2/util/jsonutil" ) @@ -30,7 +31,7 @@ func (rb *singleRequestBuilder) parseRequest(request *openrtb2.BidRequest) (err imps, ok := rb.newRequest[impKey].([]any) if !ok { - return errImpMissing + return util.ErrImpMissing } for index, imp := range imps { imp, ok := imp.(map[string]any) @@ -51,7 +52,7 @@ func (rb *singleRequestBuilder) parseRequest(request *openrtb2.BidRequest) (err // it create single RequestData object for all impressions. func (rb *singleRequestBuilder) makeRequest() (requestData []*adapters.RequestData, errs []error) { if len(rb.imps) == 0 { - errs = append(errs, newBadInputError(errImpMissing.Error())) + errs = append(errs, util.NewBadInputError(util.ErrImpMissing.Error())) return } @@ -62,8 +63,8 @@ func (rb *singleRequestBuilder) makeRequest() (requestData []*adapters.RequestDa //step 1: get endpoint if endpoint, err = rb.getEndpoint(getImpExtBidderParams(rb.imps[0])); err != nil { - errs = append(errs, newBadInputError(err.Error())) - return nil, errs + errs = append(errs, util.NewBadInputError(err.Error())) + return } //step 2: replace parameters @@ -75,7 +76,7 @@ func (rb *singleRequestBuilder) makeRequest() (requestData []*adapters.RequestDa //step 3: append new request data if requestData, err = appendRequestData(requestData, rb.newRequest, endpoint, rb.impIDs); err != nil { - errs = append(errs, newBadInputError(err.Error())) + errs = append(errs, util.NewBadInputError(err.Error())) } - return requestData, errs + return } diff --git a/adapters/ortbbidder/single_request_builder_test.go b/adapters/ortbbidder/single_request_builder_test.go index 50e02ddeea1..3b66cc257df 100644 --- a/adapters/ortbbidder/single_request_builder_test.go +++ b/adapters/ortbbidder/single_request_builder_test.go @@ -10,6 +10,7 @@ import ( "github.com/prebid/openrtb/v20/openrtb2" "github.com/prebid/prebid-server/v2/adapters" "github.com/prebid/prebid-server/v2/adapters/ortbbidder/bidderparams" + "github.com/prebid/prebid-server/v2/adapters/ortbbidder/util" "github.com/stretchr/testify/assert" ) @@ -36,7 +37,7 @@ func TestSingleRequestBuilderParseRequest(t *testing.T) { }, }, want: want{ - err: errImpMissing, + err: util.ErrImpMissing, rawRequest: json.RawMessage(`{"id":"id","imp":null}`), imps: nil, newRequest: map[string]any{ @@ -111,7 +112,7 @@ func TestSingleRequestBuilderMakeRequest(t *testing.T) { }, want: want{ requestData: nil, - errs: []error{newBadInputError(errImpMissing.Error())}, + errs: []error{util.NewBadInputError(util.ErrImpMissing.Error())}, }, }, { @@ -213,7 +214,7 @@ func TestSingleRequestBuilderMakeRequest(t *testing.T) { }, want: want{ requestData: nil, - errs: []error{newBadInputError("failed to replace macros in endpoint, err:template: endpointTemplate:1:2: " + + errs: []error{util.NewBadInputError("failed to replace macros in endpoint, err:template: endpointTemplate:1:2: " + "executing \"endpointTemplate\" at : error calling errorFunc: intentional error")}, }, }, diff --git a/adapters/ortbbidder/util/errors.go b/adapters/ortbbidder/util/errors.go new file mode 100644 index 00000000000..d5f438fafca --- /dev/null +++ b/adapters/ortbbidder/util/errors.go @@ -0,0 +1,33 @@ +package util + +import ( + "errors" + "fmt" + + "github.com/prebid/prebid-server/v2/errortypes" +) + +// list of constant errors +var ( + ErrImpMissing error = errors.New("imp object not found in request") + ErrNilBidderParamCfg error = errors.New("found nil bidderParamsConfig") + ErrBidTypeMissingImpID error = NewWarning("failed to map response-param:[bidType] method:[auto_detect] error:[bid.impid is missing]") +) + +func NewBadInputError(message string, args ...any) error { + return &errortypes.BadInput{ + Message: fmt.Sprintf(message, args...), + } +} + +func NewBadServerResponseError(message string, args ...any) error { + return &errortypes.BadServerResponse{ + Message: fmt.Sprintf(message, args...), + } +} + +func NewWarning(message string, args ...any) error { + return &errortypes.Warning{ + Message: fmt.Sprintf(message, args...), + } +} diff --git a/adapters/ortbbidder/util/errors_test.go b/adapters/ortbbidder/util/errors_test.go new file mode 100644 index 00000000000..15b25a0027d --- /dev/null +++ b/adapters/ortbbidder/util/errors_test.go @@ -0,0 +1,95 @@ +package util + +import ( + "testing" + + "github.com/prebid/prebid-server/v2/errortypes" + "github.com/stretchr/testify/assert" +) + +func TestNewBadInputError(t *testing.T) { + type args struct { + message string + args []any + } + tests := []struct { + name string + args args + wantErr error + }{ + { + name: "bad input error with params", + args: args{ + message: "bad input error [%s]", + args: []any{"field"}, + }, + wantErr: &errortypes.BadInput{ + Message: "bad input error [field]", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := NewBadInputError(tt.args.message, tt.args.args...) + assert.Equal(t, tt.wantErr, err) + }) + } +} + +func TestNewBadServerResponseError(t *testing.T) { + type args struct { + message string + args []any + } + tests := []struct { + name string + args args + wantErr error + }{ + { + name: "bad serevr error with params", + args: args{ + message: "bad input error [%s]", + args: []any{"field"}, + }, + wantErr: &errortypes.BadServerResponse{ + Message: "bad input error [field]", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := NewBadServerResponseError(tt.args.message, tt.args.args...) + assert.Equal(t, tt.wantErr, err) + }) + } +} + +func TestNewWarning(t *testing.T) { + type args struct { + message string + args []any + } + tests := []struct { + name string + args args + wantErr error + }{ + { + name: "warning with params", + args: args{ + message: "bad error [%s] : [%d]", + args: []any{"field", 10}, + }, + wantErr: &errortypes.Warning{ + Message: "bad error [field] : [10]", + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := NewWarning(tt.args.message, tt.args.args...) + assert.Equal(t, tt.wantErr, err) + }) + } +} diff --git a/adapters/ortbbidder/util/util_test.go b/adapters/ortbbidder/util/util_test.go index c5773fd5134..259f003ec13 100644 --- a/adapters/ortbbidder/util/util_test.go +++ b/adapters/ortbbidder/util/util_test.go @@ -492,6 +492,13 @@ func TestGetValueFromLocation(t *testing.T) { expectedValue: nil, ok: false, }, + { + name: "Value is present but node-element is not list", + node: node, + path: "seatbid.bid", + expectedValue: nil, + ok: false, + }, { name: "Value is not present in node due to invalid index", node: jsonToMap(`{"seatbid":[{"bid":[{"ext":{"mtype":"video"}}]}]}`),