github.com/adxhyt/docker@v1.4.2-0.20150117221845-467b7c821390/integration-cli/docker_cli_exec_test.go (about) 1 package main 2 3 import ( 4 "bufio" 5 "os" 6 "os/exec" 7 "strings" 8 "testing" 9 "time" 10 ) 11 12 func TestExec(t *testing.T) { 13 runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "testing", "busybox", "sh", "-c", "echo test > /tmp/file && sleep 100") 14 if out, _, _, err := runCommandWithStdoutStderr(runCmd); err != nil { 15 t.Fatal(out, err) 16 } 17 18 execCmd := exec.Command(dockerBinary, "exec", "testing", "cat", "/tmp/file") 19 out, _, err := runCommandWithOutput(execCmd) 20 if err != nil { 21 t.Fatal(out, err) 22 } 23 24 out = strings.Trim(out, "\r\n") 25 26 if expected := "test"; out != expected { 27 t.Errorf("container exec should've printed %q but printed %q", expected, out) 28 } 29 30 deleteAllContainers() 31 32 logDone("exec - basic test") 33 } 34 35 func TestExecInteractiveStdinClose(t *testing.T) { 36 defer deleteAllContainers() 37 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "run", "-itd", "busybox", "/bin/cat")) 38 if err != nil { 39 t.Fatal(err) 40 } 41 42 contId := strings.TrimSpace(out) 43 44 returnchan := make(chan struct{}) 45 46 go func() { 47 var err error 48 cmd := exec.Command(dockerBinary, "exec", "-i", contId, "/bin/ls", "/") 49 cmd.Stdin = os.Stdin 50 if err != nil { 51 t.Fatal(err) 52 } 53 54 out, err := cmd.CombinedOutput() 55 if err != nil { 56 t.Fatal(err, out) 57 } 58 59 if string(out) == "" { 60 t.Fatalf("Output was empty, likely blocked by standard input") 61 } 62 63 returnchan <- struct{}{} 64 }() 65 66 select { 67 case <-returnchan: 68 case <-time.After(10 * time.Second): 69 t.Fatal("timed out running docker exec") 70 } 71 72 logDone("exec - interactive mode closes stdin after execution") 73 } 74 75 func TestExecInteractive(t *testing.T) { 76 runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "testing", "busybox", "sh", "-c", "echo test > /tmp/file && sleep 100") 77 if out, _, _, err := runCommandWithStdoutStderr(runCmd); err != nil { 78 t.Fatal(out, err) 79 } 80 81 execCmd := exec.Command(dockerBinary, "exec", "-i", "testing", "sh") 82 stdin, err := execCmd.StdinPipe() 83 if err != nil { 84 t.Fatal(err) 85 } 86 stdout, err := execCmd.StdoutPipe() 87 if err != nil { 88 t.Fatal(err) 89 } 90 91 if err := execCmd.Start(); err != nil { 92 t.Fatal(err) 93 } 94 if _, err := stdin.Write([]byte("cat /tmp/file\n")); err != nil { 95 t.Fatal(err) 96 } 97 98 r := bufio.NewReader(stdout) 99 line, err := r.ReadString('\n') 100 if err != nil { 101 t.Fatal(err) 102 } 103 line = strings.TrimSpace(line) 104 if line != "test" { 105 t.Fatalf("Output should be 'test', got '%q'", line) 106 } 107 if err := stdin.Close(); err != nil { 108 t.Fatal(err) 109 } 110 finish := make(chan struct{}) 111 go func() { 112 if err := execCmd.Wait(); err != nil { 113 t.Fatal(err) 114 } 115 close(finish) 116 }() 117 select { 118 case <-finish: 119 case <-time.After(1 * time.Second): 120 t.Fatal("docker exec failed to exit on stdin close") 121 } 122 123 deleteAllContainers() 124 125 logDone("exec - Interactive test") 126 } 127 128 func TestExecAfterContainerRestart(t *testing.T) { 129 runCmd := exec.Command(dockerBinary, "run", "-d", "busybox", "top") 130 out, _, err := runCommandWithOutput(runCmd) 131 if err != nil { 132 t.Fatal(out, err) 133 } 134 135 cleanedContainerID := stripTrailingCharacters(out) 136 137 runCmd = exec.Command(dockerBinary, "restart", cleanedContainerID) 138 if out, _, err = runCommandWithOutput(runCmd); err != nil { 139 t.Fatal(out, err) 140 } 141 142 runCmd = exec.Command(dockerBinary, "exec", cleanedContainerID, "echo", "hello") 143 out, _, err = runCommandWithOutput(runCmd) 144 if err != nil { 145 t.Fatal(out, err) 146 } 147 148 outStr := strings.TrimSpace(out) 149 if outStr != "hello" { 150 t.Errorf("container should've printed hello, instead printed %q", outStr) 151 } 152 153 deleteAllContainers() 154 155 logDone("exec - exec running container after container restart") 156 } 157 158 func TestExecAfterDaemonRestart(t *testing.T) { 159 d := NewDaemon(t) 160 if err := d.StartWithBusybox(); err != nil { 161 t.Fatalf("Could not start daemon with busybox: %v", err) 162 } 163 defer d.Stop() 164 165 if out, err := d.Cmd("run", "-d", "--name", "top", "-p", "80", "busybox:latest", "top"); err != nil { 166 t.Fatalf("Could not run top: err=%v\n%s", err, out) 167 } 168 169 if err := d.Restart(); err != nil { 170 t.Fatalf("Could not restart daemon: %v", err) 171 } 172 173 if out, err := d.Cmd("start", "top"); err != nil { 174 t.Fatalf("Could not start top after daemon restart: err=%v\n%s", err, out) 175 } 176 177 out, err := d.Cmd("exec", "top", "echo", "hello") 178 if err != nil { 179 t.Fatalf("Could not exec on container top: err=%v\n%s", err, out) 180 } 181 182 outStr := strings.TrimSpace(string(out)) 183 if outStr != "hello" { 184 t.Errorf("container should've printed hello, instead printed %q", outStr) 185 } 186 187 logDone("exec - exec running container after daemon restart") 188 } 189 190 // Regresssion test for #9155, #9044 191 func TestExecEnv(t *testing.T) { 192 defer deleteAllContainers() 193 194 runCmd := exec.Command(dockerBinary, "run", 195 "-e", "LALA=value1", 196 "-e", "LALA=value2", 197 "-d", "--name", "testing", "busybox", "top") 198 if out, _, _, err := runCommandWithStdoutStderr(runCmd); err != nil { 199 t.Fatal(out, err) 200 } 201 202 execCmd := exec.Command(dockerBinary, "exec", "testing", "env") 203 out, _, err := runCommandWithOutput(execCmd) 204 if err != nil { 205 t.Fatal(out, err) 206 } 207 208 if strings.Contains(out, "LALA=value1") || 209 !strings.Contains(out, "LALA=value2") || 210 !strings.Contains(out, "HOME=/root") { 211 t.Errorf("exec env(%q), expect %q, %q", out, "LALA=value2", "HOME=/root") 212 } 213 214 logDone("exec - exec inherits correct env") 215 } 216 217 func TestExecExitStatus(t *testing.T) { 218 runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "top", "busybox", "top") 219 if out, _, _, err := runCommandWithStdoutStderr(runCmd); err != nil { 220 t.Fatal(out, err) 221 } 222 223 // Test normal (non-detached) case first 224 cmd := exec.Command(dockerBinary, "exec", "top", "sh", "-c", "exit 23") 225 ec, _ := runCommand(cmd) 226 227 if ec != 23 { 228 t.Fatalf("Should have had an ExitCode of 23, not: %d", ec) 229 } 230 231 logDone("exec - exec non-zero ExitStatus") 232 } 233 234 func TestExecPausedContainer(t *testing.T) { 235 236 defer deleteAllContainers() 237 defer unpauseAllContainers() 238 239 runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "testing", "busybox", "top") 240 out, _, err := runCommandWithOutput(runCmd) 241 if err != nil { 242 t.Fatal(out, err) 243 } 244 245 ContainerID := stripTrailingCharacters(out) 246 247 pausedCmd := exec.Command(dockerBinary, "pause", "testing") 248 out, _, _, err = runCommandWithStdoutStderr(pausedCmd) 249 if err != nil { 250 t.Fatal(out, err) 251 } 252 253 execCmd := exec.Command(dockerBinary, "exec", "-i", "-t", ContainerID, "echo", "hello") 254 out, _, err = runCommandWithOutput(execCmd) 255 if err == nil { 256 t.Fatal("container should fail to exec new command if it is paused") 257 } 258 259 expected := ContainerID + " is paused, unpause the container before exec" 260 if !strings.Contains(out, expected) { 261 t.Fatal("container should not exec new command if it is paused") 262 } 263 264 logDone("exec - exec should not exec a pause container") 265 } 266 267 // regression test for #9476 268 func TestExecTtyCloseStdin(t *testing.T) { 269 defer deleteAllContainers() 270 271 cmd := exec.Command(dockerBinary, "run", "-d", "-it", "--name", "exec_tty_stdin", "busybox") 272 if out, _, err := runCommandWithOutput(cmd); err != nil { 273 t.Fatal(out, err) 274 } 275 276 cmd = exec.Command(dockerBinary, "exec", "-i", "exec_tty_stdin", "cat") 277 stdinRw, err := cmd.StdinPipe() 278 if err != nil { 279 t.Fatal(err) 280 } 281 282 stdinRw.Write([]byte("test")) 283 stdinRw.Close() 284 285 if out, _, err := runCommandWithOutput(cmd); err != nil { 286 t.Fatal(out, err) 287 } 288 289 cmd = exec.Command(dockerBinary, "top", "exec_tty_stdin") 290 out, _, err := runCommandWithOutput(cmd) 291 if err != nil { 292 t.Fatal(out, err) 293 } 294 295 outArr := strings.Split(out, "\n") 296 if len(outArr) > 3 || strings.Contains(out, "nsenter-exec") { 297 // This is the really bad part 298 if out, _, err := runCommandWithOutput(exec.Command(dockerBinary, "rm", "-f", "exec_tty_stdin")); err != nil { 299 t.Fatal(out, err) 300 } 301 302 t.Fatalf("exec process left running\n\t %s", out) 303 } 304 305 logDone("exec - stdin is closed properly with tty enabled") 306 } 307 308 func TestExecTtyWithoutStdin(t *testing.T) { 309 defer deleteAllContainers() 310 311 cmd := exec.Command(dockerBinary, "run", "-d", "-ti", "busybox") 312 out, _, err := runCommandWithOutput(cmd) 313 if err != nil { 314 t.Fatalf("failed to start container: %v (%v)", out, err) 315 } 316 317 id := strings.TrimSpace(out) 318 if err := waitRun(id); err != nil { 319 t.Fatal(err) 320 } 321 322 defer func() { 323 cmd := exec.Command(dockerBinary, "kill", id) 324 if out, _, err := runCommandWithOutput(cmd); err != nil { 325 t.Fatalf("failed to kill container: %v (%v)", out, err) 326 } 327 }() 328 329 done := make(chan struct{}) 330 go func() { 331 defer close(done) 332 333 cmd := exec.Command(dockerBinary, "exec", "-ti", id, "true") 334 if _, err := cmd.StdinPipe(); err != nil { 335 t.Fatal(err) 336 } 337 338 expected := "cannot enable tty mode" 339 if out, _, err := runCommandWithOutput(cmd); err == nil { 340 t.Fatal("exec should have failed") 341 } else if !strings.Contains(out, expected) { 342 t.Fatalf("exec failed with error %q: expected %q", out, expected) 343 } 344 }() 345 346 select { 347 case <-done: 348 case <-time.After(3 * time.Second): 349 t.Fatal("exec is running but should have failed") 350 } 351 352 logDone("exec - forbid piped stdin to tty enabled container") 353 } 354 355 func TestExecParseError(t *testing.T) { 356 defer deleteAllContainers() 357 358 runCmd := exec.Command(dockerBinary, "run", "-d", "--name", "top", "busybox", "top") 359 if out, _, err := runCommandWithOutput(runCmd); err != nil { 360 t.Fatal(out, err) 361 } 362 363 // Test normal (non-detached) case first 364 cmd := exec.Command(dockerBinary, "exec", "top") 365 if _, stderr, code, err := runCommandWithStdoutStderr(cmd); err == nil || !strings.Contains(stderr, "See '"+dockerBinary+" exec --help'") || code == 0 { 366 t.Fatalf("Should have thrown error & point to help: %s", stderr) 367 } 368 logDone("exec - error on parseExec should point to help") 369 } 370 371 func TestExecStopNotHanging(t *testing.T) { 372 defer deleteAllContainers() 373 if out, err := exec.Command(dockerBinary, "run", "-d", "--name", "testing", "busybox", "top").CombinedOutput(); err != nil { 374 t.Fatal(out, err) 375 } 376 377 if err := exec.Command(dockerBinary, "exec", "testing", "top").Start(); err != nil { 378 t.Fatal(err) 379 } 380 381 wait := make(chan struct{}) 382 go func() { 383 if out, err := exec.Command(dockerBinary, "stop", "testing").CombinedOutput(); err != nil { 384 t.Fatal(out, err) 385 } 386 close(wait) 387 }() 388 select { 389 case <-time.After(3 * time.Second): 390 t.Fatal("Container stop timed out") 391 case <-wait: 392 } 393 logDone("exec - container with exec not hanging on stop") 394 }