commands_test.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701
  1. package docker
  2. import (
  3. "bufio"
  4. "fmt"
  5. "github.com/dotcloud/docker/utils"
  6. "io"
  7. "io/ioutil"
  8. "strings"
  9. "testing"
  10. "time"
  11. )
  12. func closeWrap(args ...io.Closer) error {
  13. e := false
  14. ret := fmt.Errorf("Error closing elements")
  15. for _, c := range args {
  16. if err := c.Close(); err != nil {
  17. e = true
  18. ret = fmt.Errorf("%s\n%s", ret, err)
  19. }
  20. }
  21. if e {
  22. return ret
  23. }
  24. return nil
  25. }
  26. func setTimeout(t *testing.T, msg string, d time.Duration, f func()) {
  27. c := make(chan bool)
  28. // Make sure we are not too long
  29. go func() {
  30. time.Sleep(d)
  31. c <- true
  32. }()
  33. go func() {
  34. f()
  35. c <- false
  36. }()
  37. if <-c && msg != "" {
  38. t.Fatal(msg)
  39. }
  40. }
  41. func assertPipe(input, output string, r io.Reader, w io.Writer, count int) error {
  42. for i := 0; i < count; i++ {
  43. if _, err := w.Write([]byte(input)); err != nil {
  44. return err
  45. }
  46. o, err := bufio.NewReader(r).ReadString('\n')
  47. if err != nil {
  48. return err
  49. }
  50. if strings.Trim(o, " \r\n") != output {
  51. return fmt.Errorf("Unexpected output. Expected [%s], received [%s]", output, o)
  52. }
  53. }
  54. return nil
  55. }
  56. // TestRunHostname checks that 'docker run -h' correctly sets a custom hostname
  57. func TestRunHostname(t *testing.T) {
  58. stdout, stdoutPipe := io.Pipe()
  59. cli := NewDockerCli(nil, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
  60. defer cleanup(globalRuntime)
  61. c := make(chan struct{})
  62. go func() {
  63. defer close(c)
  64. if err := cli.CmdRun("-h", "foobar", unitTestImageID, "hostname"); err != nil {
  65. t.Fatal(err)
  66. }
  67. }()
  68. setTimeout(t, "Reading command output time out", 2*time.Second, func() {
  69. cmdOutput, err := bufio.NewReader(stdout).ReadString('\n')
  70. if err != nil {
  71. t.Fatal(err)
  72. }
  73. if cmdOutput != "foobar\n" {
  74. t.Fatalf("'hostname' should display '%s', not '%s'", "foobar\n", cmdOutput)
  75. }
  76. })
  77. container := globalRuntime.List()[0]
  78. setTimeout(t, "CmdRun timed out", 10*time.Second, func() {
  79. <-c
  80. go func() {
  81. cli.CmdWait(container.ID)
  82. }()
  83. if _, err := bufio.NewReader(stdout).ReadString('\n'); err != nil {
  84. t.Fatal(err)
  85. }
  86. })
  87. // Cleanup pipes
  88. if err := closeWrap(stdout, stdoutPipe); err != nil {
  89. t.Fatal(err)
  90. }
  91. }
  92. // TestRunWorkdir checks that 'docker run -w' correctly sets a custom working directory
  93. func TestRunWorkdir(t *testing.T) {
  94. stdout, stdoutPipe := io.Pipe()
  95. cli := NewDockerCli(nil, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
  96. defer cleanup(globalRuntime)
  97. c := make(chan struct{})
  98. go func() {
  99. defer close(c)
  100. if err := cli.CmdRun("-w", "/foo/bar", unitTestImageID, "pwd"); err != nil {
  101. t.Fatal(err)
  102. }
  103. }()
  104. setTimeout(t, "Reading command output time out", 2*time.Second, func() {
  105. cmdOutput, err := bufio.NewReader(stdout).ReadString('\n')
  106. if err != nil {
  107. t.Fatal(err)
  108. }
  109. if cmdOutput != "/foo/bar\n" {
  110. t.Fatalf("'pwd' should display '%s', not '%s'", "/foo/bar\n", cmdOutput)
  111. }
  112. })
  113. container := globalRuntime.List()[0]
  114. setTimeout(t, "CmdRun timed out", 10*time.Second, func() {
  115. <-c
  116. go func() {
  117. cli.CmdWait(container.ID)
  118. }()
  119. if _, err := bufio.NewReader(stdout).ReadString('\n'); err != nil {
  120. t.Fatal(err)
  121. }
  122. })
  123. // Cleanup pipes
  124. if err := closeWrap(stdout, stdoutPipe); err != nil {
  125. t.Fatal(err)
  126. }
  127. }
  128. // TestRunWorkdirExists checks that 'docker run -w' correctly sets a custom working directory, even if it exists
  129. func TestRunWorkdirExists(t *testing.T) {
  130. stdout, stdoutPipe := io.Pipe()
  131. cli := NewDockerCli(nil, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
  132. defer cleanup(globalRuntime)
  133. c := make(chan struct{})
  134. go func() {
  135. defer close(c)
  136. if err := cli.CmdRun("-w", "/proc", unitTestImageID, "pwd"); err != nil {
  137. t.Fatal(err)
  138. }
  139. }()
  140. setTimeout(t, "Reading command output time out", 2*time.Second, func() {
  141. cmdOutput, err := bufio.NewReader(stdout).ReadString('\n')
  142. if err != nil {
  143. t.Fatal(err)
  144. }
  145. if cmdOutput != "/proc\n" {
  146. t.Fatalf("'pwd' should display '%s', not '%s'", "/proc\n", cmdOutput)
  147. }
  148. })
  149. container := globalRuntime.List()[0]
  150. setTimeout(t, "CmdRun timed out", 5*time.Second, func() {
  151. <-c
  152. go func() {
  153. cli.CmdWait(container.ID)
  154. }()
  155. if _, err := bufio.NewReader(stdout).ReadString('\n'); err != nil {
  156. t.Fatal(err)
  157. }
  158. })
  159. // Cleanup pipes
  160. if err := closeWrap(stdout, stdoutPipe); err != nil {
  161. t.Fatal(err)
  162. }
  163. }
  164. func TestRunExit(t *testing.T) {
  165. stdin, stdinPipe := io.Pipe()
  166. stdout, stdoutPipe := io.Pipe()
  167. cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
  168. defer cleanup(globalRuntime)
  169. c1 := make(chan struct{})
  170. go func() {
  171. cli.CmdRun("-i", unitTestImageID, "/bin/cat")
  172. close(c1)
  173. }()
  174. setTimeout(t, "Read/Write assertion timed out", 2*time.Second, func() {
  175. if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
  176. t.Fatal(err)
  177. }
  178. })
  179. container := globalRuntime.List()[0]
  180. // Closing /bin/cat stdin, expect it to exit
  181. if err := stdin.Close(); err != nil {
  182. t.Fatal(err)
  183. }
  184. // as the process exited, CmdRun must finish and unblock. Wait for it
  185. setTimeout(t, "Waiting for CmdRun timed out", 10*time.Second, func() {
  186. <-c1
  187. go func() {
  188. cli.CmdWait(container.ID)
  189. }()
  190. if _, err := bufio.NewReader(stdout).ReadString('\n'); err != nil {
  191. t.Fatal(err)
  192. }
  193. })
  194. // Make sure that the client has been disconnected
  195. setTimeout(t, "The client should have been disconnected once the remote process exited.", 2*time.Second, func() {
  196. // Expecting pipe i/o error, just check that read does not block
  197. stdin.Read([]byte{})
  198. })
  199. // Cleanup pipes
  200. if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
  201. t.Fatal(err)
  202. }
  203. }
  204. // Expected behaviour: the process dies when the client disconnects
  205. func TestRunDisconnect(t *testing.T) {
  206. stdin, stdinPipe := io.Pipe()
  207. stdout, stdoutPipe := io.Pipe()
  208. cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
  209. defer cleanup(globalRuntime)
  210. c1 := make(chan struct{})
  211. go func() {
  212. // We're simulating a disconnect so the return value doesn't matter. What matters is the
  213. // fact that CmdRun returns.
  214. cli.CmdRun("-i", unitTestImageID, "/bin/cat")
  215. close(c1)
  216. }()
  217. setTimeout(t, "Read/Write assertion timed out", 2*time.Second, func() {
  218. if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
  219. t.Fatal(err)
  220. }
  221. })
  222. // Close pipes (simulate disconnect)
  223. if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
  224. t.Fatal(err)
  225. }
  226. // as the pipes are close, we expect the process to die,
  227. // therefore CmdRun to unblock. Wait for CmdRun
  228. setTimeout(t, "Waiting for CmdRun timed out", 2*time.Second, func() {
  229. <-c1
  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 := globalRuntime.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. // Expected behaviour: the process dies when the client disconnects
  242. func TestRunDisconnectTty(t *testing.T) {
  243. stdin, stdinPipe := io.Pipe()
  244. stdout, stdoutPipe := io.Pipe()
  245. cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
  246. defer cleanup(globalRuntime)
  247. c1 := make(chan struct{})
  248. go func() {
  249. // We're simulating a disconnect so the return value doesn't matter. What matters is the
  250. // fact that CmdRun returns.
  251. if err := cli.CmdRun("-i", "-t", unitTestImageID, "/bin/cat"); err != nil {
  252. utils.Debugf("Error CmdRun: %s", err)
  253. }
  254. close(c1)
  255. }()
  256. setTimeout(t, "Waiting for the container to be started timed out", 10*time.Second, func() {
  257. for {
  258. // Client disconnect after run -i should keep stdin out in TTY mode
  259. l := globalRuntime.List()
  260. if len(l) == 1 && l[0].State.Running {
  261. break
  262. }
  263. time.Sleep(10 * time.Millisecond)
  264. }
  265. })
  266. // Client disconnect after run -i should keep stdin out in TTY mode
  267. container := globalRuntime.List()[0]
  268. setTimeout(t, "Read/Write assertion timed out", 2000*time.Second, func() {
  269. if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
  270. t.Fatal(err)
  271. }
  272. })
  273. // Close pipes (simulate disconnect)
  274. if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
  275. t.Fatal(err)
  276. }
  277. // In tty mode, we expect the process to stay alive even after client's stdin closes.
  278. // Do not wait for run to finish
  279. // Give some time to monitor to do his thing
  280. container.WaitTimeout(500 * time.Millisecond)
  281. if !container.State.Running {
  282. t.Fatalf("/bin/cat should still be running after closing stdin (tty mode)")
  283. }
  284. }
  285. // TestAttachStdin checks attaching to stdin without stdout and stderr.
  286. // 'docker run -i -a stdin' should sends the client's stdin to the command,
  287. // then detach from it and print the container id.
  288. func TestRunAttachStdin(t *testing.T) {
  289. stdin, stdinPipe := io.Pipe()
  290. stdout, stdoutPipe := io.Pipe()
  291. cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
  292. defer cleanup(globalRuntime)
  293. ch := make(chan struct{})
  294. go func() {
  295. defer close(ch)
  296. cli.CmdRun("-i", "-a", "stdin", unitTestImageID, "sh", "-c", "echo hello && cat && sleep 5")
  297. }()
  298. // Send input to the command, close stdin
  299. setTimeout(t, "Write timed out", 10*time.Second, func() {
  300. if _, err := stdinPipe.Write([]byte("hi there\n")); err != nil {
  301. t.Fatal(err)
  302. }
  303. if err := stdinPipe.Close(); err != nil {
  304. t.Fatal(err)
  305. }
  306. })
  307. container := globalRuntime.List()[0]
  308. // Check output
  309. setTimeout(t, "Reading command output time out", 10*time.Second, func() {
  310. cmdOutput, err := bufio.NewReader(stdout).ReadString('\n')
  311. if err != nil {
  312. t.Fatal(err)
  313. }
  314. if cmdOutput != container.ShortID()+"\n" {
  315. t.Fatalf("Wrong output: should be '%s', not '%s'\n", container.ShortID()+"\n", cmdOutput)
  316. }
  317. })
  318. // wait for CmdRun to return
  319. setTimeout(t, "Waiting for CmdRun timed out", 5*time.Second, func() {
  320. <-ch
  321. })
  322. setTimeout(t, "Waiting for command to exit timed out", 10*time.Second, func() {
  323. container.Wait()
  324. })
  325. // Check logs
  326. if cmdLogs, err := container.ReadLog("json"); err != nil {
  327. t.Fatal(err)
  328. } else {
  329. if output, err := ioutil.ReadAll(cmdLogs); err != nil {
  330. t.Fatal(err)
  331. } else {
  332. expectedLogs := []string{"{\"log\":\"hello\\n\",\"stream\":\"stdout\"", "{\"log\":\"hi there\\n\",\"stream\":\"stdout\""}
  333. for _, expectedLog := range expectedLogs {
  334. if !strings.Contains(string(output), expectedLog) {
  335. t.Fatalf("Unexpected logs: should contains '%s', it is not '%s'\n", expectedLog, output)
  336. }
  337. }
  338. }
  339. }
  340. }
  341. // TestRunDetach checks attaching and detaching with the escape sequence.
  342. func TestRunDetach(t *testing.T) {
  343. stdin, stdinPipe := io.Pipe()
  344. stdout, stdoutPipe := io.Pipe()
  345. cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
  346. defer cleanup(globalRuntime)
  347. ch := make(chan struct{})
  348. go func() {
  349. defer close(ch)
  350. cli.CmdRun("-i", "-t", unitTestImageID, "cat")
  351. }()
  352. setTimeout(t, "First read/write assertion timed out", 2*time.Second, func() {
  353. if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
  354. t.Fatal(err)
  355. }
  356. })
  357. container := globalRuntime.List()[0]
  358. setTimeout(t, "Escape sequence timeout", 5*time.Second, func() {
  359. stdinPipe.Write([]byte{16, 17})
  360. if err := stdinPipe.Close(); err != nil {
  361. t.Fatal(err)
  362. }
  363. })
  364. closeWrap(stdin, stdinPipe, stdout, stdoutPipe)
  365. // wait for CmdRun to return
  366. setTimeout(t, "Waiting for CmdRun timed out", 15*time.Second, func() {
  367. <-ch
  368. })
  369. time.Sleep(500 * time.Millisecond)
  370. if !container.State.Running {
  371. t.Fatal("The detached container should be still running")
  372. }
  373. setTimeout(t, "Waiting for container to die timed out", 20*time.Second, func() {
  374. container.Kill()
  375. })
  376. }
  377. // TestAttachDetach checks that attach in tty mode can be detached
  378. func TestAttachDetach(t *testing.T) {
  379. stdin, stdinPipe := io.Pipe()
  380. stdout, stdoutPipe := io.Pipe()
  381. cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
  382. defer cleanup(globalRuntime)
  383. ch := make(chan struct{})
  384. go func() {
  385. defer close(ch)
  386. if err := cli.CmdRun("-i", "-t", "-d", unitTestImageID, "cat"); err != nil {
  387. t.Fatal(err)
  388. }
  389. }()
  390. var container *Container
  391. setTimeout(t, "Reading container's id timed out", 10*time.Second, func() {
  392. buf := make([]byte, 1024)
  393. n, err := stdout.Read(buf)
  394. if err != nil {
  395. t.Fatal(err)
  396. }
  397. container = globalRuntime.List()[0]
  398. if strings.Trim(string(buf[:n]), " \r\n") != container.ShortID() {
  399. t.Fatalf("Wrong ID received. Expect %s, received %s", container.ShortID(), buf[:n])
  400. }
  401. })
  402. setTimeout(t, "Starting container timed out", 10*time.Second, func() {
  403. <-ch
  404. })
  405. stdin, stdinPipe = io.Pipe()
  406. stdout, stdoutPipe = io.Pipe()
  407. cli = NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
  408. ch = make(chan struct{})
  409. go func() {
  410. defer close(ch)
  411. if err := cli.CmdAttach(container.ShortID()); err != nil {
  412. if err != io.ErrClosedPipe {
  413. t.Fatal(err)
  414. }
  415. }
  416. }()
  417. setTimeout(t, "First read/write assertion timed out", 2*time.Second, func() {
  418. if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
  419. if err != io.ErrClosedPipe {
  420. t.Fatal(err)
  421. }
  422. }
  423. })
  424. setTimeout(t, "Escape sequence timeout", 5*time.Second, func() {
  425. stdinPipe.Write([]byte{16, 17})
  426. if err := stdinPipe.Close(); err != nil {
  427. t.Fatal(err)
  428. }
  429. })
  430. closeWrap(stdin, stdinPipe, stdout, stdoutPipe)
  431. // wait for CmdRun to return
  432. setTimeout(t, "Waiting for CmdAttach timed out", 15*time.Second, func() {
  433. <-ch
  434. })
  435. time.Sleep(500 * time.Millisecond)
  436. if !container.State.Running {
  437. t.Fatal("The detached container should be still running")
  438. }
  439. setTimeout(t, "Waiting for container to die timedout", 5*time.Second, func() {
  440. container.Kill()
  441. })
  442. }
  443. // Expected behaviour, the process stays alive when the client disconnects
  444. func TestAttachDisconnect(t *testing.T) {
  445. stdin, stdinPipe := io.Pipe()
  446. stdout, stdoutPipe := io.Pipe()
  447. cli := NewDockerCli(stdin, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
  448. defer cleanup(globalRuntime)
  449. go func() {
  450. // Start a process in daemon mode
  451. if err := cli.CmdRun("-d", "-i", unitTestImageID, "/bin/cat"); err != nil {
  452. utils.Debugf("Error CmdRun: %s", err)
  453. }
  454. }()
  455. setTimeout(t, "Waiting for CmdRun timed out", 10*time.Second, func() {
  456. if _, err := bufio.NewReader(stdout).ReadString('\n'); err != nil {
  457. t.Fatal(err)
  458. }
  459. })
  460. setTimeout(t, "Waiting for the container to be started timed out", 10*time.Second, func() {
  461. for {
  462. l := globalRuntime.List()
  463. if len(l) == 1 && l[0].State.Running {
  464. break
  465. }
  466. time.Sleep(10 * time.Millisecond)
  467. }
  468. })
  469. container := globalRuntime.List()[0]
  470. // Attach to it
  471. c1 := make(chan struct{})
  472. go func() {
  473. // We're simulating a disconnect so the return value doesn't matter. What matters is the
  474. // fact that CmdAttach returns.
  475. cli.CmdAttach(container.ID)
  476. close(c1)
  477. }()
  478. setTimeout(t, "First read/write assertion timed out", 2*time.Second, func() {
  479. if err := assertPipe("hello\n", "hello", stdout, stdinPipe, 15); err != nil {
  480. t.Fatal(err)
  481. }
  482. })
  483. // Close pipes (client disconnects)
  484. if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
  485. t.Fatal(err)
  486. }
  487. // Wait for attach to finish, the client disconnected, therefore, Attach finished his job
  488. setTimeout(t, "Waiting for CmdAttach timed out", 2*time.Second, func() {
  489. <-c1
  490. })
  491. // We closed stdin, expect /bin/cat to still be running
  492. // Wait a little bit to make sure container.monitor() did his thing
  493. err := container.WaitTimeout(500 * time.Millisecond)
  494. if err == nil || !container.State.Running {
  495. t.Fatalf("/bin/cat is not running after closing stdin")
  496. }
  497. // Try to avoid the timeout in destroy. Best effort, don't check error
  498. cStdin, _ := container.StdinPipe()
  499. cStdin.Close()
  500. container.Wait()
  501. }
  502. // Expected behaviour: container gets deleted automatically after exit
  503. func TestRunAutoRemove(t *testing.T) {
  504. t.Skip("Fixme. Skipping test for now, race condition")
  505. stdout, stdoutPipe := io.Pipe()
  506. cli := NewDockerCli(nil, stdoutPipe, ioutil.Discard, testDaemonProto, testDaemonAddr)
  507. defer cleanup(globalRuntime)
  508. c := make(chan struct{})
  509. go func() {
  510. defer close(c)
  511. if err := cli.CmdRun("-rm", unitTestImageID, "hostname"); err != nil {
  512. t.Fatal(err)
  513. }
  514. }()
  515. var temporaryContainerID string
  516. setTimeout(t, "Reading command output time out", 2*time.Second, func() {
  517. cmdOutput, err := bufio.NewReader(stdout).ReadString('\n')
  518. if err != nil {
  519. t.Fatal(err)
  520. }
  521. temporaryContainerID = cmdOutput
  522. if err := closeWrap(stdout, stdoutPipe); err != nil {
  523. t.Fatal(err)
  524. }
  525. })
  526. setTimeout(t, "CmdRun timed out", 10*time.Second, func() {
  527. <-c
  528. })
  529. time.Sleep(500 * time.Millisecond)
  530. if len(globalRuntime.List()) > 0 {
  531. t.Fatalf("failed to remove container automatically: container %s still exists", temporaryContainerID)
  532. }
  533. }
  534. func TestCmdLogs(t *testing.T) {
  535. cli := NewDockerCli(nil, ioutil.Discard, ioutil.Discard, testDaemonProto, testDaemonAddr)
  536. defer cleanup(globalRuntime)
  537. if err := cli.CmdRun(unitTestImageID, "sh", "-c", "ls -l"); err != nil {
  538. t.Fatal(err)
  539. }
  540. if err := cli.CmdRun("-t", unitTestImageID, "sh", "-c", "ls -l"); err != nil {
  541. t.Fatal(err)
  542. }
  543. if err := cli.CmdLogs(globalRuntime.List()[0].ID); err != nil {
  544. t.Fatal(err)
  545. }
  546. }
  547. // Expected behaviour: using / as a bind mount source should throw an error
  548. func TestRunErrorBindMountRootSource(t *testing.T) {
  549. cli := NewDockerCli(nil, nil, ioutil.Discard, testDaemonProto, testDaemonAddr)
  550. defer cleanup(globalRuntime)
  551. c := make(chan struct{})
  552. go func() {
  553. defer close(c)
  554. if err := cli.CmdRun("-v", "/:/tmp", unitTestImageID, "echo 'should fail'"); err == nil {
  555. t.Fatal("should have failed to run when using / as a source for the bind mount")
  556. }
  557. }()
  558. setTimeout(t, "CmdRun timed out", 5*time.Second, func() {
  559. <-c
  560. })
  561. }
  562. // Expected behaviour: error out when attempting to bind mount non-existing source paths
  563. func TestRunErrorBindNonExistingSource(t *testing.T) {
  564. cli := NewDockerCli(nil, nil, ioutil.Discard, testDaemonProto, testDaemonAddr)
  565. defer cleanup(globalRuntime)
  566. c := make(chan struct{})
  567. go func() {
  568. defer close(c)
  569. if err := cli.CmdRun("-v", "/i/dont/exist:/tmp", unitTestImageID, "echo 'should fail'"); err == nil {
  570. t.Fatal("should have failed to run when using /i/dont/exist as a source for the bind mount")
  571. }
  572. }()
  573. setTimeout(t, "CmdRun timed out", 5*time.Second, func() {
  574. <-c
  575. })
  576. }