github.com/ssdev-go/moby@v17.12.1-ce-rc2+incompatible/integration-cli/docker_cli_cp_utils_test.go (about) 1 package main 2 3 import ( 4 "bytes" 5 "fmt" 6 "io/ioutil" 7 "os" 8 "os/exec" 9 "path/filepath" 10 "runtime" 11 "strings" 12 13 "github.com/docker/docker/integration-cli/checker" 14 "github.com/docker/docker/pkg/archive" 15 "github.com/go-check/check" 16 ) 17 18 type fileType uint32 19 20 const ( 21 ftRegular fileType = iota 22 ftDir 23 ftSymlink 24 ) 25 26 type fileData struct { 27 filetype fileType 28 path string 29 contents string 30 uid int 31 gid int 32 mode int 33 } 34 35 func (fd fileData) creationCommand() string { 36 var command string 37 38 switch fd.filetype { 39 case ftRegular: 40 // Don't overwrite the file if it already exists! 41 command = fmt.Sprintf("if [ ! -f %s ]; then echo %q > %s; fi", fd.path, fd.contents, fd.path) 42 case ftDir: 43 command = fmt.Sprintf("mkdir -p %s", fd.path) 44 case ftSymlink: 45 command = fmt.Sprintf("ln -fs %s %s", fd.contents, fd.path) 46 } 47 48 return command 49 } 50 51 func mkFilesCommand(fds []fileData) string { 52 commands := make([]string, len(fds)) 53 54 for i, fd := range fds { 55 commands[i] = fd.creationCommand() 56 } 57 58 return strings.Join(commands, " && ") 59 } 60 61 var defaultFileData = []fileData{ 62 {ftRegular, "file1", "file1", 0, 0, 0666}, 63 {ftRegular, "file2", "file2", 0, 0, 0666}, 64 {ftRegular, "file3", "file3", 0, 0, 0666}, 65 {ftRegular, "file4", "file4", 0, 0, 0666}, 66 {ftRegular, "file5", "file5", 0, 0, 0666}, 67 {ftRegular, "file6", "file6", 0, 0, 0666}, 68 {ftRegular, "file7", "file7", 0, 0, 0666}, 69 {ftDir, "dir1", "", 0, 0, 0777}, 70 {ftRegular, "dir1/file1-1", "file1-1", 0, 0, 0666}, 71 {ftRegular, "dir1/file1-2", "file1-2", 0, 0, 0666}, 72 {ftDir, "dir2", "", 0, 0, 0666}, 73 {ftRegular, "dir2/file2-1", "file2-1", 0, 0, 0666}, 74 {ftRegular, "dir2/file2-2", "file2-2", 0, 0, 0666}, 75 {ftDir, "dir3", "", 0, 0, 0666}, 76 {ftRegular, "dir3/file3-1", "file3-1", 0, 0, 0666}, 77 {ftRegular, "dir3/file3-2", "file3-2", 0, 0, 0666}, 78 {ftDir, "dir4", "", 0, 0, 0666}, 79 {ftRegular, "dir4/file3-1", "file4-1", 0, 0, 0666}, 80 {ftRegular, "dir4/file3-2", "file4-2", 0, 0, 0666}, 81 {ftDir, "dir5", "", 0, 0, 0666}, 82 {ftSymlink, "symlinkToFile1", "file1", 0, 0, 0666}, 83 {ftSymlink, "symlinkToDir1", "dir1", 0, 0, 0666}, 84 {ftSymlink, "brokenSymlinkToFileX", "fileX", 0, 0, 0666}, 85 {ftSymlink, "brokenSymlinkToDirX", "dirX", 0, 0, 0666}, 86 {ftSymlink, "symlinkToAbsDir", "/root", 0, 0, 0666}, 87 {ftDir, "permdirtest", "", 2, 2, 0700}, 88 {ftRegular, "permdirtest/permtest", "perm_test", 65534, 65534, 0400}, 89 } 90 91 func defaultMkContentCommand() string { 92 return mkFilesCommand(defaultFileData) 93 } 94 95 func makeTestContentInDir(c *check.C, dir string) { 96 for _, fd := range defaultFileData { 97 path := filepath.Join(dir, filepath.FromSlash(fd.path)) 98 switch fd.filetype { 99 case ftRegular: 100 c.Assert(ioutil.WriteFile(path, []byte(fd.contents+"\n"), os.FileMode(fd.mode)), checker.IsNil) 101 case ftDir: 102 c.Assert(os.Mkdir(path, os.FileMode(fd.mode)), checker.IsNil) 103 case ftSymlink: 104 c.Assert(os.Symlink(fd.contents, path), checker.IsNil) 105 } 106 107 if fd.filetype != ftSymlink && runtime.GOOS != "windows" { 108 c.Assert(os.Chown(path, fd.uid, fd.gid), checker.IsNil) 109 } 110 } 111 } 112 113 type testContainerOptions struct { 114 addContent bool 115 readOnly bool 116 volumes []string 117 workDir string 118 command string 119 } 120 121 func makeTestContainer(c *check.C, options testContainerOptions) (containerID string) { 122 if options.addContent { 123 mkContentCmd := defaultMkContentCommand() 124 if options.command == "" { 125 options.command = mkContentCmd 126 } else { 127 options.command = fmt.Sprintf("%s && %s", defaultMkContentCommand(), options.command) 128 } 129 } 130 131 if options.command == "" { 132 options.command = "#(nop)" 133 } 134 135 args := []string{"run", "-d"} 136 137 for _, volume := range options.volumes { 138 args = append(args, "-v", volume) 139 } 140 141 if options.workDir != "" { 142 args = append(args, "-w", options.workDir) 143 } 144 145 if options.readOnly { 146 args = append(args, "--read-only") 147 } 148 149 args = append(args, "busybox", "/bin/sh", "-c", options.command) 150 151 out, _ := dockerCmd(c, args...) 152 153 containerID = strings.TrimSpace(out) 154 155 out, _ = dockerCmd(c, "wait", containerID) 156 157 exitCode := strings.TrimSpace(out) 158 if exitCode != "0" { 159 out, _ = dockerCmd(c, "logs", containerID) 160 } 161 c.Assert(exitCode, checker.Equals, "0", check.Commentf("failed to make test container: %s", out)) 162 163 return 164 } 165 166 func makeCatFileCommand(path string) string { 167 return fmt.Sprintf("if [ -f %s ]; then cat %s; fi", path, path) 168 } 169 170 func cpPath(pathElements ...string) string { 171 localizedPathElements := make([]string, len(pathElements)) 172 for i, path := range pathElements { 173 localizedPathElements[i] = filepath.FromSlash(path) 174 } 175 return strings.Join(localizedPathElements, string(filepath.Separator)) 176 } 177 178 func cpPathTrailingSep(pathElements ...string) string { 179 return fmt.Sprintf("%s%c", cpPath(pathElements...), filepath.Separator) 180 } 181 182 func containerCpPath(containerID string, pathElements ...string) string { 183 joined := strings.Join(pathElements, "/") 184 return fmt.Sprintf("%s:%s", containerID, joined) 185 } 186 187 func containerCpPathTrailingSep(containerID string, pathElements ...string) string { 188 return fmt.Sprintf("%s/", containerCpPath(containerID, pathElements...)) 189 } 190 191 func runDockerCp(c *check.C, src, dst string, params []string) (err error) { 192 c.Logf("running `docker cp %s %s %s`", strings.Join(params, " "), src, dst) 193 194 args := []string{"cp"} 195 196 args = append(args, params...) 197 198 args = append(args, src, dst) 199 200 out, _, err := runCommandWithOutput(exec.Command(dockerBinary, args...)) 201 if err != nil { 202 err = fmt.Errorf("error executing `docker cp` command: %s: %s", err, out) 203 } 204 205 return 206 } 207 208 func startContainerGetOutput(c *check.C, containerID string) (out string, err error) { 209 c.Logf("running `docker start -a %s`", containerID) 210 211 args := []string{"start", "-a", containerID} 212 213 out, _, err = runCommandWithOutput(exec.Command(dockerBinary, args...)) 214 if err != nil { 215 err = fmt.Errorf("error executing `docker start` command: %s: %s", err, out) 216 } 217 218 return 219 } 220 221 func getTestDir(c *check.C, label string) (tmpDir string) { 222 var err error 223 224 tmpDir, err = ioutil.TempDir("", label) 225 // unable to make temporary directory 226 c.Assert(err, checker.IsNil) 227 228 return 229 } 230 231 func isCpNotExist(err error) bool { 232 return strings.Contains(strings.ToLower(err.Error()), "could not find the file") 233 } 234 235 func isCpDirNotExist(err error) bool { 236 return strings.Contains(err.Error(), archive.ErrDirNotExists.Error()) 237 } 238 239 func isCpNotDir(err error) bool { 240 return strings.Contains(err.Error(), archive.ErrNotDirectory.Error()) || strings.Contains(err.Error(), "filename, directory name, or volume label syntax is incorrect") 241 } 242 243 func isCpCannotCopyDir(err error) bool { 244 return strings.Contains(err.Error(), archive.ErrCannotCopyDir.Error()) 245 } 246 247 func isCpCannotCopyReadOnly(err error) bool { 248 return strings.Contains(err.Error(), "marked read-only") 249 } 250 251 func isCannotOverwriteNonDirWithDir(err error) bool { 252 return strings.Contains(err.Error(), "cannot overwrite non-directory") 253 } 254 255 func fileContentEquals(c *check.C, filename, contents string) (err error) { 256 c.Logf("checking that file %q contains %q\n", filename, contents) 257 258 fileBytes, err := ioutil.ReadFile(filename) 259 if err != nil { 260 return 261 } 262 263 expectedBytes, err := ioutil.ReadAll(strings.NewReader(contents)) 264 if err != nil { 265 return 266 } 267 268 if !bytes.Equal(fileBytes, expectedBytes) { 269 err = fmt.Errorf("file content not equal - expected %q, got %q", string(expectedBytes), string(fileBytes)) 270 } 271 272 return 273 } 274 275 func symlinkTargetEquals(c *check.C, symlink, expectedTarget string) (err error) { 276 c.Logf("checking that the symlink %q points to %q\n", symlink, expectedTarget) 277 278 actualTarget, err := os.Readlink(symlink) 279 if err != nil { 280 return 281 } 282 283 if actualTarget != expectedTarget { 284 err = fmt.Errorf("symlink target points to %q not %q", actualTarget, expectedTarget) 285 } 286 287 return 288 } 289 290 func containerStartOutputEquals(c *check.C, containerID, contents string) (err error) { 291 c.Logf("checking that container %q start output contains %q\n", containerID, contents) 292 293 out, err := startContainerGetOutput(c, containerID) 294 if err != nil { 295 return 296 } 297 298 if out != contents { 299 err = fmt.Errorf("output contents not equal - expected %q, got %q", contents, out) 300 } 301 302 return 303 } 304 305 func defaultVolumes(tmpDir string) []string { 306 if SameHostDaemon() { 307 return []string{ 308 "/vol1", 309 fmt.Sprintf("%s:/vol2", tmpDir), 310 fmt.Sprintf("%s:/vol3", filepath.Join(tmpDir, "vol3")), 311 fmt.Sprintf("%s:/vol_ro:ro", filepath.Join(tmpDir, "vol_ro")), 312 } 313 } 314 315 // Can't bind-mount volumes with separate host daemon. 316 return []string{"/vol1", "/vol2", "/vol3", "/vol_ro:/vol_ro:ro"} 317 }