api_test.go 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344
  1. package docker
  2. import (
  3. "bufio"
  4. "bytes"
  5. "code.google.com/p/go/src/pkg/archive/tar"
  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 TestSaveImageAndThenLoad(t *testing.T) {
  337. eng := NewTestEngine(t)
  338. defer mkRuntimeFromEngine(eng, t).Nuke()
  339. // save image
  340. r := httptest.NewRecorder()
  341. req, err := http.NewRequest("GET", "/images/"+unitTestImageID+"/get", nil)
  342. if err != nil {
  343. t.Fatal(err)
  344. }
  345. if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  346. t.Fatal(err)
  347. }
  348. if r.Code != http.StatusOK {
  349. t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
  350. }
  351. tarball := r.Body
  352. // delete the image
  353. r = httptest.NewRecorder()
  354. req, err = http.NewRequest("DELETE", "/images/"+unitTestImageID, nil)
  355. if err != nil {
  356. t.Fatal(err)
  357. }
  358. if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  359. t.Fatal(err)
  360. }
  361. if r.Code != http.StatusOK {
  362. t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
  363. }
  364. // make sure there is no image
  365. r = httptest.NewRecorder()
  366. req, err = http.NewRequest("GET", "/images/"+unitTestImageID+"/get", nil)
  367. if err != nil {
  368. t.Fatal(err)
  369. }
  370. if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  371. t.Fatal(err)
  372. }
  373. if r.Code != http.StatusNotFound {
  374. t.Fatalf("%d NotFound expected, received %d\n", http.StatusNotFound, r.Code)
  375. }
  376. // load the image
  377. r = httptest.NewRecorder()
  378. req, err = http.NewRequest("POST", "/images/load", tarball)
  379. if err != nil {
  380. t.Fatal(err)
  381. }
  382. if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  383. t.Fatal(err)
  384. }
  385. if r.Code != http.StatusOK {
  386. t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
  387. }
  388. // finally make sure the image is there
  389. r = httptest.NewRecorder()
  390. req, err = http.NewRequest("GET", "/images/"+unitTestImageID+"/get", nil)
  391. if err != nil {
  392. t.Fatal(err)
  393. }
  394. if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  395. t.Fatal(err)
  396. }
  397. if r.Code != http.StatusOK {
  398. t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
  399. }
  400. }
  401. func TestGetContainersChanges(t *testing.T) {
  402. eng := NewTestEngine(t)
  403. defer mkRuntimeFromEngine(eng, t).Nuke()
  404. // Create a container and remove a file
  405. containerID := createTestContainer(eng,
  406. &runconfig.Config{
  407. Image: unitTestImageID,
  408. Cmd: []string{"/bin/rm", "/etc/passwd"},
  409. },
  410. t,
  411. )
  412. containerRun(eng, containerID, t)
  413. r := httptest.NewRecorder()
  414. req, err := http.NewRequest("GET", "/containers/"+containerID+"/changes", nil)
  415. if err != nil {
  416. t.Fatal(err)
  417. }
  418. if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  419. t.Fatal(err)
  420. }
  421. assertHttpNotError(r, t)
  422. outs := engine.NewTable("", 0)
  423. if _, err := outs.ReadListFrom(r.Body.Bytes()); err != nil {
  424. t.Fatal(err)
  425. }
  426. // Check the changelog
  427. success := false
  428. for _, elem := range outs.Data {
  429. if elem.Get("Path") == "/etc/passwd" && elem.GetInt("Kind") == 2 {
  430. success = true
  431. }
  432. }
  433. if !success {
  434. t.Fatalf("/etc/passwd as been removed but is not present in the diff")
  435. }
  436. }
  437. func TestGetContainersTop(t *testing.T) {
  438. eng := NewTestEngine(t)
  439. defer mkRuntimeFromEngine(eng, t).Nuke()
  440. containerID := createTestContainer(eng,
  441. &runconfig.Config{
  442. Image: unitTestImageID,
  443. Cmd: []string{"/bin/sh", "-c", "cat"},
  444. OpenStdin: true,
  445. },
  446. t,
  447. )
  448. defer func() {
  449. // Make sure the process dies before destroying runtime
  450. containerKill(eng, containerID, t)
  451. containerWait(eng, containerID, t)
  452. }()
  453. startContainer(eng, containerID, t)
  454. setTimeout(t, "Waiting for the container to be started timed out", 10*time.Second, func() {
  455. for {
  456. if containerRunning(eng, containerID, t) {
  457. break
  458. }
  459. time.Sleep(10 * time.Millisecond)
  460. }
  461. })
  462. if !containerRunning(eng, containerID, t) {
  463. t.Fatalf("Container should be running")
  464. }
  465. // Make sure sh spawn up cat
  466. setTimeout(t, "read/write assertion timed out", 2*time.Second, func() {
  467. in, out := containerAttach(eng, containerID, t)
  468. if err := assertPipe("hello\n", "hello", out, in, 150); err != nil {
  469. t.Fatal(err)
  470. }
  471. })
  472. r := httptest.NewRecorder()
  473. req, err := http.NewRequest("GET", "/containers/"+containerID+"/top?ps_args=aux", nil)
  474. if err != nil {
  475. t.Fatal(err)
  476. }
  477. if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  478. t.Fatal(err)
  479. }
  480. assertHttpNotError(r, t)
  481. var procs engine.Env
  482. if err := procs.Decode(r.Body); err != nil {
  483. t.Fatal(err)
  484. }
  485. if len(procs.GetList("Titles")) != 11 {
  486. t.Fatalf("Expected 11 titles, found %d.", len(procs.GetList("Titles")))
  487. }
  488. if procs.GetList("Titles")[0] != "USER" || procs.GetList("Titles")[10] != "COMMAND" {
  489. 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])
  490. }
  491. processes := [][]string{}
  492. if err := procs.GetJson("Processes", &processes); err != nil {
  493. t.Fatal(err)
  494. }
  495. if len(processes) != 2 {
  496. t.Fatalf("Expected 2 processes, found %d.", len(processes))
  497. }
  498. if processes[0][10] != "/bin/sh -c cat" {
  499. t.Fatalf("Expected `/bin/sh -c cat`, found %s.", processes[0][10])
  500. }
  501. if processes[1][10] != "/bin/sh -c cat" {
  502. t.Fatalf("Expected `/bin/sh -c cat`, found %s.", processes[1][10])
  503. }
  504. }
  505. func TestGetContainersByName(t *testing.T) {
  506. eng := NewTestEngine(t)
  507. defer mkRuntimeFromEngine(eng, t).Nuke()
  508. // Create a container and remove a file
  509. containerID := createTestContainer(eng,
  510. &runconfig.Config{
  511. Image: unitTestImageID,
  512. Cmd: []string{"echo", "test"},
  513. },
  514. t,
  515. )
  516. r := httptest.NewRecorder()
  517. req, err := http.NewRequest("GET", "/containers/"+containerID+"/json", nil)
  518. if err != nil {
  519. t.Fatal(err)
  520. }
  521. if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  522. t.Fatal(err)
  523. }
  524. assertHttpNotError(r, t)
  525. outContainer := &docker.Container{}
  526. if err := json.Unmarshal(r.Body.Bytes(), outContainer); err != nil {
  527. t.Fatal(err)
  528. }
  529. if outContainer.ID != containerID {
  530. t.Fatalf("Wrong containers retrieved. Expected %s, received %s", containerID, outContainer.ID)
  531. }
  532. }
  533. func TestPostCommit(t *testing.T) {
  534. eng := NewTestEngine(t)
  535. defer mkRuntimeFromEngine(eng, t).Nuke()
  536. srv := mkServerFromEngine(eng, t)
  537. // Create a container and remove a file
  538. containerID := createTestContainer(eng,
  539. &runconfig.Config{
  540. Image: unitTestImageID,
  541. Cmd: []string{"touch", "/test"},
  542. },
  543. t,
  544. )
  545. containerRun(eng, containerID, t)
  546. req, err := http.NewRequest("POST", "/commit?repo=testrepo&testtag=tag&container="+containerID, bytes.NewReader([]byte{}))
  547. if err != nil {
  548. t.Fatal(err)
  549. }
  550. r := httptest.NewRecorder()
  551. if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  552. t.Fatal(err)
  553. }
  554. assertHttpNotError(r, t)
  555. if r.Code != http.StatusCreated {
  556. t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code)
  557. }
  558. var env engine.Env
  559. if err := env.Decode(r.Body); err != nil {
  560. t.Fatal(err)
  561. }
  562. if _, err := srv.ImageInspect(env.Get("Id")); err != nil {
  563. t.Fatalf("The image has not been committed")
  564. }
  565. }
  566. func TestPostContainersCreate(t *testing.T) {
  567. eng := NewTestEngine(t)
  568. defer mkRuntimeFromEngine(eng, t).Nuke()
  569. configJSON, err := json.Marshal(&runconfig.Config{
  570. Image: unitTestImageID,
  571. Memory: 33554432,
  572. Cmd: []string{"touch", "/test"},
  573. })
  574. if err != nil {
  575. t.Fatal(err)
  576. }
  577. req, err := http.NewRequest("POST", "/containers/create", bytes.NewReader(configJSON))
  578. if err != nil {
  579. t.Fatal(err)
  580. }
  581. r := httptest.NewRecorder()
  582. if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  583. t.Fatal(err)
  584. }
  585. assertHttpNotError(r, t)
  586. if r.Code != http.StatusCreated {
  587. t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code)
  588. }
  589. var apiRun engine.Env
  590. if err := apiRun.Decode(r.Body); err != nil {
  591. t.Fatal(err)
  592. }
  593. containerID := apiRun.Get("Id")
  594. containerAssertExists(eng, containerID, t)
  595. containerRun(eng, containerID, t)
  596. if !containerFileExists(eng, containerID, "test", t) {
  597. t.Fatal("Test file was not created")
  598. }
  599. }
  600. func TestPostContainersKill(t *testing.T) {
  601. eng := NewTestEngine(t)
  602. defer mkRuntimeFromEngine(eng, t).Nuke()
  603. containerID := createTestContainer(eng,
  604. &runconfig.Config{
  605. Image: unitTestImageID,
  606. Cmd: []string{"/bin/cat"},
  607. OpenStdin: true,
  608. },
  609. t,
  610. )
  611. startContainer(eng, containerID, t)
  612. // Give some time to the process to start
  613. containerWaitTimeout(eng, containerID, t)
  614. if !containerRunning(eng, containerID, t) {
  615. t.Errorf("Container should be running")
  616. }
  617. r := httptest.NewRecorder()
  618. req, err := http.NewRequest("POST", "/containers/"+containerID+"/kill", bytes.NewReader([]byte{}))
  619. if err != nil {
  620. t.Fatal(err)
  621. }
  622. if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  623. t.Fatal(err)
  624. }
  625. assertHttpNotError(r, t)
  626. if r.Code != http.StatusNoContent {
  627. t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
  628. }
  629. if containerRunning(eng, containerID, t) {
  630. t.Fatalf("The container hasn't been killed")
  631. }
  632. }
  633. func TestPostContainersRestart(t *testing.T) {
  634. eng := NewTestEngine(t)
  635. defer mkRuntimeFromEngine(eng, t).Nuke()
  636. containerID := createTestContainer(eng,
  637. &runconfig.Config{
  638. Image: unitTestImageID,
  639. Cmd: []string{"/bin/top"},
  640. OpenStdin: true,
  641. },
  642. t,
  643. )
  644. startContainer(eng, containerID, t)
  645. // Give some time to the process to start
  646. containerWaitTimeout(eng, containerID, t)
  647. if !containerRunning(eng, containerID, t) {
  648. t.Errorf("Container should be running")
  649. }
  650. req, err := http.NewRequest("POST", "/containers/"+containerID+"/restart?t=1", bytes.NewReader([]byte{}))
  651. if err != nil {
  652. t.Fatal(err)
  653. }
  654. r := httptest.NewRecorder()
  655. if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  656. t.Fatal(err)
  657. }
  658. assertHttpNotError(r, t)
  659. if r.Code != http.StatusNoContent {
  660. t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
  661. }
  662. // Give some time to the process to restart
  663. containerWaitTimeout(eng, containerID, t)
  664. if !containerRunning(eng, containerID, t) {
  665. t.Fatalf("Container should be running")
  666. }
  667. containerKill(eng, containerID, t)
  668. }
  669. func TestPostContainersStart(t *testing.T) {
  670. eng := NewTestEngine(t)
  671. defer mkRuntimeFromEngine(eng, t).Nuke()
  672. containerID := createTestContainer(
  673. eng,
  674. &runconfig.Config{
  675. Image: unitTestImageID,
  676. Cmd: []string{"/bin/cat"},
  677. OpenStdin: true,
  678. },
  679. t,
  680. )
  681. hostConfigJSON, err := json.Marshal(&runconfig.HostConfig{})
  682. req, err := http.NewRequest("POST", "/containers/"+containerID+"/start", bytes.NewReader(hostConfigJSON))
  683. if err != nil {
  684. t.Fatal(err)
  685. }
  686. req.Header.Set("Content-Type", "application/json")
  687. r := httptest.NewRecorder()
  688. if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  689. t.Fatal(err)
  690. }
  691. assertHttpNotError(r, t)
  692. if r.Code != http.StatusNoContent {
  693. t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
  694. }
  695. containerAssertExists(eng, containerID, t)
  696. // Give some time to the process to start
  697. // FIXME: use Wait once it's available as a job
  698. containerWaitTimeout(eng, containerID, t)
  699. if !containerRunning(eng, containerID, t) {
  700. t.Errorf("Container should be running")
  701. }
  702. r = httptest.NewRecorder()
  703. if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  704. t.Fatal(err)
  705. }
  706. // Starting an already started container should return an error
  707. // FIXME: verify a precise error code. There is a possible bug here
  708. // which causes this to return 404 even though the container exists.
  709. assertHttpError(r, t)
  710. containerAssertExists(eng, containerID, t)
  711. containerKill(eng, containerID, t)
  712. }
  713. // Expected behaviour: using / as a bind mount source should throw an error
  714. func TestRunErrorBindMountRootSource(t *testing.T) {
  715. eng := NewTestEngine(t)
  716. defer mkRuntimeFromEngine(eng, t).Nuke()
  717. containerID := createTestContainer(
  718. eng,
  719. &runconfig.Config{
  720. Image: unitTestImageID,
  721. Cmd: []string{"/bin/cat"},
  722. OpenStdin: true,
  723. },
  724. t,
  725. )
  726. hostConfigJSON, err := json.Marshal(&runconfig.HostConfig{
  727. Binds: []string{"/:/tmp"},
  728. })
  729. req, err := http.NewRequest("POST", "/containers/"+containerID+"/start", bytes.NewReader(hostConfigJSON))
  730. if err != nil {
  731. t.Fatal(err)
  732. }
  733. req.Header.Set("Content-Type", "application/json")
  734. r := httptest.NewRecorder()
  735. if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  736. t.Fatal(err)
  737. }
  738. if r.Code != http.StatusInternalServerError {
  739. containerKill(eng, containerID, t)
  740. t.Fatal("should have failed to run when using / as a source for the bind mount")
  741. }
  742. }
  743. func TestPostContainersStop(t *testing.T) {
  744. eng := NewTestEngine(t)
  745. defer mkRuntimeFromEngine(eng, t).Nuke()
  746. containerID := createTestContainer(eng,
  747. &runconfig.Config{
  748. Image: unitTestImageID,
  749. Cmd: []string{"/bin/top"},
  750. OpenStdin: true,
  751. },
  752. t,
  753. )
  754. startContainer(eng, containerID, t)
  755. // Give some time to the process to start
  756. containerWaitTimeout(eng, containerID, t)
  757. if !containerRunning(eng, containerID, t) {
  758. t.Errorf("Container should be running")
  759. }
  760. // Note: as it is a POST request, it requires a body.
  761. req, err := http.NewRequest("POST", "/containers/"+containerID+"/stop?t=1", bytes.NewReader([]byte{}))
  762. if err != nil {
  763. t.Fatal(err)
  764. }
  765. r := httptest.NewRecorder()
  766. if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  767. t.Fatal(err)
  768. }
  769. assertHttpNotError(r, t)
  770. if r.Code != http.StatusNoContent {
  771. t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
  772. }
  773. if containerRunning(eng, containerID, t) {
  774. t.Fatalf("The container hasn't been stopped")
  775. }
  776. }
  777. func TestPostContainersWait(t *testing.T) {
  778. eng := NewTestEngine(t)
  779. defer mkRuntimeFromEngine(eng, t).Nuke()
  780. containerID := createTestContainer(eng,
  781. &runconfig.Config{
  782. Image: unitTestImageID,
  783. Cmd: []string{"/bin/sleep", "1"},
  784. OpenStdin: true,
  785. },
  786. t,
  787. )
  788. startContainer(eng, containerID, t)
  789. setTimeout(t, "Wait timed out", 3*time.Second, func() {
  790. r := httptest.NewRecorder()
  791. req, err := http.NewRequest("POST", "/containers/"+containerID+"/wait", bytes.NewReader([]byte{}))
  792. if err != nil {
  793. t.Fatal(err)
  794. }
  795. if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  796. t.Fatal(err)
  797. }
  798. assertHttpNotError(r, t)
  799. var apiWait engine.Env
  800. if err := apiWait.Decode(r.Body); err != nil {
  801. t.Fatal(err)
  802. }
  803. if apiWait.GetInt("StatusCode") != 0 {
  804. t.Fatalf("Non zero exit code for sleep: %d\n", apiWait.GetInt("StatusCode"))
  805. }
  806. })
  807. if containerRunning(eng, containerID, t) {
  808. t.Fatalf("The container should be stopped after wait")
  809. }
  810. }
  811. func TestPostContainersAttach(t *testing.T) {
  812. eng := NewTestEngine(t)
  813. defer mkRuntimeFromEngine(eng, t).Nuke()
  814. containerID := createTestContainer(eng,
  815. &runconfig.Config{
  816. Image: unitTestImageID,
  817. Cmd: []string{"/bin/cat"},
  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 := api.ServeRequest(eng, api.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{1, 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. func TestPostContainersAttachStderr(t *testing.T) {
  876. eng := NewTestEngine(t)
  877. defer mkRuntimeFromEngine(eng, t).Nuke()
  878. containerID := createTestContainer(eng,
  879. &runconfig.Config{
  880. Image: unitTestImageID,
  881. Cmd: []string{"/bin/sh", "-c", "/bin/cat >&2"},
  882. OpenStdin: true,
  883. },
  884. t,
  885. )
  886. // Start the process
  887. startContainer(eng, containerID, t)
  888. stdin, stdinPipe := io.Pipe()
  889. stdout, stdoutPipe := io.Pipe()
  890. // Try to avoid the timeout in destroy. Best effort, don't check error
  891. defer func() {
  892. closeWrap(stdin, stdinPipe, stdout, stdoutPipe)
  893. containerKill(eng, containerID, t)
  894. }()
  895. // Attach to it
  896. c1 := make(chan struct{})
  897. go func() {
  898. defer close(c1)
  899. r := &hijackTester{
  900. ResponseRecorder: httptest.NewRecorder(),
  901. in: stdin,
  902. out: stdoutPipe,
  903. }
  904. req, err := http.NewRequest("POST", "/containers/"+containerID+"/attach?stream=1&stdin=1&stdout=1&stderr=1", bytes.NewReader([]byte{}))
  905. if err != nil {
  906. t.Fatal(err)
  907. }
  908. if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  909. t.Fatal(err)
  910. }
  911. assertHttpNotError(r.ResponseRecorder, t)
  912. }()
  913. // Acknowledge hijack
  914. setTimeout(t, "hijack acknowledge timed out", 2*time.Second, func() {
  915. stdout.Read([]byte{})
  916. stdout.Read(make([]byte, 4096))
  917. })
  918. setTimeout(t, "read/write assertion timed out", 2*time.Second, func() {
  919. if err := assertPipe("hello\n", string([]byte{2, 0, 0, 0, 0, 0, 0, 6})+"hello", stdout, stdinPipe, 150); err != nil {
  920. t.Fatal(err)
  921. }
  922. })
  923. // Close pipes (client disconnects)
  924. if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
  925. t.Fatal(err)
  926. }
  927. // Wait for attach to finish, the client disconnected, therefore, Attach finished his job
  928. setTimeout(t, "Waiting for CmdAttach timed out", 10*time.Second, func() {
  929. <-c1
  930. })
  931. // We closed stdin, expect /bin/cat to still be running
  932. // Wait a little bit to make sure container.monitor() did his thing
  933. containerWaitTimeout(eng, containerID, t)
  934. // Try to avoid the timeout in destroy. Best effort, don't check error
  935. cStdin, _ := containerAttach(eng, containerID, t)
  936. cStdin.Close()
  937. containerWait(eng, containerID, t)
  938. }
  939. // FIXME: Test deleting running container
  940. // FIXME: Test deleting container with volume
  941. // FIXME: Test deleting volume in use by other container
  942. func TestDeleteContainers(t *testing.T) {
  943. eng := NewTestEngine(t)
  944. defer mkRuntimeFromEngine(eng, t).Nuke()
  945. containerID := createTestContainer(eng,
  946. &runconfig.Config{
  947. Image: unitTestImageID,
  948. Cmd: []string{"touch", "/test"},
  949. },
  950. t,
  951. )
  952. req, err := http.NewRequest("DELETE", "/containers/"+containerID, nil)
  953. if err != nil {
  954. t.Fatal(err)
  955. }
  956. r := httptest.NewRecorder()
  957. if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  958. t.Fatal(err)
  959. }
  960. assertHttpNotError(r, t)
  961. if r.Code != http.StatusNoContent {
  962. t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
  963. }
  964. containerAssertNotExists(eng, containerID, t)
  965. }
  966. func TestOptionsRoute(t *testing.T) {
  967. eng := NewTestEngine(t)
  968. defer mkRuntimeFromEngine(eng, t).Nuke()
  969. r := httptest.NewRecorder()
  970. req, err := http.NewRequest("OPTIONS", "/", nil)
  971. if err != nil {
  972. t.Fatal(err)
  973. }
  974. if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  975. t.Fatal(err)
  976. }
  977. assertHttpNotError(r, t)
  978. if r.Code != http.StatusOK {
  979. t.Errorf("Expected response for OPTIONS request to be \"200\", %v found.", r.Code)
  980. }
  981. }
  982. func TestGetEnabledCors(t *testing.T) {
  983. eng := NewTestEngine(t)
  984. defer mkRuntimeFromEngine(eng, t).Nuke()
  985. r := httptest.NewRecorder()
  986. req, err := http.NewRequest("GET", "/version", nil)
  987. if err != nil {
  988. t.Fatal(err)
  989. }
  990. if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  991. t.Fatal(err)
  992. }
  993. assertHttpNotError(r, t)
  994. if r.Code != http.StatusOK {
  995. t.Errorf("Expected response for OPTIONS request to be \"200\", %v found.", r.Code)
  996. }
  997. allowOrigin := r.Header().Get("Access-Control-Allow-Origin")
  998. allowHeaders := r.Header().Get("Access-Control-Allow-Headers")
  999. allowMethods := r.Header().Get("Access-Control-Allow-Methods")
  1000. if allowOrigin != "*" {
  1001. t.Errorf("Expected header Access-Control-Allow-Origin to be \"*\", %s found.", allowOrigin)
  1002. }
  1003. if allowHeaders != "Origin, X-Requested-With, Content-Type, Accept" {
  1004. t.Errorf("Expected header Access-Control-Allow-Headers to be \"Origin, X-Requested-With, Content-Type, Accept\", %s found.", allowHeaders)
  1005. }
  1006. if allowMethods != "GET, POST, DELETE, PUT, OPTIONS" {
  1007. t.Errorf("Expected hearder Access-Control-Allow-Methods to be \"GET, POST, DELETE, PUT, OPTIONS\", %s found.", allowMethods)
  1008. }
  1009. }
  1010. func TestDeleteImages(t *testing.T) {
  1011. eng := NewTestEngine(t)
  1012. defer mkRuntimeFromEngine(eng, t).Nuke()
  1013. initialImages := getImages(eng, t, true, "")
  1014. if err := eng.Job("tag", unitTestImageName, "test", "test").Run(); err != nil {
  1015. t.Fatal(err)
  1016. }
  1017. images := getImages(eng, t, true, "")
  1018. if len(images.Data[0].GetList("RepoTags")) != len(initialImages.Data[0].GetList("RepoTags"))+1 {
  1019. t.Errorf("Expected %d images, %d found", len(initialImages.Data[0].GetList("RepoTags"))+1, len(images.Data[0].GetList("RepoTags")))
  1020. }
  1021. req, err := http.NewRequest("DELETE", "/images/"+unitTestImageID, nil)
  1022. if err != nil {
  1023. t.Fatal(err)
  1024. }
  1025. r := httptest.NewRecorder()
  1026. if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  1027. t.Fatal(err)
  1028. }
  1029. if r.Code != http.StatusConflict {
  1030. t.Fatalf("Expected http status 409-conflict, got %v", r.Code)
  1031. }
  1032. req2, err := http.NewRequest("DELETE", "/images/test:test", nil)
  1033. if err != nil {
  1034. t.Fatal(err)
  1035. }
  1036. r2 := httptest.NewRecorder()
  1037. if err := api.ServeRequest(eng, api.APIVERSION, r2, req2); err != nil {
  1038. t.Fatal(err)
  1039. }
  1040. assertHttpNotError(r2, t)
  1041. if r2.Code != http.StatusOK {
  1042. t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
  1043. }
  1044. outs := engine.NewTable("Created", 0)
  1045. if _, err := outs.ReadListFrom(r2.Body.Bytes()); err != nil {
  1046. t.Fatal(err)
  1047. }
  1048. if len(outs.Data) != 1 {
  1049. t.Fatalf("Expected %d event (untagged), got %d", 1, len(outs.Data))
  1050. }
  1051. images = getImages(eng, t, false, "")
  1052. if images.Len() != initialImages.Len() {
  1053. t.Errorf("Expected %d image, %d found", initialImages.Len(), images.Len())
  1054. }
  1055. }
  1056. func TestPostContainersCopy(t *testing.T) {
  1057. eng := NewTestEngine(t)
  1058. defer mkRuntimeFromEngine(eng, t).Nuke()
  1059. // Create a container and remove a file
  1060. containerID := createTestContainer(eng,
  1061. &runconfig.Config{
  1062. Image: unitTestImageID,
  1063. Cmd: []string{"touch", "/test.txt"},
  1064. },
  1065. t,
  1066. )
  1067. containerRun(eng, containerID, t)
  1068. r := httptest.NewRecorder()
  1069. var copyData engine.Env
  1070. copyData.Set("Resource", "/test.txt")
  1071. copyData.Set("HostPath", ".")
  1072. jsonData := bytes.NewBuffer(nil)
  1073. if err := copyData.Encode(jsonData); err != nil {
  1074. t.Fatal(err)
  1075. }
  1076. req, err := http.NewRequest("POST", "/containers/"+containerID+"/copy", jsonData)
  1077. if err != nil {
  1078. t.Fatal(err)
  1079. }
  1080. req.Header.Add("Content-Type", "application/json")
  1081. if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  1082. t.Fatal(err)
  1083. }
  1084. assertHttpNotError(r, t)
  1085. if r.Code != http.StatusOK {
  1086. t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
  1087. }
  1088. found := false
  1089. for tarReader := tar.NewReader(r.Body); ; {
  1090. h, err := tarReader.Next()
  1091. if err != nil {
  1092. if err == io.EOF {
  1093. break
  1094. }
  1095. t.Fatal(err)
  1096. }
  1097. if h.Name == "test.txt" {
  1098. found = true
  1099. break
  1100. }
  1101. }
  1102. if !found {
  1103. t.Fatalf("The created test file has not been found in the copied output")
  1104. }
  1105. }
  1106. func TestPostContainersCopyWhenContainerNotFound(t *testing.T) {
  1107. eng := NewTestEngine(t)
  1108. defer mkRuntimeFromEngine(eng, t).Nuke()
  1109. r := httptest.NewRecorder()
  1110. var copyData engine.Env
  1111. copyData.Set("Resource", "/test.txt")
  1112. copyData.Set("HostPath", ".")
  1113. jsonData := bytes.NewBuffer(nil)
  1114. if err := copyData.Encode(jsonData); err != nil {
  1115. t.Fatal(err)
  1116. }
  1117. req, err := http.NewRequest("POST", "/containers/id_not_found/copy", jsonData)
  1118. if err != nil {
  1119. t.Fatal(err)
  1120. }
  1121. req.Header.Add("Content-Type", "application/json")
  1122. if err := api.ServeRequest(eng, api.APIVERSION, r, req); err != nil {
  1123. t.Fatal(err)
  1124. }
  1125. if r.Code != http.StatusNotFound {
  1126. t.Fatalf("404 expected for id_not_found Container, received %v", r.Code)
  1127. }
  1128. }
  1129. // Mocked types for tests
  1130. type NopConn struct {
  1131. io.ReadCloser
  1132. io.Writer
  1133. }
  1134. func (c *NopConn) LocalAddr() net.Addr { return nil }
  1135. func (c *NopConn) RemoteAddr() net.Addr { return nil }
  1136. func (c *NopConn) SetDeadline(t time.Time) error { return nil }
  1137. func (c *NopConn) SetReadDeadline(t time.Time) error { return nil }
  1138. func (c *NopConn) SetWriteDeadline(t time.Time) error { return nil }
  1139. type hijackTester struct {
  1140. *httptest.ResponseRecorder
  1141. in io.ReadCloser
  1142. out io.Writer
  1143. }
  1144. func (t *hijackTester) Hijack() (net.Conn, *bufio.ReadWriter, error) {
  1145. bufrw := bufio.NewReadWriter(bufio.NewReader(t.in), bufio.NewWriter(t.out))
  1146. conn := &NopConn{
  1147. ReadCloser: t.in,
  1148. Writer: t.out,
  1149. }
  1150. return conn, bufrw, nil
  1151. }