Files
dodo/pkg/config/config_test.go

355 lines
12 KiB
Go

package config
import (
"net/url"
"testing"
"time"
"github.com/aykhans/dodo/pkg/types"
"github.com/aykhans/dodo/pkg/utils"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestMergeConfig(t *testing.T) {
t.Run("MergeConfig with all fields from new config", func(t *testing.T) {
originalURL, _ := url.Parse("https://original.example.com")
newURL, _ := url.Parse("https://new.example.com")
originalTimeout := 5 * time.Second
newTimeout := 10 * time.Second
originalDuration := 1 * time.Minute
newDuration := 2 * time.Minute
config := &Config{
Files: []types.ConfigFile{},
Method: utils.ToPtr("GET"),
URL: originalURL,
Timeout: &originalTimeout,
DodosCount: utils.ToPtr(uint(1)),
RequestCount: utils.ToPtr(uint(10)),
Duration: &originalDuration,
Yes: utils.ToPtr(false),
SkipVerify: utils.ToPtr(false),
Params: types.Params{{Key: "old", Value: []string{"value"}}},
Headers: types.Headers{{Key: "Old-Header", Value: []string{"old"}}},
Cookies: types.Cookies{{Key: "oldCookie", Value: []string{"oldValue"}}},
Bodies: types.Bodies{types.Body("old body")},
Proxies: types.Proxies{},
}
newConfig := &Config{
Files: []types.ConfigFile{},
Method: utils.ToPtr("POST"),
URL: newURL,
Timeout: &newTimeout,
DodosCount: utils.ToPtr(uint(5)),
RequestCount: utils.ToPtr(uint(20)),
Duration: &newDuration,
Yes: utils.ToPtr(true),
SkipVerify: utils.ToPtr(true),
Params: types.Params{{Key: "new", Value: []string{"value"}}},
Headers: types.Headers{{Key: "New-Header", Value: []string{"new"}}},
Cookies: types.Cookies{{Key: "newCookie", Value: []string{"newValue"}}},
Bodies: types.Bodies{types.Body("new body")},
Proxies: types.Proxies{},
}
config.MergeConfig(newConfig)
assert.Equal(t, "POST", *config.Method)
assert.Equal(t, newURL, config.URL)
assert.Equal(t, newTimeout, *config.Timeout)
assert.Equal(t, uint(5), *config.DodosCount)
assert.Equal(t, uint(20), *config.RequestCount)
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.Empty(t, config.Proxies)
})
t.Run("MergeConfig with partial fields from new config", func(t *testing.T) {
originalURL, _ := url.Parse("https://original.example.com")
originalTimeout := 5 * time.Second
config := &Config{
Files: []types.ConfigFile{},
Method: utils.ToPtr("GET"),
URL: originalURL,
Timeout: &originalTimeout,
DodosCount: utils.ToPtr(uint(1)),
Headers: types.Headers{{Key: "Original-Header", Value: []string{"original"}}},
}
newURL, _ := url.Parse("https://new.example.com")
newConfig := &Config{
Files: []types.ConfigFile{},
URL: newURL,
DodosCount: utils.ToPtr(uint(10)),
}
config.MergeConfig(newConfig)
assert.Equal(t, "GET", *config.Method, "Method should remain unchanged")
assert.Equal(t, newURL, config.URL, "URL should be updated")
assert.Equal(t, originalTimeout, *config.Timeout, "Timeout should remain unchanged")
assert.Equal(t, uint(10), *config.DodosCount, "DodosCount should be updated")
assert.Equal(t, types.Headers{{Key: "Original-Header", Value: []string{"original"}}}, config.Headers, "Headers should remain unchanged")
})
t.Run("MergeConfig with nil new config fields", func(t *testing.T) {
originalURL, _ := url.Parse("https://original.example.com")
originalTimeout := 5 * time.Second
config := &Config{
Files: []types.ConfigFile{},
Method: utils.ToPtr("GET"),
URL: originalURL,
Timeout: &originalTimeout,
DodosCount: utils.ToPtr(uint(1)),
Yes: utils.ToPtr(false),
SkipVerify: utils.ToPtr(false),
}
newConfig := &Config{
Files: []types.ConfigFile{},
Method: nil,
URL: nil,
Timeout: nil,
DodosCount: nil,
Yes: nil,
SkipVerify: nil,
}
originalConfigCopy := *config
config.MergeConfig(newConfig)
assert.Equal(t, originalConfigCopy.Method, config.Method)
assert.Equal(t, originalConfigCopy.URL, config.URL)
assert.Equal(t, originalConfigCopy.Timeout, config.Timeout)
assert.Equal(t, originalConfigCopy.DodosCount, config.DodosCount)
assert.Equal(t, originalConfigCopy.Yes, config.Yes)
assert.Equal(t, originalConfigCopy.SkipVerify, config.SkipVerify)
})
t.Run("MergeConfig with empty slices", func(t *testing.T) {
configFile, _ := types.ParseConfigFile("original.yml")
config := &Config{
Files: []types.ConfigFile{*configFile},
Params: types.Params{{Key: "original", Value: []string{"value"}}},
Headers: types.Headers{{Key: "Original-Header", Value: []string{"original"}}},
Cookies: types.Cookies{{Key: "originalCookie", Value: []string{"originalValue"}}},
Bodies: types.Bodies{types.Body("original body")},
Proxies: types.Proxies{},
}
newConfig := &Config{
Files: []types.ConfigFile{},
Params: types.Params{},
Headers: types.Headers{},
Cookies: types.Cookies{},
Bodies: types.Bodies{},
Proxies: types.Proxies{},
}
config.MergeConfig(newConfig)
assert.Equal(t, []types.ConfigFile{*configFile}, config.Files, "Empty Files should not override")
assert.Equal(t, types.Params{{Key: "original", Value: []string{"value"}}}, config.Params, "Empty Params should not override")
assert.Equal(t, types.Headers{{Key: "Original-Header", Value: []string{"original"}}}, config.Headers, "Empty Headers should not override")
assert.Equal(t, types.Cookies{{Key: "originalCookie", Value: []string{"originalValue"}}}, config.Cookies, "Empty Cookies should not override")
assert.Equal(t, types.Bodies{types.Body("original body")}, config.Bodies, "Empty Bodies should not override")
assert.Equal(t, types.Proxies{}, config.Proxies, "Empty Proxies should not override")
})
t.Run("MergeConfig with Files field", func(t *testing.T) {
configFile1, _ := types.ParseConfigFile("config1.yml")
configFile2, _ := types.ParseConfigFile("config2.yaml")
config := &Config{
Files: []types.ConfigFile{*configFile1},
Method: utils.ToPtr("GET"),
Headers: types.Headers{{Key: "Original-Header", Value: []string{"original"}}},
}
newConfig := &Config{
Files: []types.ConfigFile{*configFile2},
Method: utils.ToPtr("POST"),
}
config.MergeConfig(newConfig)
assert.Equal(t, "POST", *config.Method, "Method should be updated")
assert.Equal(t, []types.ConfigFile{*configFile1, *configFile2}, config.Files, "Files should be appended")
assert.Equal(t, types.Headers{{Key: "Original-Header", Value: []string{"original"}}}, config.Headers, "Headers should remain unchanged")
})
t.Run("MergeConfig on empty original config", func(t *testing.T) {
config := &Config{}
newURL, _ := url.Parse("https://new.example.com")
newTimeout := 10 * time.Second
newDuration := 2 * time.Minute
newConfig := &Config{
Files: []types.ConfigFile{},
Method: utils.ToPtr("POST"),
URL: newURL,
Timeout: &newTimeout,
DodosCount: utils.ToPtr(uint(5)),
RequestCount: utils.ToPtr(uint(20)),
Duration: &newDuration,
Yes: utils.ToPtr(true),
SkipVerify: utils.ToPtr(true),
Params: types.Params{{Key: "new", Value: []string{"value"}}},
Headers: types.Headers{{Key: "New-Header", Value: []string{"new"}}},
Cookies: types.Cookies{{Key: "newCookie", Value: []string{"newValue"}}},
Bodies: types.Bodies{types.Body("new body")},
Proxies: types.Proxies{},
}
config.MergeConfig(newConfig)
assert.Equal(t, "POST", *config.Method)
assert.Equal(t, newURL, config.URL)
assert.Equal(t, newTimeout, *config.Timeout)
assert.Equal(t, uint(5), *config.DodosCount)
assert.Equal(t, uint(20), *config.RequestCount)
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.Empty(t, config.Proxies)
})
}
func TestSetDefaults(t *testing.T) {
t.Run("SetDefaults on empty config", func(t *testing.T) {
config := &Config{}
config.SetDefaults()
require.NotNil(t, config.Method)
assert.Equal(t, Defaults.Method, *config.Method)
require.NotNil(t, config.Timeout)
assert.Equal(t, Defaults.RequestTimeout, *config.Timeout)
require.NotNil(t, config.DodosCount)
assert.Equal(t, Defaults.DodosCount, *config.DodosCount)
require.NotNil(t, config.Yes)
assert.Equal(t, Defaults.Yes, *config.Yes)
require.NotNil(t, config.SkipVerify)
assert.Equal(t, Defaults.SkipVerify, *config.SkipVerify)
assert.True(t, config.Headers.Has("User-Agent"))
assert.Equal(t, Defaults.UserAgent, config.Headers[0].Value[0])
})
t.Run("SetDefaults preserves existing values", func(t *testing.T) {
customTimeout := 30 * time.Second
config := &Config{
Method: utils.ToPtr("POST"),
Timeout: &customTimeout,
DodosCount: utils.ToPtr(uint(10)),
Yes: utils.ToPtr(true),
SkipVerify: utils.ToPtr(true),
Headers: types.Headers{{Key: "User-Agent", Value: []string{"custom-agent"}}},
}
config.SetDefaults()
assert.Equal(t, "POST", *config.Method, "Method should not be overridden")
assert.Equal(t, customTimeout, *config.Timeout, "Timeout should not be overridden")
assert.Equal(t, uint(10), *config.DodosCount, "DodosCount should not be overridden")
assert.True(t, *config.Yes, "Yes should not be overridden")
assert.True(t, *config.SkipVerify, "SkipVerify should not be overridden")
assert.Equal(t, "custom-agent", config.Headers[0].Value[0], "User-Agent should not be overridden")
assert.Len(t, config.Headers, 1, "Should not add duplicate User-Agent")
})
t.Run("SetDefaults adds User-Agent when missing", func(t *testing.T) {
config := &Config{
Files: []types.ConfigFile{},
Headers: types.Headers{{Key: "Content-Type", Value: []string{"application/json"}}},
}
config.SetDefaults()
assert.Len(t, config.Headers, 2)
assert.True(t, config.Headers.Has("User-Agent"))
assert.True(t, config.Headers.Has("Content-Type"))
var userAgentFound bool
for _, h := range config.Headers {
if h.Key == "User-Agent" {
userAgentFound = true
assert.Equal(t, Defaults.UserAgent, h.Value[0])
break
}
}
assert.True(t, userAgentFound, "User-Agent header should be added")
})
t.Run("SetDefaults with partial config", func(t *testing.T) {
config := &Config{
Files: []types.ConfigFile{},
Method: utils.ToPtr("PUT"),
Yes: utils.ToPtr(true),
}
config.SetDefaults()
assert.Equal(t, "PUT", *config.Method, "Existing Method should be preserved")
assert.True(t, *config.Yes, "Existing Yes should be preserved")
require.NotNil(t, config.Timeout)
assert.Equal(t, Defaults.RequestTimeout, *config.Timeout, "Timeout should be set to default")
require.NotNil(t, config.DodosCount)
assert.Equal(t, Defaults.DodosCount, *config.DodosCount, "DodosCount should be set to default")
require.NotNil(t, config.SkipVerify)
assert.Equal(t, Defaults.SkipVerify, *config.SkipVerify, "SkipVerify should be set to default")
assert.True(t, config.Headers.Has("User-Agent"))
})
t.Run("SetDefaults idempotent", func(t *testing.T) {
config := &Config{}
config.SetDefaults()
firstCallHeaders := len(config.Headers)
firstCallMethod := *config.Method
firstCallTimeout := *config.Timeout
config.SetDefaults()
assert.Len(t, config.Headers, firstCallHeaders, "Headers count should not change on second call")
assert.Equal(t, firstCallMethod, *config.Method, "Method should not change on second call")
assert.Equal(t, firstCallTimeout, *config.Timeout, "Timeout should not change on second call")
})
t.Run("SetDefaults with empty Headers initializes correctly", func(t *testing.T) {
config := &Config{
Files: []types.ConfigFile{},
Headers: types.Headers{},
}
config.SetDefaults()
assert.Len(t, config.Headers, 1)
assert.Equal(t, "User-Agent", config.Headers[0].Key)
assert.Equal(t, Defaults.UserAgent, config.Headers[0].Value[0])
})
}