api_test.go 28 KB

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