Browse code

Move TearDownTest cleaning to environment package

Signed-off-by: Vincent Demeester <vincent@sbr.pm>

Vincent Demeester authored on 2017/03/02 02:45:04
Showing 7 changed files
... ...
@@ -34,9 +34,6 @@ const (
34 34
 var (
35 35
 	testEnv *environment.Execution
36 36
 
37
-	// FIXME(vdemeester) remove these and use environmentdaemonPid
38
-	protectedImages = map[string]struct{}{}
39
-
40 37
 	// the docker client binary to use
41 38
 	dockerBinary = "docker"
42 39
 )
... ...
@@ -64,16 +61,6 @@ func TestMain(m *testing.M) {
64 64
 		os.Exit(1)
65 65
 	}
66 66
 
67
-	cmd := exec.Command(dockerBinary, "images", "-f", "dangling=false", "--format", "{{.Repository}}:{{.Tag}}")
68
-	cmd.Env = appendBaseEnv(true)
69
-	out, err := cmd.CombinedOutput()
70
-	if err != nil {
71
-		panic(fmt.Errorf("err=%v\nout=%s\n", err, out))
72
-	}
73
-	images := strings.Split(strings.TrimSpace(string(out)), "\n")
74
-	for _, img := range images {
75
-		protectedImages[img] = struct{}{}
76
-	}
77 67
 	if testEnv.LocalDaemon() {
78 68
 		fmt.Println("INFO: Testing against a local daemon")
79 69
 	} else {
... ...
@@ -84,6 +71,14 @@ func TestMain(m *testing.M) {
84 84
 }
85 85
 
86 86
 func Test(t *testing.T) {
87
+	cmd := exec.Command(dockerBinary, "images", "-f", "dangling=false", "--format", "{{.Repository}}:{{.Tag}}")
88
+	cmd.Env = appendBaseEnv(true)
89
+	out, err := cmd.CombinedOutput()
90
+	if err != nil {
91
+		panic(fmt.Errorf("err=%v\nout=%s\n", err, out))
92
+	}
93
+	images := strings.Split(strings.TrimSpace(string(out)), "\n")
94
+	testEnv.ProtectImage(t, images...)
87 95
 	if testEnv.DaemonPlatform() == "linux" {
88 96
 		ensureFrozenImagesLinux(t)
89 97
 	}
... ...
@@ -104,14 +99,7 @@ func (s *DockerSuite) OnTimeout(c *check.C) {
104 104
 }
105 105
 
106 106
 func (s *DockerSuite) TearDownTest(c *check.C) {
107
-	unpauseAllContainers(c)
108
-	deleteAllContainers(c)
109
-	deleteAllImages(c)
110
-	deleteAllVolumes(c)
111
-	deleteAllNetworks(c)
112
-	if testEnv.DaemonPlatform() == "linux" {
113
-		deleteAllPlugins(c)
114
-	}
107
+	testEnv.Clean(c, dockerBinary)
115 108
 }
116 109
 
117 110
 func init() {
... ...
@@ -20,23 +20,19 @@ import (
20 20
 	"time"
21 21
 
22 22
 	"github.com/docker/docker/api/types"
23
-	volumetypes "github.com/docker/docker/api/types/volume"
24 23
 	"github.com/docker/docker/integration-cli/checker"
25 24
 	"github.com/docker/docker/integration-cli/daemon"
25
+	"github.com/docker/docker/integration-cli/environment"
26 26
 	"github.com/docker/docker/integration-cli/registry"
27 27
 	"github.com/docker/docker/integration-cli/request"
28
-	"github.com/docker/docker/opts"
29 28
 	"github.com/docker/docker/pkg/stringutils"
30 29
 	icmd "github.com/docker/docker/pkg/testutil/cmd"
31 30
 	"github.com/go-check/check"
32 31
 )
33 32
 
33
+// Deprecated
34 34
 func daemonHost() string {
35
-	daemonURLStr := "unix://" + opts.DefaultUnixSocket
36
-	if daemonHostVar := os.Getenv("DOCKER_HOST"); daemonHostVar != "" {
37
-		daemonURLStr = daemonHostVar
38
-	}
39
-	return daemonURLStr
35
+	return environment.DaemonHost()
40 36
 }
41 37
 
42 38
 // FIXME(vdemeester) move this away are remove ignoreNoSuchContainer bool
... ...
@@ -58,6 +54,7 @@ func getAllContainers(c *check.C) string {
58 58
 	return result.Combined()
59 59
 }
60 60
 
61
+// Deprecated
61 62
 func deleteAllContainers(c *check.C) {
62 63
 	containers := getAllContainers(c)
63 64
 	if containers != "" {
... ...
@@ -66,136 +63,6 @@ func deleteAllContainers(c *check.C) {
66 66
 	}
67 67
 }
68 68
 
69
-func deleteAllNetworks(c *check.C) {
70
-	networks, err := getAllNetworks()
71
-	c.Assert(err, check.IsNil)
72
-	var errs []string
73
-	for _, n := range networks {
74
-		if n.Name == "bridge" || n.Name == "none" || n.Name == "host" {
75
-			continue
76
-		}
77
-		if testEnv.DaemonPlatform() == "windows" && strings.ToLower(n.Name) == "nat" {
78
-			// nat is a pre-defined network on Windows and cannot be removed
79
-			continue
80
-		}
81
-		status, b, err := request.SockRequest("DELETE", "/networks/"+n.Name, nil, daemonHost())
82
-		if err != nil {
83
-			errs = append(errs, err.Error())
84
-			continue
85
-		}
86
-		if status != http.StatusNoContent {
87
-			errs = append(errs, fmt.Sprintf("error deleting network %s: %s", n.Name, string(b)))
88
-		}
89
-	}
90
-	c.Assert(errs, checker.HasLen, 0, check.Commentf(strings.Join(errs, "\n")))
91
-}
92
-
93
-func getAllNetworks() ([]types.NetworkResource, error) {
94
-	var networks []types.NetworkResource
95
-	_, b, err := request.SockRequest("GET", "/networks", nil, daemonHost())
96
-	if err != nil {
97
-		return nil, err
98
-	}
99
-	if err := json.Unmarshal(b, &networks); err != nil {
100
-		return nil, err
101
-	}
102
-	return networks, nil
103
-}
104
-
105
-func deleteAllPlugins(c *check.C) {
106
-	plugins, err := getAllPlugins()
107
-	c.Assert(err, checker.IsNil)
108
-	var errs []string
109
-	for _, p := range plugins {
110
-		pluginName := p.Name
111
-		status, b, err := request.SockRequest("DELETE", "/plugins/"+pluginName+"?force=1", nil, daemonHost())
112
-		if err != nil {
113
-			errs = append(errs, err.Error())
114
-			continue
115
-		}
116
-		if status != http.StatusOK {
117
-			errs = append(errs, fmt.Sprintf("error deleting plugin %s: %s", p.Name, string(b)))
118
-		}
119
-	}
120
-	c.Assert(errs, checker.HasLen, 0, check.Commentf(strings.Join(errs, "\n")))
121
-}
122
-
123
-func getAllPlugins() (types.PluginsListResponse, error) {
124
-	var plugins types.PluginsListResponse
125
-	_, b, err := request.SockRequest("GET", "/plugins", nil, daemonHost())
126
-	if err != nil {
127
-		return nil, err
128
-	}
129
-	if err := json.Unmarshal(b, &plugins); err != nil {
130
-		return nil, err
131
-	}
132
-	return plugins, nil
133
-}
134
-
135
-func deleteAllVolumes(c *check.C) {
136
-	volumes, err := getAllVolumes()
137
-	c.Assert(err, checker.IsNil)
138
-	var errs []string
139
-	for _, v := range volumes {
140
-		status, b, err := request.SockRequest("DELETE", "/volumes/"+v.Name, nil, daemonHost())
141
-		if err != nil {
142
-			errs = append(errs, err.Error())
143
-			continue
144
-		}
145
-		if status != http.StatusNoContent {
146
-			errs = append(errs, fmt.Sprintf("error deleting volume %s: %s", v.Name, string(b)))
147
-		}
148
-	}
149
-	c.Assert(errs, checker.HasLen, 0, check.Commentf(strings.Join(errs, "\n")))
150
-}
151
-
152
-func getAllVolumes() ([]*types.Volume, error) {
153
-	var volumes volumetypes.VolumesListOKBody
154
-	_, b, err := request.SockRequest("GET", "/volumes", nil, daemonHost())
155
-	if err != nil {
156
-		return nil, err
157
-	}
158
-	if err := json.Unmarshal(b, &volumes); err != nil {
159
-		return nil, err
160
-	}
161
-	return volumes.Volumes, nil
162
-}
163
-
164
-func deleteAllImages(c *check.C) {
165
-	cmd := exec.Command(dockerBinary, "images", "--digests")
166
-	cmd.Env = appendBaseEnv(true)
167
-	out, err := cmd.CombinedOutput()
168
-	c.Assert(err, checker.IsNil)
169
-	lines := strings.Split(string(out), "\n")[1:]
170
-	imgMap := map[string]struct{}{}
171
-	for _, l := range lines {
172
-		if l == "" {
173
-			continue
174
-		}
175
-		fields := strings.Fields(l)
176
-		imgTag := fields[0] + ":" + fields[1]
177
-		if _, ok := protectedImages[imgTag]; !ok {
178
-			if fields[0] == "<none>" || fields[1] == "<none>" {
179
-				if fields[2] != "<none>" {
180
-					imgMap[fields[0]+"@"+fields[2]] = struct{}{}
181
-				} else {
182
-					imgMap[fields[3]] = struct{}{}
183
-				}
184
-				// continue
185
-			} else {
186
-				imgMap[imgTag] = struct{}{}
187
-			}
188
-		}
189
-	}
190
-	if len(imgMap) != 0 {
191
-		imgs := make([]string, 0, len(imgMap))
192
-		for k := range imgMap {
193
-			imgs = append(imgs, k)
194
-		}
195
-		dockerCmd(c, append([]string{"rmi", "-f"}, imgs...)...)
196
-	}
197
-}
198
-
199 69
 func getPausedContainers(c *check.C) []string {
200 70
 	result := icmd.RunCommand(dockerBinary, "ps", "-f", "status=paused", "-q", "-a")
201 71
 	result.Assert(c, icmd.Success)
... ...
@@ -206,6 +73,7 @@ func unpauseContainer(c *check.C, container string) {
206 206
 	dockerCmd(c, "unpause", container)
207 207
 }
208 208
 
209
+// Deprecated
209 210
 func unpauseAllContainers(c *check.C) {
210 211
 	containers := getPausedContainers(c)
211 212
 	for _, value := range containers {
... ...
@@ -487,7 +355,7 @@ func newRemoteFileServer(c *check.C, ctx *FakeContext) *remoteFileServer {
487 487
 		container = fmt.Sprintf("fileserver-cnt-%s", strings.ToLower(stringutils.GenerateRandomAlphaOnlyString(10)))
488 488
 	)
489 489
 
490
-	c.Assert(ensureHTTPServerImage(), checker.IsNil)
490
+	ensureHTTPServerImage(c)
491 491
 
492 492
 	// Build the image
493 493
 	fakeContextAddDockerfile(c, ctx, `FROM httpserver
494 494
new file mode 100644
... ...
@@ -0,0 +1,213 @@
0
+package environment
1
+
2
+import (
3
+	"encoding/json"
4
+	"fmt"
5
+	"net/http"
6
+	"os"
7
+	"strings"
8
+
9
+	"github.com/docker/docker/api/types"
10
+	volumetypes "github.com/docker/docker/api/types/volume"
11
+	"github.com/docker/docker/integration-cli/request"
12
+	"github.com/docker/docker/opts"
13
+	icmd "github.com/docker/docker/pkg/testutil/cmd"
14
+)
15
+
16
+type testingT interface {
17
+	logT
18
+	Fatalf(string, ...interface{})
19
+}
20
+
21
+type logT interface {
22
+	Logf(string, ...interface{})
23
+}
24
+
25
+// Clean the environment, preserving protected objects (images, containers, ...)
26
+// and removing everything else. It's meant to run after any tests so that they don't
27
+// depend on each others.
28
+func (e *Execution) Clean(t testingT, dockerBinary string) {
29
+	unpauseAllContainers(t, dockerBinary)
30
+	deleteAllContainers(t, dockerBinary)
31
+	deleteAllImages(t, dockerBinary, e.protectedElements.images)
32
+	deleteAllVolumes(t, dockerBinary)
33
+	deleteAllNetworks(t, dockerBinary, e.DaemonPlatform())
34
+	if e.DaemonPlatform() == "linux" {
35
+		deleteAllPlugins(t, dockerBinary)
36
+	}
37
+}
38
+
39
+func unpauseAllContainers(t testingT, dockerBinary string) {
40
+	containers := getPausedContainers(t, dockerBinary)
41
+	if len(containers) > 0 {
42
+		icmd.RunCommand(dockerBinary, append([]string{"unpause"}, containers...)...).Assert(t, icmd.Success)
43
+	}
44
+}
45
+
46
+func getPausedContainers(t testingT, dockerBinary string) []string {
47
+	result := icmd.RunCommand(dockerBinary, "ps", "-f", "status=paused", "-q", "-a")
48
+	result.Assert(t, icmd.Success)
49
+	return strings.Fields(result.Combined())
50
+}
51
+
52
+func deleteAllContainers(t testingT, dockerBinary string) {
53
+	containers := getAllContainers(t, dockerBinary)
54
+	if len(containers) > 0 {
55
+		icmd.RunCommand(dockerBinary, append([]string{"rm", "-fv"}, containers...)...).Assert(t, icmd.Success)
56
+	}
57
+}
58
+
59
+func getAllContainers(t testingT, dockerBinary string) []string {
60
+	result := icmd.RunCommand(dockerBinary, "ps", "-q", "-a")
61
+	result.Assert(t, icmd.Success)
62
+	return strings.Fields(result.Combined())
63
+}
64
+
65
+func deleteAllImages(t testingT, dockerBinary string, protectedImages map[string]struct{}) {
66
+	result := icmd.RunCommand(dockerBinary, "images", "--digests")
67
+	result.Assert(t, icmd.Success)
68
+	lines := strings.Split(string(result.Combined()), "\n")[1:]
69
+	imgMap := map[string]struct{}{}
70
+	for _, l := range lines {
71
+		if l == "" {
72
+			continue
73
+		}
74
+		fields := strings.Fields(l)
75
+		imgTag := fields[0] + ":" + fields[1]
76
+		if _, ok := protectedImages[imgTag]; !ok {
77
+			if fields[0] == "<none>" || fields[1] == "<none>" {
78
+				if fields[2] != "<none>" {
79
+					imgMap[fields[0]+"@"+fields[2]] = struct{}{}
80
+				} else {
81
+					imgMap[fields[3]] = struct{}{}
82
+				}
83
+				// continue
84
+			} else {
85
+				imgMap[imgTag] = struct{}{}
86
+			}
87
+		}
88
+	}
89
+	if len(imgMap) != 0 {
90
+		imgs := make([]string, 0, len(imgMap))
91
+		for k := range imgMap {
92
+			imgs = append(imgs, k)
93
+		}
94
+		icmd.RunCommand(dockerBinary, append([]string{"rmi", "-f"}, imgs...)...).Assert(t, icmd.Success)
95
+	}
96
+}
97
+
98
+func deleteAllVolumes(t testingT, dockerBinary string) {
99
+	volumes, err := getAllVolumes()
100
+	if err != nil {
101
+		t.Fatalf("%v", err)
102
+	}
103
+	var errs []string
104
+	for _, v := range volumes {
105
+		status, b, err := request.SockRequest("DELETE", "/volumes/"+v.Name, nil, DaemonHost())
106
+		if err != nil {
107
+			errs = append(errs, err.Error())
108
+			continue
109
+		}
110
+		if status != http.StatusNoContent {
111
+			errs = append(errs, fmt.Sprintf("error deleting volume %s: %s", v.Name, string(b)))
112
+		}
113
+	}
114
+	if len(errs) > 0 {
115
+		t.Fatalf("%v", strings.Join(errs, "\n"))
116
+	}
117
+}
118
+
119
+func getAllVolumes() ([]*types.Volume, error) {
120
+	var volumes volumetypes.VolumesListOKBody
121
+	_, b, err := request.SockRequest("GET", "/volumes", nil, DaemonHost())
122
+	if err != nil {
123
+		return nil, err
124
+	}
125
+	if err := json.Unmarshal(b, &volumes); err != nil {
126
+		return nil, err
127
+	}
128
+	return volumes.Volumes, nil
129
+}
130
+
131
+func deleteAllNetworks(t testingT, dockerBinary string, daemonPlatform string) {
132
+	networks, err := getAllNetworks()
133
+	if err != nil {
134
+		t.Fatalf("%v", err)
135
+	}
136
+	var errs []string
137
+	for _, n := range networks {
138
+		if n.Name == "bridge" || n.Name == "none" || n.Name == "host" {
139
+			continue
140
+		}
141
+		if daemonPlatform == "windows" && strings.ToLower(n.Name) == "nat" {
142
+			// nat is a pre-defined network on Windows and cannot be removed
143
+			continue
144
+		}
145
+		status, b, err := request.SockRequest("DELETE", "/networks/"+n.Name, nil, DaemonHost())
146
+		if err != nil {
147
+			errs = append(errs, err.Error())
148
+			continue
149
+		}
150
+		if status != http.StatusNoContent {
151
+			errs = append(errs, fmt.Sprintf("error deleting network %s: %s", n.Name, string(b)))
152
+		}
153
+	}
154
+	if len(errs) > 0 {
155
+		t.Fatalf("%v", strings.Join(errs, "\n"))
156
+	}
157
+}
158
+
159
+func getAllNetworks() ([]types.NetworkResource, error) {
160
+	var networks []types.NetworkResource
161
+	_, b, err := request.SockRequest("GET", "/networks", nil, DaemonHost())
162
+	if err != nil {
163
+		return nil, err
164
+	}
165
+	if err := json.Unmarshal(b, &networks); err != nil {
166
+		return nil, err
167
+	}
168
+	return networks, nil
169
+}
170
+
171
+func deleteAllPlugins(t testingT, dockerBinary string) {
172
+	plugins, err := getAllPlugins()
173
+	if err != nil {
174
+		t.Fatalf("%v", err)
175
+	}
176
+	var errs []string
177
+	for _, p := range plugins {
178
+		pluginName := p.Name
179
+		status, b, err := request.SockRequest("DELETE", "/plugins/"+pluginName+"?force=1", nil, DaemonHost())
180
+		if err != nil {
181
+			errs = append(errs, err.Error())
182
+			continue
183
+		}
184
+		if status != http.StatusOK {
185
+			errs = append(errs, fmt.Sprintf("error deleting plugin %s: %s", p.Name, string(b)))
186
+		}
187
+	}
188
+	if len(errs) > 0 {
189
+		t.Fatalf("%v", strings.Join(errs, "\n"))
190
+	}
191
+}
192
+
193
+func getAllPlugins() (types.PluginsListResponse, error) {
194
+	var plugins types.PluginsListResponse
195
+	_, b, err := request.SockRequest("GET", "/plugins", nil, DaemonHost())
196
+	if err != nil {
197
+		return nil, err
198
+	}
199
+	if err := json.Unmarshal(b, &plugins); err != nil {
200
+		return nil, err
201
+	}
202
+	return plugins, nil
203
+}
204
+
205
+// DaemonHost return the daemon host string for this test execution
206
+func DaemonHost() string {
207
+	daemonURLStr := "unix://" + opts.DefaultUnixSocket
208
+	if daemonHostVar := os.Getenv("DOCKER_HOST"); daemonHostVar != "" {
209
+		daemonURLStr = daemonHostVar
210
+	}
211
+	return daemonURLStr
212
+}
... ...
@@ -32,6 +32,8 @@ type Execution struct {
32 32
 	// baseImage is the name of the base image for testing
33 33
 	// Environment variable WINDOWS_BASE_IMAGE can override this
34 34
 	baseImage string
35
+
36
+	protectedElements protectedElements
35 37
 }
36 38
 
37 39
 // New creates a new Execution struct
... ...
@@ -100,6 +102,9 @@ func New() (*Execution, error) {
100 100
 		daemonPid:            daemonPid,
101 101
 		experimentalDaemon:   info.ExperimentalBuild,
102 102
 		baseImage:            baseImage,
103
+		protectedElements: protectedElements{
104
+			images: map[string]struct{}{},
105
+		},
103 106
 	}, nil
104 107
 }
105 108
 func getDaemonDockerInfo() (types.Info, error) {
106 109
new file mode 100644
... ...
@@ -0,0 +1,12 @@
0
+package environment
1
+
2
+// ProtectImage adds the specified image(s) to be protected in case of clean
3
+func (e *Execution) ProtectImage(t testingT, images ...string) {
4
+	for _, image := range images {
5
+		e.protectedElements.images[image] = struct{}{}
6
+	}
7
+}
8
+
9
+type protectedElements struct {
10
+	images map[string]struct{}
11
+}
... ...
@@ -31,9 +31,7 @@ func ensureFrozenImagesLinux(t testingT) {
31 31
 		t.Logf(dockerCmdWithError("images"))
32 32
 		t.Fatalf("%+v", err)
33 33
 	}
34
-	for _, img := range images {
35
-		protectedImages[img] = struct{}{}
36
-	}
34
+	defer testEnv.ProtectImage(t, images...)
37 35
 }
38 36
 
39 37
 var ensureSyscallTestOnce sync.Once
... ...
@@ -46,7 +44,7 @@ func ensureSyscallTest(c *check.C) {
46 46
 	if !doIt {
47 47
 		return
48 48
 	}
49
-	protectedImages["syscall-test:latest"] = struct{}{}
49
+	defer testEnv.ProtectImage(c, "syscall-test:latest")
50 50
 
51 51
 	// if no match, must build in docker, which is significantly slower
52 52
 	// (slower mostly because of the vfs graphdriver)
... ...
@@ -104,7 +102,7 @@ func ensureSyscallTestBuild(c *check.C) {
104 104
 }
105 105
 
106 106
 func ensureNNPTest(c *check.C) {
107
-	protectedImages["nnp-test:latest"] = struct{}{}
107
+	defer testEnv.ProtectImage(c, "nnp-test:latest")
108 108
 	if testEnv.DaemonPlatform() != runtime.GOOS {
109 109
 		ensureNNPTestBuild(c)
110 110
 		return
... ...
@@ -1,7 +1,6 @@
1 1
 package main
2 2
 
3 3
 import (
4
-	"fmt"
5 4
 	"io/ioutil"
6 5
 	"os"
7 6
 	"os/exec"
... ...
@@ -11,21 +10,21 @@ import (
11 11
 
12 12
 var ensureHTTPServerOnce sync.Once
13 13
 
14
-func ensureHTTPServerImage() error {
14
+func ensureHTTPServerImage(t testingT) {
15 15
 	var doIt bool
16 16
 	ensureHTTPServerOnce.Do(func() {
17 17
 		doIt = true
18 18
 	})
19 19
 
20 20
 	if !doIt {
21
-		return nil
21
+		return
22 22
 	}
23 23
 
24
-	protectedImages["httpserver:latest"] = struct{}{}
24
+	defer testEnv.ProtectImage(t, "httpserver:latest")
25 25
 
26 26
 	tmp, err := ioutil.TempDir("", "docker-http-server-test")
27 27
 	if err != nil {
28
-		return fmt.Errorf("could not build http server: %v", err)
28
+		t.Fatalf("could not build http server: %v", err)
29 29
 	}
30 30
 	defer os.RemoveAll(tmp)
31 31
 
... ...
@@ -40,7 +39,7 @@ func ensureHTTPServerImage() error {
40 40
 
41 41
 	goCmd, lookErr := exec.LookPath("go")
42 42
 	if lookErr != nil {
43
-		return fmt.Errorf("could not build http server: %v", lookErr)
43
+		t.Fatalf("could not build http server: %v", lookErr)
44 44
 	}
45 45
 
46 46
 	cmd := exec.Command(goCmd, "build", "-o", filepath.Join(tmp, "httpserver"), "github.com/docker/docker/contrib/httpserver")
... ...
@@ -51,19 +50,18 @@ func ensureHTTPServerImage() error {
51 51
 	}...)
52 52
 	var out []byte
53 53
 	if out, err = cmd.CombinedOutput(); err != nil {
54
-		return fmt.Errorf("could not build http server: %s", string(out))
54
+		t.Fatalf("could not build http server: %s", string(out))
55 55
 	}
56 56
 
57 57
 	cpCmd, lookErr := exec.LookPath("cp")
58 58
 	if lookErr != nil {
59
-		return fmt.Errorf("could not build http server: %v", lookErr)
59
+		t.Fatalf("could not build http server: %v", lookErr)
60 60
 	}
61 61
 	if out, err = exec.Command(cpCmd, "../contrib/httpserver/Dockerfile", filepath.Join(tmp, "Dockerfile")).CombinedOutput(); err != nil {
62
-		return fmt.Errorf("could not build http server: %v", string(out))
62
+		t.Fatalf("could not build http server: %v", string(out))
63 63
 	}
64 64
 
65 65
 	if out, err = exec.Command(dockerBinary, "build", "-q", "-t", "httpserver", tmp).CombinedOutput(); err != nil {
66
-		return fmt.Errorf("could not build http server: %v", string(out))
66
+		t.Fatalf("could not build http server: %v", string(out))
67 67
 	}
68
-	return nil
69 68
 }