github.com/rish1988/moby@v25.0.2+incompatible/client/container_copy_test.go (about) 1 package client // import "github.com/docker/docker/client" 2 3 import ( 4 "bytes" 5 "context" 6 "encoding/base64" 7 "encoding/json" 8 "fmt" 9 "io" 10 "net/http" 11 "strings" 12 "testing" 13 14 "github.com/docker/docker/api/types" 15 "github.com/docker/docker/errdefs" 16 "gotest.tools/v3/assert" 17 is "gotest.tools/v3/assert/cmp" 18 ) 19 20 func TestContainerStatPathError(t *testing.T) { 21 client := &Client{ 22 client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 23 } 24 _, err := client.ContainerStatPath(context.Background(), "container_id", "path") 25 assert.Check(t, is.ErrorType(err, errdefs.IsSystem)) 26 } 27 28 func TestContainerStatPathNotFoundError(t *testing.T) { 29 client := &Client{ 30 client: newMockClient(errorMock(http.StatusNotFound, "Not found")), 31 } 32 _, err := client.ContainerStatPath(context.Background(), "container_id", "path") 33 assert.Check(t, is.ErrorType(err, errdefs.IsNotFound)) 34 } 35 36 func TestContainerStatPathNoHeaderError(t *testing.T) { 37 client := &Client{ 38 client: newMockClient(func(req *http.Request) (*http.Response, error) { 39 return &http.Response{ 40 StatusCode: http.StatusOK, 41 Body: io.NopCloser(bytes.NewReader([]byte(""))), 42 }, nil 43 }), 44 } 45 _, err := client.ContainerStatPath(context.Background(), "container_id", "path/to/file") 46 if err == nil { 47 t.Fatalf("expected an error, got nothing") 48 } 49 } 50 51 func TestContainerStatPath(t *testing.T) { 52 expectedURL := "/containers/container_id/archive" 53 expectedPath := "path/to/file" 54 client := &Client{ 55 client: newMockClient(func(req *http.Request) (*http.Response, error) { 56 if !strings.HasPrefix(req.URL.Path, expectedURL) { 57 return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 58 } 59 if req.Method != http.MethodHead { 60 return nil, fmt.Errorf("expected HEAD method, got %s", req.Method) 61 } 62 query := req.URL.Query() 63 path := query.Get("path") 64 if path != expectedPath { 65 return nil, fmt.Errorf("path not set in URL query properly") 66 } 67 content, err := json.Marshal(types.ContainerPathStat{ 68 Name: "name", 69 Mode: 0o700, 70 }) 71 if err != nil { 72 return nil, err 73 } 74 base64PathStat := base64.StdEncoding.EncodeToString(content) 75 return &http.Response{ 76 StatusCode: http.StatusOK, 77 Body: io.NopCloser(bytes.NewReader([]byte(""))), 78 Header: http.Header{ 79 "X-Docker-Container-Path-Stat": []string{base64PathStat}, 80 }, 81 }, nil 82 }), 83 } 84 stat, err := client.ContainerStatPath(context.Background(), "container_id", expectedPath) 85 if err != nil { 86 t.Fatal(err) 87 } 88 if stat.Name != "name" { 89 t.Fatalf("expected container path stat name to be 'name', got '%s'", stat.Name) 90 } 91 if stat.Mode != 0o700 { 92 t.Fatalf("expected container path stat mode to be 0700, got '%v'", stat.Mode) 93 } 94 } 95 96 func TestCopyToContainerError(t *testing.T) { 97 client := &Client{ 98 client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 99 } 100 err := client.CopyToContainer(context.Background(), "container_id", "path/to/file", bytes.NewReader([]byte("")), types.CopyToContainerOptions{}) 101 assert.Check(t, is.ErrorType(err, errdefs.IsSystem)) 102 } 103 104 func TestCopyToContainerNotFoundError(t *testing.T) { 105 client := &Client{ 106 client: newMockClient(errorMock(http.StatusNotFound, "Not found")), 107 } 108 err := client.CopyToContainer(context.Background(), "container_id", "path/to/file", bytes.NewReader([]byte("")), types.CopyToContainerOptions{}) 109 assert.Check(t, is.ErrorType(err, errdefs.IsNotFound)) 110 } 111 112 // TestCopyToContainerEmptyResponse verifies that no error is returned when a 113 // "204 No Content" is returned by the API. 114 func TestCopyToContainerEmptyResponse(t *testing.T) { 115 client := &Client{ 116 client: newMockClient(errorMock(http.StatusNoContent, "No content")), 117 } 118 err := client.CopyToContainer(context.Background(), "container_id", "path/to/file", bytes.NewReader([]byte("")), types.CopyToContainerOptions{}) 119 if err != nil { 120 t.Fatalf("unexpected error: %v", err) 121 } 122 } 123 124 func TestCopyToContainer(t *testing.T) { 125 expectedURL := "/containers/container_id/archive" 126 expectedPath := "path/to/file" 127 client := &Client{ 128 client: newMockClient(func(req *http.Request) (*http.Response, error) { 129 if !strings.HasPrefix(req.URL.Path, expectedURL) { 130 return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 131 } 132 if req.Method != http.MethodPut { 133 return nil, fmt.Errorf("expected PUT method, got %s", req.Method) 134 } 135 query := req.URL.Query() 136 path := query.Get("path") 137 if path != expectedPath { 138 return nil, fmt.Errorf("path not set in URL query properly, expected '%s', got %s", expectedPath, path) 139 } 140 noOverwriteDirNonDir := query.Get("noOverwriteDirNonDir") 141 if noOverwriteDirNonDir != "true" { 142 return nil, fmt.Errorf("noOverwriteDirNonDir not set in URL query properly, expected true, got %s", noOverwriteDirNonDir) 143 } 144 145 content, err := io.ReadAll(req.Body) 146 if err != nil { 147 return nil, err 148 } 149 if err := req.Body.Close(); err != nil { 150 return nil, err 151 } 152 if string(content) != "content" { 153 return nil, fmt.Errorf("expected content to be 'content', got %s", string(content)) 154 } 155 156 return &http.Response{ 157 StatusCode: http.StatusOK, 158 Body: io.NopCloser(bytes.NewReader([]byte(""))), 159 }, nil 160 }), 161 } 162 err := client.CopyToContainer(context.Background(), "container_id", expectedPath, bytes.NewReader([]byte("content")), types.CopyToContainerOptions{ 163 AllowOverwriteDirWithFile: false, 164 }) 165 if err != nil { 166 t.Fatal(err) 167 } 168 } 169 170 func TestCopyFromContainerError(t *testing.T) { 171 client := &Client{ 172 client: newMockClient(errorMock(http.StatusInternalServerError, "Server error")), 173 } 174 _, _, err := client.CopyFromContainer(context.Background(), "container_id", "path/to/file") 175 assert.Check(t, is.ErrorType(err, errdefs.IsSystem)) 176 } 177 178 func TestCopyFromContainerNotFoundError(t *testing.T) { 179 client := &Client{ 180 client: newMockClient(errorMock(http.StatusNotFound, "Not found")), 181 } 182 _, _, err := client.CopyFromContainer(context.Background(), "container_id", "path/to/file") 183 assert.Check(t, is.ErrorType(err, errdefs.IsNotFound)) 184 } 185 186 // TestCopyFromContainerEmptyResponse verifies that no error is returned when a 187 // "204 No Content" is returned by the API. 188 func TestCopyFromContainerEmptyResponse(t *testing.T) { 189 client := &Client{ 190 client: newMockClient(func(req *http.Request) (*http.Response, error) { 191 content, err := json.Marshal(types.ContainerPathStat{ 192 Name: "path/to/file", 193 Mode: 0o700, 194 }) 195 if err != nil { 196 return nil, err 197 } 198 base64PathStat := base64.StdEncoding.EncodeToString(content) 199 return &http.Response{ 200 StatusCode: http.StatusNoContent, 201 Header: http.Header{ 202 "X-Docker-Container-Path-Stat": []string{base64PathStat}, 203 }, 204 }, nil 205 }), 206 } 207 _, _, err := client.CopyFromContainer(context.Background(), "container_id", "path/to/file") 208 if err != nil { 209 t.Fatalf("unexpected error: %v", err) 210 } 211 } 212 213 func TestCopyFromContainerNoHeaderError(t *testing.T) { 214 client := &Client{ 215 client: newMockClient(func(req *http.Request) (*http.Response, error) { 216 return &http.Response{ 217 StatusCode: http.StatusOK, 218 Body: io.NopCloser(bytes.NewReader([]byte(""))), 219 }, nil 220 }), 221 } 222 _, _, err := client.CopyFromContainer(context.Background(), "container_id", "path/to/file") 223 if err == nil { 224 t.Fatalf("expected an error, got nothing") 225 } 226 } 227 228 func TestCopyFromContainer(t *testing.T) { 229 expectedURL := "/containers/container_id/archive" 230 expectedPath := "path/to/file" 231 client := &Client{ 232 client: newMockClient(func(req *http.Request) (*http.Response, error) { 233 if !strings.HasPrefix(req.URL.Path, expectedURL) { 234 return nil, fmt.Errorf("Expected URL '%s', got '%s'", expectedURL, req.URL) 235 } 236 if req.Method != http.MethodGet { 237 return nil, fmt.Errorf("expected GET method, got %s", req.Method) 238 } 239 query := req.URL.Query() 240 path := query.Get("path") 241 if path != expectedPath { 242 return nil, fmt.Errorf("path not set in URL query properly, expected '%s', got %s", expectedPath, path) 243 } 244 245 headercontent, err := json.Marshal(types.ContainerPathStat{ 246 Name: "name", 247 Mode: 0o700, 248 }) 249 if err != nil { 250 return nil, err 251 } 252 base64PathStat := base64.StdEncoding.EncodeToString(headercontent) 253 254 return &http.Response{ 255 StatusCode: http.StatusOK, 256 Body: io.NopCloser(bytes.NewReader([]byte("content"))), 257 Header: http.Header{ 258 "X-Docker-Container-Path-Stat": []string{base64PathStat}, 259 }, 260 }, nil 261 }), 262 } 263 r, stat, err := client.CopyFromContainer(context.Background(), "container_id", expectedPath) 264 if err != nil { 265 t.Fatal(err) 266 } 267 if stat.Name != "name" { 268 t.Fatalf("expected container path stat name to be 'name', got '%s'", stat.Name) 269 } 270 if stat.Mode != 0o700 { 271 t.Fatalf("expected container path stat mode to be 0700, got '%v'", stat.Mode) 272 } 273 content, err := io.ReadAll(r) 274 if err != nil { 275 t.Fatal(err) 276 } 277 if err := r.Close(); err != nil { 278 t.Fatal(err) 279 } 280 if string(content) != "content" { 281 t.Fatalf("expected content to be 'content', got %s", string(content)) 282 } 283 }