api_test.go 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992
  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/docker/docker/api"
  14. "github.com/docker/docker/api/server"
  15. "github.com/docker/docker/engine"
  16. "github.com/docker/docker/runconfig"
  17. "github.com/docker/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. func TestOptionsRoute(t *testing.T) {
  659. eng := NewTestEngine(t)
  660. defer mkDaemonFromEngine(eng, t).Nuke()
  661. r := httptest.NewRecorder()
  662. req, err := http.NewRequest("OPTIONS", "/", nil)
  663. if err != nil {
  664. t.Fatal(err)
  665. }
  666. if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  667. t.Fatal(err)
  668. }
  669. assertHttpNotError(r, t)
  670. if r.Code != http.StatusOK {
  671. t.Errorf("Expected response for OPTIONS request to be \"200\", %v found.", r.Code)
  672. }
  673. }
  674. func TestGetEnabledCors(t *testing.T) {
  675. eng := NewTestEngine(t)
  676. defer mkDaemonFromEngine(eng, t).Nuke()
  677. r := httptest.NewRecorder()
  678. req, err := http.NewRequest("GET", "/version", nil)
  679. if err != nil {
  680. t.Fatal(err)
  681. }
  682. if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  683. t.Fatal(err)
  684. }
  685. assertHttpNotError(r, t)
  686. if r.Code != http.StatusOK {
  687. t.Errorf("Expected response for OPTIONS request to be \"200\", %v found.", r.Code)
  688. }
  689. allowOrigin := r.Header().Get("Access-Control-Allow-Origin")
  690. allowHeaders := r.Header().Get("Access-Control-Allow-Headers")
  691. allowMethods := r.Header().Get("Access-Control-Allow-Methods")
  692. if allowOrigin != "*" {
  693. t.Errorf("Expected header Access-Control-Allow-Origin to be \"*\", %s found.", allowOrigin)
  694. }
  695. if allowHeaders != "Origin, X-Requested-With, Content-Type, Accept" {
  696. t.Errorf("Expected header Access-Control-Allow-Headers to be \"Origin, X-Requested-With, Content-Type, Accept\", %s found.", allowHeaders)
  697. }
  698. if allowMethods != "GET, POST, DELETE, PUT, OPTIONS" {
  699. t.Errorf("Expected hearder Access-Control-Allow-Methods to be \"GET, POST, DELETE, PUT, OPTIONS\", %s found.", allowMethods)
  700. }
  701. }
  702. func TestDeleteImages(t *testing.T) {
  703. eng := NewTestEngine(t)
  704. //we expect errors, so we disable stderr
  705. eng.Stderr = ioutil.Discard
  706. defer mkDaemonFromEngine(eng, t).Nuke()
  707. initialImages := getImages(eng, t, true, "")
  708. if err := eng.Job("tag", unitTestImageName, "test", "test").Run(); err != nil {
  709. t.Fatal(err)
  710. }
  711. images := getImages(eng, t, true, "")
  712. if len(images.Data[0].GetList("RepoTags")) != len(initialImages.Data[0].GetList("RepoTags"))+1 {
  713. t.Errorf("Expected %d images, %d found", len(initialImages.Data[0].GetList("RepoTags"))+1, len(images.Data[0].GetList("RepoTags")))
  714. }
  715. req, err := http.NewRequest("DELETE", "/images/"+unitTestImageID, nil)
  716. if err != nil {
  717. t.Fatal(err)
  718. }
  719. r := httptest.NewRecorder()
  720. if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  721. t.Fatal(err)
  722. }
  723. if r.Code != http.StatusConflict {
  724. t.Fatalf("Expected http status 409-conflict, got %v", r.Code)
  725. }
  726. req2, err := http.NewRequest("DELETE", "/images/test:test", nil)
  727. if err != nil {
  728. t.Fatal(err)
  729. }
  730. r2 := httptest.NewRecorder()
  731. if err := server.ServeRequest(eng, api.APIVERSION, r2, req2); err != nil {
  732. t.Fatal(err)
  733. }
  734. assertHttpNotError(r2, t)
  735. if r2.Code != http.StatusOK {
  736. t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
  737. }
  738. outs := engine.NewTable("Created", 0)
  739. if _, err := outs.ReadListFrom(r2.Body.Bytes()); err != nil {
  740. t.Fatal(err)
  741. }
  742. if len(outs.Data) != 1 {
  743. t.Fatalf("Expected %d event (untagged), got %d", 1, len(outs.Data))
  744. }
  745. images = getImages(eng, t, false, "")
  746. if images.Len() != initialImages.Len() {
  747. t.Errorf("Expected %d image, %d found", initialImages.Len(), images.Len())
  748. }
  749. }
  750. func TestPostContainersCopy(t *testing.T) {
  751. eng := NewTestEngine(t)
  752. defer mkDaemonFromEngine(eng, t).Nuke()
  753. // Create a container and remove a file
  754. containerID := createTestContainer(eng,
  755. &runconfig.Config{
  756. Image: unitTestImageID,
  757. Cmd: []string{"touch", "/test.txt"},
  758. },
  759. t,
  760. )
  761. containerRun(eng, containerID, t)
  762. r := httptest.NewRecorder()
  763. var copyData engine.Env
  764. copyData.Set("Resource", "/test.txt")
  765. copyData.Set("HostPath", ".")
  766. jsonData := bytes.NewBuffer(nil)
  767. if err := copyData.Encode(jsonData); err != nil {
  768. t.Fatal(err)
  769. }
  770. req, err := http.NewRequest("POST", "/containers/"+containerID+"/copy", jsonData)
  771. if err != nil {
  772. t.Fatal(err)
  773. }
  774. req.Header.Add("Content-Type", "application/json")
  775. if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  776. t.Fatal(err)
  777. }
  778. assertHttpNotError(r, t)
  779. if r.Code != http.StatusOK {
  780. t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
  781. }
  782. found := false
  783. for tarReader := tar.NewReader(r.Body); ; {
  784. h, err := tarReader.Next()
  785. if err != nil {
  786. if err == io.EOF {
  787. break
  788. }
  789. t.Fatal(err)
  790. }
  791. if h.Name == "test.txt" {
  792. found = true
  793. break
  794. }
  795. }
  796. if !found {
  797. t.Fatalf("The created test file has not been found in the copied output")
  798. }
  799. }
  800. func TestPostContainersCopyWhenContainerNotFound(t *testing.T) {
  801. eng := NewTestEngine(t)
  802. defer mkDaemonFromEngine(eng, t).Nuke()
  803. r := httptest.NewRecorder()
  804. var copyData engine.Env
  805. copyData.Set("Resource", "/test.txt")
  806. copyData.Set("HostPath", ".")
  807. jsonData := bytes.NewBuffer(nil)
  808. if err := copyData.Encode(jsonData); err != nil {
  809. t.Fatal(err)
  810. }
  811. req, err := http.NewRequest("POST", "/containers/id_not_found/copy", jsonData)
  812. if err != nil {
  813. t.Fatal(err)
  814. }
  815. req.Header.Add("Content-Type", "application/json")
  816. if err := server.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  817. t.Fatal(err)
  818. }
  819. if r.Code != http.StatusNotFound {
  820. t.Fatalf("404 expected for id_not_found Container, received %v", r.Code)
  821. }
  822. }
  823. // Mocked types for tests
  824. type NopConn struct {
  825. io.ReadCloser
  826. io.Writer
  827. }
  828. func (c *NopConn) LocalAddr() net.Addr { return nil }
  829. func (c *NopConn) RemoteAddr() net.Addr { return nil }
  830. func (c *NopConn) SetDeadline(t time.Time) error { return nil }
  831. func (c *NopConn) SetReadDeadline(t time.Time) error { return nil }
  832. func (c *NopConn) SetWriteDeadline(t time.Time) error { return nil }
  833. type hijackTester struct {
  834. *httptest.ResponseRecorder
  835. in io.ReadCloser
  836. out io.Writer
  837. }
  838. func (t *hijackTester) Hijack() (net.Conn, *bufio.ReadWriter, error) {
  839. bufrw := bufio.NewReadWriter(bufio.NewReader(t.in), bufio.NewWriter(t.out))
  840. conn := &NopConn{
  841. ReadCloser: t.in,
  842. Writer: t.out,
  843. }
  844. return conn, bufrw, nil
  845. }