Browse code

initial version of cli integration tests

Docker-DCO-1.1-Signed-off-by: Cristian Staretu <cristian.staretu@gmail.com> (github: unclejack)

unclejack authored on 2014/02/26 01:17:48
Showing 22 changed files
... ...
@@ -1,4 +1,4 @@
1
-.PHONY: all binary build cross default docs docs-build docs-shell shell test test-integration
1
+.PHONY: all binary build cross default docs docs-build docs-shell shell test test-integration test-integration-cli
2 2
 
3 3
 GIT_BRANCH := $(shell git rev-parse --abbrev-ref HEAD)
4 4
 DOCKER_IMAGE := docker:$(GIT_BRANCH)
... ...
@@ -23,11 +23,14 @@ docs-shell: docs-build
23 23
 	docker run --rm -i -t -p 8000:8000 "$(DOCKER_DOCS_IMAGE)" bash
24 24
 
25 25
 test: build
26
-	$(DOCKER_RUN_DOCKER) hack/make.sh test test-integration
26
+	$(DOCKER_RUN_DOCKER) hack/make.sh binary test test-integration test-integration-cli
27 27
 
28 28
 test-integration: build
29 29
 	$(DOCKER_RUN_DOCKER) hack/make.sh test-integration
30 30
 
31
+test-integration-cli: build
32
+	$(DOCKER_RUN_DOCKER) hack/make.sh binary test-integration-cli
33
+
31 34
 shell: build
32 35
 	$(DOCKER_RUN_DOCKER) bash
33 36
 
... ...
@@ -139,6 +139,7 @@ find_dirs() {
139 139
 		\( \
140 140
 			-wholename './vendor' \
141 141
 			-o -wholename './integration' \
142
+			-o -wholename './integration-cli' \
142 143
 			-o -wholename './contrib' \
143 144
 			-o -wholename './pkg/mflag/example' \
144 145
 			-o -wholename './.git' \
145 146
new file mode 100644
... ...
@@ -0,0 +1,37 @@
0
+#!/bin/bash
1
+
2
+DEST=$1
3
+DOCKERBIN=$DEST/../binary/docker-$VERSION
4
+DYNDOCKERBIN=$DEST/../dynbinary/docker-$VERSION
5
+DOCKERINITBIN=$DEST/../dynbinary/dockerinit-$VERSION
6
+
7
+set -e
8
+
9
+bundle_test_integration_cli() {
10
+	go_test_dir ./integration-cli
11
+}
12
+
13
+if [ -x "/usr/bin/docker" ]; then
14
+	echo "docker found at /usr/bin/docker"
15
+elif [ -x "$DOCKERBIN" ]; then
16
+	ln -s $DOCKERBIN /usr/bin/docker
17
+elif [ -x "$DYNDOCKERBIN" ]; then
18
+	ln -s $DYNDOCKERBIN /usr/bin/docker
19
+	ln -s $DOCKERINITBIN /usr/bin/dockerinit
20
+else
21
+	echo >&2 'error: binary or dynbinary must be run before test-integration-cli'
22
+	false
23
+fi
24
+
25
+
26
+docker -d -D -p $DEST/docker.pid &> $DEST/docker.log &
27
+sleep 2
28
+docker info
29
+DOCKERD_PID=`cat $DEST/docker.pid`
30
+
31
+bundle_test_integration_cli 2>&1 \
32
+	| tee $DEST/test.log
33
+
34
+kill $DOCKERD_PID
35
+wait $DOCKERD_PID
36
+
0 37
new file mode 100644
... ...
@@ -0,0 +1,60 @@
0
+FROM busybox
1
+RUN echo "foo"
2
+RUN echo "foo"
3
+RUN echo "foo"
4
+RUN echo "foo"
5
+RUN echo "foo"
6
+RUN echo "foo"
7
+RUN echo "foo"
8
+RUN echo "foo"
9
+RUN echo "foo"
10
+RUN echo "foo"
11
+RUN echo "foo"
12
+RUN echo "foo"
13
+RUN echo "foo"
14
+RUN echo "foo"
15
+RUN echo "foo"
16
+RUN echo "foo"
17
+RUN echo "foo"
18
+RUN echo "foo"
19
+RUN echo "foo"
20
+RUN echo "foo"
21
+RUN echo "foo"
22
+RUN echo "foo"
23
+RUN echo "foo"
24
+RUN echo "foo"
25
+RUN echo "foo"
26
+RUN echo "foo"
27
+RUN echo "foo"
28
+RUN echo "foo"
29
+RUN echo "foo"
30
+RUN echo "foo"
31
+RUN echo "foo"
32
+RUN echo "foo"
33
+RUN echo "foo"
34
+RUN echo "foo"
35
+RUN echo "foo"
36
+RUN echo "foo"
37
+RUN echo "foo"
38
+RUN echo "foo"
39
+RUN echo "foo"
40
+RUN echo "foo"
41
+RUN echo "foo"
42
+RUN echo "foo"
43
+RUN echo "foo"
44
+RUN echo "foo"
45
+RUN echo "foo"
46
+RUN echo "foo"
47
+RUN echo "foo"
48
+RUN echo "foo"
49
+RUN echo "foo"
50
+RUN echo "foo"
51
+RUN echo "foo"
52
+RUN echo "foo"
53
+RUN echo "foo"
54
+RUN echo "foo"
55
+RUN echo "foo"
56
+RUN echo "foo"
57
+RUN echo "foo"
58
+RUN echo "foo"
59
+RUN echo "foo"
0 60
new file mode 100644
... ...
@@ -0,0 +1,28 @@
0
+package main
1
+
2
+import (
3
+	"fmt"
4
+	"os/exec"
5
+	"path/filepath"
6
+	"testing"
7
+)
8
+
9
+func TestBuildSixtySteps(t *testing.T) {
10
+	buildDirectory := filepath.Join(workingDirectory, "build_tests", "TestBuildSixtySteps")
11
+	buildCmd := exec.Command(dockerBinary, "build", "-t", "foobuildsixtysteps", ".")
12
+	buildCmd.Dir = buildDirectory
13
+	out, exitCode, err := runCommandWithOutput(buildCmd)
14
+	errorOut(err, t, fmt.Sprintf("build failed to complete: %v %v", out, err))
15
+
16
+	if err != nil || exitCode != 0 {
17
+		t.Fatal("failed to build the image")
18
+	}
19
+
20
+	go deleteImages("foobuildsixtysteps")
21
+
22
+	logDone("build - build an image with sixty build steps")
23
+}
24
+
25
+// TODO: TestCaching
26
+
27
+// TODO: TestADDCacheInvalidation
0 28
new file mode 100644
... ...
@@ -0,0 +1,34 @@
0
+package main
1
+
2
+import (
3
+	"fmt"
4
+	"os/exec"
5
+	"testing"
6
+)
7
+
8
+func TestCommitAfterContainerIsDone(t *testing.T) {
9
+	runCmd := exec.Command(dockerBinary, "run", "-i", "-a", "stdin", "busybox", "echo", "foo")
10
+	out, _, _, err := runCommandWithStdoutStderr(runCmd)
11
+	errorOut(err, t, fmt.Sprintf("failed to run container: %v %v", out, err))
12
+
13
+	cleanedContainerID := stripTrailingCharacters(out)
14
+
15
+	waitCmd := exec.Command(dockerBinary, "wait", cleanedContainerID)
16
+	_, _, err = runCommandWithOutput(waitCmd)
17
+	errorOut(err, t, fmt.Sprintf("error thrown while waiting for container: %s", out))
18
+
19
+	commitCmd := exec.Command(dockerBinary, "commit", cleanedContainerID)
20
+	out, _, err = runCommandWithOutput(commitCmd)
21
+	errorOut(err, t, fmt.Sprintf("failed to commit container to image: %v %v", out, err))
22
+
23
+	cleanedImageID := stripTrailingCharacters(out)
24
+
25
+	inspectCmd := exec.Command(dockerBinary, "inspect", cleanedImageID)
26
+	out, _, err = runCommandWithOutput(inspectCmd)
27
+	errorOut(err, t, fmt.Sprintf("failed to inspect image: %v %v", out, err))
28
+
29
+	go deleteContainer(cleanedContainerID)
30
+	go deleteImages(cleanedImageID)
31
+
32
+	logDone("commit - echo foo and commit the image")
33
+}
0 34
new file mode 100644
... ...
@@ -0,0 +1,66 @@
0
+package main
1
+
2
+import (
3
+	"fmt"
4
+	"os/exec"
5
+	"strings"
6
+	"testing"
7
+)
8
+
9
+// ensure that an added file shows up in docker diff
10
+func TestDiffFilenameShownInOutput(t *testing.T) {
11
+	containerCmd := `echo foo > /root/bar`
12
+	runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", containerCmd)
13
+	cid, _, err := runCommandWithOutput(runCmd)
14
+	errorOut(err, t, fmt.Sprintf("failed to start the container: %v", err))
15
+
16
+	cleanCID := stripTrailingCharacters(cid)
17
+
18
+	diffCmd := exec.Command(dockerBinary, "diff", cleanCID)
19
+	out, _, err := runCommandWithOutput(diffCmd)
20
+	errorOut(err, t, fmt.Sprintf("failed to run diff: %v %v", out, err))
21
+
22
+	found := false
23
+	for _, line := range strings.Split(out, "\n") {
24
+		if strings.Contains("A /root/bar", line) {
25
+			found = true
26
+			break
27
+		}
28
+	}
29
+	if !found {
30
+		t.Errorf("couldn't find the new file in docker diff's output: %v", out)
31
+	}
32
+	go deleteContainer(cleanCID)
33
+
34
+	logDone("diff - check if created file shows up")
35
+}
36
+
37
+// test to ensure GH #3840 doesn't occur any more
38
+func TestDiffEnsureDockerinitFilesAreIgnored(t *testing.T) {
39
+	// this is a list of files which shouldn't show up in `docker diff`
40
+	dockerinitFiles := []string{"/etc/resolv.conf", "/etc/hostname", "/etc/hosts", "/.dockerinit", "/.dockerenv"}
41
+
42
+	// we might not run into this problem from the first run, so start a few containers
43
+	for i := 0; i < 20; i++ {
44
+		containerCmd := `echo foo > /root/bar`
45
+		runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", containerCmd)
46
+		cid, _, err := runCommandWithOutput(runCmd)
47
+		errorOut(err, t, fmt.Sprintf("%s", err))
48
+
49
+		cleanCID := stripTrailingCharacters(cid)
50
+
51
+		diffCmd := exec.Command(dockerBinary, "diff", cleanCID)
52
+		out, _, err := runCommandWithOutput(diffCmd)
53
+		errorOut(err, t, fmt.Sprintf("failed to run diff: %v %v", out, err))
54
+
55
+		go deleteContainer(cleanCID)
56
+
57
+		for _, filename := range dockerinitFiles {
58
+			if strings.Contains(out, filename) {
59
+				t.Errorf("found file which should've been ignored %v in diff output", filename)
60
+			}
61
+		}
62
+	}
63
+
64
+	logDone("diff - check if ignored files show up in diff")
65
+}
0 66
new file mode 100644
... ...
@@ -0,0 +1,50 @@
0
+package main
1
+
2
+import (
3
+	"fmt"
4
+	"os"
5
+	"os/exec"
6
+	"testing"
7
+)
8
+
9
+// export an image and try to import it into a new one
10
+func TestExportContainerAndImportImage(t *testing.T) {
11
+	runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true")
12
+	out, _, err := runCommandWithOutput(runCmd)
13
+	if err != nil {
14
+		t.Fatal("failed to create a container", out, err)
15
+	}
16
+
17
+	cleanedContainerID := stripTrailingCharacters(out)
18
+
19
+	inspectCmd := exec.Command(dockerBinary, "inspect", cleanedContainerID)
20
+	out, _, err = runCommandWithOutput(inspectCmd)
21
+	if err != nil {
22
+		t.Fatalf("output should've been a container id: %s %s ", cleanedContainerID, err)
23
+	}
24
+
25
+	exportCmdTemplate := `%v export %v > /tmp/testexp.tar`
26
+	exportCmdFinal := fmt.Sprintf(exportCmdTemplate, dockerBinary, cleanedContainerID)
27
+	exportCmd := exec.Command("bash", "-c", exportCmdFinal)
28
+	out, _, err = runCommandWithOutput(exportCmd)
29
+	errorOut(err, t, fmt.Sprintf("failed to export container: %v %v", out, err))
30
+
31
+	importCmdFinal := `cat /tmp/testexp.tar | docker import - testexp`
32
+	importCmd := exec.Command("bash", "-c", importCmdFinal)
33
+	out, _, err = runCommandWithOutput(importCmd)
34
+	errorOut(err, t, fmt.Sprintf("failed to import image: %v %v", out, err))
35
+
36
+	cleanedImageID := stripTrailingCharacters(out)
37
+
38
+	inspectCmd = exec.Command(dockerBinary, "inspect", cleanedImageID)
39
+	out, _, err = runCommandWithOutput(inspectCmd)
40
+	errorOut(err, t, fmt.Sprintf("output should've been an image id: %v %v", out, err))
41
+
42
+	go deleteImages("testexp")
43
+	go deleteContainer(cleanedContainerID)
44
+
45
+	os.Remove("/tmp/testexp.tar")
46
+
47
+	logDone("export - export a container")
48
+	logDone("import - import an image")
49
+}
0 50
new file mode 100644
... ...
@@ -0,0 +1,20 @@
0
+package main
1
+
2
+import (
3
+	"fmt"
4
+	"os/exec"
5
+	"strings"
6
+	"testing"
7
+)
8
+
9
+func TestImagesEnsureImageIsListed(t *testing.T) {
10
+	imagesCmd := exec.Command(dockerBinary, "images")
11
+	out, _, err := runCommandWithOutput(imagesCmd)
12
+	errorOut(err, t, fmt.Sprintf("listing images failed with errors: %v", err))
13
+
14
+	if !strings.Contains(out, "busybox") {
15
+		t.Fatal("images should've listed busybox")
16
+	}
17
+
18
+	logDone("images - busybox should be listed")
19
+}
0 20
new file mode 100644
... ...
@@ -0,0 +1,29 @@
0
+package main
1
+
2
+import (
3
+	"fmt"
4
+	"os/exec"
5
+	"strings"
6
+	"testing"
7
+)
8
+
9
+// ensure docker info succeeds
10
+func TestInfoEnsureSucceeds(t *testing.T) {
11
+	versionCmd := exec.Command(dockerBinary, "info")
12
+	out, exitCode, err := runCommandWithOutput(versionCmd)
13
+	errorOut(err, t, fmt.Sprintf("encountered error while running docker info: %v", err))
14
+
15
+	if err != nil || exitCode != 0 {
16
+		t.Fatal("failed to execute docker info")
17
+	}
18
+
19
+	stringsToCheck := []string{"Containers:", "Execution Driver:", "Kernel Version:"}
20
+
21
+	for _, linePrefix := range stringsToCheck {
22
+		if !strings.Contains(out, linePrefix) {
23
+			t.Errorf("couldn't find string %v in output", linePrefix)
24
+		}
25
+	}
26
+
27
+	logDone("info - verify that it works")
28
+}
0 29
new file mode 100644
... ...
@@ -0,0 +1,36 @@
0
+package main
1
+
2
+import (
3
+	"fmt"
4
+	"os/exec"
5
+	"strings"
6
+	"testing"
7
+)
8
+
9
+func TestKillContainer(t *testing.T) {
10
+	runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", "sleep 10")
11
+	out, _, err := runCommandWithOutput(runCmd)
12
+	errorOut(err, t, fmt.Sprintf("run failed with errors: %v", err))
13
+
14
+	cleanedContainerID := stripTrailingCharacters(out)
15
+
16
+	inspectCmd := exec.Command(dockerBinary, "inspect", cleanedContainerID)
17
+	inspectOut, _, err := runCommandWithOutput(inspectCmd)
18
+	errorOut(err, t, fmt.Sprintf("out should've been a container id: %v %v", inspectOut, err))
19
+
20
+	killCmd := exec.Command(dockerBinary, "kill", cleanedContainerID)
21
+	out, _, err = runCommandWithOutput(killCmd)
22
+	errorOut(err, t, fmt.Sprintf("failed to kill container: %v %v", out, err))
23
+
24
+	listRunningContainersCmd := exec.Command(dockerBinary, "ps", "-q")
25
+	out, _, err = runCommandWithOutput(listRunningContainersCmd)
26
+	errorOut(err, t, fmt.Sprintf("failed to list running containers: %v", err))
27
+
28
+	if strings.Contains(out, cleanedContainerID) {
29
+		t.Fatal("killed container is still running")
30
+	}
31
+
32
+	go deleteContainer(cleanedContainerID)
33
+
34
+	logDone("kill - kill container running sleep 10")
35
+}
0 36
new file mode 100644
... ...
@@ -0,0 +1,30 @@
0
+package main
1
+
2
+import (
3
+	"fmt"
4
+	"os/exec"
5
+	"testing"
6
+)
7
+
8
+// pulling an image from the central registry should work
9
+func TestPullImageFromCentralRegistry(t *testing.T) {
10
+	pullCmd := exec.Command(dockerBinary, "pull", "busybox")
11
+	out, exitCode, err := runCommandWithOutput(pullCmd)
12
+	errorOut(err, t, fmt.Sprintf("%s %s", out, err))
13
+
14
+	if err != nil || exitCode != 0 {
15
+		t.Fatal("pulling the busybox image from the registry has failed")
16
+	}
17
+	logDone("pull - pull busybox")
18
+}
19
+
20
+// pulling a non-existing image from the central registry should return a non-zero exit code
21
+func TestPullNonExistingImage(t *testing.T) {
22
+	pullCmd := exec.Command(dockerBinary, "pull", "fooblahblah1234")
23
+	_, exitCode, err := runCommandWithOutput(pullCmd)
24
+
25
+	if err == nil || exitCode == 0 {
26
+		t.Fatal("expected non-zero exit status when pulling non-existing image")
27
+	}
28
+	logDone("pull - pull fooblahblah1234 (non-existing image)")
29
+}
0 30
new file mode 100644
... ...
@@ -0,0 +1,48 @@
0
+package main
1
+
2
+import (
3
+	"fmt"
4
+	"os/exec"
5
+	"testing"
6
+)
7
+
8
+// these tests need a freshly started empty private docker registry
9
+
10
+// pulling an image from the central registry should work
11
+func TestPushBusyboxImage(t *testing.T) {
12
+	// skip this test until we're able to use a registry
13
+	t.Skip()
14
+	// tag the image to upload it tot he private registry
15
+	repoName := fmt.Sprintf("%v/busybox", privateRegistryURL)
16
+	tagCmd := exec.Command(dockerBinary, "tag", "busybox", repoName)
17
+	out, exitCode, err := runCommandWithOutput(tagCmd)
18
+	errorOut(err, t, fmt.Sprintf("%v %v", out, err))
19
+
20
+	if err != nil || exitCode != 0 {
21
+		t.Fatal("image tagging failed")
22
+	}
23
+
24
+	pushCmd := exec.Command(dockerBinary, "push", repoName)
25
+	out, exitCode, err = runCommandWithOutput(pushCmd)
26
+	errorOut(err, t, fmt.Sprintf("%v %v", out, err))
27
+
28
+	go deleteImages(repoName)
29
+
30
+	if err != nil || exitCode != 0 {
31
+		t.Fatal("pushing the image to the private registry has failed")
32
+	}
33
+	logDone("push - push busybox to private registry")
34
+}
35
+
36
+// pushing an image without a prefix should throw an error
37
+func TestPushUnprefixedRepo(t *testing.T) {
38
+	// skip this test until we're able to use a registry
39
+	t.Skip()
40
+	pushCmd := exec.Command(dockerBinary, "push", "busybox")
41
+	_, exitCode, err := runCommandWithOutput(pushCmd)
42
+
43
+	if err == nil || exitCode == 0 {
44
+		t.Fatal("pushing an unprefixed repo didn't result in a non-zero exit status")
45
+	}
46
+	logDone("push - push unprefixed busybox repo --> must fail")
47
+}
0 48
new file mode 100644
... ...
@@ -0,0 +1,255 @@
0
+package main
1
+
2
+import (
3
+	"fmt"
4
+	"os/exec"
5
+	"strings"
6
+	"testing"
7
+)
8
+
9
+// "test123" should be printed by docker run
10
+func TestDockerRunEchoStdout(t *testing.T) {
11
+	runCmd := exec.Command(dockerBinary, "run", "busybox", "echo", "test123")
12
+	out, _, _, err := runCommandWithStdoutStderr(runCmd)
13
+	errorOut(err, t, out)
14
+
15
+	if out != "test123\n" {
16
+		t.Errorf("container should've printed 'test123'")
17
+	}
18
+
19
+	deleteAllContainers()
20
+
21
+	logDone("run - echo test123")
22
+}
23
+
24
+// "test" should be printed
25
+func TestDockerRunEchoStdoutWithMemoryLimit(t *testing.T) {
26
+	runCmd := exec.Command(dockerBinary, "run", "-m", "2786432", "busybox", "echo", "test")
27
+	out, _, _, err := runCommandWithStdoutStderr(runCmd)
28
+	errorOut(err, t, out)
29
+
30
+	if out != "test\n" {
31
+		t.Errorf("container should've printed 'test'")
32
+
33
+	}
34
+
35
+	deleteAllContainers()
36
+
37
+	logDone("run - echo with memory limit")
38
+}
39
+
40
+// "test" should be printed
41
+func TestDockerRunEchoStdoutWitCPULimit(t *testing.T) {
42
+	runCmd := exec.Command(dockerBinary, "run", "-c", "1000", "busybox", "echo", "test")
43
+	out, _, _, err := runCommandWithStdoutStderr(runCmd)
44
+	errorOut(err, t, out)
45
+
46
+	if out != "test\n" {
47
+		t.Errorf("container should've printed 'test'")
48
+	}
49
+
50
+	deleteAllContainers()
51
+
52
+	logDone("run - echo with CPU limit")
53
+}
54
+
55
+// "test" should be printed
56
+func TestDockerRunEchoStdoutWithCPUAndMemoryLimit(t *testing.T) {
57
+	runCmd := exec.Command(dockerBinary, "run", "-c", "1000", "-m", "2786432", "busybox", "echo", "test")
58
+	out, _, _, err := runCommandWithStdoutStderr(runCmd)
59
+	errorOut(err, t, out)
60
+
61
+	if out != "test\n" {
62
+		t.Errorf("container should've printed 'test'")
63
+	}
64
+
65
+	deleteAllContainers()
66
+
67
+	logDone("run - echo with CPU and memory limit")
68
+}
69
+
70
+// "test" should be printed
71
+func TestDockerRunEchoNamedContainer(t *testing.T) {
72
+	runCmd := exec.Command(dockerBinary, "run", "--name", "testfoonamedcontainer", "busybox", "echo", "test")
73
+	out, _, _, err := runCommandWithStdoutStderr(runCmd)
74
+	errorOut(err, t, out)
75
+
76
+	if out != "test\n" {
77
+		t.Errorf("container should've printed 'test'")
78
+	}
79
+
80
+	if err := deleteContainer("testfoonamedcontainer"); err != nil {
81
+		t.Errorf("failed to remove the named container: %v", err)
82
+	}
83
+
84
+	deleteAllContainers()
85
+
86
+	logDone("run - echo with named container")
87
+}
88
+
89
+// it should be possible to ping Google DNS resolver
90
+// this will fail when Internet access is unavailable
91
+func TestDockerRunPingGoogle(t *testing.T) {
92
+	runCmd := exec.Command(dockerBinary, "run", "busybox", "ping", "-c", "1", "8.8.8.8")
93
+	out, _, _, err := runCommandWithStdoutStderr(runCmd)
94
+	errorOut(err, t, out)
95
+
96
+	errorOut(err, t, "container should've been able to ping 8.8.8.8")
97
+
98
+	deleteAllContainers()
99
+
100
+	logDone("run - ping 8.8.8.8")
101
+}
102
+
103
+// the exit code should be 0
104
+// some versions of lxc might make this test fail
105
+func TestDockerRunExitCodeZero(t *testing.T) {
106
+	runCmd := exec.Command(dockerBinary, "run", "busybox", "true")
107
+	exitCode, err := runCommand(runCmd)
108
+	errorOut(err, t, fmt.Sprintf("%s", err))
109
+
110
+	if exitCode != 0 {
111
+		t.Errorf("container should've exited with exit code 0")
112
+	}
113
+
114
+	deleteAllContainers()
115
+
116
+	logDone("run - exit with 0")
117
+}
118
+
119
+// the exit code should be 1
120
+// some versions of lxc might make this test fail
121
+func TestDockerRunExitCodeOne(t *testing.T) {
122
+	runCmd := exec.Command(dockerBinary, "run", "busybox", "false")
123
+	exitCode, err := runCommand(runCmd)
124
+	if err != nil && !strings.Contains("exit status 1", fmt.Sprintf("%s", err)) {
125
+		t.Fatal(err)
126
+	}
127
+	if exitCode != 1 {
128
+		t.Errorf("container should've exited with exit code 1")
129
+	}
130
+
131
+	deleteAllContainers()
132
+
133
+	logDone("run - exit with 1")
134
+}
135
+
136
+// it should be possible to pipe in data via stdin to a process running in a container
137
+// some versions of lxc might make this test fail
138
+func TestRunStdinPipe(t *testing.T) {
139
+	runCmd := exec.Command("bash", "-c", `echo "blahblah" | docker run -i -a stdin busybox cat`)
140
+	out, _, _, err := runCommandWithStdoutStderr(runCmd)
141
+	errorOut(err, t, out)
142
+
143
+	out = stripTrailingCharacters(out)
144
+
145
+	inspectCmd := exec.Command(dockerBinary, "inspect", out)
146
+	inspectOut, _, err := runCommandWithOutput(inspectCmd)
147
+	errorOut(err, t, fmt.Sprintf("out should've been a container id: %s %s", out, inspectOut))
148
+
149
+	waitCmd := exec.Command(dockerBinary, "wait", out)
150
+	_, _, err = runCommandWithOutput(waitCmd)
151
+	errorOut(err, t, fmt.Sprintf("error thrown while waiting for container: %s", out))
152
+
153
+	logsCmd := exec.Command(dockerBinary, "logs", out)
154
+	containerLogs, _, err := runCommandWithOutput(logsCmd)
155
+	errorOut(err, t, fmt.Sprintf("error thrown while trying to get container logs: %s", err))
156
+
157
+	containerLogs = stripTrailingCharacters(containerLogs)
158
+
159
+	if containerLogs != "blahblah" {
160
+		t.Errorf("logs didn't print the container's logs %s", containerLogs)
161
+	}
162
+
163
+	rmCmd := exec.Command(dockerBinary, "rm", out)
164
+	_, _, err = runCommandWithOutput(rmCmd)
165
+	errorOut(err, t, fmt.Sprintf("rm failed to remove container %s", err))
166
+
167
+	deleteAllContainers()
168
+
169
+	logDone("run - pipe in with -i -a stdin")
170
+}
171
+
172
+// the container's ID should be printed when starting a container in detached mode
173
+func TestDockerRunDetachedContainerIDPrinting(t *testing.T) {
174
+	runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true")
175
+	out, _, _, err := runCommandWithStdoutStderr(runCmd)
176
+	errorOut(err, t, out)
177
+
178
+	out = stripTrailingCharacters(out)
179
+
180
+	inspectCmd := exec.Command(dockerBinary, "inspect", out)
181
+	inspectOut, _, err := runCommandWithOutput(inspectCmd)
182
+	errorOut(err, t, fmt.Sprintf("out should've been a container id: %s %s", out, inspectOut))
183
+
184
+	waitCmd := exec.Command(dockerBinary, "wait", out)
185
+	_, _, err = runCommandWithOutput(waitCmd)
186
+	errorOut(err, t, fmt.Sprintf("error thrown while waiting for container: %s", out))
187
+
188
+	rmCmd := exec.Command(dockerBinary, "rm", out)
189
+	rmOut, _, err := runCommandWithOutput(rmCmd)
190
+	errorOut(err, t, "rm failed to remove container")
191
+
192
+	rmOut = stripTrailingCharacters(rmOut)
193
+	if rmOut != out {
194
+		t.Errorf("rm didn't print the container ID %s %s", out, rmOut)
195
+	}
196
+
197
+	deleteAllContainers()
198
+
199
+	logDone("run - print container ID in detached mode")
200
+}
201
+
202
+// the working directory should be set correctly
203
+func TestDockerRunWorkingDirectory(t *testing.T) {
204
+	runCmd := exec.Command(dockerBinary, "run", "-w", "/root", "busybox", "pwd")
205
+	out, _, _, err := runCommandWithStdoutStderr(runCmd)
206
+	errorOut(err, t, out)
207
+
208
+	out = stripTrailingCharacters(out)
209
+
210
+	if out != "/root" {
211
+		t.Errorf("-w failed to set working directory")
212
+	}
213
+
214
+	runCmd = exec.Command(dockerBinary, "run", "--workdir", "/root", "busybox", "pwd")
215
+	out, _, _, err = runCommandWithStdoutStderr(runCmd)
216
+	errorOut(err, t, out)
217
+
218
+	out = stripTrailingCharacters(out)
219
+
220
+	if out != "/root" {
221
+		t.Errorf("--workdir failed to set working directory")
222
+	}
223
+
224
+	deleteAllContainers()
225
+
226
+	logDone("run - run with working directory set by -w")
227
+	logDone("run - run with working directory set by --workdir")
228
+}
229
+
230
+// pinging Google's DNS resolver should fail when we disable the networking
231
+func TestDockerRunWithoutNetworking(t *testing.T) {
232
+	runCmd := exec.Command(dockerBinary, "run", "--networking=false", "busybox", "ping", "-c", "1", "8.8.8.8")
233
+	out, _, exitCode, err := runCommandWithStdoutStderr(runCmd)
234
+	if err != nil && exitCode != 1 {
235
+		t.Fatal(out, err)
236
+	}
237
+	if exitCode != 1 {
238
+		t.Errorf("--networking=false should've disabled the network; the container shouldn't have been able to ping 8.8.8.8")
239
+	}
240
+
241
+	runCmd = exec.Command(dockerBinary, "run", "-n=false", "busybox", "ping", "-c", "1", "8.8.8.8")
242
+	out, _, exitCode, err = runCommandWithStdoutStderr(runCmd)
243
+	if err != nil && exitCode != 1 {
244
+		t.Fatal(out, err)
245
+	}
246
+	if exitCode != 1 {
247
+		t.Errorf("-n=false should've disabled the network; the container shouldn't have been able to ping 8.8.8.8")
248
+	}
249
+
250
+	deleteAllContainers()
251
+
252
+	logDone("run - disable networking with --networking=false")
253
+	logDone("run - disable networking with -n=false")
254
+}
0 255
new file mode 100644
... ...
@@ -0,0 +1,52 @@
0
+package main
1
+
2
+import (
3
+	"fmt"
4
+	"os"
5
+	"os/exec"
6
+	"testing"
7
+)
8
+
9
+// save a repo and try to load it
10
+func TestSaveAndLoadRepo(t *testing.T) {
11
+	runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true")
12
+	out, _, err := runCommandWithOutput(runCmd)
13
+	errorOut(err, t, fmt.Sprintf("failed to create a container: %v %v", out, err))
14
+
15
+	cleanedContainerID := stripTrailingCharacters(out)
16
+
17
+	repoName := "foobar-save-load-test"
18
+
19
+	inspectCmd := exec.Command(dockerBinary, "inspect", cleanedContainerID)
20
+	out, _, err = runCommandWithOutput(inspectCmd)
21
+	errorOut(err, t, fmt.Sprintf("output should've been a container id: %v %v", cleanedContainerID, err))
22
+
23
+	commitCmd := exec.Command(dockerBinary, "commit", cleanedContainerID, repoName)
24
+	out, _, err = runCommandWithOutput(commitCmd)
25
+	errorOut(err, t, fmt.Sprintf("failed to commit container: %v %v", out, err))
26
+
27
+	saveCmdTemplate := `%v save %v > /tmp/foobar-save-load-test.tar`
28
+	saveCmdFinal := fmt.Sprintf(saveCmdTemplate, dockerBinary, repoName)
29
+	saveCmd := exec.Command("bash", "-c", saveCmdFinal)
30
+	out, _, err = runCommandWithOutput(saveCmd)
31
+	errorOut(err, t, fmt.Sprintf("failed to save repo: %v %v", out, err))
32
+
33
+	deleteImages(repoName)
34
+
35
+	loadCmdFinal := `cat /tmp/foobar-save-load-test.tar | docker load`
36
+	loadCmd := exec.Command("bash", "-c", loadCmdFinal)
37
+	out, _, err = runCommandWithOutput(loadCmd)
38
+	errorOut(err, t, fmt.Sprintf("failed to load repo: %v %v", out, err))
39
+
40
+	inspectCmd = exec.Command(dockerBinary, "inspect", repoName)
41
+	out, _, err = runCommandWithOutput(inspectCmd)
42
+	errorOut(err, t, fmt.Sprintf("the repo should exist after loading it: %v %v", out, err))
43
+
44
+	go deleteImages(repoName)
45
+	go deleteContainer(cleanedContainerID)
46
+
47
+	os.Remove("/tmp/foobar-save-load-test.tar")
48
+
49
+	logDone("save - save a repo")
50
+	logDone("load - load a repo")
51
+}
0 52
new file mode 100644
... ...
@@ -0,0 +1,25 @@
0
+package main
1
+
2
+import (
3
+	"fmt"
4
+	"os/exec"
5
+	"strings"
6
+	"testing"
7
+)
8
+
9
+// search for repos named  "registry" on the central registry
10
+func TestSearchOnCentralRegistry(t *testing.T) {
11
+	searchCmd := exec.Command(dockerBinary)
12
+	out, exitCode, err := runCommandWithOutput(searchCmd)
13
+	errorOut(err, t, fmt.Sprintf("encountered error while searching: %v", err))
14
+
15
+	if err != nil || exitCode != 0 {
16
+		t.Fatal("failed to search on the central registry")
17
+	}
18
+
19
+	if !strings.Contains(out, "registry") {
20
+		t.Fatal("couldn't find any repository named (or containing) 'registry'")
21
+	}
22
+
23
+	logDone("search - search for repositories named (or containing) 'registry'")
24
+}
0 25
new file mode 100644
... ...
@@ -0,0 +1,86 @@
0
+package main
1
+
2
+import (
3
+	"fmt"
4
+	"os/exec"
5
+	"testing"
6
+)
7
+
8
+// tagging a named image in a new unprefixed repo should work
9
+func TestTagUnprefixedRepoByName(t *testing.T) {
10
+	pullCmd := exec.Command(dockerBinary, "pull", "busybox")
11
+	out, exitCode, err := runCommandWithOutput(pullCmd)
12
+	errorOut(err, t, fmt.Sprintf("%s %s", out, err))
13
+
14
+	if err != nil || exitCode != 0 {
15
+		t.Fatal("pulling the busybox image from the registry has failed")
16
+	}
17
+
18
+	tagCmd := exec.Command(dockerBinary, "tag", "busybox", "testfoobarbaz")
19
+	out, _, err = runCommandWithOutput(tagCmd)
20
+	errorOut(err, t, fmt.Sprintf("%v %v", out, err))
21
+
22
+	deleteImages("testfoobarbaz")
23
+
24
+	logDone("tag - busybox -> testfoobarbaz")
25
+}
26
+
27
+// tagging an image by ID in a new unprefixed repo should work
28
+func TestTagUnprefixedRepoByID(t *testing.T) {
29
+	getIDCmd := exec.Command(dockerBinary, "inspect", "-f", "{{.id}}", "busybox")
30
+	out, _, err := runCommandWithOutput(getIDCmd)
31
+	errorOut(err, t, fmt.Sprintf("failed to get the image ID of busybox: %v", err))
32
+
33
+	cleanedImageID := stripTrailingCharacters(out)
34
+	tagCmd := exec.Command(dockerBinary, "tag", cleanedImageID, "testfoobarbaz")
35
+	out, _, err = runCommandWithOutput(tagCmd)
36
+	errorOut(err, t, fmt.Sprintf("%s %s", out, err))
37
+
38
+	deleteImages("testfoobarbaz")
39
+
40
+	logDone("tag - busybox's image ID -> testfoobarbaz")
41
+}
42
+
43
+// ensure we don't allow the use of invalid tags; these tag operations should fail
44
+func TestTagInvalidUnprefixedRepo(t *testing.T) {
45
+	// skip this until we start blocking bad tags
46
+	t.Skip()
47
+
48
+	invalidRepos := []string{"-foo", "fo$z$", "Foo@3cc", "Foo$3", "Foo*3", "Fo^3", "Foo!3", "F)xcz(", "fo", "f"}
49
+
50
+	for _, repo := range invalidRepos {
51
+		tagCmd := exec.Command(dockerBinary, "tag", "busybox", repo)
52
+		_, _, err := runCommandWithOutput(tagCmd)
53
+		if err == nil {
54
+			t.Errorf("tag busybox %v should have failed", repo)
55
+			continue
56
+		}
57
+		logMessage := fmt.Sprintf("tag - busybox %v --> must fail", repo)
58
+		logDone(logMessage)
59
+	}
60
+}
61
+
62
+// ensure we allow the use of valid tags
63
+func TestTagValidPrefixedRepo(t *testing.T) {
64
+	pullCmd := exec.Command(dockerBinary, "pull", "busybox")
65
+	out, exitCode, err := runCommandWithOutput(pullCmd)
66
+	errorOut(err, t, fmt.Sprintf("%s %s", out, err))
67
+
68
+	if err != nil || exitCode != 0 {
69
+		t.Fatal("pulling the busybox image from the registry has failed")
70
+	}
71
+
72
+	validRepos := []string{"fooo/bar", "fooaa/test"}
73
+
74
+	for _, repo := range validRepos {
75
+		tagCmd := exec.Command(dockerBinary, "tag", "busybox", repo)
76
+		_, _, err := runCommandWithOutput(tagCmd)
77
+		if err != nil {
78
+			t.Errorf("tag busybox %v should have worked: %s", repo, err)
79
+			continue
80
+		}
81
+		go deleteImages(repo)
82
+		logMessage := fmt.Sprintf("tag - busybox %v", repo)
83
+		logDone(logMessage)
84
+	}
85
+}
0 86
new file mode 100644
... ...
@@ -0,0 +1,32 @@
0
+package main
1
+
2
+import (
3
+	"fmt"
4
+	"os/exec"
5
+	"strings"
6
+	"testing"
7
+)
8
+
9
+func TestTop(t *testing.T) {
10
+	runCmd := exec.Command(dockerBinary, "run", "-i", "-d", "busybox", "sleep", "20")
11
+	out, _, err := runCommandWithOutput(runCmd)
12
+	errorOut(err, t, fmt.Sprintf("failed to start the container: %v", err))
13
+
14
+	cleanedContainerID := stripTrailingCharacters(out)
15
+
16
+	topCmd := exec.Command(dockerBinary, "top", cleanedContainerID)
17
+	out, _, err = runCommandWithOutput(topCmd)
18
+	errorOut(err, t, fmt.Sprintf("failed to run top: %v %v", out, err))
19
+
20
+	killCmd := exec.Command(dockerBinary, "kill", cleanedContainerID)
21
+	_, err = runCommand(killCmd)
22
+	errorOut(err, t, fmt.Sprintf("failed to kill container: %v", err))
23
+
24
+	go deleteContainer(cleanedContainerID)
25
+
26
+	if !strings.Contains(out, "sleep 20") {
27
+		t.Fatal("top should've listed sleep 20 in the process list")
28
+	}
29
+
30
+	logDone("top - sleep process should be listed")
31
+}
0 32
new file mode 100644
... ...
@@ -0,0 +1,29 @@
0
+package main
1
+
2
+import (
3
+	"fmt"
4
+	"os/exec"
5
+	"strings"
6
+	"testing"
7
+)
8
+
9
+// ensure docker version works
10
+func TestVersionEnsureSucceeds(t *testing.T) {
11
+	versionCmd := exec.Command(dockerBinary, "version")
12
+	out, exitCode, err := runCommandWithOutput(versionCmd)
13
+	errorOut(err, t, fmt.Sprintf("encountered error while running docker version: %v", err))
14
+
15
+	if err != nil || exitCode != 0 {
16
+		t.Fatal("failed to execute docker version")
17
+	}
18
+
19
+	stringsToCheck := []string{"Client version:", "Go version (client):", "Git commit (client):", "Server version:", "Git commit (server):", "Go version (server):", "Last stable version:"}
20
+
21
+	for _, linePrefix := range stringsToCheck {
22
+		if !strings.Contains(out, linePrefix) {
23
+			t.Errorf("couldn't find string %v in output", linePrefix)
24
+		}
25
+	}
26
+
27
+	logDone("version - verify that it works and that the output is properly formatted")
28
+}
0 29
new file mode 100644
... ...
@@ -0,0 +1,29 @@
0
+package main
1
+
2
+import (
3
+	"os"
4
+)
5
+
6
+// the docker binary to use
7
+var dockerBinary = "docker"
8
+
9
+// the private registry image to use for tests involving the registry
10
+var registryImageName = "registry"
11
+
12
+// the private registry to use for tests
13
+var privateRegistryURL = "127.0.0.1:5000"
14
+
15
+var workingDirectory string
16
+
17
+func init() {
18
+	if dockerBin := os.Getenv("DOCKER_BINARY"); dockerBin != "" {
19
+		dockerBinary = dockerBin
20
+	}
21
+	if registryImage := os.Getenv("REGISTRY_IMAGE"); registryImage != "" {
22
+		registryImageName = registryImage
23
+	}
24
+	if registry := os.Getenv("REGISTRY_URL"); registry != "" {
25
+		privateRegistryURL = registry
26
+	}
27
+	workingDirectory, _ = os.Getwd()
28
+}
0 29
new file mode 100644
... ...
@@ -0,0 +1,56 @@
0
+package main
1
+
2
+import (
3
+	"fmt"
4
+	"os/exec"
5
+	"strings"
6
+)
7
+
8
+func deleteContainer(container string) error {
9
+	container = strings.Replace(container, "\n", " ", -1)
10
+	container = strings.Trim(container, " ")
11
+	rmArgs := fmt.Sprintf("rm %v", container)
12
+	rmSplitArgs := strings.Split(rmArgs, " ")
13
+	rmCmd := exec.Command(dockerBinary, rmSplitArgs...)
14
+	exitCode, err := runCommand(rmCmd)
15
+	// set error manually if not set
16
+	if exitCode != 0 && err == nil {
17
+		err = fmt.Errorf("failed to remove container: `docker rm` exit is non-zero")
18
+	}
19
+
20
+	return err
21
+}
22
+
23
+func getAllContainers() (string, error) {
24
+	getContainersCmd := exec.Command(dockerBinary, "ps", "-q", "-a")
25
+	out, exitCode, err := runCommandWithOutput(getContainersCmd)
26
+	if exitCode != 0 && err == nil {
27
+		err = fmt.Errorf("failed to get a list of containers: %v\n", out)
28
+	}
29
+
30
+	return out, err
31
+}
32
+
33
+func deleteAllContainers() error {
34
+	containers, err := getAllContainers()
35
+	if err != nil {
36
+		fmt.Println(containers)
37
+		return err
38
+	}
39
+
40
+	if err = deleteContainer(containers); err != nil {
41
+		return err
42
+	}
43
+	return nil
44
+}
45
+
46
+func deleteImages(images string) error {
47
+	rmiCmd := exec.Command(dockerBinary, "rmi", images)
48
+	exitCode, err := runCommand(rmiCmd)
49
+	// set error manually if not set
50
+	if exitCode != 0 && err == nil {
51
+		err = fmt.Errorf("failed to remove image: `docker rmi` exit is non-zero")
52
+	}
53
+
54
+	return err
55
+}
0 56
new file mode 100644
... ...
@@ -0,0 +1,109 @@
0
+package main
1
+
2
+import (
3
+	"bytes"
4
+	"fmt"
5
+	"io"
6
+	"os/exec"
7
+	"strings"
8
+	"syscall"
9
+	"testing"
10
+)
11
+
12
+func getExitCode(err error) (int, error) {
13
+	exitCode := 0
14
+	if exiterr, ok := err.(*exec.ExitError); ok {
15
+		if procExit := exiterr.Sys().(syscall.WaitStatus); ok {
16
+			return procExit.ExitStatus(), nil
17
+		}
18
+	}
19
+	return exitCode, fmt.Errorf("failed to get exit code")
20
+}
21
+
22
+func runCommandWithOutput(cmd *exec.Cmd) (output string, exitCode int, err error) {
23
+	exitCode = 0
24
+	out, err := cmd.CombinedOutput()
25
+	if err != nil {
26
+		var exiterr error
27
+		if exitCode, exiterr = getExitCode(err); exiterr != nil {
28
+			// TODO: Fix this so we check the error's text.
29
+			// we've failed to retrieve exit code, so we set it to 127
30
+			exitCode = 127
31
+		}
32
+	}
33
+	output = string(out)
34
+	return
35
+}
36
+
37
+func runCommandWithStdoutStderr(cmd *exec.Cmd) (stdout string, stderr string, exitCode int, err error) {
38
+	exitCode = 0
39
+	var stderrBuffer bytes.Buffer
40
+	stderrPipe, err := cmd.StderrPipe()
41
+	if err != nil {
42
+		return "", "", -1, err
43
+	}
44
+	go io.Copy(&stderrBuffer, stderrPipe)
45
+	out, err := cmd.Output()
46
+
47
+	if err != nil {
48
+		var exiterr error
49
+		if exitCode, exiterr = getExitCode(err); exiterr != nil {
50
+			// TODO: Fix this so we check the error's text.
51
+			// we've failed to retrieve exit code, so we set it to 127
52
+			exitCode = 127
53
+		}
54
+	}
55
+	stdout = string(out)
56
+	stderr = string(stderrBuffer.Bytes())
57
+	return
58
+}
59
+
60
+func runCommand(cmd *exec.Cmd) (exitCode int, err error) {
61
+	exitCode = 0
62
+	err = cmd.Run()
63
+	if err != nil {
64
+		var exiterr error
65
+		if exitCode, exiterr = getExitCode(err); exiterr != nil {
66
+			// TODO: Fix this so we check the error's text.
67
+			// we've failed to retrieve exit code, so we set it to 127
68
+			exitCode = 127
69
+		}
70
+	}
71
+	return
72
+}
73
+
74
+func startCommand(cmd *exec.Cmd) (exitCode int, err error) {
75
+	exitCode = 0
76
+	err = cmd.Start()
77
+	if err != nil {
78
+		var exiterr error
79
+		if exitCode, exiterr = getExitCode(err); exiterr != nil {
80
+			// TODO: Fix this so we check the error's text.
81
+			// we've failed to retrieve exit code, so we set it to 127
82
+			exitCode = 127
83
+		}
84
+	}
85
+	return
86
+}
87
+
88
+func logDone(message string) {
89
+	fmt.Printf("[PASSED]: %s\n", message)
90
+}
91
+
92
+func stripTrailingCharacters(target string) string {
93
+	target = strings.Trim(target, "\n")
94
+	target = strings.Trim(target, " ")
95
+	return target
96
+}
97
+
98
+func errorOut(err error, t *testing.T, message string) {
99
+	if err != nil {
100
+		t.Fatal(message)
101
+	}
102
+}
103
+
104
+func errorOutOnNonNilError(err error, t *testing.T, message string) {
105
+	if err == nil {
106
+		t.Fatalf(message)
107
+	}
108
+}