github.com/rsampaio/docker@v0.7.2-0.20150827203920-fdc73cc3fc31/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 := 40
   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  }