image_pull_test.go 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200
  1. package client // import "github.com/docker/docker/client"
  2. import (
  3. "bytes"
  4. "context"
  5. "fmt"
  6. "io"
  7. "net/http"
  8. "strings"
  9. "testing"
  10. "github.com/docker/docker/api/types"
  11. "github.com/docker/docker/api/types/registry"
  12. "github.com/docker/docker/errdefs"
  13. )
  14. func TestImagePullReferenceParseError(t *testing.T) {
  15. client := &Client{
  16. client: newMockClient(func(req *http.Request) (*http.Response, error) {
  17. return nil, nil
  18. }),
  19. }
  20. // An empty reference is an invalid reference
  21. _, err := client.ImagePull(context.Background(), "", types.ImagePullOptions{})
  22. if err == nil || !strings.Contains(err.Error(), "invalid reference format") {
  23. t.Fatalf("expected an error, got %v", err)
  24. }
  25. }
  26. func TestImagePullAnyError(t *testing.T) {
  27. client := &Client{
  28. client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")),
  29. }
  30. _, err := client.ImagePull(context.Background(), "myimage", types.ImagePullOptions{})
  31. if !errdefs.IsSystem(err) {
  32. t.Fatalf("expected a Server Error, got %[1]T: %[1]v", err)
  33. }
  34. }
  35. func TestImagePullStatusUnauthorizedError(t *testing.T) {
  36. client := &Client{
  37. client: newMockClient(errorMock(http.StatusUnauthorized, "Unauthorized error")),
  38. }
  39. _, err := client.ImagePull(context.Background(), "myimage", types.ImagePullOptions{})
  40. if !errdefs.IsUnauthorized(err) {
  41. t.Fatalf("expected a Unauthorized Error, got %[1]T: %[1]v", err)
  42. }
  43. }
  44. func TestImagePullWithUnauthorizedErrorAndPrivilegeFuncError(t *testing.T) {
  45. client := &Client{
  46. client: newMockClient(errorMock(http.StatusUnauthorized, "Unauthorized error")),
  47. }
  48. privilegeFunc := func() (string, error) {
  49. return "", fmt.Errorf("Error requesting privilege")
  50. }
  51. _, err := client.ImagePull(context.Background(), "myimage", types.ImagePullOptions{
  52. PrivilegeFunc: privilegeFunc,
  53. })
  54. if err == nil || err.Error() != "Error requesting privilege" {
  55. t.Fatalf("expected an error requesting privilege, got %v", err)
  56. }
  57. }
  58. func TestImagePullWithUnauthorizedErrorAndAnotherUnauthorizedError(t *testing.T) {
  59. client := &Client{
  60. client: newMockClient(errorMock(http.StatusUnauthorized, "Unauthorized error")),
  61. }
  62. privilegeFunc := func() (string, error) {
  63. return "a-auth-header", nil
  64. }
  65. _, err := client.ImagePull(context.Background(), "myimage", types.ImagePullOptions{
  66. PrivilegeFunc: privilegeFunc,
  67. })
  68. if !errdefs.IsUnauthorized(err) {
  69. t.Fatalf("expected a Unauthorized Error, got %[1]T: %[1]v", err)
  70. }
  71. }
  72. func TestImagePullWithPrivilegedFuncNoError(t *testing.T) {
  73. expectedURL := "/images/create"
  74. client := &Client{
  75. client: newMockClient(func(req *http.Request) (*http.Response, error) {
  76. if !strings.HasPrefix(req.URL.Path, expectedURL) {
  77. return nil, fmt.Errorf("expected URL '%s', got '%s'", expectedURL, req.URL)
  78. }
  79. auth := req.Header.Get(registry.AuthHeader)
  80. if auth == "NotValid" {
  81. return &http.Response{
  82. StatusCode: http.StatusUnauthorized,
  83. Body: io.NopCloser(bytes.NewReader([]byte("Invalid credentials"))),
  84. }, nil
  85. }
  86. if auth != "IAmValid" {
  87. return nil, fmt.Errorf("invalid auth header: expected %s, got %s", "IAmValid", auth)
  88. }
  89. query := req.URL.Query()
  90. fromImage := query.Get("fromImage")
  91. if fromImage != "myimage" {
  92. return nil, fmt.Errorf("fromimage not set in URL query properly. Expected '%s', got %s", "myimage", fromImage)
  93. }
  94. tag := query.Get("tag")
  95. if tag != "latest" {
  96. return nil, fmt.Errorf("tag not set in URL query properly. Expected '%s', got %s", "latest", tag)
  97. }
  98. return &http.Response{
  99. StatusCode: http.StatusOK,
  100. Body: io.NopCloser(bytes.NewReader([]byte("hello world"))),
  101. }, nil
  102. }),
  103. }
  104. privilegeFunc := func() (string, error) {
  105. return "IAmValid", nil
  106. }
  107. resp, err := client.ImagePull(context.Background(), "myimage", types.ImagePullOptions{
  108. RegistryAuth: "NotValid",
  109. PrivilegeFunc: privilegeFunc,
  110. })
  111. if err != nil {
  112. t.Fatal(err)
  113. }
  114. body, err := io.ReadAll(resp)
  115. if err != nil {
  116. t.Fatal(err)
  117. }
  118. if string(body) != "hello world" {
  119. t.Fatalf("expected 'hello world', got %s", string(body))
  120. }
  121. }
  122. func TestImagePullWithoutErrors(t *testing.T) {
  123. expectedURL := "/images/create"
  124. expectedOutput := "hello world"
  125. pullCases := []struct {
  126. all bool
  127. reference string
  128. expectedImage string
  129. expectedTag string
  130. }{
  131. {
  132. all: false,
  133. reference: "myimage",
  134. expectedImage: "myimage",
  135. expectedTag: "latest",
  136. },
  137. {
  138. all: false,
  139. reference: "myimage:tag",
  140. expectedImage: "myimage",
  141. expectedTag: "tag",
  142. },
  143. {
  144. all: true,
  145. reference: "myimage",
  146. expectedImage: "myimage",
  147. expectedTag: "",
  148. },
  149. {
  150. all: true,
  151. reference: "myimage:anything",
  152. expectedImage: "myimage",
  153. expectedTag: "",
  154. },
  155. }
  156. for _, pullCase := range pullCases {
  157. client := &Client{
  158. client: newMockClient(func(req *http.Request) (*http.Response, error) {
  159. if !strings.HasPrefix(req.URL.Path, expectedURL) {
  160. return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL)
  161. }
  162. query := req.URL.Query()
  163. fromImage := query.Get("fromImage")
  164. if fromImage != pullCase.expectedImage {
  165. return nil, fmt.Errorf("fromimage not set in URL query properly. Expected '%s', got %s", pullCase.expectedImage, fromImage)
  166. }
  167. tag := query.Get("tag")
  168. if tag != pullCase.expectedTag {
  169. return nil, fmt.Errorf("tag not set in URL query properly. Expected '%s', got %s", pullCase.expectedTag, tag)
  170. }
  171. return &http.Response{
  172. StatusCode: http.StatusOK,
  173. Body: io.NopCloser(bytes.NewReader([]byte(expectedOutput))),
  174. }, nil
  175. }),
  176. }
  177. resp, err := client.ImagePull(context.Background(), pullCase.reference, types.ImagePullOptions{
  178. All: pullCase.all,
  179. })
  180. if err != nil {
  181. t.Fatal(err)
  182. }
  183. body, err := io.ReadAll(resp)
  184. if err != nil {
  185. t.Fatal(err)
  186. }
  187. if string(body) != expectedOutput {
  188. t.Fatalf("expected '%s', got %s", expectedOutput, string(body))
  189. }
  190. }
  191. }