Browse code

Merge pull request #12292 from cpuguy83/remove_commands_integration

Remove commands integration

Phil Estes authored on 2015/04/15 05:17:25
Showing 7 changed files
... ...
@@ -14,7 +14,6 @@ import (
14 14
 	"syscall"
15 15
 	"time"
16 16
 
17
-	"github.com/docker/libcontainer"
18 17
 	"github.com/docker/libcontainer/configs"
19 18
 	"github.com/docker/libcontainer/devices"
20 19
 	"github.com/docker/libcontainer/label"
... ...
@@ -1020,14 +1019,6 @@ func (container *Container) Exposes(p nat.Port) bool {
1020 1020
 	return exists
1021 1021
 }
1022 1022
 
1023
-func (container *Container) GetPtyMaster() (libcontainer.Console, error) {
1024
-	ttyConsole, ok := container.command.ProcessConfig.Terminal.(execdriver.TtyTerminal)
1025
-	if !ok {
1026
-		return nil, ErrNoTTY
1027
-	}
1028
-	return ttyConsole.Master(), nil
1029
-}
1030
-
1031 1023
 func (container *Container) HostConfig() *runconfig.HostConfig {
1032 1024
 	container.Lock()
1033 1025
 	res := container.hostConfig
... ...
@@ -1,6 +1,7 @@
1 1
 package main
2 2
 
3 3
 import (
4
+	"bufio"
4 5
 	"io"
5 6
 	"os/exec"
6 7
 	"strings"
... ...
@@ -134,3 +135,51 @@ func TestAttachTtyWithoutStdin(t *testing.T) {
134 134
 
135 135
 	logDone("attach - forbid piped stdin to tty enabled container")
136 136
 }
137
+
138
+func TestAttachDisconnect(t *testing.T) {
139
+	defer deleteAllContainers()
140
+	out, _, _ := dockerCmd(t, "run", "-di", "busybox", "/bin/cat")
141
+	id := strings.TrimSpace(out)
142
+
143
+	cmd := exec.Command(dockerBinary, "attach", id)
144
+	stdin, err := cmd.StdinPipe()
145
+	if err != nil {
146
+		t.Fatal(err)
147
+	}
148
+	defer stdin.Close()
149
+	stdout, err := cmd.StdoutPipe()
150
+	if err != nil {
151
+		t.Fatal(err)
152
+	}
153
+	defer stdout.Close()
154
+	if err := cmd.Start(); err != nil {
155
+		t.Fatal(err)
156
+	}
157
+	defer cmd.Process.Kill()
158
+
159
+	if _, err := stdin.Write([]byte("hello\n")); err != nil {
160
+		t.Fatal(err)
161
+	}
162
+	out, err = bufio.NewReader(stdout).ReadString('\n')
163
+	if err != nil {
164
+		t.Fatal(err)
165
+	}
166
+	if strings.TrimSpace(out) != "hello" {
167
+		t.Fatalf("exepected 'hello', got %q", out)
168
+	}
169
+
170
+	if err := stdin.Close(); err != nil {
171
+		t.Fatal(err)
172
+	}
173
+
174
+	// Expect container to still be running after stdin is closed
175
+	running, err := inspectField(id, "State.Running")
176
+	if err != nil {
177
+		t.Fatal(err)
178
+	}
179
+	if running != "true" {
180
+		t.Fatal("exepected container to still be running")
181
+	}
182
+
183
+	logDone("attach - disconnect")
184
+}
... ...
@@ -3,11 +3,13 @@
3 3
 package main
4 4
 
5 5
 import (
6
+	"bufio"
6 7
 	"os/exec"
7 8
 	"strings"
8 9
 	"testing"
9 10
 	"time"
10 11
 
12
+	"github.com/docker/docker/pkg/stringid"
11 13
 	"github.com/kr/pty"
12 14
 )
13 15
 
... ...
@@ -137,3 +139,150 @@ func TestAttachAfterDetach(t *testing.T) {
137 137
 
138 138
 	logDone("attach - reconnect after detaching")
139 139
 }
140
+
141
+// TestAttachDetach checks that attach in tty mode can be detached using the long container ID
142
+func TestAttachDetach(t *testing.T) {
143
+	out, _, _ := dockerCmd(t, "run", "-itd", "busybox", "cat")
144
+	id := strings.TrimSpace(out)
145
+	if err := waitRun(id); err != nil {
146
+		t.Fatal(err)
147
+	}
148
+
149
+	cpty, tty, err := pty.Open()
150
+	if err != nil {
151
+		t.Fatal(err)
152
+	}
153
+	defer cpty.Close()
154
+
155
+	cmd := exec.Command(dockerBinary, "attach", id)
156
+	cmd.Stdin = tty
157
+	stdout, err := cmd.StdoutPipe()
158
+	if err != nil {
159
+		t.Fatal(err)
160
+	}
161
+	defer stdout.Close()
162
+	if err := cmd.Start(); err != nil {
163
+		t.Fatal(err)
164
+	}
165
+	if err := waitRun(id); err != nil {
166
+		t.Fatalf("error waiting for container to start: %v", err)
167
+	}
168
+
169
+	if _, err := cpty.Write([]byte("hello\n")); err != nil {
170
+		t.Fatal(err)
171
+	}
172
+	out, err = bufio.NewReader(stdout).ReadString('\n')
173
+	if err != nil {
174
+		t.Fatal(err)
175
+	}
176
+	if strings.TrimSpace(out) != "hello" {
177
+		t.Fatalf("exepected 'hello', got %q", out)
178
+	}
179
+
180
+	// escape sequence
181
+	if _, err := cpty.Write([]byte{16}); err != nil {
182
+		t.Fatal(err)
183
+	}
184
+	time.Sleep(100 * time.Millisecond)
185
+	if _, err := cpty.Write([]byte{17}); err != nil {
186
+		t.Fatal(err)
187
+	}
188
+
189
+	ch := make(chan struct{})
190
+	go func() {
191
+		cmd.Wait()
192
+		ch <- struct{}{}
193
+	}()
194
+
195
+	running, err := inspectField(id, "State.Running")
196
+	if err != nil {
197
+		t.Fatal(err)
198
+	}
199
+	if running != "true" {
200
+		t.Fatal("exepected container to still be running")
201
+	}
202
+
203
+	go func() {
204
+		dockerCmd(t, "kill", id)
205
+	}()
206
+
207
+	select {
208
+	case <-ch:
209
+	case <-time.After(10 * time.Millisecond):
210
+		t.Fatal("timed out waiting for container to exit")
211
+	}
212
+
213
+	logDone("attach - detach")
214
+}
215
+
216
+// TestAttachDetachTruncatedID checks that attach in tty mode can be detached
217
+func TestAttachDetachTruncatedID(t *testing.T) {
218
+	out, _, _ := dockerCmd(t, "run", "-itd", "busybox", "cat")
219
+	id := stringid.TruncateID(strings.TrimSpace(out))
220
+	if err := waitRun(id); err != nil {
221
+		t.Fatal(err)
222
+	}
223
+
224
+	cpty, tty, err := pty.Open()
225
+	if err != nil {
226
+		t.Fatal(err)
227
+	}
228
+	defer cpty.Close()
229
+
230
+	cmd := exec.Command(dockerBinary, "attach", id)
231
+	cmd.Stdin = tty
232
+	stdout, err := cmd.StdoutPipe()
233
+	if err != nil {
234
+		t.Fatal(err)
235
+	}
236
+	defer stdout.Close()
237
+	if err := cmd.Start(); err != nil {
238
+		t.Fatal(err)
239
+	}
240
+
241
+	if _, err := cpty.Write([]byte("hello\n")); err != nil {
242
+		t.Fatal(err)
243
+	}
244
+	out, err = bufio.NewReader(stdout).ReadString('\n')
245
+	if err != nil {
246
+		t.Fatal(err)
247
+	}
248
+	if strings.TrimSpace(out) != "hello" {
249
+		t.Fatalf("exepected 'hello', got %q", out)
250
+	}
251
+
252
+	// escape sequence
253
+	if _, err := cpty.Write([]byte{16}); err != nil {
254
+		t.Fatal(err)
255
+	}
256
+	time.Sleep(100 * time.Millisecond)
257
+	if _, err := cpty.Write([]byte{17}); err != nil {
258
+		t.Fatal(err)
259
+	}
260
+
261
+	ch := make(chan struct{})
262
+	go func() {
263
+		cmd.Wait()
264
+		ch <- struct{}{}
265
+	}()
266
+
267
+	running, err := inspectField(id, "State.Running")
268
+	if err != nil {
269
+		t.Fatal(err)
270
+	}
271
+	if running != "true" {
272
+		t.Fatal("exepected container to still be running")
273
+	}
274
+
275
+	go func() {
276
+		dockerCmd(t, "kill", id)
277
+	}()
278
+
279
+	select {
280
+	case <-ch:
281
+	case <-time.After(10 * time.Millisecond):
282
+		t.Fatal("timed out waiting for container to exit")
283
+	}
284
+
285
+	logDone("attach - detach truncated ID")
286
+}
... ...
@@ -3,6 +3,7 @@
3 3
 package main
4 4
 
5 5
 import (
6
+	"bufio"
6 7
 	"fmt"
7 8
 	"io/ioutil"
8 9
 	"os"
... ...
@@ -201,3 +202,73 @@ func TestRunDeviceDirectory(t *testing.T) {
201 201
 
202 202
 	logDone("run - test --device directory mounts all internal devices")
203 203
 }
204
+
205
+// TestRunDetach checks attaching and detaching with the escape sequence.
206
+func TestRunAttachDetach(t *testing.T) {
207
+	defer deleteAllContainers()
208
+	name := "attach-detach"
209
+	cmd := exec.Command(dockerBinary, "run", "--name", name, "-it", "busybox", "cat")
210
+	stdout, err := cmd.StdoutPipe()
211
+	if err != nil {
212
+		t.Fatal(err)
213
+	}
214
+	cpty, tty, err := pty.Open()
215
+	if err != nil {
216
+		t.Fatal(err)
217
+	}
218
+	defer cpty.Close()
219
+	cmd.Stdin = tty
220
+	if err := cmd.Start(); err != nil {
221
+		t.Fatal(err)
222
+	}
223
+	if err := waitRun(name); err != nil {
224
+		t.Fatal(err)
225
+	}
226
+
227
+	if _, err := cpty.Write([]byte("hello\n")); err != nil {
228
+		t.Fatal(err)
229
+	}
230
+
231
+	out, err := bufio.NewReader(stdout).ReadString('\n')
232
+	if err != nil {
233
+		t.Fatal(err)
234
+	}
235
+	if strings.TrimSpace(out) != "hello" {
236
+		t.Fatalf("exepected 'hello', got %q", out)
237
+	}
238
+
239
+	// escape sequence
240
+	if _, err := cpty.Write([]byte{16}); err != nil {
241
+		t.Fatal(err)
242
+	}
243
+	time.Sleep(100 * time.Millisecond)
244
+	if _, err := cpty.Write([]byte{17}); err != nil {
245
+		t.Fatal(err)
246
+	}
247
+
248
+	ch := make(chan struct{})
249
+	go func() {
250
+		cmd.Wait()
251
+		ch <- struct{}{}
252
+	}()
253
+
254
+	running, err := inspectField(name, "State.Running")
255
+	if err != nil {
256
+		t.Fatal(err)
257
+	}
258
+	if running != "true" {
259
+		t.Fatal("exepected container to still be running")
260
+	}
261
+
262
+	go func() {
263
+		dockerCmd(t, "kill", name)
264
+	}()
265
+
266
+	select {
267
+	case <-ch:
268
+	case <-time.After(10 * time.Millisecond):
269
+		t.Fatal("timed out waiting for container to exit")
270
+	}
271
+
272
+	logDone("run - attach detach")
273
+}
... ...
@@ -213,7 +213,16 @@ func waitInspect(name, expr, expected string, timeout int) error {
213 213
 		cmd := exec.Command(dockerBinary, "inspect", "-f", expr, name)
214 214
 		out, _, err := runCommandWithOutput(cmd)
215 215
 		if err != nil {
216
-			return fmt.Errorf("error executing docker inspect: %v", err)
216
+			if !strings.Contains(out, "No such") {
217
+				return fmt.Errorf("error executing docker inspect: %v\n%s", err, out)
218
+			}
219
+			select {
220
+			case <-after:
221
+				return err
222
+			default:
223
+				time.Sleep(10 * time.Millisecond)
224
+				continue
225
+			}
217 226
 		}
218 227
 
219 228
 		out = strings.TrimSpace(out)
220 229
deleted file mode 100644
... ...
@@ -1,436 +0,0 @@
1
-package docker
2
-
3
-import (
4
-	"bufio"
5
-	"fmt"
6
-	"io"
7
-	"io/ioutil"
8
-	"strings"
9
-	"testing"
10
-	"time"
11
-
12
-	"github.com/Sirupsen/logrus"
13
-	"github.com/docker/docker/api/client"
14
-	"github.com/docker/docker/daemon"
15
-	"github.com/docker/docker/pkg/stringid"
16
-	"github.com/docker/docker/pkg/term"
17
-	"github.com/kr/pty"
18
-)
19
-
20
-func closeWrap(args ...io.Closer) error {
21
-	e := false
22
-	ret := fmt.Errorf("Error closing elements")
23
-	for _, c := range args {
24
-		if err := c.Close(); err != nil {
25
-			e = true
26
-			ret = fmt.Errorf("%s\n%s", ret, err)
27
-		}
28
-	}
29
-	if e {
30
-		return ret
31
-	}
32
-	return nil
33
-}
34
-
35
-func setRaw(t *testing.T, c *daemon.Container) *term.State {
36
-	pty, err := c.GetPtyMaster()
37
-	if err != nil {
38
-		t.Fatal(err)
39
-	}
40
-	state, err := term.MakeRaw(pty.Fd())
41
-	if err != nil {
42
-		t.Fatal(err)
43
-	}
44
-	return state
45
-}
46
-
47
-func unsetRaw(t *testing.T, c *daemon.Container, state *term.State) {
48
-	pty, err := c.GetPtyMaster()
49
-	if err != nil {
50
-		t.Fatal(err)
51
-	}
52
-	term.RestoreTerminal(pty.Fd(), state)
53
-}
54
-
55
-func waitContainerStart(t *testing.T, timeout time.Duration) *daemon.Container {
56
-	var container *daemon.Container
57
-
58
-	setTimeout(t, "Waiting for the container to be started timed out", timeout, func() {
59
-		for {
60
-			l := globalDaemon.List()
61
-			if len(l) == 1 && l[0].IsRunning() {
62
-				container = l[0]
63
-				break
64
-			}
65
-			time.Sleep(10 * time.Millisecond)
66
-		}
67
-	})
68
-
69
-	if container == nil {
70
-		t.Fatal("An error occured while waiting for the container to start")
71
-	}
72
-
73
-	return container
74
-}
75
-
76
-func setTimeout(t *testing.T, msg string, d time.Duration, f func()) {
77
-	c := make(chan bool)
78
-
79
-	// Make sure we are not too long
80
-	go func() {
81
-		time.Sleep(d)
82
-		c <- true
83
-	}()
84
-	go func() {
85
-		f()
86
-		c <- false
87
-	}()
88
-	if <-c && msg != "" {
89
-		t.Fatal(msg)
90
-	}
91
-}
92
-
93
-func expectPipe(expected string, r io.Reader) error {
94
-	o, err := bufio.NewReader(r).ReadString('\n')
95
-	if err != nil {
96
-		return err
97
-	}
98
-	if strings.Trim(o, " \r\n") != expected {
99
-		return fmt.Errorf("Unexpected output. Expected [%s], received [%s]", expected, o)
100
-	}
101
-	return nil
102
-}
103
-
104
-func assertPipe(input, output string, r io.Reader, w io.Writer, count int) error {
105
-	for i := 0; i < count; i++ {
106
-		if _, err := w.Write([]byte(input)); err != nil {
107
-			return err
108
-		}
109
-		if err := expectPipe(output, r); err != nil {
110
-			return err
111
-		}
112
-	}
113
-	return nil
114
-}
115
-
116
-// TestRunDetach checks attaching and detaching with the escape sequence.
117
-func TestRunDetach(t *testing.T) {
118
-	stdout, stdoutPipe := io.Pipe()
119
-	cpty, tty, err := pty.Open()
120
-	if err != nil {
121
-		t.Fatal(err)
122
-	}
123
-
124
-	cli := client.NewDockerCli(tty, stdoutPipe, ioutil.Discard, "", testDaemonProto, testDaemonAddr, nil)
125
-	defer cleanup(globalEngine, t)
126
-
127
-	ch := make(chan struct{})
128
-	go func() {
129
-		defer close(ch)
130
-		cli.CmdRun("-i", "-t", unitTestImageID, "cat")
131
-	}()
132
-
133
-	container := waitContainerStart(t, 10*time.Second)
134
-
135
-	state := setRaw(t, container)
136
-	defer unsetRaw(t, container, state)
137
-
138
-	setTimeout(t, "First read/write assertion timed out", 2*time.Second, func() {
139
-		if err := assertPipe("hello\n", "hello", stdout, cpty, 150); err != nil {
140
-			t.Fatal(err)
141
-		}
142
-	})
143
-
144
-	setTimeout(t, "Escape sequence timeout", 5*time.Second, func() {
145
-		cpty.Write([]byte{16})
146
-		time.Sleep(100 * time.Millisecond)
147
-		cpty.Write([]byte{17})
148
-	})
149
-
150
-	// wait for CmdRun to return
151
-	setTimeout(t, "Waiting for CmdRun timed out", 15*time.Second, func() {
152
-		<-ch
153
-	})
154
-	closeWrap(cpty, stdout, stdoutPipe)
155
-
156
-	time.Sleep(500 * time.Millisecond)
157
-	if !container.IsRunning() {
158
-		t.Fatal("The detached container should be still running")
159
-	}
160
-
161
-	setTimeout(t, "Waiting for container to die timed out", 20*time.Second, func() {
162
-		container.Kill()
163
-	})
164
-}
165
-
166
-// TestAttachDetach checks that attach in tty mode can be detached using the long container ID
167
-func TestAttachDetach(t *testing.T) {
168
-	stdout, stdoutPipe := io.Pipe()
169
-	cpty, tty, err := pty.Open()
170
-	if err != nil {
171
-		t.Fatal(err)
172
-	}
173
-
174
-	cli := client.NewDockerCli(tty, stdoutPipe, ioutil.Discard, "", testDaemonProto, testDaemonAddr, nil)
175
-	defer cleanup(globalEngine, t)
176
-
177
-	ch := make(chan struct{})
178
-	go func() {
179
-		defer close(ch)
180
-		if err := cli.CmdRun("-i", "-t", "-d", unitTestImageID, "cat"); err != nil {
181
-			t.Fatal(err)
182
-		}
183
-	}()
184
-
185
-	container := waitContainerStart(t, 10*time.Second)
186
-
187
-	setTimeout(t, "Reading container's id timed out", 10*time.Second, func() {
188
-		buf := make([]byte, 1024)
189
-		n, err := stdout.Read(buf)
190
-		if err != nil {
191
-			t.Fatal(err)
192
-		}
193
-
194
-		if strings.Trim(string(buf[:n]), " \r\n") != container.ID {
195
-			t.Fatalf("Wrong ID received. Expect %s, received %s", container.ID, buf[:n])
196
-		}
197
-	})
198
-	setTimeout(t, "Starting container timed out", 10*time.Second, func() {
199
-		<-ch
200
-	})
201
-
202
-	state := setRaw(t, container)
203
-	defer unsetRaw(t, container, state)
204
-
205
-	stdout, stdoutPipe = io.Pipe()
206
-	cpty, tty, err = pty.Open()
207
-	if err != nil {
208
-		t.Fatal(err)
209
-	}
210
-
211
-	cli = client.NewDockerCli(tty, stdoutPipe, ioutil.Discard, "", testDaemonProto, testDaemonAddr, nil)
212
-
213
-	ch = make(chan struct{})
214
-	go func() {
215
-		defer close(ch)
216
-		if err := cli.CmdAttach(container.ID); err != nil {
217
-			if err != io.ErrClosedPipe {
218
-				t.Fatal(err)
219
-			}
220
-		}
221
-	}()
222
-
223
-	setTimeout(t, "First read/write assertion timed out", 2*time.Second, func() {
224
-		if err := assertPipe("hello\n", "hello", stdout, cpty, 150); err != nil {
225
-			if err != io.ErrClosedPipe {
226
-				t.Fatal(err)
227
-			}
228
-		}
229
-	})
230
-
231
-	setTimeout(t, "Escape sequence timeout", 5*time.Second, func() {
232
-		cpty.Write([]byte{16})
233
-		time.Sleep(100 * time.Millisecond)
234
-		cpty.Write([]byte{17})
235
-	})
236
-
237
-	// wait for CmdRun to return
238
-	setTimeout(t, "Waiting for CmdAttach timed out", 15*time.Second, func() {
239
-		<-ch
240
-	})
241
-
242
-	closeWrap(cpty, stdout, stdoutPipe)
243
-
244
-	time.Sleep(500 * time.Millisecond)
245
-	if !container.IsRunning() {
246
-		t.Fatal("The detached container should be still running")
247
-	}
248
-
249
-	setTimeout(t, "Waiting for container to die timedout", 5*time.Second, func() {
250
-		container.Kill()
251
-	})
252
-}
253
-
254
-// TestAttachDetachTruncatedID checks that attach in tty mode can be detached
255
-func TestAttachDetachTruncatedID(t *testing.T) {
256
-	stdout, stdoutPipe := io.Pipe()
257
-	cpty, tty, err := pty.Open()
258
-	if err != nil {
259
-		t.Fatal(err)
260
-	}
261
-
262
-	cli := client.NewDockerCli(tty, stdoutPipe, ioutil.Discard, "", testDaemonProto, testDaemonAddr, nil)
263
-	defer cleanup(globalEngine, t)
264
-
265
-	// Discard the CmdRun output
266
-	go stdout.Read(make([]byte, 1024))
267
-	setTimeout(t, "Starting container timed out", 2*time.Second, func() {
268
-		if err := cli.CmdRun("-i", "-t", "-d", unitTestImageID, "cat"); err != nil {
269
-			t.Fatal(err)
270
-		}
271
-	})
272
-
273
-	container := waitContainerStart(t, 10*time.Second)
274
-
275
-	state := setRaw(t, container)
276
-	defer unsetRaw(t, container, state)
277
-
278
-	stdout, stdoutPipe = io.Pipe()
279
-	cpty, tty, err = pty.Open()
280
-	if err != nil {
281
-		t.Fatal(err)
282
-	}
283
-
284
-	cli = client.NewDockerCli(tty, stdoutPipe, ioutil.Discard, "", testDaemonProto, testDaemonAddr, nil)
285
-
286
-	ch := make(chan struct{})
287
-	go func() {
288
-		defer close(ch)
289
-		if err := cli.CmdAttach(stringid.TruncateID(container.ID)); err != nil {
290
-			if err != io.ErrClosedPipe {
291
-				t.Fatal(err)
292
-			}
293
-		}
294
-	}()
295
-
296
-	setTimeout(t, "First read/write assertion timed out", 2*time.Second, func() {
297
-		if err := assertPipe("hello\n", "hello", stdout, cpty, 150); err != nil {
298
-			if err != io.ErrClosedPipe {
299
-				t.Fatal(err)
300
-			}
301
-		}
302
-	})
303
-
304
-	setTimeout(t, "Escape sequence timeout", 5*time.Second, func() {
305
-		cpty.Write([]byte{16})
306
-		time.Sleep(100 * time.Millisecond)
307
-		cpty.Write([]byte{17})
308
-	})
309
-
310
-	// wait for CmdRun to return
311
-	setTimeout(t, "Waiting for CmdAttach timed out", 15*time.Second, func() {
312
-		<-ch
313
-	})
314
-	closeWrap(cpty, stdout, stdoutPipe)
315
-
316
-	time.Sleep(500 * time.Millisecond)
317
-	if !container.IsRunning() {
318
-		t.Fatal("The detached container should be still running")
319
-	}
320
-
321
-	setTimeout(t, "Waiting for container to die timedout", 5*time.Second, func() {
322
-		container.Kill()
323
-	})
324
-}
325
-
326
-// Expected behaviour, the process stays alive when the client disconnects
327
-func TestAttachDisconnect(t *testing.T) {
328
-	stdout, stdoutPipe := io.Pipe()
329
-	cpty, tty, err := pty.Open()
330
-	if err != nil {
331
-		t.Fatal(err)
332
-	}
333
-
334
-	cli := client.NewDockerCli(tty, stdoutPipe, ioutil.Discard, "", testDaemonProto, testDaemonAddr, nil)
335
-	defer cleanup(globalEngine, t)
336
-
337
-	go func() {
338
-		// Start a process in daemon mode
339
-		if err := cli.CmdRun("-d", "-i", unitTestImageID, "/bin/cat"); err != nil {
340
-			logrus.Debugf("Error CmdRun: %s", err)
341
-		}
342
-	}()
343
-
344
-	setTimeout(t, "Waiting for CmdRun timed out", 10*time.Second, func() {
345
-		if _, err := bufio.NewReader(stdout).ReadString('\n'); err != nil {
346
-			t.Fatal(err)
347
-		}
348
-	})
349
-
350
-	setTimeout(t, "Waiting for the container to be started timed out", 10*time.Second, func() {
351
-		for {
352
-			l := globalDaemon.List()
353
-			if len(l) == 1 && l[0].IsRunning() {
354
-				break
355
-			}
356
-			time.Sleep(10 * time.Millisecond)
357
-		}
358
-	})
359
-
360
-	container := globalDaemon.List()[0]
361
-
362
-	// Attach to it
363
-	c1 := make(chan struct{})
364
-	go func() {
365
-		// We're simulating a disconnect so the return value doesn't matter. What matters is the
366
-		// fact that CmdAttach returns.
367
-		cli.CmdAttach(container.ID)
368
-		close(c1)
369
-	}()
370
-
371
-	setTimeout(t, "First read/write assertion timed out", 2*time.Second, func() {
372
-		if err := assertPipe("hello\n", "hello", stdout, cpty, 150); err != nil {
373
-			t.Fatal(err)
374
-		}
375
-	})
376
-	// Close pipes (client disconnects)
377
-	if err := closeWrap(cpty, stdout, stdoutPipe); err != nil {
378
-		t.Fatal(err)
379
-	}
380
-
381
-	// Wait for attach to finish, the client disconnected, therefore, Attach finished his job
382
-	setTimeout(t, "Waiting for CmdAttach timed out", 2*time.Second, func() {
383
-		<-c1
384
-	})
385
-
386
-	// We closed stdin, expect /bin/cat to still be running
387
-	// Wait a little bit to make sure container.monitor() did his thing
388
-	_, err = container.WaitStop(500 * time.Millisecond)
389
-	if err == nil || !container.IsRunning() {
390
-		t.Fatalf("/bin/cat is not running after closing stdin")
391
-	}
392
-
393
-	// Try to avoid the timeout in destroy. Best effort, don't check error
394
-	cStdin := container.StdinPipe()
395
-	cStdin.Close()
396
-	container.WaitStop(-1 * time.Second)
397
-}
398
-
399
-// Expected behaviour: container gets deleted automatically after exit
400
-func TestRunAutoRemove(t *testing.T) {
401
-	t.Skip("Fixme. Skipping test for now, race condition")
402
-	stdout, stdoutPipe := io.Pipe()
403
-
404
-	cli := client.NewDockerCli(nil, stdoutPipe, ioutil.Discard, "", testDaemonProto, testDaemonAddr, nil)
405
-	defer cleanup(globalEngine, t)
406
-
407
-	c := make(chan struct{})
408
-	go func() {
409
-		defer close(c)
410
-		if err := cli.CmdRun("--rm", unitTestImageID, "hostname"); err != nil {
411
-			t.Fatal(err)
412
-		}
413
-	}()
414
-
415
-	var temporaryContainerID string
416
-	setTimeout(t, "Reading command output time out", 2*time.Second, func() {
417
-		cmdOutput, err := bufio.NewReader(stdout).ReadString('\n')
418
-		if err != nil {
419
-			t.Fatal(err)
420
-		}
421
-		temporaryContainerID = cmdOutput
422
-		if err := closeWrap(stdout, stdoutPipe); err != nil {
423
-			t.Fatal(err)
424
-		}
425
-	})
426
-
427
-	setTimeout(t, "CmdRun timed out", 10*time.Second, func() {
428
-		<-c
429
-	})
430
-
431
-	time.Sleep(500 * time.Millisecond)
432
-
433
-	if len(globalDaemon.List()) > 0 {
434
-		t.Fatalf("failed to remove container automatically: container %s still exists", temporaryContainerID)
435
-	}
436
-}
437 1
new file mode 100644
... ...
@@ -0,0 +1,88 @@
0
+package docker
1
+
2
+import (
3
+	"bufio"
4
+	"fmt"
5
+	"io"
6
+	"strings"
7
+	"testing"
8
+	"time"
9
+
10
+	"github.com/docker/docker/daemon"
11
+)
12
+
13
+func closeWrap(args ...io.Closer) error {
14
+	e := false
15
+	ret := fmt.Errorf("Error closing elements")
16
+	for _, c := range args {
17
+		if err := c.Close(); err != nil {
18
+			e = true
19
+			ret = fmt.Errorf("%s\n%s", ret, err)
20
+		}
21
+	}
22
+	if e {
23
+		return ret
24
+	}
25
+	return nil
26
+}
27
+
28
+func waitContainerStart(t *testing.T, timeout time.Duration) *daemon.Container {
29
+	var container *daemon.Container
30
+
31
+	setTimeout(t, "Waiting for the container to be started timed out", timeout, func() {
32
+		for {
33
+			l := globalDaemon.List()
34
+			if len(l) == 1 && l[0].IsRunning() {
35
+				container = l[0]
36
+				break
37
+			}
38
+			time.Sleep(10 * time.Millisecond)
39
+		}
40
+	})
41
+
42
+	if container == nil {
43
+		t.Fatal("An error occured while waiting for the container to start")
44
+	}
45
+
46
+	return container
47
+}
48
+
49
+func setTimeout(t *testing.T, msg string, d time.Duration, f func()) {
50
+	c := make(chan bool)
51
+
52
+	// Make sure we are not too long
53
+	go func() {
54
+		time.Sleep(d)
55
+		c <- true
56
+	}()
57
+	go func() {
58
+		f()
59
+		c <- false
60
+	}()
61
+	if <-c && msg != "" {
62
+		t.Fatal(msg)
63
+	}
64
+}
65
+
66
+func expectPipe(expected string, r io.Reader) error {
67
+	o, err := bufio.NewReader(r).ReadString('\n')
68
+	if err != nil {
69
+		return err
70
+	}
71
+	if strings.Trim(o, " \r\n") != expected {
72
+		return fmt.Errorf("Unexpected output. Expected [%s], received [%s]", expected, o)
73
+	}
74
+	return nil
75
+}
76
+
77
+func assertPipe(input, output string, r io.Reader, w io.Writer, count int) error {
78
+	for i := 0; i < count; i++ {
79
+		if _, err := w.Write([]byte(input)); err != nil {
80
+			return err
81
+		}
82
+		if err := expectPipe(output, r); err != nil {
83
+			return err
84
+		}
85
+	}
86
+	return nil
87
+}