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