api_test.go 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679
  1. package docker
  2. import (
  3. "bufio"
  4. "bytes"
  5. "encoding/json"
  6. "io"
  7. "io/ioutil"
  8. "net"
  9. "net/http"
  10. "net/http/httptest"
  11. "testing"
  12. "time"
  13. "github.com/docker/docker/api"
  14. "github.com/docker/docker/api/server"
  15. "github.com/docker/docker/api/types"
  16. "github.com/docker/docker/engine"
  17. "github.com/docker/docker/runconfig"
  18. "github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar"
  19. )
  20. func TestPostContainersKill(t *testing.T) {
  21. eng := NewTestEngine(t)
  22. defer mkDaemonFromEngine(eng, t).Nuke()
  23. containerID := createTestContainer(eng,
  24. &runconfig.Config{
  25. Image: unitTestImageID,
  26. Cmd: runconfig.NewCommand("/bin/cat"),
  27. OpenStdin: true,
  28. },
  29. t,
  30. )
  31. startContainer(eng, containerID, t)
  32. // Give some time to the process to start
  33. containerWaitTimeout(eng, containerID, t)
  34. if !containerRunning(eng, containerID, t) {
  35. t.Errorf("Container should be running")
  36. }
  37. r := httptest.NewRecorder()
  38. req, err := http.NewRequest("POST", "/containers/"+containerID+"/kill", bytes.NewReader([]byte{}))
  39. if err != nil {
  40. t.Fatal(err)
  41. }
  42. server.ServeRequest(eng, api.APIVERSION, r, req)
  43. assertHttpNotError(r, t)
  44. if r.Code != http.StatusNoContent {
  45. t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
  46. }
  47. if containerRunning(eng, containerID, t) {
  48. t.Fatalf("The container hasn't been killed")
  49. }
  50. }
  51. func TestPostContainersRestart(t *testing.T) {
  52. eng := NewTestEngine(t)
  53. defer mkDaemonFromEngine(eng, t).Nuke()
  54. containerID := createTestContainer(eng,
  55. &runconfig.Config{
  56. Image: unitTestImageID,
  57. Cmd: runconfig.NewCommand("/bin/top"),
  58. OpenStdin: true,
  59. },
  60. t,
  61. )
  62. startContainer(eng, containerID, t)
  63. // Give some time to the process to start
  64. containerWaitTimeout(eng, containerID, t)
  65. if !containerRunning(eng, containerID, t) {
  66. t.Errorf("Container should be running")
  67. }
  68. req, err := http.NewRequest("POST", "/containers/"+containerID+"/restart?t=1", bytes.NewReader([]byte{}))
  69. if err != nil {
  70. t.Fatal(err)
  71. }
  72. r := httptest.NewRecorder()
  73. server.ServeRequest(eng, api.APIVERSION, r, req)
  74. assertHttpNotError(r, t)
  75. if r.Code != http.StatusNoContent {
  76. t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
  77. }
  78. // Give some time to the process to restart
  79. containerWaitTimeout(eng, containerID, t)
  80. if !containerRunning(eng, containerID, t) {
  81. t.Fatalf("Container should be running")
  82. }
  83. containerKill(eng, containerID, t)
  84. }
  85. func TestPostContainersStart(t *testing.T) {
  86. eng := NewTestEngine(t)
  87. defer mkDaemonFromEngine(eng, t).Nuke()
  88. containerID := createTestContainer(
  89. eng,
  90. &runconfig.Config{
  91. Image: unitTestImageID,
  92. Cmd: runconfig.NewCommand("/bin/cat"),
  93. OpenStdin: true,
  94. },
  95. t,
  96. )
  97. hostConfigJSON, err := json.Marshal(&runconfig.HostConfig{})
  98. req, err := http.NewRequest("POST", "/containers/"+containerID+"/start", bytes.NewReader(hostConfigJSON))
  99. if err != nil {
  100. t.Fatal(err)
  101. }
  102. req.Header.Set("Content-Type", "application/json")
  103. r := httptest.NewRecorder()
  104. server.ServeRequest(eng, api.APIVERSION, r, req)
  105. assertHttpNotError(r, t)
  106. if r.Code != http.StatusNoContent {
  107. t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
  108. }
  109. containerAssertExists(eng, containerID, t)
  110. req, err = http.NewRequest("POST", "/containers/"+containerID+"/start", bytes.NewReader(hostConfigJSON))
  111. if err != nil {
  112. t.Fatal(err)
  113. }
  114. req.Header.Set("Content-Type", "application/json")
  115. r = httptest.NewRecorder()
  116. server.ServeRequest(eng, api.APIVERSION, r, req)
  117. // Starting an already started container should return a 304
  118. assertHttpNotError(r, t)
  119. if r.Code != http.StatusNotModified {
  120. t.Fatalf("%d NOT MODIFIER expected, received %d\n", http.StatusNotModified, r.Code)
  121. }
  122. containerAssertExists(eng, containerID, t)
  123. containerKill(eng, containerID, t)
  124. }
  125. func TestPostContainersStop(t *testing.T) {
  126. eng := NewTestEngine(t)
  127. defer mkDaemonFromEngine(eng, t).Nuke()
  128. containerID := createTestContainer(eng,
  129. &runconfig.Config{
  130. Image: unitTestImageID,
  131. Cmd: runconfig.NewCommand("/bin/top"),
  132. OpenStdin: true,
  133. },
  134. t,
  135. )
  136. startContainer(eng, containerID, t)
  137. // Give some time to the process to start
  138. containerWaitTimeout(eng, containerID, t)
  139. if !containerRunning(eng, containerID, t) {
  140. t.Errorf("Container should be running")
  141. }
  142. // Note: as it is a POST request, it requires a body.
  143. req, err := http.NewRequest("POST", "/containers/"+containerID+"/stop?t=1", bytes.NewReader([]byte{}))
  144. if err != nil {
  145. t.Fatal(err)
  146. }
  147. r := httptest.NewRecorder()
  148. server.ServeRequest(eng, api.APIVERSION, r, req)
  149. assertHttpNotError(r, t)
  150. if r.Code != http.StatusNoContent {
  151. t.Fatalf("%d NO CONTENT expected, received %d\n", http.StatusNoContent, r.Code)
  152. }
  153. if containerRunning(eng, containerID, t) {
  154. t.Fatalf("The container hasn't been stopped")
  155. }
  156. req, err = http.NewRequest("POST", "/containers/"+containerID+"/stop?t=1", bytes.NewReader([]byte{}))
  157. if err != nil {
  158. t.Fatal(err)
  159. }
  160. r = httptest.NewRecorder()
  161. server.ServeRequest(eng, api.APIVERSION, r, req)
  162. // Stopping an already stopper container should return a 304
  163. assertHttpNotError(r, t)
  164. if r.Code != http.StatusNotModified {
  165. t.Fatalf("%d NOT MODIFIER expected, received %d\n", http.StatusNotModified, r.Code)
  166. }
  167. }
  168. func TestPostContainersWait(t *testing.T) {
  169. eng := NewTestEngine(t)
  170. defer mkDaemonFromEngine(eng, t).Nuke()
  171. containerID := createTestContainer(eng,
  172. &runconfig.Config{
  173. Image: unitTestImageID,
  174. Cmd: runconfig.NewCommand("/bin/sleep", "1"),
  175. OpenStdin: true,
  176. },
  177. t,
  178. )
  179. startContainer(eng, containerID, t)
  180. setTimeout(t, "Wait timed out", 3*time.Second, func() {
  181. r := httptest.NewRecorder()
  182. req, err := http.NewRequest("POST", "/containers/"+containerID+"/wait", bytes.NewReader([]byte{}))
  183. if err != nil {
  184. t.Fatal(err)
  185. }
  186. server.ServeRequest(eng, api.APIVERSION, r, req)
  187. assertHttpNotError(r, t)
  188. var apiWait engine.Env
  189. if err := apiWait.Decode(r.Body); err != nil {
  190. t.Fatal(err)
  191. }
  192. if apiWait.GetInt("StatusCode") != 0 {
  193. t.Fatalf("Non zero exit code for sleep: %d\n", apiWait.GetInt("StatusCode"))
  194. }
  195. })
  196. if containerRunning(eng, containerID, t) {
  197. t.Fatalf("The container should be stopped after wait")
  198. }
  199. }
  200. func TestPostContainersAttach(t *testing.T) {
  201. eng := NewTestEngine(t)
  202. defer mkDaemonFromEngine(eng, t).Nuke()
  203. containerID := createTestContainer(eng,
  204. &runconfig.Config{
  205. Image: unitTestImageID,
  206. Cmd: runconfig.NewCommand("/bin/cat"),
  207. OpenStdin: true,
  208. },
  209. t,
  210. )
  211. // Start the process
  212. startContainer(eng, containerID, t)
  213. stdin, stdinPipe := io.Pipe()
  214. stdout, stdoutPipe := io.Pipe()
  215. // Try to avoid the timeout in destroy. Best effort, don't check error
  216. defer func() {
  217. closeWrap(stdin, stdinPipe, stdout, stdoutPipe)
  218. containerKill(eng, containerID, t)
  219. }()
  220. // Attach to it
  221. c1 := make(chan struct{})
  222. go func() {
  223. defer close(c1)
  224. r := &hijackTester{
  225. ResponseRecorder: httptest.NewRecorder(),
  226. in: stdin,
  227. out: stdoutPipe,
  228. }
  229. req, err := http.NewRequest("POST", "/containers/"+containerID+"/attach?stream=1&stdin=1&stdout=1&stderr=1", bytes.NewReader([]byte{}))
  230. if err != nil {
  231. t.Fatal(err)
  232. }
  233. server.ServeRequest(eng, api.APIVERSION, r, req)
  234. assertHttpNotError(r.ResponseRecorder, t)
  235. }()
  236. // Acknowledge hijack
  237. setTimeout(t, "hijack acknowledge timed out", 2*time.Second, func() {
  238. stdout.Read([]byte{})
  239. stdout.Read(make([]byte, 4096))
  240. })
  241. setTimeout(t, "read/write assertion timed out", 2*time.Second, func() {
  242. if err := assertPipe("hello\n", string([]byte{1, 0, 0, 0, 0, 0, 0, 6})+"hello", stdout, stdinPipe, 150); err != nil {
  243. t.Fatal(err)
  244. }
  245. })
  246. // Close pipes (client disconnects)
  247. if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
  248. t.Fatal(err)
  249. }
  250. // Wait for attach to finish, the client disconnected, therefore, Attach finished his job
  251. setTimeout(t, "Waiting for CmdAttach timed out", 10*time.Second, func() {
  252. <-c1
  253. })
  254. // We closed stdin, expect /bin/cat to still be running
  255. // Wait a little bit to make sure container.monitor() did his thing
  256. containerWaitTimeout(eng, containerID, t)
  257. // Try to avoid the timeout in destroy. Best effort, don't check error
  258. cStdin, _ := containerAttach(eng, containerID, t)
  259. cStdin.Close()
  260. containerWait(eng, containerID, t)
  261. }
  262. func TestPostContainersAttachStderr(t *testing.T) {
  263. eng := NewTestEngine(t)
  264. defer mkDaemonFromEngine(eng, t).Nuke()
  265. containerID := createTestContainer(eng,
  266. &runconfig.Config{
  267. Image: unitTestImageID,
  268. Cmd: runconfig.NewCommand("/bin/sh", "-c", "/bin/cat >&2"),
  269. OpenStdin: true,
  270. },
  271. t,
  272. )
  273. // Start the process
  274. startContainer(eng, containerID, t)
  275. stdin, stdinPipe := io.Pipe()
  276. stdout, stdoutPipe := io.Pipe()
  277. // Try to avoid the timeout in destroy. Best effort, don't check error
  278. defer func() {
  279. closeWrap(stdin, stdinPipe, stdout, stdoutPipe)
  280. containerKill(eng, containerID, t)
  281. }()
  282. // Attach to it
  283. c1 := make(chan struct{})
  284. go func() {
  285. defer close(c1)
  286. r := &hijackTester{
  287. ResponseRecorder: httptest.NewRecorder(),
  288. in: stdin,
  289. out: stdoutPipe,
  290. }
  291. req, err := http.NewRequest("POST", "/containers/"+containerID+"/attach?stream=1&stdin=1&stdout=1&stderr=1", bytes.NewReader([]byte{}))
  292. if err != nil {
  293. t.Fatal(err)
  294. }
  295. server.ServeRequest(eng, api.APIVERSION, r, req)
  296. assertHttpNotError(r.ResponseRecorder, t)
  297. }()
  298. // Acknowledge hijack
  299. setTimeout(t, "hijack acknowledge timed out", 2*time.Second, func() {
  300. stdout.Read([]byte{})
  301. stdout.Read(make([]byte, 4096))
  302. })
  303. setTimeout(t, "read/write assertion timed out", 2*time.Second, func() {
  304. if err := assertPipe("hello\n", string([]byte{2, 0, 0, 0, 0, 0, 0, 6})+"hello", stdout, stdinPipe, 150); err != nil {
  305. t.Fatal(err)
  306. }
  307. })
  308. // Close pipes (client disconnects)
  309. if err := closeWrap(stdin, stdinPipe, stdout, stdoutPipe); err != nil {
  310. t.Fatal(err)
  311. }
  312. // Wait for attach to finish, the client disconnected, therefore, Attach finished his job
  313. setTimeout(t, "Waiting for CmdAttach timed out", 10*time.Second, func() {
  314. <-c1
  315. })
  316. // We closed stdin, expect /bin/cat to still be running
  317. // Wait a little bit to make sure container.monitor() did his thing
  318. containerWaitTimeout(eng, containerID, t)
  319. // Try to avoid the timeout in destroy. Best effort, don't check error
  320. cStdin, _ := containerAttach(eng, containerID, t)
  321. cStdin.Close()
  322. containerWait(eng, containerID, t)
  323. }
  324. func TestOptionsRoute(t *testing.T) {
  325. eng := NewTestEngine(t)
  326. defer mkDaemonFromEngine(eng, t).Nuke()
  327. r := httptest.NewRecorder()
  328. req, err := http.NewRequest("OPTIONS", "/", nil)
  329. if err != nil {
  330. t.Fatal(err)
  331. }
  332. server.ServeRequest(eng, api.APIVERSION, r, req)
  333. assertHttpNotError(r, t)
  334. if r.Code != http.StatusOK {
  335. t.Errorf("Expected response for OPTIONS request to be \"200\", %v found.", r.Code)
  336. }
  337. }
  338. func TestGetEnabledCors(t *testing.T) {
  339. eng := NewTestEngine(t)
  340. defer mkDaemonFromEngine(eng, t).Nuke()
  341. r := httptest.NewRecorder()
  342. req, err := http.NewRequest("GET", "/version", nil)
  343. if err != nil {
  344. t.Fatal(err)
  345. }
  346. server.ServeRequest(eng, api.APIVERSION, r, req)
  347. assertHttpNotError(r, t)
  348. if r.Code != http.StatusOK {
  349. t.Errorf("Expected response for OPTIONS request to be \"200\", %v found.", r.Code)
  350. }
  351. allowOrigin := r.Header().Get("Access-Control-Allow-Origin")
  352. allowHeaders := r.Header().Get("Access-Control-Allow-Headers")
  353. allowMethods := r.Header().Get("Access-Control-Allow-Methods")
  354. if allowOrigin != "*" {
  355. t.Errorf("Expected header Access-Control-Allow-Origin to be \"*\", %s found.", allowOrigin)
  356. }
  357. if allowHeaders != "Origin, X-Requested-With, Content-Type, Accept, X-Registry-Auth" {
  358. t.Errorf("Expected header Access-Control-Allow-Headers to be \"Origin, X-Requested-With, Content-Type, Accept, X-Registry-Auth\", %s found.", allowHeaders)
  359. }
  360. if allowMethods != "GET, POST, DELETE, PUT, OPTIONS" {
  361. t.Errorf("Expected hearder Access-Control-Allow-Methods to be \"GET, POST, DELETE, PUT, OPTIONS\", %s found.", allowMethods)
  362. }
  363. }
  364. func TestDeleteImages(t *testing.T) {
  365. eng := NewTestEngine(t)
  366. //we expect errors, so we disable stderr
  367. eng.Stderr = ioutil.Discard
  368. defer mkDaemonFromEngine(eng, t).Nuke()
  369. initialImages := getImages(eng, t, true, "")
  370. if err := eng.Job("tag", unitTestImageName, "test", "test").Run(); err != nil {
  371. t.Fatal(err)
  372. }
  373. images := getImages(eng, t, true, "")
  374. if len(images[0].RepoTags) != len(initialImages[0].RepoTags)+1 {
  375. t.Errorf("Expected %d images, %d found", len(initialImages[0].RepoTags)+1, len(images[0].RepoTags))
  376. }
  377. req, err := http.NewRequest("DELETE", "/images/"+unitTestImageID, nil)
  378. if err != nil {
  379. t.Fatal(err)
  380. }
  381. r := httptest.NewRecorder()
  382. server.ServeRequest(eng, api.APIVERSION, r, req)
  383. if r.Code != http.StatusConflict {
  384. t.Fatalf("Expected http status 409-conflict, got %v", r.Code)
  385. }
  386. req2, err := http.NewRequest("DELETE", "/images/test:test", nil)
  387. if err != nil {
  388. t.Fatal(err)
  389. }
  390. r2 := httptest.NewRecorder()
  391. server.ServeRequest(eng, api.APIVERSION, r2, req2)
  392. assertHttpNotError(r2, t)
  393. if r2.Code != http.StatusOK {
  394. t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
  395. }
  396. delImages := []types.ImageDelete{}
  397. err = json.Unmarshal(r2.Body.Bytes(), &delImages)
  398. if err != nil {
  399. t.Fatal(err)
  400. }
  401. if len(delImages) != 1 {
  402. t.Fatalf("Expected %d event (untagged), got %d", 1, len(delImages))
  403. }
  404. images = getImages(eng, t, false, "")
  405. if len(images) != len(initialImages) {
  406. t.Errorf("Expected %d image, %d found", len(initialImages), len(images))
  407. }
  408. }
  409. func TestPostContainersCopy(t *testing.T) {
  410. eng := NewTestEngine(t)
  411. defer mkDaemonFromEngine(eng, t).Nuke()
  412. // Create a container and remove a file
  413. containerID := createTestContainer(eng,
  414. &runconfig.Config{
  415. Image: unitTestImageID,
  416. Cmd: runconfig.NewCommand("touch", "/test.txt"),
  417. },
  418. t,
  419. )
  420. containerRun(eng, containerID, t)
  421. r := httptest.NewRecorder()
  422. var copyData engine.Env
  423. copyData.Set("Resource", "/test.txt")
  424. copyData.Set("HostPath", ".")
  425. jsonData := bytes.NewBuffer(nil)
  426. if err := copyData.Encode(jsonData); err != nil {
  427. t.Fatal(err)
  428. }
  429. req, err := http.NewRequest("POST", "/containers/"+containerID+"/copy", jsonData)
  430. if err != nil {
  431. t.Fatal(err)
  432. }
  433. req.Header.Add("Content-Type", "application/json")
  434. server.ServeRequest(eng, api.APIVERSION, r, req)
  435. assertHttpNotError(r, t)
  436. if r.Code != http.StatusOK {
  437. t.Fatalf("%d OK expected, received %d\n", http.StatusOK, r.Code)
  438. }
  439. found := false
  440. for tarReader := tar.NewReader(r.Body); ; {
  441. h, err := tarReader.Next()
  442. if err != nil {
  443. if err == io.EOF {
  444. break
  445. }
  446. t.Fatal(err)
  447. }
  448. if h.Name == "test.txt" {
  449. found = true
  450. break
  451. }
  452. }
  453. if !found {
  454. t.Fatalf("The created test file has not been found in the copied output")
  455. }
  456. }
  457. func TestPostContainersCopyWhenContainerNotFound(t *testing.T) {
  458. eng := NewTestEngine(t)
  459. defer mkDaemonFromEngine(eng, t).Nuke()
  460. r := httptest.NewRecorder()
  461. var copyData engine.Env
  462. copyData.Set("Resource", "/test.txt")
  463. copyData.Set("HostPath", ".")
  464. jsonData := bytes.NewBuffer(nil)
  465. if err := copyData.Encode(jsonData); err != nil {
  466. t.Fatal(err)
  467. }
  468. req, err := http.NewRequest("POST", "/containers/id_not_found/copy", jsonData)
  469. if err != nil {
  470. t.Fatal(err)
  471. }
  472. req.Header.Add("Content-Type", "application/json")
  473. server.ServeRequest(eng, api.APIVERSION, r, req)
  474. if r.Code != http.StatusNotFound {
  475. t.Fatalf("404 expected for id_not_found Container, received %v", r.Code)
  476. }
  477. }
  478. // Regression test for https://github.com/docker/docker/issues/6231
  479. func TestConstainersStartChunkedEncodingHostConfig(t *testing.T) {
  480. eng := NewTestEngine(t)
  481. defer mkDaemonFromEngine(eng, t).Nuke()
  482. r := httptest.NewRecorder()
  483. var testData engine.Env
  484. testData.Set("Image", "docker-test-image")
  485. testData.SetAuto("Volumes", map[string]struct{}{"/foo": {}})
  486. testData.Set("Cmd", "true")
  487. jsonData := bytes.NewBuffer(nil)
  488. if err := testData.Encode(jsonData); err != nil {
  489. t.Fatal(err)
  490. }
  491. req, err := http.NewRequest("POST", "/containers/create?name=chunk_test", jsonData)
  492. if err != nil {
  493. t.Fatal(err)
  494. }
  495. req.Header.Add("Content-Type", "application/json")
  496. server.ServeRequest(eng, api.APIVERSION, r, req)
  497. assertHttpNotError(r, t)
  498. var testData2 engine.Env
  499. testData2.SetAuto("Binds", []string{"/tmp:/foo"})
  500. jsonData = bytes.NewBuffer(nil)
  501. if err := testData2.Encode(jsonData); err != nil {
  502. t.Fatal(err)
  503. }
  504. req, err = http.NewRequest("POST", "/containers/chunk_test/start", jsonData)
  505. if err != nil {
  506. t.Fatal(err)
  507. }
  508. req.Header.Add("Content-Type", "application/json")
  509. // This is a cheat to make the http request do chunked encoding
  510. // Otherwise (just setting the Content-Encoding to chunked) net/http will overwrite
  511. // https://golang.org/src/pkg/net/http/request.go?s=11980:12172
  512. req.ContentLength = -1
  513. server.ServeRequest(eng, api.APIVERSION, r, req)
  514. assertHttpNotError(r, t)
  515. type config struct {
  516. HostConfig struct {
  517. Binds []string
  518. }
  519. }
  520. req, err = http.NewRequest("GET", "/containers/chunk_test/json", nil)
  521. if err != nil {
  522. t.Fatal(err)
  523. }
  524. r2 := httptest.NewRecorder()
  525. req.Header.Add("Content-Type", "application/json")
  526. server.ServeRequest(eng, api.APIVERSION, r2, req)
  527. assertHttpNotError(r, t)
  528. c := config{}
  529. json.Unmarshal(r2.Body.Bytes(), &c)
  530. if len(c.HostConfig.Binds) == 0 {
  531. t.Fatal("Chunked Encoding not handled")
  532. }
  533. if c.HostConfig.Binds[0] != "/tmp:/foo" {
  534. t.Fatal("Chunked encoding not properly handled, execpted binds to be /tmp:/foo, got:", c.HostConfig.Binds[0])
  535. }
  536. }
  537. // Mocked types for tests
  538. type NopConn struct {
  539. io.ReadCloser
  540. io.Writer
  541. }
  542. func (c *NopConn) LocalAddr() net.Addr { return nil }
  543. func (c *NopConn) RemoteAddr() net.Addr { return nil }
  544. func (c *NopConn) SetDeadline(t time.Time) error { return nil }
  545. func (c *NopConn) SetReadDeadline(t time.Time) error { return nil }
  546. func (c *NopConn) SetWriteDeadline(t time.Time) error { return nil }
  547. type hijackTester struct {
  548. *httptest.ResponseRecorder
  549. in io.ReadCloser
  550. out io.Writer
  551. }
  552. func (t *hijackTester) Hijack() (net.Conn, *bufio.ReadWriter, error) {
  553. bufrw := bufio.NewReadWriter(bufio.NewReader(t.in), bufio.NewWriter(t.out))
  554. conn := &NopConn{
  555. ReadCloser: t.in,
  556. Writer: t.out,
  557. }
  558. return conn, bufrw, nil
  559. }