api_test.go 27 KB

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