api_test.go 25 KB

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