portainer/pkg/libhelm/sdk/values_test.go

243 lines
5.4 KiB
Go

package sdk
import (
"os"
"path/filepath"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestMergeValues(t *testing.T) {
tests := []struct {
name string
base map[string]any
override map[string]any
expected map[string]any
}{
{
name: "empty base returns override",
base: nil,
override: map[string]any{"key": "value"},
expected: map[string]any{"key": "value"},
},
{
name: "empty override returns base",
base: map[string]any{"key": "value"},
override: nil,
expected: map[string]any{"key": "value"},
},
{
name: "both nil returns nil",
base: nil,
override: nil,
expected: nil,
},
{
name: "simple merge without conflicts",
base: map[string]any{"key1": "value1"},
override: map[string]any{"key2": "value2"},
expected: map[string]any{"key1": "value1", "key2": "value2"},
},
{
name: "override replaces scalar value",
base: map[string]any{"key": "old"},
override: map[string]any{"key": "new"},
expected: map[string]any{"key": "new"},
},
{
name: "nested map merge preserves non-conflicting keys",
base: map[string]any{
"config": map[string]any{
"port": 8080,
"host": "localhost",
},
},
override: map[string]any{
"config": map[string]any{
"port": 9090,
},
},
expected: map[string]any{
"config": map[string]any{
"port": 9090,
"host": "localhost",
},
},
},
{
name: "deep nested merge",
base: map[string]any{
"level1": map[string]any{
"level2": map[string]any{
"key1": "value1",
"key2": "value2",
},
"other": "data",
},
},
override: map[string]any{
"level1": map[string]any{
"level2": map[string]any{
"key2": "overridden",
"key3": "new",
},
},
},
expected: map[string]any{
"level1": map[string]any{
"level2": map[string]any{
"key1": "value1",
"key2": "overridden",
"key3": "new",
},
"other": "data",
},
},
},
{
name: "override replaces scalar with map",
base: map[string]any{
"value": "simple",
},
override: map[string]any{
"value": map[string]any{
"complex": "object",
},
},
expected: map[string]any{
"value": map[string]any{
"complex": "object",
},
},
},
{
name: "override replaces map with scalar",
base: map[string]any{
"value": map[string]any{
"complex": "object",
},
},
override: map[string]any{
"value": "simple",
},
expected: map[string]any{
"value": "simple",
},
},
{
name: "arrays are replaced not merged",
base: map[string]any{
"items": []any{"a", "b", "c"},
},
override: map[string]any{
"items": []any{"x", "y"},
},
expected: map[string]any{
"items": []any{"x", "y"},
},
},
{
name: "helm typical scenario - image override",
base: map[string]any{
"replicaCount": 1,
"image": map[string]any{
"repository": "nginx",
"tag": "latest",
"pullPolicy": "IfNotPresent",
},
"service": map[string]any{
"type": "ClusterIP",
"port": 80,
},
},
override: map[string]any{
"replicaCount": 3,
"image": map[string]any{
"tag": "v1.2.3",
},
"service": map[string]any{
"type": "LoadBalancer",
},
},
expected: map[string]any{
"replicaCount": 3,
"image": map[string]any{
"repository": "nginx",
"tag": "v1.2.3",
"pullPolicy": "IfNotPresent",
},
"service": map[string]any{
"type": "LoadBalancer",
"port": 80,
},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
result := MergeValues(tt.base, tt.override)
assert.Equal(t, tt.expected, result)
})
}
}
func TestGetHelmValuesFromFile(t *testing.T) {
// Create a temporary directory for test files
tempDir, err := os.MkdirTemp("", "helm-values-test-*")
require.NoError(t, err)
defer os.RemoveAll(tempDir)
t.Run("empty file path returns empty map", func(t *testing.T) {
vals, err := GetHelmValuesFromFile("")
require.NoError(t, err)
assert.Nil(t, vals)
})
t.Run("non-existent file returns error", func(t *testing.T) {
_, err := GetHelmValuesFromFile(filepath.Join(tempDir, "nonexistent.yaml"))
require.Error(t, err)
assert.Contains(t, err.Error(), "failed to read values file")
})
t.Run("valid values file", func(t *testing.T) {
valuesPath := filepath.Join(tempDir, "values.yaml")
valuesContent := []byte(`
replicaCount: 3
image:
repository: nginx
tag: v1.0.0
service:
port: 8080
`)
err := os.WriteFile(valuesPath, valuesContent, 0644)
require.NoError(t, err)
vals, err := GetHelmValuesFromFile(valuesPath)
require.NoError(t, err)
assert.NotNil(t, vals)
// YAML parser returns numbers as float64
assert.InDelta(t, float64(3), vals["replicaCount"], 1e-9)
image, ok := vals["image"].(map[string]any)
require.True(t, ok)
assert.Equal(t, "nginx", image["repository"])
assert.Equal(t, "v1.0.0", image["tag"])
})
t.Run("invalid YAML in file returns error", func(t *testing.T) {
invalidPath := filepath.Join(tempDir, "invalid.yaml")
invalidContent := []byte(`
invalid: yaml: content: [[[
`)
err := os.WriteFile(invalidPath, invalidContent, 0644)
require.NoError(t, err)
_, err = GetHelmValuesFromFile(invalidPath)
require.Error(t, err)
assert.Contains(t, err.Error(), "failed to parse values file")
})
}