api_test.go 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992
  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/api/types"
  18. "github.com/docker/docker/builder"
  19. "github.com/docker/docker/engine"
  20. "github.com/docker/docker/runconfig"
  21. "github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
  22. )
  23. func TestSaveImageAndThenLoad(t *testing.T) {
  24. eng := NewTestEngine(t)
  25. defer mkDaemonFromEngine(eng, t).Nuke()
  26. // save image
  27. r := httptest.NewRecorder()
  28. req, err := http.NewRequest("GET", "/images/"+unitTestImageID+"/get", nil)
  29. if err != nil {
  30. t.Fatal(err)
  31. }
  32. server.ServeRequest(eng, api.APIVERSION, r, req)
  33. if r.Code != http.StatusOK {
  34. t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
  35. }
  36. tarball := r.Body
  37. // delete the image
  38. r = httptest.NewRecorder()
  39. req, err = http.NewRequest("DELETE", "/images/"+unitTestImageID, nil)
  40. if err != nil {
  41. t.Fatal(err)
  42. }
  43. server.ServeRequest(eng, api.APIVERSION, r, req)
  44. if r.Code != http.StatusOK {
  45. t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
  46. }
  47. // make sure there is no image
  48. r = httptest.NewRecorder()
  49. req, err = http.NewRequest("GET", "/images/"+unitTestImageID+"/get", nil)
  50. if err != nil {
  51. t.Fatal(err)
  52. }
  53. server.ServeRequest(eng, api.APIVERSION, r, req)
  54. if r.Code != http.StatusNotFound {
  55. t.Fatalf("%d NotFound expected, received %d\n", http.StatusNotFound, r.Code)
  56. }
  57. // load the image
  58. r = httptest.NewRecorder()
  59. req, err = http.NewRequest("POST", "/images/load", tarball)
  60. if err != nil {
  61. t.Fatal(err)
  62. }
  63. server.ServeRequest(eng, api.APIVERSION, r, req)
  64. if r.Code != http.StatusOK {
  65. t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
  66. }
  67. // finally make sure the image is there
  68. r = httptest.NewRecorder()
  69. req, err = http.NewRequest("GET", "/images/"+unitTestImageID+"/get", nil)
  70. if err != nil {
  71. t.Fatal(err)
  72. }
  73. server.ServeRequest(eng, api.APIVERSION, r, req)
  74. if r.Code != http.StatusOK {
  75. t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
  76. }
  77. }
  78. func TestGetContainersTop(t *testing.T) {
  79. eng := NewTestEngine(t)
  80. defer mkDaemonFromEngine(eng, t).Nuke()
  81. containerID := createTestContainer(eng,
  82. &runconfig.Config{
  83. Image: unitTestImageID,
  84. Cmd: runconfig.NewCommand("/bin/sh", "-c", "cat"),
  85. OpenStdin: true,
  86. },
  87. t,
  88. )
  89. defer func() {
  90. // Make sure the process dies before destroying daemon
  91. containerKill(eng, containerID, t)
  92. containerWait(eng, containerID, t)
  93. }()
  94. startContainer(eng, containerID, t)
  95. setTimeout(t, "Waiting for the container to be started timed out", 10*time.Second, func() {
  96. for {
  97. if containerRunning(eng, containerID, t) {
  98. break
  99. }
  100. time.Sleep(10 * time.Millisecond)
  101. }
  102. })
  103. if !containerRunning(eng, containerID, t) {
  104. t.Fatalf("Container should be running")
  105. }
  106. // Make sure sh spawn up cat
  107. setTimeout(t, "read/write assertion timed out", 2*time.Second, func() {
  108. in, out := containerAttach(eng, containerID, t)
  109. if err := assertPipe("hello\n", "hello", out, in, 150); err != nil {
  110. t.Fatal(err)
  111. }
  112. })
  113. r := httptest.NewRecorder()
  114. req, err := http.NewRequest("GET", "/containers/"+containerID+"/top?ps_args=aux", nil)
  115. if err != nil {
  116. t.Fatal(err)
  117. }
  118. server.ServeRequest(eng, api.APIVERSION, r, req)
  119. assertHttpNotError(r, t)
  120. var procs engine.Env
  121. if err := procs.Decode(r.Body); err != nil {
  122. t.Fatal(err)
  123. }
  124. if len(procs.GetList("Titles")) != 11 {
  125. t.Fatalf("Expected 11 titles, found %d.", len(procs.GetList("Titles")))
  126. }
  127. if procs.GetList("Titles")[0] != "USER" || procs.GetList("Titles")[10] != "COMMAND" {
  128. 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])
  129. }
  130. processes := [][]string{}
  131. if err := procs.GetJson("Processes", &processes); err != nil {
  132. t.Fatal(err)
  133. }
  134. if len(processes) != 2 {
  135. t.Fatalf("Expected 2 processes, found %d.", len(processes))
  136. }
  137. if processes[0][10] != "/bin/sh -c cat" {
  138. t.Fatalf("Expected `/bin/sh -c cat`, found %s.", processes[0][10])
  139. }
  140. if processes[1][10] != "/bin/sh -c cat" {
  141. t.Fatalf("Expected `/bin/sh -c cat`, found %s.", processes[1][10])
  142. }
  143. }
  144. func TestPostCommit(t *testing.T) {
  145. eng := NewTestEngine(t)
  146. b := &builder.BuilderJob{Engine: eng}
  147. b.Install()
  148. defer mkDaemonFromEngine(eng, t).Nuke()
  149. // Create a container and remove a file
  150. containerID := createTestContainer(eng,
  151. &runconfig.Config{
  152. Image: unitTestImageID,
  153. Cmd: runconfig.NewCommand("touch", "/test"),
  154. },
  155. t,
  156. )
  157. containerRun(eng, containerID, t)
  158. req, err := http.NewRequest("POST", "/commit?repo=testrepo&testtag=tag&container="+containerID, bytes.NewReader([]byte{}))
  159. if err != nil {
  160. t.Fatal(err)
  161. }
  162. r := httptest.NewRecorder()
  163. server.ServeRequest(eng, api.APIVERSION, r, req)
  164. assertHttpNotError(r, t)
  165. if r.Code != http.StatusCreated {
  166. t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code)
  167. }
  168. var env engine.Env
  169. if err := env.Decode(r.Body); err != nil {
  170. t.Fatal(err)
  171. }
  172. if err := eng.Job("image_inspect", env.Get("Id")).Run(); err != nil {
  173. t.Fatalf("The image has not been committed")
  174. }
  175. }
  176. func TestPostContainersCreate(t *testing.T) {
  177. eng := NewTestEngine(t)
  178. defer mkDaemonFromEngine(eng, t).Nuke()
  179. configJSON, err := json.Marshal(&runconfig.Config{
  180. Image: unitTestImageID,
  181. Cmd: runconfig.NewCommand("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. Cmd: runconfig.NewCommand("touch", "/test"),
  214. })
  215. if err != nil {
  216. t.Fatal(err)
  217. }
  218. req, err := http.NewRequest("POST", "/containers/create", bytes.NewReader(configJSON))
  219. if err != nil {
  220. t.Fatal(err)
  221. }
  222. r := httptest.NewRecorder()
  223. server.ServeRequest(eng, api.APIVERSION, r, req)
  224. // Don't add Content-Type header
  225. // req.Header.Set("Content-Type", "application/json")
  226. server.ServeRequest(eng, api.APIVERSION, r, req)
  227. if r.Code != http.StatusInternalServerError || !strings.Contains(((*r.Body).String()), "application/json") {
  228. t.Fatal("Create should have failed due to no Content-Type header - got:", r)
  229. }
  230. // Now add header but with wrong type and retest
  231. req.Header.Set("Content-Type", "application/xml")
  232. server.ServeRequest(eng, api.APIVERSION, r, req)
  233. if r.Code != http.StatusInternalServerError || !strings.Contains(((*r.Body).String()), "application/json") {
  234. t.Fatal("Create should have failed due to wrong Content-Type header - got:", r)
  235. }
  236. }
  237. // Issue 7941 - test to make sure a "null" in JSON is just ignored.
  238. // W/o this fix a null in JSON would be parsed into a string var as "null"
  239. func TestPostCreateNull(t *testing.T) {
  240. eng := NewTestEngine(t)
  241. daemon := mkDaemonFromEngine(eng, t)
  242. defer daemon.Nuke()
  243. configStr := fmt.Sprintf(`{
  244. "Hostname":"",
  245. "Domainname":"",
  246. "Memory":0,
  247. "MemorySwap":0,
  248. "CpuShares":0,
  249. "Cpuset":null,
  250. "AttachStdin":true,
  251. "AttachStdout":true,
  252. "AttachStderr":true,
  253. "PortSpecs":null,
  254. "ExposedPorts":{},
  255. "Tty":true,
  256. "OpenStdin":true,
  257. "StdinOnce":true,
  258. "Env":[],
  259. "Cmd":"ls",
  260. "Image":"%s",
  261. "Volumes":{},
  262. "WorkingDir":"",
  263. "Entrypoint":null,
  264. "NetworkDisabled":false,
  265. "OnBuild":null}`, unitTestImageID)
  266. req, err := http.NewRequest("POST", "/containers/create", strings.NewReader(configStr))
  267. if err != nil {
  268. t.Fatal(err)
  269. }
  270. req.Header.Set("Content-Type", "application/json")
  271. r := httptest.NewRecorder()
  272. server.ServeRequest(eng, api.APIVERSION, r, req)
  273. assertHttpNotError(r, t)
  274. if r.Code != http.StatusCreated {
  275. t.Fatalf("%d Created expected, received %d\n", http.StatusCreated, r.Code)
  276. }
  277. var apiRun engine.Env
  278. if err := apiRun.Decode(r.Body); err != nil {
  279. t.Fatal(err)
  280. }
  281. containerID := apiRun.Get("Id")
  282. containerAssertExists(eng, containerID, t)
  283. c, _ := daemon.Get(containerID)
  284. if c.HostConfig().CpusetCpus != "" {
  285. t.Fatalf("Cpuset should have been empty - instead its:" + c.HostConfig().CpusetCpus)
  286. }
  287. }
  288. func TestPostContainersKill(t *testing.T) {
  289. eng := NewTestEngine(t)
  290. defer mkDaemonFromEngine(eng, t).Nuke()
  291. containerID := createTestContainer(eng,
  292. &runconfig.Config{
  293. Image: unitTestImageID,
  294. Cmd: runconfig.NewCommand("/bin/cat"),
  295. OpenStdin: true,
  296. },
  297. t,
  298. )
  299. startContainer(eng, containerID, t)
  300. // Give some time to the process to start
  301. containerWaitTimeout(eng, containerID, t)
  302. if !containerRunning(eng, containerID, t) {
  303. t.Errorf("Container should be running")
  304. }
  305. r := httptest.NewRecorder()
  306. req, err := http.NewRequest("POST", "/containers/"+containerID+"/kill", bytes.NewReader([]byte{}))
  307. if err != nil {
  308. t.Fatal(err)
  309. }
  310. server.ServeRequest(eng, api.APIVERSION, r, req)
  311. assertHttpNotError(r, t)
  312. if r.Code != http.StatusNoContent {
  313. t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
  314. }
  315. if containerRunning(eng, containerID, t) {
  316. t.Fatalf("The container hasn't been killed")
  317. }
  318. }
  319. func TestPostContainersRestart(t *testing.T) {
  320. eng := NewTestEngine(t)
  321. defer mkDaemonFromEngine(eng, t).Nuke()
  322. containerID := createTestContainer(eng,
  323. &runconfig.Config{
  324. Image: unitTestImageID,
  325. Cmd: runconfig.NewCommand("/bin/top"),
  326. OpenStdin: true,
  327. },
  328. t,
  329. )
  330. startContainer(eng, containerID, t)
  331. // Give some time to the process to start
  332. containerWaitTimeout(eng, containerID, t)
  333. if !containerRunning(eng, containerID, t) {
  334. t.Errorf("Container should be running")
  335. }
  336. req, err := http.NewRequest("POST", "/containers/"+containerID+"/restart?t=1", bytes.NewReader([]byte{}))
  337. if err != nil {
  338. t.Fatal(err)
  339. }
  340. r := httptest.NewRecorder()
  341. server.ServeRequest(eng, api.APIVERSION, r, req)
  342. assertHttpNotError(r, t)
  343. if r.Code != http.StatusNoContent {
  344. t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
  345. }
  346. // Give some time to the process to restart
  347. containerWaitTimeout(eng, containerID, t)
  348. if !containerRunning(eng, containerID, t) {
  349. t.Fatalf("Container should be running")
  350. }
  351. containerKill(eng, containerID, t)
  352. }
  353. func TestPostContainersStart(t *testing.T) {
  354. eng := NewTestEngine(t)
  355. defer mkDaemonFromEngine(eng, t).Nuke()
  356. containerID := createTestContainer(
  357. eng,
  358. &runconfig.Config{
  359. Image: unitTestImageID,
  360. Cmd: runconfig.NewCommand("/bin/cat"),
  361. OpenStdin: true,
  362. },
  363. t,
  364. )
  365. hostConfigJSON, err := json.Marshal(&runconfig.HostConfig{})
  366. req, err := http.NewRequest("POST", "/containers/"+containerID+"/start", bytes.NewReader(hostConfigJSON))
  367. if err != nil {
  368. t.Fatal(err)
  369. }
  370. req.Header.Set("Content-Type", "application/json")
  371. r := httptest.NewRecorder()
  372. server.ServeRequest(eng, api.APIVERSION, r, req)
  373. assertHttpNotError(r, t)
  374. if r.Code != http.StatusNoContent {
  375. t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
  376. }
  377. containerAssertExists(eng, containerID, t)
  378. req, err = http.NewRequest("POST", "/containers/"+containerID+"/start", bytes.NewReader(hostConfigJSON))
  379. if err != nil {
  380. t.Fatal(err)
  381. }
  382. req.Header.Set("Content-Type", "application/json")
  383. r = httptest.NewRecorder()
  384. server.ServeRequest(eng, api.APIVERSION, r, req)
  385. // Starting an already started container should return a 304
  386. assertHttpNotError(r, t)
  387. if r.Code != http.StatusNotModified {
  388. t.Fatalf("%d NOT MODIFIER expected, received %d\n", http.StatusNotModified, r.Code)
  389. }
  390. containerAssertExists(eng, containerID, t)
  391. containerKill(eng, containerID, t)
  392. }
  393. func TestPostContainersStop(t *testing.T) {
  394. eng := NewTestEngine(t)
  395. defer mkDaemonFromEngine(eng, t).Nuke()
  396. containerID := createTestContainer(eng,
  397. &runconfig.Config{
  398. Image: unitTestImageID,
  399. Cmd: runconfig.NewCommand("/bin/top"),
  400. OpenStdin: true,
  401. },
  402. t,
  403. )
  404. startContainer(eng, containerID, t)
  405. // Give some time to the process to start
  406. containerWaitTimeout(eng, containerID, t)
  407. if !containerRunning(eng, containerID, t) {
  408. t.Errorf("Container should be running")
  409. }
  410. // Note: as it is a POST request, it requires a body.
  411. req, err := http.NewRequest("POST", "/containers/"+containerID+"/stop?t=1", bytes.NewReader([]byte{}))
  412. if err != nil {
  413. t.Fatal(err)
  414. }
  415. r := httptest.NewRecorder()
  416. server.ServeRequest(eng, api.APIVERSION, r, req)
  417. assertHttpNotError(r, t)
  418. if r.Code != http.StatusNoContent {
  419. t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
  420. }
  421. if containerRunning(eng, containerID, t) {
  422. t.Fatalf("The container hasn't been stopped")
  423. }
  424. req, err = http.NewRequest("POST", "/containers/"+containerID+"/stop?t=1", bytes.NewReader([]byte{}))
  425. if err != nil {
  426. t.Fatal(err)
  427. }
  428. r = httptest.NewRecorder()
  429. server.ServeRequest(eng, api.APIVERSION, r, req)
  430. // Stopping an already stopper container should return a 304
  431. assertHttpNotError(r, t)
  432. if r.Code != http.StatusNotModified {
  433. t.Fatalf("%d NOT MODIFIER expected, received %d\n", http.StatusNotModified, r.Code)
  434. }
  435. }
  436. func TestPostContainersWait(t *testing.T) {
  437. eng := NewTestEngine(t)
  438. defer mkDaemonFromEngine(eng, t).Nuke()
  439. containerID := createTestContainer(eng,
  440. &runconfig.Config{
  441. Image: unitTestImageID,
  442. Cmd: runconfig.NewCommand("/bin/sleep", "1"),
  443. OpenStdin: true,
  444. },
  445. t,
  446. )
  447. startContainer(eng, containerID, t)
  448. setTimeout(t, "Wait timed out", 3*time.Second, func() {
  449. r := httptest.NewRecorder()
  450. req, err := http.NewRequest("POST", "/containers/"+containerID+"/wait", bytes.NewReader([]byte{}))
  451. if err != nil {
  452. t.Fatal(err)
  453. }
  454. server.ServeRequest(eng, api.APIVERSION, r, req)
  455. assertHttpNotError(r, t)
  456. var apiWait engine.Env
  457. if err := apiWait.Decode(r.Body); err != nil {
  458. t.Fatal(err)
  459. }
  460. if apiWait.GetInt("StatusCode") != 0 {
  461. t.Fatalf("Non zero exit code for sleep: %d\n", apiWait.GetInt("StatusCode"))
  462. }
  463. })
  464. if containerRunning(eng, containerID, t) {
  465. t.Fatalf("The container should be stopped after wait")
  466. }
  467. }
  468. func TestPostContainersAttach(t *testing.T) {
  469. eng := NewTestEngine(t)
  470. defer mkDaemonFromEngine(eng, t).Nuke()
  471. containerID := createTestContainer(eng,
  472. &runconfig.Config{
  473. Image: unitTestImageID,
  474. Cmd: runconfig.NewCommand("/bin/cat"),
  475. OpenStdin: true,
  476. },
  477. t,
  478. )
  479. // Start the process
  480. startContainer(eng, containerID, t)
  481. stdin, stdinPipe := io.Pipe()
  482. stdout, stdoutPipe := io.Pipe()
  483. // Try to avoid the timeout in destroy. Best effort, don't check error
  484. defer func() {
  485. closeWrap(stdin, stdinPipe, stdout, stdoutPipe)
  486. containerKill(eng, containerID, t)
  487. }()
  488. // Attach to it
  489. c1 := make(chan struct{})
  490. go func() {
  491. defer close(c1)
  492. r := &hijackTester{
  493. ResponseRecorder: httptest.NewRecorder(),
  494. in: stdin,
  495. out: stdoutPipe,
  496. }
  497. req, err := http.NewRequest("POST", "/containers/"+containerID+"/attach?stream=1&stdin=1&stdout=1&stderr=1", bytes.NewReader([]byte{}))
  498. if err != nil {
  499. t.Fatal(err)
  500. }
  501. server.ServeRequest(eng, api.APIVERSION, r, req)
  502. assertHttpNotError(r.ResponseRecorder, t)
  503. }()
  504. // Acknowledge hijack
  505. setTimeout(t, "hijack acknowledge timed out", 2*time.Second, func() {
  506. stdout.Read([]byte{})
  507. stdout.Read(make([]byte, 4096))
  508. })
  509. setTimeout(t, "read/write assertion timed out", 2*time.Second, func() {
  510. if err := assertPipe("hello\n", string([]byte{1, 0, 0, 0, 0, 0, 0, 6})+"hello", stdout, stdinPipe, 150); err != nil {
  511. t.Fatal(err)
  512. }
  513. })
  514. // Close pipes (client disconnects)
  515. if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
  516. t.Fatal(err)
  517. }
  518. // Wait for attach to finish, the client disconnected, therefore, Attach finished his job
  519. setTimeout(t, "Waiting for CmdAttach timed out", 10*time.Second, func() {
  520. <-c1
  521. })
  522. // We closed stdin, expect /bin/cat to still be running
  523. // Wait a little bit to make sure container.monitor() did his thing
  524. containerWaitTimeout(eng, containerID, t)
  525. // Try to avoid the timeout in destroy. Best effort, don't check error
  526. cStdin, _ := containerAttach(eng, containerID, t)
  527. cStdin.Close()
  528. containerWait(eng, containerID, t)
  529. }
  530. func TestPostContainersAttachStderr(t *testing.T) {
  531. eng := NewTestEngine(t)
  532. defer mkDaemonFromEngine(eng, t).Nuke()
  533. containerID := createTestContainer(eng,
  534. &runconfig.Config{
  535. Image: unitTestImageID,
  536. Cmd: runconfig.NewCommand("/bin/sh", "-c", "/bin/cat >&2"),
  537. OpenStdin: true,
  538. },
  539. t,
  540. )
  541. // Start the process
  542. startContainer(eng, containerID, t)
  543. stdin, stdinPipe := io.Pipe()
  544. stdout, stdoutPipe := io.Pipe()
  545. // Try to avoid the timeout in destroy. Best effort, don't check error
  546. defer func() {
  547. closeWrap(stdin, stdinPipe, stdout, stdoutPipe)
  548. containerKill(eng, containerID, t)
  549. }()
  550. // Attach to it
  551. c1 := make(chan struct{})
  552. go func() {
  553. defer close(c1)
  554. r := &hijackTester{
  555. ResponseRecorder: httptest.NewRecorder(),
  556. in: stdin,
  557. out: stdoutPipe,
  558. }
  559. req, err := http.NewRequest("POST", "/containers/"+containerID+"/attach?stream=1&stdin=1&stdout=1&stderr=1", bytes.NewReader([]byte{}))
  560. if err != nil {
  561. t.Fatal(err)
  562. }
  563. server.ServeRequest(eng, api.APIVERSION, r, req)
  564. assertHttpNotError(r.ResponseRecorder, t)
  565. }()
  566. // Acknowledge hijack
  567. setTimeout(t, "hijack acknowledge timed out", 2*time.Second, func() {
  568. stdout.Read([]byte{})
  569. stdout.Read(make([]byte, 4096))
  570. })
  571. setTimeout(t, "read/write assertion timed out", 2*time.Second, func() {
  572. if err := assertPipe("hello\n", string([]byte{2, 0, 0, 0, 0, 0, 0, 6})+"hello", stdout, stdinPipe, 150); err != nil {
  573. t.Fatal(err)
  574. }
  575. })
  576. // Close pipes (client disconnects)
  577. if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
  578. t.Fatal(err)
  579. }
  580. // Wait for attach to finish, the client disconnected, therefore, Attach finished his job
  581. setTimeout(t, "Waiting for CmdAttach timed out", 10*time.Second, func() {
  582. <-c1
  583. })
  584. // We closed stdin, expect /bin/cat to still be running
  585. // Wait a little bit to make sure container.monitor() did his thing
  586. containerWaitTimeout(eng, containerID, t)
  587. // Try to avoid the timeout in destroy. Best effort, don't check error
  588. cStdin, _ := containerAttach(eng, containerID, t)
  589. cStdin.Close()
  590. containerWait(eng, containerID, t)
  591. }
  592. func TestOptionsRoute(t *testing.T) {
  593. eng := NewTestEngine(t)
  594. defer mkDaemonFromEngine(eng, t).Nuke()
  595. r := httptest.NewRecorder()
  596. req, err := http.NewRequest("OPTIONS", "/", nil)
  597. if err != nil {
  598. t.Fatal(err)
  599. }
  600. server.ServeRequest(eng, api.APIVERSION, r, req)
  601. assertHttpNotError(r, t)
  602. if r.Code != http.StatusOK {
  603. t.Errorf("Expected response for OPTIONS request to be \"200\", %v found.", r.Code)
  604. }
  605. }
  606. func TestGetEnabledCors(t *testing.T) {
  607. eng := NewTestEngine(t)
  608. defer mkDaemonFromEngine(eng, t).Nuke()
  609. r := httptest.NewRecorder()
  610. req, err := http.NewRequest("GET", "/version", nil)
  611. if err != nil {
  612. t.Fatal(err)
  613. }
  614. server.ServeRequest(eng, api.APIVERSION, r, req)
  615. assertHttpNotError(r, t)
  616. if r.Code != http.StatusOK {
  617. t.Errorf("Expected response for OPTIONS request to be \"200\", %v found.", r.Code)
  618. }
  619. allowOrigin := r.Header().Get("Access-Control-Allow-Origin")
  620. allowHeaders := r.Header().Get("Access-Control-Allow-Headers")
  621. allowMethods := r.Header().Get("Access-Control-Allow-Methods")
  622. if allowOrigin != "*" {
  623. t.Errorf("Expected header Access-Control-Allow-Origin to be \"*\", %s found.", allowOrigin)
  624. }
  625. if allowHeaders != "Origin, X-Requested-With, Content-Type, Accept, X-Registry-Auth" {
  626. t.Errorf("Expected header Access-Control-Allow-Headers to be \"Origin, X-Requested-With, Content-Type, Accept, X-Registry-Auth\", %s found.", allowHeaders)
  627. }
  628. if allowMethods != "GET, POST, DELETE, PUT, OPTIONS" {
  629. t.Errorf("Expected hearder Access-Control-Allow-Methods to be \"GET, POST, DELETE, PUT, OPTIONS\", %s found.", allowMethods)
  630. }
  631. }
  632. func TestDeleteImages(t *testing.T) {
  633. eng := NewTestEngine(t)
  634. //we expect errors, so we disable stderr
  635. eng.Stderr = ioutil.Discard
  636. defer mkDaemonFromEngine(eng, t).Nuke()
  637. initialImages := getImages(eng, t, true, "")
  638. if err := eng.Job("tag", unitTestImageName, "test", "test").Run(); err != nil {
  639. t.Fatal(err)
  640. }
  641. images := getImages(eng, t, true, "")
  642. if len(images[0].RepoTags) != len(initialImages[0].RepoTags)+1 {
  643. t.Errorf("Expected %d images, %d found", len(initialImages[0].RepoTags)+1, len(images[0].RepoTags))
  644. }
  645. req, err := http.NewRequest("DELETE", "/images/"+unitTestImageID, nil)
  646. if err != nil {
  647. t.Fatal(err)
  648. }
  649. r := httptest.NewRecorder()
  650. server.ServeRequest(eng, api.APIVERSION, r, req)
  651. if r.Code != http.StatusConflict {
  652. t.Fatalf("Expected http status 409-conflict, got %v", r.Code)
  653. }
  654. req2, err := http.NewRequest("DELETE", "/images/test:test", nil)
  655. if err != nil {
  656. t.Fatal(err)
  657. }
  658. r2 := httptest.NewRecorder()
  659. server.ServeRequest(eng, api.APIVERSION, r2, req2)
  660. assertHttpNotError(r2, t)
  661. if r2.Code != http.StatusOK {
  662. t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
  663. }
  664. delImages := []types.ImageDelete{}
  665. err = json.Unmarshal(r2.Body.Bytes(), &delImages)
  666. if err != nil {
  667. t.Fatal(err)
  668. }
  669. if len(delImages) != 1 {
  670. t.Fatalf("Expected %d event (untagged), got %d", 1, len(delImages))
  671. }
  672. images = getImages(eng, t, false, "")
  673. if len(images) != len(initialImages) {
  674. t.Errorf("Expected %d image, %d found", len(initialImages), len(images))
  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: runconfig.NewCommand("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. // https://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. }