Skip to content

Commit d388193

Browse files
Refactor: Add tests for env vars and secrets, update hasWorkToDo
Co-authored-by: luke <[email protected]>
1 parent a3178a9 commit d388193

File tree

2 files changed

+275
-6
lines changed

2 files changed

+275
-6
lines changed

pkg/abstractions/image/build_test.go

Lines changed: 273 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,155 @@ func TestRenderV2Dockerfile_FromStepsAndCommands(t *testing.T) {
8181
assert.Contains(t, df, "RUN echo step\n")
8282
}
8383

84+
// Test that RenderV2Dockerfile correctly renders environment variables and secrets
85+
func TestRenderV2Dockerfile_WithEnvVarsAndSecrets(t *testing.T) {
86+
cfg := types.AppConfig{}
87+
b := &Builder{config: cfg}
88+
89+
tests := []struct {
90+
name string
91+
opts *BuildOpts
92+
expected []string
93+
}{
94+
{
95+
name: "EnvVars only",
96+
opts: &BuildOpts{
97+
BaseImageRegistry: "docker.io",
98+
BaseImageName: "library/alpine",
99+
BaseImageTag: "3.18",
100+
EnvVars: []string{"FOO=bar", "BAZ=qux"},
101+
IgnorePython: true,
102+
},
103+
expected: []string{
104+
"FROM docker.io/library/alpine:3.18\n",
105+
"ENV FOO=bar\n",
106+
"ENV BAZ=qux\n",
107+
},
108+
},
109+
{
110+
name: "BuildSecrets only",
111+
opts: &BuildOpts{
112+
BaseImageRegistry: "docker.io",
113+
BaseImageName: "library/alpine",
114+
BaseImageTag: "3.18",
115+
BuildSecrets: []string{"SECRET1=value1", "SECRET2=value2"},
116+
IgnorePython: true,
117+
},
118+
expected: []string{
119+
"FROM docker.io/library/alpine:3.18\n",
120+
"ARG SECRET1\n",
121+
"ARG SECRET2\n",
122+
},
123+
},
124+
{
125+
name: "Both EnvVars and BuildSecrets",
126+
opts: &BuildOpts{
127+
BaseImageRegistry: "docker.io",
128+
BaseImageName: "library/alpine",
129+
BaseImageTag: "3.18",
130+
EnvVars: []string{"MY_ENV=production"},
131+
BuildSecrets: []string{"API_KEY=secret123"},
132+
IgnorePython: true,
133+
},
134+
expected: []string{
135+
"FROM docker.io/library/alpine:3.18\n",
136+
"ENV MY_ENV=production\n",
137+
"ARG API_KEY\n",
138+
},
139+
},
140+
{
141+
name: "EnvVars with commands",
142+
opts: &BuildOpts{
143+
BaseImageRegistry: "docker.io",
144+
BaseImageName: "library/alpine",
145+
BaseImageTag: "3.18",
146+
EnvVars: []string{"DEBIAN_FRONTEND=noninteractive"},
147+
Commands: []string{"apt-get update"},
148+
IgnorePython: true,
149+
},
150+
expected: []string{
151+
"FROM docker.io/library/alpine:3.18\n",
152+
"ENV DEBIAN_FRONTEND=noninteractive\n",
153+
"RUN apt-get update\n",
154+
},
155+
},
156+
}
157+
158+
for _, tt := range tests {
159+
t.Run(tt.name, func(t *testing.T) {
160+
df, err := b.RenderV2Dockerfile(tt.opts)
161+
assert.NoError(t, err)
162+
163+
for _, expected := range tt.expected {
164+
assert.Contains(t, df, expected, "Dockerfile should contain: %s", expected)
165+
}
166+
})
167+
}
168+
}
169+
170+
// Test that appendToDockerfile correctly renders environment variables and secrets
171+
func TestAppendToDockerfile_WithEnvVarsAndSecrets(t *testing.T) {
172+
cfg := types.AppConfig{}
173+
b := &Builder{config: cfg}
174+
175+
tests := []struct {
176+
name string
177+
opts *BuildOpts
178+
expected []string
179+
}{
180+
{
181+
name: "Append EnvVars to existing Dockerfile",
182+
opts: &BuildOpts{
183+
Dockerfile: "FROM ubuntu:22.04\nRUN apt-get update",
184+
EnvVars: []string{"NODE_ENV=production", "PORT=8080"},
185+
IgnorePython: true,
186+
},
187+
expected: []string{
188+
"FROM ubuntu:22.04\nRUN apt-get update",
189+
"ENV NODE_ENV=production\n",
190+
"ENV PORT=8080\n",
191+
},
192+
},
193+
{
194+
name: "Append BuildSecrets to existing Dockerfile",
195+
opts: &BuildOpts{
196+
Dockerfile: "FROM ubuntu:22.04",
197+
BuildSecrets: []string{"NPM_TOKEN=token123", "GITHUB_TOKEN=ghp_xxx"},
198+
IgnorePython: true,
199+
},
200+
expected: []string{
201+
"FROM ubuntu:22.04",
202+
"ARG NPM_TOKEN\n",
203+
"ARG GITHUB_TOKEN\n",
204+
},
205+
},
206+
{
207+
name: "Append both EnvVars and BuildSecrets",
208+
opts: &BuildOpts{
209+
Dockerfile: "FROM ubuntu:22.04\nRUN echo 'building'",
210+
EnvVars: []string{"APP_ENV=staging"},
211+
BuildSecrets: []string{"DB_PASSWORD=secret"},
212+
IgnorePython: true,
213+
},
214+
expected: []string{
215+
"FROM ubuntu:22.04\nRUN echo 'building'",
216+
"ENV APP_ENV=staging\n",
217+
"ARG DB_PASSWORD\n",
218+
},
219+
},
220+
}
221+
222+
for _, tt := range tests {
223+
t.Run(tt.name, func(t *testing.T) {
224+
result := b.appendToDockerfile(tt.opts)
225+
226+
for _, expected := range tt.expected {
227+
assert.Contains(t, result, expected, "Dockerfile should contain: %s", expected)
228+
}
229+
})
230+
}
231+
}
232+
84233
func TestAppendToDockerfile_WithPythonPackages(t *testing.T) {
85234
cfg := types.AppConfig{
86235
ImageService: types.ImageServiceConfig{
@@ -492,7 +641,7 @@ func TestCustomDockerfile_IgnorePython_CompleteScenarios(t *testing.T) {
492641
commands: []string{},
493642
shouldInstallPy: false,
494643
shouldInstallPkgs: false,
495-
description: "ignore_python=true, no packages, no commands no Python",
644+
description: "ignore_python=true, no packages, no commands ? no Python",
496645
},
497646
{
498647
name: "IgnorePython_WithCommands",
@@ -503,7 +652,7 @@ func TestCustomDockerfile_IgnorePython_CompleteScenarios(t *testing.T) {
503652
commands: []string{"apk add nodejs"},
504653
shouldInstallPy: false,
505654
shouldInstallPkgs: false,
506-
description: "ignore_python=true, no packages, has commands no Python, but commands run",
655+
description: "ignore_python=true, no packages, has commands ? no Python, but commands run",
507656
},
508657
{
509658
name: "IgnorePython_WithPackages",
@@ -514,7 +663,7 @@ func TestCustomDockerfile_IgnorePython_CompleteScenarios(t *testing.T) {
514663
commands: []string{},
515664
shouldInstallPy: true,
516665
shouldInstallPkgs: true,
517-
description: "ignore_python=true, has packages Python installed (packages need it)",
666+
description: "ignore_python=true, has packages ? Python installed (packages need it)",
518667
},
519668
{
520669
name: "Normal_WithPython",
@@ -525,7 +674,7 @@ func TestCustomDockerfile_IgnorePython_CompleteScenarios(t *testing.T) {
525674
commands: []string{},
526675
shouldInstallPy: true,
527676
shouldInstallPkgs: false,
528-
description: "ignore_python=false, no packages Python installed",
677+
description: "ignore_python=false, no packages ? Python installed",
529678
},
530679
{
531680
name: "Normal_WithPythonAndPackages",
@@ -536,7 +685,7 @@ func TestCustomDockerfile_IgnorePython_CompleteScenarios(t *testing.T) {
536685
commands: []string{},
537686
shouldInstallPy: true,
538687
shouldInstallPkgs: true,
539-
description: "ignore_python=false, has packages Python and packages installed",
688+
description: "ignore_python=false, has packages ? Python and packages installed",
540689
},
541690
}
542691

@@ -605,7 +754,7 @@ func TestRenderV2Dockerfile_PythonInstallation(t *testing.T) {
605754
b := &Builder{config: cfg}
606755

607756
t.Run("IgnorePython_NoPackages_SkipsPython", func(t *testing.T) {
608-
// Matches v1: if IgnorePython && no packages skip Python entirely
757+
// Matches v1: if IgnorePython && no packages ? skip Python entirely
609758
opts := &BuildOpts{
610759
BaseImageRegistry: "docker.io",
611760
BaseImageName: "library/ubuntu",
@@ -1201,3 +1350,121 @@ func Test_parseBuildSteps(t *testing.T) {
12011350
result := parseBuildSteps(steps, pythonVersion, false)
12021351
assert.Equal(t, expected, result)
12031352
}
1353+
1354+
// Test hasWorkToDo correctly identifies when EnvVars or BuildSecrets require a Dockerfile
1355+
func Test_hasWorkToDo(t *testing.T) {
1356+
config := types.AppConfig{
1357+
ImageService: types.ImageServiceConfig{
1358+
PythonVersion: "python3.10",
1359+
Runner: types.RunnerConfig{
1360+
BaseImageName: "base-image",
1361+
BaseImageRegistry: "docker.io",
1362+
PythonStandalone: types.PythonStandaloneConfig{
1363+
InstallScriptTemplate: "echo installing python {{.PythonVersion}}",
1364+
},
1365+
},
1366+
},
1367+
}
1368+
1369+
b := &Builder{
1370+
config: config,
1371+
}
1372+
1373+
tests := []struct {
1374+
name string
1375+
opts *BuildOpts
1376+
expected bool
1377+
reason string
1378+
}{
1379+
{
1380+
name: "EnvVars requires work",
1381+
opts: &BuildOpts{
1382+
EnvVars: []string{"FOO=bar", "BAZ=qux"},
1383+
IgnorePython: true, // Explicitly ignore Python to test EnvVars alone
1384+
},
1385+
expected: true,
1386+
reason: "EnvVars should trigger Dockerfile generation",
1387+
},
1388+
{
1389+
name: "BuildSecrets requires work",
1390+
opts: &BuildOpts{
1391+
BuildSecrets: []string{"SECRET1=value1", "SECRET2=value2"},
1392+
IgnorePython: true, // Explicitly ignore Python to test secrets alone
1393+
},
1394+
expected: true,
1395+
reason: "BuildSecrets should trigger Dockerfile generation",
1396+
},
1397+
{
1398+
name: "EnvVars and BuildSecrets together requires work",
1399+
opts: &BuildOpts{
1400+
EnvVars: []string{"FOO=bar"},
1401+
BuildSecrets: []string{"SECRET1=value1"},
1402+
IgnorePython: true,
1403+
},
1404+
expected: true,
1405+
reason: "EnvVars and BuildSecrets together should trigger Dockerfile generation",
1406+
},
1407+
{
1408+
name: "Commands requires work",
1409+
opts: &BuildOpts{
1410+
Commands: []string{"echo hello"},
1411+
IgnorePython: true,
1412+
},
1413+
expected: true,
1414+
reason: "Commands should trigger Dockerfile generation",
1415+
},
1416+
{
1417+
name: "BuildSteps requires work",
1418+
opts: &BuildOpts{
1419+
BuildSteps: []BuildStep{{Command: "apt update", Type: "shell"}},
1420+
IgnorePython: true,
1421+
},
1422+
expected: true,
1423+
reason: "BuildSteps should trigger Dockerfile generation",
1424+
},
1425+
{
1426+
name: "PythonPackages requires work",
1427+
opts: &BuildOpts{
1428+
PythonPackages: []string{"numpy"},
1429+
PythonVersion: "python3.10",
1430+
},
1431+
expected: true,
1432+
reason: "PythonPackages should trigger Dockerfile generation",
1433+
},
1434+
{
1435+
name: "PythonVersion without IgnorePython requires work",
1436+
opts: &BuildOpts{
1437+
PythonVersion: "python3.10",
1438+
IgnorePython: false,
1439+
},
1440+
expected: true,
1441+
reason: "PythonVersion without IgnorePython should trigger Dockerfile generation",
1442+
},
1443+
{
1444+
name: "No work needed",
1445+
opts: &BuildOpts{
1446+
IgnorePython: true,
1447+
// No commands, build steps, packages, env vars, or secrets
1448+
},
1449+
expected: false,
1450+
reason: "Empty opts with IgnorePython should not require work",
1451+
},
1452+
{
1453+
name: "PythonVersion with IgnorePython and no other work",
1454+
opts: &BuildOpts{
1455+
PythonVersion: "python3.10",
1456+
IgnorePython: true,
1457+
// No other build steps
1458+
},
1459+
expected: false,
1460+
reason: "PythonVersion with IgnorePython and no other work should not require Dockerfile",
1461+
},
1462+
}
1463+
1464+
for _, tt := range tests {
1465+
t.Run(tt.name, func(t *testing.T) {
1466+
result := b.hasWorkToDo(tt.opts)
1467+
assert.Equal(t, tt.expected, result, tt.reason)
1468+
})
1469+
}
1470+
}

pkg/abstractions/image/builder.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,8 @@ func (b *Builder) hasWorkToDo(opts *BuildOpts) bool {
251251
return len(opts.Commands) > 0 ||
252252
len(opts.BuildSteps) > 0 ||
253253
len(opts.PythonPackages) > 0 ||
254+
len(opts.EnvVars) > 0 ||
255+
len(opts.BuildSecrets) > 0 ||
254256
(opts.PythonVersion != "" && !opts.IgnorePython)
255257
}
256258

0 commit comments

Comments
 (0)