github.com/slene/docker@v1.8.0-rc1/integration-cli/docker_cli_help_test.go (about) 1 package main 2 3 import ( 4 "os" 5 "os/exec" 6 "runtime" 7 "strings" 8 "unicode" 9 10 "github.com/docker/docker/pkg/homedir" 11 "github.com/go-check/check" 12 ) 13 14 func (s *DockerSuite) TestHelpTextVerify(c *check.C) { 15 // Make sure main help text fits within 80 chars and that 16 // on non-windows system we use ~ when possible (to shorten things). 17 // Test for HOME set to its default value and set to "/" on linux 18 // Yes on windows setting up an array and looping (right now) isn't 19 // necessary because we just have one value, but we'll need the 20 // array/loop on linux so we might as well set it up so that we can 21 // test any number of home dirs later on and all we need to do is 22 // modify the array - the rest of the testing infrastructure should work 23 homes := []string{homedir.Get()} 24 25 // Non-Windows machines need to test for this special case of $HOME 26 if runtime.GOOS != "windows" { 27 homes = append(homes, "/") 28 } 29 30 homeKey := homedir.Key() 31 baseEnvs := os.Environ() 32 33 // Remove HOME env var from list so we can add a new value later. 34 for i, env := range baseEnvs { 35 if strings.HasPrefix(env, homeKey+"=") { 36 baseEnvs = append(baseEnvs[:i], baseEnvs[i+1:]...) 37 break 38 } 39 } 40 41 for _, home := range homes { 42 // Dup baseEnvs and add our new HOME value 43 newEnvs := make([]string, len(baseEnvs)+1) 44 copy(newEnvs, baseEnvs) 45 newEnvs[len(newEnvs)-1] = homeKey + "=" + home 46 47 scanForHome := runtime.GOOS != "windows" && home != "/" 48 49 // Check main help text to make sure its not over 80 chars 50 helpCmd := exec.Command(dockerBinary, "help") 51 helpCmd.Env = newEnvs 52 out, ec, err := runCommandWithOutput(helpCmd) 53 if err != nil || ec != 0 { 54 c.Fatalf("docker help should have worked\nout:%s\nec:%d", out, ec) 55 } 56 lines := strings.Split(out, "\n") 57 for _, line := range lines { 58 if len(line) > 80 { 59 c.Fatalf("Line is too long(%d chars):\n%s", len(line), line) 60 } 61 62 // All lines should not end with a space 63 if strings.HasSuffix(line, " ") { 64 c.Fatalf("Line should not end with a space: %s", line) 65 } 66 67 if scanForHome && strings.Contains(line, `=`+home) { 68 c.Fatalf("Line should use '%q' instead of %q:\n%s", homedir.GetShortcutString(), home, line) 69 } 70 if runtime.GOOS != "windows" { 71 i := strings.Index(line, homedir.GetShortcutString()) 72 if i >= 0 && i != len(line)-1 && line[i+1] != '/' { 73 c.Fatalf("Main help should not have used home shortcut:\n%s", line) 74 } 75 } 76 } 77 78 // Make sure each cmd's help text fits within 80 chars and that 79 // on non-windows system we use ~ when possible (to shorten things). 80 // Pull the list of commands from the "Commands:" section of docker help 81 helpCmd = exec.Command(dockerBinary, "help") 82 helpCmd.Env = newEnvs 83 out, ec, err = runCommandWithOutput(helpCmd) 84 if err != nil || ec != 0 { 85 c.Fatalf("docker help should have worked\nout:%s\nec:%d", out, ec) 86 } 87 i := strings.Index(out, "Commands:") 88 if i < 0 { 89 c.Fatalf("Missing 'Commands:' in:\n%s", out) 90 } 91 92 cmds := []string{} 93 // Grab all chars starting at "Commands:" 94 helpOut := strings.Split(out[i:], "\n") 95 // First line is just "Commands:" 96 if isLocalDaemon { 97 // Replace first line with "daemon" command since it's not part of the list of commands. 98 helpOut[0] = " daemon" 99 } else { 100 // Skip first line 101 helpOut = helpOut[1:] 102 } 103 for _, cmd := range helpOut { 104 var stderr string 105 106 // Stop on blank line or non-idented line 107 if cmd == "" || !unicode.IsSpace(rune(cmd[0])) { 108 break 109 } 110 111 // Grab just the first word of each line 112 cmd = strings.Split(strings.TrimSpace(cmd), " ")[0] 113 cmds = append(cmds, cmd) 114 115 // Check the full usage text 116 helpCmd := exec.Command(dockerBinary, cmd, "--help") 117 helpCmd.Env = newEnvs 118 out, stderr, ec, err = runCommandWithStdoutStderr(helpCmd) 119 if len(stderr) != 0 { 120 c.Fatalf("Error on %q help. non-empty stderr:%q", cmd, stderr) 121 } 122 if strings.HasSuffix(out, "\n\n") { 123 c.Fatalf("Should not have blank line on %q\nout:%q", cmd, out) 124 } 125 if !strings.Contains(out, "--help=false") { 126 c.Fatalf("Should show full usage on %q\nout:%q", cmd, out) 127 } 128 if err != nil || ec != 0 { 129 c.Fatalf("Error on %q help: %s\nexit code:%d", cmd, out, ec) 130 } 131 132 // Check each line for lots of stuff 133 lines := strings.Split(out, "\n") 134 for _, line := range lines { 135 if len(line) > 90 { 136 c.Fatalf("Help for %q is too long(%d chars):\n%s", cmd, 137 len(line), line) 138 } 139 140 if scanForHome && strings.Contains(line, `"`+home) { 141 c.Fatalf("Help for %q should use ~ instead of %q on:\n%s", 142 cmd, home, line) 143 } 144 i := strings.Index(line, "~") 145 if i >= 0 && i != len(line)-1 && line[i+1] != '/' { 146 c.Fatalf("Help for %q should not have used ~:\n%s", cmd, line) 147 } 148 149 // If a line starts with 4 spaces then assume someone 150 // added a multi-line description for an option and we need 151 // to flag it 152 if strings.HasPrefix(line, " ") { 153 c.Fatalf("Help for %q should not have a multi-line option: %s", cmd, line) 154 } 155 156 // Options should NOT end with a period 157 if strings.HasPrefix(line, " -") && strings.HasSuffix(line, ".") { 158 c.Fatalf("Help for %q should not end with a period: %s", cmd, line) 159 } 160 161 // Options should NOT end with a space 162 if strings.HasSuffix(line, " ") { 163 c.Fatalf("Help for %q should not end with a space: %s", cmd, line) 164 } 165 166 } 167 168 // For each command make sure we generate an error 169 // if we give a bad arg 170 dCmd := exec.Command(dockerBinary, cmd, "--badArg") 171 out, stderr, ec, err = runCommandWithStdoutStderr(dCmd) 172 if len(out) != 0 || len(stderr) == 0 || ec == 0 || err == nil { 173 c.Fatalf("Bad results from 'docker %s --badArg'\nec:%d\nstdout:%s\nstderr:%s\nerr:%q", cmd, ec, out, stderr, err) 174 } 175 // Be really picky 176 if strings.HasSuffix(stderr, "\n\n") { 177 c.Fatalf("Should not have a blank line at the end of 'docker rm'\n%s", stderr) 178 } 179 180 // Now make sure that each command will print a short-usage 181 // (not a full usage - meaning no opts section) if we 182 // are missing a required arg or pass in a bad arg 183 184 // These commands will never print a short-usage so don't test 185 noShortUsage := map[string]string{ 186 "images": "", 187 "login": "", 188 "logout": "", 189 } 190 191 if _, ok := noShortUsage[cmd]; !ok { 192 // For each command run it w/o any args. It will either return 193 // valid output or print a short-usage 194 var dCmd *exec.Cmd 195 var stdout, stderr string 196 var args []string 197 198 // skipNoArgs are ones that we don't want to try w/o 199 // any args. Either because it'll hang the test or 200 // lead to incorrect test result (like false negative). 201 // Whatever the reason, skip trying to run w/o args and 202 // jump to trying with a bogus arg. 203 skipNoArgs := map[string]struct{}{ 204 "daemon": {}, 205 "events": {}, 206 "load": {}, 207 } 208 209 ec = 0 210 if _, ok := skipNoArgs[cmd]; !ok { 211 args = []string{cmd} 212 dCmd = exec.Command(dockerBinary, args...) 213 stdout, stderr, ec, err = runCommandWithStdoutStderr(dCmd) 214 } 215 216 // If its ok w/o any args then try again with an arg 217 if ec == 0 { 218 args = []string{cmd, "badArg"} 219 dCmd = exec.Command(dockerBinary, args...) 220 stdout, stderr, ec, err = runCommandWithStdoutStderr(dCmd) 221 } 222 223 if len(stdout) != 0 || len(stderr) == 0 || ec == 0 || err == nil { 224 c.Fatalf("Bad output from %q\nstdout:%q\nstderr:%q\nec:%d\nerr:%q", args, stdout, stderr, ec, err) 225 } 226 // Should have just short usage 227 if !strings.Contains(stderr, "\nUsage:\t") { 228 c.Fatalf("Missing short usage on %q\nstderr:%q", args, stderr) 229 } 230 // But shouldn't have full usage 231 if strings.Contains(stderr, "--help=false") { 232 c.Fatalf("Should not have full usage on %q\nstderr:%q", args, stderr) 233 } 234 if strings.HasSuffix(stderr, "\n\n") { 235 c.Fatalf("Should not have a blank line on %q\nstderr:%q", args, stderr) 236 } 237 } 238 239 } 240 241 expected := 39 242 if isLocalDaemon { 243 expected++ // for the daemon command 244 } 245 if len(cmds) != expected { 246 c.Fatalf("Wrong # of cmds(%d), it should be: %d\nThe list:\n%q", 247 len(cmds), expected, cmds) 248 } 249 } 250 251 } 252 253 func (s *DockerSuite) TestHelpExitCodesHelpOutput(c *check.C) { 254 // Test to make sure the exit code and output (stdout vs stderr) of 255 // various good and bad cases are what we expect 256 257 // docker : stdout=all, stderr=empty, rc=0 258 cmd := exec.Command(dockerBinary) 259 stdout, stderr, ec, err := runCommandWithStdoutStderr(cmd) 260 if len(stdout) == 0 || len(stderr) != 0 || ec != 0 || err != nil { 261 c.Fatalf("Bad results from 'docker'\nec:%d\nstdout:%s\nstderr:%s\nerr:%v", ec, stdout, stderr, err) 262 } 263 // Be really pick 264 if strings.HasSuffix(stdout, "\n\n") { 265 c.Fatalf("Should not have a blank line at the end of 'docker'\n%s", stdout) 266 } 267 268 // docker help: stdout=all, stderr=empty, rc=0 269 cmd = exec.Command(dockerBinary, "help") 270 stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd) 271 if len(stdout) == 0 || len(stderr) != 0 || ec != 0 || err != nil { 272 c.Fatalf("Bad results from 'docker help'\nec:%d\nstdout:%s\nstderr:%s\nerr:%v", ec, stdout, stderr, err) 273 } 274 // Be really pick 275 if strings.HasSuffix(stdout, "\n\n") { 276 c.Fatalf("Should not have a blank line at the end of 'docker help'\n%s", stdout) 277 } 278 279 // docker --help: stdout=all, stderr=empty, rc=0 280 cmd = exec.Command(dockerBinary, "--help") 281 stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd) 282 if len(stdout) == 0 || len(stderr) != 0 || ec != 0 || err != nil { 283 c.Fatalf("Bad results from 'docker --help'\nec:%d\nstdout:%s\nstderr:%s\nerr:%v", ec, stdout, stderr, err) 284 } 285 // Be really pick 286 if strings.HasSuffix(stdout, "\n\n") { 287 c.Fatalf("Should not have a blank line at the end of 'docker --help'\n%s", stdout) 288 } 289 290 // docker inspect busybox: stdout=all, stderr=empty, rc=0 291 // Just making sure stderr is empty on valid cmd 292 cmd = exec.Command(dockerBinary, "inspect", "busybox") 293 stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd) 294 if len(stdout) == 0 || len(stderr) != 0 || ec != 0 || err != nil { 295 c.Fatalf("Bad results from 'docker inspect busybox'\nec:%d\nstdout:%s\nstderr:%s\nerr:%v", ec, stdout, stderr, err) 296 } 297 // Be really pick 298 if strings.HasSuffix(stdout, "\n\n") { 299 c.Fatalf("Should not have a blank line at the end of 'docker inspect busyBox'\n%s", stdout) 300 } 301 302 // docker rm: stdout=empty, stderr=all, rc!=0 303 // testing the min arg error msg 304 cmd = exec.Command(dockerBinary, "rm") 305 stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd) 306 if len(stdout) != 0 || len(stderr) == 0 || ec == 0 || err == nil { 307 c.Fatalf("Bad results from 'docker rm'\nec:%d\nstdout:%s\nstderr:%s\nerr:%v", ec, stdout, stderr, err) 308 } 309 // Should not contain full help text but should contain info about 310 // # of args and Usage line 311 if !strings.Contains(stderr, "requires a minimum") { 312 c.Fatalf("Missing # of args text from 'docker rm'\nstderr:%s", stderr) 313 } 314 315 // docker rm NoSuchContainer: stdout=empty, stderr=all, rc=0 316 // testing to make sure no blank line on error 317 cmd = exec.Command(dockerBinary, "rm", "NoSuchContainer") 318 stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd) 319 if len(stdout) != 0 || len(stderr) == 0 || ec == 0 || err == nil { 320 c.Fatalf("Bad results from 'docker rm NoSuchContainer'\nec:%d\nstdout:%s\nstderr:%s\nerr:%v", ec, stdout, stderr, err) 321 } 322 // Be really picky 323 if strings.HasSuffix(stderr, "\n\n") { 324 c.Fatalf("Should not have a blank line at the end of 'docker rm'\n%s", stderr) 325 } 326 327 // docker BadCmd: stdout=empty, stderr=all, rc=0 328 cmd = exec.Command(dockerBinary, "BadCmd") 329 stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd) 330 if len(stdout) != 0 || len(stderr) == 0 || ec == 0 || err == nil { 331 c.Fatalf("Bad results from 'docker BadCmd'\nec:%d\nstdout:%s\nstderr:%s\nerr:%v", ec, stdout, stderr, err) 332 } 333 if stderr != "docker: 'BadCmd' is not a docker command.\nSee 'docker --help'.\n" { 334 c.Fatalf("Unexcepted output for 'docker badCmd'\nstderr:%s", stderr) 335 } 336 // Be really picky 337 if strings.HasSuffix(stderr, "\n\n") { 338 c.Fatalf("Should not have a blank line at the end of 'docker rm'\n%s", stderr) 339 } 340 341 }