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  }