server_unit_test.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514
  1. package server
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "net/http"
  8. "net/http/httptest"
  9. "reflect"
  10. "strings"
  11. "testing"
  12. "github.com/docker/docker/api"
  13. "github.com/docker/docker/api/types"
  14. "github.com/docker/docker/engine"
  15. "github.com/docker/docker/pkg/version"
  16. )
  17. func TestGetBoolParam(t *testing.T) {
  18. if ret, err := getBoolParam("true"); err != nil || !ret {
  19. t.Fatalf("true -> true, nil | got %t %s", ret, err)
  20. }
  21. if ret, err := getBoolParam("True"); err != nil || !ret {
  22. t.Fatalf("True -> true, nil | got %t %s", ret, err)
  23. }
  24. if ret, err := getBoolParam("1"); err != nil || !ret {
  25. t.Fatalf("1 -> true, nil | got %t %s", ret, err)
  26. }
  27. if ret, err := getBoolParam(""); err != nil || ret {
  28. t.Fatalf("\"\" -> false, nil | got %t %s", ret, err)
  29. }
  30. if ret, err := getBoolParam("false"); err != nil || ret {
  31. t.Fatalf("false -> false, nil | got %t %s", ret, err)
  32. }
  33. if ret, err := getBoolParam("0"); err != nil || ret {
  34. t.Fatalf("0 -> false, nil | got %t %s", ret, err)
  35. }
  36. if ret, err := getBoolParam("faux"); err == nil || ret {
  37. t.Fatalf("faux -> false, err | got %t %s", ret, err)
  38. }
  39. }
  40. func TesthttpError(t *testing.T) {
  41. r := httptest.NewRecorder()
  42. httpError(r, fmt.Errorf("No such method"))
  43. if r.Code != http.StatusNotFound {
  44. t.Fatalf("Expected %d, got %d", http.StatusNotFound, r.Code)
  45. }
  46. httpError(r, fmt.Errorf("This accound hasn't been activated"))
  47. if r.Code != http.StatusForbidden {
  48. t.Fatalf("Expected %d, got %d", http.StatusForbidden, r.Code)
  49. }
  50. httpError(r, fmt.Errorf("Some error"))
  51. if r.Code != http.StatusInternalServerError {
  52. t.Fatalf("Expected %d, got %d", http.StatusInternalServerError, r.Code)
  53. }
  54. }
  55. func TestGetVersion(t *testing.T) {
  56. eng := engine.New()
  57. var called bool
  58. eng.Register("version", func(job *engine.Job) error {
  59. called = true
  60. v := &engine.Env{}
  61. v.SetJson("Version", "42.1")
  62. v.Set("ApiVersion", "1.1.1.1.1")
  63. v.Set("GoVersion", "2.42")
  64. v.Set("Os", "Linux")
  65. v.Set("Arch", "x86_64")
  66. if _, err := v.WriteTo(job.Stdout); err != nil {
  67. return err
  68. }
  69. return nil
  70. })
  71. r := serveRequest("GET", "/version", nil, eng, t)
  72. if !called {
  73. t.Fatalf("handler was not called")
  74. }
  75. v := readEnv(r.Body, t)
  76. if v.Get("Version") != "42.1" {
  77. t.Fatalf("%#v\n", v)
  78. }
  79. if r.HeaderMap.Get("Content-Type") != "application/json" {
  80. t.Fatalf("%#v\n", r)
  81. }
  82. }
  83. func TestGetInfo(t *testing.T) {
  84. eng := engine.New()
  85. var called bool
  86. eng.Register("info", func(job *engine.Job) error {
  87. called = true
  88. v := &engine.Env{}
  89. v.SetInt("Containers", 1)
  90. v.SetInt("Images", 42000)
  91. if _, err := v.WriteTo(job.Stdout); err != nil {
  92. return err
  93. }
  94. return nil
  95. })
  96. r := serveRequest("GET", "/info", nil, eng, t)
  97. if !called {
  98. t.Fatalf("handler was not called")
  99. }
  100. v := readEnv(r.Body, t)
  101. if v.GetInt("Images") != 42000 {
  102. t.Fatalf("%#v\n", v)
  103. }
  104. if v.GetInt("Containers") != 1 {
  105. t.Fatalf("%#v\n", v)
  106. }
  107. assertContentType(r, "application/json", t)
  108. }
  109. func TestGetImagesJSON(t *testing.T) {
  110. eng := engine.New()
  111. var called bool
  112. eng.Register("images", func(job *engine.Job) error {
  113. called = true
  114. v := createEnvFromGetImagesJSONStruct(sampleImage)
  115. if err := json.NewEncoder(job.Stdout).Encode(v); err != nil {
  116. return err
  117. }
  118. return nil
  119. })
  120. r := serveRequest("GET", "/images/json", nil, eng, t)
  121. if !called {
  122. t.Fatal("handler was not called")
  123. }
  124. assertHttpNotError(r, t)
  125. assertContentType(r, "application/json", t)
  126. var observed getImagesJSONStruct
  127. if err := json.Unmarshal(r.Body.Bytes(), &observed); err != nil {
  128. t.Fatal(err)
  129. }
  130. if !reflect.DeepEqual(observed, sampleImage) {
  131. t.Errorf("Expected %#v but got %#v", sampleImage, observed)
  132. }
  133. }
  134. func TestGetImagesJSONFilter(t *testing.T) {
  135. eng := engine.New()
  136. filter := "nothing"
  137. eng.Register("images", func(job *engine.Job) error {
  138. filter = job.Getenv("filter")
  139. return nil
  140. })
  141. serveRequest("GET", "/images/json?filter=aaaa", nil, eng, t)
  142. if filter != "aaaa" {
  143. t.Errorf("%#v", filter)
  144. }
  145. }
  146. func TestGetImagesJSONFilters(t *testing.T) {
  147. eng := engine.New()
  148. filter := "nothing"
  149. eng.Register("images", func(job *engine.Job) error {
  150. filter = job.Getenv("filters")
  151. return nil
  152. })
  153. serveRequest("GET", "/images/json?filters=nnnn", nil, eng, t)
  154. if filter != "nnnn" {
  155. t.Errorf("%#v", filter)
  156. }
  157. }
  158. func TestGetImagesJSONAll(t *testing.T) {
  159. eng := engine.New()
  160. allFilter := "-1"
  161. eng.Register("images", func(job *engine.Job) error {
  162. allFilter = job.Getenv("all")
  163. return nil
  164. })
  165. serveRequest("GET", "/images/json?all=1", nil, eng, t)
  166. if allFilter != "1" {
  167. t.Errorf("%#v", allFilter)
  168. }
  169. }
  170. func TestGetImagesJSONLegacyFormat(t *testing.T) {
  171. eng := engine.New()
  172. var called bool
  173. eng.Register("images", func(job *engine.Job) error {
  174. called = true
  175. images := []types.Image{
  176. createEnvFromGetImagesJSONStruct(sampleImage),
  177. }
  178. if err := json.NewEncoder(job.Stdout).Encode(images); err != nil {
  179. return err
  180. }
  181. return nil
  182. })
  183. r := serveRequestUsingVersion("GET", "/images/json", "1.6", nil, eng, t)
  184. if !called {
  185. t.Fatal("handler was not called")
  186. }
  187. assertHttpNotError(r, t)
  188. assertContentType(r, "application/json", t)
  189. images := engine.NewTable("Created", 0)
  190. if _, err := images.ReadListFrom(r.Body.Bytes()); err != nil {
  191. t.Fatal(err)
  192. }
  193. if images.Len() != 1 {
  194. t.Fatalf("Expected 1 image, %d found", images.Len())
  195. }
  196. image := images.Data[0]
  197. if image.Get("Tag") != "test-tag" {
  198. t.Errorf("Expected tag 'test-tag', found '%s'", image.Get("Tag"))
  199. }
  200. if image.Get("Repository") != "test-name" {
  201. t.Errorf("Expected repository 'test-name', found '%s'", image.Get("Repository"))
  202. }
  203. }
  204. func TestGetContainersByName(t *testing.T) {
  205. eng := engine.New()
  206. name := "container_name"
  207. var called bool
  208. eng.Register("container_inspect", func(job *engine.Job) error {
  209. called = true
  210. if job.Args[0] != name {
  211. t.Errorf("name != '%s': %#v", name, job.Args[0])
  212. }
  213. if api.APIVERSION.LessThan("1.12") && !job.GetenvBool("dirty") {
  214. t.Errorf("dirty env variable not set")
  215. } else if api.APIVERSION.GreaterThanOrEqualTo("1.12") && job.GetenvBool("dirty") {
  216. t.Errorf("dirty env variable set when it shouldn't")
  217. }
  218. v := &engine.Env{}
  219. v.SetBool("dirty", true)
  220. if _, err := v.WriteTo(job.Stdout); err != nil {
  221. return err
  222. }
  223. return nil
  224. })
  225. r := serveRequest("GET", "/containers/"+name+"/json", nil, eng, t)
  226. if !called {
  227. t.Fatal("handler was not called")
  228. }
  229. assertContentType(r, "application/json", t)
  230. var stdoutJson interface{}
  231. if err := json.Unmarshal(r.Body.Bytes(), &stdoutJson); err != nil {
  232. t.Fatalf("%#v", err)
  233. }
  234. if stdoutJson.(map[string]interface{})["dirty"].(float64) != 1 {
  235. t.Fatalf("%#v", stdoutJson)
  236. }
  237. }
  238. func TestLogs(t *testing.T) {
  239. eng := engine.New()
  240. var inspect bool
  241. var logs bool
  242. eng.Register("container_inspect", func(job *engine.Job) error {
  243. inspect = true
  244. if len(job.Args) == 0 {
  245. t.Fatal("Job arguments is empty")
  246. }
  247. if job.Args[0] != "test" {
  248. t.Fatalf("Container name %s, must be test", job.Args[0])
  249. }
  250. return nil
  251. })
  252. expected := "logs"
  253. eng.Register("logs", func(job *engine.Job) error {
  254. logs = true
  255. if len(job.Args) == 0 {
  256. t.Fatal("Job arguments is empty")
  257. }
  258. if job.Args[0] != "test" {
  259. t.Fatalf("Container name %s, must be test", job.Args[0])
  260. }
  261. follow := job.Getenv("follow")
  262. if follow != "1" {
  263. t.Fatalf("follow: %s, must be 1", follow)
  264. }
  265. stdout := job.Getenv("stdout")
  266. if stdout != "1" {
  267. t.Fatalf("stdout %s, must be 1", stdout)
  268. }
  269. stderr := job.Getenv("stderr")
  270. if stderr != "" {
  271. t.Fatalf("stderr %s, must be empty", stderr)
  272. }
  273. timestamps := job.Getenv("timestamps")
  274. if timestamps != "1" {
  275. t.Fatalf("timestamps %s, must be 1", timestamps)
  276. }
  277. job.Stdout.Write([]byte(expected))
  278. return nil
  279. })
  280. r := serveRequest("GET", "/containers/test/logs?follow=1&stdout=1&timestamps=1", nil, eng, t)
  281. if r.Code != http.StatusOK {
  282. t.Fatalf("Got status %d, expected %d", r.Code, http.StatusOK)
  283. }
  284. if !inspect {
  285. t.Fatal("container_inspect job was not called")
  286. }
  287. if !logs {
  288. t.Fatal("logs job was not called")
  289. }
  290. res := r.Body.String()
  291. if res != expected {
  292. t.Fatalf("Output %s, expected %s", res, expected)
  293. }
  294. }
  295. func TestLogsNoStreams(t *testing.T) {
  296. eng := engine.New()
  297. var inspect bool
  298. var logs bool
  299. eng.Register("container_inspect", func(job *engine.Job) error {
  300. inspect = true
  301. if len(job.Args) == 0 {
  302. t.Fatal("Job arguments is empty")
  303. }
  304. if job.Args[0] != "test" {
  305. t.Fatalf("Container name %s, must be test", job.Args[0])
  306. }
  307. return nil
  308. })
  309. eng.Register("logs", func(job *engine.Job) error {
  310. logs = true
  311. return nil
  312. })
  313. r := serveRequest("GET", "/containers/test/logs", nil, eng, t)
  314. if r.Code != http.StatusBadRequest {
  315. t.Fatalf("Got status %d, expected %d", r.Code, http.StatusBadRequest)
  316. }
  317. if inspect {
  318. t.Fatal("container_inspect job was called, but it shouldn't")
  319. }
  320. if logs {
  321. t.Fatal("logs job was called, but it shouldn't")
  322. }
  323. res := strings.TrimSpace(r.Body.String())
  324. expected := "Bad parameters: you must choose at least one stream"
  325. if !strings.Contains(res, expected) {
  326. t.Fatalf("Output %s, expected %s in it", res, expected)
  327. }
  328. }
  329. func TestGetImagesHistory(t *testing.T) {
  330. eng := engine.New()
  331. imageName := "docker-test-image"
  332. var called bool
  333. eng.Register("history", func(job *engine.Job) error {
  334. called = true
  335. if len(job.Args) == 0 {
  336. t.Fatal("Job arguments is empty")
  337. }
  338. if job.Args[0] != imageName {
  339. t.Fatalf("name != '%s': %#v", imageName, job.Args[0])
  340. }
  341. v := &engine.Env{}
  342. if _, err := v.WriteTo(job.Stdout); err != nil {
  343. return err
  344. }
  345. return nil
  346. })
  347. r := serveRequest("GET", "/images/"+imageName+"/history", nil, eng, t)
  348. if !called {
  349. t.Fatalf("handler was not called")
  350. }
  351. if r.Code != http.StatusOK {
  352. t.Fatalf("Got status %d, expected %d", r.Code, http.StatusOK)
  353. }
  354. if r.HeaderMap.Get("Content-Type") != "application/json" {
  355. t.Fatalf("%#v\n", r)
  356. }
  357. }
  358. func TestGetImagesByName(t *testing.T) {
  359. eng := engine.New()
  360. name := "image_name"
  361. var called bool
  362. eng.Register("image_inspect", func(job *engine.Job) error {
  363. called = true
  364. if job.Args[0] != name {
  365. t.Fatalf("name != '%s': %#v", name, job.Args[0])
  366. }
  367. if api.APIVERSION.LessThan("1.12") && !job.GetenvBool("dirty") {
  368. t.Fatal("dirty env variable not set")
  369. } else if api.APIVERSION.GreaterThanOrEqualTo("1.12") && job.GetenvBool("dirty") {
  370. t.Fatal("dirty env variable set when it shouldn't")
  371. }
  372. v := &engine.Env{}
  373. v.SetBool("dirty", true)
  374. if _, err := v.WriteTo(job.Stdout); err != nil {
  375. return err
  376. }
  377. return nil
  378. })
  379. r := serveRequest("GET", "/images/"+name+"/json", nil, eng, t)
  380. if !called {
  381. t.Fatal("handler was not called")
  382. }
  383. if r.HeaderMap.Get("Content-Type") != "application/json" {
  384. t.Fatalf("%#v\n", r)
  385. }
  386. var stdoutJson interface{}
  387. if err := json.Unmarshal(r.Body.Bytes(), &stdoutJson); err != nil {
  388. t.Fatalf("%#v", err)
  389. }
  390. if stdoutJson.(map[string]interface{})["dirty"].(float64) != 1 {
  391. t.Fatalf("%#v", stdoutJson)
  392. }
  393. }
  394. func TestDeleteContainers(t *testing.T) {
  395. eng := engine.New()
  396. name := "foo"
  397. var called bool
  398. eng.Register("rm", func(job *engine.Job) error {
  399. called = true
  400. if len(job.Args) == 0 {
  401. t.Fatalf("Job arguments is empty")
  402. }
  403. if job.Args[0] != name {
  404. t.Fatalf("name != '%s': %#v", name, job.Args[0])
  405. }
  406. return nil
  407. })
  408. r := serveRequest("DELETE", "/containers/"+name, nil, eng, t)
  409. if !called {
  410. t.Fatalf("handler was not called")
  411. }
  412. if r.Code != http.StatusNoContent {
  413. t.Fatalf("Got status %d, expected %d", r.Code, http.StatusNoContent)
  414. }
  415. }
  416. func serveRequest(method, target string, body io.Reader, eng *engine.Engine, t *testing.T) *httptest.ResponseRecorder {
  417. return serveRequestUsingVersion(method, target, api.APIVERSION, body, eng, t)
  418. }
  419. func serveRequestUsingVersion(method, target string, version version.Version, body io.Reader, eng *engine.Engine, t *testing.T) *httptest.ResponseRecorder {
  420. r := httptest.NewRecorder()
  421. req, err := http.NewRequest(method, target, body)
  422. if err != nil {
  423. t.Fatal(err)
  424. }
  425. ServeRequest(eng, version, r, req)
  426. return r
  427. }
  428. func readEnv(src io.Reader, t *testing.T) *engine.Env {
  429. out := engine.NewOutput()
  430. v, err := out.AddEnv()
  431. if err != nil {
  432. t.Fatal(err)
  433. }
  434. if _, err := io.Copy(out, src); err != nil {
  435. t.Fatal(err)
  436. }
  437. out.Close()
  438. return v
  439. }
  440. func toJson(data interface{}, t *testing.T) io.Reader {
  441. var buf bytes.Buffer
  442. if err := json.NewEncoder(&buf).Encode(data); err != nil {
  443. t.Fatal(err)
  444. }
  445. return &buf
  446. }
  447. func assertContentType(recorder *httptest.ResponseRecorder, contentType string, t *testing.T) {
  448. if recorder.HeaderMap.Get("Content-Type") != contentType {
  449. t.Fatalf("%#v\n", recorder)
  450. }
  451. }
  452. // XXX: Duplicated from integration/utils_test.go, but maybe that's OK as that
  453. // should die as soon as we converted all integration tests?
  454. // assertHttpNotError expect the given response to not have an error.
  455. // Otherwise the it causes the test to fail.
  456. func assertHttpNotError(r *httptest.ResponseRecorder, t *testing.T) {
  457. // Non-error http status are [200, 400)
  458. if r.Code < http.StatusOK || r.Code >= http.StatusBadRequest {
  459. t.Fatal(fmt.Errorf("Unexpected http error: %v", r.Code))
  460. }
  461. }
  462. func createEnvFromGetImagesJSONStruct(data getImagesJSONStruct) types.Image {
  463. return types.Image{
  464. RepoTags: data.RepoTags,
  465. ID: data.Id,
  466. Created: int(data.Created),
  467. Size: int(data.Size),
  468. VirtualSize: int(data.VirtualSize),
  469. }
  470. }
  471. type getImagesJSONStruct struct {
  472. RepoTags []string
  473. Id string
  474. Created int64
  475. Size int64
  476. VirtualSize int64
  477. }
  478. var sampleImage getImagesJSONStruct = getImagesJSONStruct{
  479. RepoTags: []string{"test-name:test-tag"},
  480. Id: "ID",
  481. Created: 999,
  482. Size: 777,
  483. VirtualSize: 666,
  484. }