2015-02-03 22:51:35 -05:00
package main
import (
2015-02-06 17:17:34 -05:00
"os"
2015-02-03 22:51:35 -05:00
"os/exec"
2015-02-06 17:17:34 -05:00
"runtime"
2015-02-03 22:51:35 -05:00
"strings"
2015-02-04 18:28:51 -05:00
"unicode"
2015-02-18 16:32:42 -05:00
"github.com/docker/docker/pkg/homedir"
2015-10-20 05:40:24 -04:00
"github.com/docker/docker/pkg/integration/checker"
2015-04-18 12:46:47 -04:00
"github.com/go-check/check"
2015-02-03 22:51:35 -05:00
)
2015-04-18 12:46:47 -04:00
func ( s * DockerSuite ) TestHelpTextVerify ( c * check . C ) {
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-02-03 22:51:35 -05:00
// Make sure main help text fits within 80 chars and that
2015-02-06 17:17:34 -05:00
// on non-windows system we use ~ when possible (to shorten things).
// Test for HOME set to its default value and set to "/" on linux
// Yes on windows setting up an array and looping (right now) isn't
// necessary because we just have one value, but we'll need the
// array/loop on linux so we might as well set it up so that we can
// test any number of home dirs later on and all we need to do is
// modify the array - the rest of the testing infrastructure should work
homes := [ ] string { homedir . Get ( ) }
2015-02-03 22:51:35 -05:00
2015-02-06 17:17:34 -05:00
// Non-Windows machines need to test for this special case of $HOME
if runtime . GOOS != "windows" {
homes = append ( homes , "/" )
2015-02-03 22:51:35 -05:00
}
2015-02-18 16:32:42 -05:00
2015-02-06 17:17:34 -05:00
homeKey := homedir . Key ( )
baseEnvs := os . Environ ( )
2015-02-03 22:51:35 -05:00
2015-02-06 17:17:34 -05:00
// Remove HOME env var from list so we can add a new value later.
for i , env := range baseEnvs {
if strings . HasPrefix ( env , homeKey + "=" ) {
baseEnvs = append ( baseEnvs [ : i ] , baseEnvs [ i + 1 : ] ... )
2015-02-04 18:28:51 -05:00
break
}
2015-02-06 17:17:34 -05:00
}
2015-02-04 18:28:51 -05:00
2015-02-06 17:17:34 -05:00
for _ , home := range homes {
// Dup baseEnvs and add our new HOME value
newEnvs := make ( [ ] string , len ( baseEnvs ) + 1 )
copy ( newEnvs , baseEnvs )
newEnvs [ len ( newEnvs ) - 1 ] = homeKey + "=" + home
2015-02-04 18:28:51 -05:00
2015-02-06 17:17:34 -05:00
scanForHome := runtime . GOOS != "windows" && home != "/"
2015-02-04 18:28:51 -05:00
2015-02-06 17:17:34 -05:00
// Check main help text to make sure its not over 80 chars
helpCmd := exec . Command ( dockerBinary , "help" )
helpCmd . Env = newEnvs
2015-10-20 05:40:24 -04:00
out , _ , err := runCommandWithOutput ( helpCmd )
c . Assert ( err , checker . IsNil , check . Commentf ( out ) )
2015-02-03 22:51:35 -05:00
lines := strings . Split ( out , "\n" )
for _ , line := range lines {
2015-10-20 05:40:24 -04:00
c . Assert ( len ( line ) , checker . LessOrEqualThan , 80 , check . Commentf ( "Line is too long:\n%s" , line ) )
2015-03-03 12:04:06 -05:00
2015-03-11 09:11:15 -04:00
// All lines should not end with a space
2015-10-20 05:40:24 -04:00
c . Assert ( line , checker . Not ( checker . HasSuffix ) , " " , check . Commentf ( "Line should not end with a space" ) )
2015-03-11 09:11:15 -04:00
2015-02-06 17:17:34 -05:00
if scanForHome && strings . Contains ( line , ` = ` + home ) {
2015-04-18 12:46:47 -04:00
c . Fatalf ( "Line should use '%q' instead of %q:\n%s" , homedir . GetShortcutString ( ) , home , line )
2015-02-06 17:17:34 -05:00
}
if runtime . GOOS != "windows" {
i := strings . Index ( line , homedir . GetShortcutString ( ) )
if i >= 0 && i != len ( line ) - 1 && line [ i + 1 ] != '/' {
2015-04-18 12:46:47 -04:00
c . Fatalf ( "Main help should not have used home shortcut:\n%s" , line )
2015-02-06 17:17:34 -05:00
}
2015-02-03 22:51:35 -05:00
}
}
2015-10-07 08:09:46 -04:00
// Make sure each cmd's help text fits within 90 chars and that
2015-02-06 17:17:34 -05:00
// on non-windows system we use ~ when possible (to shorten things).
// Pull the list of commands from the "Commands:" section of docker help
helpCmd = exec . Command ( dockerBinary , "help" )
helpCmd . Env = newEnvs
2015-10-20 05:40:24 -04:00
out , _ , err = runCommandWithOutput ( helpCmd )
c . Assert ( err , checker . IsNil , check . Commentf ( out ) )
2015-02-06 17:17:34 -05:00
i := strings . Index ( out , "Commands:" )
2015-10-20 05:40:24 -04:00
c . Assert ( i , checker . GreaterOrEqualThan , 0 , check . Commentf ( "Missing 'Commands:' in:\n%s" , out ) )
2015-02-06 17:17:34 -05:00
cmds := [ ] string { }
2015-05-01 10:00:43 -04:00
// Grab all chars starting at "Commands:"
helpOut := strings . Split ( out [ i : ] , "\n" )
// First line is just "Commands:"
if isLocalDaemon {
// Replace first line with "daemon" command since it's not part of the list of commands.
helpOut [ 0 ] = " daemon"
} else {
// Skip first line
helpOut = helpOut [ 1 : ]
}
2015-05-23 11:57:50 -04:00
2015-09-08 17:19:27 -04:00
// Create the list of commands we want to test
cmdsToTest := [ ] string { }
for _ , cmd := range helpOut {
2015-02-06 17:17:34 -05:00
// Stop on blank line or non-idented line
if cmd == "" || ! unicode . IsSpace ( rune ( cmd [ 0 ] ) ) {
break
}
// Grab just the first word of each line
cmd = strings . Split ( strings . TrimSpace ( cmd ) , " " ) [ 0 ]
2015-09-08 17:19:27 -04:00
cmds = append ( cmds , cmd ) // Saving count for later
cmdsToTest = append ( cmdsToTest , cmd )
}
// Add some 'two word' commands - would be nice to automatically
// calculate this list - somehow
cmdsToTest = append ( cmdsToTest , "volume create" )
cmdsToTest = append ( cmdsToTest , "volume inspect" )
cmdsToTest = append ( cmdsToTest , "volume ls" )
cmdsToTest = append ( cmdsToTest , "volume rm" )
for _ , cmd := range cmdsToTest {
var stderr string
args := strings . Split ( cmd + " --help" , " " )
2015-02-06 17:17:34 -05:00
2015-05-23 11:57:50 -04:00
// Check the full usage text
2015-09-08 17:19:27 -04:00
helpCmd := exec . Command ( dockerBinary , args ... )
2015-02-06 17:17:34 -05:00
helpCmd . Env = newEnvs
2015-10-20 05:40:24 -04:00
out , stderr , _ , err = runCommandWithStdoutStderr ( helpCmd )
c . Assert ( len ( stderr ) , checker . Equals , 0 , check . Commentf ( "Error on %q help. non-empty stderr:%q" , cmd , stderr ) )
c . Assert ( out , checker . Not ( checker . HasSuffix ) , "\n\n" , check . Commentf ( "Should not have blank line on %q\n" , cmd ) )
2015-11-18 21:27:59 -05:00
c . Assert ( out , checker . Contains , "--help" , check . Commentf ( "All commands should mention '--help'. Command '%v' did not.\n" , cmd ) )
2015-10-20 05:40:24 -04:00
c . Assert ( err , checker . IsNil , check . Commentf ( out ) )
2015-05-23 11:57:50 -04:00
// Check each line for lots of stuff
2015-02-06 17:17:34 -05:00
lines := strings . Split ( out , "\n" )
for _ , line := range lines {
2015-12-08 10:37:59 -05:00
c . Assert ( len ( line ) , checker . LessOrEqualThan , 103 , check . Commentf ( "Help for %q is too long:\n%s" , cmd , line ) )
2015-03-03 12:04:06 -05:00
2015-02-06 17:17:34 -05:00
if scanForHome && strings . Contains ( line , ` " ` + home ) {
2015-04-18 12:46:47 -04:00
c . Fatalf ( "Help for %q should use ~ instead of %q on:\n%s" ,
2015-02-06 17:17:34 -05:00
cmd , home , line )
}
i := strings . Index ( line , "~" )
if i >= 0 && i != len ( line ) - 1 && line [ i + 1 ] != '/' {
2015-04-18 12:46:47 -04:00
c . Fatalf ( "Help for %q should not have used ~:\n%s" , cmd , line )
2015-02-06 17:17:34 -05:00
}
2015-03-03 12:04:06 -05:00
// If a line starts with 4 spaces then assume someone
// added a multi-line description for an option and we need
// to flag it
2015-10-20 05:40:24 -04:00
c . Assert ( line , checker . Not ( checker . HasPrefix ) , " " , check . Commentf ( "Help for %q should not have a multi-line option" , cmd ) )
2015-03-03 12:04:06 -05:00
// Options should NOT end with a period
if strings . HasPrefix ( line , " -" ) && strings . HasSuffix ( line , "." ) {
2015-04-18 12:46:47 -04:00
c . Fatalf ( "Help for %q should not end with a period: %s" , cmd , line )
2015-03-03 12:04:06 -05:00
}
2015-03-11 06:48:57 -04:00
2015-03-11 09:11:15 -04:00
// Options should NOT end with a space
2015-10-20 05:40:24 -04:00
c . Assert ( line , checker . Not ( checker . HasSuffix ) , " " , check . Commentf ( "Help for %q should not end with a space" , cmd ) )
2015-03-11 09:11:15 -04:00
2015-02-06 17:17:34 -05:00
}
2015-05-23 11:57:50 -04:00
// For each command make sure we generate an error
// if we give a bad arg
2015-09-08 17:19:27 -04:00
args = strings . Split ( cmd + " --badArg" , " " )
2015-10-20 05:40:24 -04:00
out , _ , err = dockerCmdWithError ( args ... )
c . Assert ( err , checker . NotNil , check . Commentf ( out ) )
2015-05-23 11:57:50 -04:00
// Be really picky
2015-10-20 05:40:24 -04:00
c . Assert ( stderr , checker . Not ( checker . HasSuffix ) , "\n\n" , check . Commentf ( "Should not have a blank line at the end of 'docker rm'\n" ) )
2015-05-23 11:57:50 -04:00
// Now make sure that each command will print a short-usage
// (not a full usage - meaning no opts section) if we
// are missing a required arg or pass in a bad arg
// These commands will never print a short-usage so don't test
noShortUsage := map [ string ] string {
2015-07-14 10:33:24 -04:00
"images" : "" ,
"login" : "" ,
"logout" : "" ,
"network" : "" ,
2015-10-03 08:53:25 -04:00
"stats" : "" ,
2015-05-23 11:57:50 -04:00
}
if _ , ok := noShortUsage [ cmd ] ; ! ok {
// For each command run it w/o any args. It will either return
// valid output or print a short-usage
var dCmd * exec . Cmd
var stdout , stderr string
var args [ ] string
// skipNoArgs are ones that we don't want to try w/o
// any args. Either because it'll hang the test or
// lead to incorrect test result (like false negative).
// Whatever the reason, skip trying to run w/o args and
// jump to trying with a bogus arg.
2015-05-01 10:00:43 -04:00
skipNoArgs := map [ string ] struct { } {
"daemon" : { } ,
"events" : { } ,
"load" : { } ,
2015-05-23 11:57:50 -04:00
}
2015-10-20 05:40:24 -04:00
ec := 0
2015-05-23 11:57:50 -04:00
if _ , ok := skipNoArgs [ cmd ] ; ! ok {
2015-09-08 17:19:27 -04:00
args = strings . Split ( cmd , " " )
2015-05-23 11:57:50 -04:00
dCmd = exec . Command ( dockerBinary , args ... )
stdout , stderr , ec , err = runCommandWithStdoutStderr ( dCmd )
}
// If its ok w/o any args then try again with an arg
if ec == 0 {
2015-09-08 17:19:27 -04:00
args = strings . Split ( cmd + " badArg" , " " )
2015-05-23 11:57:50 -04:00
dCmd = exec . Command ( dockerBinary , args ... )
stdout , stderr , ec , err = runCommandWithStdoutStderr ( dCmd )
}
if len ( stdout ) != 0 || len ( stderr ) == 0 || ec == 0 || err == nil {
c . Fatalf ( "Bad output from %q\nstdout:%q\nstderr:%q\nec:%d\nerr:%q" , args , stdout , stderr , ec , err )
}
// Should have just short usage
2015-10-20 05:40:24 -04:00
c . Assert ( stderr , checker . Contains , "\nUsage:\t" , check . Commentf ( "Missing short usage on %q\n" , args ) )
2015-05-23 11:57:50 -04:00
// But shouldn't have full usage
2015-10-20 05:40:24 -04:00
c . Assert ( stderr , checker . Not ( checker . Contains ) , "--help=false" , check . Commentf ( "Should not have full usage on %q\n" , args ) )
c . Assert ( stderr , checker . Not ( checker . HasSuffix ) , "\n\n" , check . Commentf ( "Should not have a blank line on %q\n" , args ) )
2015-05-23 11:57:50 -04:00
}
2015-02-06 17:17:34 -05:00
}
2015-07-14 10:33:24 -04:00
// Number of commands for standard release and experimental release
standard := 40
experimental := 1
expected := standard + experimental
2015-05-01 10:00:43 -04:00
if isLocalDaemon {
expected ++ // for the daemon command
}
2015-10-20 05:40:24 -04:00
c . Assert ( len ( cmds ) , checker . LessOrEqualThan , expected , check . Commentf ( "Wrong # of cmds, it should be: %d\nThe list:\n%q" , expected , cmds ) )
2015-02-04 18:28:51 -05:00
}
2015-02-03 22:51:35 -05:00
}
2015-05-09 14:33:06 -04:00
2015-05-23 11:57:50 -04:00
func ( s * DockerSuite ) TestHelpExitCodesHelpOutput ( c * check . C ) {
2015-08-28 13:36:42 -04:00
testRequires ( c , DaemonIsLinux )
2015-05-23 11:57:50 -04:00
// Test to make sure the exit code and output (stdout vs stderr) of
// various good and bad cases are what we expect
2015-05-09 14:33:06 -04:00
2015-05-23 11:57:50 -04:00
// docker : stdout=all, stderr=empty, rc=0
2015-10-20 05:40:24 -04:00
out , _ , err := dockerCmdWithError ( )
c . Assert ( err , checker . IsNil , check . Commentf ( out ) )
2015-05-23 11:57:50 -04:00
// Be really pick
2015-10-20 05:40:24 -04:00
c . Assert ( out , checker . Not ( checker . HasSuffix ) , "\n\n" , check . Commentf ( "Should not have a blank line at the end of 'docker'\n" ) )
2015-05-09 14:33:06 -04:00
2015-05-23 11:57:50 -04:00
// docker help: stdout=all, stderr=empty, rc=0
2015-10-20 05:40:24 -04:00
out , _ , err = dockerCmdWithError ( "help" )
c . Assert ( err , checker . IsNil , check . Commentf ( out ) )
2015-05-23 11:57:50 -04:00
// Be really pick
2015-10-20 05:40:24 -04:00
c . Assert ( out , checker . Not ( checker . HasSuffix ) , "\n\n" , check . Commentf ( "Should not have a blank line at the end of 'docker help'\n" ) )
2015-05-09 14:33:06 -04:00
2015-05-23 11:57:50 -04:00
// docker --help: stdout=all, stderr=empty, rc=0
2015-10-20 05:40:24 -04:00
out , _ , err = dockerCmdWithError ( "--help" )
c . Assert ( err , checker . IsNil , check . Commentf ( out ) )
2015-05-23 11:57:50 -04:00
// Be really pick
2015-10-20 05:40:24 -04:00
c . Assert ( out , checker . Not ( checker . HasSuffix ) , "\n\n" , check . Commentf ( "Should not have a blank line at the end of 'docker --help'\n" ) )
2015-05-09 14:33:06 -04:00
2015-05-23 11:57:50 -04:00
// docker inspect busybox: stdout=all, stderr=empty, rc=0
// Just making sure stderr is empty on valid cmd
2015-10-20 05:40:24 -04:00
out , _ , err = dockerCmdWithError ( "inspect" , "busybox" )
c . Assert ( err , checker . IsNil , check . Commentf ( out ) )
2015-05-23 11:57:50 -04:00
// Be really pick
2015-10-20 05:40:24 -04:00
c . Assert ( out , checker . Not ( checker . HasSuffix ) , "\n\n" , check . Commentf ( "Should not have a blank line at the end of 'docker inspect busyBox'\n" ) )
2015-05-23 11:57:50 -04:00
// docker rm: stdout=empty, stderr=all, rc!=0
// testing the min arg error msg
2015-10-20 05:40:24 -04:00
cmd := exec . Command ( dockerBinary , "rm" )
stdout , stderr , _ , err := runCommandWithStdoutStderr ( cmd )
c . Assert ( err , checker . NotNil )
c . Assert ( stdout , checker . Equals , "" )
2015-05-23 11:57:50 -04:00
// Should not contain full help text but should contain info about
// # of args and Usage line
2015-10-20 05:40:24 -04:00
c . Assert ( stderr , checker . Contains , "requires a minimum" , check . Commentf ( "Missing # of args text from 'docker rm'\n" ) )
2015-05-23 11:57:50 -04:00
// docker rm NoSuchContainer: stdout=empty, stderr=all, rc=0
// testing to make sure no blank line on error
cmd = exec . Command ( dockerBinary , "rm" , "NoSuchContainer" )
2015-10-20 05:40:24 -04:00
stdout , stderr , _ , err = runCommandWithStdoutStderr ( cmd )
c . Assert ( err , checker . NotNil )
c . Assert ( len ( stderr ) , checker . Not ( checker . Equals ) , 0 )
c . Assert ( stdout , checker . Equals , "" )
2015-05-23 11:57:50 -04:00
// Be really picky
2015-10-20 05:40:24 -04:00
c . Assert ( stderr , checker . Not ( checker . HasSuffix ) , "\n\n" , check . Commentf ( "Should not have a blank line at the end of 'docker rm'\n" ) )
2015-05-23 11:57:50 -04:00
// docker BadCmd: stdout=empty, stderr=all, rc=0
cmd = exec . Command ( dockerBinary , "BadCmd" )
2015-10-20 05:40:24 -04:00
stdout , stderr , _ , err = runCommandWithStdoutStderr ( cmd )
c . Assert ( err , checker . NotNil )
c . Assert ( stdout , checker . Equals , "" )
c . Assert ( stderr , checker . Equals , "docker: 'BadCmd' is not a docker command.\nSee 'docker --help'.\n" , check . Commentf ( "Unexcepted output for 'docker badCmd'\n" ) )
2015-05-09 14:33:06 -04:00
}