Signed-off-by: Tomasz Kopczynski <tomek@kopczynski.net.pl>
Tomasz Kopczynski authored on 2016/06/27 05:01:28... | ... |
@@ -6,7 +6,10 @@ import ( |
6 | 6 |
"strings" |
7 | 7 |
"testing" |
8 | 8 |
|
9 |
+ "github.com/docker/engine-api/types" |
|
9 | 10 |
"github.com/docker/engine-api/types/container" |
11 |
+ "github.com/docker/engine-api/types/strslice" |
|
12 |
+ "github.com/docker/go-connections/nat" |
|
10 | 13 |
) |
11 | 14 |
|
12 | 15 |
type commandWithFunction struct { |
... | ... |
@@ -206,3 +209,263 @@ func TestOnbuild(t *testing.T) { |
206 | 206 |
t.Fatalf("Wrong ONBUILD command. Expected: %s, got: %s", expectedOnbuild, b.runConfig.OnBuild[0]) |
207 | 207 |
} |
208 | 208 |
} |
209 |
+ |
|
210 |
+func TestWorkdir(t *testing.T) { |
|
211 |
+ b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true} |
|
212 |
+ |
|
213 |
+ workingDir := "/app" |
|
214 |
+ |
|
215 |
+ if runtime.GOOS == "windows" { |
|
216 |
+ workingDir = "C:\app" |
|
217 |
+ } |
|
218 |
+ |
|
219 |
+ err := workdir(b, []string{workingDir}, nil, "") |
|
220 |
+ |
|
221 |
+ if err != nil { |
|
222 |
+ t.Fatalf("Error should be empty, got: %s", err.Error()) |
|
223 |
+ } |
|
224 |
+ |
|
225 |
+ if b.runConfig.WorkingDir != workingDir { |
|
226 |
+ t.Fatalf("WorkingDir should be set to %s, got %s", workingDir, b.runConfig.WorkingDir) |
|
227 |
+ } |
|
228 |
+ |
|
229 |
+} |
|
230 |
+ |
|
231 |
+func TestCmd(t *testing.T) { |
|
232 |
+ b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true} |
|
233 |
+ |
|
234 |
+ command := "./executable" |
|
235 |
+ |
|
236 |
+ err := cmd(b, []string{command}, nil, "") |
|
237 |
+ |
|
238 |
+ if err != nil { |
|
239 |
+ t.Fatalf("Error should be empty, got: %s", err.Error()) |
|
240 |
+ } |
|
241 |
+ |
|
242 |
+ var expectedCommand strslice.StrSlice |
|
243 |
+ |
|
244 |
+ if runtime.GOOS == "windows" { |
|
245 |
+ expectedCommand = strslice.StrSlice(append([]string{"cmd"}, "/S", "/C", command)) |
|
246 |
+ } else { |
|
247 |
+ expectedCommand = strslice.StrSlice(append([]string{"/bin/sh"}, "-c", command)) |
|
248 |
+ } |
|
249 |
+ |
|
250 |
+ if !compareStrSlice(b.runConfig.Cmd, expectedCommand) { |
|
251 |
+ t.Fatalf("Command should be set to %s, got %s", command, b.runConfig.Cmd) |
|
252 |
+ } |
|
253 |
+ |
|
254 |
+ if !b.cmdSet { |
|
255 |
+ t.Fatalf("Command should be marked as set") |
|
256 |
+ } |
|
257 |
+} |
|
258 |
+ |
|
259 |
+func compareStrSlice(slice1, slice2 strslice.StrSlice) bool { |
|
260 |
+ if len(slice1) != len(slice2) { |
|
261 |
+ return false |
|
262 |
+ } |
|
263 |
+ |
|
264 |
+ for i := range slice1 { |
|
265 |
+ if slice1[i] != slice2[i] { |
|
266 |
+ return false |
|
267 |
+ } |
|
268 |
+ } |
|
269 |
+ |
|
270 |
+ return true |
|
271 |
+} |
|
272 |
+ |
|
273 |
+func TestHealthcheckNone(t *testing.T) { |
|
274 |
+ b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true} |
|
275 |
+ |
|
276 |
+ if err := healthcheck(b, []string{"NONE"}, nil, ""); err != nil { |
|
277 |
+ t.Fatalf("Error should be empty, got: %s", err.Error()) |
|
278 |
+ } |
|
279 |
+ |
|
280 |
+ if b.runConfig.Healthcheck == nil { |
|
281 |
+ t.Fatal("Healthcheck should be set, got nil") |
|
282 |
+ } |
|
283 |
+ |
|
284 |
+ expectedTest := strslice.StrSlice(append([]string{"NONE"})) |
|
285 |
+ |
|
286 |
+ if !compareStrSlice(expectedTest, b.runConfig.Healthcheck.Test) { |
|
287 |
+ t.Fatalf("Command should be set to %s, got %s", expectedTest, b.runConfig.Healthcheck.Test) |
|
288 |
+ } |
|
289 |
+} |
|
290 |
+ |
|
291 |
+func TestHealthcheckCmd(t *testing.T) { |
|
292 |
+ b := &Builder{flags: &BFlags{flags: make(map[string]*Flag)}, runConfig: &container.Config{}, disableCommit: true} |
|
293 |
+ |
|
294 |
+ if err := healthcheck(b, []string{"CMD", "curl", "-f", "http://localhost/", "||", "exit", "1"}, nil, ""); err != nil { |
|
295 |
+ t.Fatalf("Error should be empty, got: %s", err.Error()) |
|
296 |
+ } |
|
297 |
+ |
|
298 |
+ if b.runConfig.Healthcheck == nil { |
|
299 |
+ t.Fatal("Healthcheck should be set, got nil") |
|
300 |
+ } |
|
301 |
+ |
|
302 |
+ expectedTest := strslice.StrSlice(append([]string{"CMD-SHELL"}, "curl -f http://localhost/ || exit 1")) |
|
303 |
+ |
|
304 |
+ if !compareStrSlice(expectedTest, b.runConfig.Healthcheck.Test) { |
|
305 |
+ t.Fatalf("Command should be set to %s, got %s", expectedTest, b.runConfig.Healthcheck.Test) |
|
306 |
+ } |
|
307 |
+} |
|
308 |
+ |
|
309 |
+func TestEntrypoint(t *testing.T) { |
|
310 |
+ b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true} |
|
311 |
+ |
|
312 |
+ entrypointCmd := "/usr/sbin/nginx" |
|
313 |
+ |
|
314 |
+ if err := entrypoint(b, []string{entrypointCmd}, nil, ""); err != nil { |
|
315 |
+ t.Fatalf("Error should be empty, got: %s", err.Error()) |
|
316 |
+ } |
|
317 |
+ |
|
318 |
+ if b.runConfig.Entrypoint == nil { |
|
319 |
+ t.Fatalf("Entrypoint should be set") |
|
320 |
+ } |
|
321 |
+ |
|
322 |
+ var expectedEntrypoint strslice.StrSlice |
|
323 |
+ |
|
324 |
+ if runtime.GOOS == "windows" { |
|
325 |
+ expectedEntrypoint = strslice.StrSlice(append([]string{"cmd"}, "/S", "/C", entrypointCmd)) |
|
326 |
+ } else { |
|
327 |
+ expectedEntrypoint = strslice.StrSlice(append([]string{"/bin/sh"}, "-c", entrypointCmd)) |
|
328 |
+ } |
|
329 |
+ |
|
330 |
+ if !compareStrSlice(expectedEntrypoint, b.runConfig.Entrypoint) { |
|
331 |
+ t.Fatalf("Entrypoint command should be set to %s, got %s", expectedEntrypoint, b.runConfig.Entrypoint) |
|
332 |
+ } |
|
333 |
+} |
|
334 |
+ |
|
335 |
+func TestExpose(t *testing.T) { |
|
336 |
+ b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true} |
|
337 |
+ |
|
338 |
+ exposedPort := "80" |
|
339 |
+ |
|
340 |
+ if err := expose(b, []string{exposedPort}, nil, ""); err != nil { |
|
341 |
+ t.Fatalf("Error should be empty, got: %s", err.Error()) |
|
342 |
+ } |
|
343 |
+ |
|
344 |
+ if b.runConfig.ExposedPorts == nil { |
|
345 |
+ t.Fatalf("ExposedPorts should be set") |
|
346 |
+ } |
|
347 |
+ |
|
348 |
+ if len(b.runConfig.ExposedPorts) != 1 { |
|
349 |
+ t.Fatalf("ExposedPorts should contain only 1 element. Got %s", b.runConfig.ExposedPorts) |
|
350 |
+ } |
|
351 |
+ |
|
352 |
+ portsMapping, err := nat.ParsePortSpec(exposedPort) |
|
353 |
+ |
|
354 |
+ if err != nil { |
|
355 |
+ t.Fatalf("Error when parsing port spec: %s", err.Error()) |
|
356 |
+ } |
|
357 |
+ |
|
358 |
+ if _, ok := b.runConfig.ExposedPorts[portsMapping[0].Port]; !ok { |
|
359 |
+ t.Fatalf("Port %s should be present. Got %s", exposedPort, b.runConfig.ExposedPorts) |
|
360 |
+ } |
|
361 |
+} |
|
362 |
+ |
|
363 |
+func TestUser(t *testing.T) { |
|
364 |
+ b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true} |
|
365 |
+ |
|
366 |
+ userCommand := "foo" |
|
367 |
+ |
|
368 |
+ if err := user(b, []string{userCommand}, nil, ""); err != nil { |
|
369 |
+ t.Fatalf("Error should be empty, got: %s", err.Error()) |
|
370 |
+ } |
|
371 |
+ |
|
372 |
+ if b.runConfig.User != userCommand { |
|
373 |
+ t.Fatalf("User should be set to %s, got %s", userCommand, b.runConfig.User) |
|
374 |
+ } |
|
375 |
+} |
|
376 |
+ |
|
377 |
+func TestVolume(t *testing.T) { |
|
378 |
+ b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true} |
|
379 |
+ |
|
380 |
+ exposedVolume := "/foo" |
|
381 |
+ |
|
382 |
+ if err := volume(b, []string{exposedVolume}, nil, ""); err != nil { |
|
383 |
+ t.Fatalf("Error should be empty, got: %s", err.Error()) |
|
384 |
+ } |
|
385 |
+ |
|
386 |
+ if b.runConfig.Volumes == nil { |
|
387 |
+ t.Fatalf("Volumes should be set") |
|
388 |
+ } |
|
389 |
+ |
|
390 |
+ if len(b.runConfig.Volumes) != 1 { |
|
391 |
+ t.Fatalf("Volumes should contain only 1 element. Got %s", b.runConfig.Volumes) |
|
392 |
+ } |
|
393 |
+ |
|
394 |
+ if _, ok := b.runConfig.Volumes[exposedVolume]; !ok { |
|
395 |
+ t.Fatalf("Volume %s should be present. Got %s", exposedVolume, b.runConfig.Volumes) |
|
396 |
+ } |
|
397 |
+} |
|
398 |
+ |
|
399 |
+func TestStopSignal(t *testing.T) { |
|
400 |
+ b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true} |
|
401 |
+ |
|
402 |
+ signal := "SIGKILL" |
|
403 |
+ |
|
404 |
+ if err := stopSignal(b, []string{signal}, nil, ""); err != nil { |
|
405 |
+ t.Fatalf("Error should be empty, got: %s", err.Error()) |
|
406 |
+ } |
|
407 |
+ |
|
408 |
+ if b.runConfig.StopSignal != signal { |
|
409 |
+ t.Fatalf("StopSignal should be set to %s, got %s", signal, b.runConfig.StopSignal) |
|
410 |
+ } |
|
411 |
+} |
|
412 |
+ |
|
413 |
+func TestArg(t *testing.T) { |
|
414 |
+ buildOptions := &types.ImageBuildOptions{BuildArgs: make(map[string]string)} |
|
415 |
+ |
|
416 |
+ b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true, allowedBuildArgs: make(map[string]bool), options: buildOptions} |
|
417 |
+ |
|
418 |
+ argName := "foo" |
|
419 |
+ argVal := "bar" |
|
420 |
+ argDef := fmt.Sprintf("%s=%s", argName, argVal) |
|
421 |
+ |
|
422 |
+ if err := arg(b, []string{argDef}, nil, ""); err != nil { |
|
423 |
+ t.Fatalf("Error should be empty, got: %s", err.Error()) |
|
424 |
+ } |
|
425 |
+ |
|
426 |
+ allowed, ok := b.allowedBuildArgs[argName] |
|
427 |
+ |
|
428 |
+ if !ok { |
|
429 |
+ t.Fatalf("%s argument should be allowed as a build arg", argName) |
|
430 |
+ } |
|
431 |
+ |
|
432 |
+ if !allowed { |
|
433 |
+ t.Fatalf("%s argument was present in map but disallowed as a build arg", argName) |
|
434 |
+ } |
|
435 |
+ |
|
436 |
+ val, ok := b.options.BuildArgs[argName] |
|
437 |
+ |
|
438 |
+ if !ok { |
|
439 |
+ t.Fatalf("%s argument should be a build arg", argName) |
|
440 |
+ } |
|
441 |
+ |
|
442 |
+ if val != "bar" { |
|
443 |
+ t.Fatalf("%s argument should have default value 'bar', got %s", argName, val) |
|
444 |
+ } |
|
445 |
+} |
|
446 |
+ |
|
447 |
+func TestShell(t *testing.T) { |
|
448 |
+ b := &Builder{flags: &BFlags{}, runConfig: &container.Config{}, disableCommit: true} |
|
449 |
+ |
|
450 |
+ shellCmd := "powershell" |
|
451 |
+ |
|
452 |
+ attrs := make(map[string]bool) |
|
453 |
+ attrs["json"] = true |
|
454 |
+ |
|
455 |
+ if err := shell(b, []string{shellCmd}, attrs, ""); err != nil { |
|
456 |
+ t.Fatalf("Error should be empty, got: %s", err.Error()) |
|
457 |
+ } |
|
458 |
+ |
|
459 |
+ if b.runConfig.Shell == nil { |
|
460 |
+ t.Fatalf("Shell should be set") |
|
461 |
+ } |
|
462 |
+ |
|
463 |
+ expectedShell := strslice.StrSlice([]string{shellCmd}) |
|
464 |
+ |
|
465 |
+ if !compareStrSlice(expectedShell, b.runConfig.Shell) { |
|
466 |
+ t.Fatalf("Shell should be set to %s, got %s", expectedShell, b.runConfig.Shell) |
|
467 |
+ } |
|
468 |
+} |
209 | 469 |
new file mode 100644 |
... | ... |
@@ -0,0 +1,33 @@ |
0 |
+// +build !windows |
|
1 |
+ |
|
2 |
+package dockerfile |
|
3 |
+ |
|
4 |
+import ( |
|
5 |
+ "testing" |
|
6 |
+) |
|
7 |
+ |
|
8 |
+func TestNormaliseWorkdir(t *testing.T) { |
|
9 |
+ testCases := []struct{ current, requested, expected, expectedError string }{ |
|
10 |
+ {``, ``, ``, `cannot normalise nothing`}, |
|
11 |
+ {``, `foo`, `/foo`, ``}, |
|
12 |
+ {``, `/foo`, `/foo`, ``}, |
|
13 |
+ {`/foo`, `bar`, `/foo/bar`, ``}, |
|
14 |
+ {`/foo`, `/bar`, `/bar`, ``}, |
|
15 |
+ } |
|
16 |
+ |
|
17 |
+ for _, test := range testCases { |
|
18 |
+ normalised, err := normaliseWorkdir(test.current, test.requested) |
|
19 |
+ |
|
20 |
+ if test.expectedError != "" && err == nil { |
|
21 |
+ t.Fatalf("NormaliseWorkdir should return an error %s, got nil", test.expectedError) |
|
22 |
+ } |
|
23 |
+ |
|
24 |
+ if test.expectedError != "" && err.Error() != test.expectedError { |
|
25 |
+ t.Fatalf("NormaliseWorkdir returned wrong error. Expected %s, got %s", test.expectedError, err.Error()) |
|
26 |
+ } |
|
27 |
+ |
|
28 |
+ if normalised != test.expected { |
|
29 |
+ t.Fatalf("NormaliseWorkdir error. Expected %s for current %s and requested %s, got %s", test.expected, test.current, test.requested, normalised) |
|
30 |
+ } |
|
31 |
+ } |
|
32 |
+} |
... | ... |
@@ -34,52 +34,25 @@ func TestSymlinkDockerfile(t *testing.T) { |
34 | 34 |
readAndCheckDockerfile(t, "symlinkDockerfile", contextDir, builder.DefaultDockerfileName, expectedError) |
35 | 35 |
} |
36 | 36 |
|
37 |
-func readAndCheckDockerfile(t *testing.T, testName, contextDir, dockerfilePath, expectedError string) { |
|
38 |
- tarStream, err := archive.Tar(contextDir, archive.Uncompressed) |
|
39 |
- |
|
40 |
- if err != nil { |
|
41 |
- t.Fatalf("Error when creating tar stream: %s", err) |
|
42 |
- } |
|
43 |
- |
|
44 |
- defer func() { |
|
45 |
- if err = tarStream.Close(); err != nil { |
|
46 |
- t.Fatalf("Error when closing tar stream: %s", err) |
|
47 |
- } |
|
48 |
- }() |
|
49 |
- |
|
50 |
- context, err := builder.MakeTarSumContext(tarStream) |
|
51 |
- |
|
52 |
- if err != nil { |
|
53 |
- t.Fatalf("Error when creating tar context: %s", err) |
|
54 |
- } |
|
55 |
- |
|
56 |
- defer func() { |
|
57 |
- if err = context.Close(); err != nil { |
|
58 |
- t.Fatalf("Error when closing tar context: %s", err) |
|
59 |
- } |
|
60 |
- }() |
|
61 |
- |
|
62 |
- options := &types.ImageBuildOptions{ |
|
63 |
- Dockerfile: dockerfilePath, |
|
64 |
- } |
|
65 |
- |
|
66 |
- b := &Builder{options: options, context: context} |
|
67 |
- |
|
68 |
- err = b.readDockerfile() |
|
37 |
+func TestDockerfileOutsideTheBuildContext(t *testing.T) { |
|
38 |
+ contextDir, cleanup := createTestTempDir(t, "", "builder-dockerfile-test") |
|
39 |
+ defer cleanup() |
|
69 | 40 |
|
70 |
- if err == nil { |
|
71 |
- t.Fatalf("No error when executing test: %s", testName) |
|
72 |
- } |
|
41 |
+ expectedError := "Forbidden path outside the build context" |
|
73 | 42 |
|
74 |
- if !strings.Contains(err.Error(), expectedError) { |
|
75 |
- t.Fatalf("Wrong error message. Should be \"%s\". Got \"%s\"", expectedError, err.Error()) |
|
76 |
- } |
|
43 |
+ readAndCheckDockerfile(t, "DockerfileOutsideTheBuildContext", contextDir, "../../Dockerfile", expectedError) |
|
77 | 44 |
} |
78 | 45 |
|
79 |
-func TestDockerfileOutsideTheBuildContext(t *testing.T) { |
|
46 |
+func TestNonExistingDockerfile(t *testing.T) { |
|
80 | 47 |
contextDir, cleanup := createTestTempDir(t, "", "builder-dockerfile-test") |
81 | 48 |
defer cleanup() |
82 | 49 |
|
50 |
+ expectedError := "Cannot locate specified Dockerfile: Dockerfile" |
|
51 |
+ |
|
52 |
+ readAndCheckDockerfile(t, "NonExistingDockerfile", contextDir, "Dockerfile", expectedError) |
|
53 |
+} |
|
54 |
+ |
|
55 |
+func readAndCheckDockerfile(t *testing.T, testName, contextDir, dockerfilePath, expectedError string) { |
|
83 | 56 |
tarStream, err := archive.Tar(contextDir, archive.Uncompressed) |
84 | 57 |
|
85 | 58 |
if err != nil { |
... | ... |
@@ -105,7 +78,7 @@ func TestDockerfileOutsideTheBuildContext(t *testing.T) { |
105 | 105 |
}() |
106 | 106 |
|
107 | 107 |
options := &types.ImageBuildOptions{ |
108 |
- Dockerfile: "../../Dockerfile", |
|
108 |
+ Dockerfile: dockerfilePath, |
|
109 | 109 |
} |
110 | 110 |
|
111 | 111 |
b := &Builder{options: options, context: context} |
... | ... |
@@ -113,11 +86,9 @@ func TestDockerfileOutsideTheBuildContext(t *testing.T) { |
113 | 113 |
err = b.readDockerfile() |
114 | 114 |
|
115 | 115 |
if err == nil { |
116 |
- t.Fatalf("No error when executing test for Dockerfile outside the build context") |
|
116 |
+ t.Fatalf("No error when executing test: %s", testName) |
|
117 | 117 |
} |
118 | 118 |
|
119 |
- expectedError := "Forbidden path outside the build context" |
|
120 |
- |
|
121 | 119 |
if !strings.Contains(err.Error(), expectedError) { |
122 | 120 |
t.Fatalf("Wrong error message. Should be \"%s\". Got \"%s\"", expectedError, err.Error()) |
123 | 121 |
} |