diff --git a/components/engine/integration-cli/docker_cli_attach_unix_test.go b/components/engine/integration-cli/docker_cli_attach_unix_test.go index bea73d770d..ebc3804e3e 100644 --- a/components/engine/integration-cli/docker_cli_attach_unix_test.go +++ b/components/engine/integration-cli/docker_cli_attach_unix_test.go @@ -9,6 +9,7 @@ import ( "testing" "time" + "github.com/docker/docker/pkg/stringid" "github.com/kr/pty" ) @@ -213,3 +214,75 @@ func TestAttachDetach(t *testing.T) { 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") +} diff --git a/components/engine/integration/commands_test.go b/components/engine/integration/commands_test.go index 88a7bb87b3..900bdace22 100644 --- a/components/engine/integration/commands_test.go +++ b/components/engine/integration/commands_test.go @@ -12,7 +12,6 @@ import ( "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" ) @@ -113,78 +112,6 @@ func assertPipe(input, output string, r io.Reader, w io.Writer, count int) error return nil } -// 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()