summaryrefslogtreecommitdiff
path: root/integration-cli
diff options
context:
space:
mode:
Diffstat (limited to 'integration-cli')
-rw-r--r--integration-cli/build_tests/TestBuildSixtySteps/Dockerfile60
-rw-r--r--integration-cli/docker_cli_build_test.go28
-rw-r--r--integration-cli/docker_cli_commit_test.go34
-rw-r--r--integration-cli/docker_cli_diff_test.go91
-rw-r--r--integration-cli/docker_cli_export_import_test.go50
-rw-r--r--integration-cli/docker_cli_images_test.go58
-rw-r--r--integration-cli/docker_cli_import_test.go20
-rw-r--r--integration-cli/docker_cli_info_test.go29
-rw-r--r--integration-cli/docker_cli_kill_test.go36
-rw-r--r--integration-cli/docker_cli_logs_test.go76
-rw-r--r--integration-cli/docker_cli_pull_test.go30
-rw-r--r--integration-cli/docker_cli_push_test.go48
-rw-r--r--integration-cli/docker_cli_run_test.go386
-rw-r--r--integration-cli/docker_cli_save_load_test.go52
-rw-r--r--integration-cli/docker_cli_search_test.go25
-rw-r--r--integration-cli/docker_cli_tag_test.go86
-rw-r--r--integration-cli/docker_cli_top_test.go32
-rw-r--r--integration-cli/docker_cli_version_test.go39
-rw-r--r--integration-cli/docker_test_vars.go29
-rw-r--r--integration-cli/docker_utils.go63
-rw-r--r--integration-cli/utils.go113
21 files changed, 1385 insertions, 0 deletions
diff --git a/integration-cli/build_tests/TestBuildSixtySteps/Dockerfile b/integration-cli/build_tests/TestBuildSixtySteps/Dockerfile
new file mode 100644
index 0000000000..89b66f4f1d
--- /dev/null
+++ b/integration-cli/build_tests/TestBuildSixtySteps/Dockerfile
@@ -0,0 +1,60 @@
+FROM busybox
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
+RUN echo "foo"
diff --git a/integration-cli/docker_cli_build_test.go b/integration-cli/docker_cli_build_test.go
new file mode 100644
index 0000000000..7cd42dc69c
--- /dev/null
+++ b/integration-cli/docker_cli_build_test.go
@@ -0,0 +1,28 @@
+package main
+
+import (
+ "fmt"
+ "os/exec"
+ "path/filepath"
+ "testing"
+)
+
+func TestBuildSixtySteps(t *testing.T) {
+ buildDirectory := filepath.Join(workingDirectory, "build_tests", "TestBuildSixtySteps")
+ buildCmd := exec.Command(dockerBinary, "build", "-t", "foobuildsixtysteps", ".")
+ buildCmd.Dir = buildDirectory
+ out, exitCode, err := runCommandWithOutput(buildCmd)
+ errorOut(err, t, fmt.Sprintf("build failed to complete: %v %v", out, err))
+
+ if err != nil || exitCode != 0 {
+ t.Fatal("failed to build the image")
+ }
+
+ deleteImages("foobuildsixtysteps")
+
+ logDone("build - build an image with sixty build steps")
+}
+
+// TODO: TestCaching
+
+// TODO: TestADDCacheInvalidation
diff --git a/integration-cli/docker_cli_commit_test.go b/integration-cli/docker_cli_commit_test.go
new file mode 100644
index 0000000000..51adaac9df
--- /dev/null
+++ b/integration-cli/docker_cli_commit_test.go
@@ -0,0 +1,34 @@
+package main
+
+import (
+ "fmt"
+ "os/exec"
+ "testing"
+)
+
+func TestCommitAfterContainerIsDone(t *testing.T) {
+ runCmd := exec.Command(dockerBinary, "run", "-i", "-a", "stdin", "busybox", "echo", "foo")
+ out, _, _, err := runCommandWithStdoutStderr(runCmd)
+ errorOut(err, t, fmt.Sprintf("failed to run container: %v %v", out, err))
+
+ cleanedContainerID := stripTrailingCharacters(out)
+
+ waitCmd := exec.Command(dockerBinary, "wait", cleanedContainerID)
+ _, _, err = runCommandWithOutput(waitCmd)
+ errorOut(err, t, fmt.Sprintf("error thrown while waiting for container: %s", out))
+
+ commitCmd := exec.Command(dockerBinary, "commit", cleanedContainerID)
+ out, _, err = runCommandWithOutput(commitCmd)
+ errorOut(err, t, fmt.Sprintf("failed to commit container to image: %v %v", out, err))
+
+ cleanedImageID := stripTrailingCharacters(out)
+
+ inspectCmd := exec.Command(dockerBinary, "inspect", cleanedImageID)
+ out, _, err = runCommandWithOutput(inspectCmd)
+ errorOut(err, t, fmt.Sprintf("failed to inspect image: %v %v", out, err))
+
+ deleteContainer(cleanedContainerID)
+ deleteImages(cleanedImageID)
+
+ logDone("commit - echo foo and commit the image")
+}
diff --git a/integration-cli/docker_cli_diff_test.go b/integration-cli/docker_cli_diff_test.go
new file mode 100644
index 0000000000..478ebd2df1
--- /dev/null
+++ b/integration-cli/docker_cli_diff_test.go
@@ -0,0 +1,91 @@
+package main
+
+import (
+ "fmt"
+ "os/exec"
+ "strings"
+ "testing"
+)
+
+// ensure that an added file shows up in docker diff
+func TestDiffFilenameShownInOutput(t *testing.T) {
+ containerCmd := `echo foo > /root/bar`
+ runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", containerCmd)
+ cid, _, err := runCommandWithOutput(runCmd)
+ errorOut(err, t, fmt.Sprintf("failed to start the container: %v", err))
+
+ cleanCID := stripTrailingCharacters(cid)
+
+ diffCmd := exec.Command(dockerBinary, "diff", cleanCID)
+ out, _, err := runCommandWithOutput(diffCmd)
+ errorOut(err, t, fmt.Sprintf("failed to run diff: %v %v", out, err))
+
+ found := false
+ for _, line := range strings.Split(out, "\n") {
+ if strings.Contains("A /root/bar", line) {
+ found = true
+ break
+ }
+ }
+ if !found {
+ t.Errorf("couldn't find the new file in docker diff's output: %v", out)
+ }
+ deleteContainer(cleanCID)
+
+ logDone("diff - check if created file shows up")
+}
+
+// test to ensure GH #3840 doesn't occur any more
+func TestDiffEnsureDockerinitFilesAreIgnored(t *testing.T) {
+ // this is a list of files which shouldn't show up in `docker diff`
+ dockerinitFiles := []string{"/etc/resolv.conf", "/etc/hostname", "/etc/hosts", "/.dockerinit", "/.dockerenv"}
+
+ // we might not run into this problem from the first run, so start a few containers
+ for i := 0; i < 20; i++ {
+ containerCmd := `echo foo > /root/bar`
+ runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", containerCmd)
+ cid, _, err := runCommandWithOutput(runCmd)
+ errorOut(err, t, fmt.Sprintf("%s", err))
+
+ cleanCID := stripTrailingCharacters(cid)
+
+ diffCmd := exec.Command(dockerBinary, "diff", cleanCID)
+ out, _, err := runCommandWithOutput(diffCmd)
+ errorOut(err, t, fmt.Sprintf("failed to run diff: %v %v", out, err))
+
+ deleteContainer(cleanCID)
+
+ for _, filename := range dockerinitFiles {
+ if strings.Contains(out, filename) {
+ t.Errorf("found file which should've been ignored %v in diff output", filename)
+ }
+ }
+ }
+
+ logDone("diff - check if ignored files show up in diff")
+}
+
+func TestDiffEnsureOnlyKmsgAndPtmx(t *testing.T) {
+ runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sleep 0")
+ cid, _, err := runCommandWithOutput(runCmd)
+ errorOut(err, t, fmt.Sprintf("%s", err))
+ cleanCID := stripTrailingCharacters(cid)
+
+ diffCmd := exec.Command(dockerBinary, "diff", cleanCID)
+ out, _, err := runCommandWithOutput(diffCmd)
+ errorOut(err, t, fmt.Sprintf("failed to run diff: %v %v", out, err))
+ deleteContainer(cleanCID)
+
+ expected := map[string]bool{
+ "C /dev": true,
+ "A /dev/full": true, // busybox
+ "C /dev/ptmx": true, // libcontainer
+ "A /dev/kmsg": true, // lxc
+ }
+
+ for _, line := range strings.Split(out, "\n") {
+ if line != "" && !expected[line] {
+ t.Errorf("'%s' is shown in the diff but shouldn't", line)
+ }
+ }
+}
diff --git a/integration-cli/docker_cli_export_import_test.go b/integration-cli/docker_cli_export_import_test.go
new file mode 100644
index 0000000000..2e443cd39e
--- /dev/null
+++ b/integration-cli/docker_cli_export_import_test.go
@@ -0,0 +1,50 @@
+package main
+
+import (
+ "fmt"
+ "os"
+ "os/exec"
+ "testing"
+)
+
+// export an image and try to import it into a new one
+func TestExportContainerAndImportImage(t *testing.T) {
+ runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true")
+ out, _, err := runCommandWithOutput(runCmd)
+ if err != nil {
+ t.Fatal("failed to create a container", out, err)
+ }
+
+ cleanedContainerID := stripTrailingCharacters(out)
+
+ inspectCmd := exec.Command(dockerBinary, "inspect", cleanedContainerID)
+ out, _, err = runCommandWithOutput(inspectCmd)
+ if err != nil {
+ t.Fatalf("output should've been a container id: %s %s ", cleanedContainerID, err)
+ }
+
+ exportCmdTemplate := `%v export %v > /tmp/testexp.tar`
+ exportCmdFinal := fmt.Sprintf(exportCmdTemplate, dockerBinary, cleanedContainerID)
+ exportCmd := exec.Command("bash", "-c", exportCmdFinal)
+ out, _, err = runCommandWithOutput(exportCmd)
+ errorOut(err, t, fmt.Sprintf("failed to export container: %v %v", out, err))
+
+ importCmdFinal := `cat /tmp/testexp.tar | docker import - testexp`
+ importCmd := exec.Command("bash", "-c", importCmdFinal)
+ out, _, err = runCommandWithOutput(importCmd)
+ errorOut(err, t, fmt.Sprintf("failed to import image: %v %v", out, err))
+
+ cleanedImageID := stripTrailingCharacters(out)
+
+ inspectCmd = exec.Command(dockerBinary, "inspect", cleanedImageID)
+ out, _, err = runCommandWithOutput(inspectCmd)
+ errorOut(err, t, fmt.Sprintf("output should've been an image id: %v %v", out, err))
+
+ deleteContainer(cleanedContainerID)
+ deleteImages("testexp")
+
+ os.Remove("/tmp/testexp.tar")
+
+ logDone("export - export a container")
+ logDone("import - import an image")
+}
diff --git a/integration-cli/docker_cli_images_test.go b/integration-cli/docker_cli_images_test.go
new file mode 100644
index 0000000000..82b70bab40
--- /dev/null
+++ b/integration-cli/docker_cli_images_test.go
@@ -0,0 +1,58 @@
+package main
+
+import (
+ "fmt"
+ "os/exec"
+ "strings"
+ "testing"
+)
+
+func TestImagesEnsureImageIsListed(t *testing.T) {
+ imagesCmd := exec.Command(dockerBinary, "images")
+ out, _, err := runCommandWithOutput(imagesCmd)
+ errorOut(err, t, fmt.Sprintf("listing images failed with errors: %v", err))
+
+ if !strings.Contains(out, "busybox") {
+ t.Fatal("images should've listed busybox")
+ }
+
+ logDone("images - busybox should be listed")
+}
+
+func TestCLIImageTagRemove(t *testing.T) {
+ imagesBefore, _, _ := cmd(t, "images", "-a")
+ cmd(t, "tag", "busybox", "utest:tag1")
+ cmd(t, "tag", "busybox", "utest/docker:tag2")
+ cmd(t, "tag", "busybox", "utest:5000/docker:tag3")
+ {
+ imagesAfter, _, _ := cmd(t, "images", "-a")
+ if nLines(imagesAfter) != nLines(imagesBefore)+3 {
+ t.Fatalf("before: %#s\n\nafter: %#s\n", imagesBefore, imagesAfter)
+ }
+ }
+ cmd(t, "rmi", "utest/docker:tag2")
+ {
+ imagesAfter, _, _ := cmd(t, "images", "-a")
+ if nLines(imagesAfter) != nLines(imagesBefore)+2 {
+ t.Fatalf("before: %#s\n\nafter: %#s\n", imagesBefore, imagesAfter)
+ }
+
+ }
+ cmd(t, "rmi", "utest:5000/docker:tag3")
+ {
+ imagesAfter, _, _ := cmd(t, "images", "-a")
+ if nLines(imagesAfter) != nLines(imagesBefore)+1 {
+ t.Fatalf("before: %#s\n\nafter: %#s\n", imagesBefore, imagesAfter)
+ }
+
+ }
+ cmd(t, "rmi", "utest:tag1")
+ {
+ imagesAfter, _, _ := cmd(t, "images", "-a")
+ if nLines(imagesAfter) != nLines(imagesBefore)+0 {
+ t.Fatalf("before: %#s\n\nafter: %#s\n", imagesBefore, imagesAfter)
+ }
+
+ }
+ logDone("tag,rmi- tagging the same images multiple times then removing tags")
+}
diff --git a/integration-cli/docker_cli_import_test.go b/integration-cli/docker_cli_import_test.go
new file mode 100644
index 0000000000..9b36aa9ce1
--- /dev/null
+++ b/integration-cli/docker_cli_import_test.go
@@ -0,0 +1,20 @@
+package main
+
+import (
+ "fmt"
+ "os/exec"
+ "strings"
+ "testing"
+)
+
+func TestImportDisplay(t *testing.T) {
+ importCmd := exec.Command(dockerBinary, "import", "https://github.com/ewindisch/docker-cirros/raw/master/cirros-0.3.0-x86_64-lxc.tar.gz")
+ out, _, err := runCommandWithOutput(importCmd)
+ errorOut(err, t, fmt.Sprintf("import failed with errors: %v", err))
+
+ if n := len(strings.Split(out, "\n")); n != 3 {
+ t.Fatalf("display is messed up: %d '\\n' instead of 3", n)
+ }
+
+ logDone("import - cirros was imported and display is fine")
+}
diff --git a/integration-cli/docker_cli_info_test.go b/integration-cli/docker_cli_info_test.go
new file mode 100644
index 0000000000..32aa3a2125
--- /dev/null
+++ b/integration-cli/docker_cli_info_test.go
@@ -0,0 +1,29 @@
+package main
+
+import (
+ "fmt"
+ "os/exec"
+ "strings"
+ "testing"
+)
+
+// ensure docker info succeeds
+func TestInfoEnsureSucceeds(t *testing.T) {
+ versionCmd := exec.Command(dockerBinary, "info")
+ out, exitCode, err := runCommandWithOutput(versionCmd)
+ errorOut(err, t, fmt.Sprintf("encountered error while running docker info: %v", err))
+
+ if err != nil || exitCode != 0 {
+ t.Fatal("failed to execute docker info")
+ }
+
+ stringsToCheck := []string{"Containers:", "Execution Driver:", "Kernel Version:"}
+
+ for _, linePrefix := range stringsToCheck {
+ if !strings.Contains(out, linePrefix) {
+ t.Errorf("couldn't find string %v in output", linePrefix)
+ }
+ }
+
+ logDone("info - verify that it works")
+}
diff --git a/integration-cli/docker_cli_kill_test.go b/integration-cli/docker_cli_kill_test.go
new file mode 100644
index 0000000000..b8265d8cfb
--- /dev/null
+++ b/integration-cli/docker_cli_kill_test.go
@@ -0,0 +1,36 @@
+package main
+
+import (
+ "fmt"
+ "os/exec"
+ "strings"
+ "testing"
+)
+
+func TestKillContainer(t *testing.T) {
+ runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", "sleep 10")
+ out, _, err := runCommandWithOutput(runCmd)
+ errorOut(err, t, fmt.Sprintf("run failed with errors: %v", err))
+
+ cleanedContainerID := stripTrailingCharacters(out)
+
+ inspectCmd := exec.Command(dockerBinary, "inspect", cleanedContainerID)
+ inspectOut, _, err := runCommandWithOutput(inspectCmd)
+ errorOut(err, t, fmt.Sprintf("out should've been a container id: %v %v", inspectOut, err))
+
+ killCmd := exec.Command(dockerBinary, "kill", cleanedContainerID)
+ out, _, err = runCommandWithOutput(killCmd)
+ errorOut(err, t, fmt.Sprintf("failed to kill container: %v %v", out, err))
+
+ listRunningContainersCmd := exec.Command(dockerBinary, "ps", "-q")
+ out, _, err = runCommandWithOutput(listRunningContainersCmd)
+ errorOut(err, t, fmt.Sprintf("failed to list running containers: %v", err))
+
+ if strings.Contains(out, cleanedContainerID) {
+ t.Fatal("killed container is still running")
+ }
+
+ deleteContainer(cleanedContainerID)
+
+ logDone("kill - kill container running sleep 10")
+}
diff --git a/integration-cli/docker_cli_logs_test.go b/integration-cli/docker_cli_logs_test.go
new file mode 100644
index 0000000000..8fcf4d7333
--- /dev/null
+++ b/integration-cli/docker_cli_logs_test.go
@@ -0,0 +1,76 @@
+package main
+
+import (
+ "fmt"
+ "os/exec"
+ "testing"
+)
+
+// This used to work, it test a log of PageSize-1 (gh#4851)
+func TestLogsContainerSmallerThanPage(t *testing.T) {
+ testLen := 32767
+ runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo -n =; done; echo", testLen))
+ out, _, _, err := runCommandWithStdoutStderr(runCmd)
+ errorOut(err, t, fmt.Sprintf("run failed with errors: %v", err))
+
+ cleanedContainerID := stripTrailingCharacters(out)
+ exec.Command(dockerBinary, "wait", cleanedContainerID).Run()
+
+ logsCmd := exec.Command(dockerBinary, "logs", cleanedContainerID)
+ out, _, _, err = runCommandWithStdoutStderr(logsCmd)
+ errorOut(err, t, fmt.Sprintf("failed to log container: %v %v", out, err))
+
+ if len(out) != testLen+1 {
+ t.Fatalf("Expected log length of %d, received %d\n", testLen+1, len(out))
+ }
+
+ deleteContainer(cleanedContainerID)
+
+ logDone("logs - logs container running echo smaller than page size")
+}
+
+// Regression test: When going over the PageSize, it used to panic (gh#4851)
+func TestLogsContainerBiggerThanPage(t *testing.T) {
+ testLen := 32768
+ runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo -n =; done; echo", testLen))
+ out, _, _, err := runCommandWithStdoutStderr(runCmd)
+ errorOut(err, t, fmt.Sprintf("run failed with errors: %v", err))
+
+ cleanedContainerID := stripTrailingCharacters(out)
+ exec.Command(dockerBinary, "wait", cleanedContainerID).Run()
+
+ logsCmd := exec.Command(dockerBinary, "logs", cleanedContainerID)
+ out, _, _, err = runCommandWithStdoutStderr(logsCmd)
+ errorOut(err, t, fmt.Sprintf("failed to log container: %v %v", out, err))
+
+ if len(out) != testLen+1 {
+ t.Fatalf("Expected log length of %d, received %d\n", testLen+1, len(out))
+ }
+
+ deleteContainer(cleanedContainerID)
+
+ logDone("logs - logs container running echo bigger than page size")
+}
+
+// Regression test: When going much over the PageSize, it used to block (gh#4851)
+func TestLogsContainerMuchBiggerThanPage(t *testing.T) {
+ testLen := 33000
+ runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "sh", "-c", fmt.Sprintf("for i in $(seq 1 %d); do echo -n =; done; echo", testLen))
+ out, _, _, err := runCommandWithStdoutStderr(runCmd)
+ errorOut(err, t, fmt.Sprintf("run failed with errors: %v", err))
+
+ cleanedContainerID := stripTrailingCharacters(out)
+ exec.Command(dockerBinary, "wait", cleanedContainerID).Run()
+
+ logsCmd := exec.Command(dockerBinary, "logs", cleanedContainerID)
+ out, _, _, err = runCommandWithStdoutStderr(logsCmd)
+ errorOut(err, t, fmt.Sprintf("failed to log container: %v %v", out, err))
+
+ if len(out) != testLen+1 {
+ t.Fatalf("Expected log length of %d, received %d\n", testLen+1, len(out))
+ }
+
+ deleteContainer(cleanedContainerID)
+
+ logDone("logs - logs container running echo much bigger than page size")
+}
diff --git a/integration-cli/docker_cli_pull_test.go b/integration-cli/docker_cli_pull_test.go
new file mode 100644
index 0000000000..13b443f3d6
--- /dev/null
+++ b/integration-cli/docker_cli_pull_test.go
@@ -0,0 +1,30 @@
+package main
+
+import (
+ "fmt"
+ "os/exec"
+ "testing"
+)
+
+// pulling an image from the central registry should work
+func TestPullImageFromCentralRegistry(t *testing.T) {
+ pullCmd := exec.Command(dockerBinary, "pull", "busybox")
+ out, exitCode, err := runCommandWithOutput(pullCmd)
+ errorOut(err, t, fmt.Sprintf("%s %s", out, err))
+
+ if err != nil || exitCode != 0 {
+ t.Fatal("pulling the busybox image from the registry has failed")
+ }
+ logDone("pull - pull busybox")
+}
+
+// pulling a non-existing image from the central registry should return a non-zero exit code
+func TestPullNonExistingImage(t *testing.T) {
+ pullCmd := exec.Command(dockerBinary, "pull", "fooblahblah1234")
+ _, exitCode, err := runCommandWithOutput(pullCmd)
+
+ if err == nil || exitCode == 0 {
+ t.Fatal("expected non-zero exit status when pulling non-existing image")
+ }
+ logDone("pull - pull fooblahblah1234 (non-existing image)")
+}
diff --git a/integration-cli/docker_cli_push_test.go b/integration-cli/docker_cli_push_test.go
new file mode 100644
index 0000000000..160bb9e286
--- /dev/null
+++ b/integration-cli/docker_cli_push_test.go
@@ -0,0 +1,48 @@
+package main
+
+import (
+ "fmt"
+ "os/exec"
+ "testing"
+)
+
+// these tests need a freshly started empty private docker registry
+
+// pulling an image from the central registry should work
+func TestPushBusyboxImage(t *testing.T) {
+ // skip this test until we're able to use a registry
+ t.Skip()
+ // tag the image to upload it tot he private registry
+ repoName := fmt.Sprintf("%v/busybox", privateRegistryURL)
+ tagCmd := exec.Command(dockerBinary, "tag", "busybox", repoName)
+ out, exitCode, err := runCommandWithOutput(tagCmd)
+ errorOut(err, t, fmt.Sprintf("%v %v", out, err))
+
+ if err != nil || exitCode != 0 {
+ t.Fatal("image tagging failed")
+ }
+
+ pushCmd := exec.Command(dockerBinary, "push", repoName)
+ out, exitCode, err = runCommandWithOutput(pushCmd)
+ errorOut(err, t, fmt.Sprintf("%v %v", out, err))
+
+ deleteImages(repoName)
+
+ if err != nil || exitCode != 0 {
+ t.Fatal("pushing the image to the private registry has failed")
+ }
+ logDone("push - push busybox to private registry")
+}
+
+// pushing an image without a prefix should throw an error
+func TestPushUnprefixedRepo(t *testing.T) {
+ // skip this test until we're able to use a registry
+ t.Skip()
+ pushCmd := exec.Command(dockerBinary, "push", "busybox")
+ _, exitCode, err := runCommandWithOutput(pushCmd)
+
+ if err == nil || exitCode == 0 {
+ t.Fatal("pushing an unprefixed repo didn't result in a non-zero exit status")
+ }
+ logDone("push - push unprefixed busybox repo --> must fail")
+}
diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go
new file mode 100644
index 0000000000..b0805dd35c
--- /dev/null
+++ b/integration-cli/docker_cli_run_test.go
@@ -0,0 +1,386 @@
+package main
+
+import (
+ "fmt"
+ "os/exec"
+ "strings"
+ "testing"
+)
+
+// "test123" should be printed by docker run
+func TestDockerRunEchoStdout(t *testing.T) {
+ runCmd := exec.Command(dockerBinary, "run", "busybox", "echo", "test123")
+ out, _, _, err := runCommandWithStdoutStderr(runCmd)
+ errorOut(err, t, out)
+
+ if out != "test123\n" {
+ t.Errorf("container should've printed 'test123'")
+ }
+
+ deleteAllContainers()
+
+ logDone("run - echo test123")
+}
+
+// "test" should be printed
+func TestDockerRunEchoStdoutWithMemoryLimit(t *testing.T) {
+ runCmd := exec.Command(dockerBinary, "run", "-m", "2786432", "busybox", "echo", "test")
+ out, _, _, err := runCommandWithStdoutStderr(runCmd)
+ errorOut(err, t, out)
+
+ if out != "test\n" {
+ t.Errorf("container should've printed 'test'")
+
+ }
+
+ deleteAllContainers()
+
+ logDone("run - echo with memory limit")
+}
+
+// "test" should be printed
+func TestDockerRunEchoStdoutWitCPULimit(t *testing.T) {
+ runCmd := exec.Command(dockerBinary, "run", "-c", "1000", "busybox", "echo", "test")
+ out, _, _, err := runCommandWithStdoutStderr(runCmd)
+ errorOut(err, t, out)
+
+ if out != "test\n" {
+ t.Errorf("container should've printed 'test'")
+ }
+
+ deleteAllContainers()
+
+ logDone("run - echo with CPU limit")
+}
+
+// "test" should be printed
+func TestDockerRunEchoStdoutWithCPUAndMemoryLimit(t *testing.T) {
+ runCmd := exec.Command(dockerBinary, "run", "-c", "1000", "-m", "2786432", "busybox", "echo", "test")
+ out, _, _, err := runCommandWithStdoutStderr(runCmd)
+ errorOut(err, t, out)
+
+ if out != "test\n" {
+ t.Errorf("container should've printed 'test'")
+ }
+
+ deleteAllContainers()
+
+ logDone("run - echo with CPU and memory limit")
+}
+
+// "test" should be printed
+func TestDockerRunEchoNamedContainer(t *testing.T) {
+ runCmd := exec.Command(dockerBinary, "run", "--name", "testfoonamedcontainer", "busybox", "echo", "test")
+ out, _, _, err := runCommandWithStdoutStderr(runCmd)
+ errorOut(err, t, out)
+
+ if out != "test\n" {
+ t.Errorf("container should've printed 'test'")
+ }
+
+ if err := deleteContainer("testfoonamedcontainer"); err != nil {
+ t.Errorf("failed to remove the named container: %v", err)
+ }
+
+ deleteAllContainers()
+
+ logDone("run - echo with named container")
+}
+
+// it should be possible to ping Google DNS resolver
+// this will fail when Internet access is unavailable
+func TestDockerRunPingGoogle(t *testing.T) {
+ runCmd := exec.Command(dockerBinary, "run", "busybox", "ping", "-c", "1", "8.8.8.8")
+ out, _, _, err := runCommandWithStdoutStderr(runCmd)
+ errorOut(err, t, out)
+
+ errorOut(err, t, "container should've been able to ping 8.8.8.8")
+
+ deleteAllContainers()
+
+ logDone("run - ping 8.8.8.8")
+}
+
+// the exit code should be 0
+// some versions of lxc might make this test fail
+func TestDockerRunExitCodeZero(t *testing.T) {
+ runCmd := exec.Command(dockerBinary, "run", "busybox", "true")
+ exitCode, err := runCommand(runCmd)
+ errorOut(err, t, fmt.Sprintf("%s", err))
+
+ if exitCode != 0 {
+ t.Errorf("container should've exited with exit code 0")
+ }
+
+ deleteAllContainers()
+
+ logDone("run - exit with 0")
+}
+
+// the exit code should be 1
+// some versions of lxc might make this test fail
+func TestDockerRunExitCodeOne(t *testing.T) {
+ runCmd := exec.Command(dockerBinary, "run", "busybox", "false")
+ exitCode, err := runCommand(runCmd)
+ if err != nil && !strings.Contains("exit status 1", fmt.Sprintf("%s", err)) {
+ t.Fatal(err)
+ }
+ if exitCode != 1 {
+ t.Errorf("container should've exited with exit code 1")
+ }
+
+ deleteAllContainers()
+
+ logDone("run - exit with 1")
+}
+
+// it should be possible to pipe in data via stdin to a process running in a container
+// some versions of lxc might make this test fail
+func TestRunStdinPipe(t *testing.T) {
+ runCmd := exec.Command("bash", "-c", `echo "blahblah" | docker run -i -a stdin busybox cat`)
+ out, _, _, err := runCommandWithStdoutStderr(runCmd)
+ errorOut(err, t, out)
+
+ out = stripTrailingCharacters(out)
+
+ inspectCmd := exec.Command(dockerBinary, "inspect", out)
+ inspectOut, _, err := runCommandWithOutput(inspectCmd)
+ errorOut(err, t, fmt.Sprintf("out should've been a container id: %s %s", out, inspectOut))
+
+ waitCmd := exec.Command(dockerBinary, "wait", out)
+ _, _, err = runCommandWithOutput(waitCmd)
+ errorOut(err, t, fmt.Sprintf("error thrown while waiting for container: %s", out))
+
+ logsCmd := exec.Command(dockerBinary, "logs", out)
+ containerLogs, _, err := runCommandWithOutput(logsCmd)
+ errorOut(err, t, fmt.Sprintf("error thrown while trying to get container logs: %s", err))
+
+ containerLogs = stripTrailingCharacters(containerLogs)
+
+ if containerLogs != "blahblah" {
+ t.Errorf("logs didn't print the container's logs %s", containerLogs)
+ }
+
+ rmCmd := exec.Command(dockerBinary, "rm", out)
+ _, _, err = runCommandWithOutput(rmCmd)
+ errorOut(err, t, fmt.Sprintf("rm failed to remove container %s", err))
+
+ deleteAllContainers()
+
+ logDone("run - pipe in with -i -a stdin")
+}
+
+// the container's ID should be printed when starting a container in detached mode
+func TestDockerRunDetachedContainerIDPrinting(t *testing.T) {
+ runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true")
+ out, _, _, err := runCommandWithStdoutStderr(runCmd)
+ errorOut(err, t, out)
+
+ out = stripTrailingCharacters(out)
+
+ inspectCmd := exec.Command(dockerBinary, "inspect", out)
+ inspectOut, _, err := runCommandWithOutput(inspectCmd)
+ errorOut(err, t, fmt.Sprintf("out should've been a container id: %s %s", out, inspectOut))
+
+ waitCmd := exec.Command(dockerBinary, "wait", out)
+ _, _, err = runCommandWithOutput(waitCmd)
+ errorOut(err, t, fmt.Sprintf("error thrown while waiting for container: %s", out))
+
+ rmCmd := exec.Command(dockerBinary, "rm", out)
+ rmOut, _, err := runCommandWithOutput(rmCmd)
+ errorOut(err, t, "rm failed to remove container")
+
+ rmOut = stripTrailingCharacters(rmOut)
+ if rmOut != out {
+ t.Errorf("rm didn't print the container ID %s %s", out, rmOut)
+ }
+
+ deleteAllContainers()
+
+ logDone("run - print container ID in detached mode")
+}
+
+// the working directory should be set correctly
+func TestDockerRunWorkingDirectory(t *testing.T) {
+ runCmd := exec.Command(dockerBinary, "run", "-w", "/root", "busybox", "pwd")
+ out, _, _, err := runCommandWithStdoutStderr(runCmd)
+ errorOut(err, t, out)
+
+ out = stripTrailingCharacters(out)
+
+ if out != "/root" {
+ t.Errorf("-w failed to set working directory")
+ }
+
+ runCmd = exec.Command(dockerBinary, "run", "--workdir", "/root", "busybox", "pwd")
+ out, _, _, err = runCommandWithStdoutStderr(runCmd)
+ errorOut(err, t, out)
+
+ out = stripTrailingCharacters(out)
+
+ if out != "/root" {
+ t.Errorf("--workdir failed to set working directory")
+ }
+
+ deleteAllContainers()
+
+ logDone("run - run with working directory set by -w")
+ logDone("run - run with working directory set by --workdir")
+}
+
+// pinging Google's DNS resolver should fail when we disable the networking
+func TestDockerRunWithoutNetworking(t *testing.T) {
+ runCmd := exec.Command(dockerBinary, "run", "--networking=false", "busybox", "ping", "-c", "1", "8.8.8.8")
+ out, _, exitCode, err := runCommandWithStdoutStderr(runCmd)
+ if err != nil && exitCode != 1 {
+ t.Fatal(out, err)
+ }
+ if exitCode != 1 {
+ t.Errorf("--networking=false should've disabled the network; the container shouldn't have been able to ping 8.8.8.8")
+ }
+
+ runCmd = exec.Command(dockerBinary, "run", "-n=false", "busybox", "ping", "-c", "1", "8.8.8.8")
+ out, _, exitCode, err = runCommandWithStdoutStderr(runCmd)
+ if err != nil && exitCode != 1 {
+ t.Fatal(out, err)
+ }
+ if exitCode != 1 {
+ t.Errorf("-n=false should've disabled the network; the container shouldn't have been able to ping 8.8.8.8")
+ }
+
+ deleteAllContainers()
+
+ logDone("run - disable networking with --networking=false")
+ logDone("run - disable networking with -n=false")
+}
+
+// Regression test for #4741
+func TestDockerRunWithVolumesAsFiles(t *testing.T) {
+ runCmd := exec.Command(dockerBinary, "run", "--name", "test-data", "--volume", "/etc/hosts:/target-file", "busybox", "true")
+ out, stderr, exitCode, err := runCommandWithStdoutStderr(runCmd)
+ if err != nil && exitCode != 0 {
+ t.Fatal("1", out, stderr, err)
+ }
+
+ runCmd = exec.Command(dockerBinary, "run", "--volumes-from", "test-data", "busybox", "cat", "/target-file")
+ out, stderr, exitCode, err = runCommandWithStdoutStderr(runCmd)
+ if err != nil && exitCode != 0 {
+ t.Fatal("2", out, stderr, err)
+ }
+ deleteAllContainers()
+
+ logDone("run - regression test for #4741 - volumes from as files")
+}
+
+// Regression test for #4979
+func TestDockerRunWithVolumesFromExited(t *testing.T) {
+ runCmd := exec.Command(dockerBinary, "run", "--name", "test-data", "--volume", "/some/dir", "busybox", "touch", "/some/dir/file")
+ out, stderr, exitCode, err := runCommandWithStdoutStderr(runCmd)
+ if err != nil && exitCode != 0 {
+ t.Fatal("1", out, stderr, err)
+ }
+
+ runCmd = exec.Command(dockerBinary, "run", "--volumes-from", "test-data", "busybox", "cat", "/some/dir/file")
+ out, stderr, exitCode, err = runCommandWithStdoutStderr(runCmd)
+ if err != nil && exitCode != 0 {
+ t.Fatal("2", out, stderr, err)
+ }
+ deleteAllContainers()
+
+ logDone("run - regression test for #4979 - volumes-from on exited container")
+}
+
+// Regression test for #4830
+func TestDockerRunWithRelativePath(t *testing.T) {
+ runCmd := exec.Command(dockerBinary, "run", "-v", "tmp:/other-tmp", "busybox", "true")
+ if _, _, _, err := runCommandWithStdoutStderr(runCmd); err == nil {
+ t.Fatalf("relative path should result in an error")
+ }
+
+ deleteAllContainers()
+
+ logDone("run - volume with relative path")
+}
+
+func TestVolumesMountedAsReadonly(t *testing.T) {
+ cmd := exec.Command(dockerBinary, "run", "-v", "/test:/test:ro", "busybox", "touch", "/test/somefile")
+ if code, err := runCommand(cmd); err == nil || code == 0 {
+ t.Fatalf("run should fail because volume is ro: exit code %d", code)
+ }
+
+ deleteAllContainers()
+
+ logDone("run - volumes as readonly mount")
+}
+
+func TestVolumesFromInReadonlyMode(t *testing.T) {
+ cmd := exec.Command(dockerBinary, "run", "--name", "parent", "-v", "/test", "busybox", "true")
+ if _, err := runCommand(cmd); err != nil {
+ t.Fatal(err)
+ }
+
+ cmd = exec.Command(dockerBinary, "run", "--volumes-from", "parent:ro", "busybox", "touch", "/test/file")
+ if code, err := runCommand(cmd); err == nil || code == 0 {
+ t.Fatalf("run should fail because volume is ro: exit code %d", code)
+ }
+
+ deleteAllContainers()
+
+ logDone("run - volumes from as readonly mount")
+}
+
+// Regression test for #1201
+func TestVolumesFromInReadWriteMode(t *testing.T) {
+ cmd := exec.Command(dockerBinary, "run", "--name", "parent", "-v", "/test", "busybox", "true")
+ if _, err := runCommand(cmd); err != nil {
+ t.Fatal(err)
+ }
+
+ cmd = exec.Command(dockerBinary, "run", "--volumes-from", "parent", "busybox", "touch", "/test/file")
+ if _, err := runCommand(cmd); err != nil {
+ t.Fatal(err)
+ }
+
+ deleteAllContainers()
+
+ logDone("run - volumes from as read write mount")
+}
+
+// Test for #1351
+func TestApplyVolumesFromBeforeVolumes(t *testing.T) {
+ cmd := exec.Command(dockerBinary, "run", "--name", "parent", "-v", "/test", "busybox", "touch", "/test/foo")
+ if _, err := runCommand(cmd); err != nil {
+ t.Fatal(err)
+ }
+
+ cmd = exec.Command(dockerBinary, "run", "--volumes-from", "parent", "-v", "/test", "busybox", "cat", "/test/foo")
+ if _, err := runCommand(cmd); err != nil {
+ t.Fatal(err)
+ }
+
+ deleteAllContainers()
+
+ logDone("run - volumes from mounted first")
+}
+
+func TestMultipleVolumesFrom(t *testing.T) {
+ cmd := exec.Command(dockerBinary, "run", "--name", "parent1", "-v", "/test", "busybox", "touch", "/test/foo")
+ if _, err := runCommand(cmd); err != nil {
+ t.Fatal(err)
+ }
+
+ cmd = exec.Command(dockerBinary, "run", "--name", "parent2", "-v", "/other", "busybox", "touch", "/other/bar")
+ if _, err := runCommand(cmd); err != nil {
+ t.Fatal(err)
+ }
+
+ cmd = exec.Command(dockerBinary, "run", "--volumes-from", "parent1", "--volumes-from", "parent2",
+ "busybox", "sh", "-c", "cat /test/foo && cat /other/bar")
+ if _, err := runCommand(cmd); err != nil {
+ t.Fatal(err)
+ }
+
+ deleteAllContainers()
+
+ logDone("run - multiple volumes from")
+}
diff --git a/integration-cli/docker_cli_save_load_test.go b/integration-cli/docker_cli_save_load_test.go
new file mode 100644
index 0000000000..d728c7de95
--- /dev/null
+++ b/integration-cli/docker_cli_save_load_test.go
@@ -0,0 +1,52 @@
+package main
+
+import (
+ "fmt"
+ "os"
+ "os/exec"
+ "testing"
+)
+
+// save a repo and try to load it
+func TestSaveAndLoadRepo(t *testing.T) {
+ runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true")
+ out, _, err := runCommandWithOutput(runCmd)
+ errorOut(err, t, fmt.Sprintf("failed to create a container: %v %v", out, err))
+
+ cleanedContainerID := stripTrailingCharacters(out)
+
+ repoName := "foobar-save-load-test"
+
+ inspectCmd := exec.Command(dockerBinary, "inspect", cleanedContainerID)
+ out, _, err = runCommandWithOutput(inspectCmd)
+ errorOut(err, t, fmt.Sprintf("output should've been a container id: %v %v", cleanedContainerID, err))
+
+ commitCmd := exec.Command(dockerBinary, "commit", cleanedContainerID, repoName)
+ out, _, err = runCommandWithOutput(commitCmd)
+ errorOut(err, t, fmt.Sprintf("failed to commit container: %v %v", out, err))
+
+ saveCmdTemplate := `%v save %v > /tmp/foobar-save-load-test.tar`
+ saveCmdFinal := fmt.Sprintf(saveCmdTemplate, dockerBinary, repoName)
+ saveCmd := exec.Command("bash", "-c", saveCmdFinal)
+ out, _, err = runCommandWithOutput(saveCmd)
+ errorOut(err, t, fmt.Sprintf("failed to save repo: %v %v", out, err))
+
+ deleteImages(repoName)
+
+ loadCmdFinal := `cat /tmp/foobar-save-load-test.tar | docker load`
+ loadCmd := exec.Command("bash", "-c", loadCmdFinal)
+ out, _, err = runCommandWithOutput(loadCmd)
+ errorOut(err, t, fmt.Sprintf("failed to load repo: %v %v", out, err))
+
+ inspectCmd = exec.Command(dockerBinary, "inspect", repoName)
+ out, _, err = runCommandWithOutput(inspectCmd)
+ errorOut(err, t, fmt.Sprintf("the repo should exist after loading it: %v %v", out, err))
+
+ deleteContainer(cleanedContainerID)
+ deleteImages(repoName)
+
+ os.Remove("/tmp/foobar-save-load-test.tar")
+
+ logDone("save - save a repo")
+ logDone("load - load a repo")
+}
diff --git a/integration-cli/docker_cli_search_test.go b/integration-cli/docker_cli_search_test.go
new file mode 100644
index 0000000000..050aec51a6
--- /dev/null
+++ b/integration-cli/docker_cli_search_test.go
@@ -0,0 +1,25 @@
+package main
+
+import (
+ "fmt"
+ "os/exec"
+ "strings"
+ "testing"
+)
+
+// search for repos named "registry" on the central registry
+func TestSearchOnCentralRegistry(t *testing.T) {
+ searchCmd := exec.Command(dockerBinary)
+ out, exitCode, err := runCommandWithOutput(searchCmd)
+ errorOut(err, t, fmt.Sprintf("encountered error while searching: %v", err))
+
+ if err != nil || exitCode != 0 {
+ t.Fatal("failed to search on the central registry")
+ }
+
+ if !strings.Contains(out, "registry") {
+ t.Fatal("couldn't find any repository named (or containing) 'registry'")
+ }
+
+ logDone("search - search for repositories named (or containing) 'registry'")
+}
diff --git a/integration-cli/docker_cli_tag_test.go b/integration-cli/docker_cli_tag_test.go
new file mode 100644
index 0000000000..d75b7db385
--- /dev/null
+++ b/integration-cli/docker_cli_tag_test.go
@@ -0,0 +1,86 @@
+package main
+
+import (
+ "fmt"
+ "os/exec"
+ "testing"
+)
+
+// tagging a named image in a new unprefixed repo should work
+func TestTagUnprefixedRepoByName(t *testing.T) {
+ pullCmd := exec.Command(dockerBinary, "pull", "busybox")
+ out, exitCode, err := runCommandWithOutput(pullCmd)
+ errorOut(err, t, fmt.Sprintf("%s %s", out, err))
+
+ if err != nil || exitCode != 0 {
+ t.Fatal("pulling the busybox image from the registry has failed")
+ }
+
+ tagCmd := exec.Command(dockerBinary, "tag", "busybox", "testfoobarbaz")
+ out, _, err = runCommandWithOutput(tagCmd)
+ errorOut(err, t, fmt.Sprintf("%v %v", out, err))
+
+ deleteImages("testfoobarbaz")
+
+ logDone("tag - busybox -> testfoobarbaz")
+}
+
+// tagging an image by ID in a new unprefixed repo should work
+func TestTagUnprefixedRepoByID(t *testing.T) {
+ getIDCmd := exec.Command(dockerBinary, "inspect", "-f", "{{.id}}", "busybox")
+ out, _, err := runCommandWithOutput(getIDCmd)
+ errorOut(err, t, fmt.Sprintf("failed to get the image ID of busybox: %v", err))
+
+ cleanedImageID := stripTrailingCharacters(out)
+ tagCmd := exec.Command(dockerBinary, "tag", cleanedImageID, "testfoobarbaz")
+ out, _, err = runCommandWithOutput(tagCmd)
+ errorOut(err, t, fmt.Sprintf("%s %s", out, err))
+
+ deleteImages("testfoobarbaz")
+
+ logDone("tag - busybox's image ID -> testfoobarbaz")
+}
+
+// ensure we don't allow the use of invalid tags; these tag operations should fail
+func TestTagInvalidUnprefixedRepo(t *testing.T) {
+ // skip this until we start blocking bad tags
+ t.Skip()
+
+ invalidRepos := []string{"-foo", "fo$z$", "Foo@3cc", "Foo$3", "Foo*3", "Fo^3", "Foo!3", "F)xcz(", "fo", "f"}
+
+ for _, repo := range invalidRepos {
+ tagCmd := exec.Command(dockerBinary, "tag", "busybox", repo)
+ _, _, err := runCommandWithOutput(tagCmd)
+ if err == nil {
+ t.Errorf("tag busybox %v should have failed", repo)
+ continue
+ }
+ logMessage := fmt.Sprintf("tag - busybox %v --> must fail", repo)
+ logDone(logMessage)
+ }
+}
+
+// ensure we allow the use of valid tags
+func TestTagValidPrefixedRepo(t *testing.T) {
+ pullCmd := exec.Command(dockerBinary, "pull", "busybox")
+ out, exitCode, err := runCommandWithOutput(pullCmd)
+ errorOut(err, t, fmt.Sprintf("%s %s", out, err))
+
+ if err != nil || exitCode != 0 {
+ t.Fatal("pulling the busybox image from the registry has failed")
+ }
+
+ validRepos := []string{"fooo/bar", "fooaa/test"}
+
+ for _, repo := range validRepos {
+ tagCmd := exec.Command(dockerBinary, "tag", "busybox", repo)
+ _, _, err := runCommandWithOutput(tagCmd)
+ if err != nil {
+ t.Errorf("tag busybox %v should have worked: %s", repo, err)
+ continue
+ }
+ deleteImages(repo)
+ logMessage := fmt.Sprintf("tag - busybox %v", repo)
+ logDone(logMessage)
+ }
+}
diff --git a/integration-cli/docker_cli_top_test.go b/integration-cli/docker_cli_top_test.go
new file mode 100644
index 0000000000..73d590cf06
--- /dev/null
+++ b/integration-cli/docker_cli_top_test.go
@@ -0,0 +1,32 @@
+package main
+
+import (
+ "fmt"
+ "os/exec"
+ "strings"
+ "testing"
+)
+
+func TestTop(t *testing.T) {
+ runCmd := exec.Command(dockerBinary, "run", "-i", "-d", "busybox", "sleep", "20")
+ out, _, err := runCommandWithOutput(runCmd)
+ errorOut(err, t, fmt.Sprintf("failed to start the container: %v", err))
+
+ cleanedContainerID := stripTrailingCharacters(out)
+
+ topCmd := exec.Command(dockerBinary, "top", cleanedContainerID)
+ out, _, err = runCommandWithOutput(topCmd)
+ errorOut(err, t, fmt.Sprintf("failed to run top: %v %v", out, err))
+
+ killCmd := exec.Command(dockerBinary, "kill", cleanedContainerID)
+ _, err = runCommand(killCmd)
+ errorOut(err, t, fmt.Sprintf("failed to kill container: %v", err))
+
+ deleteContainer(cleanedContainerID)
+
+ if !strings.Contains(out, "sleep 20") {
+ t.Fatal("top should've listed sleep 20 in the process list")
+ }
+
+ logDone("top - sleep process should be listed")
+}
diff --git a/integration-cli/docker_cli_version_test.go b/integration-cli/docker_cli_version_test.go
new file mode 100644
index 0000000000..f18d5bede6
--- /dev/null
+++ b/integration-cli/docker_cli_version_test.go
@@ -0,0 +1,39 @@
+package main
+
+import (
+ "fmt"
+ "os/exec"
+ "strings"
+ "testing"
+)
+
+// ensure docker version works
+func TestVersionEnsureSucceeds(t *testing.T) {
+ versionCmd := exec.Command(dockerBinary, "version")
+ out, exitCode, err := runCommandWithOutput(versionCmd)
+ errorOut(err, t, fmt.Sprintf("encountered error while running docker version: %v", err))
+
+ if err != nil || exitCode != 0 {
+ t.Fatal("failed to execute docker version")
+ }
+
+ stringsToCheck := []string{
+ "Client version:",
+ "Client API version:",
+ "Go version (client):",
+ "Git commit (client):",
+ "Server version:",
+ "Server API version:",
+ "Git commit (server):",
+ "Go version (server):",
+ "Last stable version:",
+ }
+
+ for _, linePrefix := range stringsToCheck {
+ if !strings.Contains(out, linePrefix) {
+ t.Errorf("couldn't find string %v in output", linePrefix)
+ }
+ }
+
+ logDone("version - verify that it works and that the output is properly formatted")
+}
diff --git a/integration-cli/docker_test_vars.go b/integration-cli/docker_test_vars.go
new file mode 100644
index 0000000000..f8bd5c116b
--- /dev/null
+++ b/integration-cli/docker_test_vars.go
@@ -0,0 +1,29 @@
+package main
+
+import (
+ "os"
+)
+
+// the docker binary to use
+var dockerBinary = "docker"
+
+// the private registry image to use for tests involving the registry
+var registryImageName = "registry"
+
+// the private registry to use for tests
+var privateRegistryURL = "127.0.0.1:5000"
+
+var workingDirectory string
+
+func init() {
+ if dockerBin := os.Getenv("DOCKER_BINARY"); dockerBin != "" {
+ dockerBinary = dockerBin
+ }
+ if registryImage := os.Getenv("REGISTRY_IMAGE"); registryImage != "" {
+ registryImageName = registryImage
+ }
+ if registry := os.Getenv("REGISTRY_URL"); registry != "" {
+ privateRegistryURL = registry
+ }
+ workingDirectory, _ = os.Getwd()
+}
diff --git a/integration-cli/docker_utils.go b/integration-cli/docker_utils.go
new file mode 100644
index 0000000000..6da86c9753
--- /dev/null
+++ b/integration-cli/docker_utils.go
@@ -0,0 +1,63 @@
+package main
+
+import (
+ "fmt"
+ "os/exec"
+ "strings"
+ "testing"
+)
+
+func deleteContainer(container string) error {
+ container = strings.Replace(container, "\n", " ", -1)
+ container = strings.Trim(container, " ")
+ rmArgs := fmt.Sprintf("rm %v", container)
+ rmSplitArgs := strings.Split(rmArgs, " ")
+ rmCmd := exec.Command(dockerBinary, rmSplitArgs...)
+ exitCode, err := runCommand(rmCmd)
+ // set error manually if not set
+ if exitCode != 0 && err == nil {
+ err = fmt.Errorf("failed to remove container: `docker rm` exit is non-zero")
+ }
+
+ return err
+}
+
+func getAllContainers() (string, error) {
+ getContainersCmd := exec.Command(dockerBinary, "ps", "-q", "-a")
+ out, exitCode, err := runCommandWithOutput(getContainersCmd)
+ if exitCode != 0 && err == nil {
+ err = fmt.Errorf("failed to get a list of containers: %v\n", out)
+ }
+
+ return out, err
+}
+
+func deleteAllContainers() error {
+ containers, err := getAllContainers()
+ if err != nil {
+ fmt.Println(containers)
+ return err
+ }
+
+ if err = deleteContainer(containers); err != nil {
+ return err
+ }
+ return nil
+}
+
+func deleteImages(images string) error {
+ rmiCmd := exec.Command(dockerBinary, "rmi", images)
+ exitCode, err := runCommand(rmiCmd)
+ // set error manually if not set
+ if exitCode != 0 && err == nil {
+ err = fmt.Errorf("failed to remove image: `docker rmi` exit is non-zero")
+ }
+
+ return err
+}
+
+func cmd(t *testing.T, args ...string) (string, int, error) {
+ out, status, err := runCommandWithOutput(exec.Command(dockerBinary, args...))
+ errorOut(err, t, fmt.Sprintf("'%s' failed with errors: %v (%v)", strings.Join(args, " "), err, out))
+ return out, status, err
+}
diff --git a/integration-cli/utils.go b/integration-cli/utils.go
new file mode 100644
index 0000000000..ae7af52687
--- /dev/null
+++ b/integration-cli/utils.go
@@ -0,0 +1,113 @@
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "os/exec"
+ "strings"
+ "syscall"
+ "testing"
+)
+
+func getExitCode(err error) (int, error) {
+ exitCode := 0
+ if exiterr, ok := err.(*exec.ExitError); ok {
+ if procExit := exiterr.Sys().(syscall.WaitStatus); ok {
+ return procExit.ExitStatus(), nil
+ }
+ }
+ return exitCode, fmt.Errorf("failed to get exit code")
+}
+
+func runCommandWithOutput(cmd *exec.Cmd) (output string, exitCode int, err error) {
+ exitCode = 0
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ var exiterr error
+ if exitCode, exiterr = getExitCode(err); exiterr != nil {
+ // TODO: Fix this so we check the error's text.
+ // we've failed to retrieve exit code, so we set it to 127
+ exitCode = 127
+ }
+ }
+ output = string(out)
+ return
+}
+
+func runCommandWithStdoutStderr(cmd *exec.Cmd) (stdout string, stderr string, exitCode int, err error) {
+ exitCode = 0
+ var stderrBuffer bytes.Buffer
+ stderrPipe, err := cmd.StderrPipe()
+ if err != nil {
+ return "", "", -1, err
+ }
+ go io.Copy(&stderrBuffer, stderrPipe)
+ out, err := cmd.Output()
+
+ if err != nil {
+ var exiterr error
+ if exitCode, exiterr = getExitCode(err); exiterr != nil {
+ // TODO: Fix this so we check the error's text.
+ // we've failed to retrieve exit code, so we set it to 127
+ exitCode = 127
+ }
+ }
+ stdout = string(out)
+ stderr = string(stderrBuffer.Bytes())
+ return
+}
+
+func runCommand(cmd *exec.Cmd) (exitCode int, err error) {
+ exitCode = 0
+ err = cmd.Run()
+ if err != nil {
+ var exiterr error
+ if exitCode, exiterr = getExitCode(err); exiterr != nil {
+ // TODO: Fix this so we check the error's text.
+ // we've failed to retrieve exit code, so we set it to 127
+ exitCode = 127
+ }
+ }
+ return
+}
+
+func startCommand(cmd *exec.Cmd) (exitCode int, err error) {
+ exitCode = 0
+ err = cmd.Start()
+ if err != nil {
+ var exiterr error
+ if exitCode, exiterr = getExitCode(err); exiterr != nil {
+ // TODO: Fix this so we check the error's text.
+ // we've failed to retrieve exit code, so we set it to 127
+ exitCode = 127
+ }
+ }
+ return
+}
+
+func logDone(message string) {
+ fmt.Printf("[PASSED]: %s\n", message)
+}
+
+func stripTrailingCharacters(target string) string {
+ target = strings.Trim(target, "\n")
+ target = strings.Trim(target, " ")
+ return target
+}
+
+func errorOut(err error, t *testing.T, message string) {
+ if err != nil {
+ t.Fatal(message)
+ }
+}
+
+func errorOutOnNonNilError(err error, t *testing.T, message string) {
+ if err == nil {
+ t.Fatalf(message)
+ }
+}
+
+func nLines(s string) int {
+ return strings.Count(s, "\n")
+}