mirror of
https://github.com/moby/moby.git
synced 2022-11-09 12:21:53 -05:00
Improve the time taken by DockerSuite.TestHelpTextVerify. This test runs docker <command> --help on all commands supported and also check the output
when it is passed with bad arguments and no arguments. This patch would divide the total number of commands into five sets and runs them in parallel. Test time is improved from around 9 seconds to around 3 seconds Signed-off-by: Sainath Grandhi <sainath.grandhi@intel.com>
This commit is contained in:
parent
e2221d1f37
commit
7f33ec7507
1 changed files with 148 additions and 104 deletions
|
@ -1,6 +1,7 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"strings"
|
||||
|
@ -13,6 +14,7 @@ import (
|
|||
|
||||
func (s *DockerSuite) TestHelpTextVerify(c *check.C) {
|
||||
testRequires(c, DaemonIsLinux)
|
||||
|
||||
// Make sure main help text fits within 80 chars and that
|
||||
// on non-windows system we use ~ when possible (to shorten things).
|
||||
// Test for HOME set to its default value and set to "/" on linux
|
||||
|
@ -40,6 +42,7 @@ func (s *DockerSuite) TestHelpTextVerify(c *check.C) {
|
|||
}
|
||||
|
||||
for _, home := range homes {
|
||||
|
||||
// Dup baseEnvs and add our new HOME value
|
||||
newEnvs := make([]string, len(baseEnvs)+1)
|
||||
copy(newEnvs, baseEnvs)
|
||||
|
@ -117,114 +120,22 @@ func (s *DockerSuite) TestHelpTextVerify(c *check.C) {
|
|||
cmdsToTest = append(cmdsToTest, "volume ls")
|
||||
cmdsToTest = append(cmdsToTest, "volume rm")
|
||||
|
||||
for _, cmd := range cmdsToTest {
|
||||
var stderr string
|
||||
// Divide the list of commands into go routines and run the func testcommand on the commands in parallel
|
||||
// to save runtime of test
|
||||
|
||||
args := strings.Split(cmd+" --help", " ")
|
||||
errChan := make(chan error)
|
||||
|
||||
// Check the full usage text
|
||||
helpCmd := exec.Command(dockerBinary, args...)
|
||||
helpCmd.Env = newEnvs
|
||||
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))
|
||||
c.Assert(out, checker.Contains, "--help", check.Commentf("All commands should mention '--help'. Command '%v' did not.\n", cmd))
|
||||
|
||||
c.Assert(err, checker.IsNil, check.Commentf(out))
|
||||
|
||||
// Check each line for lots of stuff
|
||||
lines := strings.Split(out, "\n")
|
||||
for _, line := range lines {
|
||||
c.Assert(len(line), checker.LessOrEqualThan, 107, check.Commentf("Help for %q is too long:\n%s", cmd, line))
|
||||
|
||||
if scanForHome && strings.Contains(line, `"`+home) {
|
||||
c.Fatalf("Help for %q should use ~ instead of %q on:\n%s",
|
||||
cmd, home, line)
|
||||
}
|
||||
i := strings.Index(line, "~")
|
||||
if i >= 0 && i != len(line)-1 && line[i+1] != '/' {
|
||||
c.Fatalf("Help for %q should not have used ~:\n%s", cmd, line)
|
||||
}
|
||||
|
||||
// If a line starts with 4 spaces then assume someone
|
||||
// added a multi-line description for an option and we need
|
||||
// to flag it
|
||||
c.Assert(line, checker.Not(checker.HasPrefix), " ", check.Commentf("Help for %q should not have a multi-line option", cmd))
|
||||
|
||||
// Options should NOT end with a period
|
||||
if strings.HasPrefix(line, " -") && strings.HasSuffix(line, ".") {
|
||||
c.Fatalf("Help for %q should not end with a period: %s", cmd, line)
|
||||
}
|
||||
|
||||
// Options should NOT end with a space
|
||||
c.Assert(line, checker.Not(checker.HasSuffix), " ", check.Commentf("Help for %q should not end with a space", cmd))
|
||||
for index := 0; index < len(cmdsToTest); index++ {
|
||||
go func(index int) {
|
||||
errChan <- testCommand(cmdsToTest[index], newEnvs, scanForHome, home)
|
||||
}(index)
|
||||
}
|
||||
|
||||
for index := 0; index < len(cmdsToTest); index++ {
|
||||
err := <-errChan
|
||||
if err != nil {
|
||||
c.Fatal(err)
|
||||
}
|
||||
|
||||
// For each command make sure we generate an error
|
||||
// if we give a bad arg
|
||||
args = strings.Split(cmd+" --badArg", " ")
|
||||
|
||||
out, _, err = dockerCmdWithError(args...)
|
||||
c.Assert(err, checker.NotNil, check.Commentf(out))
|
||||
// Be really picky
|
||||
c.Assert(stderr, checker.Not(checker.HasSuffix), "\n\n", check.Commentf("Should not have a blank line at the end of 'docker rm'\n"))
|
||||
|
||||
// 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{
|
||||
"images": "",
|
||||
"login": "",
|
||||
"logout": "",
|
||||
"network": "",
|
||||
"stats": "",
|
||||
}
|
||||
|
||||
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.
|
||||
skipNoArgs := map[string]struct{}{
|
||||
"daemon": {},
|
||||
"events": {},
|
||||
"load": {},
|
||||
}
|
||||
|
||||
ec := 0
|
||||
if _, ok := skipNoArgs[cmd]; !ok {
|
||||
args = strings.Split(cmd, " ")
|
||||
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 {
|
||||
args = strings.Split(cmd+" badArg", " ")
|
||||
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
|
||||
c.Assert(stderr, checker.Contains, "\nUsage:\t", check.Commentf("Missing short usage on %q\n", args))
|
||||
// But shouldn't have full usage
|
||||
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))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Number of commands for standard release and experimental release
|
||||
|
@ -296,3 +207,136 @@ func (s *DockerSuite) TestHelpExitCodesHelpOutput(c *check.C) {
|
|||
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"))
|
||||
}
|
||||
|
||||
func testCommand(cmd string, newEnvs []string, scanForHome bool, home string) error {
|
||||
|
||||
args := strings.Split(cmd+" --help", " ")
|
||||
|
||||
// Check the full usage text
|
||||
helpCmd := exec.Command(dockerBinary, args...)
|
||||
helpCmd.Env = newEnvs
|
||||
out, stderr, _, err := runCommandWithStdoutStderr(helpCmd)
|
||||
if len(stderr) != 0 {
|
||||
return fmt.Errorf("Error on %q help. non-empty stderr:%q\n", cmd, stderr)
|
||||
}
|
||||
if strings.HasSuffix(out, "\n\n") {
|
||||
return fmt.Errorf("Should not have blank line on %q\n", cmd)
|
||||
}
|
||||
if !strings.Contains(out, "--help") {
|
||||
return fmt.Errorf("All commands should mention '--help'. Command '%v' did not.\n", cmd)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return fmt.Errorf(out)
|
||||
}
|
||||
|
||||
// Check each line for lots of stuff
|
||||
lines := strings.Split(out, "\n")
|
||||
for _, line := range lines {
|
||||
if len(line) > 107 {
|
||||
return fmt.Errorf("Help for %q is too long:\n%s\n", cmd, line)
|
||||
}
|
||||
|
||||
if scanForHome && strings.Contains(line, `"`+home) {
|
||||
return fmt.Errorf("Help for %q should use ~ instead of %q on:\n%s\n",
|
||||
cmd, home, line)
|
||||
}
|
||||
i := strings.Index(line, "~")
|
||||
if i >= 0 && i != len(line)-1 && line[i+1] != '/' {
|
||||
return fmt.Errorf("Help for %q should not have used ~:\n%s", cmd, line)
|
||||
}
|
||||
|
||||
// If a line starts with 4 spaces then assume someone
|
||||
// added a multi-line description for an option and we need
|
||||
// to flag it
|
||||
if strings.HasPrefix(line, " ") {
|
||||
return fmt.Errorf("Help for %q should not have a multi-line option", cmd)
|
||||
}
|
||||
|
||||
// Options should NOT end with a period
|
||||
if strings.HasPrefix(line, " -") && strings.HasSuffix(line, ".") {
|
||||
return fmt.Errorf("Help for %q should not end with a period: %s", cmd, line)
|
||||
}
|
||||
|
||||
// Options should NOT end with a space
|
||||
if strings.HasSuffix(line, " ") {
|
||||
return fmt.Errorf("Help for %q should not end with a space", cmd)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// For each command make sure we generate an error
|
||||
// if we give a bad arg
|
||||
args = strings.Split(cmd+" --badArg", " ")
|
||||
|
||||
out, _, err = dockerCmdWithError(args...)
|
||||
if err == nil {
|
||||
return fmt.Errorf(out)
|
||||
}
|
||||
|
||||
// Be really picky
|
||||
if strings.HasSuffix(stderr, "\n\n") {
|
||||
return fmt.Errorf("Should not have a blank line at the end of 'docker rm'\n")
|
||||
}
|
||||
|
||||
// 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{
|
||||
"images": "",
|
||||
"login": "",
|
||||
"logout": "",
|
||||
"network": "",
|
||||
"stats": "",
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
// 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.
|
||||
skipNoArgs := map[string]struct{}{
|
||||
"daemon": {},
|
||||
"events": {},
|
||||
"load": {},
|
||||
}
|
||||
|
||||
ec := 0
|
||||
if _, ok := skipNoArgs[cmd]; !ok {
|
||||
args = strings.Split(cmd, " ")
|
||||
dCmd = exec.Command(dockerBinary, args...)
|
||||
out, stderr, ec, err = runCommandWithStdoutStderr(dCmd)
|
||||
}
|
||||
|
||||
// If its ok w/o any args then try again with an arg
|
||||
if ec == 0 {
|
||||
args = strings.Split(cmd+" badArg", " ")
|
||||
dCmd = exec.Command(dockerBinary, args...)
|
||||
out, stderr, ec, err = runCommandWithStdoutStderr(dCmd)
|
||||
}
|
||||
|
||||
if len(out) != 0 || len(stderr) == 0 || ec == 0 || err == nil {
|
||||
return fmt.Errorf("Bad output from %q\nstdout:%q\nstderr:%q\nec:%d\nerr:%q\n", args, out, stderr, ec, err)
|
||||
}
|
||||
// Should have just short usage
|
||||
if !strings.Contains(stderr, "\nUsage:\t") {
|
||||
return fmt.Errorf("Missing short usage on %q\n", args)
|
||||
}
|
||||
// But shouldn't have full usage
|
||||
if strings.Contains(stderr, "--help=false") {
|
||||
return fmt.Errorf("Should not have full usage on %q\n", args)
|
||||
}
|
||||
if strings.HasSuffix(stderr, "\n\n") {
|
||||
return fmt.Errorf("Should not have a blank line on %q\n", args)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue