diff --git a/integration-cli/docker_cli_attach_test.go b/integration-cli/docker_cli_attach_test.go new file mode 100644 index 0000000000..1480b807aa --- /dev/null +++ b/integration-cli/docker_cli_attach_test.go @@ -0,0 +1,51 @@ +package main + +import ( + "os/exec" + "strings" + "sync" + "testing" + "time" +) + +func TestMultipleAttachRestart(t *testing.T) { + cmd := exec.Command(dockerBinary, "run", "--name", "attacher", "-d", "busybox", + "/bin/sh", "-c", "sleep 1 && echo hello") + + group := sync.WaitGroup{} + group.Add(4) + + go func() { + defer group.Done() + out, _, err := runCommandWithOutput(cmd) + if err != nil { + t.Fatal(err, out) + } + }() + time.Sleep(500 * time.Millisecond) + + for i := 0; i < 3; i++ { + go func() { + defer group.Done() + c := exec.Command(dockerBinary, "attach", "attacher") + + out, _, err := runCommandWithOutput(c) + if err != nil { + t.Fatal(err, out) + } + if actual := strings.Trim(out, "\r\n"); actual != "hello" { + t.Fatalf("unexpected output %s expected hello", actual) + } + }() + } + + group.Wait() + + cmd = exec.Command(dockerBinary, "kill", "attacher") + if _, err := runCommand(cmd); err != nil { + t.Fatal(err) + } + deleteAllContainers() + + logDone("run - multiple attach") +} diff --git a/integration-cli/docker_cli_commit_test.go b/integration-cli/docker_cli_commit_test.go index 51adaac9df..e99379231e 100644 --- a/integration-cli/docker_cli_commit_test.go +++ b/integration-cli/docker_cli_commit_test.go @@ -3,6 +3,7 @@ package main import ( "fmt" "os/exec" + "strings" "testing" ) @@ -32,3 +33,32 @@ func TestCommitAfterContainerIsDone(t *testing.T) { logDone("commit - echo foo and commit the image") } + +func TestCommitNewFile(t *testing.T) { + cmd := exec.Command(dockerBinary, "run", "--name", "commiter", "busybox", "/bin/sh", "-c", "echo koye > /foo") + if _, err := runCommand(cmd); err != nil { + t.Fatal(err) + } + + cmd = exec.Command(dockerBinary, "commit", "commiter") + imageId, _, err := runCommandWithOutput(cmd) + if err != nil { + t.Fatal(err) + } + imageId = strings.Trim(imageId, "\r\n") + + cmd = exec.Command(dockerBinary, "run", imageId, "cat", "/foo") + + out, _, err := runCommandWithOutput(cmd) + if err != nil { + t.Fatal(err, out) + } + if actual := strings.Trim(out, "\r\n"); actual != "koye" { + t.Fatalf("expected output koye received %s", actual) + } + + deleteAllContainers() + deleteImages(imageId) + + logDone("commit - commit file and read") +} diff --git a/integration-cli/docker_cli_run_test.go b/integration-cli/docker_cli_run_test.go index b0805dd35c..d356f5f4de 100644 --- a/integration-cli/docker_cli_run_test.go +++ b/integration-cli/docker_cli_run_test.go @@ -2,8 +2,12 @@ package main import ( "fmt" + "os" "os/exec" + "regexp" + "sort" "strings" + "sync" "testing" ) @@ -384,3 +388,280 @@ func TestMultipleVolumesFrom(t *testing.T) { logDone("run - multiple volumes from") } + +// this tests verifies the ID format for the container +func TestVerifyContainerID(t *testing.T) { + cmd := exec.Command(dockerBinary, "run", "-d", "busybox", "true") + out, exit, err := runCommandWithOutput(cmd) + if err != nil { + t.Fatal(err) + } + if exit != 0 { + t.Fatalf("expected exit code 0 received %d", exit) + } + match, err := regexp.MatchString("^[0-9a-f]{64}$", strings.TrimSuffix(out, "\n")) + if err != nil { + t.Fatal(err) + } + if !match { + t.Fatalf("Invalid container ID: %s", out) + } + + deleteAllContainers() + + logDone("run - verify container ID") +} + +// Test that creating a container with a volume doesn't crash. Regression test for #995. +func TestCreateVolume(t *testing.T) { + cmd := exec.Command(dockerBinary, "run", "-v", "/var/lib/data", "busybox", "true") + if _, err := runCommand(cmd); err != nil { + t.Fatal(err) + } + + deleteAllContainers() + + logDone("run - create docker mangaed volume") +} + +func TestExitCode(t *testing.T) { + cmd := exec.Command(dockerBinary, "run", "busybox", "/bin/sh", "-c", "exit 72") + + exit, err := runCommand(cmd) + if err == nil { + t.Fatal("should not have a non nil error") + } + if exit != 72 { + t.Fatalf("expected exit code 72 received %d", exit) + } + + deleteAllContainers() + + logDone("run - correct exit code") +} + +func TestUserDefaultsToRoot(t *testing.T) { + cmd := exec.Command(dockerBinary, "run", "busybox", "id") + + out, _, err := runCommandWithOutput(cmd) + if err != nil { + t.Fatal(err, out) + } + if !strings.Contains(out, "uid=0(root) gid=0(root)") { + t.Fatalf("expected root user got %s", out) + } + deleteAllContainers() + + logDone("run - default user") +} + +func TestUserByName(t *testing.T) { + cmd := exec.Command(dockerBinary, "run", "-u", "root", "busybox", "id") + + out, _, err := runCommandWithOutput(cmd) + if err != nil { + t.Fatal(err, out) + } + if !strings.Contains(out, "uid=0(root) gid=0(root)") { + t.Fatalf("expected root user got %s", out) + } + deleteAllContainers() + + logDone("run - user by name") +} + +func TestUserByID(t *testing.T) { + cmd := exec.Command(dockerBinary, "run", "-u", "1", "busybox", "id") + + out, _, err := runCommandWithOutput(cmd) + if err != nil { + t.Fatal(err, out) + } + if !strings.Contains(out, "uid=1(daemon) gid=1(daemon)") { + t.Fatalf("expected daemon user got %s", out) + } + deleteAllContainers() + + logDone("run - user by id") +} + +func TestUserNotFound(t *testing.T) { + cmd := exec.Command(dockerBinary, "run", "-u", "notme", "busybox", "id") + + _, err := runCommand(cmd) + if err == nil { + t.Fatal("unknown user should cause container to fail") + } + deleteAllContainers() + + logDone("run - user not found") +} + +func TestRunTwoConcurrentContainers(t *testing.T) { + group := sync.WaitGroup{} + group.Add(2) + + for i := 0; i < 2; i++ { + go func() { + defer group.Done() + cmd := exec.Command(dockerBinary, "run", "busybox", "sleep", "2") + if _, err := runCommand(cmd); err != nil { + t.Fatal(err) + } + }() + } + + group.Wait() + + deleteAllContainers() + + logDone("run - two concurrent containers") +} + +func TestEnvironment(t *testing.T) { + cmd := exec.Command(dockerBinary, "run", "-h", "testing", "-e=FALSE=true", "-e=TRUE", "-e=TRICKY", "busybox", "env") + cmd.Env = append(os.Environ(), + "TRUE=false", + "TRICKY=tri\ncky\n", + ) + + out, _, err := runCommandWithOutput(cmd) + if err != nil { + t.Fatal(err, out) + } + + actualEnv := strings.Split(out, "\n") + if actualEnv[len(actualEnv)-1] == "" { + actualEnv = actualEnv[:len(actualEnv)-1] + } + sort.Strings(actualEnv) + + goodEnv := []string{ + "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", + "HOME=/", + "HOSTNAME=testing", + "FALSE=true", + "TRUE=false", + "TRICKY=tri", + "cky", + "", + } + sort.Strings(goodEnv) + if len(goodEnv) != len(actualEnv) { + t.Fatalf("Wrong environment: should be %d variables, not: '%s'\n", len(goodEnv), strings.Join(actualEnv, ", ")) + } + for i := range goodEnv { + if actualEnv[i] != goodEnv[i] { + t.Fatalf("Wrong environment variable: should be %s, not %s", goodEnv[i], actualEnv[i]) + } + } + + deleteAllContainers() + + logDone("run - verify environment") +} + +func TestContainerNetwork(t *testing.T) { + cmd := exec.Command(dockerBinary, "run", "busybox", "ping", "-c", "1", "127.0.0.1") + if _, err := runCommand(cmd); err != nil { + t.Fatal(err) + } + + deleteAllContainers() + + logDone("run - test container network via ping") +} + +// Issue #4681 +func TestLoopbackWhenNetworkDisabled(t *testing.T) { + cmd := exec.Command(dockerBinary, "run", "--networking=false", "busybox", "ping", "-c", "1", "127.0.0.1") + if _, err := runCommand(cmd); err != nil { + t.Fatal(err) + } + + deleteAllContainers() + + logDone("run - test container loopback when networking disabled") +} + +func TestLoopbackOnlyExistsWhenNetworkingDisabled(t *testing.T) { + cmd := exec.Command(dockerBinary, "run", "--networking=false", "busybox", "ip", "a", "show", "up") + out, _, err := runCommandWithOutput(cmd) + if err != nil { + t.Fatal(err, out) + } + + interfaces := regexp.MustCompile(`(?m)^[0-9]+: [a-zA-Z0-9]+`).FindAllString(out, -1) + if len(interfaces) != 1 { + t.Fatalf("Wrong interface count in test container: expected [*: lo], got %s", interfaces) + } + if !strings.HasSuffix(interfaces[0], ": lo") { + t.Fatalf("Wrong interface in test container: expected [*: lo], got %s", interfaces) + } + + deleteAllContainers() + + logDone("run - test loopback only exists when networking disabled") +} + +func TestPrivilegedCanMknod(t *testing.T) { + cmd := exec.Command(dockerBinary, "run", "--privileged", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok") + out, _, err := runCommandWithOutput(cmd) + if err != nil { + t.Fatal(err) + } + + if actual := strings.Trim(out, "\r\n"); actual != "ok" { + t.Fatalf("expected output ok received %s", actual) + } + deleteAllContainers() + + logDone("run - test privileged can mknod") +} + +func TestUnPrivilegedCanMknod(t *testing.T) { + cmd := exec.Command(dockerBinary, "run", "busybox", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok") + out, _, err := runCommandWithOutput(cmd) + if err != nil { + t.Fatal(err) + } + + if actual := strings.Trim(out, "\r\n"); actual != "ok" { + t.Fatalf("expected output ok received %s", actual) + } + deleteAllContainers() + + logDone("run - test un-privileged can mknod") +} + +func TestPrivilegedCanMount(t *testing.T) { + cmd := exec.Command(dockerBinary, "run", "--privileged", "busybox", "sh", "-c", "mount -t tmpfs none /tmp && echo ok") + + out, _, err := runCommandWithOutput(cmd) + if err != nil { + t.Fatal(err) + } + + if actual := strings.Trim(out, "\r\n"); actual != "ok" { + t.Fatalf("expected output ok received %s", actual) + } + deleteAllContainers() + + logDone("run - test privileged can mount") +} + +func TestUnPrivilegedCannotMount(t *testing.T) { + cmd := exec.Command(dockerBinary, "run", "busybox", "sh", "-c", "mount -t tmpfs none /tmp && echo ok") + + out, _, err := runCommandWithOutput(cmd) + if err == nil { + t.Fatal(err, out) + } + + if actual := strings.Trim(out, "\r\n"); actual == "ok" { + t.Fatalf("expected output not ok received %s", actual) + } + deleteAllContainers() + + logDone("run - test un-privileged cannot mount") +} diff --git a/integration/container_test.go b/integration/container_test.go index 018d7454cc..67b2783ce9 100644 --- a/integration/container_test.go +++ b/integration/container_test.go @@ -1,439 +1,17 @@ package docker import ( - "bufio" "fmt" "github.com/dotcloud/docker/runconfig" - "github.com/dotcloud/docker/utils" "io" "io/ioutil" "os" "path" - "regexp" - "sort" "strings" "testing" "time" ) -func TestIDFormat(t *testing.T) { - daemon := mkDaemon(t) - defer nuke(daemon) - container1, _, err := daemon.Create( - &runconfig.Config{ - Image: GetTestImage(daemon).ID, - Cmd: []string{"/bin/sh", "-c", "echo hello world"}, - }, - "", - ) - if err != nil { - t.Fatal(err) - } - match, err := regexp.Match("^[0-9a-f]{64}$", []byte(container1.ID)) - if err != nil { - t.Fatal(err) - } - if !match { - t.Fatalf("Invalid container ID: %s", container1.ID) - } -} - -func TestMultipleAttachRestart(t *testing.T) { - daemon := mkDaemon(t) - defer nuke(daemon) - container, _, _ := mkContainer( - daemon, - []string{"_", "/bin/sh", "-c", "i=1; while [ $i -le 5 ]; do i=`expr $i + 1`; echo hello; done"}, - t, - ) - defer daemon.Destroy(container) - - // Simulate 3 client attaching to the container and stop/restart - - stdout1, err := container.StdoutPipe() - if err != nil { - t.Fatal(err) - } - stdout2, err := container.StdoutPipe() - if err != nil { - t.Fatal(err) - } - stdout3, err := container.StdoutPipe() - if err != nil { - t.Fatal(err) - } - if err := container.Start(); err != nil { - t.Fatal(err) - } - l1, err := bufio.NewReader(stdout1).ReadString('\n') - if err != nil { - t.Fatal(err) - } - if strings.Trim(l1, " \r\n") != "hello" { - t.Fatalf("Unexpected output. Expected [%s], received [%s]", "hello", l1) - } - l2, err := bufio.NewReader(stdout2).ReadString('\n') - if err != nil { - t.Fatal(err) - } - if strings.Trim(l2, " \r\n") != "hello" { - t.Fatalf("Unexpected output. Expected [%s], received [%s]", "hello", l2) - } - l3, err := bufio.NewReader(stdout3).ReadString('\n') - if err != nil { - t.Fatal(err) - } - if strings.Trim(l3, " \r\n") != "hello" { - t.Fatalf("Unexpected output. Expected [%s], received [%s]", "hello", l3) - } - - if err := container.Stop(10); err != nil { - t.Fatal(err) - } - - stdout1, err = container.StdoutPipe() - if err != nil { - t.Fatal(err) - } - stdout2, err = container.StdoutPipe() - if err != nil { - t.Fatal(err) - } - stdout3, err = container.StdoutPipe() - if err != nil { - t.Fatal(err) - } - if err := container.Start(); err != nil { - t.Fatal(err) - } - - setTimeout(t, "Timeout reading from the process", 3*time.Second, func() { - l1, err = bufio.NewReader(stdout1).ReadString('\n') - if err != nil { - t.Fatal(err) - } - if strings.Trim(l1, " \r\n") != "hello" { - t.Fatalf("Unexpected output. Expected [%s], received [%s]", "hello", l1) - } - l2, err = bufio.NewReader(stdout2).ReadString('\n') - if err != nil { - t.Fatal(err) - } - if strings.Trim(l2, " \r\n") != "hello" { - t.Fatalf("Unexpected output. Expected [%s], received [%s]", "hello", l2) - } - l3, err = bufio.NewReader(stdout3).ReadString('\n') - if err != nil { - t.Fatal(err) - } - if strings.Trim(l3, " \r\n") != "hello" { - t.Fatalf("Unexpected output. Expected [%s], received [%s]", "hello", l3) - } - }) - container.Wait() -} - -func TestDiff(t *testing.T) { - eng := NewTestEngine(t) - daemon := mkDaemonFromEngine(eng, t) - defer nuke(daemon) - // Create a container and remove a file - container1, _, _ := mkContainer(daemon, []string{"_", "/bin/rm", "/etc/passwd"}, t) - defer daemon.Destroy(container1) - - // The changelog should be empty and not fail before run. See #1705 - c, err := container1.Changes() - if err != nil { - t.Fatal(err) - } - if len(c) != 0 { - t.Fatalf("Changelog should be empty before run") - } - - if err := container1.Run(); err != nil { - t.Fatal(err) - } - - // Check the changelog - c, err = container1.Changes() - if err != nil { - t.Fatal(err) - } - success := false - for _, elem := range c { - if elem.Path == "/etc/passwd" && elem.Kind == 2 { - success = true - } - } - if !success { - t.Fatalf("/etc/passwd as been removed but is not present in the diff") - } - - // Commit the container - img, err := daemon.Commit(container1, "", "", "unit test commited image - diff", "", nil) - if err != nil { - t.Fatal(err) - } - - // Create a new container from the commited image - container2, _, _ := mkContainer(daemon, []string{img.ID, "cat", "/etc/passwd"}, t) - defer daemon.Destroy(container2) - - if err := container2.Run(); err != nil { - t.Fatal(err) - } - - // Check the changelog - c, err = container2.Changes() - if err != nil { - t.Fatal(err) - } - for _, elem := range c { - if elem.Path == "/etc/passwd" { - t.Fatalf("/etc/passwd should not be present in the diff after commit.") - } - } - - // Create a new container - container3, _, _ := mkContainer(daemon, []string{"_", "rm", "/bin/httpd"}, t) - defer daemon.Destroy(container3) - - if err := container3.Run(); err != nil { - t.Fatal(err) - } - - // Check the changelog - c, err = container3.Changes() - if err != nil { - t.Fatal(err) - } - success = false - for _, elem := range c { - if elem.Path == "/bin/httpd" && elem.Kind == 2 { - success = true - } - } - if !success { - t.Fatalf("/bin/httpd should be present in the diff after commit.") - } -} - -func TestCommitAutoRun(t *testing.T) { - daemon := mkDaemon(t) - defer nuke(daemon) - container1, _, _ := mkContainer(daemon, []string{"_", "/bin/sh", "-c", "echo hello > /world"}, t) - defer daemon.Destroy(container1) - - if container1.State.IsRunning() { - t.Errorf("Container shouldn't be running") - } - if err := container1.Run(); err != nil { - t.Fatal(err) - } - if container1.State.IsRunning() { - t.Errorf("Container shouldn't be running") - } - - img, err := daemon.Commit(container1, "", "", "unit test commited image", "", &runconfig.Config{Cmd: []string{"cat", "/world"}}) - if err != nil { - t.Error(err) - } - - // FIXME: Make a TestCommit that stops here and check docker.root/layers/img.id/world - container2, _, _ := mkContainer(daemon, []string{img.ID}, t) - defer daemon.Destroy(container2) - stdout, err := container2.StdoutPipe() - if err != nil { - t.Fatal(err) - } - stderr, err := container2.StderrPipe() - if err != nil { - t.Fatal(err) - } - if err := container2.Start(); err != nil { - t.Fatal(err) - } - container2.Wait() - output, err := ioutil.ReadAll(stdout) - if err != nil { - t.Fatal(err) - } - output2, err := ioutil.ReadAll(stderr) - if err != nil { - t.Fatal(err) - } - if err := stdout.Close(); err != nil { - t.Fatal(err) - } - if err := stderr.Close(); err != nil { - t.Fatal(err) - } - if string(output) != "hello\n" { - t.Fatalf("Unexpected output. Expected %s, received: %s (err: %s)", "hello\n", output, output2) - } -} - -func TestCommitRun(t *testing.T) { - daemon := mkDaemon(t) - defer nuke(daemon) - - container1, _, _ := mkContainer(daemon, []string{"_", "/bin/sh", "-c", "echo hello > /world"}, t) - defer daemon.Destroy(container1) - - if container1.State.IsRunning() { - t.Errorf("Container shouldn't be running") - } - if err := container1.Run(); err != nil { - t.Fatal(err) - } - if container1.State.IsRunning() { - t.Errorf("Container shouldn't be running") - } - - img, err := daemon.Commit(container1, "", "", "unit test commited image", "", nil) - if err != nil { - t.Error(err) - } - - // FIXME: Make a TestCommit that stops here and check docker.root/layers/img.id/world - container2, _, _ := mkContainer(daemon, []string{img.ID, "cat", "/world"}, t) - defer daemon.Destroy(container2) - stdout, err := container2.StdoutPipe() - if err != nil { - t.Fatal(err) - } - stderr, err := container2.StderrPipe() - if err != nil { - t.Fatal(err) - } - if err := container2.Start(); err != nil { - t.Fatal(err) - } - container2.Wait() - output, err := ioutil.ReadAll(stdout) - if err != nil { - t.Fatal(err) - } - output2, err := ioutil.ReadAll(stderr) - if err != nil { - t.Fatal(err) - } - if err := stdout.Close(); err != nil { - t.Fatal(err) - } - if err := stderr.Close(); err != nil { - t.Fatal(err) - } - if string(output) != "hello\n" { - t.Fatalf("Unexpected output. Expected %s, received: %s (err: %s)", "hello\n", output, output2) - } -} - -func TestStart(t *testing.T) { - daemon := mkDaemon(t) - defer nuke(daemon) - container, _, _ := mkContainer(daemon, []string{"-i", "_", "/bin/cat"}, t) - defer daemon.Destroy(container) - - cStdin, err := container.StdinPipe() - if err != nil { - t.Fatal(err) - } - - if err := container.Start(); err != nil { - t.Fatal(err) - } - - // Give some time to the process to start - container.WaitTimeout(500 * time.Millisecond) - - if !container.State.IsRunning() { - t.Errorf("Container should be running") - } - if err := container.Start(); err != nil { - t.Fatalf("A running container should be able to be started") - } - - // Try to avoid the timeout in destroy. Best effort, don't check error - cStdin.Close() - container.WaitTimeout(2 * time.Second) -} - -func TestCpuShares(t *testing.T) { - _, err1 := os.Stat("/sys/fs/cgroup/cpuacct,cpu") - _, err2 := os.Stat("/sys/fs/cgroup/cpu,cpuacct") - if err1 == nil || err2 == nil { - t.Skip("Fixme. Setting cpu cgroup shares doesn't work in dind on a Fedora host. The lxc utils are confused by the cpu,cpuacct mount.") - } - daemon := mkDaemon(t) - defer nuke(daemon) - container, _, _ := mkContainer(daemon, []string{"-m", "33554432", "-c", "1000", "-i", "_", "/bin/cat"}, t) - defer daemon.Destroy(container) - - cStdin, err := container.StdinPipe() - if err != nil { - t.Fatal(err) - } - - if err := container.Start(); err != nil { - t.Fatal(err) - } - - // Give some time to the process to start - container.WaitTimeout(500 * time.Millisecond) - - if !container.State.IsRunning() { - t.Errorf("Container should be running") - } - if err := container.Start(); err != nil { - t.Fatalf("A running container should be able to be started") - } - - // Try to avoid the timeout in destroy. Best effort, don't check error - cStdin.Close() - container.WaitTimeout(2 * time.Second) -} - -func TestRun(t *testing.T) { - daemon := mkDaemon(t) - defer nuke(daemon) - container, _, _ := mkContainer(daemon, []string{"_", "ls", "-al"}, t) - defer daemon.Destroy(container) - - if container.State.IsRunning() { - t.Errorf("Container shouldn't be running") - } - if err := container.Run(); err != nil { - t.Fatal(err) - } - if container.State.IsRunning() { - t.Errorf("Container shouldn't be running") - } -} - -func TestOutput(t *testing.T) { - daemon := mkDaemon(t) - defer nuke(daemon) - container, _, err := daemon.Create( - &runconfig.Config{ - Image: GetTestImage(daemon).ID, - Cmd: []string{"echo", "-n", "foobar"}, - }, - "", - ) - if err != nil { - t.Fatal(err) - } - defer daemon.Destroy(container) - output, err := container.Output() - if err != nil { - t.Fatal(err) - } - if string(output) != "foobar" { - t.Fatalf("%s != %s", string(output), "foobar") - } -} - func TestKillDifferentUser(t *testing.T) { daemon := mkDaemon(t) defer nuke(daemon) @@ -492,119 +70,6 @@ func TestKillDifferentUser(t *testing.T) { } } -// Test that creating a container with a volume doesn't crash. Regression test for #995. -func TestCreateVolume(t *testing.T) { - eng := NewTestEngine(t) - daemon := mkDaemonFromEngine(eng, t) - defer nuke(daemon) - - config, hc, _, err := runconfig.Parse([]string{"-v", "/var/lib/data", unitTestImageID, "echo", "hello", "world"}, nil) - if err != nil { - t.Fatal(err) - } - jobCreate := eng.Job("create") - if err := jobCreate.ImportEnv(config); err != nil { - t.Fatal(err) - } - var id string - jobCreate.Stdout.AddString(&id) - if err := jobCreate.Run(); err != nil { - t.Fatal(err) - } - jobStart := eng.Job("start", id) - if err := jobStart.ImportEnv(hc); err != nil { - t.Fatal(err) - } - if err := jobStart.Run(); err != nil { - t.Fatal(err) - } - // FIXME: this hack can be removed once Wait is a job - c := daemon.Get(id) - if c == nil { - t.Fatalf("Couldn't retrieve container %s from daemon", id) - } - c.WaitTimeout(500 * time.Millisecond) - c.Wait() -} - -func TestKill(t *testing.T) { - daemon := mkDaemon(t) - defer nuke(daemon) - container, _, err := daemon.Create(&runconfig.Config{ - Image: GetTestImage(daemon).ID, - Cmd: []string{"sleep", "2"}, - }, - "", - ) - if err != nil { - t.Fatal(err) - } - defer daemon.Destroy(container) - - if container.State.IsRunning() { - t.Errorf("Container shouldn't be running") - } - if err := container.Start(); err != nil { - t.Fatal(err) - } - - // Give some time to lxc to spawn the process - container.WaitTimeout(500 * time.Millisecond) - - if !container.State.IsRunning() { - t.Errorf("Container should be running") - } - if err := container.Kill(); err != nil { - t.Fatal(err) - } - if container.State.IsRunning() { - t.Errorf("Container shouldn't be running") - } - container.Wait() - if container.State.IsRunning() { - t.Errorf("Container shouldn't be running") - } - // Try stopping twice - if err := container.Kill(); err != nil { - t.Fatal(err) - } -} - -func TestExitCode(t *testing.T) { - daemon := mkDaemon(t) - defer nuke(daemon) - - trueContainer, _, err := daemon.Create(&runconfig.Config{ - Image: GetTestImage(daemon).ID, - Cmd: []string{"/bin/true"}, - }, "") - if err != nil { - t.Fatal(err) - } - defer daemon.Destroy(trueContainer) - if err := trueContainer.Run(); err != nil { - t.Fatal(err) - } - if code := trueContainer.State.GetExitCode(); code != 0 { - t.Fatalf("Unexpected exit code %d (expected 0)", code) - } - - falseContainer, _, err := daemon.Create(&runconfig.Config{ - Image: GetTestImage(daemon).ID, - Cmd: []string{"/bin/false"}, - }, "") - if err != nil { - t.Fatal(err) - } - defer daemon.Destroy(falseContainer) - if err := falseContainer.Run(); err != nil { - t.Fatal(err) - } - if code := falseContainer.State.GetExitCode(); code != 1 { - t.Fatalf("Unexpected exit code %d (expected 1)", code) - } -} - func TestRestart(t *testing.T) { daemon := mkDaemon(t) defer nuke(daemon) @@ -712,190 +177,6 @@ func TestRestartStdin(t *testing.T) { } } -func TestUser(t *testing.T) { - daemon := mkDaemon(t) - defer nuke(daemon) - - // Default user must be root - container, _, err := daemon.Create(&runconfig.Config{ - Image: GetTestImage(daemon).ID, - Cmd: []string{"id"}, - }, - "", - ) - if err != nil { - t.Fatal(err) - } - defer daemon.Destroy(container) - output, err := container.Output() - if err != nil { - t.Fatal(err) - } - if !strings.Contains(string(output), "uid=0(root) gid=0(root)") { - t.Error(string(output)) - } - - // Set a username - container, _, err = daemon.Create(&runconfig.Config{ - Image: GetTestImage(daemon).ID, - Cmd: []string{"id"}, - - User: "root", - }, - "", - ) - if err != nil { - t.Fatal(err) - } - defer daemon.Destroy(container) - output, err = container.Output() - if code := container.State.GetExitCode(); err != nil || code != 0 { - t.Fatal(err) - } - if !strings.Contains(string(output), "uid=0(root) gid=0(root)") { - t.Error(string(output)) - } - - // Set a UID - container, _, err = daemon.Create(&runconfig.Config{ - Image: GetTestImage(daemon).ID, - Cmd: []string{"id"}, - - User: "0", - }, - "", - ) - if code := container.State.GetExitCode(); err != nil || code != 0 { - t.Fatal(err) - } - defer daemon.Destroy(container) - output, err = container.Output() - if code := container.State.GetExitCode(); err != nil || code != 0 { - t.Fatal(err) - } - if !strings.Contains(string(output), "uid=0(root) gid=0(root)") { - t.Error(string(output)) - } - - // Set a different user by uid - container, _, err = daemon.Create(&runconfig.Config{ - Image: GetTestImage(daemon).ID, - Cmd: []string{"id"}, - - User: "1", - }, - "", - ) - if err != nil { - t.Fatal(err) - } - defer daemon.Destroy(container) - output, err = container.Output() - if err != nil { - t.Fatal(err) - } else if code := container.State.GetExitCode(); code != 0 { - t.Fatalf("Container exit code is invalid: %d\nOutput:\n%s\n", code, output) - } - if !strings.Contains(string(output), "uid=1(daemon) gid=1(daemon)") { - t.Error(string(output)) - } - - // Set a different user by username - container, _, err = daemon.Create(&runconfig.Config{ - Image: GetTestImage(daemon).ID, - Cmd: []string{"id"}, - - User: "daemon", - }, - "", - ) - if err != nil { - t.Fatal(err) - } - defer daemon.Destroy(container) - output, err = container.Output() - if code := container.State.GetExitCode(); err != nil || code != 0 { - t.Fatal(err) - } - if !strings.Contains(string(output), "uid=1(daemon) gid=1(daemon)") { - t.Error(string(output)) - } - - // Test an wrong username - container, _, err = daemon.Create(&runconfig.Config{ - Image: GetTestImage(daemon).ID, - Cmd: []string{"id"}, - - User: "unknownuser", - }, - "", - ) - if err != nil { - t.Fatal(err) - } - defer daemon.Destroy(container) - output, err = container.Output() - if container.State.GetExitCode() == 0 { - t.Fatal("Starting container with wrong uid should fail but it passed.") - } -} - -func TestMultipleContainers(t *testing.T) { - daemon := mkDaemon(t) - defer nuke(daemon) - - container1, _, err := daemon.Create(&runconfig.Config{ - Image: GetTestImage(daemon).ID, - Cmd: []string{"sleep", "2"}, - }, - "", - ) - if err != nil { - t.Fatal(err) - } - defer daemon.Destroy(container1) - - container2, _, err := daemon.Create(&runconfig.Config{ - Image: GetTestImage(daemon).ID, - Cmd: []string{"sleep", "2"}, - }, - "", - ) - if err != nil { - t.Fatal(err) - } - defer daemon.Destroy(container2) - - // Start both containers - if err := container1.Start(); err != nil { - t.Fatal(err) - } - if err := container2.Start(); err != nil { - t.Fatal(err) - } - - // Make sure they are running before trying to kill them - container1.WaitTimeout(250 * time.Millisecond) - container2.WaitTimeout(250 * time.Millisecond) - - // If we are here, both containers should be running - if !container1.State.IsRunning() { - t.Fatal("Container not running") - } - if !container2.State.IsRunning() { - t.Fatal("Container not running") - } - - // Kill them - if err := container1.Kill(); err != nil { - t.Fatal(err) - } - - if err := container2.Kill(); err != nil { - t.Fatal(err) - } -} - func TestStdin(t *testing.T) { daemon := mkDaemon(t) defer nuke(daemon) @@ -986,60 +267,6 @@ func TestTty(t *testing.T) { } } -func TestEnv(t *testing.T) { - os.Setenv("TRUE", "false") - os.Setenv("TRICKY", "tri\ncky\n") - daemon := mkDaemon(t) - defer nuke(daemon) - config, _, _, err := runconfig.Parse([]string{"-e=FALSE=true", "-e=TRUE", "-e=TRICKY", GetTestImage(daemon).ID, "env"}, nil) - if err != nil { - t.Fatal(err) - } - container, _, err := daemon.Create(config, "") - if err != nil { - t.Fatal(err) - } - defer daemon.Destroy(container) - - stdout, err := container.StdoutPipe() - if err != nil { - t.Fatal(err) - } - defer stdout.Close() - if err := container.Start(); err != nil { - t.Fatal(err) - } - container.Wait() - output, err := ioutil.ReadAll(stdout) - if err != nil { - t.Fatal(err) - } - actualEnv := strings.Split(string(output), "\n") - if actualEnv[len(actualEnv)-1] == "" { - actualEnv = actualEnv[:len(actualEnv)-1] - } - sort.Strings(actualEnv) - goodEnv := []string{ - "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", - "HOME=/", - "HOSTNAME=" + utils.TruncateID(container.ID), - "FALSE=true", - "TRUE=false", - "TRICKY=tri", - "cky", - "", - } - sort.Strings(goodEnv) - if len(goodEnv) != len(actualEnv) { - t.Fatalf("Wrong environment: should be %d variables, not: '%s'\n", len(goodEnv), strings.Join(actualEnv, ", ")) - } - for i := range goodEnv { - if actualEnv[i] != goodEnv[i] { - t.Fatalf("Wrong environment variable: should be %s, not %s", goodEnv[i], actualEnv[i]) - } - } -} - func TestEntrypoint(t *testing.T) { daemon := mkDaemon(t) defer nuke(daemon) @@ -1316,139 +543,3 @@ func TestRestartWithVolumes(t *testing.T) { t.Fatalf("Expected volume path: %s Actual path: %s", expected, actual) } } - -func TestContainerNetwork(t *testing.T) { - daemon := mkDaemon(t) - defer nuke(daemon) - container, _, err := daemon.Create( - &runconfig.Config{ - Image: GetTestImage(daemon).ID, - // If I change this to ping 8.8.8.8 it fails. Any idea why? - timthelion - Cmd: []string{"ping", "-c", "1", "127.0.0.1"}, - }, - "", - ) - if err != nil { - t.Fatal(err) - } - defer daemon.Destroy(container) - if err := container.Run(); err != nil { - t.Fatal(err) - } - if code := container.State.GetExitCode(); code != 0 { - t.Fatalf("Unexpected ping 127.0.0.1 exit code %d (expected 0)", code) - } -} - -// Issue #4681 -func TestLoopbackFunctionsWhenNetworkingIsDissabled(t *testing.T) { - daemon := mkDaemon(t) - defer nuke(daemon) - container, _, err := daemon.Create( - &runconfig.Config{ - Image: GetTestImage(daemon).ID, - Cmd: []string{"ping", "-c", "1", "127.0.0.1"}, - NetworkDisabled: true, - }, - "", - ) - if err != nil { - t.Fatal(err) - } - defer daemon.Destroy(container) - if err := container.Run(); err != nil { - t.Fatal(err) - } - if code := container.State.GetExitCode(); code != 0 { - t.Fatalf("Unexpected ping 127.0.0.1 exit code %d (expected 0)", code) - } -} - -func TestOnlyLoopbackExistsWhenUsingDisableNetworkOption(t *testing.T) { - eng := NewTestEngine(t) - daemon := mkDaemonFromEngine(eng, t) - defer nuke(daemon) - - config, hc, _, err := runconfig.Parse([]string{"-n=false", GetTestImage(daemon).ID, "ip", "addr", "show", "up"}, nil) - if err != nil { - t.Fatal(err) - } - - jobCreate := eng.Job("create") - if err := jobCreate.ImportEnv(config); err != nil { - t.Fatal(err) - } - var id string - jobCreate.Stdout.AddString(&id) - if err := jobCreate.Run(); err != nil { - t.Fatal(err) - } - // FIXME: this hack can be removed once Wait is a job - c := daemon.Get(id) - if c == nil { - t.Fatalf("Couldn't retrieve container %s from daemon", id) - } - stdout, err := c.StdoutPipe() - if err != nil { - t.Fatal(err) - } - - jobStart := eng.Job("start", id) - if err := jobStart.ImportEnv(hc); err != nil { - t.Fatal(err) - } - if err := jobStart.Run(); err != nil { - t.Fatal(err) - } - - c.WaitTimeout(500 * time.Millisecond) - c.Wait() - output, err := ioutil.ReadAll(stdout) - if err != nil { - t.Fatal(err) - } - - interfaces := regexp.MustCompile(`(?m)^[0-9]+: [a-zA-Z0-9]+`).FindAllString(string(output), -1) - if len(interfaces) != 1 { - t.Fatalf("Wrong interface count in test container: expected [*: lo], got %s", interfaces) - } - if !strings.HasSuffix(interfaces[0], ": lo") { - t.Fatalf("Wrong interface in test container: expected [*: lo], got %s", interfaces) - } -} - -func TestPrivilegedCanMknod(t *testing.T) { - eng := NewTestEngine(t) - daemon := mkDaemonFromEngine(eng, t) - defer daemon.Nuke() - if output, err := runContainer(eng, daemon, []string{"--privileged", "_", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok"}, t); output != "ok\n" { - t.Fatalf("Could not mknod into privileged container %s %v", output, err) - } -} - -func TestPrivilegedCanMount(t *testing.T) { - eng := NewTestEngine(t) - daemon := mkDaemonFromEngine(eng, t) - defer daemon.Nuke() - if output, _ := runContainer(eng, daemon, []string{"--privileged", "_", "sh", "-c", "mount -t tmpfs none /tmp && echo ok"}, t); output != "ok\n" { - t.Fatal("Could not mount into privileged container") - } -} - -func TestUnprivilegedCanMknod(t *testing.T) { - eng := NewTestEngine(t) - daemon := mkDaemonFromEngine(eng, t) - defer daemon.Nuke() - if output, _ := runContainer(eng, daemon, []string{"_", "sh", "-c", "mknod /tmp/sda b 8 0 && echo ok"}, t); output != "ok\n" { - t.Fatal("Couldn't mknod into secure container") - } -} - -func TestUnprivilegedCannotMount(t *testing.T) { - eng := NewTestEngine(t) - daemon := mkDaemonFromEngine(eng, t) - defer daemon.Nuke() - if output, _ := runContainer(eng, daemon, []string{"_", "sh", "-c", "mount -t tmpfs none /tmp || echo ok"}, t); output != "ok\n" { - t.Fatal("Could mount into secure container") - } -} diff --git a/integration/iptables_test.go b/integration/iptables_test.go deleted file mode 100644 index 1dd4194350..0000000000 --- a/integration/iptables_test.go +++ /dev/null @@ -1,22 +0,0 @@ -package docker - -import ( - "github.com/dotcloud/docker/pkg/iptables" - "os" - "testing" -) - -// FIXME: this test should be a unit test. -// For example by mocking os/exec to make sure iptables is not actually called. - -func TestIptables(t *testing.T) { - if _, err := iptables.Raw("-L"); err != nil { - t.Fatal(err) - } - path := os.Getenv("PATH") - os.Setenv("PATH", "") - defer os.Setenv("PATH", path) - if _, err := iptables.Raw("-L"); err == nil { - t.Fatal("Not finding iptables in the PATH should cause an error") - } -}