diff --git a/pkg/config/config.go b/pkg/config/config.go index 8d4d7a8..9f691ee 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -75,20 +75,20 @@ func (config *Config) Merge(newConfig *Config) { if newConfig.SkipVerify != nil { config.SkipVerify = newConfig.SkipVerify } - if len(newConfig.Params) != 0 { // TODO: append - config.Params = newConfig.Params + if len(newConfig.Params) != 0 { + config.Params.Append(newConfig.Params...) } - if len(newConfig.Headers) != 0 { // TODO: append - config.Headers = newConfig.Headers + if len(newConfig.Headers) != 0 { + config.Headers.Append(newConfig.Headers...) } - if len(newConfig.Cookies) != 0 { // TODO: append - config.Cookies = newConfig.Cookies + if len(newConfig.Cookies) != 0 { + config.Cookies.Append(newConfig.Cookies...) } - if len(newConfig.Bodies) != 0 { // TODO: append - config.Bodies = newConfig.Bodies + if len(newConfig.Bodies) != 0 { + config.Bodies.Append(newConfig.Bodies...) } - if len(newConfig.Proxies) != 0 { // TODO: append - config.Proxies = newConfig.Proxies + if len(newConfig.Proxies) != 0 { + config.Proxies.Append(newConfig.Proxies...) } } diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go index 0ab0814..7add4e8 100644 --- a/pkg/config/config_test.go +++ b/pkg/config/config_test.go @@ -66,10 +66,10 @@ func TestMergeConfig(t *testing.T) { assert.Equal(t, newDuration, *config.Duration) assert.True(t, *config.Yes) assert.True(t, *config.SkipVerify) - assert.Equal(t, types.Params{{Key: "new", Value: []string{"value"}}}, config.Params) - assert.Equal(t, types.Headers{{Key: "New-Header", Value: []string{"new"}}}, config.Headers) - assert.Equal(t, types.Cookies{{Key: "newCookie", Value: []string{"newValue"}}}, config.Cookies) - assert.Equal(t, types.Bodies{types.Body("new body")}, config.Bodies) + assert.Equal(t, types.Params{{Key: "old", Value: []string{"value"}}, {Key: "new", Value: []string{"value"}}}, config.Params) + assert.Equal(t, types.Headers{{Key: "Old-Header", Value: []string{"old"}}, {Key: "New-Header", Value: []string{"new"}}}, config.Headers) + assert.Equal(t, types.Cookies{{Key: "oldCookie", Value: []string{"oldValue"}}, {Key: "newCookie", Value: []string{"newValue"}}}, config.Cookies) + assert.Equal(t, types.Bodies{types.Body("old body"), types.Body("new body")}, config.Bodies) assert.Empty(t, config.Proxies) }) @@ -352,3 +352,176 @@ func TestSetDefaults(t *testing.T) { assert.Equal(t, Defaults.UserAgent, config.Headers[0].Value[0]) }) } + +func TestMergeConfig_AppendBehavior(t *testing.T) { + t.Run("MergeConfig appends params with same key", func(t *testing.T) { + config := &Config{ + Params: types.Params{{Key: "filter", Value: []string{"active"}}}, + } + + newConfig := &Config{ + Params: types.Params{{Key: "filter", Value: []string{"verified"}}}, + } + + config.Merge(newConfig) + + assert.Len(t, config.Params, 1) + paramValue := config.Params.GetValue("filter") + require.NotNil(t, paramValue) + assert.Equal(t, []string{"active", "verified"}, *paramValue) + }) + + t.Run("MergeConfig appends headers with same key", func(t *testing.T) { + config := &Config{ + Headers: types.Headers{{Key: "Accept", Value: []string{"text/html"}}}, + } + + newConfig := &Config{ + Headers: types.Headers{{Key: "Accept", Value: []string{"application/json"}}}, + } + + config.Merge(newConfig) + + assert.Len(t, config.Headers, 1) + headerValue := config.Headers.GetValue("Accept") + require.NotNil(t, headerValue) + assert.Equal(t, []string{"text/html", "application/json"}, *headerValue) + }) + + t.Run("MergeConfig appends cookies with same key", func(t *testing.T) { + config := &Config{ + Cookies: types.Cookies{{Key: "session", Value: []string{"old_token"}}}, + } + + newConfig := &Config{ + Cookies: types.Cookies{{Key: "session", Value: []string{"new_token"}}}, + } + + config.Merge(newConfig) + + assert.Len(t, config.Cookies, 1) + cookieValue := config.Cookies.GetValue("session") + require.NotNil(t, cookieValue) + assert.Equal(t, []string{"old_token", "new_token"}, *cookieValue) + }) + + t.Run("MergeConfig appends bodies", func(t *testing.T) { + config := &Config{ + Bodies: types.Bodies{types.Body("first body")}, + } + + newConfig := &Config{ + Bodies: types.Bodies{types.Body("second body"), types.Body("third body")}, + } + + config.Merge(newConfig) + + assert.Len(t, config.Bodies, 3) + assert.Equal(t, types.Body("first body"), config.Bodies[0]) + assert.Equal(t, types.Body("second body"), config.Bodies[1]) + assert.Equal(t, types.Body("third body"), config.Bodies[2]) + }) + + t.Run("MergeConfig appends proxies", func(t *testing.T) { + proxy1URL, _ := url.Parse("http://proxy1.example.com:8080") + proxy2URL, _ := url.Parse("http://proxy2.example.com:8080") + proxy3URL, _ := url.Parse("https://proxy3.example.com:443") + + config := &Config{ + Proxies: types.Proxies{types.Proxy(*proxy1URL)}, + } + + newConfig := &Config{ + Proxies: types.Proxies{types.Proxy(*proxy2URL), types.Proxy(*proxy3URL)}, + } + + config.Merge(newConfig) + + assert.Len(t, config.Proxies, 3) + assert.Equal(t, "http://proxy1.example.com:8080", config.Proxies[0].String()) + assert.Equal(t, "http://proxy2.example.com:8080", config.Proxies[1].String()) + assert.Equal(t, "https://proxy3.example.com:443", config.Proxies[2].String()) + }) + + t.Run("MergeConfig appends mixed content", func(t *testing.T) { + config := &Config{ + Params: types.Params{{Key: "limit", Value: []string{"10"}}}, + Headers: types.Headers{{Key: "Authorization", Value: []string{"Bearer token1"}}}, + Cookies: types.Cookies{{Key: "theme", Value: []string{"dark"}}}, + Bodies: types.Bodies{types.Body("original")}, + } + + newConfig := &Config{ + Params: types.Params{{Key: "offset", Value: []string{"0"}}, {Key: "limit", Value: []string{"20"}}}, + Headers: types.Headers{{Key: "Content-Type", Value: []string{"application/json"}}, {Key: "Authorization", Value: []string{"Bearer token2"}}}, + Cookies: types.Cookies{{Key: "lang", Value: []string{"en"}}, {Key: "theme", Value: []string{"light"}}}, + Bodies: types.Bodies{types.Body("updated")}, + } + + config.Merge(newConfig) + + // Check params + assert.Len(t, config.Params, 2) + limitValue := config.Params.GetValue("limit") + require.NotNil(t, limitValue) + assert.Equal(t, []string{"10", "20"}, *limitValue) + offsetValue := config.Params.GetValue("offset") + require.NotNil(t, offsetValue) + assert.Equal(t, []string{"0"}, *offsetValue) + + // Check headers + assert.Len(t, config.Headers, 2) + authValue := config.Headers.GetValue("Authorization") + require.NotNil(t, authValue) + assert.Equal(t, []string{"Bearer token1", "Bearer token2"}, *authValue) + contentTypeValue := config.Headers.GetValue("Content-Type") + require.NotNil(t, contentTypeValue) + assert.Equal(t, []string{"application/json"}, *contentTypeValue) + + // Check cookies + assert.Len(t, config.Cookies, 2) + themeValue := config.Cookies.GetValue("theme") + require.NotNil(t, themeValue) + assert.Equal(t, []string{"dark", "light"}, *themeValue) + langValue := config.Cookies.GetValue("lang") + require.NotNil(t, langValue) + assert.Equal(t, []string{"en"}, *langValue) + + // Check bodies + assert.Len(t, config.Bodies, 2) + assert.Equal(t, types.Body("original"), config.Bodies[0]) + assert.Equal(t, types.Body("updated"), config.Bodies[1]) + }) + + t.Run("MergeConfig with empty slices does not append", func(t *testing.T) { + config := &Config{ + Params: types.Params{{Key: "existing", Value: []string{"value"}}}, + Headers: types.Headers{{Key: "Existing-Header", Value: []string{"value"}}}, + Cookies: types.Cookies{{Key: "existing", Value: []string{"value"}}}, + Bodies: types.Bodies{types.Body("existing")}, + Proxies: types.Proxies{}, + } + + originalParams := len(config.Params) + originalHeaders := len(config.Headers) + originalCookies := len(config.Cookies) + originalBodies := len(config.Bodies) + originalProxies := len(config.Proxies) + + newConfig := &Config{ + Params: types.Params{}, + Headers: types.Headers{}, + Cookies: types.Cookies{}, + Bodies: types.Bodies{}, + Proxies: types.Proxies{}, + } + + config.Merge(newConfig) + + assert.Len(t, config.Params, originalParams, "Empty params should not change existing params") + assert.Len(t, config.Headers, originalHeaders, "Empty headers should not change existing headers") + assert.Len(t, config.Cookies, originalCookies, "Empty cookies should not change existing cookies") + assert.Len(t, config.Bodies, originalBodies, "Empty bodies should not change existing bodies") + assert.Len(t, config.Proxies, originalProxies, "Empty proxies should not change existing proxies") + }) +} diff --git a/pkg/config/parser/env_test.go b/pkg/config/parser/env_test.go index 48d23fc..a8a4d4e 100644 --- a/pkg/config/parser/env_test.go +++ b/pkg/config/parser/env_test.go @@ -5,9 +5,7 @@ import ( "testing" "time" - "github.com/aykhans/dodo/pkg/config" "github.com/aykhans/dodo/pkg/types" - "github.com/aykhans/dodo/pkg/utils" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -1129,38 +1127,3 @@ func TestConfigENVParser_PartialConfiguration(t *testing.T) { assert.Nil(t, config.RequestCount) }) } - -func TestConfigENVParser_MergeScenarios(t *testing.T) { - t.Run("Parse configuration suitable for merging", func(t *testing.T) { - // Set only specific fields that would override defaults - t.Setenv("METHOD", "PUT") - t.Setenv("TIMEOUT", "45s") - t.Setenv("HEADER", "X-Custom: value") - - parser := NewConfigENVParser("") - envConfig, err := parser.Parse() - - require.NoError(t, err) - require.NotNil(t, envConfig) - - // Create a default config - defaultConfig := &config.Config{ - Method: utils.ToPtr("GET"), - Timeout: utils.ToPtr(30 * time.Second), - DodosCount: utils.ToPtr(uint(1)), - Headers: types.Headers{{Key: "User-Agent", Value: []string{"DefaultAgent/1.0"}}}, - } - - // Merge the parsed config into defaults - defaultConfig.Merge(envConfig) - - // Verify merged values - assert.Equal(t, "PUT", *defaultConfig.Method, "Method should be overridden") - assert.Equal(t, 45*time.Second, *defaultConfig.Timeout, "Timeout should be overridden") - assert.Equal(t, uint(1), *defaultConfig.DodosCount, "DodosCount should remain from default") - - // Headers should contain the new header (merge behavior depends on implementation) - assert.Len(t, defaultConfig.Headers, 1) - assert.Equal(t, "X-Custom", defaultConfig.Headers[0].Key) - }) -}