github.com/toplink-cn/moby@v0.0.0-20240305205811-460b4aebdf81/integration-cli/utils_test.go (about) 1 package main 2 3 import ( 4 "fmt" 5 "os" 6 "os/exec" 7 "path/filepath" 8 "strings" 9 "testing" 10 11 "github.com/docker/docker/integration-cli/cli" 12 "github.com/docker/docker/testutil" 13 "github.com/pkg/errors" 14 "gotest.tools/v3/icmd" 15 ) 16 17 func getPrefixAndSlashFromDaemonPlatform() (prefix, slash string) { 18 if testEnv.DaemonInfo.OSType == "windows" { 19 return "c:", `\` 20 } 21 return "", "/" 22 } 23 24 // TODO: update code to call cmd.RunCmd directly, and remove this function 25 // Deprecated: use gotest.tools/icmd 26 func runCommandWithOutput(execCmd *exec.Cmd) (string, int, error) { 27 result := icmd.RunCmd(icmd.Cmd{ 28 Command: execCmd.Args, 29 Env: execCmd.Env, 30 Dir: execCmd.Dir, 31 Stdin: execCmd.Stdin, 32 Stdout: execCmd.Stdout, 33 }) 34 return result.Combined(), result.ExitCode, result.Error 35 } 36 37 // ParseCgroupPaths parses 'procCgroupData', which is output of '/proc/<pid>/cgroup', and returns 38 // a map which cgroup name as key and path as value. 39 func ParseCgroupPaths(procCgroupData string) map[string]string { 40 cgroupPaths := map[string]string{} 41 for _, line := range strings.Split(procCgroupData, "\n") { 42 parts := strings.Split(line, ":") 43 if len(parts) != 3 { 44 continue 45 } 46 cgroupPaths[parts[1]] = parts[2] 47 } 48 return cgroupPaths 49 } 50 51 // RandomTmpDirPath provides a temporary path with rand string appended. 52 // does not create or checks if it exists. 53 func RandomTmpDirPath(s string, platform string) string { 54 // TODO: why doesn't this use os.TempDir() ? 55 tmp := "/tmp" 56 if platform == "windows" { 57 tmp = os.Getenv("TEMP") 58 } 59 path := filepath.Join(tmp, fmt.Sprintf("%s.%s", s, testutil.GenerateRandomAlphaOnlyString(10))) 60 if platform == "windows" { 61 return filepath.FromSlash(path) // Using \ 62 } 63 return filepath.ToSlash(path) // Using / 64 } 65 66 // RunCommandPipelineWithOutput runs the array of commands with the output 67 // of each pipelined with the following (like cmd1 | cmd2 | cmd3 would do). 68 // It returns the final output, the exitCode different from 0 and the error 69 // if something bad happened. 70 // Deprecated: use icmd instead 71 func RunCommandPipelineWithOutput(cmds ...*exec.Cmd) (output string, err error) { 72 if len(cmds) < 2 { 73 return "", errors.New("pipeline does not have multiple cmds") 74 } 75 76 // connect stdin of each cmd to stdout pipe of previous cmd 77 for i, cmd := range cmds { 78 if i > 0 { 79 prevCmd := cmds[i-1] 80 cmd.Stdin, err = prevCmd.StdoutPipe() 81 82 if err != nil { 83 return "", fmt.Errorf("cannot set stdout pipe for %s: %v", cmd.Path, err) 84 } 85 } 86 } 87 88 // start all cmds except the last 89 for _, cmd := range cmds[:len(cmds)-1] { 90 if err = cmd.Start(); err != nil { 91 return "", fmt.Errorf("starting %s failed with error: %v", cmd.Path, err) 92 } 93 } 94 95 defer func() { 96 var pipeErrMsgs []string 97 // wait all cmds except the last to release their resources 98 for _, cmd := range cmds[:len(cmds)-1] { 99 if pipeErr := cmd.Wait(); pipeErr != nil { 100 pipeErrMsgs = append(pipeErrMsgs, fmt.Sprintf("command %s failed with error: %v", cmd.Path, pipeErr)) 101 } 102 } 103 if len(pipeErrMsgs) > 0 && err == nil { 104 err = fmt.Errorf("pipelineError from Wait: %v", strings.Join(pipeErrMsgs, ", ")) 105 } 106 }() 107 108 // wait on last cmd 109 out, err := cmds[len(cmds)-1].CombinedOutput() 110 return string(out), err 111 } 112 113 type elementListOptions struct { 114 element, format string 115 } 116 117 func existingElements(c *testing.T, opts elementListOptions) []string { 118 var args []string 119 switch opts.element { 120 case "container": 121 args = append(args, "ps", "-a") 122 case "image": 123 args = append(args, "images", "-a") 124 case "network": 125 args = append(args, "network", "ls") 126 case "plugin": 127 args = append(args, "plugin", "ls") 128 case "volume": 129 args = append(args, "volume", "ls") 130 } 131 if opts.format != "" { 132 args = append(args, "--format", opts.format) 133 } 134 out := cli.DockerCmd(c, args...).Combined() 135 var lines []string 136 for _, l := range strings.Split(out, "\n") { 137 if l != "" { 138 lines = append(lines, l) 139 } 140 } 141 return lines 142 } 143 144 // ExistingContainerIDs returns a list of currently existing container IDs. 145 func ExistingContainerIDs(c *testing.T) []string { 146 return existingElements(c, elementListOptions{element: "container", format: "{{.ID}}"}) 147 } 148 149 // ExistingContainerNames returns a list of existing container names. 150 func ExistingContainerNames(c *testing.T) []string { 151 return existingElements(c, elementListOptions{element: "container", format: "{{.Names}}"}) 152 } 153 154 // RemoveLinesForExistingElements removes existing elements from the output of a 155 // docker command. 156 // This function takes an output []string and returns a []string. 157 func RemoveLinesForExistingElements(output, existing []string) []string { 158 for _, e := range existing { 159 index := -1 160 for i, line := range output { 161 if strings.Contains(line, e) { 162 index = i 163 break 164 } 165 } 166 if index != -1 { 167 output = append(output[:index], output[index+1:]...) 168 } 169 } 170 return output 171 } 172 173 // RemoveOutputForExistingElements removes existing elements from the output of 174 // a docker command. 175 // This function takes an output string and returns a string. 176 func RemoveOutputForExistingElements(output string, existing []string) string { 177 res := RemoveLinesForExistingElements(strings.Split(output, "\n"), existing) 178 return strings.Join(res, "\n") 179 }