api_test.go 26 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021
  1. package docker
  2. import (
  3. "bufio"
  4. "bytes"
  5. "encoding/json"
  6. "io"
  7. "io/ioutil"
  8. "net"
  9. "net/http"
  10. "net/http/httptest"
  11. "testing"
  12. "time"
  13. "github.com/dotcloud/docker/api"
  14. "github.com/dotcloud/docker/api/server"
  15. "github.com/dotcloud/docker/engine"
  16. "github.com/dotcloud/docker/runconfig"
  17. "github.com/dotcloud/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
  18. )
  19. func TestGetContainersJSON(t *testing.T) {
  20. eng := NewTestEngine(t)
  21. defer mkDaemonFromEngine(eng, t).Nuke()
  22. job := eng.Job("containers")
  23. job.SetenvBool("all", true)
  24. outs, err := job.Stdout.AddTable()
  25. if err != nil {
  26. t.Fatal(err)
  27. }
  28. if err := job.Run(); err != nil {
  29. t.Fatal(err)
  30. }
  31. beginLen := len(outs.Data)
  32. containerID := createTestContainer(eng, &runconfig.Config{
  33. Image: unitTestImageID,
  34. Cmd: []string{"echo", "test"},
  35. }, t)
  36. if containerID == "" {
  37. t.Fatalf("Received empty container ID")
  38. }
  39. req, err := http.NewRequest("GET", "/containers/json?all=1", nil)
  40. if err != nil {
  41. t.Fatal(err)
  42. }
  43. r := httptest.NewRecorder()
  44. if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  45. t.Fatal(err)
  46. }
  47. assertHttpNotError(r, t)
  48. containers := engine.NewTable("", 0)
  49. if _, err := containers.ReadListFrom(r.Body.Bytes()); err != nil {
  50. t.Fatal(err)
  51. }
  52. if len(containers.Data) != beginLen+1 {
  53. t.Fatalf("Expected %d container, %d found (started with: %d)", beginLen+1, len(containers.Data), beginLen)
  54. }
  55. if id := containers.Data[0].Get("Id"); id != containerID {
  56. t.Fatalf("Container ID mismatch. Expected: %s, received: %s\n", containerID, id)
  57. }
  58. }
  59. func TestGetContainersExport(t *testing.T) {
  60. eng := NewTestEngine(t)
  61. defer mkDaemonFromEngine(eng, t).Nuke()
  62. // Create a container and remove a file
  63. containerID := createTestContainer(eng,
  64. &runconfig.Config{
  65. Image: unitTestImageID,
  66. Cmd: []string{"touch", "/test"},
  67. },
  68. t,
  69. )
  70. containerRun(eng, containerID, t)
  71. r := httptest.NewRecorder()
  72. req, err := http.NewRequest("GET", "/containers/"+containerID+"/export", nil)
  73. if err != nil {
  74. t.Fatal(err)
  75. }
  76. if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  77. t.Fatal(err)
  78. }
  79. assertHttpNotError(r, t)
  80. if r.Code != http.StatusOK {
  81. t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
  82. }
  83. found := false
  84. for tarReader := tar.NewReader(r.Body); ; {
  85. h, err := tarReader.Next()
  86. if err != nil {
  87. if err == io.EOF {
  88. break
  89. }
  90. t.Fatal(err)
  91. }
  92. if h.Name == "test" {
  93. found = true
  94. break
  95. }
  96. }
  97. if !found {
  98. t.Fatalf("The created test file has not been found in the exported image")
  99. }
  100. }
  101. func TestSaveImageAndThenLoad(t *testing.T) {
  102. eng := NewTestEngine(t)
  103. defer mkDaemonFromEngine(eng, t).Nuke()
  104. // save image
  105. r := httptest.NewRecorder()
  106. req, err := http.NewRequest("GET", "/images/"+unitTestImageID+"/get", nil)
  107. if err != nil {
  108. t.Fatal(err)
  109. }
  110. if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  111. t.Fatal(err)
  112. }
  113. if r.Code != http.StatusOK {
  114. t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
  115. }
  116. tarball := r.Body
  117. // delete the image
  118. r = httptest.NewRecorder()
  119. req, err = http.NewRequest("DELETE", "/images/"+unitTestImageID, nil)
  120. if err != nil {
  121. t.Fatal(err)
  122. }
  123. if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  124. t.Fatal(err)
  125. }
  126. if r.Code != http.StatusOK {
  127. t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
  128. }
  129. // make sure there is no image
  130. r = httptest.NewRecorder()
  131. req, err = http.NewRequest("GET", "/images/"+unitTestImageID+"/get", nil)
  132. if err != nil {
  133. t.Fatal(err)
  134. }
  135. if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  136. t.Fatal(err)
  137. }
  138. if r.Code != http.StatusNotFound {
  139. t.Fatalf("%d NotFound expected, received %d\n", http.StatusNotFound, r.Code)
  140. }
  141. // load the image
  142. r = httptest.NewRecorder()
  143. req, err = http.NewRequest("POST", "/images/load", tarball)
  144. if err != nil {
  145. t.Fatal(err)
  146. }
  147. if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  148. t.Fatal(err)
  149. }
  150. if r.Code != http.StatusOK {
  151. t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
  152. }
  153. // finally make sure the image is there
  154. r = httptest.NewRecorder()
  155. req, err = http.NewRequest("GET", "/images/"+unitTestImageID+"/get", nil)
  156. if err != nil {
  157. t.Fatal(err)
  158. }
  159. if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  160. t.Fatal(err)
  161. }
  162. if r.Code != http.StatusOK {
  163. t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
  164. }
  165. }
  166. func TestGetContainersChanges(t *testing.T) {
  167. eng := NewTestEngine(t)
  168. defer mkDaemonFromEngine(eng, t).Nuke()
  169. // Create a container and remove a file
  170. containerID := createTestContainer(eng,
  171. &runconfig.Config{
  172. Image: unitTestImageID,
  173. Cmd: []string{"/bin/rm", "/etc/passwd"},
  174. },
  175. t,
  176. )
  177. containerRun(eng, containerID, t)
  178. r := httptest.NewRecorder()
  179. req, err := http.NewRequest("GET", "/containers/"+containerID+"/changes", nil)
  180. if err != nil {
  181. t.Fatal(err)
  182. }
  183. if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  184. t.Fatal(err)
  185. }
  186. assertHttpNotError(r, t)
  187. outs := engine.NewTable("", 0)
  188. if _, err := outs.ReadListFrom(r.Body.Bytes()); err != nil {
  189. t.Fatal(err)
  190. }
  191. // Check the changelog
  192. success := false
  193. for _, elem := range outs.Data {
  194. if elem.Get("Path") == "/etc/passwd" && elem.GetInt("Kind") == 2 {
  195. success = true
  196. }
  197. }
  198. if !success {
  199. t.Fatalf("/etc/passwd as been removed but is not present in the diff")
  200. }
  201. }
  202. func TestGetContainersTop(t *testing.T) {
  203. eng := NewTestEngine(t)
  204. defer mkDaemonFromEngine(eng, t).Nuke()
  205. containerID := createTestContainer(eng,
  206. &runconfig.Config{
  207. Image: unitTestImageID,
  208. Cmd: []string{"/bin/sh", "-c", "cat"},
  209. OpenStdin: true,
  210. },
  211. t,
  212. )
  213. defer func() {
  214. // Make sure the process dies before destroying daemon
  215. containerKill(eng, containerID, t)
  216. containerWait(eng, containerID, t)
  217. }()
  218. startContainer(eng, containerID, t)
  219. setTimeout(t, "Waiting for the container to be started timed out", 10*time.Second, func() {
  220. for {
  221. if containerRunning(eng, containerID, t) {
  222. break
  223. }
  224. time.Sleep(10 * time.Millisecond)
  225. }
  226. })
  227. if !containerRunning(eng, containerID, t) {
  228. t.Fatalf("Container should be running")
  229. }
  230. // Make sure sh spawn up cat
  231. setTimeout(t, "read/write assertion timed out", 2*time.Second, func() {
  232. in, out := containerAttach(eng, containerID, t)
  233. if err := assertPipe("hello\n", "hello", out, in, 150); err != nil {
  234. t.Fatal(err)
  235. }
  236. })
  237. r := httptest.NewRecorder()
  238. req, err := http.NewRequest("GET", "/containers/"+containerID+"/top?ps_args=aux", nil)
  239. if err != nil {
  240. t.Fatal(err)
  241. }
  242. if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  243. t.Fatal(err)
  244. }
  245. assertHttpNotError(r, t)
  246. var procs engine.Env
  247. if err := procs.Decode(r.Body); err != nil {
  248. t.Fatal(err)
  249. }
  250. if len(procs.GetList("Titles")) != 11 {
  251. t.Fatalf("Expected 11 titles, found %d.", len(procs.GetList("Titles")))
  252. }
  253. if procs.GetList("Titles")[0] != "USER" || procs.GetList("Titles")[10] != "COMMAND" {
  254. t.Fatalf("Expected Titles[0] to be USER and Titles[10] to be COMMAND, found %s and %s.", procs.GetList("Titles")[0], procs.GetList("Titles")[10])
  255. }
  256. processes := [][]string{}
  257. if err := procs.GetJson("Processes", &processes); err != nil {
  258. t.Fatal(err)
  259. }
  260. if len(processes) != 2 {
  261. t.Fatalf("Expected 2 processes, found %d.", len(processes))
  262. }
  263. if processes[0][10] != "/bin/sh -c cat" {
  264. t.Fatalf("Expected `/bin/sh -c cat`, found %s.", processes[0][10])
  265. }
  266. if processes[1][10] != "/bin/sh -c cat" {
  267. t.Fatalf("Expected `/bin/sh -c cat`, found %s.", processes[1][10])
  268. }
  269. }
  270. func TestPostCommit(t *testing.T) {
  271. eng := NewTestEngine(t)
  272. defer mkDaemonFromEngine(eng, t).Nuke()
  273. // Create a container and remove a file
  274. containerID := createTestContainer(eng,
  275. &runconfig.Config{
  276. Image: unitTestImageID,
  277. Cmd: []string{"touch", "/test"},
  278. },
  279. t,
  280. )
  281. containerRun(eng, containerID, t)
  282. req, err := http.NewRequest("POST", "/commit?repo=testrepo&testtag=tag&container="+containerID, bytes.NewReader([]byte{}))
  283. if err != nil {
  284. t.Fatal(err)
  285. }
  286. r := httptest.NewRecorder()
  287. if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  288. t.Fatal(err)
  289. }
  290. assertHttpNotError(r, t)
  291. if r.Code != http.StatusCreated {
  292. t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code)
  293. }
  294. var env engine.Env
  295. if err := env.Decode(r.Body); err != nil {
  296. t.Fatal(err)
  297. }
  298. if err := eng.Job("image_inspect", env.Get("Id")).Run(); err != nil {
  299. t.Fatalf("The image has not been committed")
  300. }
  301. }
  302. func TestPostContainersCreate(t *testing.T) {
  303. eng := NewTestEngine(t)
  304. defer mkDaemonFromEngine(eng, t).Nuke()
  305. configJSON, err := json.Marshal(&runconfig.Config{
  306. Image: unitTestImageID,
  307. Memory: 33554432,
  308. Cmd: []string{"touch", "/test"},
  309. })
  310. if err != nil {
  311. t.Fatal(err)
  312. }
  313. req, err := http.NewRequest("POST", "/containers/create", bytes.NewReader(configJSON))
  314. if err != nil {
  315. t.Fatal(err)
  316. }
  317. r := httptest.NewRecorder()
  318. if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  319. t.Fatal(err)
  320. }
  321. assertHttpNotError(r, t)
  322. if r.Code != http.StatusCreated {
  323. t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code)
  324. }
  325. var apiRun engine.Env
  326. if err := apiRun.Decode(r.Body); err != nil {
  327. t.Fatal(err)
  328. }
  329. containerID := apiRun.Get("Id")
  330. containerAssertExists(eng, containerID, t)
  331. containerRun(eng, containerID, t)
  332. if !containerFileExists(eng, containerID, "test", t) {
  333. t.Fatal("Test file was not created")
  334. }
  335. }
  336. func TestPostContainersKill(t *testing.T) {
  337. eng := NewTestEngine(t)
  338. defer mkDaemonFromEngine(eng, t).Nuke()
  339. containerID := createTestContainer(eng,
  340. &runconfig.Config{
  341. Image: unitTestImageID,
  342. Cmd: []string{"/bin/cat"},
  343. OpenStdin: true,
  344. },
  345. t,
  346. )
  347. startContainer(eng, containerID, t)
  348. // Give some time to the process to start
  349. containerWaitTimeout(eng, containerID, t)
  350. if !containerRunning(eng, containerID, t) {
  351. t.Errorf("Container should be running")
  352. }
  353. r := httptest.NewRecorder()
  354. req, err := http.NewRequest("POST", "/containers/"+containerID+"/kill", bytes.NewReader([]byte{}))
  355. if err != nil {
  356. t.Fatal(err)
  357. }
  358. if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  359. t.Fatal(err)
  360. }
  361. assertHttpNotError(r, t)
  362. if r.Code != http.StatusNoContent {
  363. t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
  364. }
  365. if containerRunning(eng, containerID, t) {
  366. t.Fatalf("The container hasn't been killed")
  367. }
  368. }
  369. func TestPostContainersRestart(t *testing.T) {
  370. eng := NewTestEngine(t)
  371. defer mkDaemonFromEngine(eng, t).Nuke()
  372. containerID := createTestContainer(eng,
  373. &runconfig.Config{
  374. Image: unitTestImageID,
  375. Cmd: []string{"/bin/top"},
  376. OpenStdin: true,
  377. },
  378. t,
  379. )
  380. startContainer(eng, containerID, t)
  381. // Give some time to the process to start
  382. containerWaitTimeout(eng, containerID, t)
  383. if !containerRunning(eng, containerID, t) {
  384. t.Errorf("Container should be running")
  385. }
  386. req, err := http.NewRequest("POST", "/containers/"+containerID+"/restart?t=1", bytes.NewReader([]byte{}))
  387. if err != nil {
  388. t.Fatal(err)
  389. }
  390. r := httptest.NewRecorder()
  391. if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  392. t.Fatal(err)
  393. }
  394. assertHttpNotError(r, t)
  395. if r.Code != http.StatusNoContent {
  396. t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
  397. }
  398. // Give some time to the process to restart
  399. containerWaitTimeout(eng, containerID, t)
  400. if !containerRunning(eng, containerID, t) {
  401. t.Fatalf("Container should be running")
  402. }
  403. containerKill(eng, containerID, t)
  404. }
  405. func TestPostContainersStart(t *testing.T) {
  406. eng := NewTestEngine(t)
  407. defer mkDaemonFromEngine(eng, t).Nuke()
  408. containerID := createTestContainer(
  409. eng,
  410. &runconfig.Config{
  411. Image: unitTestImageID,
  412. Cmd: []string{"/bin/cat"},
  413. OpenStdin: true,
  414. },
  415. t,
  416. )
  417. hostConfigJSON, err := json.Marshal(&runconfig.HostConfig{})
  418. req, err := http.NewRequest("POST", "/containers/"+containerID+"/start", bytes.NewReader(hostConfigJSON))
  419. if err != nil {
  420. t.Fatal(err)
  421. }
  422. req.Header.Set("Content-Type", "application/json")
  423. r := httptest.NewRecorder()
  424. if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  425. t.Fatal(err)
  426. }
  427. assertHttpNotError(r, t)
  428. if r.Code != http.StatusNoContent {
  429. t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
  430. }
  431. containerAssertExists(eng, containerID, t)
  432. req, err = http.NewRequest("POST", "/containers/"+containerID+"/start", bytes.NewReader(hostConfigJSON))
  433. if err != nil {
  434. t.Fatal(err)
  435. }
  436. req.Header.Set("Content-Type", "application/json")
  437. r = httptest.NewRecorder()
  438. if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  439. t.Fatal(err)
  440. }
  441. // Starting an already started container should return a 304
  442. assertHttpNotError(r, t)
  443. if r.Code != http.StatusNotModified {
  444. t.Fatalf("%d NOT MODIFIER expected, received %d\n", http.StatusNotModified, r.Code)
  445. }
  446. containerAssertExists(eng, containerID, t)
  447. containerKill(eng, containerID, t)
  448. }
  449. func TestPostContainersStop(t *testing.T) {
  450. eng := NewTestEngine(t)
  451. defer mkDaemonFromEngine(eng, t).Nuke()
  452. containerID := createTestContainer(eng,
  453. &runconfig.Config{
  454. Image: unitTestImageID,
  455. Cmd: []string{"/bin/top"},
  456. OpenStdin: true,
  457. },
  458. t,
  459. )
  460. startContainer(eng, containerID, t)
  461. // Give some time to the process to start
  462. containerWaitTimeout(eng, containerID, t)
  463. if !containerRunning(eng, containerID, t) {
  464. t.Errorf("Container should be running")
  465. }
  466. // Note: as it is a POST request, it requires a body.
  467. req, err := http.NewRequest("POST", "/containers/"+containerID+"/stop?t=1", bytes.NewReader([]byte{}))
  468. if err != nil {
  469. t.Fatal(err)
  470. }
  471. r := httptest.NewRecorder()
  472. if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  473. t.Fatal(err)
  474. }
  475. assertHttpNotError(r, t)
  476. if r.Code != http.StatusNoContent {
  477. t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
  478. }
  479. if containerRunning(eng, containerID, t) {
  480. t.Fatalf("The container hasn't been stopped")
  481. }
  482. req, err = http.NewRequest("POST", "/containers/"+containerID+"/stop?t=1", bytes.NewReader([]byte{}))
  483. if err != nil {
  484. t.Fatal(err)
  485. }
  486. r = httptest.NewRecorder()
  487. if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  488. t.Fatal(err)
  489. }
  490. // Stopping an already stopper container should return a 304
  491. assertHttpNotError(r, t)
  492. if r.Code != http.StatusNotModified {
  493. t.Fatalf("%d NOT MODIFIER expected, received %d\n", http.StatusNotModified, r.Code)
  494. }
  495. }
  496. func TestPostContainersWait(t *testing.T) {
  497. eng := NewTestEngine(t)
  498. defer mkDaemonFromEngine(eng, t).Nuke()
  499. containerID := createTestContainer(eng,
  500. &runconfig.Config{
  501. Image: unitTestImageID,
  502. Cmd: []string{"/bin/sleep", "1"},
  503. OpenStdin: true,
  504. },
  505. t,
  506. )
  507. startContainer(eng, containerID, t)
  508. setTimeout(t, "Wait timed out", 3*time.Second, func() {
  509. r := httptest.NewRecorder()
  510. req, err := http.NewRequest("POST", "/containers/"+containerID+"/wait", bytes.NewReader([]byte{}))
  511. if err != nil {
  512. t.Fatal(err)
  513. }
  514. if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  515. t.Fatal(err)
  516. }
  517. assertHttpNotError(r, t)
  518. var apiWait engine.Env
  519. if err := apiWait.Decode(r.Body); err != nil {
  520. t.Fatal(err)
  521. }
  522. if apiWait.GetInt("StatusCode") != 0 {
  523. t.Fatalf("Non zero exit code for sleep: %d\n", apiWait.GetInt("StatusCode"))
  524. }
  525. })
  526. if containerRunning(eng, containerID, t) {
  527. t.Fatalf("The container should be stopped after wait")
  528. }
  529. }
  530. func TestPostContainersAttach(t *testing.T) {
  531. eng := NewTestEngine(t)
  532. defer mkDaemonFromEngine(eng, t).Nuke()
  533. containerID := createTestContainer(eng,
  534. &runconfig.Config{
  535. Image: unitTestImageID,
  536. Cmd: []string{"/bin/cat"},
  537. OpenStdin: true,
  538. },
  539. t,
  540. )
  541. // Start the process
  542. startContainer(eng, containerID, t)
  543. stdin, stdinPipe := io.Pipe()
  544. stdout, stdoutPipe := io.Pipe()
  545. // Try to avoid the timeout in destroy. Best effort, don't check error
  546. defer func() {
  547. closeWrap(stdin, stdinPipe, stdout, stdoutPipe)
  548. containerKill(eng, containerID, t)
  549. }()
  550. // Attach to it
  551. c1 := make(chan struct{})
  552. go func() {
  553. defer close(c1)
  554. r := &hijackTester{
  555. ResponseRecorder: httptest.NewRecorder(),
  556. in: stdin,
  557. out: stdoutPipe,
  558. }
  559. req, err := http.NewRequest("POST", "/containers/"+containerID+"/attach?stream=1&stdin=1&stdout=1&stderr=1", bytes.NewReader([]byte{}))
  560. if err != nil {
  561. t.Fatal(err)
  562. }
  563. if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  564. t.Fatal(err)
  565. }
  566. assertHttpNotError(r.ResponseRecorder, t)
  567. }()
  568. // Acknowledge hijack
  569. setTimeout(t, "hijack acknowledge timed out", 2*time.Second, func() {
  570. stdout.Read([]byte{})
  571. stdout.Read(make([]byte, 4096))
  572. })
  573. setTimeout(t, "read/write assertion timed out", 2*time.Second, func() {
  574. if err := assertPipe("hello\n", string([]byte{1, 0, 0, 0, 0, 0, 0, 6})+"hello", stdout, stdinPipe, 150); err != nil {
  575. t.Fatal(err)
  576. }
  577. })
  578. // Close pipes (client disconnects)
  579. if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
  580. t.Fatal(err)
  581. }
  582. // Wait for attach to finish, the client disconnected, therefore, Attach finished his job
  583. setTimeout(t, "Waiting for CmdAttach timed out", 10*time.Second, func() {
  584. <-c1
  585. })
  586. // We closed stdin, expect /bin/cat to still be running
  587. // Wait a little bit to make sure container.monitor() did his thing
  588. containerWaitTimeout(eng, containerID, t)
  589. // Try to avoid the timeout in destroy. Best effort, don't check error
  590. cStdin, _ := containerAttach(eng, containerID, t)
  591. cStdin.Close()
  592. containerWait(eng, containerID, t)
  593. }
  594. func TestPostContainersAttachStderr(t *testing.T) {
  595. eng := NewTestEngine(t)
  596. defer mkDaemonFromEngine(eng, t).Nuke()
  597. containerID := createTestContainer(eng,
  598. &runconfig.Config{
  599. Image: unitTestImageID,
  600. Cmd: []string{"/bin/sh", "-c", "/bin/cat >&2"},
  601. OpenStdin: true,
  602. },
  603. t,
  604. )
  605. // Start the process
  606. startContainer(eng, containerID, t)
  607. stdin, stdinPipe := io.Pipe()
  608. stdout, stdoutPipe := io.Pipe()
  609. // Try to avoid the timeout in destroy. Best effort, don't check error
  610. defer func() {
  611. closeWrap(stdin, stdinPipe, stdout, stdoutPipe)
  612. containerKill(eng, containerID, t)
  613. }()
  614. // Attach to it
  615. c1 := make(chan struct{})
  616. go func() {
  617. defer close(c1)
  618. r := &hijackTester{
  619. ResponseRecorder: httptest.NewRecorder(),
  620. in: stdin,
  621. out: stdoutPipe,
  622. }
  623. req, err := http.NewRequest("POST", "/containers/"+containerID+"/attach?stream=1&stdin=1&stdout=1&stderr=1", bytes.NewReader([]byte{}))
  624. if err != nil {
  625. t.Fatal(err)
  626. }
  627. if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  628. t.Fatal(err)
  629. }
  630. assertHttpNotError(r.ResponseRecorder, t)
  631. }()
  632. // Acknowledge hijack
  633. setTimeout(t, "hijack acknowledge timed out", 2*time.Second, func() {
  634. stdout.Read([]byte{})
  635. stdout.Read(make([]byte, 4096))
  636. })
  637. setTimeout(t, "read/write assertion timed out", 2*time.Second, func() {
  638. if err := assertPipe("hello\n", string([]byte{2, 0, 0, 0, 0, 0, 0, 6})+"hello", stdout, stdinPipe, 150); err != nil {
  639. t.Fatal(err)
  640. }
  641. })
  642. // Close pipes (client disconnects)
  643. if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
  644. t.Fatal(err)
  645. }
  646. // Wait for attach to finish, the client disconnected, therefore, Attach finished his job
  647. setTimeout(t, "Waiting for CmdAttach timed out", 10*time.Second, func() {
  648. <-c1
  649. })
  650. // We closed stdin, expect /bin/cat to still be running
  651. // Wait a little bit to make sure container.monitor() did his thing
  652. containerWaitTimeout(eng, containerID, t)
  653. // Try to avoid the timeout in destroy. Best effort, don't check error
  654. cStdin, _ := containerAttach(eng, containerID, t)
  655. cStdin.Close()
  656. containerWait(eng, containerID, t)
  657. }
  658. // FIXME: Test deleting running container
  659. // FIXME: Test deleting container with volume
  660. // FIXME: Test deleting volume in use by other container
  661. func TestDeleteContainers(t *testing.T) {
  662. eng := NewTestEngine(t)
  663. defer mkDaemonFromEngine(eng, t).Nuke()
  664. containerID := createTestContainer(eng,
  665. &runconfig.Config{
  666. Image: unitTestImageID,
  667. Cmd: []string{"touch", "/test"},
  668. },
  669. t,
  670. )
  671. req, err := http.NewRequest("DELETE", "/containers/"+containerID, nil)
  672. if err != nil {
  673. t.Fatal(err)
  674. }
  675. r := httptest.NewRecorder()
  676. if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  677. t.Fatal(err)
  678. }
  679. assertHttpNotError(r, t)
  680. if r.Code != http.StatusNoContent {
  681. t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
  682. }
  683. containerAssertNotExists(eng, containerID, t)
  684. }
  685. func TestOptionsRoute(t *testing.T) {
  686. eng := NewTestEngine(t)
  687. defer mkDaemonFromEngine(eng, t).Nuke()
  688. r := httptest.NewRecorder()
  689. req, err := http.NewRequest("OPTIONS", "/", nil)
  690. if err != nil {
  691. t.Fatal(err)
  692. }
  693. if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  694. t.Fatal(err)
  695. }
  696. assertHttpNotError(r, t)
  697. if r.Code != http.StatusOK {
  698. t.Errorf("Expected response for OPTIONS request to be \"200\", %v found.", r.Code)
  699. }
  700. }
  701. func TestGetEnabledCors(t *testing.T) {
  702. eng := NewTestEngine(t)
  703. defer mkDaemonFromEngine(eng, t).Nuke()
  704. r := httptest.NewRecorder()
  705. req, err := http.NewRequest("GET", "/version", nil)
  706. if err != nil {
  707. t.Fatal(err)
  708. }
  709. if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  710. t.Fatal(err)
  711. }
  712. assertHttpNotError(r, t)
  713. if r.Code != http.StatusOK {
  714. t.Errorf("Expected response for OPTIONS request to be \"200\", %v found.", r.Code)
  715. }
  716. allowOrigin := r.Header().Get("Access-Control-Allow-Origin")
  717. allowHeaders := r.Header().Get("Access-Control-Allow-Headers")
  718. allowMethods := r.Header().Get("Access-Control-Allow-Methods")
  719. if allowOrigin != "*" {
  720. t.Errorf("Expected header Access-Control-Allow-Origin to be \"*\", %s found.", allowOrigin)
  721. }
  722. if allowHeaders != "Origin, X-Requested-With, Content-Type, Accept" {
  723. t.Errorf("Expected header Access-Control-Allow-Headers to be \"Origin, X-Requested-With, Content-Type, Accept\", %s found.", allowHeaders)
  724. }
  725. if allowMethods != "GET, POST, DELETE, PUT, OPTIONS" {
  726. t.Errorf("Expected hearder Access-Control-Allow-Methods to be \"GET, POST, DELETE, PUT, OPTIONS\", %s found.", allowMethods)
  727. }
  728. }
  729. func TestDeleteImages(t *testing.T) {
  730. eng := NewTestEngine(t)
  731. //we expect errors, so we disable stderr
  732. eng.Stderr = ioutil.Discard
  733. defer mkDaemonFromEngine(eng, t).Nuke()
  734. initialImages := getImages(eng, t, true, "")
  735. if err := eng.Job("tag", unitTestImageName, "test", "test").Run(); err != nil {
  736. t.Fatal(err)
  737. }
  738. images := getImages(eng, t, true, "")
  739. if len(images.Data[0].GetList("RepoTags")) != len(initialImages.Data[0].GetList("RepoTags"))+1 {
  740. t.Errorf("Expected %d images, %d found", len(initialImages.Data[0].GetList("RepoTags"))+1, len(images.Data[0].GetList("RepoTags")))
  741. }
  742. req, err := http.NewRequest("DELETE", "/images/"+unitTestImageID, nil)
  743. if err != nil {
  744. t.Fatal(err)
  745. }
  746. r := httptest.NewRecorder()
  747. if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  748. t.Fatal(err)
  749. }
  750. if r.Code != http.StatusConflict {
  751. t.Fatalf("Expected http status 409-conflict, got %v", r.Code)
  752. }
  753. req2, err := http.NewRequest("DELETE", "/images/test:test", nil)
  754. if err != nil {
  755. t.Fatal(err)
  756. }
  757. r2 := httptest.NewRecorder()
  758. if err := server.ServeRequest(eng, api.APIVERSION, r2, req2); err != nil {
  759. t.Fatal(err)
  760. }
  761. assertHttpNotError(r2, t)
  762. if r2.Code != http.StatusOK {
  763. t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
  764. }
  765. outs := engine.NewTable("Created", 0)
  766. if _, err := outs.ReadListFrom(r2.Body.Bytes()); err != nil {
  767. t.Fatal(err)
  768. }
  769. if len(outs.Data) != 1 {
  770. t.Fatalf("Expected %d event (untagged), got %d", 1, len(outs.Data))
  771. }
  772. images = getImages(eng, t, false, "")
  773. if images.Len() != initialImages.Len() {
  774. t.Errorf("Expected %d image, %d found", initialImages.Len(), images.Len())
  775. }
  776. }
  777. func TestPostContainersCopy(t *testing.T) {
  778. eng := NewTestEngine(t)
  779. defer mkDaemonFromEngine(eng, t).Nuke()
  780. // Create a container and remove a file
  781. containerID := createTestContainer(eng,
  782. &runconfig.Config{
  783. Image: unitTestImageID,
  784. Cmd: []string{"touch", "/test.txt"},
  785. },
  786. t,
  787. )
  788. containerRun(eng, containerID, t)
  789. r := httptest.NewRecorder()
  790. var copyData engine.Env
  791. copyData.Set("Resource", "/test.txt")
  792. copyData.Set("HostPath", ".")
  793. jsonData := bytes.NewBuffer(nil)
  794. if err := copyData.Encode(jsonData); err != nil {
  795. t.Fatal(err)
  796. }
  797. req, err := http.NewRequest("POST", "/containers/"+containerID+"/copy", jsonData)
  798. if err != nil {
  799. t.Fatal(err)
  800. }
  801. req.Header.Add("Content-Type", "application/json")
  802. if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  803. t.Fatal(err)
  804. }
  805. assertHttpNotError(r, t)
  806. if r.Code != http.StatusOK {
  807. t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
  808. }
  809. found := false
  810. for tarReader := tar.NewReader(r.Body); ; {
  811. h, err := tarReader.Next()
  812. if err != nil {
  813. if err == io.EOF {
  814. break
  815. }
  816. t.Fatal(err)
  817. }
  818. if h.Name == "test.txt" {
  819. found = true
  820. break
  821. }
  822. }
  823. if !found {
  824. t.Fatalf("The created test file has not been found in the copied output")
  825. }
  826. }
  827. func TestPostContainersCopyWhenContainerNotFound(t *testing.T) {
  828. eng := NewTestEngine(t)
  829. defer mkDaemonFromEngine(eng, t).Nuke()
  830. r := httptest.NewRecorder()
  831. var copyData engine.Env
  832. copyData.Set("Resource", "/test.txt")
  833. copyData.Set("HostPath", ".")
  834. jsonData := bytes.NewBuffer(nil)
  835. if err := copyData.Encode(jsonData); err != nil {
  836. t.Fatal(err)
  837. }
  838. req, err := http.NewRequest("POST", "/containers/id_not_found/copy", jsonData)
  839. if err != nil {
  840. t.Fatal(err)
  841. }
  842. req.Header.Add("Content-Type", "application/json")
  843. if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  844. t.Fatal(err)
  845. }
  846. if r.Code != http.StatusNotFound {
  847. t.Fatalf("404 expected for id_not_found Container, received %v", r.Code)
  848. }
  849. }
  850. // Mocked types for tests
  851. type NopConn struct {
  852. io.ReadCloser
  853. io.Writer
  854. }
  855. func (c *NopConn) LocalAddr() net.Addr { return nil }
  856. func (c *NopConn) RemoteAddr() net.Addr { return nil }
  857. func (c *NopConn) SetDeadline(t time.Time) error { return nil }
  858. func (c *NopConn) SetReadDeadline(t time.Time) error { return nil }
  859. func (c *NopConn) SetWriteDeadline(t time.Time) error { return nil }
  860. type hijackTester struct {
  861. *httptest.ResponseRecorder
  862. in io.ReadCloser
  863. out io.Writer
  864. }
  865. func (t *hijackTester) Hijack() (net.Conn, *bufio.ReadWriter, error) {
  866. bufrw := bufio.NewReadWriter(bufio.NewReader(t.in), bufio.NewWriter(t.out))
  867. conn := &NopConn{
  868. ReadCloser: t.in,
  869. Writer: t.out,
  870. }
  871. return conn, bufrw, nil
  872. }