api_test.go 32 KB

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