github.com/ld86/docker@v1.7.1-rc3/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 // Grab all chars starting at "Commands:" 93 // Skip first line, its "Commands:" 94 cmds := []string{} 95 for _, cmd := range strings.Split(out[i:], "\n")[1:] { 96 var stderr string 97 98 // Stop on blank line or non-idented line 99 if cmd == "" || !unicode.IsSpace(rune(cmd[0])) { 100 break 101 } 102 103 // Grab just the first word of each line 104 cmd = strings.Split(strings.TrimSpace(cmd), " ")[0] 105 cmds = append(cmds, cmd) 106 107 // Check the full usage text 108 helpCmd := exec.Command(dockerBinary, cmd, "--help") 109 helpCmd.Env = newEnvs 110 out, stderr, ec, err = runCommandWithStdoutStderr(helpCmd) 111 if len(stderr) != 0 { 112 c.Fatalf("Error on %q help. non-empty stderr:%q", cmd, stderr) 113 } 114 if strings.HasSuffix(out, "\n\n") { 115 c.Fatalf("Should not have blank line on %q\nout:%q", cmd, out) 116 } 117 if !strings.Contains(out, "--help=false") { 118 c.Fatalf("Should show full usage on %q\nout:%q", cmd, out) 119 } 120 if err != nil || ec != 0 { 121 c.Fatalf("Error on %q help: %s\nexit code:%d", cmd, out, ec) 122 } 123 124 // Check each line for lots of stuff 125 lines := strings.Split(out, "\n") 126 for _, line := range lines { 127 if len(line) > 80 { 128 c.Fatalf("Help for %q is too long(%d chars):\n%s", cmd, 129 len(line), line) 130 } 131 132 if scanForHome && strings.Contains(line, `"`+home) { 133 c.Fatalf("Help for %q should use ~ instead of %q on:\n%s", 134 cmd, home, line) 135 } 136 i := strings.Index(line, "~") 137 if i >= 0 && i != len(line)-1 && line[i+1] != '/' { 138 c.Fatalf("Help for %q should not have used ~:\n%s", cmd, line) 139 } 140 141 // If a line starts with 4 spaces then assume someone 142 // added a multi-line description for an option and we need 143 // to flag it 144 if strings.HasPrefix(line, " ") { 145 c.Fatalf("Help for %q should not have a multi-line option: %s", cmd, line) 146 } 147 148 // Options should NOT end with a period 149 if strings.HasPrefix(line, " -") && strings.HasSuffix(line, ".") { 150 c.Fatalf("Help for %q should not end with a period: %s", cmd, line) 151 } 152 153 // Options should NOT end with a space 154 if strings.HasSuffix(line, " ") { 155 c.Fatalf("Help for %q should not end with a space: %s", cmd, line) 156 } 157 158 } 159 160 // For each command make sure we generate an error 161 // if we give a bad arg 162 dCmd := exec.Command(dockerBinary, cmd, "--badArg") 163 out, stderr, ec, err = runCommandWithStdoutStderr(dCmd) 164 if len(out) != 0 || len(stderr) == 0 || ec == 0 || err == nil { 165 c.Fatalf("Bad results from 'docker %s --badArg'\nec:%d\nstdout:%s\nstderr:%s\nerr:%q", cmd, ec, out, stderr, err) 166 } 167 // Be really picky 168 if strings.HasSuffix(stderr, "\n\n") { 169 c.Fatalf("Should not have a blank line at the end of 'docker rm'\n%s", stderr) 170 } 171 172 // Now make sure that each command will print a short-usage 173 // (not a full usage - meaning no opts section) if we 174 // are missing a required arg or pass in a bad arg 175 176 // These commands will never print a short-usage so don't test 177 noShortUsage := map[string]string{ 178 "images": "", 179 "login": "", 180 "logout": "", 181 } 182 183 if _, ok := noShortUsage[cmd]; !ok { 184 // For each command run it w/o any args. It will either return 185 // valid output or print a short-usage 186 var dCmd *exec.Cmd 187 var stdout, stderr string 188 var args []string 189 190 // skipNoArgs are ones that we don't want to try w/o 191 // any args. Either because it'll hang the test or 192 // lead to incorrect test result (like false negative). 193 // Whatever the reason, skip trying to run w/o args and 194 // jump to trying with a bogus arg. 195 skipNoArgs := map[string]string{ 196 "events": "", 197 "load": "", 198 } 199 200 ec = 0 201 if _, ok := skipNoArgs[cmd]; !ok { 202 args = []string{cmd} 203 dCmd = exec.Command(dockerBinary, args...) 204 stdout, stderr, ec, err = runCommandWithStdoutStderr(dCmd) 205 } 206 207 // If its ok w/o any args then try again with an arg 208 if ec == 0 { 209 args = []string{cmd, "badArg"} 210 dCmd = exec.Command(dockerBinary, args...) 211 stdout, stderr, ec, err = runCommandWithStdoutStderr(dCmd) 212 } 213 214 if len(stdout) != 0 || len(stderr) == 0 || ec == 0 || err == nil { 215 c.Fatalf("Bad output from %q\nstdout:%q\nstderr:%q\nec:%d\nerr:%q", args, stdout, stderr, ec, err) 216 } 217 // Should have just short usage 218 if !strings.Contains(stderr, "\nUsage: ") { 219 c.Fatalf("Missing short usage on %q\nstderr:%q", args, stderr) 220 } 221 // But shouldn't have full usage 222 if strings.Contains(stderr, "--help=false") { 223 c.Fatalf("Should not have full usage on %q\nstderr:%q", args, stderr) 224 } 225 if strings.HasSuffix(stderr, "\n\n") { 226 c.Fatalf("Should not have a blank line on %q\nstderr:%q", args, stderr) 227 } 228 } 229 230 } 231 232 expected := 39 233 if len(cmds) != expected { 234 c.Fatalf("Wrong # of cmds(%d), it should be: %d\nThe list:\n%q", 235 len(cmds), expected, cmds) 236 } 237 } 238 239 } 240 241 func (s *DockerSuite) TestHelpExitCodesHelpOutput(c *check.C) { 242 // Test to make sure the exit code and output (stdout vs stderr) of 243 // various good and bad cases are what we expect 244 245 // docker : stdout=all, stderr=empty, rc=0 246 cmd := exec.Command(dockerBinary) 247 stdout, stderr, ec, err := runCommandWithStdoutStderr(cmd) 248 if len(stdout) == 0 || len(stderr) != 0 || ec != 0 || err != nil { 249 c.Fatalf("Bad results from 'docker'\nec:%d\nstdout:%s\nstderr:%s\nerr:%q", ec, stdout, stderr, err) 250 } 251 // Be really pick 252 if strings.HasSuffix(stdout, "\n\n") { 253 c.Fatalf("Should not have a blank line at the end of 'docker'\n%s", stdout) 254 } 255 256 // docker help: stdout=all, stderr=empty, rc=0 257 cmd = exec.Command(dockerBinary, "help") 258 stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd) 259 if len(stdout) == 0 || len(stderr) != 0 || ec != 0 || err != nil { 260 c.Fatalf("Bad results from 'docker help'\nec:%d\nstdout:%s\nstderr:%s\nerr:%q", ec, stdout, stderr, err) 261 } 262 // Be really pick 263 if strings.HasSuffix(stdout, "\n\n") { 264 c.Fatalf("Should not have a blank line at the end of 'docker help'\n%s", stdout) 265 } 266 267 // docker --help: stdout=all, stderr=empty, rc=0 268 cmd = exec.Command(dockerBinary, "--help") 269 stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd) 270 if len(stdout) == 0 || len(stderr) != 0 || ec != 0 || err != nil { 271 c.Fatalf("Bad results from 'docker --help'\nec:%d\nstdout:%s\nstderr:%s\nerr:%q", ec, stdout, stderr, err) 272 } 273 // Be really pick 274 if strings.HasSuffix(stdout, "\n\n") { 275 c.Fatalf("Should not have a blank line at the end of 'docker --help'\n%s", stdout) 276 } 277 278 // docker inspect busybox: stdout=all, stderr=empty, rc=0 279 // Just making sure stderr is empty on valid cmd 280 cmd = exec.Command(dockerBinary, "inspect", "busybox") 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 inspect busybox'\nec:%d\nstdout:%s\nstderr:%s\nerr:%q", 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 inspect busyBox'\n%s", stdout) 288 } 289 290 // docker rm: stdout=empty, stderr=all, rc!=0 291 // testing the min arg error msg 292 cmd = exec.Command(dockerBinary, "rm") 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 rm'\nec:%d\nstdout:%s\nstderr:%s\nerr:%q", ec, stdout, stderr, err) 296 } 297 // Should not contain full help text but should contain info about 298 // # of args and Usage line 299 if !strings.Contains(stderr, "requires a minimum") { 300 c.Fatalf("Missing # of args text from 'docker rm'\nstderr:%s", stderr) 301 } 302 303 // docker rm NoSuchContainer: stdout=empty, stderr=all, rc=0 304 // testing to make sure no blank line on error 305 cmd = exec.Command(dockerBinary, "rm", "NoSuchContainer") 306 stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd) 307 if len(stdout) != 0 || len(stderr) == 0 || ec == 0 || err == nil { 308 c.Fatalf("Bad results from 'docker rm NoSuchContainer'\nec:%d\nstdout:%s\nstderr:%s\nerr:%q", ec, stdout, stderr, err) 309 } 310 // Be really picky 311 if strings.HasSuffix(stderr, "\n\n") { 312 c.Fatalf("Should not have a blank line at the end of 'docker rm'\n%s", stderr) 313 } 314 315 // docker BadCmd: stdout=empty, stderr=all, rc=0 316 cmd = exec.Command(dockerBinary, "BadCmd") 317 stdout, stderr, ec, err = runCommandWithStdoutStderr(cmd) 318 if len(stdout) != 0 || len(stderr) == 0 || ec == 0 || err == nil { 319 c.Fatalf("Bad results from 'docker BadCmd'\nec:%d\nstdout:%s\nstderr:%s\nerr:%q", ec, stdout, stderr, err) 320 } 321 if stderr != "docker: 'BadCmd' is not a docker command.\nSee 'docker --help'.\n" { 322 c.Fatalf("Unexcepted output for 'docker badCmd'\nstderr:%s", stderr) 323 } 324 // Be really picky 325 if strings.HasSuffix(stderr, "\n\n") { 326 c.Fatalf("Should not have a blank line at the end of 'docker rm'\n%s", stderr) 327 } 328 329 }