mirror of https://github.com/portainer/portainer
243 lines
5.4 KiB
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")
|
|
})
|
|
}
|