github.com/rita33cool1/iot-system-gateway@v0.0.0-20200911033302-e65bde238cc5/docker-engine/integration-cli/docker_cli_cp_from_container_test.go (about)

     1  package main
     2  
     3  import (
     4  	"os"
     5  	"path/filepath"
     6  
     7  	"github.com/docker/docker/integration-cli/checker"
     8  	"github.com/go-check/check"
     9  )
    10  
    11  // Try all of the test cases from the archive package which implements the
    12  // internals of `docker cp` and ensure that the behavior matches when actually
    13  // copying to and from containers.
    14  
    15  // Basic assumptions about SRC and DST:
    16  // 1. SRC must exist.
    17  // 2. If SRC ends with a trailing separator, it must be a directory.
    18  // 3. DST parent directory must exist.
    19  // 4. If DST exists as a file, it must not end with a trailing separator.
    20  
    21  // Check that copying from a container to a local symlink copies to the symlink
    22  // target and does not overwrite the local symlink itself.
    23  // TODO: move to docker/cli and/or integration/container/copy_test.go
    24  func (s *DockerSuite) TestCpFromSymlinkDestination(c *check.C) {
    25  	testRequires(c, DaemonIsLinux)
    26  	containerID := makeTestContainer(c, testContainerOptions{addContent: true})
    27  
    28  	tmpDir := getTestDir(c, "test-cp-from-err-dst-not-dir")
    29  	defer os.RemoveAll(tmpDir)
    30  
    31  	makeTestContentInDir(c, tmpDir)
    32  
    33  	// First, copy a file from the container to a symlink to a file. This
    34  	// should overwrite the symlink target contents with the source contents.
    35  	srcPath := containerCpPath(containerID, "/file2")
    36  	dstPath := cpPath(tmpDir, "symlinkToFile1")
    37  
    38  	c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil)
    39  
    40  	// The symlink should not have been modified.
    41  	c.Assert(symlinkTargetEquals(c, dstPath, "file1"), checker.IsNil)
    42  
    43  	// The file should have the contents of "file2" now.
    44  	c.Assert(fileContentEquals(c, cpPath(tmpDir, "file1"), "file2\n"), checker.IsNil)
    45  
    46  	// Next, copy a file from the container to a symlink to a directory. This
    47  	// should copy the file into the symlink target directory.
    48  	dstPath = cpPath(tmpDir, "symlinkToDir1")
    49  
    50  	c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil)
    51  
    52  	// The symlink should not have been modified.
    53  	c.Assert(symlinkTargetEquals(c, dstPath, "dir1"), checker.IsNil)
    54  
    55  	// The file should have the contents of "file2" now.
    56  	c.Assert(fileContentEquals(c, cpPath(tmpDir, "file2"), "file2\n"), checker.IsNil)
    57  
    58  	// Next, copy a file from the container to a symlink to a file that does
    59  	// not exist (a broken symlink). This should create the target file with
    60  	// the contents of the source file.
    61  	dstPath = cpPath(tmpDir, "brokenSymlinkToFileX")
    62  
    63  	c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil)
    64  
    65  	// The symlink should not have been modified.
    66  	c.Assert(symlinkTargetEquals(c, dstPath, "fileX"), checker.IsNil)
    67  
    68  	// The file should have the contents of "file2" now.
    69  	c.Assert(fileContentEquals(c, cpPath(tmpDir, "fileX"), "file2\n"), checker.IsNil)
    70  
    71  	// Next, copy a directory from the container to a symlink to a local
    72  	// directory. This should copy the directory into the symlink target
    73  	// directory and not modify the symlink.
    74  	srcPath = containerCpPath(containerID, "/dir2")
    75  	dstPath = cpPath(tmpDir, "symlinkToDir1")
    76  
    77  	c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil)
    78  
    79  	// The symlink should not have been modified.
    80  	c.Assert(symlinkTargetEquals(c, dstPath, "dir1"), checker.IsNil)
    81  
    82  	// The directory should now contain a copy of "dir2".
    83  	c.Assert(fileContentEquals(c, cpPath(tmpDir, "dir1/dir2/file2-1"), "file2-1\n"), checker.IsNil)
    84  
    85  	// Next, copy a directory from the container to a symlink to a local
    86  	// directory that does not exist (a broken symlink). This should create
    87  	// the target as a directory with the contents of the source directory. It
    88  	// should not modify the symlink.
    89  	dstPath = cpPath(tmpDir, "brokenSymlinkToDirX")
    90  
    91  	c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil)
    92  
    93  	// The symlink should not have been modified.
    94  	c.Assert(symlinkTargetEquals(c, dstPath, "dirX"), checker.IsNil)
    95  
    96  	// The "dirX" directory should now be a copy of "dir2".
    97  	c.Assert(fileContentEquals(c, cpPath(tmpDir, "dirX/file2-1"), "file2-1\n"), checker.IsNil)
    98  }
    99  
   100  // Possibilities are reduced to the remaining 10 cases:
   101  //
   102  //  case | srcIsDir | onlyDirContents | dstExists | dstIsDir | dstTrSep | action
   103  // ===================================================================================================
   104  //   A   |  no      |  -              |  no       |  -       |  no      |  create file
   105  //   B   |  no      |  -              |  no       |  -       |  yes     |  error
   106  //   C   |  no      |  -              |  yes      |  no      |  -       |  overwrite file
   107  //   D   |  no      |  -              |  yes      |  yes     |  -       |  create file in dst dir
   108  //   E   |  yes     |  no             |  no       |  -       |  -       |  create dir, copy contents
   109  //   F   |  yes     |  no             |  yes      |  no      |  -       |  error
   110  //   G   |  yes     |  no             |  yes      |  yes     |  -       |  copy dir and contents
   111  //   H   |  yes     |  yes            |  no       |  -       |  -       |  create dir, copy contents
   112  //   I   |  yes     |  yes            |  yes      |  no      |  -       |  error
   113  //   J   |  yes     |  yes            |  yes      |  yes     |  -       |  copy dir contents
   114  //
   115  
   116  // A. SRC specifies a file and DST (no trailing path separator) doesn't
   117  //    exist. This should create a file with the name DST and copy the
   118  //    contents of the source file into it.
   119  func (s *DockerSuite) TestCpFromCaseA(c *check.C) {
   120  	testRequires(c, DaemonIsLinux)
   121  	containerID := makeTestContainer(c, testContainerOptions{
   122  		addContent: true, workDir: "/root",
   123  	})
   124  
   125  	tmpDir := getTestDir(c, "test-cp-from-case-a")
   126  	defer os.RemoveAll(tmpDir)
   127  
   128  	srcPath := containerCpPath(containerID, "/root/file1")
   129  	dstPath := cpPath(tmpDir, "itWorks.txt")
   130  
   131  	c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil)
   132  
   133  	c.Assert(fileContentEquals(c, dstPath, "file1\n"), checker.IsNil)
   134  }
   135  
   136  // B. SRC specifies a file and DST (with trailing path separator) doesn't
   137  //    exist. This should cause an error because the copy operation cannot
   138  //    create a directory when copying a single file.
   139  func (s *DockerSuite) TestCpFromCaseB(c *check.C) {
   140  	testRequires(c, DaemonIsLinux)
   141  	containerID := makeTestContainer(c, testContainerOptions{addContent: true})
   142  
   143  	tmpDir := getTestDir(c, "test-cp-from-case-b")
   144  	defer os.RemoveAll(tmpDir)
   145  
   146  	srcPath := containerCpPath(containerID, "/file1")
   147  	dstDir := cpPathTrailingSep(tmpDir, "testDir")
   148  
   149  	err := runDockerCp(c, srcPath, dstDir, nil)
   150  	c.Assert(err, checker.NotNil)
   151  
   152  	c.Assert(isCpDirNotExist(err), checker.True, check.Commentf("expected DirNotExists error, but got %T: %s", err, err))
   153  }
   154  
   155  // C. SRC specifies a file and DST exists as a file. This should overwrite
   156  //    the file at DST with the contents of the source file.
   157  func (s *DockerSuite) TestCpFromCaseC(c *check.C) {
   158  	testRequires(c, DaemonIsLinux)
   159  	containerID := makeTestContainer(c, testContainerOptions{
   160  		addContent: true, workDir: "/root",
   161  	})
   162  
   163  	tmpDir := getTestDir(c, "test-cp-from-case-c")
   164  	defer os.RemoveAll(tmpDir)
   165  
   166  	makeTestContentInDir(c, tmpDir)
   167  
   168  	srcPath := containerCpPath(containerID, "/root/file1")
   169  	dstPath := cpPath(tmpDir, "file2")
   170  
   171  	// Ensure the local file starts with different content.
   172  	c.Assert(fileContentEquals(c, dstPath, "file2\n"), checker.IsNil)
   173  
   174  	c.Assert(runDockerCp(c, srcPath, dstPath, nil), checker.IsNil)
   175  
   176  	c.Assert(fileContentEquals(c, dstPath, "file1\n"), checker.IsNil)
   177  }
   178  
   179  // D. SRC specifies a file and DST exists as a directory. This should place
   180  //    a copy of the source file inside it using the basename from SRC. Ensure
   181  //    this works whether DST has a trailing path separator or not.
   182  func (s *DockerSuite) TestCpFromCaseD(c *check.C) {
   183  	testRequires(c, DaemonIsLinux)
   184  	containerID := makeTestContainer(c, testContainerOptions{addContent: true})
   185  
   186  	tmpDir := getTestDir(c, "test-cp-from-case-d")
   187  	defer os.RemoveAll(tmpDir)
   188  
   189  	makeTestContentInDir(c, tmpDir)
   190  
   191  	srcPath := containerCpPath(containerID, "/file1")
   192  	dstDir := cpPath(tmpDir, "dir1")
   193  	dstPath := filepath.Join(dstDir, "file1")
   194  
   195  	// Ensure that dstPath doesn't exist.
   196  	_, err := os.Stat(dstPath)
   197  	c.Assert(os.IsNotExist(err), checker.True, check.Commentf("did not expect dstPath %q to exist", dstPath))
   198  
   199  	c.Assert(runDockerCp(c, srcPath, dstDir, nil), checker.IsNil)
   200  
   201  	c.Assert(fileContentEquals(c, dstPath, "file1\n"), checker.IsNil)
   202  
   203  	// Now try again but using a trailing path separator for dstDir.
   204  
   205  	// unable to remove dstDir
   206  	c.Assert(os.RemoveAll(dstDir), checker.IsNil)
   207  
   208  	// unable to make dstDir
   209  	c.Assert(os.MkdirAll(dstDir, os.FileMode(0755)), checker.IsNil)
   210  
   211  	dstDir = cpPathTrailingSep(tmpDir, "dir1")
   212  
   213  	c.Assert(runDockerCp(c, srcPath, dstDir, nil), checker.IsNil)
   214  
   215  	c.Assert(fileContentEquals(c, dstPath, "file1\n"), checker.IsNil)
   216  }
   217  
   218  // E. SRC specifies a directory and DST does not exist. This should create a
   219  //    directory at DST and copy the contents of the SRC directory into the DST
   220  //    directory. Ensure this works whether DST has a trailing path separator or
   221  //    not.
   222  func (s *DockerSuite) TestCpFromCaseE(c *check.C) {
   223  	testRequires(c, DaemonIsLinux)
   224  	containerID := makeTestContainer(c, testContainerOptions{addContent: true})
   225  
   226  	tmpDir := getTestDir(c, "test-cp-from-case-e")
   227  	defer os.RemoveAll(tmpDir)
   228  
   229  	srcDir := containerCpPath(containerID, "dir1")
   230  	dstDir := cpPath(tmpDir, "testDir")
   231  	dstPath := filepath.Join(dstDir, "file1-1")
   232  
   233  	c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil)
   234  
   235  	c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil)
   236  
   237  	// Now try again but using a trailing path separator for dstDir.
   238  
   239  	// unable to remove dstDir
   240  	c.Assert(os.RemoveAll(dstDir), checker.IsNil)
   241  
   242  	dstDir = cpPathTrailingSep(tmpDir, "testDir")
   243  
   244  	c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil)
   245  
   246  	c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil)
   247  }
   248  
   249  // F. SRC specifies a directory and DST exists as a file. This should cause an
   250  //    error as it is not possible to overwrite a file with a directory.
   251  func (s *DockerSuite) TestCpFromCaseF(c *check.C) {
   252  	testRequires(c, DaemonIsLinux)
   253  	containerID := makeTestContainer(c, testContainerOptions{
   254  		addContent: true, workDir: "/root",
   255  	})
   256  
   257  	tmpDir := getTestDir(c, "test-cp-from-case-f")
   258  	defer os.RemoveAll(tmpDir)
   259  
   260  	makeTestContentInDir(c, tmpDir)
   261  
   262  	srcDir := containerCpPath(containerID, "/root/dir1")
   263  	dstFile := cpPath(tmpDir, "file1")
   264  
   265  	err := runDockerCp(c, srcDir, dstFile, nil)
   266  	c.Assert(err, checker.NotNil)
   267  
   268  	c.Assert(isCpCannotCopyDir(err), checker.True, check.Commentf("expected ErrCannotCopyDir error, but got %T: %s", err, err))
   269  }
   270  
   271  // G. SRC specifies a directory and DST exists as a directory. This should copy
   272  //    the SRC directory and all its contents to the DST directory. Ensure this
   273  //    works whether DST has a trailing path separator or not.
   274  func (s *DockerSuite) TestCpFromCaseG(c *check.C) {
   275  	testRequires(c, DaemonIsLinux)
   276  	containerID := makeTestContainer(c, testContainerOptions{
   277  		addContent: true, workDir: "/root",
   278  	})
   279  
   280  	tmpDir := getTestDir(c, "test-cp-from-case-g")
   281  	defer os.RemoveAll(tmpDir)
   282  
   283  	makeTestContentInDir(c, tmpDir)
   284  
   285  	srcDir := containerCpPath(containerID, "/root/dir1")
   286  	dstDir := cpPath(tmpDir, "dir2")
   287  	resultDir := filepath.Join(dstDir, "dir1")
   288  	dstPath := filepath.Join(resultDir, "file1-1")
   289  
   290  	c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil)
   291  
   292  	c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil)
   293  
   294  	// Now try again but using a trailing path separator for dstDir.
   295  
   296  	// unable to remove dstDir
   297  	c.Assert(os.RemoveAll(dstDir), checker.IsNil)
   298  
   299  	// unable to make dstDir
   300  	c.Assert(os.MkdirAll(dstDir, os.FileMode(0755)), checker.IsNil)
   301  
   302  	dstDir = cpPathTrailingSep(tmpDir, "dir2")
   303  
   304  	c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil)
   305  
   306  	c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil)
   307  }
   308  
   309  // H. SRC specifies a directory's contents only and DST does not exist. This
   310  //    should create a directory at DST and copy the contents of the SRC
   311  //    directory (but not the directory itself) into the DST directory. Ensure
   312  //    this works whether DST has a trailing path separator or not.
   313  func (s *DockerSuite) TestCpFromCaseH(c *check.C) {
   314  	testRequires(c, DaemonIsLinux)
   315  	containerID := makeTestContainer(c, testContainerOptions{addContent: true})
   316  
   317  	tmpDir := getTestDir(c, "test-cp-from-case-h")
   318  	defer os.RemoveAll(tmpDir)
   319  
   320  	srcDir := containerCpPathTrailingSep(containerID, "dir1") + "."
   321  	dstDir := cpPath(tmpDir, "testDir")
   322  	dstPath := filepath.Join(dstDir, "file1-1")
   323  
   324  	c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil)
   325  
   326  	c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil)
   327  
   328  	// Now try again but using a trailing path separator for dstDir.
   329  
   330  	// unable to remove resultDir
   331  	c.Assert(os.RemoveAll(dstDir), checker.IsNil)
   332  
   333  	dstDir = cpPathTrailingSep(tmpDir, "testDir")
   334  
   335  	c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil)
   336  
   337  	c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil)
   338  }
   339  
   340  // I. SRC specifies a directory's contents only and DST exists as a file. This
   341  //    should cause an error as it is not possible to overwrite a file with a
   342  //    directory.
   343  func (s *DockerSuite) TestCpFromCaseI(c *check.C) {
   344  	testRequires(c, DaemonIsLinux)
   345  	containerID := makeTestContainer(c, testContainerOptions{
   346  		addContent: true, workDir: "/root",
   347  	})
   348  
   349  	tmpDir := getTestDir(c, "test-cp-from-case-i")
   350  	defer os.RemoveAll(tmpDir)
   351  
   352  	makeTestContentInDir(c, tmpDir)
   353  
   354  	srcDir := containerCpPathTrailingSep(containerID, "/root/dir1") + "."
   355  	dstFile := cpPath(tmpDir, "file1")
   356  
   357  	err := runDockerCp(c, srcDir, dstFile, nil)
   358  	c.Assert(err, checker.NotNil)
   359  
   360  	c.Assert(isCpCannotCopyDir(err), checker.True, check.Commentf("expected ErrCannotCopyDir error, but got %T: %s", err, err))
   361  }
   362  
   363  // J. SRC specifies a directory's contents only and DST exists as a directory.
   364  //    This should copy the contents of the SRC directory (but not the directory
   365  //    itself) into the DST directory. Ensure this works whether DST has a
   366  //    trailing path separator or not.
   367  func (s *DockerSuite) TestCpFromCaseJ(c *check.C) {
   368  	testRequires(c, DaemonIsLinux)
   369  	containerID := makeTestContainer(c, testContainerOptions{
   370  		addContent: true, workDir: "/root",
   371  	})
   372  
   373  	tmpDir := getTestDir(c, "test-cp-from-case-j")
   374  	defer os.RemoveAll(tmpDir)
   375  
   376  	makeTestContentInDir(c, tmpDir)
   377  
   378  	srcDir := containerCpPathTrailingSep(containerID, "/root/dir1") + "."
   379  	dstDir := cpPath(tmpDir, "dir2")
   380  	dstPath := filepath.Join(dstDir, "file1-1")
   381  
   382  	c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil)
   383  
   384  	c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil)
   385  
   386  	// Now try again but using a trailing path separator for dstDir.
   387  
   388  	// unable to remove dstDir
   389  	c.Assert(os.RemoveAll(dstDir), checker.IsNil)
   390  
   391  	// unable to make dstDir
   392  	c.Assert(os.MkdirAll(dstDir, os.FileMode(0755)), checker.IsNil)
   393  
   394  	dstDir = cpPathTrailingSep(tmpDir, "dir2")
   395  
   396  	c.Assert(runDockerCp(c, srcDir, dstDir, nil), checker.IsNil)
   397  
   398  	c.Assert(fileContentEquals(c, dstPath, "file1-1\n"), checker.IsNil)
   399  }