浏览代码

Merge pull request #12292 from cpuguy83/remove_commands_integration

Remove commands integration
Phil Estes 10 年之前
父节点
当前提交
2f0f04e8fa

+ 0 - 9
daemon/container.go

@@ -14,7 +14,6 @@ import (
 	"syscall"
 	"syscall"
 	"time"
 	"time"
 
 
-	"github.com/docker/libcontainer"
 	"github.com/docker/libcontainer/configs"
 	"github.com/docker/libcontainer/configs"
 	"github.com/docker/libcontainer/devices"
 	"github.com/docker/libcontainer/devices"
 	"github.com/docker/libcontainer/label"
 	"github.com/docker/libcontainer/label"
@@ -1020,14 +1019,6 @@ func (container *Container) Exposes(p nat.Port) bool {
 	return exists
 	return exists
 }
 }
 
 
-func (container *Container) GetPtyMaster() (libcontainer.Console, error) {
-	ttyConsole, ok := container.command.ProcessConfig.Terminal.(execdriver.TtyTerminal)
-	if !ok {
-		return nil, ErrNoTTY
-	}
-	return ttyConsole.Master(), nil
-}
-
 func (container *Container) HostConfig() *runconfig.HostConfig {
 func (container *Container) HostConfig() *runconfig.HostConfig {
 	container.Lock()
 	container.Lock()
 	res := container.hostConfig
 	res := container.hostConfig

+ 49 - 0
integration-cli/docker_cli_attach_test.go

@@ -1,6 +1,7 @@
 package main
 package main
 
 
 import (
 import (
+	"bufio"
 	"io"
 	"io"
 	"os/exec"
 	"os/exec"
 	"strings"
 	"strings"
@@ -134,3 +135,51 @@ func TestAttachTtyWithoutStdin(t *testing.T) {
 
 
 	logDone("attach - forbid piped stdin to tty enabled container")
 	logDone("attach - forbid piped stdin to tty enabled container")
 }
 }
+
+func TestAttachDisconnect(t *testing.T) {
+	defer deleteAllContainers()
+	out, _, _ := dockerCmd(t, "run", "-di", "busybox", "/bin/cat")
+	id := strings.TrimSpace(out)
+
+	cmd := exec.Command(dockerBinary, "attach", id)
+	stdin, err := cmd.StdinPipe()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer stdin.Close()
+	stdout, err := cmd.StdoutPipe()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer stdout.Close()
+	if err := cmd.Start(); err != nil {
+		t.Fatal(err)
+	}
+	defer cmd.Process.Kill()
+
+	if _, err := stdin.Write([]byte("hello\n")); err != nil {
+		t.Fatal(err)
+	}
+	out, err = bufio.NewReader(stdout).ReadString('\n')
+	if err != nil {
+		t.Fatal(err)
+	}
+	if strings.TrimSpace(out) != "hello" {
+		t.Fatalf("exepected 'hello', got %q", out)
+	}
+
+	if err := stdin.Close(); err != nil {
+		t.Fatal(err)
+	}
+
+	// Expect container to still be running after stdin is closed
+	running, err := inspectField(id, "State.Running")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if running != "true" {
+		t.Fatal("exepected container to still be running")
+	}
+
+	logDone("attach - disconnect")
+}

+ 149 - 0
integration-cli/docker_cli_attach_unix_test.go

@@ -3,11 +3,13 @@
 package main
 package main
 
 
 import (
 import (
+	"bufio"
 	"os/exec"
 	"os/exec"
 	"strings"
 	"strings"
 	"testing"
 	"testing"
 	"time"
 	"time"
 
 
+	"github.com/docker/docker/pkg/stringid"
 	"github.com/kr/pty"
 	"github.com/kr/pty"
 )
 )
 
 
@@ -137,3 +139,150 @@ func TestAttachAfterDetach(t *testing.T) {
 
 
 	logDone("attach - reconnect after detaching")
 	logDone("attach - reconnect after detaching")
 }
 }
+
+// TestAttachDetach checks that attach in tty mode can be detached using the long container ID
+func TestAttachDetach(t *testing.T) {
+	out, _, _ := dockerCmd(t, "run", "-itd", "busybox", "cat")
+	id := strings.TrimSpace(out)
+	if err := waitRun(id); err != nil {
+		t.Fatal(err)
+	}
+
+	cpty, tty, err := pty.Open()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer cpty.Close()
+
+	cmd := exec.Command(dockerBinary, "attach", id)
+	cmd.Stdin = tty
+	stdout, err := cmd.StdoutPipe()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer stdout.Close()
+	if err := cmd.Start(); err != nil {
+		t.Fatal(err)
+	}
+	if err := waitRun(id); err != nil {
+		t.Fatalf("error waiting for container to start: %v", err)
+	}
+
+	if _, err := cpty.Write([]byte("hello\n")); err != nil {
+		t.Fatal(err)
+	}
+	out, err = bufio.NewReader(stdout).ReadString('\n')
+	if err != nil {
+		t.Fatal(err)
+	}
+	if strings.TrimSpace(out) != "hello" {
+		t.Fatalf("exepected 'hello', got %q", out)
+	}
+
+	// escape sequence
+	if _, err := cpty.Write([]byte{16}); err != nil {
+		t.Fatal(err)
+	}
+	time.Sleep(100 * time.Millisecond)
+	if _, err := cpty.Write([]byte{17}); err != nil {
+		t.Fatal(err)
+	}
+
+	ch := make(chan struct{})
+	go func() {
+		cmd.Wait()
+		ch <- struct{}{}
+	}()
+
+	running, err := inspectField(id, "State.Running")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if running != "true" {
+		t.Fatal("exepected container to still be running")
+	}
+
+	go func() {
+		dockerCmd(t, "kill", id)
+	}()
+
+	select {
+	case <-ch:
+	case <-time.After(10 * time.Millisecond):
+		t.Fatal("timed out waiting for container to exit")
+	}
+
+	logDone("attach - detach")
+}
+
+// TestAttachDetachTruncatedID checks that attach in tty mode can be detached
+func TestAttachDetachTruncatedID(t *testing.T) {
+	out, _, _ := dockerCmd(t, "run", "-itd", "busybox", "cat")
+	id := stringid.TruncateID(strings.TrimSpace(out))
+	if err := waitRun(id); err != nil {
+		t.Fatal(err)
+	}
+
+	cpty, tty, err := pty.Open()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer cpty.Close()
+
+	cmd := exec.Command(dockerBinary, "attach", id)
+	cmd.Stdin = tty
+	stdout, err := cmd.StdoutPipe()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer stdout.Close()
+	if err := cmd.Start(); err != nil {
+		t.Fatal(err)
+	}
+
+	if _, err := cpty.Write([]byte("hello\n")); err != nil {
+		t.Fatal(err)
+	}
+	out, err = bufio.NewReader(stdout).ReadString('\n')
+	if err != nil {
+		t.Fatal(err)
+	}
+	if strings.TrimSpace(out) != "hello" {
+		t.Fatalf("exepected 'hello', got %q", out)
+	}
+
+	// escape sequence
+	if _, err := cpty.Write([]byte{16}); err != nil {
+		t.Fatal(err)
+	}
+	time.Sleep(100 * time.Millisecond)
+	if _, err := cpty.Write([]byte{17}); err != nil {
+		t.Fatal(err)
+	}
+
+	ch := make(chan struct{})
+	go func() {
+		cmd.Wait()
+		ch <- struct{}{}
+	}()
+
+	running, err := inspectField(id, "State.Running")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if running != "true" {
+		t.Fatal("exepected container to still be running")
+	}
+
+	go func() {
+		dockerCmd(t, "kill", id)
+	}()
+
+	select {
+	case <-ch:
+	case <-time.After(10 * time.Millisecond):
+		t.Fatal("timed out waiting for container to exit")
+	}
+
+	logDone("attach - detach truncated ID")
+}

+ 71 - 0
integration-cli/docker_cli_run_unix_test.go

@@ -3,6 +3,7 @@
 package main
 package main
 
 
 import (
 import (
+	"bufio"
 	"fmt"
 	"fmt"
 	"io/ioutil"
 	"io/ioutil"
 	"os"
 	"os"
@@ -201,3 +202,73 @@ func TestRunDeviceDirectory(t *testing.T) {
 
 
 	logDone("run - test --device directory mounts all internal devices")
 	logDone("run - test --device directory mounts all internal devices")
 }
 }
+
+// TestRunDetach checks attaching and detaching with the escape sequence.
+func TestRunAttachDetach(t *testing.T) {
+	defer deleteAllContainers()
+	name := "attach-detach"
+	cmd := exec.Command(dockerBinary, "run", "--name", name, "-it", "busybox", "cat")
+	stdout, err := cmd.StdoutPipe()
+	if err != nil {
+		t.Fatal(err)
+	}
+	cpty, tty, err := pty.Open()
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer cpty.Close()
+	cmd.Stdin = tty
+	if err := cmd.Start(); err != nil {
+		t.Fatal(err)
+	}
+	if err := waitRun(name); err != nil {
+		t.Fatal(err)
+	}
+
+	if _, err := cpty.Write([]byte("hello\n")); err != nil {
+		t.Fatal(err)
+	}
+
+	out, err := bufio.NewReader(stdout).ReadString('\n')
+	if err != nil {
+		t.Fatal(err)
+	}
+	if strings.TrimSpace(out) != "hello" {
+		t.Fatalf("exepected 'hello', got %q", out)
+	}
+
+	// escape sequence
+	if _, err := cpty.Write([]byte{16}); err != nil {
+		t.Fatal(err)
+	}
+	time.Sleep(100 * time.Millisecond)
+	if _, err := cpty.Write([]byte{17}); err != nil {
+		t.Fatal(err)
+	}
+
+	ch := make(chan struct{})
+	go func() {
+		cmd.Wait()
+		ch <- struct{}{}
+	}()
+
+	running, err := inspectField(name, "State.Running")
+	if err != nil {
+		t.Fatal(err)
+	}
+	if running != "true" {
+		t.Fatal("exepected container to still be running")
+	}
+
+	go func() {
+		dockerCmd(t, "kill", name)
+	}()
+
+	select {
+	case <-ch:
+	case <-time.After(10 * time.Millisecond):
+		t.Fatal("timed out waiting for container to exit")
+	}
+
+	logDone("run - attach detach")
+}

+ 10 - 1
integration-cli/utils.go

@@ -213,7 +213,16 @@ func waitInspect(name, expr, expected string, timeout int) error {
 		cmd := exec.Command(dockerBinary, "inspect", "-f", expr, name)
 		cmd := exec.Command(dockerBinary, "inspect", "-f", expr, name)
 		out, _, err := runCommandWithOutput(cmd)
 		out, _, err := runCommandWithOutput(cmd)
 		if err != nil {
 		if err != nil {
-			return fmt.Errorf("error executing docker inspect: %v", err)
+			if !strings.Contains(out, "No such") {
+				return fmt.Errorf("error executing docker inspect: %v\n%s", err, out)
+			}
+			select {
+			case <-after:
+				return err
+			default:
+				time.Sleep(10 * time.Millisecond)
+				continue
+			}
 		}
 		}
 
 
 		out = strings.TrimSpace(out)
 		out = strings.TrimSpace(out)

+ 0 - 436
integration/commands_test.go

@@ -1,436 +0,0 @@
-package docker
-
-import (
-	"bufio"
-	"fmt"
-	"io"
-	"io/ioutil"
-	"strings"
-	"testing"
-	"time"
-
-	"github.com/Sirupsen/logrus"
-	"github.com/docker/docker/api/client"
-	"github.com/docker/docker/daemon"
-	"github.com/docker/docker/pkg/stringid"
-	"github.com/docker/docker/pkg/term"
-	"github.com/kr/pty"
-)
-
-func closeWrap(args ...io.Closer) error {
-	e := false
-	ret := fmt.Errorf("Error closing elements")
-	for _, c := range args {
-		if err := c.Close(); err != nil {
-			e = true
-			ret = fmt.Errorf("%s\n%s", ret, err)
-		}
-	}
-	if e {
-		return ret
-	}
-	return nil
-}
-
-func setRaw(t *testing.T, c *daemon.Container) *term.State {
-	pty, err := c.GetPtyMaster()
-	if err != nil {
-		t.Fatal(err)
-	}
-	state, err := term.MakeRaw(pty.Fd())
-	if err != nil {
-		t.Fatal(err)
-	}
-	return state
-}
-
-func unsetRaw(t *testing.T, c *daemon.Container, state *term.State) {
-	pty, err := c.GetPtyMaster()
-	if err != nil {
-		t.Fatal(err)
-	}
-	term.RestoreTerminal(pty.Fd(), state)
-}
-
-func waitContainerStart(t *testing.T, timeout time.Duration) *daemon.Container {
-	var container *daemon.Container
-
-	setTimeout(t, "Waiting for the container to be started timed out", timeout, func() {
-		for {
-			l := globalDaemon.List()
-			if len(l) == 1 && l[0].IsRunning() {
-				container = l[0]
-				break
-			}
-			time.Sleep(10 * time.Millisecond)
-		}
-	})
-
-	if container == nil {
-		t.Fatal("An error occured while waiting for the container to start")
-	}
-
-	return container
-}
-
-func setTimeout(t *testing.T, msg string, d time.Duration, f func()) {
-	c := make(chan bool)
-
-	// Make sure we are not too long
-	go func() {
-		time.Sleep(d)
-		c <- true
-	}()
-	go func() {
-		f()
-		c <- false
-	}()
-	if <-c && msg != "" {
-		t.Fatal(msg)
-	}
-}
-
-func expectPipe(expected string, r io.Reader) error {
-	o, err := bufio.NewReader(r).ReadString('\n')
-	if err != nil {
-		return err
-	}
-	if strings.Trim(o, " \r\n") != expected {
-		return fmt.Errorf("Unexpected output. Expected [%s], received [%s]", expected, o)
-	}
-	return nil
-}
-
-func assertPipe(input, output string, r io.Reader, w io.Writer, count int) error {
-	for i := 0; i < count; i++ {
-		if _, err := w.Write([]byte(input)); err != nil {
-			return err
-		}
-		if err := expectPipe(output, r); err != nil {
-			return err
-		}
-	}
-	return nil
-}
-
-// TestRunDetach checks attaching and detaching with the escape sequence.
-func TestRunDetach(t *testing.T) {
-	stdout, stdoutPipe := io.Pipe()
-	cpty, tty, err := pty.Open()
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	cli := client.NewDockerCli(tty, stdoutPipe, ioutil.Discard, "", testDaemonProto, testDaemonAddr, nil)
-	defer cleanup(globalEngine, t)
-
-	ch := make(chan struct{})
-	go func() {
-		defer close(ch)
-		cli.CmdRun("-i", "-t", unitTestImageID, "cat")
-	}()
-
-	container := waitContainerStart(t, 10*time.Second)
-
-	state := setRaw(t, container)
-	defer unsetRaw(t, container, state)
-
-	setTimeout(t, "First read/write assertion timed out", 2*time.Second, func() {
-		if err := assertPipe("hello\n", "hello", stdout, cpty, 150); err != nil {
-			t.Fatal(err)
-		}
-	})
-
-	setTimeout(t, "Escape sequence timeout", 5*time.Second, func() {
-		cpty.Write([]byte{16})
-		time.Sleep(100 * time.Millisecond)
-		cpty.Write([]byte{17})
-	})
-
-	// wait for CmdRun to return
-	setTimeout(t, "Waiting for CmdRun timed out", 15*time.Second, func() {
-		<-ch
-	})
-	closeWrap(cpty, stdout, stdoutPipe)
-
-	time.Sleep(500 * time.Millisecond)
-	if !container.IsRunning() {
-		t.Fatal("The detached container should be still running")
-	}
-
-	setTimeout(t, "Waiting for container to die timed out", 20*time.Second, func() {
-		container.Kill()
-	})
-}
-
-// TestAttachDetach checks that attach in tty mode can be detached using the long container ID
-func TestAttachDetach(t *testing.T) {
-	stdout, stdoutPipe := io.Pipe()
-	cpty, tty, err := pty.Open()
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	cli := client.NewDockerCli(tty, stdoutPipe, ioutil.Discard, "", testDaemonProto, testDaemonAddr, nil)
-	defer cleanup(globalEngine, t)
-
-	ch := make(chan struct{})
-	go func() {
-		defer close(ch)
-		if err := cli.CmdRun("-i", "-t", "-d", unitTestImageID, "cat"); err != nil {
-			t.Fatal(err)
-		}
-	}()
-
-	container := waitContainerStart(t, 10*time.Second)
-
-	setTimeout(t, "Reading container's id timed out", 10*time.Second, func() {
-		buf := make([]byte, 1024)
-		n, err := stdout.Read(buf)
-		if err != nil {
-			t.Fatal(err)
-		}
-
-		if strings.Trim(string(buf[:n]), " \r\n") != container.ID {
-			t.Fatalf("Wrong ID received. Expect %s, received %s", container.ID, buf[:n])
-		}
-	})
-	setTimeout(t, "Starting container timed out", 10*time.Second, func() {
-		<-ch
-	})
-
-	state := setRaw(t, container)
-	defer unsetRaw(t, container, state)
-
-	stdout, stdoutPipe = io.Pipe()
-	cpty, tty, err = pty.Open()
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	cli = client.NewDockerCli(tty, stdoutPipe, ioutil.Discard, "", testDaemonProto, testDaemonAddr, nil)
-
-	ch = make(chan struct{})
-	go func() {
-		defer close(ch)
-		if err := cli.CmdAttach(container.ID); err != nil {
-			if err != io.ErrClosedPipe {
-				t.Fatal(err)
-			}
-		}
-	}()
-
-	setTimeout(t, "First read/write assertion timed out", 2*time.Second, func() {
-		if err := assertPipe("hello\n", "hello", stdout, cpty, 150); err != nil {
-			if err != io.ErrClosedPipe {
-				t.Fatal(err)
-			}
-		}
-	})
-
-	setTimeout(t, "Escape sequence timeout", 5*time.Second, func() {
-		cpty.Write([]byte{16})
-		time.Sleep(100 * time.Millisecond)
-		cpty.Write([]byte{17})
-	})
-
-	// wait for CmdRun to return
-	setTimeout(t, "Waiting for CmdAttach timed out", 15*time.Second, func() {
-		<-ch
-	})
-
-	closeWrap(cpty, stdout, stdoutPipe)
-
-	time.Sleep(500 * time.Millisecond)
-	if !container.IsRunning() {
-		t.Fatal("The detached container should be still running")
-	}
-
-	setTimeout(t, "Waiting for container to die timedout", 5*time.Second, func() {
-		container.Kill()
-	})
-}
-
-// TestAttachDetachTruncatedID checks that attach in tty mode can be detached
-func TestAttachDetachTruncatedID(t *testing.T) {
-	stdout, stdoutPipe := io.Pipe()
-	cpty, tty, err := pty.Open()
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	cli := client.NewDockerCli(tty, stdoutPipe, ioutil.Discard, "", testDaemonProto, testDaemonAddr, nil)
-	defer cleanup(globalEngine, t)
-
-	// Discard the CmdRun output
-	go stdout.Read(make([]byte, 1024))
-	setTimeout(t, "Starting container timed out", 2*time.Second, func() {
-		if err := cli.CmdRun("-i", "-t", "-d", unitTestImageID, "cat"); err != nil {
-			t.Fatal(err)
-		}
-	})
-
-	container := waitContainerStart(t, 10*time.Second)
-
-	state := setRaw(t, container)
-	defer unsetRaw(t, container, state)
-
-	stdout, stdoutPipe = io.Pipe()
-	cpty, tty, err = pty.Open()
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	cli = client.NewDockerCli(tty, stdoutPipe, ioutil.Discard, "", testDaemonProto, testDaemonAddr, nil)
-
-	ch := make(chan struct{})
-	go func() {
-		defer close(ch)
-		if err := cli.CmdAttach(stringid.TruncateID(container.ID)); err != nil {
-			if err != io.ErrClosedPipe {
-				t.Fatal(err)
-			}
-		}
-	}()
-
-	setTimeout(t, "First read/write assertion timed out", 2*time.Second, func() {
-		if err := assertPipe("hello\n", "hello", stdout, cpty, 150); err != nil {
-			if err != io.ErrClosedPipe {
-				t.Fatal(err)
-			}
-		}
-	})
-
-	setTimeout(t, "Escape sequence timeout", 5*time.Second, func() {
-		cpty.Write([]byte{16})
-		time.Sleep(100 * time.Millisecond)
-		cpty.Write([]byte{17})
-	})
-
-	// wait for CmdRun to return
-	setTimeout(t, "Waiting for CmdAttach timed out", 15*time.Second, func() {
-		<-ch
-	})
-	closeWrap(cpty, stdout, stdoutPipe)
-
-	time.Sleep(500 * time.Millisecond)
-	if !container.IsRunning() {
-		t.Fatal("The detached container should be still running")
-	}
-
-	setTimeout(t, "Waiting for container to die timedout", 5*time.Second, func() {
-		container.Kill()
-	})
-}
-
-// Expected behaviour, the process stays alive when the client disconnects
-func TestAttachDisconnect(t *testing.T) {
-	stdout, stdoutPipe := io.Pipe()
-	cpty, tty, err := pty.Open()
-	if err != nil {
-		t.Fatal(err)
-	}
-
-	cli := client.NewDockerCli(tty, stdoutPipe, ioutil.Discard, "", testDaemonProto, testDaemonAddr, nil)
-	defer cleanup(globalEngine, t)
-
-	go func() {
-		// Start a process in daemon mode
-		if err := cli.CmdRun("-d", "-i", unitTestImageID, "/bin/cat"); err != nil {
-			logrus.Debugf("Error CmdRun: %s", err)
-		}
-	}()
-
-	setTimeout(t, "Waiting for CmdRun timed out", 10*time.Second, func() {
-		if _, err := bufio.NewReader(stdout).ReadString('\n'); err != nil {
-			t.Fatal(err)
-		}
-	})
-
-	setTimeout(t, "Waiting for the container to be started timed out", 10*time.Second, func() {
-		for {
-			l := globalDaemon.List()
-			if len(l) == 1 && l[0].IsRunning() {
-				break
-			}
-			time.Sleep(10 * time.Millisecond)
-		}
-	})
-
-	container := globalDaemon.List()[0]
-
-	// Attach to it
-	c1 := make(chan struct{})
-	go func() {
-		// We're simulating a disconnect so the return value doesn't matter. What matters is the
-		// fact that CmdAttach returns.
-		cli.CmdAttach(container.ID)
-		close(c1)
-	}()
-
-	setTimeout(t, "First read/write assertion timed out", 2*time.Second, func() {
-		if err := assertPipe("hello\n", "hello", stdout, cpty, 150); err != nil {
-			t.Fatal(err)
-		}
-	})
-	// Close pipes (client disconnects)
-	if err := closeWrap(cpty, stdout, stdoutPipe); err != nil {
-		t.Fatal(err)
-	}
-
-	// Wait for attach to finish, the client disconnected, therefore, Attach finished his job
-	setTimeout(t, "Waiting for CmdAttach timed out", 2*time.Second, func() {
-		<-c1
-	})
-
-	// We closed stdin, expect /bin/cat to still be running
-	// Wait a little bit to make sure container.monitor() did his thing
-	_, err = container.WaitStop(500 * time.Millisecond)
-	if err == nil || !container.IsRunning() {
-		t.Fatalf("/bin/cat is not running after closing stdin")
-	}
-
-	// Try to avoid the timeout in destroy. Best effort, don't check error
-	cStdin := container.StdinPipe()
-	cStdin.Close()
-	container.WaitStop(-1 * time.Second)
-}
-
-// Expected behaviour: container gets deleted automatically after exit
-func TestRunAutoRemove(t *testing.T) {
-	t.Skip("Fixme. Skipping test for now, race condition")
-	stdout, stdoutPipe := io.Pipe()
-
-	cli := client.NewDockerCli(nil, stdoutPipe, ioutil.Discard, "", testDaemonProto, testDaemonAddr, nil)
-	defer cleanup(globalEngine, t)
-
-	c := make(chan struct{})
-	go func() {
-		defer close(c)
-		if err := cli.CmdRun("--rm", unitTestImageID, "hostname"); err != nil {
-			t.Fatal(err)
-		}
-	}()
-
-	var temporaryContainerID string
-	setTimeout(t, "Reading command output time out", 2*time.Second, func() {
-		cmdOutput, err := bufio.NewReader(stdout).ReadString('\n')
-		if err != nil {
-			t.Fatal(err)
-		}
-		temporaryContainerID = cmdOutput
-		if err := closeWrap(stdout, stdoutPipe); err != nil {
-			t.Fatal(err)
-		}
-	})
-
-	setTimeout(t, "CmdRun timed out", 10*time.Second, func() {
-		<-c
-	})
-
-	time.Sleep(500 * time.Millisecond)
-
-	if len(globalDaemon.List()) > 0 {
-		t.Fatalf("failed to remove container automatically: container %s still exists", temporaryContainerID)
-	}
-}

+ 88 - 0
integration/utils.go

@@ -0,0 +1,88 @@
+package docker
+
+import (
+	"bufio"
+	"fmt"
+	"io"
+	"strings"
+	"testing"
+	"time"
+
+	"github.com/docker/docker/daemon"
+)
+
+func closeWrap(args ...io.Closer) error {
+	e := false
+	ret := fmt.Errorf("Error closing elements")
+	for _, c := range args {
+		if err := c.Close(); err != nil {
+			e = true
+			ret = fmt.Errorf("%s\n%s", ret, err)
+		}
+	}
+	if e {
+		return ret
+	}
+	return nil
+}
+
+func waitContainerStart(t *testing.T, timeout time.Duration) *daemon.Container {
+	var container *daemon.Container
+
+	setTimeout(t, "Waiting for the container to be started timed out", timeout, func() {
+		for {
+			l := globalDaemon.List()
+			if len(l) == 1 && l[0].IsRunning() {
+				container = l[0]
+				break
+			}
+			time.Sleep(10 * time.Millisecond)
+		}
+	})
+
+	if container == nil {
+		t.Fatal("An error occured while waiting for the container to start")
+	}
+
+	return container
+}
+
+func setTimeout(t *testing.T, msg string, d time.Duration, f func()) {
+	c := make(chan bool)
+
+	// Make sure we are not too long
+	go func() {
+		time.Sleep(d)
+		c <- true
+	}()
+	go func() {
+		f()
+		c <- false
+	}()
+	if <-c && msg != "" {
+		t.Fatal(msg)
+	}
+}
+
+func expectPipe(expected string, r io.Reader) error {
+	o, err := bufio.NewReader(r).ReadString('\n')
+	if err != nil {
+		return err
+	}
+	if strings.Trim(o, " \r\n") != expected {
+		return fmt.Errorf("Unexpected output. Expected [%s], received [%s]", expected, o)
+	}
+	return nil
+}
+
+func assertPipe(input, output string, r io.Reader, w io.Writer, count int) error {
+	for i := 0; i < count; i++ {
+		if _, err := w.Write([]byte(input)); err != nil {
+			return err
+		}
+		if err := expectPipe(output, r); err != nil {
+			return err
+		}
+	}
+	return nil
+}