Browse code

Builder dispatchers unit tests

Signed-off-by: Tomasz Kopczynski <tomek@kopczynski.net.pl>

Tomasz Kopczynski authored on 2016/06/27 05:01:28
Showing 3 changed files
... ...
@@ -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
 	}