api_test.go 31 KB

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