Browse code

Fix run disconnect behavious in tty mode + add unit test to enforce it

Guillaume J. Charmes authored on 2013/04/06 11:02:35
Showing 2 changed files
... ...
@@ -191,6 +191,54 @@ func TestRunDisconnect(t *testing.T) {
191 191
 	})
192 192
 }
193 193
 
194
+// Expected behaviour: the process dies when the client disconnects
195
+func TestRunDisconnectTty(t *testing.T) {
196
+	runtime, err := newTestRuntime()
197
+	if err != nil {
198
+		t.Fatal(err)
199
+	}
200
+	defer nuke(runtime)
201
+
202
+	srv := &Server{runtime: runtime}
203
+
204
+	stdin, stdinPipe := io.Pipe()
205
+	stdout, stdoutPipe := io.Pipe()
206
+	c1 := make(chan struct{})
207
+	go func() {
208
+		// We're simulating a disconnect so the return value doesn't matter. What matters is the
209
+		// fact that CmdRun returns.
210
+		srv.CmdRun(stdin, rcli.NewDockerLocalConn(stdoutPipe), "-i", "-t", GetTestImage(runtime).Id, "/bin/cat")
211
+		close(c1)
212
+	}()
213
+
214
+	setTimeout(t, "Read/Write assertion timed out", 2*time.Second, func() {
215
+		if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
216
+			t.Fatal(err)
217
+		}
218
+	})
219
+
220
+	// Close pipes (simulate disconnect)
221
+	if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
222
+		t.Fatal(err)
223
+	}
224
+
225
+	// as the pipes are close, we expect the process to die,
226
+	// therefore CmdRun to unblock. Wait for CmdRun
227
+	setTimeout(t, "Waiting for CmdRun timed out", 2*time.Second, func() {
228
+		<-c1
229
+	})
230
+
231
+	// Client disconnect after run -i should cause stdin to be closed, which should
232
+	// cause /bin/cat to exit.
233
+	setTimeout(t, "Waiting for /bin/cat to exit timed out", 2*time.Second, func() {
234
+		container := runtime.List()[0]
235
+		container.Wait()
236
+		if container.State.Running {
237
+			t.Fatalf("/bin/cat is still running after closing stdin")
238
+		}
239
+	})
240
+}
241
+
194 242
 // TestAttachStdin checks attaching to stdin without stdout and stderr.
195 243
 // 'docker run -i -a stdin' should sends the client's stdin to the command,
196 244
 // then detach from it and print the container id.
... ...
@@ -251,6 +251,9 @@ func (container *Container) Attach(stdin io.ReadCloser, stdinCloser io.Closer, s
251 251
 					defer cStderr.Close()
252 252
 				}
253 253
 				if container.Config.StdinOnce {
254
+					if container.Config.Tty {
255
+						defer container.Kill()
256
+					}
254 257
 					defer cStdin.Close()
255 258
 				}
256 259
 				_, err := io.Copy(cStdin, stdin)