api_test.go 31 KB

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