diff --git a/adapters/ortbbidder/bidderparams/config.go b/adapters/ortbbidder/bidderparams/config.go index 4d191369a8b..11cf886a65e 100644 --- a/adapters/ortbbidder/bidderparams/config.go +++ b/adapters/ortbbidder/bidderparams/config.go @@ -32,11 +32,11 @@ func (bcfg *BidderConfig) SetRequestParams(bidderName string, requestParams map[ } // SetRequestParams sets the bidder specific requestParams -func (bcfg *BidderConfig) SetResponseParams(bidderName string, requestParams map[string]BidderParamMapper) { +func (bcfg *BidderConfig) SetResponseParams(bidderName string, responseParams map[string]BidderParamMapper) { if _, found := bcfg.bidderConfigMap[bidderName]; !found { bcfg.bidderConfigMap[bidderName] = &config{} } - bcfg.bidderConfigMap[bidderName].requestParams = requestParams + bcfg.bidderConfigMap[bidderName].responseParams = responseParams } // GetRequestParams returns bidder specific requestParams diff --git a/adapters/ortbbidder/bidderparams/parser.go b/adapters/ortbbidder/bidderparams/parser.go index e4e7f435da7..87b5a3dd4d7 100644 --- a/adapters/ortbbidder/bidderparams/parser.go +++ b/adapters/ortbbidder/bidderparams/parser.go @@ -1,11 +1,12 @@ package bidderparams import ( - "encoding/json" "fmt" "os" "path/filepath" "strings" + + "github.com/prebid/prebid-server/v2/util/jsonutil" ) const ( @@ -64,7 +65,7 @@ func readFile(dirPath, file string) (map[string]any, error) { return nil, err } var contentMap map[string]any - err = json.Unmarshal(content, &contentMap) + err = jsonutil.UnmarshalValid(content, &contentMap) return contentMap, err } diff --git a/adapters/ortbbidder/bidderparams/parser_test.go b/adapters/ortbbidder/bidderparams/parser_test.go index 6548ac8177e..fb71bc0479e 100644 --- a/adapters/ortbbidder/bidderparams/parser_test.go +++ b/adapters/ortbbidder/bidderparams/parser_test.go @@ -156,6 +156,7 @@ func TestPrepareRequestParams(t *testing.T) { requestParams, err := prepareParams(tt.args.bidderName, tt.args.requestParamCfg) assert.Equalf(t, tt.want.err, err, "updateBidderParamsMapper returned unexpected error") assert.Equalf(t, tt.want.requestParams, requestParams, "updateBidderParamsMapper returned unexpected mapper") + }) } } @@ -174,7 +175,7 @@ func TestLoadBidderConfig(t *testing.T) { name: "read_directory_fail", want: want{ biddersConfigMap: nil, - err: "error:[open invalid-path: no such file or directory] dirPath:[invalid-path]", + err: "error handling request params: error:[open invalid-request-param-path: no such file or directory] dirPath:[invalid-request-param-path]", }, setup: func() (string, string, error) { return "invalid-request-param-path", "invalid-response-param-path", nil @@ -184,7 +185,7 @@ func TestLoadBidderConfig(t *testing.T) { name: "found_file_without_.json_extension", want: want{ biddersConfigMap: nil, - err: "error:[invalid_json_file_name] filename:[example.txt]", + err: "error handling request params: error:[invalid_json_file_name] filename:[example.txt]", }, setup: func() (string, string, error) { dirPath := t.TempDir() @@ -192,6 +193,35 @@ func TestLoadBidderConfig(t *testing.T) { return dirPath, "", err }, }, + { + name: "response params - read_directory_fail", + want: want{ + biddersConfigMap: nil, + err: "error handling response params: error:[open invalid-path: no such file or directory] dirPath:[invalid-path]", + }, + setup: func() (string, string, error) { + dirPath := t.TempDir() + err := os.WriteFile(dirPath+"/example.json", []byte("anything"), 0644) + return dirPath, "invalid-path", err + }, + }, + { + name: "response params - found_file_without_.json_extension", + want: want{ + biddersConfigMap: nil, + err: "error handling response params: error:[invalid_json_file_name] filename:[example.txt]", + }, + setup: func() (string, string, error) { + requestDirPath := t.TempDir() + err := os.WriteFile(requestDirPath+"/example.json", []byte("anything"), 0644) + if err != nil { + return "", "", err + } + responseDirPath := t.TempDir() + err = os.WriteFile(responseDirPath+"/example.txt", []byte("anything"), 0644) + return requestDirPath, responseDirPath, err + }, + }, { name: "oRTB_bidder_not_found", want: want{ @@ -199,21 +229,31 @@ func TestLoadBidderConfig(t *testing.T) { err: "", }, setup: func() (string, string, error) { - dirPath := t.TempDir() - err := os.WriteFile(dirPath+"/example.json", []byte("anything"), 0644) - return dirPath, "", err + requestDirPath := t.TempDir() + err := os.WriteFile(requestDirPath+"/example.json", []byte("anything"), 0644) + if err != nil { + return "", "", err + } + responseDirPath := t.TempDir() + err = os.WriteFile(responseDirPath+"/example.json", []byte("anything"), 0644) + return requestDirPath, responseDirPath, err }, }, { name: "oRTB_bidder_found_but_invalid_json_present", want: want{ biddersConfigMap: nil, - err: "error:[fail_to_read_file]", + err: "error handling request params: error:[fail_to_read_file]", }, setup: func() (string, string, error) { - dirPath := t.TempDir() - err := os.WriteFile(dirPath+"/owortb_test.json", []byte("anything"), 0644) - return dirPath, "", err + requestDirPath := t.TempDir() + err := os.WriteFile(requestDirPath+"/owortb_test.json", []byte("anything"), 0644) + if err != nil { + return "", "", err + } + responseDirPath := t.TempDir() + err = os.WriteFile(responseDirPath+"/owortb_test.json", []byte("anything"), 0644) + return requestDirPath, responseDirPath, err }, }, { @@ -227,9 +267,14 @@ func TestLoadBidderConfig(t *testing.T) { err: "", }, setup: func() (string, string, error) { - dirPath := t.TempDir() - err := os.WriteFile(dirPath+"/owortb_test.json", []byte("{}"), 0644) - return dirPath, "", err + requestDirPath := t.TempDir() + err := os.WriteFile(requestDirPath+"/owortb_test.json", []byte("{}"), 0644) + if err != nil { + return "", "", err + } + responseDirPath := t.TempDir() + err = os.WriteFile(responseDirPath+"/owortb_test.json", []byte("{}"), 0644) + return requestDirPath, responseDirPath, err }, }, { @@ -239,9 +284,14 @@ func TestLoadBidderConfig(t *testing.T) { err: "error:[invalid_json_file_content_malformed_properties] bidderName:[owortb_test]", }, setup: func() (string, string, error) { - dirPath := t.TempDir() - err := os.WriteFile(dirPath+"/owortb_test.json", []byte(`{"properties":"invalid-properties"}`), 0644) - return dirPath, "", err + requestDirPath := t.TempDir() + err := os.WriteFile(requestDirPath+"/owortb_test.json", []byte(`{"properties":"invalid-properties"}`), 0644) + if err != nil { + return "", "", err + } + responseDirPath := t.TempDir() + err = os.WriteFile(responseDirPath+"/owortb_test.json", []byte(`{"properties":"invalid-properties"}`), 0644) + return requestDirPath, responseDirPath, err }, }, { @@ -254,13 +304,16 @@ func TestLoadBidderConfig(t *testing.T) { "adunitid": {Location: "app.adunit.id"}, "slotname": {Location: "ext.slotname"}, }, + responseParams: map[string]BidderParamMapper{ + "mtype": {Location: "seatbid.#.bid.#.ext.mtype"}, + }, }, }}, err: "", }, setup: func() (string, string, error) { - dirPath := t.TempDir() - err := os.WriteFile(dirPath+"/owortb_test.json", []byte(` + requestDirPath := t.TempDir() + err := os.WriteFile(requestDirPath+"/owortb_test.json", []byte(` { "title":"ortb bidder", "properties": { @@ -275,7 +328,20 @@ func TestLoadBidderConfig(t *testing.T) { } } `), 0644) - return dirPath, "", err + if err != nil { + return "", "", err + } + responseDirPath := t.TempDir() + err = os.WriteFile(responseDirPath+"/owortb_test.json", []byte(`{ + "title":"ortb bidder", + "properties": { + "mtype": { + "type": "string", + "location": "seatbid.#.bid.#.ext.mtype" + } + } + }`), 0644) + return requestDirPath, responseDirPath, err }, }, } diff --git a/adapters/ortbbidder/error.go b/adapters/ortbbidder/error.go deleted file mode 100644 index 09eed2ed3a4..00000000000 --- a/adapters/ortbbidder/error.go +++ /dev/null @@ -1,13 +0,0 @@ -package ortbbidder - -import ( - "fmt" - - "github.com/prebid/prebid-server/v2/errortypes" -) - -func newBadServerResponseError(message string, args ...any) error { - return &errortypes.BadServerResponse{ - Message: fmt.Sprintf(message, args...), - } -} diff --git a/adapters/ortbbidder/errors.go b/adapters/ortbbidder/errors.go index d1866947a9e..af64cbd21f3 100644 --- a/adapters/ortbbidder/errors.go +++ b/adapters/ortbbidder/errors.go @@ -19,3 +19,9 @@ func newBadInputError(message string, args ...any) error { Message: fmt.Sprintf(message, args...), } } + +func newBadServerResponseError(message string, args ...any) error { + return &errortypes.BadServerResponse{ + Message: fmt.Sprintf(message, args...), + } +} diff --git a/adapters/ortbbidder/ortbbidder_test.go b/adapters/ortbbidder/ortbbidder_test.go index 46ba6f2f9d4..6f8bb447939 100644 --- a/adapters/ortbbidder/ortbbidder_test.go +++ b/adapters/ortbbidder/ortbbidder_test.go @@ -2,6 +2,7 @@ package ortbbidder import ( "encoding/json" + "fmt" "net/http" "testing" "text/template" @@ -11,9 +12,120 @@ import ( "github.com/prebid/prebid-server/v2/adapters/ortbbidder/bidderparams" "github.com/prebid/prebid-server/v2/config" "github.com/prebid/prebid-server/v2/errortypes" + "github.com/prebid/prebid-server/v2/openrtb_ext" "github.com/stretchr/testify/assert" ) +func TestBuilder(t *testing.T) { + InitBidderParamsConfig("../../static/bidder-params", "../../static/bidder-params") + type args struct { + bidderName openrtb_ext.BidderName + config config.Adapter + server config.Server + } + type want struct { + err error + bidder adapters.Bidder + } + tests := []struct { + name string + args args + want want + }{ + { + name: "fails_to_parse_extra_info", + args: args{ + bidderName: "ortbbidder", + config: config.Adapter{ + ExtraAdapterInfo: "invalid-string", + }, + server: config.Server{}, + }, + want: want{ + bidder: nil, + err: fmt.Errorf("failed to parse extra_info: expect { or n, but found i"), + }, + }, + { + name: "fails_to_parse_template_endpoint", + args: args{ + bidderName: "ortbbidder", + config: config.Adapter{ + ExtraAdapterInfo: "{}", + Endpoint: "http://{{.Host}", + }, + server: config.Server{}, + }, + want: want{ + bidder: nil, + err: fmt.Errorf("failed to parse endpoint url template: template: endpointTemplate:1: bad character U+007D '}'"), + }, + }, + { + name: "bidder_with_requestMode", + args: args{ + bidderName: "ortbbidder", + config: config.Adapter{ + ExtraAdapterInfo: `{"requestMode":"single"}`, + }, + server: config.Server{}, + }, + want: want{ + bidder: &adapter{ + adapterInfo: adapterInfo{ + extraInfo: extraAdapterInfo{ + RequestMode: "single", + }, + Adapter: config.Adapter{ + ExtraAdapterInfo: `{"requestMode":"single"}`, + }, + bidderName: "ortbbidder", + endpointTemplate: func() *template.Template { + template, _ := template.New("endpointTemplate").Option("missingkey=zero").Parse("") + return template + }(), + }, + bidderParamsConfig: g_bidderParamsConfig, + }, + err: nil, + }, + }, + { + name: "bidder_without_requestMode", + args: args{ + bidderName: "ortbbidder", + config: config.Adapter{ + ExtraAdapterInfo: "", + }, + server: config.Server{}, + }, + want: want{ + bidder: &adapter{ + adapterInfo: adapterInfo{ + Adapter: config.Adapter{ + ExtraAdapterInfo: ``, + }, + bidderName: "ortbbidder", + endpointTemplate: func() *template.Template { + template, _ := template.New("endpointTemplate").Option("missingkey=zero").Parse("") + return template + }(), + }, + bidderParamsConfig: g_bidderParamsConfig, + }, + err: nil, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := Builder(tt.args.bidderName, tt.args.config, tt.args.server) + assert.Equal(t, tt.want.bidder, got, "mismatched bidder") + assert.Equal(t, tt.want.err, err, "mismatched error") + }) + } +} + func TestMakeRequests(t *testing.T) { type args struct { request *openrtb2.BidRequest @@ -304,14 +416,18 @@ func TestMakeBids(t *testing.T) { expectedResponse: nil, responseData: nil, setup: func() adapter { - return adapter{} + return adapter{ + bidderParamsConfig: &bidderparams.BidderConfig{}, + } }, }, { name: "no content response data", responseData: &adapters.ResponseData{StatusCode: http.StatusNoContent}, setup: func() adapter { - return adapter{} + return adapter{ + bidderParamsConfig: &bidderparams.BidderConfig{}, + } }, expectedResponse: nil, expectedErrors: nil, @@ -320,7 +436,9 @@ func TestMakeBids(t *testing.T) { name: "status bad request in response data", responseData: &adapters.ResponseData{StatusCode: http.StatusBadRequest}, setup: func() adapter { - return adapter{} + return adapter{ + bidderParamsConfig: &bidderparams.BidderConfig{}, + } }, expectedResponse: nil, expectedErrors: []error{&errortypes.BadInput{ @@ -332,7 +450,9 @@ func TestMakeBids(t *testing.T) { responseData: &adapters.ResponseData{StatusCode: http.StatusTooManyRequests}, setup: func() adapter { - return adapter{} + return adapter{ + bidderParamsConfig: &bidderparams.BidderConfig{}, + } }, expectedResponse: nil, expectedErrors: []error{&errortypes.BadServerResponse{ @@ -347,7 +467,9 @@ func TestMakeBids(t *testing.T) { Body: []byte(`{"id":1,"seatbid":[{"seat":"test_bidder","bid":[{"id":"bid-1","mtype":2}]}]`), }, setup: func() adapter { - return adapter{} + return adapter{ + bidderParamsConfig: &bidderparams.BidderConfig{}, + } }, expectedResponse: nil, expectedErrors: []error{&errortypes.FailedToUnmarshal{ diff --git a/adapters/ortbbidder/respone_builder_test.go b/adapters/ortbbidder/respone_builder_test.go index a7ff8437670..37bcd6cc9a2 100644 --- a/adapters/ortbbidder/respone_builder_test.go +++ b/adapters/ortbbidder/respone_builder_test.go @@ -18,13 +18,6 @@ func TestNewResponseBuilder(t *testing.T) { responseParams map[string]bidderparams.BidderParamMapper expected *responseBuilder }{ - { - name: "With nil responseParams", - responseParams: nil, - expected: &responseBuilder{ - responseParams: make(map[string]bidderparams.BidderParamMapper), - }, - }, { name: "With non-nil responseParams", responseParams: map[string]bidderparams.BidderParamMapper{ diff --git a/adapters/ortbbidder/response_builder.go b/adapters/ortbbidder/response_builder.go index 421f2a481ea..6612a445f39 100644 --- a/adapters/ortbbidder/response_builder.go +++ b/adapters/ortbbidder/response_builder.go @@ -26,6 +26,7 @@ type responseBuilder struct { } func newResponseBuilder(responseParams map[string]bidderparams.BidderParamMapper) *responseBuilder { + return &responseBuilder{ responseParams: responseParams, } diff --git a/adapters/ortbbidder/util/util.go b/adapters/ortbbidder/util/util.go index 19a0c090c49..2e4ae51208f 100644 --- a/adapters/ortbbidder/util/util.go +++ b/adapters/ortbbidder/util/util.go @@ -139,41 +139,6 @@ func GetValueFromLocation(val interface{}, path string) (interface{}, bool) { return next, true } -func setValueAtLocation(node map[string]interface{}, path string, value interface{}) bool { - location := strings.Split(path, ".") - var ( - ok bool - next interface{} = node - ) - lastIndex := len(location) - 1 - for i, loc := range location { - switch nxt := next.(type) { - case map[string]interface{}: - if i == lastIndex { - nxt[loc] = value - return true - } - next, ok = nxt[loc] - if !ok { - return false - } - case []interface{}: - index, err := strconv.Atoi(loc) - if err != nil || index < 0 || index >= len(nxt) { - return false - } - if i == lastIndex { - nxt[index] = value - return true - } - next = nxt[index] - default: - return false - } - } - return false -} - func GetPath(path string, array []int) string { parts := strings.Split(path, ".") j := 0 diff --git a/adapters/ortbbidder/util/util_test.go b/adapters/ortbbidder/util/util_test.go index 2d782dcf9c7..15eaa25c706 100644 --- a/adapters/ortbbidder/util/util_test.go +++ b/adapters/ortbbidder/util/util_test.go @@ -1,243 +1,407 @@ package util -// import ( -// "testing" +import ( + "testing" -// "github.com/stretchr/testify/assert" -// ) + "github.com/stretchr/testify/assert" +) -// func TestSetValue(t *testing.T) { -// type args struct { -// node map[string]any -// location []string -// value any -// } -// type want struct { -// node map[string]any -// status bool -// } -// tests := []struct { -// name string -// args args -// want want -// }{ -// { -// name: "set_nil_value", -// args: args{ -// node: map[string]any{}, -// location: []string{"key"}, -// value: nil, -// }, -// want: want{ -// status: false, -// node: map[string]any{}, -// }, -// }, -// { -// name: "set_value_in_empty_location", -// args: args{ -// node: map[string]any{}, -// location: []string{}, -// value: 123, -// }, -// want: want{ -// status: false, -// node: map[string]any{}, -// }, -// }, -// { -// name: "set_value_in_invalid_location_modifies_node", -// args: args{ -// node: map[string]any{}, -// location: []string{"key", ""}, -// value: 123, -// }, -// want: want{ -// status: false, -// node: map[string]any{ -// "key": map[string]any{}, -// }, -// }, -// }, -// { -// name: "set_value_at_root_level_in_empty_node", -// args: args{ -// node: map[string]any{}, -// location: []string{"key"}, -// value: 123, -// }, -// want: want{ -// status: true, -// node: map[string]any{"key": 123}, -// }, -// }, -// { -// name: "set_value_at_root_level_in_non-empty_node", -// args: args{ -// node: map[string]any{"oldKey": "oldValue"}, -// location: []string{"key"}, -// value: 123, -// }, -// want: want{ -// status: true, -// node: map[string]any{"oldKey": "oldValue", "key": 123}, -// }, -// }, -// { -// name: "set_value_at_non-root_level_in_non-json_node", -// args: args{ -// node: map[string]any{"rootKey": "rootValue"}, -// location: []string{"rootKey", "key"}, -// value: 123, -// }, -// want: want{ -// status: false, -// node: map[string]any{"rootKey": "rootValue"}, -// }, -// }, -// { -// name: "set_value_at_non-root_level_in_json_node", -// args: args{ -// node: map[string]any{"rootKey": map[string]any{ -// "oldKey": "oldValue", -// }}, -// location: []string{"rootKey", "newKey"}, -// value: 123, -// }, -// want: want{ -// status: true, -// node: map[string]any{"rootKey": map[string]any{ -// "oldKey": "oldValue", -// "newKey": 123, -// }}, -// }, -// }, -// { -// name: "set_value_at_non-root_level_in_nested-json_node", -// args: args{ -// node: map[string]any{"rootKey": map[string]any{ -// "parentKey1": map[string]any{ -// "innerKey": "innerValue", -// }, -// }}, -// location: []string{"rootKey", "parentKey2"}, -// value: "newKeyValue", -// }, -// want: want{ -// status: true, -// node: map[string]any{"rootKey": map[string]any{ -// "parentKey1": map[string]any{ -// "innerKey": "innerValue", -// }, -// "parentKey2": "newKeyValue", -// }}, -// }, -// }, -// { -// name: "override_existing_key's_value", -// args: args{ -// node: map[string]any{"rootKey": map[string]any{ -// "parentKey": map[string]any{ -// "innerKey": "innerValue", -// }, -// }}, -// location: []string{"rootKey", "parentKey"}, -// value: "newKeyValue", -// }, -// want: want{ -// status: true, -// node: map[string]any{"rootKey": map[string]any{ -// "parentKey": "newKeyValue", -// }}, -// }, -// }, -// { -// name: "appsite_key_app_object_present", -// args: args{ -// node: map[string]any{"app": map[string]any{ -// "parentKey": "oldValue", -// }}, -// location: []string{"appsite", "parentKey"}, -// value: "newKeyValue", -// }, -// want: want{ -// status: true, -// node: map[string]any{"app": map[string]any{ -// "parentKey": "newKeyValue", -// }}, -// }, -// }, -// { -// name: "appsite_key_site_object_present", -// args: args{ -// node: map[string]any{"site": map[string]any{ -// "parentKey": "oldValue", -// }}, -// location: []string{"appsite", "parentKey"}, -// value: "newKeyValue", -// }, -// want: want{ -// status: true, -// node: map[string]any{"site": map[string]any{ -// "parentKey": "newKeyValue", -// }}, -// }, -// }, -// } -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// got := setValue(tt.args.node, tt.args.location, tt.args.value) -// assert.Equalf(t, tt.want.node, tt.args.node, "SetValue failed to update node object") -// assert.Equalf(t, tt.want.status, got, "SetValue returned invalid status") -// }) -// } -// } +func TestSetValue(t *testing.T) { + type args struct { + requestNode map[string]any + location []string + value any + } + type want struct { + node map[string]any + status bool + } + tests := []struct { + name string + args args + want want + }{ + { + name: "set_nil_value", + args: args{ + requestNode: map[string]any{}, + location: []string{"key"}, + value: nil, + }, + want: want{ + status: false, + node: map[string]any{}, + }, + }, + { + name: "set_value_in_empty_location", + args: args{ + requestNode: map[string]any{}, + location: []string{}, + value: 123, + }, + want: want{ + status: false, + node: map[string]any{}, + }, + }, + { + name: "set_value_in_invalid_location_modifies_node", + args: args{ + requestNode: map[string]any{}, + location: []string{"key", ""}, + value: 123, + }, + want: want{ + status: false, + node: map[string]any{ + "key": map[string]any{}, + }, + }, + }, + { + name: "set_value_at_root_level_in_empty_node", + args: args{ + requestNode: map[string]any{}, + location: []string{"key"}, + value: 123, + }, + want: want{ + status: true, + node: map[string]any{"key": 123}, + }, + }, + { + name: "set_value_at_root_level_in_non-empty_node", + args: args{ + requestNode: map[string]any{"oldKey": "oldValue"}, + location: []string{"key"}, + value: 123, + }, + want: want{ + status: true, + node: map[string]any{"oldKey": "oldValue", "key": 123}, + }, + }, + { + name: "set_value_at_non-root_level_in_non-json_node", + args: args{ + requestNode: map[string]any{"rootKey": "rootValue"}, + location: []string{"rootKey", "key"}, + value: 123, + }, + want: want{ + status: false, + node: map[string]any{"rootKey": "rootValue"}, + }, + }, + { + name: "set_value_at_non-root_level_in_json_node", + args: args{ + requestNode: map[string]any{"rootKey": map[string]any{ + "oldKey": "oldValue", + }}, + location: []string{"rootKey", "newKey"}, + value: 123, + }, + want: want{ + status: true, + node: map[string]any{"rootKey": map[string]any{ + "oldKey": "oldValue", + "newKey": 123, + }}, + }, + }, + { + name: "set_value_at_non-root_level_in_nested-json_node", + args: args{ + requestNode: map[string]any{"rootKey": map[string]any{ + "parentKey1": map[string]any{ + "innerKey": "innerValue", + }, + }}, + location: []string{"rootKey", "parentKey2"}, + value: "newKeyValue", + }, + want: want{ + status: true, + node: map[string]any{"rootKey": map[string]any{ + "parentKey1": map[string]any{ + "innerKey": "innerValue", + }, + "parentKey2": "newKeyValue", + }}, + }, + }, + { + name: "override_existing_key's_value", + args: args{ + requestNode: map[string]any{"rootKey": map[string]any{ + "parentKey": map[string]any{ + "innerKey": "innerValue", + }, + }}, + location: []string{"rootKey", "parentKey"}, + value: "newKeyValue", + }, + want: want{ + status: true, + node: map[string]any{"rootKey": map[string]any{ + "parentKey": "newKeyValue", + }}, + }, + }, + { + name: "appsite_key_app_object_present", + args: args{ + requestNode: map[string]any{"app": map[string]any{ + "parentKey": "oldValue", + }}, + location: []string{"appsite", "parentKey"}, + value: "newKeyValue", + }, + want: want{ + status: true, + node: map[string]any{"app": map[string]any{ + "parentKey": "newKeyValue", + }}, + }, + }, + { + name: "appsite_key_site_object_present", + args: args{ + requestNode: map[string]any{"site": map[string]any{ + "parentKey": "oldValue", + }}, + location: []string{"appsite", "parentKey"}, + value: "newKeyValue", + }, + want: want{ + status: true, + node: map[string]any{"site": map[string]any{ + "parentKey": "newKeyValue", + }}, + }, + }, + { + name: "request_has_list_of_interface", + args: args{ + requestNode: map[string]any{ + "id": "req_1", + "imp": []any{ + map[string]any{ + "id": "imp_1", + }, + }, + }, + location: []string{"imp", "0", "ext"}, + value: "value", + }, + want: want{ + status: true, + node: map[string]any{ + "id": "req_1", + "imp": []any{ + map[string]any{ + "id": "imp_1", + "ext": "value", + }, + }, + }, + }, + }, + { + name: "request_has_list_of_interface_with_multi_items", + args: args{ + requestNode: map[string]any{ + "id": "req_1", + "imp": []any{ + map[string]any{ + "id": "imp_1", + }, + map[string]any{ + "id": "imp_2", + }, + }, + }, + location: []string{"imp", "1", "ext"}, + value: "value", + }, + want: want{ + status: true, + node: map[string]any{ + "id": "req_1", + "imp": []any{ + map[string]any{ + "id": "imp_1", + }, + map[string]any{ + "id": "imp_2", + "ext": "value", + }, + }, + }, + }, + }, + { + name: "request_has_list_of_interface_with_multi_items_but_invalid_index_to_update", + args: args{ + requestNode: map[string]any{ + "id": "req_1", + "imp": []any{ + map[string]any{ + "id": "imp_1", + }, + }, + }, + location: []string{"imp", "3", "ext"}, + value: "value", + }, + want: want{ + status: false, + node: map[string]any{ + "id": "req_1", + "imp": []any{ + map[string]any{ + "id": "imp_1", + }, + }, + }, + }, + }, + { + name: "request_has_list_of_interface_with_multi_items_but_valid_index_to_update", + args: args{ + requestNode: map[string]any{ + "id": "req_1", + "imp": []any{ + map[string]any{ + "id": "imp_1", + }, + }, + }, + location: []string{"imp", "0"}, + value: map[string]any{ + "id": "updated_id", + }, + }, + want: want{ + status: true, + node: map[string]any{ + "id": "req_1", + "imp": []any{ + map[string]any{ + "id": "updated_id", + }, + }, + }, + }, + }, + { + name: "request_has_list_of_interface_where_new_node_need_to_be_created", + args: args{ + requestNode: map[string]any{ + "id": "req_1", + "imp": []any{ + nil, nil, + }, + }, + location: []string{"imp", "0", "ext"}, + value: map[string]any{ + "id": "updated_id", + }, + }, + want: want{ + status: true, + node: map[string]any{ + "id": "req_1", + "imp": []any{ + map[string]any{ + "ext": map[string]any{ + "id": "updated_id", + }, + }, + nil, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got := SetValue(tt.args.requestNode, tt.args.location, tt.args.value) + assert.Equalf(t, tt.want.node, tt.args.requestNode, "SetValue failed to update node object") + assert.Equalf(t, tt.want.status, got, "SetValue returned invalid status") + }) + } +} -// func TestGetNode(t *testing.T) { -// type args struct { -// nodes map[string]any -// key string -// } -// tests := []struct { -// name string -// args args -// want any -// }{ -// { -// name: "appsite_key_present_when_app_object_present", -// args: args{ -// nodes: map[string]any{"app": map[string]any{ -// "parentKey": "oldValue", -// }}, -// key: "appsite", -// }, -// want: map[string]any{"parentKey": "oldValue"}, -// }, -// { -// name: "appsite_key_present_when_site_object_present", -// args: args{ -// nodes: map[string]any{"site": map[string]any{ -// "siteKey": "siteValue", -// }}, -// key: "appsite", -// }, -// want: map[string]any{"siteKey": "siteValue"}, -// }, -// { -// name: "appsite_key_absent", -// args: args{ -// nodes: map[string]any{"device": map[string]any{ -// "deviceKey": "deviceVal", -// }}, -// key: "appsite", -// }, -// want: nil, -// }, -// } -// for _, tt := range tests { -// t.Run(tt.name, func(t *testing.T) { -// node := getNode(tt.args.nodes, tt.args.key) -// assert.Equal(t, tt.want, node) -// }) -// } -// } +func TestGetNode(t *testing.T) { + type args struct { + requestNode map[string]any + key string + } + tests := []struct { + name string + args args + want any + }{ + { + name: "appsite_key_present_when_app_object_present", + args: args{ + requestNode: map[string]any{"app": map[string]any{ + "parentKey": "oldValue", + }}, + key: "appsite", + }, + want: map[string]any{"parentKey": "oldValue"}, + }, + { + name: "appsite_key_present_when_site_object_present", + args: args{ + requestNode: map[string]any{"site": map[string]any{ + "siteKey": "siteValue", + }}, + key: "appsite", + }, + want: map[string]any{"siteKey": "siteValue"}, + }, + { + name: "appsite_key_absent", + args: args{ + requestNode: map[string]any{"device": map[string]any{ + "deviceKey": "deviceVal", + }}, + key: "appsite", + }, + want: nil, + }, + { + name: "imp_key_present", + args: args{ + requestNode: map[string]any{ + "device": map[string]any{ + "deviceKey": "deviceVal", + }, + "imp": []any{ + map[string]any{ + "id": "imp_1", + }, + }, + }, + key: "imp", + }, + want: []any{ + map[string]any{ + "id": "imp_1", + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + node := getNode(tt.args.requestNode, tt.args.key) + assert.Equal(t, tt.want, node) + }) + } +}