github.com/rentongzhang/docker@v1.8.2-rc1/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/go-check/check"
     8  )
     9  
    10  // docker cp CONTAINER:PATH LOCALPATH
    11  
    12  // Try all of the test cases from the archive package which implements the
    13  // internals of `docker cp` and ensure that the behavior matches when actually
    14  // copying to and from containers.
    15  
    16  // Basic assumptions about SRC and DST:
    17  // 1. SRC must exist.
    18  // 2. If SRC ends with a trailing separator, it must be a directory.
    19  // 3. DST parent directory must exist.
    20  // 4. If DST exists as a file, it must not end with a trailing separator.
    21  
    22  // First get these easy error cases out of the way.
    23  
    24  // Test for error when SRC does not exist.
    25  func (s *DockerSuite) TestCpFromErrSrcNotExists(c *check.C) {
    26  	cID := makeTestContainer(c, testContainerOptions{})
    27  	defer deleteContainer(cID)
    28  
    29  	tmpDir := getTestDir(c, "test-cp-from-err-src-not-exists")
    30  	defer os.RemoveAll(tmpDir)
    31  
    32  	err := runDockerCp(c, containerCpPath(cID, "file1"), tmpDir)
    33  	if err == nil {
    34  		c.Fatal("expected IsNotExist error, but got nil instead")
    35  	}
    36  
    37  	if !isCpNotExist(err) {
    38  		c.Fatalf("expected IsNotExist error, but got %T: %s", err, err)
    39  	}
    40  }
    41  
    42  // Test for error when SRC ends in a trailing
    43  // path separator but it exists as a file.
    44  func (s *DockerSuite) TestCpFromErrSrcNotDir(c *check.C) {
    45  	cID := makeTestContainer(c, testContainerOptions{addContent: true})
    46  	defer deleteContainer(cID)
    47  
    48  	tmpDir := getTestDir(c, "test-cp-from-err-src-not-dir")
    49  	defer os.RemoveAll(tmpDir)
    50  
    51  	err := runDockerCp(c, containerCpPathTrailingSep(cID, "file1"), tmpDir)
    52  	if err == nil {
    53  		c.Fatal("expected IsNotDir error, but got nil instead")
    54  	}
    55  
    56  	if !isCpNotDir(err) {
    57  		c.Fatalf("expected IsNotDir error, but got %T: %s", err, err)
    58  	}
    59  }
    60  
    61  // Test for error when SRC is a valid file or directory,
    62  // bu the DST parent directory does not exist.
    63  func (s *DockerSuite) TestCpFromErrDstParentNotExists(c *check.C) {
    64  	cID := makeTestContainer(c, testContainerOptions{addContent: true})
    65  	defer deleteContainer(cID)
    66  
    67  	tmpDir := getTestDir(c, "test-cp-from-err-dst-parent-not-exists")
    68  	defer os.RemoveAll(tmpDir)
    69  
    70  	makeTestContentInDir(c, tmpDir)
    71  
    72  	// Try with a file source.
    73  	srcPath := containerCpPath(cID, "/file1")
    74  	dstPath := cpPath(tmpDir, "notExists", "file1")
    75  
    76  	err := runDockerCp(c, srcPath, dstPath)
    77  	if err == nil {
    78  		c.Fatal("expected IsNotExist error, but got nil instead")
    79  	}
    80  
    81  	if !isCpNotExist(err) {
    82  		c.Fatalf("expected IsNotExist error, but got %T: %s", err, err)
    83  	}
    84  
    85  	// Try with a directory source.
    86  	srcPath = containerCpPath(cID, "/dir1")
    87  
    88  	if err := runDockerCp(c, srcPath, dstPath); err == nil {
    89  		c.Fatal("expected IsNotExist error, but got nil instead")
    90  	}
    91  
    92  	if !isCpNotExist(err) {
    93  		c.Fatalf("expected IsNotExist error, but got %T: %s", err, err)
    94  	}
    95  }
    96  
    97  // Test for error when DST ends in a trailing
    98  // path separator but exists as a file.
    99  func (s *DockerSuite) TestCpFromErrDstNotDir(c *check.C) {
   100  	cID := makeTestContainer(c, testContainerOptions{addContent: true})
   101  	defer deleteContainer(cID)
   102  
   103  	tmpDir := getTestDir(c, "test-cp-from-err-dst-not-dir")
   104  	defer os.RemoveAll(tmpDir)
   105  
   106  	makeTestContentInDir(c, tmpDir)
   107  
   108  	// Try with a file source.
   109  	srcPath := containerCpPath(cID, "/file1")
   110  	dstPath := cpPathTrailingSep(tmpDir, "file1")
   111  
   112  	err := runDockerCp(c, srcPath, dstPath)
   113  	if err == nil {
   114  		c.Fatal("expected IsNotDir error, but got nil instead")
   115  	}
   116  
   117  	if !isCpNotDir(err) {
   118  		c.Fatalf("expected IsNotDir error, but got %T: %s", err, err)
   119  	}
   120  
   121  	// Try with a directory source.
   122  	srcPath = containerCpPath(cID, "/dir1")
   123  
   124  	if err := runDockerCp(c, srcPath, dstPath); err == nil {
   125  		c.Fatal("expected IsNotDir error, but got nil instead")
   126  	}
   127  
   128  	if !isCpNotDir(err) {
   129  		c.Fatalf("expected IsNotDir error, but got %T: %s", err, err)
   130  	}
   131  }
   132  
   133  // Check that copying from a container to a local symlink copies to the symlink
   134  // target and does not overwrite the local symlink itself.
   135  func (s *DockerSuite) TestCpFromSymlinkDestination(c *check.C) {
   136  	cID := makeTestContainer(c, testContainerOptions{addContent: true})
   137  	defer deleteContainer(cID)
   138  
   139  	tmpDir := getTestDir(c, "test-cp-from-err-dst-not-dir")
   140  	defer os.RemoveAll(tmpDir)
   141  
   142  	makeTestContentInDir(c, tmpDir)
   143  
   144  	// First, copy a file from the container to a symlink to a file. This
   145  	// should overwrite the symlink target contents with the source contents.
   146  	srcPath := containerCpPath(cID, "/file2")
   147  	dstPath := cpPath(tmpDir, "symlinkToFile1")
   148  
   149  	if err := runDockerCp(c, srcPath, dstPath); err != nil {
   150  		c.Fatalf("unexpected error %T: %s", err, err)
   151  	}
   152  
   153  	// The symlink should not have been modified.
   154  	if err := symlinkTargetEquals(c, dstPath, "file1"); err != nil {
   155  		c.Fatal(err)
   156  	}
   157  
   158  	// The file should have the contents of "file2" now.
   159  	if err := fileContentEquals(c, cpPath(tmpDir, "file1"), "file2\n"); err != nil {
   160  		c.Fatal(err)
   161  	}
   162  
   163  	// Next, copy a file from the container to a symlink to a directory. This
   164  	// should copy the file into the symlink target directory.
   165  	dstPath = cpPath(tmpDir, "symlinkToDir1")
   166  
   167  	if err := runDockerCp(c, srcPath, dstPath); err != nil {
   168  		c.Fatalf("unexpected error %T: %s", err, err)
   169  	}
   170  
   171  	// The symlink should not have been modified.
   172  	if err := symlinkTargetEquals(c, dstPath, "dir1"); err != nil {
   173  		c.Fatal(err)
   174  	}
   175  
   176  	// The file should have the contents of "file2" now.
   177  	if err := fileContentEquals(c, cpPath(tmpDir, "file2"), "file2\n"); err != nil {
   178  		c.Fatal(err)
   179  	}
   180  
   181  	// Next, copy a file from the container to a symlink to a file that does
   182  	// not exist (a broken symlink). This should create the target file with
   183  	// the contents of the source file.
   184  	dstPath = cpPath(tmpDir, "brokenSymlinkToFileX")
   185  
   186  	if err := runDockerCp(c, srcPath, dstPath); err != nil {
   187  		c.Fatalf("unexpected error %T: %s", err, err)
   188  	}
   189  
   190  	// The symlink should not have been modified.
   191  	if err := symlinkTargetEquals(c, dstPath, "fileX"); err != nil {
   192  		c.Fatal(err)
   193  	}
   194  
   195  	// The file should have the contents of "file2" now.
   196  	if err := fileContentEquals(c, cpPath(tmpDir, "fileX"), "file2\n"); err != nil {
   197  		c.Fatal(err)
   198  	}
   199  
   200  	// Next, copy a directory from the container to a symlink to a local
   201  	// directory. This should copy the directory into the symlink target
   202  	// directory and not modify the symlink.
   203  	srcPath = containerCpPath(cID, "/dir2")
   204  	dstPath = cpPath(tmpDir, "symlinkToDir1")
   205  
   206  	if err := runDockerCp(c, srcPath, dstPath); err != nil {
   207  		c.Fatalf("unexpected error %T: %s", err, err)
   208  	}
   209  
   210  	// The symlink should not have been modified.
   211  	if err := symlinkTargetEquals(c, dstPath, "dir1"); err != nil {
   212  		c.Fatal(err)
   213  	}
   214  
   215  	// The directory should now contain a copy of "dir2".
   216  	if err := fileContentEquals(c, cpPath(tmpDir, "dir1/dir2/file2-1"), "file2-1\n"); err != nil {
   217  		c.Fatal(err)
   218  	}
   219  
   220  	// Next, copy a directory from the container to a symlink to a local
   221  	// directory that does not exist (a broken symlink). This should create
   222  	// the target as a directory with the contents of the source directory. It
   223  	// should not modify the symlink.
   224  	dstPath = cpPath(tmpDir, "brokenSymlinkToDirX")
   225  
   226  	if err := runDockerCp(c, srcPath, dstPath); err != nil {
   227  		c.Fatalf("unexpected error %T: %s", err, err)
   228  	}
   229  
   230  	// The symlink should not have been modified.
   231  	if err := symlinkTargetEquals(c, dstPath, "dirX"); err != nil {
   232  		c.Fatal(err)
   233  	}
   234  
   235  	// The "dirX" directory should now be a copy of "dir2".
   236  	if err := fileContentEquals(c, cpPath(tmpDir, "dirX/file2-1"), "file2-1\n"); err != nil {
   237  		c.Fatal(err)
   238  	}
   239  }
   240  
   241  // Possibilities are reduced to the remaining 10 cases:
   242  //
   243  //  case | srcIsDir | onlyDirContents | dstExists | dstIsDir | dstTrSep | action
   244  // ===================================================================================================
   245  //   A   |  no      |  -              |  no       |  -       |  no      |  create file
   246  //   B   |  no      |  -              |  no       |  -       |  yes     |  error
   247  //   C   |  no      |  -              |  yes      |  no      |  -       |  overwrite file
   248  //   D   |  no      |  -              |  yes      |  yes     |  -       |  create file in dst dir
   249  //   E   |  yes     |  no             |  no       |  -       |  -       |  create dir, copy contents
   250  //   F   |  yes     |  no             |  yes      |  no      |  -       |  error
   251  //   G   |  yes     |  no             |  yes      |  yes     |  -       |  copy dir and contents
   252  //   H   |  yes     |  yes            |  no       |  -       |  -       |  create dir, copy contents
   253  //   I   |  yes     |  yes            |  yes      |  no      |  -       |  error
   254  //   J   |  yes     |  yes            |  yes      |  yes     |  -       |  copy dir contents
   255  //
   256  
   257  // A. SRC specifies a file and DST (no trailing path separator) doesn't
   258  //    exist. This should create a file with the name DST and copy the
   259  //    contents of the source file into it.
   260  func (s *DockerSuite) TestCpFromCaseA(c *check.C) {
   261  	cID := makeTestContainer(c, testContainerOptions{
   262  		addContent: true, workDir: "/root",
   263  	})
   264  	defer deleteContainer(cID)
   265  
   266  	tmpDir := getTestDir(c, "test-cp-from-case-a")
   267  	defer os.RemoveAll(tmpDir)
   268  
   269  	srcPath := containerCpPath(cID, "/root/file1")
   270  	dstPath := cpPath(tmpDir, "itWorks.txt")
   271  
   272  	if err := runDockerCp(c, srcPath, dstPath); err != nil {
   273  		c.Fatalf("unexpected error %T: %s", err, err)
   274  	}
   275  
   276  	if err := fileContentEquals(c, dstPath, "file1\n"); err != nil {
   277  		c.Fatal(err)
   278  	}
   279  }
   280  
   281  // B. SRC specifies a file and DST (with trailing path separator) doesn't
   282  //    exist. This should cause an error because the copy operation cannot
   283  //    create a directory when copying a single file.
   284  func (s *DockerSuite) TestCpFromCaseB(c *check.C) {
   285  	cID := makeTestContainer(c, testContainerOptions{addContent: true})
   286  	defer deleteContainer(cID)
   287  
   288  	tmpDir := getTestDir(c, "test-cp-from-case-b")
   289  	defer os.RemoveAll(tmpDir)
   290  
   291  	srcPath := containerCpPath(cID, "/file1")
   292  	dstDir := cpPathTrailingSep(tmpDir, "testDir")
   293  
   294  	err := runDockerCp(c, srcPath, dstDir)
   295  	if err == nil {
   296  		c.Fatal("expected DirNotExists error, but got nil instead")
   297  	}
   298  
   299  	if !isCpDirNotExist(err) {
   300  		c.Fatalf("expected DirNotExists error, but got %T: %s", err, err)
   301  	}
   302  }
   303  
   304  // C. SRC specifies a file and DST exists as a file. This should overwrite
   305  //    the file at DST with the contents of the source file.
   306  func (s *DockerSuite) TestCpFromCaseC(c *check.C) {
   307  	cID := makeTestContainer(c, testContainerOptions{
   308  		addContent: true, workDir: "/root",
   309  	})
   310  	defer deleteContainer(cID)
   311  
   312  	tmpDir := getTestDir(c, "test-cp-from-case-c")
   313  	defer os.RemoveAll(tmpDir)
   314  
   315  	makeTestContentInDir(c, tmpDir)
   316  
   317  	srcPath := containerCpPath(cID, "/root/file1")
   318  	dstPath := cpPath(tmpDir, "file2")
   319  
   320  	// Ensure the local file starts with different content.
   321  	if err := fileContentEquals(c, dstPath, "file2\n"); err != nil {
   322  		c.Fatal(err)
   323  	}
   324  
   325  	if err := runDockerCp(c, srcPath, dstPath); err != nil {
   326  		c.Fatalf("unexpected error %T: %s", err, err)
   327  	}
   328  
   329  	if err := fileContentEquals(c, dstPath, "file1\n"); err != nil {
   330  		c.Fatal(err)
   331  	}
   332  }
   333  
   334  // D. SRC specifies a file and DST exists as a directory. This should place
   335  //    a copy of the source file inside it using the basename from SRC. Ensure
   336  //    this works whether DST has a trailing path separator or not.
   337  func (s *DockerSuite) TestCpFromCaseD(c *check.C) {
   338  	cID := makeTestContainer(c, testContainerOptions{addContent: true})
   339  	defer deleteContainer(cID)
   340  
   341  	tmpDir := getTestDir(c, "test-cp-from-case-d")
   342  	defer os.RemoveAll(tmpDir)
   343  
   344  	makeTestContentInDir(c, tmpDir)
   345  
   346  	srcPath := containerCpPath(cID, "/file1")
   347  	dstDir := cpPath(tmpDir, "dir1")
   348  	dstPath := filepath.Join(dstDir, "file1")
   349  
   350  	// Ensure that dstPath doesn't exist.
   351  	if _, err := os.Stat(dstPath); !os.IsNotExist(err) {
   352  		c.Fatalf("did not expect dstPath %q to exist", dstPath)
   353  	}
   354  
   355  	if err := runDockerCp(c, srcPath, dstDir); err != nil {
   356  		c.Fatalf("unexpected error %T: %s", err, err)
   357  	}
   358  
   359  	if err := fileContentEquals(c, dstPath, "file1\n"); err != nil {
   360  		c.Fatal(err)
   361  	}
   362  
   363  	// Now try again but using a trailing path separator for dstDir.
   364  
   365  	if err := os.RemoveAll(dstDir); err != nil {
   366  		c.Fatalf("unable to remove dstDir: %s", err)
   367  	}
   368  
   369  	if err := os.MkdirAll(dstDir, os.FileMode(0755)); err != nil {
   370  		c.Fatalf("unable to make dstDir: %s", err)
   371  	}
   372  
   373  	dstDir = cpPathTrailingSep(tmpDir, "dir1")
   374  
   375  	if err := runDockerCp(c, srcPath, dstDir); err != nil {
   376  		c.Fatalf("unexpected error %T: %s", err, err)
   377  	}
   378  
   379  	if err := fileContentEquals(c, dstPath, "file1\n"); err != nil {
   380  		c.Fatal(err)
   381  	}
   382  }
   383  
   384  // E. SRC specifies a directory and DST does not exist. This should create a
   385  //    directory at DST and copy the contents of the SRC directory into the DST
   386  //    directory. Ensure this works whether DST has a trailing path separator or
   387  //    not.
   388  func (s *DockerSuite) TestCpFromCaseE(c *check.C) {
   389  	cID := makeTestContainer(c, testContainerOptions{addContent: true})
   390  	defer deleteContainer(cID)
   391  
   392  	tmpDir := getTestDir(c, "test-cp-from-case-e")
   393  	defer os.RemoveAll(tmpDir)
   394  
   395  	srcDir := containerCpPath(cID, "dir1")
   396  	dstDir := cpPath(tmpDir, "testDir")
   397  	dstPath := filepath.Join(dstDir, "file1-1")
   398  
   399  	if err := runDockerCp(c, srcDir, dstDir); err != nil {
   400  		c.Fatalf("unexpected error %T: %s", err, err)
   401  	}
   402  
   403  	if err := fileContentEquals(c, dstPath, "file1-1\n"); err != nil {
   404  		c.Fatal(err)
   405  	}
   406  
   407  	// Now try again but using a trailing path separator for dstDir.
   408  
   409  	if err := os.RemoveAll(dstDir); err != nil {
   410  		c.Fatalf("unable to remove dstDir: %s", err)
   411  	}
   412  
   413  	dstDir = cpPathTrailingSep(tmpDir, "testDir")
   414  
   415  	if err := runDockerCp(c, srcDir, dstDir); err != nil {
   416  		c.Fatalf("unexpected error %T: %s", err, err)
   417  	}
   418  
   419  	if err := fileContentEquals(c, dstPath, "file1-1\n"); err != nil {
   420  		c.Fatal(err)
   421  	}
   422  }
   423  
   424  // F. SRC specifies a directory and DST exists as a file. This should cause an
   425  //    error as it is not possible to overwrite a file with a directory.
   426  func (s *DockerSuite) TestCpFromCaseF(c *check.C) {
   427  	cID := makeTestContainer(c, testContainerOptions{
   428  		addContent: true, workDir: "/root",
   429  	})
   430  	defer deleteContainer(cID)
   431  
   432  	tmpDir := getTestDir(c, "test-cp-from-case-f")
   433  	defer os.RemoveAll(tmpDir)
   434  
   435  	makeTestContentInDir(c, tmpDir)
   436  
   437  	srcDir := containerCpPath(cID, "/root/dir1")
   438  	dstFile := cpPath(tmpDir, "file1")
   439  
   440  	err := runDockerCp(c, srcDir, dstFile)
   441  	if err == nil {
   442  		c.Fatal("expected ErrCannotCopyDir error, but got nil instead")
   443  	}
   444  
   445  	if !isCpCannotCopyDir(err) {
   446  		c.Fatalf("expected ErrCannotCopyDir error, but got %T: %s", err, err)
   447  	}
   448  }
   449  
   450  // G. SRC specifies a directory and DST exists as a directory. This should copy
   451  //    the SRC directory and all its contents to the DST directory. Ensure this
   452  //    works whether DST has a trailing path separator or not.
   453  func (s *DockerSuite) TestCpFromCaseG(c *check.C) {
   454  	cID := makeTestContainer(c, testContainerOptions{
   455  		addContent: true, workDir: "/root",
   456  	})
   457  	defer deleteContainer(cID)
   458  
   459  	tmpDir := getTestDir(c, "test-cp-from-case-g")
   460  	defer os.RemoveAll(tmpDir)
   461  
   462  	makeTestContentInDir(c, tmpDir)
   463  
   464  	srcDir := containerCpPath(cID, "/root/dir1")
   465  	dstDir := cpPath(tmpDir, "dir2")
   466  	resultDir := filepath.Join(dstDir, "dir1")
   467  	dstPath := filepath.Join(resultDir, "file1-1")
   468  
   469  	if err := runDockerCp(c, srcDir, dstDir); err != nil {
   470  		c.Fatalf("unexpected error %T: %s", err, err)
   471  	}
   472  
   473  	if err := fileContentEquals(c, dstPath, "file1-1\n"); err != nil {
   474  		c.Fatal(err)
   475  	}
   476  
   477  	// Now try again but using a trailing path separator for dstDir.
   478  
   479  	if err := os.RemoveAll(dstDir); err != nil {
   480  		c.Fatalf("unable to remove dstDir: %s", err)
   481  	}
   482  
   483  	if err := os.MkdirAll(dstDir, os.FileMode(0755)); err != nil {
   484  		c.Fatalf("unable to make dstDir: %s", err)
   485  	}
   486  
   487  	dstDir = cpPathTrailingSep(tmpDir, "dir2")
   488  
   489  	if err := runDockerCp(c, srcDir, dstDir); err != nil {
   490  		c.Fatalf("unexpected error %T: %s", err, err)
   491  	}
   492  
   493  	if err := fileContentEquals(c, dstPath, "file1-1\n"); err != nil {
   494  		c.Fatal(err)
   495  	}
   496  }
   497  
   498  // H. SRC specifies a directory's contents only and DST does not exist. This
   499  //    should create a directory at DST and copy the contents of the SRC
   500  //    directory (but not the directory itself) into the DST directory. Ensure
   501  //    this works whether DST has a trailing path separator or not.
   502  func (s *DockerSuite) TestCpFromCaseH(c *check.C) {
   503  	cID := makeTestContainer(c, testContainerOptions{addContent: true})
   504  	defer deleteContainer(cID)
   505  
   506  	tmpDir := getTestDir(c, "test-cp-from-case-h")
   507  	defer os.RemoveAll(tmpDir)
   508  
   509  	srcDir := containerCpPathTrailingSep(cID, "dir1") + "."
   510  	dstDir := cpPath(tmpDir, "testDir")
   511  	dstPath := filepath.Join(dstDir, "file1-1")
   512  
   513  	if err := runDockerCp(c, srcDir, dstDir); err != nil {
   514  		c.Fatalf("unexpected error %T: %s", err, err)
   515  	}
   516  
   517  	if err := fileContentEquals(c, dstPath, "file1-1\n"); err != nil {
   518  		c.Fatal(err)
   519  	}
   520  
   521  	// Now try again but using a trailing path separator for dstDir.
   522  
   523  	if err := os.RemoveAll(dstDir); err != nil {
   524  		c.Fatalf("unable to remove resultDir: %s", err)
   525  	}
   526  
   527  	dstDir = cpPathTrailingSep(tmpDir, "testDir")
   528  
   529  	if err := runDockerCp(c, srcDir, dstDir); err != nil {
   530  		c.Fatalf("unexpected error %T: %s", err, err)
   531  	}
   532  
   533  	if err := fileContentEquals(c, dstPath, "file1-1\n"); err != nil {
   534  		c.Fatal(err)
   535  	}
   536  }
   537  
   538  // I. SRC specifies a direcotry's contents only and DST exists as a file. This
   539  //    should cause an error as it is not possible to overwrite a file with a
   540  //    directory.
   541  func (s *DockerSuite) TestCpFromCaseI(c *check.C) {
   542  	cID := makeTestContainer(c, testContainerOptions{
   543  		addContent: true, workDir: "/root",
   544  	})
   545  	defer deleteContainer(cID)
   546  
   547  	tmpDir := getTestDir(c, "test-cp-from-case-i")
   548  	defer os.RemoveAll(tmpDir)
   549  
   550  	makeTestContentInDir(c, tmpDir)
   551  
   552  	srcDir := containerCpPathTrailingSep(cID, "/root/dir1") + "."
   553  	dstFile := cpPath(tmpDir, "file1")
   554  
   555  	err := runDockerCp(c, srcDir, dstFile)
   556  	if err == nil {
   557  		c.Fatal("expected ErrCannotCopyDir error, but got nil instead")
   558  	}
   559  
   560  	if !isCpCannotCopyDir(err) {
   561  		c.Fatalf("expected ErrCannotCopyDir error, but got %T: %s", err, err)
   562  	}
   563  }
   564  
   565  // J. SRC specifies a directory's contents only and DST exists as a directory.
   566  //    This should copy the contents of the SRC directory (but not the directory
   567  //    itself) into the DST directory. Ensure this works whether DST has a
   568  //    trailing path separator or not.
   569  func (s *DockerSuite) TestCpFromCaseJ(c *check.C) {
   570  	cID := makeTestContainer(c, testContainerOptions{
   571  		addContent: true, workDir: "/root",
   572  	})
   573  	defer deleteContainer(cID)
   574  
   575  	tmpDir := getTestDir(c, "test-cp-from-case-j")
   576  	defer os.RemoveAll(tmpDir)
   577  
   578  	makeTestContentInDir(c, tmpDir)
   579  
   580  	srcDir := containerCpPathTrailingSep(cID, "/root/dir1") + "."
   581  	dstDir := cpPath(tmpDir, "dir2")
   582  	dstPath := filepath.Join(dstDir, "file1-1")
   583  
   584  	if err := runDockerCp(c, srcDir, dstDir); err != nil {
   585  		c.Fatalf("unexpected error %T: %s", err, err)
   586  	}
   587  
   588  	if err := fileContentEquals(c, dstPath, "file1-1\n"); err != nil {
   589  		c.Fatal(err)
   590  	}
   591  
   592  	// Now try again but using a trailing path separator for dstDir.
   593  
   594  	if err := os.RemoveAll(dstDir); err != nil {
   595  		c.Fatalf("unable to remove dstDir: %s", err)
   596  	}
   597  
   598  	if err := os.MkdirAll(dstDir, os.FileMode(0755)); err != nil {
   599  		c.Fatalf("unable to make dstDir: %s", err)
   600  	}
   601  
   602  	dstDir = cpPathTrailingSep(tmpDir, "dir2")
   603  
   604  	if err := runDockerCp(c, srcDir, dstDir); err != nil {
   605  		c.Fatalf("unexpected error %T: %s", err, err)
   606  	}
   607  
   608  	if err := fileContentEquals(c, dstPath, "file1-1\n"); err != nil {
   609  		c.Fatal(err)
   610  	}
   611  }