Browse code

Optimize slow bottleneck test of DockerHubPullSuite.TestPullNonExistingImage.

This PR fix the DockerHubPullSuite.TestPullNonExistingImage test
in #19425. The majority of the execution time in this test is
from multiple executions of 'docker pull', each of which takes
more than one second even though it tries to pull a non-existing
image.
Without changing the behavior of the 'docker pull' itself, this
fix tries to execute the 'docker pull' command in parallel in
order to speed up the execution of the overall test.
Since each 'docker pull' is independent, executions in parallel
should not alter the purpose of the test.

Signed-off-by: Yong Tang <yong.tang.github@outlook.com>

Yong Tang authored on 2016/03/03 23:18:10
Showing 1 changed files
... ...
@@ -4,6 +4,7 @@ import (
4 4
 	"fmt"
5 5
 	"regexp"
6 6
 	"strings"
7
+	"sync"
7 8
 	"time"
8 9
 
9 10
 	"github.com/docker/distribution/digest"
... ...
@@ -39,30 +40,68 @@ func (s *DockerHubPullSuite) TestPullFromCentralRegistry(c *check.C) {
39 39
 // combinations of implicit tag and library prefix.
40 40
 func (s *DockerHubPullSuite) TestPullNonExistingImage(c *check.C) {
41 41
 	testRequires(c, DaemonIsLinux)
42
-	for _, e := range []struct {
42
+
43
+	type entry struct {
43 44
 		Repo  string
44 45
 		Alias string
45
-	}{
46
+	}
47
+
48
+	entries := []entry{
46 49
 		{"library/asdfasdf", "asdfasdf:foobar"},
47 50
 		{"library/asdfasdf", "library/asdfasdf:foobar"},
48 51
 		{"library/asdfasdf", "asdfasdf"},
49 52
 		{"library/asdfasdf", "asdfasdf:latest"},
50 53
 		{"library/asdfasdf", "library/asdfasdf"},
51 54
 		{"library/asdfasdf", "library/asdfasdf:latest"},
52
-	} {
53
-		out, err := s.CmdWithError("pull", e.Alias)
54
-		c.Assert(err, checker.NotNil, check.Commentf("expected non-zero exit status when pulling non-existing image: %s", out))
55
-		// Hub returns 401 rather than 404 for nonexistent repos over
56
-		// the v2 protocol - but we should end up falling back to v1,
57
-		// which does return a 404.
58
-		c.Assert(out, checker.Contains, fmt.Sprintf("Error: image %s not found", e.Repo), check.Commentf("expected image not found error messages"))
59
-
60
-		// pull -a on a nonexistent registry should fall back as well
55
+	}
56
+
57
+	// The option field indicates "-a" or not.
58
+	type record struct {
59
+		e      entry
60
+		option string
61
+		out    string
62
+		err    error
63
+	}
64
+
65
+	// Execute 'docker pull' in parallel, pass results (out, err) and
66
+	// necessary information ("-a" or not, and the image name) to channel.
67
+	var group sync.WaitGroup
68
+	recordChan := make(chan record, len(entries)*2)
69
+	for _, e := range entries {
70
+		group.Add(1)
71
+		go func(e entry) {
72
+			defer group.Done()
73
+			out, err := s.CmdWithError("pull", e.Alias)
74
+			recordChan <- record{e, "", out, err}
75
+		}(e)
61 76
 		if !strings.ContainsRune(e.Alias, ':') {
62
-			out, err := s.CmdWithError("pull", "-a", e.Alias)
63
-			c.Assert(err, checker.NotNil, check.Commentf("expected non-zero exit status when pulling non-existing image: %s", out))
64
-			c.Assert(out, checker.Contains, fmt.Sprintf("Error: image %s not found", e.Repo), check.Commentf("expected image not found error messages"))
65
-			c.Assert(out, checker.Not(checker.Contains), "unauthorized", check.Commentf(`message should not contain "unauthorized"`))
77
+			// pull -a on a nonexistent registry should fall back as well
78
+			group.Add(1)
79
+			go func(e entry) {
80
+				defer group.Done()
81
+				out, err := s.CmdWithError("pull", "-a", e.Alias)
82
+				recordChan <- record{e, "-a", out, err}
83
+			}(e)
84
+		}
85
+	}
86
+
87
+	// Wait for completion
88
+	group.Wait()
89
+	close(recordChan)
90
+
91
+	// Process the results (out, err).
92
+	for record := range recordChan {
93
+		if len(record.option) == 0 {
94
+			c.Assert(record.err, checker.NotNil, check.Commentf("expected non-zero exit status when pulling non-existing image: %s", record.out))
95
+			// Hub returns 401 rather than 404 for nonexistent repos over
96
+			// the v2 protocol - but we should end up falling back to v1,
97
+			// which does return a 404.
98
+			c.Assert(record.out, checker.Contains, fmt.Sprintf("Error: image %s not found", record.e.Repo), check.Commentf("expected image not found error messages"))
99
+		} else {
100
+			// pull -a on a nonexistent registry should fall back as well
101
+			c.Assert(record.err, checker.NotNil, check.Commentf("expected non-zero exit status when pulling non-existing image: %s", record.out))
102
+			c.Assert(record.out, checker.Contains, fmt.Sprintf("Error: image %s not found", record.e.Repo), check.Commentf("expected image not found error messages"))
103
+			c.Assert(record.out, checker.Not(checker.Contains), "unauthorized", check.Commentf(`message should not contain "unauthorized"`))
66 104
 		}
67 105
 	}
68 106