Skip to content

Commit 50f9817

Browse files
committed
Added some tests
1 parent c6ab0c7 commit 50f9817

5 files changed

Lines changed: 410 additions & 0 deletions

File tree

.github/workflows/build.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,5 +17,8 @@ jobs:
1717
- name: Install dependencies
1818
run: go mod tidy
1919

20+
- name: Test
21+
run: go test ./...
22+
2023
- name: Build
2124
run: go build -v -o env-exec ./cmd/env-exec/main.go

internal/config/loader_test.go

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
package config
2+
3+
import (
4+
"os"
5+
"path/filepath"
6+
"testing"
7+
)
8+
9+
func TestLoad(t *testing.T) {
10+
tests := []struct {
11+
name string
12+
content string
13+
wantErr bool
14+
wantEnvLen int
15+
check func(*testing.T, *RootConfig)
16+
}{
17+
{
18+
name: "valid plain value",
19+
content: "env:\n - name: TEST\n value: hello",
20+
wantEnvLen: 1,
21+
check: func(t *testing.T, cfg *RootConfig) {
22+
if cfg.Env[0].Name != "TEST" || cfg.Env[0].Value != "hello" {
23+
t.Errorf("got %+v", cfg.Env[0])
24+
}
25+
},
26+
},
27+
{
28+
name: "with defaults",
29+
content: "defaults:\n gcp:\n project: my-project\nenv:\n - name: X\n value: y",
30+
wantEnvLen: 1,
31+
check: func(t *testing.T, cfg *RootConfig) {
32+
if cfg.Defaults.GCP.Project != "my-project" {
33+
t.Errorf("want default project 'my-project', got %q", cfg.Defaults.GCP.Project)
34+
}
35+
},
36+
},
37+
{
38+
name: "GCP secret",
39+
content: `env:
40+
- name: SECRET
41+
valueFrom:
42+
gcpSecretKeyRef:
43+
name: my-secret
44+
project: my-project`,
45+
wantEnvLen: 1,
46+
check: func(t *testing.T, cfg *RootConfig) {
47+
if cfg.Env[0].ValueFrom.GCPSecretKeyRef.Name != "my-secret" {
48+
t.Errorf("got %+v", cfg.Env[0].ValueFrom.GCPSecretKeyRef)
49+
}
50+
},
51+
},
52+
{
53+
name: "GitLab variable",
54+
content: `env:
55+
- name: VAR
56+
valueFrom:
57+
gitlabVariableKeyRef:
58+
project: "12345"
59+
key: my-key`,
60+
wantEnvLen: 1,
61+
check: func(t *testing.T, cfg *RootConfig) {
62+
ref := cfg.Env[0].ValueFrom.GitlabVariableKeyRef
63+
if ref.Project != "12345" || ref.Key != "my-key" {
64+
t.Errorf("got %+v", ref)
65+
}
66+
},
67+
},
68+
{
69+
name: "empty file",
70+
content: "",
71+
wantEnvLen: 0,
72+
},
73+
{
74+
name: "invalid YAML",
75+
content: "env:\n - name: TEST\n value: [invalid",
76+
wantErr: true,
77+
},
78+
}
79+
80+
for _, tt := range tests {
81+
t.Run(tt.name, func(t *testing.T) {
82+
tmpDir := t.TempDir()
83+
configPath := filepath.Join(tmpDir, "config.yaml")
84+
if err := os.WriteFile(configPath, []byte(tt.content), 0644); err != nil {
85+
t.Fatal(err)
86+
}
87+
t.Setenv("ENV_EXEC_YAML", configPath)
88+
89+
cfg, err := Load()
90+
if tt.wantErr {
91+
if err == nil {
92+
t.Error("want error, got nil")
93+
}
94+
return
95+
}
96+
if err != nil {
97+
t.Fatalf("unexpected error: %v", err)
98+
}
99+
if len(cfg.Env) != tt.wantEnvLen {
100+
t.Errorf("want %d env vars, got %d", tt.wantEnvLen, len(cfg.Env))
101+
}
102+
if tt.check != nil {
103+
tt.check(t, cfg)
104+
}
105+
})
106+
}
107+
}
108+
109+
func TestLoad_MissingFile(t *testing.T) {
110+
tmpDir := t.TempDir()
111+
origDir, _ := os.Getwd()
112+
os.Chdir(tmpDir)
113+
defer os.Chdir(origDir)
114+
os.Unsetenv("ENV_EXEC_YAML")
115+
116+
cfg, err := Load()
117+
if err != nil {
118+
t.Fatalf("want no error for missing file, got: %v", err)
119+
}
120+
if cfg == nil || len(cfg.Env) != 0 {
121+
t.Errorf("want empty config, got: %+v", cfg)
122+
}
123+
}

internal/config/validation_test.go

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
package config
2+
3+
import (
4+
"strings"
5+
"testing"
6+
)
7+
8+
func TestValidate(t *testing.T) {
9+
tests := []struct {
10+
name string
11+
config *RootConfig
12+
wantErr string
13+
}{
14+
{
15+
name: "empty config",
16+
config: &RootConfig{},
17+
wantErr: "",
18+
},
19+
{
20+
name: "valid plain value",
21+
config: &RootConfig{Env: []EnvConfig{{Name: "TEST", Value: "hello"}}},
22+
wantErr: "",
23+
},
24+
{
25+
name: "valid GCP secret",
26+
config: &RootConfig{Env: []EnvConfig{{
27+
Name: "TEST",
28+
ValueFrom: ValueFrom{GCPSecretKeyRef: GCPSecretKeyRef{Name: "secret"}},
29+
}}},
30+
wantErr: "",
31+
},
32+
{
33+
name: "valid GitLab variable",
34+
config: &RootConfig{Env: []EnvConfig{{
35+
Name: "TEST",
36+
ValueFrom: ValueFrom{GitlabVariableKeyRef: GitlabVariableKeyRef{Project: "123", Key: "key"}},
37+
}}},
38+
wantErr: "",
39+
},
40+
{
41+
name: "multiple valid env vars",
42+
config: &RootConfig{Env: []EnvConfig{
43+
{Name: "VAR1", Value: "value1"},
44+
{Name: "VAR2", Value: "value2"},
45+
}},
46+
wantErr: "",
47+
},
48+
{
49+
name: "missing name",
50+
config: &RootConfig{Env: []EnvConfig{{Value: "test"}}},
51+
wantErr: "name is required",
52+
},
53+
{
54+
name: "missing value and valueFrom",
55+
config: &RootConfig{Env: []EnvConfig{{Name: "TEST"}}},
56+
wantErr: "must have value or valueFrom",
57+
},
58+
{
59+
name: "GitLab missing project",
60+
config: &RootConfig{Env: []EnvConfig{{
61+
Name: "TEST",
62+
ValueFrom: ValueFrom{GitlabVariableKeyRef: GitlabVariableKeyRef{Key: "key"}},
63+
}}},
64+
wantErr: "gitlabVariableKeyRef.project is required",
65+
},
66+
{
67+
name: "GitLab missing key treated as no valueFrom",
68+
config: &RootConfig{Env: []EnvConfig{{
69+
Name: "TEST",
70+
ValueFrom: ValueFrom{GitlabVariableKeyRef: GitlabVariableKeyRef{Project: "123"}},
71+
}}},
72+
wantErr: "must have value or valueFrom",
73+
},
74+
}
75+
76+
for _, tt := range tests {
77+
t.Run(tt.name, func(t *testing.T) {
78+
err := Validate(tt.config)
79+
if tt.wantErr == "" && err != nil {
80+
t.Errorf("unexpected error: %v", err)
81+
}
82+
if tt.wantErr != "" && (err == nil || !strings.Contains(err.Error(), tt.wantErr)) {
83+
t.Errorf("want error containing %q, got: %v", tt.wantErr, err)
84+
}
85+
})
86+
}
87+
}

internal/env/env_test.go

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
package env
2+
3+
import (
4+
"bytes"
5+
"io"
6+
"os"
7+
"strings"
8+
"testing"
9+
)
10+
11+
func captureStdout(f func()) string {
12+
old := os.Stdout
13+
r, w, _ := os.Pipe()
14+
os.Stdout = w
15+
16+
f()
17+
18+
w.Close()
19+
os.Stdout = old
20+
21+
var buf bytes.Buffer
22+
io.Copy(&buf, r)
23+
return buf.String()
24+
}
25+
26+
func TestPrint(t *testing.T) {
27+
tests := []struct {
28+
name string
29+
envVars map[string]string
30+
contains []string // for map iteration order
31+
exact string // for single var tests
32+
}{
33+
{
34+
name: "empty",
35+
envVars: map[string]string{},
36+
exact: "",
37+
},
38+
{
39+
name: "single var",
40+
envVars: map[string]string{"TEST": "hello"},
41+
exact: "export TEST='hello'\n",
42+
},
43+
{
44+
name: "escapes single quotes",
45+
envVars: map[string]string{"TEST": "it's a test"},
46+
exact: "export TEST='it'\\''s a test'\n",
47+
},
48+
{
49+
name: "multiple single quotes",
50+
envVars: map[string]string{"TEST": "it's Bob's"},
51+
exact: "export TEST='it'\\''s Bob'\\''s'\n",
52+
},
53+
{
54+
name: "spaces preserved",
55+
envVars: map[string]string{"TEST": "value with spaces"},
56+
exact: "export TEST='value with spaces'\n",
57+
},
58+
{
59+
name: "multiple vars",
60+
envVars: map[string]string{"A": "1", "B": "2"},
61+
contains: []string{"export A='1'\n", "export B='2'\n"},
62+
},
63+
}
64+
65+
for _, tt := range tests {
66+
t.Run(tt.name, func(t *testing.T) {
67+
output := captureStdout(func() { Print(tt.envVars) })
68+
69+
if tt.exact != "" {
70+
if output != tt.exact {
71+
t.Errorf("want %q, got %q", tt.exact, output)
72+
}
73+
}
74+
for _, want := range tt.contains {
75+
if !strings.Contains(output, want) {
76+
t.Errorf("want output to contain %q, got %q", want, output)
77+
}
78+
}
79+
})
80+
}
81+
}
82+
83+
func TestSet(t *testing.T) {
84+
tests := []struct {
85+
name string
86+
envVars map[string]string
87+
}{
88+
{"empty", map[string]string{}},
89+
{"single var", map[string]string{"TEST_SET_1": "value1"}},
90+
{"multiple vars", map[string]string{"TEST_SET_A": "a", "TEST_SET_B": "b"}},
91+
}
92+
93+
for _, tt := range tests {
94+
t.Run(tt.name, func(t *testing.T) {
95+
// Clean up after test
96+
for k := range tt.envVars {
97+
defer os.Unsetenv(k)
98+
}
99+
100+
if err := Set(tt.envVars); err != nil {
101+
t.Fatalf("unexpected error: %v", err)
102+
}
103+
104+
for k, want := range tt.envVars {
105+
if got := os.Getenv(k); got != want {
106+
t.Errorf("want %s=%q, got %q", k, want, got)
107+
}
108+
}
109+
})
110+
}
111+
}

0 commit comments

Comments
 (0)