diff options
Diffstat (limited to 'integration-cli')
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") +} |