github.com/justincormack/cli@v0.0.0-20201215022714-831ebeae9675/cli/command/container/cp_test.go (about) 1 package container 2 3 import ( 4 "io" 5 "io/ioutil" 6 "os" 7 "runtime" 8 "strings" 9 "testing" 10 11 "github.com/docker/cli/internal/test" 12 "github.com/docker/docker/api/types" 13 "github.com/docker/docker/pkg/archive" 14 "gotest.tools/v3/assert" 15 is "gotest.tools/v3/assert/cmp" 16 "gotest.tools/v3/fs" 17 "gotest.tools/v3/skip" 18 ) 19 20 func TestRunCopyWithInvalidArguments(t *testing.T) { 21 var testcases = []struct { 22 doc string 23 options copyOptions 24 expectedErr string 25 }{ 26 { 27 doc: "copy between container", 28 options: copyOptions{ 29 source: "first:/path", 30 destination: "second:/path", 31 }, 32 expectedErr: "copying between containers is not supported", 33 }, 34 { 35 doc: "copy without a container", 36 options: copyOptions{ 37 source: "./source", 38 destination: "./dest", 39 }, 40 expectedErr: "must specify at least one container source", 41 }, 42 } 43 for _, testcase := range testcases { 44 t.Run(testcase.doc, func(t *testing.T) { 45 err := runCopy(test.NewFakeCli(nil), testcase.options) 46 assert.Error(t, err, testcase.expectedErr) 47 }) 48 } 49 } 50 51 func TestRunCopyFromContainerToStdout(t *testing.T) { 52 tarContent := "the tar content" 53 54 fakeClient := &fakeClient{ 55 containerCopyFromFunc: func(container, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) { 56 assert.Check(t, is.Equal("container", container)) 57 return ioutil.NopCloser(strings.NewReader(tarContent)), types.ContainerPathStat{}, nil 58 }, 59 } 60 options := copyOptions{source: "container:/path", destination: "-"} 61 cli := test.NewFakeCli(fakeClient) 62 err := runCopy(cli, options) 63 assert.NilError(t, err) 64 assert.Check(t, is.Equal(tarContent, cli.OutBuffer().String())) 65 assert.Check(t, is.Equal("", cli.ErrBuffer().String())) 66 } 67 68 func TestRunCopyFromContainerToFilesystem(t *testing.T) { 69 destDir := fs.NewDir(t, "cp-test", 70 fs.WithFile("file1", "content\n")) 71 defer destDir.Remove() 72 73 fakeClient := &fakeClient{ 74 containerCopyFromFunc: func(container, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) { 75 assert.Check(t, is.Equal("container", container)) 76 readCloser, err := archive.TarWithOptions(destDir.Path(), &archive.TarOptions{}) 77 return readCloser, types.ContainerPathStat{}, err 78 }, 79 } 80 options := copyOptions{source: "container:/path", destination: destDir.Path()} 81 cli := test.NewFakeCli(fakeClient) 82 err := runCopy(cli, options) 83 assert.NilError(t, err) 84 assert.Check(t, is.Equal("", cli.OutBuffer().String())) 85 assert.Check(t, is.Equal("", cli.ErrBuffer().String())) 86 87 content, err := ioutil.ReadFile(destDir.Join("file1")) 88 assert.NilError(t, err) 89 assert.Check(t, is.Equal("content\n", string(content))) 90 } 91 92 func TestRunCopyFromContainerToFilesystemMissingDestinationDirectory(t *testing.T) { 93 destDir := fs.NewDir(t, "cp-test", 94 fs.WithFile("file1", "content\n")) 95 defer destDir.Remove() 96 97 fakeClient := &fakeClient{ 98 containerCopyFromFunc: func(container, srcPath string) (io.ReadCloser, types.ContainerPathStat, error) { 99 assert.Check(t, is.Equal("container", container)) 100 readCloser, err := archive.TarWithOptions(destDir.Path(), &archive.TarOptions{}) 101 return readCloser, types.ContainerPathStat{}, err 102 }, 103 } 104 105 options := copyOptions{ 106 source: "container:/path", 107 destination: destDir.Join("missing", "foo"), 108 } 109 cli := test.NewFakeCli(fakeClient) 110 err := runCopy(cli, options) 111 assert.ErrorContains(t, err, destDir.Join("missing")) 112 } 113 114 func TestRunCopyToContainerFromFileWithTrailingSlash(t *testing.T) { 115 srcFile := fs.NewFile(t, t.Name()) 116 defer srcFile.Remove() 117 118 options := copyOptions{ 119 source: srcFile.Path() + string(os.PathSeparator), 120 destination: "container:/path", 121 } 122 cli := test.NewFakeCli(&fakeClient{}) 123 err := runCopy(cli, options) 124 125 expectedError := "not a directory" 126 if runtime.GOOS == "windows" { 127 expectedError = "The filename, directory name, or volume label syntax is incorrect" 128 } 129 assert.ErrorContains(t, err, expectedError) 130 } 131 132 func TestRunCopyToContainerSourceDoesNotExist(t *testing.T) { 133 options := copyOptions{ 134 source: "/does/not/exist", 135 destination: "container:/path", 136 } 137 cli := test.NewFakeCli(&fakeClient{}) 138 err := runCopy(cli, options) 139 expected := "no such file or directory" 140 if runtime.GOOS == "windows" { 141 expected = "cannot find the file specified" 142 } 143 assert.ErrorContains(t, err, expected) 144 } 145 146 func TestSplitCpArg(t *testing.T) { 147 var testcases = []struct { 148 doc string 149 path string 150 os string 151 expectedContainer string 152 expectedPath string 153 }{ 154 { 155 doc: "absolute path with colon", 156 os: "linux", 157 path: "/abs/path:withcolon", 158 expectedPath: "/abs/path:withcolon", 159 }, 160 { 161 doc: "relative path with colon", 162 path: "./relative:path", 163 expectedPath: "./relative:path", 164 }, 165 { 166 doc: "absolute path with drive", 167 os: "windows", 168 path: `d:\abs\path`, 169 expectedPath: `d:\abs\path`, 170 }, 171 { 172 doc: "no separator", 173 path: "relative/path", 174 expectedPath: "relative/path", 175 }, 176 { 177 doc: "with separator", 178 path: "container:/opt/foo", 179 expectedPath: "/opt/foo", 180 expectedContainer: "container", 181 }, 182 } 183 for _, testcase := range testcases { 184 t.Run(testcase.doc, func(t *testing.T) { 185 skip.If(t, testcase.os != "" && testcase.os != runtime.GOOS) 186 187 container, path := splitCpArg(testcase.path) 188 assert.Check(t, is.Equal(testcase.expectedContainer, container)) 189 assert.Check(t, is.Equal(testcase.expectedPath, path)) 190 }) 191 } 192 } 193 194 func TestRunCopyFromContainerToFilesystemIrregularDestination(t *testing.T) { 195 options := copyOptions{source: "container:/dev/null", destination: "/dev/random"} 196 cli := test.NewFakeCli(nil) 197 err := runCopy(cli, options) 198 assert.Assert(t, err != nil) 199 expected := `"/dev/random" must be a directory or a regular file` 200 assert.ErrorContains(t, err, expected) 201 }