github.com/circular-dark/docker@v1.7.0/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  }