api_test.go 26 KB

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