image_build_test.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. package client
  2. import (
  3. "bytes"
  4. "fmt"
  5. "io/ioutil"
  6. "net/http"
  7. "reflect"
  8. "strings"
  9. "testing"
  10. "golang.org/x/net/context"
  11. "github.com/docker/docker/api/types"
  12. "github.com/docker/docker/api/types/container"
  13. "github.com/docker/go-units"
  14. )
  15. func TestImageBuildError(t *testing.T) {
  16. client := &Client{
  17. client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
  18. }
  19. _, err := client.ImageBuild(context.Background(), nil, types.ImageBuildOptions{})
  20. if err == nil || err.Error() != "Error response from daemon: Server error" {
  21. t.Fatalf("expected a Server Error, got %v", err)
  22. }
  23. }
  24. func TestImageBuild(t *testing.T) {
  25. v1 := "value1"
  26. v2 := "value2"
  27. emptyRegistryConfig := "bnVsbA=="
  28. buildCases := []struct {
  29. buildOptions types.ImageBuildOptions
  30. expectedQueryParams map[string]string
  31. expectedTags []string
  32. expectedRegistryConfig string
  33. }{
  34. {
  35. buildOptions: types.ImageBuildOptions{
  36. SuppressOutput: true,
  37. NoCache: true,
  38. Remove: true,
  39. ForceRemove: true,
  40. PullParent: true,
  41. },
  42. expectedQueryParams: map[string]string{
  43. "q": "1",
  44. "nocache": "1",
  45. "rm": "1",
  46. "forcerm": "1",
  47. "pull": "1",
  48. },
  49. expectedTags: []string{},
  50. expectedRegistryConfig: emptyRegistryConfig,
  51. },
  52. {
  53. buildOptions: types.ImageBuildOptions{
  54. SuppressOutput: false,
  55. NoCache: false,
  56. Remove: false,
  57. ForceRemove: false,
  58. PullParent: false,
  59. },
  60. expectedQueryParams: map[string]string{
  61. "q": "",
  62. "nocache": "",
  63. "rm": "0",
  64. "forcerm": "",
  65. "pull": "",
  66. },
  67. expectedTags: []string{},
  68. expectedRegistryConfig: emptyRegistryConfig,
  69. },
  70. {
  71. buildOptions: types.ImageBuildOptions{
  72. RemoteContext: "remoteContext",
  73. Isolation: container.Isolation("isolation"),
  74. CPUSetCPUs: "2",
  75. CPUSetMems: "12",
  76. CPUShares: 20,
  77. CPUQuota: 10,
  78. CPUPeriod: 30,
  79. Memory: 256,
  80. MemorySwap: 512,
  81. ShmSize: 10,
  82. CgroupParent: "cgroup_parent",
  83. Dockerfile: "Dockerfile",
  84. },
  85. expectedQueryParams: map[string]string{
  86. "remote": "remoteContext",
  87. "isolation": "isolation",
  88. "cpusetcpus": "2",
  89. "cpusetmems": "12",
  90. "cpushares": "20",
  91. "cpuquota": "10",
  92. "cpuperiod": "30",
  93. "memory": "256",
  94. "memswap": "512",
  95. "shmsize": "10",
  96. "cgroupparent": "cgroup_parent",
  97. "dockerfile": "Dockerfile",
  98. "rm": "0",
  99. },
  100. expectedTags: []string{},
  101. expectedRegistryConfig: emptyRegistryConfig,
  102. },
  103. {
  104. buildOptions: types.ImageBuildOptions{
  105. BuildArgs: map[string]*string{
  106. "ARG1": &v1,
  107. "ARG2": &v2,
  108. "ARG3": nil,
  109. },
  110. },
  111. expectedQueryParams: map[string]string{
  112. "buildargs": `{"ARG1":"value1","ARG2":"value2","ARG3":null}`,
  113. "rm": "0",
  114. },
  115. expectedTags: []string{},
  116. expectedRegistryConfig: emptyRegistryConfig,
  117. },
  118. {
  119. buildOptions: types.ImageBuildOptions{
  120. Ulimits: []*units.Ulimit{
  121. {
  122. Name: "nproc",
  123. Hard: 65557,
  124. Soft: 65557,
  125. },
  126. {
  127. Name: "nofile",
  128. Hard: 20000,
  129. Soft: 40000,
  130. },
  131. },
  132. },
  133. expectedQueryParams: map[string]string{
  134. "ulimits": `[{"Name":"nproc","Hard":65557,"Soft":65557},{"Name":"nofile","Hard":20000,"Soft":40000}]`,
  135. "rm": "0",
  136. },
  137. expectedTags: []string{},
  138. expectedRegistryConfig: emptyRegistryConfig,
  139. },
  140. {
  141. buildOptions: types.ImageBuildOptions{
  142. AuthConfigs: map[string]types.AuthConfig{
  143. "https://index.docker.io/v1/": {
  144. Auth: "dG90bwo=",
  145. },
  146. },
  147. },
  148. expectedQueryParams: map[string]string{
  149. "rm": "0",
  150. },
  151. expectedTags: []string{},
  152. expectedRegistryConfig: "eyJodHRwczovL2luZGV4LmRvY2tlci5pby92MS8iOnsiYXV0aCI6ImRHOTBid289In19",
  153. },
  154. }
  155. for _, buildCase := range buildCases {
  156. expectedURL := "/build"
  157. client := &Client{
  158. client: newMockClient(func(r *http.Request) (*http.Response, error) {
  159. if !strings.HasPrefix(r.URL.Path, expectedURL) {
  160. return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, r.URL)
  161. }
  162. // Check request headers
  163. registryConfig := r.Header.Get("X-Registry-Config")
  164. if registryConfig != buildCase.expectedRegistryConfig {
  165. return nil, fmt.Errorf("X-Registry-Config header not properly set in the request. Expected '%s', got %s", buildCase.expectedRegistryConfig, registryConfig)
  166. }
  167. contentType := r.Header.Get("Content-Type")
  168. if contentType != "application/tar" {
  169. return nil, fmt.Errorf("Content-type header not properly set in the request. Expected 'application/tar', got %s", contentType)
  170. }
  171. // Check query parameters
  172. query := r.URL.Query()
  173. for key, expected := range buildCase.expectedQueryParams {
  174. actual := query.Get(key)
  175. if actual != expected {
  176. return nil, fmt.Errorf("%s not set in URL query properly. Expected '%s', got %s", key, expected, actual)
  177. }
  178. }
  179. // Check tags
  180. if len(buildCase.expectedTags) > 0 {
  181. tags := query["t"]
  182. if !reflect.DeepEqual(tags, buildCase.expectedTags) {
  183. return nil, fmt.Errorf("t (tags) not set in URL query properly. Expected '%s', got %s", buildCase.expectedTags, tags)
  184. }
  185. }
  186. headers := http.Header{}
  187. headers.Add("Server", "Docker/v1.23 (MyOS)")
  188. return &http.Response{
  189. StatusCode: http.StatusOK,
  190. Body: ioutil.NopCloser(bytes.NewReader([]byte("body"))),
  191. Header: headers,
  192. }, nil
  193. }),
  194. }
  195. buildResponse, err := client.ImageBuild(context.Background(), nil, buildCase.buildOptions)
  196. if err != nil {
  197. t.Fatal(err)
  198. }
  199. if buildResponse.OSType != "MyOS" {
  200. t.Fatalf("expected OSType to be 'MyOS', got %s", buildResponse.OSType)
  201. }
  202. response, err := ioutil.ReadAll(buildResponse.Body)
  203. if err != nil {
  204. t.Fatal(err)
  205. }
  206. buildResponse.Body.Close()
  207. if string(response) != "body" {
  208. t.Fatalf("expected Body to contain 'body' string, got %s", response)
  209. }
  210. }
  211. }
  212. func TestGetDockerOS(t *testing.T) {
  213. cases := map[string]string{
  214. "Docker/v1.22 (linux)": "linux",
  215. "Docker/v1.22 (windows)": "windows",
  216. "Foo/v1.22 (bar)": "",
  217. }
  218. for header, os := range cases {
  219. g := getDockerOS(header)
  220. if g != os {
  221. t.Fatalf("Expected %s, got %s", os, g)
  222. }
  223. }
  224. }