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