| ... | ... |
@@ -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) |