api_test.go 22 KB

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