Browse code

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>

Sainath Grandhi authored on 2016/03/22 05:06:34
Showing 1 changed files
... ...
@@ -1,6 +1,7 @@
1 1
 package main
2 2
 
3 3
 import (
4
+	"fmt"
4 5
 	"os/exec"
5 6
 	"runtime"
6 7
 	"strings"
... ...
@@ -13,6 +14,7 @@ import (
13 13
 
14 14
 func (s *DockerSuite) TestHelpTextVerify(c *check.C) {
15 15
 	testRequires(c, DaemonIsLinux)
16
+
16 17
 	// Make sure main help text fits within 80 chars and that
17 18
 	// on non-windows system we use ~ when possible (to shorten things).
18 19
 	// Test for HOME set to its default value and set to "/" on linux
... ...
@@ -40,6 +42,7 @@ func (s *DockerSuite) TestHelpTextVerify(c *check.C) {
40 40
 	}
41 41
 
42 42
 	for _, home := range homes {
43
+
43 44
 		// Dup baseEnvs and add our new HOME value
44 45
 		newEnvs := make([]string, len(baseEnvs)+1)
45 46
 		copy(newEnvs, baseEnvs)
... ...
@@ -117,114 +120,22 @@ func (s *DockerSuite) TestHelpTextVerify(c *check.C) {
117 117
 		cmdsToTest = append(cmdsToTest, "volume ls")
118 118
 		cmdsToTest = append(cmdsToTest, "volume rm")
119 119
 
120
-		for _, cmd := range cmdsToTest {
121
-			var stderr string
122
-
123
-			args := strings.Split(cmd+" --help", " ")
124
-
125
-			// Check the full usage text
126
-			helpCmd := exec.Command(dockerBinary, args...)
127
-			helpCmd.Env = newEnvs
128
-			out, stderr, _, err = runCommandWithStdoutStderr(helpCmd)
129
-			c.Assert(len(stderr), checker.Equals, 0, check.Commentf("Error on %q help. non-empty stderr:%q", cmd, stderr))
130
-			c.Assert(out, checker.Not(checker.HasSuffix), "\n\n", check.Commentf("Should not have blank line on %q\n", cmd))
131
-			c.Assert(out, checker.Contains, "--help", check.Commentf("All commands should mention '--help'. Command '%v' did not.\n", cmd))
132
-
133
-			c.Assert(err, checker.IsNil, check.Commentf(out))
134
-
135
-			// Check each line for lots of stuff
136
-			lines := strings.Split(out, "\n")
137
-			for _, line := range lines {
138
-				c.Assert(len(line), checker.LessOrEqualThan, 107, check.Commentf("Help for %q is too long:\n%s", cmd, line))
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
-				c.Assert(line, checker.Not(checker.HasPrefix), "    ", check.Commentf("Help for %q should not have a multi-line option", cmd))
153
-
154
-				// Options should NOT end with a period
155
-				if strings.HasPrefix(line, "  -") && strings.HasSuffix(line, ".") {
156
-					c.Fatalf("Help for %q should not end with a period: %s", cmd, line)
157
-				}
158
-
159
-				// Options should NOT end with a space
160
-				c.Assert(line, checker.Not(checker.HasSuffix), " ", check.Commentf("Help for %q should not end with a space", cmd))
161
-
162
-			}
163
-
164
-			// For each command make sure we generate an error
165
-			// if we give a bad arg
166
-			args = strings.Split(cmd+" --badArg", " ")
167
-
168
-			out, _, err = dockerCmdWithError(args...)
169
-			c.Assert(err, checker.NotNil, check.Commentf(out))
170
-			// Be really picky
171
-			c.Assert(stderr, checker.Not(checker.HasSuffix), "\n\n", check.Commentf("Should not have a blank line at the end of 'docker rm'\n"))
172
-
173
-			// Now make sure that each command will print a short-usage
174
-			// (not a full usage - meaning no opts section) if we
175
-			// are missing a required arg or pass in a bad arg
176
-
177
-			// These commands will never print a short-usage so don't test
178
-			noShortUsage := map[string]string{
179
-				"images":  "",
180
-				"login":   "",
181
-				"logout":  "",
182
-				"network": "",
183
-				"stats":   "",
184
-			}
120
+		// Divide the list of commands into go routines and  run the func testcommand on the commands in parallel
121
+		// to save runtime of test
185 122
 
186
-			if _, ok := noShortUsage[cmd]; !ok {
187
-				// For each command run it w/o any args. It will either return
188
-				// valid output or print a short-usage
189
-				var dCmd *exec.Cmd
190
-				var stdout, stderr string
191
-				var args []string
192
-
193
-				// skipNoArgs are ones that we don't want to try w/o
194
-				// any args. Either because it'll hang the test or
195
-				// lead to incorrect test result (like false negative).
196
-				// Whatever the reason, skip trying to run w/o args and
197
-				// jump to trying with a bogus arg.
198
-				skipNoArgs := map[string]struct{}{
199
-					"daemon": {},
200
-					"events": {},
201
-					"load":   {},
202
-				}
123
+		errChan := make(chan error)
203 124
 
204
-				ec := 0
205
-				if _, ok := skipNoArgs[cmd]; !ok {
206
-					args = strings.Split(cmd, " ")
207
-					dCmd = exec.Command(dockerBinary, args...)
208
-					stdout, stderr, ec, err = runCommandWithStdoutStderr(dCmd)
209
-				}
210
-
211
-				// If its ok w/o any args then try again with an arg
212
-				if ec == 0 {
213
-					args = strings.Split(cmd+" badArg", " ")
214
-					dCmd = exec.Command(dockerBinary, args...)
215
-					stdout, stderr, ec, err = runCommandWithStdoutStderr(dCmd)
216
-				}
125
+		for index := 0; index < len(cmdsToTest); index++ {
126
+			go func(index int) {
127
+				errChan <- testCommand(cmdsToTest[index], newEnvs, scanForHome, home)
128
+			}(index)
129
+		}
217 130
 
218
-				if len(stdout) != 0 || len(stderr) == 0 || ec == 0 || err == nil {
219
-					c.Fatalf("Bad output from %q\nstdout:%q\nstderr:%q\nec:%d\nerr:%q", args, stdout, stderr, ec, err)
220
-				}
221
-				// Should have just short usage
222
-				c.Assert(stderr, checker.Contains, "\nUsage:\t", check.Commentf("Missing short usage on %q\n", args))
223
-				// But shouldn't have full usage
224
-				c.Assert(stderr, checker.Not(checker.Contains), "--help=false", check.Commentf("Should not have full usage on %q\n", args))
225
-				c.Assert(stderr, checker.Not(checker.HasSuffix), "\n\n", check.Commentf("Should not have a blank line on %q\n", args))
131
+		for index := 0; index < len(cmdsToTest); index++ {
132
+			err := <-errChan
133
+			if err != nil {
134
+				c.Fatal(err)
226 135
 			}
227
-
228 136
 		}
229 137
 
230 138
 		// Number of commands for standard release and experimental release
... ...
@@ -296,3 +207,136 @@ func (s *DockerSuite) TestHelpExitCodesHelpOutput(c *check.C) {
296 296
 	c.Assert(stdout, checker.Equals, "")
297 297
 	c.Assert(stderr, checker.Equals, "docker: 'BadCmd' is not a docker command.\nSee 'docker --help'.\n", check.Commentf("Unexcepted output for 'docker badCmd'\n"))
298 298
 }
299
+
300
+func testCommand(cmd string, newEnvs []string, scanForHome bool, home string) error {
301
+
302
+	args := strings.Split(cmd+" --help", " ")
303
+
304
+	// Check the full usage text
305
+	helpCmd := exec.Command(dockerBinary, args...)
306
+	helpCmd.Env = newEnvs
307
+	out, stderr, _, err := runCommandWithStdoutStderr(helpCmd)
308
+	if len(stderr) != 0 {
309
+		return fmt.Errorf("Error on %q help. non-empty stderr:%q\n", cmd, stderr)
310
+	}
311
+	if strings.HasSuffix(out, "\n\n") {
312
+		return fmt.Errorf("Should not have blank line on %q\n", cmd)
313
+	}
314
+	if !strings.Contains(out, "--help") {
315
+		return fmt.Errorf("All commands should mention '--help'. Command '%v' did not.\n", cmd)
316
+	}
317
+
318
+	if err != nil {
319
+		return fmt.Errorf(out)
320
+	}
321
+
322
+	// Check each line for lots of stuff
323
+	lines := strings.Split(out, "\n")
324
+	for _, line := range lines {
325
+		if len(line) > 107 {
326
+			return fmt.Errorf("Help for %q is too long:\n%s\n", cmd, line)
327
+		}
328
+
329
+		if scanForHome && strings.Contains(line, `"`+home) {
330
+			return fmt.Errorf("Help for %q should use ~ instead of %q on:\n%s\n",
331
+				cmd, home, line)
332
+		}
333
+		i := strings.Index(line, "~")
334
+		if i >= 0 && i != len(line)-1 && line[i+1] != '/' {
335
+			return fmt.Errorf("Help for %q should not have used ~:\n%s", cmd, line)
336
+		}
337
+
338
+		// If a line starts with 4 spaces then assume someone
339
+		// added a multi-line description for an option and we need
340
+		// to flag it
341
+		if strings.HasPrefix(line, "    ") {
342
+			return fmt.Errorf("Help for %q should not have a multi-line option", cmd)
343
+		}
344
+
345
+		// Options should NOT end with a period
346
+		if strings.HasPrefix(line, "  -") && strings.HasSuffix(line, ".") {
347
+			return fmt.Errorf("Help for %q should not end with a period: %s", cmd, line)
348
+		}
349
+
350
+		// Options should NOT end with a space
351
+		if strings.HasSuffix(line, " ") {
352
+			return fmt.Errorf("Help for %q should not end with a space", cmd)
353
+		}
354
+
355
+	}
356
+
357
+	// For each command make sure we generate an error
358
+	// if we give a bad arg
359
+	args = strings.Split(cmd+" --badArg", " ")
360
+
361
+	out, _, err = dockerCmdWithError(args...)
362
+	if err == nil {
363
+		return fmt.Errorf(out)
364
+	}
365
+
366
+	// Be really picky
367
+	if strings.HasSuffix(stderr, "\n\n") {
368
+		return fmt.Errorf("Should not have a blank line at the end of 'docker rm'\n")
369
+	}
370
+
371
+	// Now make sure that each command will print a short-usage
372
+	// (not a full usage - meaning no opts section) if we
373
+	// are missing a required arg or pass in a bad arg
374
+
375
+	// These commands will never print a short-usage so don't test
376
+	noShortUsage := map[string]string{
377
+		"images":  "",
378
+		"login":   "",
379
+		"logout":  "",
380
+		"network": "",
381
+		"stats":   "",
382
+	}
383
+
384
+	if _, ok := noShortUsage[cmd]; !ok {
385
+		// For each command run it w/o any args. It will either return
386
+		// valid output or print a short-usage
387
+		var dCmd *exec.Cmd
388
+
389
+		// skipNoArgs are ones that we don't want to try w/o
390
+		// any args. Either because it'll hang the test or
391
+		// lead to incorrect test result (like false negative).
392
+		// Whatever the reason, skip trying to run w/o args and
393
+		// jump to trying with a bogus arg.
394
+		skipNoArgs := map[string]struct{}{
395
+			"daemon": {},
396
+			"events": {},
397
+			"load":   {},
398
+		}
399
+
400
+		ec := 0
401
+		if _, ok := skipNoArgs[cmd]; !ok {
402
+			args = strings.Split(cmd, " ")
403
+			dCmd = exec.Command(dockerBinary, args...)
404
+			out, stderr, ec, err = runCommandWithStdoutStderr(dCmd)
405
+		}
406
+
407
+		// If its ok w/o any args then try again with an arg
408
+		if ec == 0 {
409
+			args = strings.Split(cmd+" badArg", " ")
410
+			dCmd = exec.Command(dockerBinary, args...)
411
+			out, stderr, ec, err = runCommandWithStdoutStderr(dCmd)
412
+		}
413
+
414
+		if len(out) != 0 || len(stderr) == 0 || ec == 0 || err == nil {
415
+			return fmt.Errorf("Bad output from %q\nstdout:%q\nstderr:%q\nec:%d\nerr:%q\n", args, out, stderr, ec, err)
416
+		}
417
+		// Should have just short usage
418
+		if !strings.Contains(stderr, "\nUsage:\t") {
419
+			return fmt.Errorf("Missing short usage on %q\n", args)
420
+		}
421
+		// But shouldn't have full usage
422
+		if strings.Contains(stderr, "--help=false") {
423
+			return fmt.Errorf("Should not have full usage on %q\n", args)
424
+		}
425
+		if strings.HasSuffix(stderr, "\n\n") {
426
+			return fmt.Errorf("Should not have a blank line on %q\n", args)
427
+		}
428
+	}
429
+
430
+	return nil
431
+}