api_test.go 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991
  1. package docker
  2. import (
  3. "bufio"
  4. "bytes"
  5. "encoding/json"
  6. "fmt"
  7. "io"
  8. "io/ioutil"
  9. "net"
  10. "net/http"
  11. "net/http/httptest"
  12. "strings"
  13. "testing"
  14. "time"
  15. "github.com/docker/docker/api"
  16. "github.com/docker/docker/api/server"
  17. "github.com/docker/docker/builder"
  18. "github.com/docker/docker/engine"
  19. "github.com/docker/docker/runconfig"
  20. "github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
  21. )
  22. func TestSaveImageAndThenLoad(t *testing.T) {
  23. eng := NewTestEngine(t)
  24. defer mkDaemonFromEngine(eng, t).Nuke()
  25. // save image
  26. r := httptest.NewRecorder()
  27. req, err := http.NewRequest("GET", "/images/"+unitTestImageID+"/get", nil)
  28. if err != nil {
  29. t.Fatal(err)
  30. }
  31. server.ServeRequest(eng, api.APIVERSION, r, req)
  32. if r.Code != http.StatusOK {
  33. t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
  34. }
  35. tarball := r.Body
  36. // delete the image
  37. r = httptest.NewRecorder()
  38. req, err = http.NewRequest("DELETE", "/images/"+unitTestImageID, nil)
  39. if err != nil {
  40. t.Fatal(err)
  41. }
  42. server.ServeRequest(eng, api.APIVERSION, r, req)
  43. if r.Code != http.StatusOK {
  44. t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
  45. }
  46. // make sure there is no image
  47. r = httptest.NewRecorder()
  48. req, err = http.NewRequest("GET", "/images/"+unitTestImageID+"/get", nil)
  49. if err != nil {
  50. t.Fatal(err)
  51. }
  52. server.ServeRequest(eng, api.APIVERSION, r, req)
  53. if r.Code != http.StatusNotFound {
  54. t.Fatalf("%d NotFound expected, received %d\n", http.StatusNotFound, r.Code)
  55. }
  56. // load the image
  57. r = httptest.NewRecorder()
  58. req, err = http.NewRequest("POST", "/images/load", tarball)
  59. if err != nil {
  60. t.Fatal(err)
  61. }
  62. server.ServeRequest(eng, api.APIVERSION, r, req)
  63. if r.Code != http.StatusOK {
  64. t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
  65. }
  66. // finally make sure the image is there
  67. r = httptest.NewRecorder()
  68. req, err = http.NewRequest("GET", "/images/"+unitTestImageID+"/get", nil)
  69. if err != nil {
  70. t.Fatal(err)
  71. }
  72. server.ServeRequest(eng, api.APIVERSION, r, req)
  73. if r.Code != http.StatusOK {
  74. t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
  75. }
  76. }
  77. func TestGetContainersTop(t *testing.T) {
  78. eng := NewTestEngine(t)
  79. defer mkDaemonFromEngine(eng, t).Nuke()
  80. containerID := createTestContainer(eng,
  81. &runconfig.Config{
  82. Image: unitTestImageID,
  83. Cmd: []string{"/bin/sh", "-c", "cat"},
  84. OpenStdin: true,
  85. },
  86. t,
  87. )
  88. defer func() {
  89. // Make sure the process dies before destroying daemon
  90. containerKill(eng, containerID, t)
  91. containerWait(eng, containerID, t)
  92. }()
  93. startContainer(eng, containerID, t)
  94. setTimeout(t, "Waiting for the container to be started timed out", 10*time.Second, func() {
  95. for {
  96. if containerRunning(eng, containerID, t) {
  97. break
  98. }
  99. time.Sleep(10 * time.Millisecond)
  100. }
  101. })
  102. if !containerRunning(eng, containerID, t) {
  103. t.Fatalf("Container should be running")
  104. }
  105. // Make sure sh spawn up cat
  106. setTimeout(t, "read/write assertion timed out", 2*time.Second, func() {
  107. in, out := containerAttach(eng, containerID, t)
  108. if err := assertPipe("hello\n", "hello", out, in, 150); err != nil {
  109. t.Fatal(err)
  110. }
  111. })
  112. r := httptest.NewRecorder()
  113. req, err := http.NewRequest("GET", "/containers/"+containerID+"/top?ps_args=aux", nil)
  114. if err != nil {
  115. t.Fatal(err)
  116. }
  117. server.ServeRequest(eng, api.APIVERSION, r, req)
  118. assertHttpNotError(r, t)
  119. var procs engine.Env
  120. if err := procs.Decode(r.Body); err != nil {
  121. t.Fatal(err)
  122. }
  123. if len(procs.GetList("Titles")) != 11 {
  124. t.Fatalf("Expected 11 titles, found %d.", len(procs.GetList("Titles")))
  125. }
  126. if procs.GetList("Titles")[0] != "USER" || procs.GetList("Titles")[10] != "COMMAND" {
  127. 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])
  128. }
  129. processes := [][]string{}
  130. if err := procs.GetJson("Processes", &processes); err != nil {
  131. t.Fatal(err)
  132. }
  133. if len(processes) != 2 {
  134. t.Fatalf("Expected 2 processes, found %d.", len(processes))
  135. }
  136. if processes[0][10] != "/bin/sh -c cat" {
  137. t.Fatalf("Expected `/bin/sh -c cat`, found %s.", processes[0][10])
  138. }
  139. if processes[1][10] != "/bin/sh -c cat" {
  140. t.Fatalf("Expected `/bin/sh -c cat`, found %s.", processes[1][10])
  141. }
  142. }
  143. func TestPostCommit(t *testing.T) {
  144. eng := NewTestEngine(t)
  145. b := &builder.BuilderJob{Engine: eng}
  146. b.Install()
  147. defer mkDaemonFromEngine(eng, t).Nuke()
  148. // Create a container and remove a file
  149. containerID := createTestContainer(eng,
  150. &runconfig.Config{
  151. Image: unitTestImageID,
  152. Cmd: []string{"touch", "/test"},
  153. },
  154. t,
  155. )
  156. containerRun(eng, containerID, t)
  157. req, err := http.NewRequest("POST", "/commit?repo=testrepo&testtag=tag&container="+containerID, bytes.NewReader([]byte{}))
  158. if err != nil {
  159. t.Fatal(err)
  160. }
  161. r := httptest.NewRecorder()
  162. server.ServeRequest(eng, api.APIVERSION, r, req)
  163. assertHttpNotError(r, t)
  164. if r.Code != http.StatusCreated {
  165. t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code)
  166. }
  167. var env engine.Env
  168. if err := env.Decode(r.Body); err != nil {
  169. t.Fatal(err)
  170. }
  171. if err := eng.Job("image_inspect", env.Get("Id")).Run(); err != nil {
  172. t.Fatalf("The image has not been committed")
  173. }
  174. }
  175. func TestPostContainersCreate(t *testing.T) {
  176. eng := NewTestEngine(t)
  177. defer mkDaemonFromEngine(eng, t).Nuke()
  178. configJSON, err := json.Marshal(&runconfig.Config{
  179. Image: unitTestImageID,
  180. Memory: 33554432,
  181. Cmd: []string{"touch", "/test"},
  182. })
  183. if err != nil {
  184. t.Fatal(err)
  185. }
  186. req, err := http.NewRequest("POST", "/containers/create", bytes.NewReader(configJSON))
  187. if err != nil {
  188. t.Fatal(err)
  189. }
  190. req.Header.Set("Content-Type", "application/json")
  191. r := httptest.NewRecorder()
  192. server.ServeRequest(eng, api.APIVERSION, r, req)
  193. assertHttpNotError(r, t)
  194. if r.Code != http.StatusCreated {
  195. t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code)
  196. }
  197. var apiRun engine.Env
  198. if err := apiRun.Decode(r.Body); err != nil {
  199. t.Fatal(err)
  200. }
  201. containerID := apiRun.Get("Id")
  202. containerAssertExists(eng, containerID, t)
  203. containerRun(eng, containerID, t)
  204. if !containerFileExists(eng, containerID, "test", t) {
  205. t.Fatal("Test file was not created")
  206. }
  207. }
  208. func TestPostJsonVerify(t *testing.T) {
  209. eng := NewTestEngine(t)
  210. defer mkDaemonFromEngine(eng, t).Nuke()
  211. configJSON, err := json.Marshal(&runconfig.Config{
  212. Image: unitTestImageID,
  213. Memory: 33554432,
  214. Cmd: []string{"touch", "/test"},
  215. })
  216. if err != nil {
  217. t.Fatal(err)
  218. }
  219. req, err := http.NewRequest("POST", "/containers/create", bytes.NewReader(configJSON))
  220. if err != nil {
  221. t.Fatal(err)
  222. }
  223. r := httptest.NewRecorder()
  224. server.ServeRequest(eng, api.APIVERSION, r, req)
  225. // Don't add Content-Type header
  226. // req.Header.Set("Content-Type", "application/json")
  227. server.ServeRequest(eng, api.APIVERSION, r, req)
  228. if r.Code != http.StatusInternalServerError || !strings.Contains(((*r.Body).String()), "application/json") {
  229. t.Fatal("Create should have failed due to no Content-Type header - got:", r)
  230. }
  231. // Now add header but with wrong type and retest
  232. req.Header.Set("Content-Type", "application/xml")
  233. server.ServeRequest(eng, api.APIVERSION, r, req)
  234. if r.Code != http.StatusInternalServerError || !strings.Contains(((*r.Body).String()), "application/json") {
  235. t.Fatal("Create should have failed due to wrong Content-Type header - got:", r)
  236. }
  237. }
  238. // Issue 7941 - test to make sure a "null" in JSON is just ignored.
  239. // W/o this fix a null in JSON would be parsed into a string var as "null"
  240. func TestPostCreateNull(t *testing.T) {
  241. eng := NewTestEngine(t)
  242. daemon := mkDaemonFromEngine(eng, t)
  243. defer daemon.Nuke()
  244. configStr := fmt.Sprintf(`{
  245. "Hostname":"",
  246. "Domainname":"",
  247. "Memory":0,
  248. "MemorySwap":0,
  249. "CpuShares":0,
  250. "Cpuset":null,
  251. "AttachStdin":true,
  252. "AttachStdout":true,
  253. "AttachStderr":true,
  254. "PortSpecs":null,
  255. "ExposedPorts":{},
  256. "Tty":true,
  257. "OpenStdin":true,
  258. "StdinOnce":true,
  259. "Env":[],
  260. "Cmd":"ls",
  261. "Image":"%s",
  262. "Volumes":{},
  263. "WorkingDir":"",
  264. "Entrypoint":null,
  265. "NetworkDisabled":false,
  266. "OnBuild":null}`, unitTestImageID)
  267. req, err := http.NewRequest("POST", "/containers/create", strings.NewReader(configStr))
  268. if err != nil {
  269. t.Fatal(err)
  270. }
  271. req.Header.Set("Content-Type", "application/json")
  272. r := httptest.NewRecorder()
  273. server.ServeRequest(eng, api.APIVERSION, r, req)
  274. assertHttpNotError(r, t)
  275. if r.Code != http.StatusCreated {
  276. t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code)
  277. }
  278. var apiRun engine.Env
  279. if err := apiRun.Decode(r.Body); err != nil {
  280. t.Fatal(err)
  281. }
  282. containerID := apiRun.Get("Id")
  283. containerAssertExists(eng, containerID, t)
  284. c, _ := daemon.Get(containerID)
  285. if c.Config.Cpuset != "" {
  286. t.Fatalf("Cpuset should have been empty - instead its:" + c.Config.Cpuset)
  287. }
  288. }
  289. func TestPostContainersKill(t *testing.T) {
  290. eng := NewTestEngine(t)
  291. defer mkDaemonFromEngine(eng, t).Nuke()
  292. containerID := createTestContainer(eng,
  293. &runconfig.Config{
  294. Image: unitTestImageID,
  295. Cmd: []string{"/bin/cat"},
  296. OpenStdin: true,
  297. },
  298. t,
  299. )
  300. startContainer(eng, containerID, t)
  301. // Give some time to the process to start
  302. containerWaitTimeout(eng, containerID, t)
  303. if !containerRunning(eng, containerID, t) {
  304. t.Errorf("Container should be running")
  305. }
  306. r := httptest.NewRecorder()
  307. req, err := http.NewRequest("POST", "/containers/"+containerID+"/kill", bytes.NewReader([]byte{}))
  308. if err != nil {
  309. t.Fatal(err)
  310. }
  311. server.ServeRequest(eng, api.APIVERSION, r, req)
  312. assertHttpNotError(r, t)
  313. if r.Code != http.StatusNoContent {
  314. t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
  315. }
  316. if containerRunning(eng, containerID, t) {
  317. t.Fatalf("The container hasn't been killed")
  318. }
  319. }
  320. func TestPostContainersRestart(t *testing.T) {
  321. eng := NewTestEngine(t)
  322. defer mkDaemonFromEngine(eng, t).Nuke()
  323. containerID := createTestContainer(eng,
  324. &runconfig.Config{
  325. Image: unitTestImageID,
  326. Cmd: []string{"/bin/top"},
  327. OpenStdin: true,
  328. },
  329. t,
  330. )
  331. startContainer(eng, containerID, t)
  332. // Give some time to the process to start
  333. containerWaitTimeout(eng, containerID, t)
  334. if !containerRunning(eng, containerID, t) {
  335. t.Errorf("Container should be running")
  336. }
  337. req, err := http.NewRequest("POST", "/containers/"+containerID+"/restart?t=1", bytes.NewReader([]byte{}))
  338. if err != nil {
  339. t.Fatal(err)
  340. }
  341. r := httptest.NewRecorder()
  342. server.ServeRequest(eng, api.APIVERSION, r, req)
  343. assertHttpNotError(r, t)
  344. if r.Code != http.StatusNoContent {
  345. t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
  346. }
  347. // Give some time to the process to restart
  348. containerWaitTimeout(eng, containerID, t)
  349. if !containerRunning(eng, containerID, t) {
  350. t.Fatalf("Container should be running")
  351. }
  352. containerKill(eng, containerID, t)
  353. }
  354. func TestPostContainersStart(t *testing.T) {
  355. eng := NewTestEngine(t)
  356. defer mkDaemonFromEngine(eng, t).Nuke()
  357. containerID := createTestContainer(
  358. eng,
  359. &runconfig.Config{
  360. Image: unitTestImageID,
  361. Cmd: []string{"/bin/cat"},
  362. OpenStdin: true,
  363. },
  364. t,
  365. )
  366. hostConfigJSON, err := json.Marshal(&runconfig.HostConfig{})
  367. req, err := http.NewRequest("POST", "/containers/"+containerID+"/start", bytes.NewReader(hostConfigJSON))
  368. if err != nil {
  369. t.Fatal(err)
  370. }
  371. req.Header.Set("Content-Type", "application/json")
  372. r := httptest.NewRecorder()
  373. server.ServeRequest(eng, api.APIVERSION, r, req)
  374. assertHttpNotError(r, t)
  375. if r.Code != http.StatusNoContent {
  376. t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
  377. }
  378. containerAssertExists(eng, containerID, t)
  379. req, err = http.NewRequest("POST", "/containers/"+containerID+"/start", bytes.NewReader(hostConfigJSON))
  380. if err != nil {
  381. t.Fatal(err)
  382. }
  383. req.Header.Set("Content-Type", "application/json")
  384. r = httptest.NewRecorder()
  385. server.ServeRequest(eng, api.APIVERSION, r, req)
  386. // Starting an already started container should return a 304
  387. assertHttpNotError(r, t)
  388. if r.Code != http.StatusNotModified {
  389. t.Fatalf("%d NOT MODIFIER expected, received %d\n", http.StatusNotModified, r.Code)
  390. }
  391. containerAssertExists(eng, containerID, t)
  392. containerKill(eng, containerID, t)
  393. }
  394. func TestPostContainersStop(t *testing.T) {
  395. eng := NewTestEngine(t)
  396. defer mkDaemonFromEngine(eng, t).Nuke()
  397. containerID := createTestContainer(eng,
  398. &runconfig.Config{
  399. Image: unitTestImageID,
  400. Cmd: []string{"/bin/top"},
  401. OpenStdin: true,
  402. },
  403. t,
  404. )
  405. startContainer(eng, containerID, t)
  406. // Give some time to the process to start
  407. containerWaitTimeout(eng, containerID, t)
  408. if !containerRunning(eng, containerID, t) {
  409. t.Errorf("Container should be running")
  410. }
  411. // Note: as it is a POST request, it requires a body.
  412. req, err := http.NewRequest("POST", "/containers/"+containerID+"/stop?t=1", bytes.NewReader([]byte{}))
  413. if err != nil {
  414. t.Fatal(err)
  415. }
  416. r := httptest.NewRecorder()
  417. server.ServeRequest(eng, api.APIVERSION, r, req)
  418. assertHttpNotError(r, t)
  419. if r.Code != http.StatusNoContent {
  420. t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
  421. }
  422. if containerRunning(eng, containerID, t) {
  423. t.Fatalf("The container hasn't been stopped")
  424. }
  425. req, err = http.NewRequest("POST", "/containers/"+containerID+"/stop?t=1", bytes.NewReader([]byte{}))
  426. if err != nil {
  427. t.Fatal(err)
  428. }
  429. r = httptest.NewRecorder()
  430. server.ServeRequest(eng, api.APIVERSION, r, req)
  431. // Stopping an already stopper container should return a 304
  432. assertHttpNotError(r, t)
  433. if r.Code != http.StatusNotModified {
  434. t.Fatalf("%d NOT MODIFIER expected, received %d\n", http.StatusNotModified, r.Code)
  435. }
  436. }
  437. func TestPostContainersWait(t *testing.T) {
  438. eng := NewTestEngine(t)
  439. defer mkDaemonFromEngine(eng, t).Nuke()
  440. containerID := createTestContainer(eng,
  441. &runconfig.Config{
  442. Image: unitTestImageID,
  443. Cmd: []string{"/bin/sleep", "1"},
  444. OpenStdin: true,
  445. },
  446. t,
  447. )
  448. startContainer(eng, containerID, t)
  449. setTimeout(t, "Wait timed out", 3*time.Second, func() {
  450. r := httptest.NewRecorder()
  451. req, err := http.NewRequest("POST", "/containers/"+containerID+"/wait", bytes.NewReader([]byte{}))
  452. if err != nil {
  453. t.Fatal(err)
  454. }
  455. server.ServeRequest(eng, api.APIVERSION, r, req)
  456. assertHttpNotError(r, t)
  457. var apiWait engine.Env
  458. if err := apiWait.Decode(r.Body); err != nil {
  459. t.Fatal(err)
  460. }
  461. if apiWait.GetInt("StatusCode") != 0 {
  462. t.Fatalf("Non zero exit code for sleep: %d\n", apiWait.GetInt("StatusCode"))
  463. }
  464. })
  465. if containerRunning(eng, containerID, t) {
  466. t.Fatalf("The container should be stopped after wait")
  467. }
  468. }
  469. func TestPostContainersAttach(t *testing.T) {
  470. eng := NewTestEngine(t)
  471. defer mkDaemonFromEngine(eng, t).Nuke()
  472. containerID := createTestContainer(eng,
  473. &runconfig.Config{
  474. Image: unitTestImageID,
  475. Cmd: []string{"/bin/cat"},
  476. OpenStdin: true,
  477. },
  478. t,
  479. )
  480. // Start the process
  481. startContainer(eng, containerID, t)
  482. stdin, stdinPipe := io.Pipe()
  483. stdout, stdoutPipe := io.Pipe()
  484. // Try to avoid the timeout in destroy. Best effort, don't check error
  485. defer func() {
  486. closeWrap(stdin, stdinPipe, stdout, stdoutPipe)
  487. containerKill(eng, containerID, t)
  488. }()
  489. // Attach to it
  490. c1 := make(chan struct{})
  491. go func() {
  492. defer close(c1)
  493. r := &hijackTester{
  494. ResponseRecorder: httptest.NewRecorder(),
  495. in: stdin,
  496. out: stdoutPipe,
  497. }
  498. req, err := http.NewRequest("POST", "/containers/"+containerID+"/attach?stream=1&stdin=1&stdout=1&stderr=1", bytes.NewReader([]byte{}))
  499. if err != nil {
  500. t.Fatal(err)
  501. }
  502. server.ServeRequest(eng, api.APIVERSION, r, req)
  503. assertHttpNotError(r.ResponseRecorder, t)
  504. }()
  505. // Acknowledge hijack
  506. setTimeout(t, "hijack acknowledge timed out", 2*time.Second, func() {
  507. stdout.Read([]byte{})
  508. stdout.Read(make([]byte, 4096))
  509. })
  510. setTimeout(t, "read/write assertion timed out", 2*time.Second, func() {
  511. if err := assertPipe("hello\n", string([]byte{1, 0, 0, 0, 0, 0, 0, 6})+"hello", stdout, stdinPipe, 150); err != nil {
  512. t.Fatal(err)
  513. }
  514. })
  515. // Close pipes (client disconnects)
  516. if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
  517. t.Fatal(err)
  518. }
  519. // Wait for attach to finish, the client disconnected, therefore, Attach finished his job
  520. setTimeout(t, "Waiting for CmdAttach timed out", 10*time.Second, func() {
  521. <-c1
  522. })
  523. // We closed stdin, expect /bin/cat to still be running
  524. // Wait a little bit to make sure container.monitor() did his thing
  525. containerWaitTimeout(eng, containerID, t)
  526. // Try to avoid the timeout in destroy. Best effort, don't check error
  527. cStdin, _ := containerAttach(eng, containerID, t)
  528. cStdin.Close()
  529. containerWait(eng, containerID, t)
  530. }
  531. func TestPostContainersAttachStderr(t *testing.T) {
  532. eng := NewTestEngine(t)
  533. defer mkDaemonFromEngine(eng, t).Nuke()
  534. containerID := createTestContainer(eng,
  535. &runconfig.Config{
  536. Image: unitTestImageID,
  537. Cmd: []string{"/bin/sh", "-c", "/bin/cat >&2"},
  538. OpenStdin: true,
  539. },
  540. t,
  541. )
  542. // Start the process
  543. startContainer(eng, containerID, t)
  544. stdin, stdinPipe := io.Pipe()
  545. stdout, stdoutPipe := io.Pipe()
  546. // Try to avoid the timeout in destroy. Best effort, don't check error
  547. defer func() {
  548. closeWrap(stdin, stdinPipe, stdout, stdoutPipe)
  549. containerKill(eng, containerID, t)
  550. }()
  551. // Attach to it
  552. c1 := make(chan struct{})
  553. go func() {
  554. defer close(c1)
  555. r := &hijackTester{
  556. ResponseRecorder: httptest.NewRecorder(),
  557. in: stdin,
  558. out: stdoutPipe,
  559. }
  560. req, err := http.NewRequest("POST", "/containers/"+containerID+"/attach?stream=1&stdin=1&stdout=1&stderr=1", bytes.NewReader([]byte{}))
  561. if err != nil {
  562. t.Fatal(err)
  563. }
  564. server.ServeRequest(eng, api.APIVERSION, r, req)
  565. assertHttpNotError(r.ResponseRecorder, t)
  566. }()
  567. // Acknowledge hijack
  568. setTimeout(t, "hijack acknowledge timed out", 2*time.Second, func() {
  569. stdout.Read([]byte{})
  570. stdout.Read(make([]byte, 4096))
  571. })
  572. setTimeout(t, "read/write assertion timed out", 2*time.Second, func() {
  573. if err := assertPipe("hello\n", string([]byte{2, 0, 0, 0, 0, 0, 0, 6})+"hello", stdout, stdinPipe, 150); err != nil {
  574. t.Fatal(err)
  575. }
  576. })
  577. // Close pipes (client disconnects)
  578. if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
  579. t.Fatal(err)
  580. }
  581. // Wait for attach to finish, the client disconnected, therefore, Attach finished his job
  582. setTimeout(t, "Waiting for CmdAttach timed out", 10*time.Second, func() {
  583. <-c1
  584. })
  585. // We closed stdin, expect /bin/cat to still be running
  586. // Wait a little bit to make sure container.monitor() did his thing
  587. containerWaitTimeout(eng, containerID, t)
  588. // Try to avoid the timeout in destroy. Best effort, don't check error
  589. cStdin, _ := containerAttach(eng, containerID, t)
  590. cStdin.Close()
  591. containerWait(eng, containerID, t)
  592. }
  593. func TestOptionsRoute(t *testing.T) {
  594. eng := NewTestEngine(t)
  595. defer mkDaemonFromEngine(eng, t).Nuke()
  596. r := httptest.NewRecorder()
  597. req, err := http.NewRequest("OPTIONS", "/", nil)
  598. if err != nil {
  599. t.Fatal(err)
  600. }
  601. server.ServeRequest(eng, api.APIVERSION, r, req)
  602. assertHttpNotError(r, t)
  603. if r.Code != http.StatusOK {
  604. t.Errorf("Expected response for OPTIONS request to be \"200\", %v found.", r.Code)
  605. }
  606. }
  607. func TestGetEnabledCors(t *testing.T) {
  608. eng := NewTestEngine(t)
  609. defer mkDaemonFromEngine(eng, t).Nuke()
  610. r := httptest.NewRecorder()
  611. req, err := http.NewRequest("GET", "/version", nil)
  612. if err != nil {
  613. t.Fatal(err)
  614. }
  615. server.ServeRequest(eng, api.APIVERSION, r, req)
  616. assertHttpNotError(r, t)
  617. if r.Code != http.StatusOK {
  618. t.Errorf("Expected response for OPTIONS request to be \"200\", %v found.", r.Code)
  619. }
  620. allowOrigin := r.Header().Get("Access-Control-Allow-Origin")
  621. allowHeaders := r.Header().Get("Access-Control-Allow-Headers")
  622. allowMethods := r.Header().Get("Access-Control-Allow-Methods")
  623. if allowOrigin != "*" {
  624. t.Errorf("Expected header Access-Control-Allow-Origin to be \"*\", %s found.", allowOrigin)
  625. }
  626. if allowHeaders != "Origin, X-Requested-With, Content-Type, Accept, X-Registry-Auth" {
  627. t.Errorf("Expected header Access-Control-Allow-Headers to be \"Origin, X-Requested-With, Content-Type, Accept, X-Registry-Auth\", %s found.", allowHeaders)
  628. }
  629. if allowMethods != "GET, POST, DELETE, PUT, OPTIONS" {
  630. t.Errorf("Expected hearder Access-Control-Allow-Methods to be \"GET, POST, DELETE, PUT, OPTIONS\", %s found.", allowMethods)
  631. }
  632. }
  633. func TestDeleteImages(t *testing.T) {
  634. eng := NewTestEngine(t)
  635. //we expect errors, so we disable stderr
  636. eng.Stderr = ioutil.Discard
  637. defer mkDaemonFromEngine(eng, t).Nuke()
  638. initialImages := getImages(eng, t, true, "")
  639. if err := eng.Job("tag", unitTestImageName, "test", "test").Run(); err != nil {
  640. t.Fatal(err)
  641. }
  642. images := getImages(eng, t, true, "")
  643. if len(images.Data[0].GetList("RepoTags")) != len(initialImages.Data[0].GetList("RepoTags"))+1 {
  644. t.Errorf("Expected %d images, %d found", len(initialImages.Data[0].GetList("RepoTags"))+1, len(images.Data[0].GetList("RepoTags")))
  645. }
  646. req, err := http.NewRequest("DELETE", "/images/"+unitTestImageID, nil)
  647. if err != nil {
  648. t.Fatal(err)
  649. }
  650. r := httptest.NewRecorder()
  651. server.ServeRequest(eng, api.APIVERSION, r, req)
  652. if r.Code != http.StatusConflict {
  653. t.Fatalf("Expected http status 409-conflict, got %v", r.Code)
  654. }
  655. req2, err := http.NewRequest("DELETE", "/images/test:test", nil)
  656. if err != nil {
  657. t.Fatal(err)
  658. }
  659. r2 := httptest.NewRecorder()
  660. server.ServeRequest(eng, api.APIVERSION, r2, req2)
  661. assertHttpNotError(r2, t)
  662. if r2.Code != http.StatusOK {
  663. t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
  664. }
  665. outs := engine.NewTable("Created", 0)
  666. if _, err := outs.ReadListFrom(r2.Body.Bytes()); err != nil {
  667. t.Fatal(err)
  668. }
  669. if len(outs.Data) != 1 {
  670. t.Fatalf("Expected %d event (untagged), got %d", 1, len(outs.Data))
  671. }
  672. images = getImages(eng, t, false, "")
  673. if images.Len() != initialImages.Len() {
  674. t.Errorf("Expected %d image, %d found", initialImages.Len(), images.Len())
  675. }
  676. }
  677. func TestPostContainersCopy(t *testing.T) {
  678. eng := NewTestEngine(t)
  679. defer mkDaemonFromEngine(eng, t).Nuke()
  680. // Create a container and remove a file
  681. containerID := createTestContainer(eng,
  682. &runconfig.Config{
  683. Image: unitTestImageID,
  684. Cmd: []string{"touch", "/test.txt"},
  685. },
  686. t,
  687. )
  688. containerRun(eng, containerID, t)
  689. r := httptest.NewRecorder()
  690. var copyData engine.Env
  691. copyData.Set("Resource", "/test.txt")
  692. copyData.Set("HostPath", ".")
  693. jsonData := bytes.NewBuffer(nil)
  694. if err := copyData.Encode(jsonData); err != nil {
  695. t.Fatal(err)
  696. }
  697. req, err := http.NewRequest("POST", "/containers/"+containerID+"/copy", jsonData)
  698. if err != nil {
  699. t.Fatal(err)
  700. }
  701. req.Header.Add("Content-Type", "application/json")
  702. server.ServeRequest(eng, api.APIVERSION, r, req)
  703. assertHttpNotError(r, t)
  704. if r.Code != http.StatusOK {
  705. t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
  706. }
  707. found := false
  708. for tarReader := tar.NewReader(r.Body); ; {
  709. h, err := tarReader.Next()
  710. if err != nil {
  711. if err == io.EOF {
  712. break
  713. }
  714. t.Fatal(err)
  715. }
  716. if h.Name == "test.txt" {
  717. found = true
  718. break
  719. }
  720. }
  721. if !found {
  722. t.Fatalf("The created test file has not been found in the copied output")
  723. }
  724. }
  725. func TestPostContainersCopyWhenContainerNotFound(t *testing.T) {
  726. eng := NewTestEngine(t)
  727. defer mkDaemonFromEngine(eng, t).Nuke()
  728. r := httptest.NewRecorder()
  729. var copyData engine.Env
  730. copyData.Set("Resource", "/test.txt")
  731. copyData.Set("HostPath", ".")
  732. jsonData := bytes.NewBuffer(nil)
  733. if err := copyData.Encode(jsonData); err != nil {
  734. t.Fatal(err)
  735. }
  736. req, err := http.NewRequest("POST", "/containers/id_not_found/copy", jsonData)
  737. if err != nil {
  738. t.Fatal(err)
  739. }
  740. req.Header.Add("Content-Type", "application/json")
  741. server.ServeRequest(eng, api.APIVERSION, r, req)
  742. if r.Code != http.StatusNotFound {
  743. t.Fatalf("404 expected for id_not_found Container, received %v", r.Code)
  744. }
  745. }
  746. // Regression test for https://github.com/docker/docker/issues/6231
  747. func TestConstainersStartChunkedEncodingHostConfig(t *testing.T) {
  748. eng := NewTestEngine(t)
  749. defer mkDaemonFromEngine(eng, t).Nuke()
  750. r := httptest.NewRecorder()
  751. var testData engine.Env
  752. testData.Set("Image", "docker-test-image")
  753. testData.SetAuto("Volumes", map[string]struct{}{"/foo": {}})
  754. testData.Set("Cmd", "true")
  755. jsonData := bytes.NewBuffer(nil)
  756. if err := testData.Encode(jsonData); err != nil {
  757. t.Fatal(err)
  758. }
  759. req, err := http.NewRequest("POST", "/containers/create?name=chunk_test", jsonData)
  760. if err != nil {
  761. t.Fatal(err)
  762. }
  763. req.Header.Add("Content-Type", "application/json")
  764. server.ServeRequest(eng, api.APIVERSION, r, req)
  765. assertHttpNotError(r, t)
  766. var testData2 engine.Env
  767. testData2.SetAuto("Binds", []string{"/tmp:/foo"})
  768. jsonData = bytes.NewBuffer(nil)
  769. if err := testData2.Encode(jsonData); err != nil {
  770. t.Fatal(err)
  771. }
  772. req, err = http.NewRequest("POST", "/containers/chunk_test/start", jsonData)
  773. if err != nil {
  774. t.Fatal(err)
  775. }
  776. req.Header.Add("Content-Type", "application/json")
  777. // This is a cheat to make the http request do chunked encoding
  778. // Otherwise (just setting the Content-Encoding to chunked) net/http will overwrite
  779. // http://golang.org/src/pkg/net/http/request.go?s=11980:12172
  780. req.ContentLength = -1
  781. server.ServeRequest(eng, api.APIVERSION, r, req)
  782. assertHttpNotError(r, t)
  783. type config struct {
  784. HostConfig struct {
  785. Binds []string
  786. }
  787. }
  788. req, err = http.NewRequest("GET", "/containers/chunk_test/json", nil)
  789. if err != nil {
  790. t.Fatal(err)
  791. }
  792. r2 := httptest.NewRecorder()
  793. req.Header.Add("Content-Type", "application/json")
  794. server.ServeRequest(eng, api.APIVERSION, r2, req)
  795. assertHttpNotError(r, t)
  796. c := config{}
  797. json.Unmarshal(r2.Body.Bytes(), &c)
  798. if len(c.HostConfig.Binds) == 0 {
  799. t.Fatal("Chunked Encoding not handled")
  800. }
  801. if c.HostConfig.Binds[0] != "/tmp:/foo" {
  802. t.Fatal("Chunked encoding not properly handled, execpted binds to be /tmp:/foo, got:", c.HostConfig.Binds[0])
  803. }
  804. }
  805. // Mocked types for tests
  806. type NopConn struct {
  807. io.ReadCloser
  808. io.Writer
  809. }
  810. func (c *NopConn) LocalAddr() net.Addr { return nil }
  811. func (c *NopConn) RemoteAddr() net.Addr { return nil }
  812. func (c *NopConn) SetDeadline(t time.Time) error { return nil }
  813. func (c *NopConn) SetReadDeadline(t time.Time) error { return nil }
  814. func (c *NopConn) SetWriteDeadline(t time.Time) error { return nil }
  815. type hijackTester struct {
  816. *httptest.ResponseRecorder
  817. in io.ReadCloser
  818. out io.Writer
  819. }
  820. func (t *hijackTester) Hijack() (net.Conn, *bufio.ReadWriter, error) {
  821. bufrw := bufio.NewReadWriter(bufio.NewReader(t.in), bufio.NewWriter(t.out))
  822. conn := &NopConn{
  823. ReadCloser: t.in,
  824. Writer: t.out,
  825. }
  826. return conn, bufrw, nil
  827. }