Browse Source

Merge pull request #12875 from runcom/remove-cfatal-in-goroutine-integration-cli

c.Fatal won't fail and exit test inside a goroutine
Jessie Frazelle 10 năm trước cách đây
mục cha
commit
d716f22aad

+ 7 - 8
integration-cli/docker_api_containers_test.go

@@ -260,15 +260,14 @@ func (s *DockerSuite) TestGetContainerStats(c *check.C) {
 		c.Fatalf("Error on container creation: %v, output: %q", err, out)
 		c.Fatalf("Error on container creation: %v, output: %q", err, out)
 	}
 	}
 	type b struct {
 	type b struct {
-		body []byte
-		err  error
+		status int
+		body   []byte
+		err    error
 	}
 	}
 	bc := make(chan b, 1)
 	bc := make(chan b, 1)
 	go func() {
 	go func() {
 		status, body, err := sockRequest("GET", "/containers/"+name+"/stats", nil)
 		status, body, err := sockRequest("GET", "/containers/"+name+"/stats", nil)
-		c.Assert(status, check.Equals, http.StatusOK)
-		c.Assert(err, check.IsNil)
-		bc <- b{body, err}
+		bc <- b{status, body, err}
 	}()
 	}()
 
 
 	// allow some time to stream the stats from the container
 	// allow some time to stream the stats from the container
@@ -283,9 +282,8 @@ func (s *DockerSuite) TestGetContainerStats(c *check.C) {
 	case <-time.After(2 * time.Second):
 	case <-time.After(2 * time.Second):
 		c.Fatal("stream was not closed after container was removed")
 		c.Fatal("stream was not closed after container was removed")
 	case sr := <-bc:
 	case sr := <-bc:
-		if sr.err != nil {
-			c.Fatal(sr.err)
-		}
+		c.Assert(sr.err, check.IsNil)
+		c.Assert(sr.status, check.Equals, http.StatusOK)
 
 
 		dec := json.NewDecoder(bytes.NewBuffer(sr.body))
 		dec := json.NewDecoder(bytes.NewBuffer(sr.body))
 		var s *types.Stats
 		var s *types.Stats
@@ -297,6 +295,7 @@ func (s *DockerSuite) TestGetContainerStats(c *check.C) {
 }
 }
 
 
 func (s *DockerSuite) TestGetStoppedContainerStats(c *check.C) {
 func (s *DockerSuite) TestGetStoppedContainerStats(c *check.C) {
+	// TODO: this test does nothing because we are c.Assert'ing in goroutine
 	var (
 	var (
 		name   = "statscontainer"
 		name   = "statscontainer"
 		runCmd = exec.Command(dockerBinary, "create", "--name", name, "busybox", "top")
 		runCmd = exec.Command(dockerBinary, "create", "--name", name, "busybox", "top")

+ 10 - 7
integration-cli/docker_cli_attach_test.go

@@ -2,6 +2,7 @@ package main
 
 
 import (
 import (
 	"bufio"
 	"bufio"
+	"fmt"
 	"io"
 	"io"
 	"os/exec"
 	"os/exec"
 	"strings"
 	"strings"
@@ -89,7 +90,6 @@ func (s *DockerSuite) TestAttachMultipleAndRestart(c *check.C) {
 }
 }
 
 
 func (s *DockerSuite) TestAttachTtyWithoutStdin(c *check.C) {
 func (s *DockerSuite) TestAttachTtyWithoutStdin(c *check.C) {
-
 	cmd := exec.Command(dockerBinary, "run", "-d", "-ti", "busybox")
 	cmd := exec.Command(dockerBinary, "run", "-d", "-ti", "busybox")
 	out, _, err := runCommandWithOutput(cmd)
 	out, _, err := runCommandWithOutput(cmd)
 	if err != nil {
 	if err != nil {
@@ -108,29 +108,32 @@ func (s *DockerSuite) TestAttachTtyWithoutStdin(c *check.C) {
 		}
 		}
 	}()
 	}()
 
 
-	done := make(chan struct{})
+	done := make(chan error)
 	go func() {
 	go func() {
 		defer close(done)
 		defer close(done)
 
 
 		cmd := exec.Command(dockerBinary, "attach", id)
 		cmd := exec.Command(dockerBinary, "attach", id)
 		if _, err := cmd.StdinPipe(); err != nil {
 		if _, err := cmd.StdinPipe(); err != nil {
-			c.Fatal(err)
+			done <- err
+			return
 		}
 		}
 
 
 		expected := "cannot enable tty mode"
 		expected := "cannot enable tty mode"
 		if out, _, err := runCommandWithOutput(cmd); err == nil {
 		if out, _, err := runCommandWithOutput(cmd); err == nil {
-			c.Fatal("attach should have failed")
+			done <- fmt.Errorf("attach should have failed")
+			return
 		} else if !strings.Contains(out, expected) {
 		} else if !strings.Contains(out, expected) {
-			c.Fatalf("attach failed with error %q: expected %q", out, expected)
+			done <- fmt.Errorf("attach failed with error %q: expected %q", out, expected)
+			return
 		}
 		}
 	}()
 	}()
 
 
 	select {
 	select {
-	case <-done:
+	case err := <-done:
+		c.Assert(err, check.IsNil)
 	case <-time.After(attachWait):
 	case <-time.After(attachWait):
 		c.Fatal("attach is running but should have failed")
 		c.Fatal("attach is running but should have failed")
 	}
 	}
-
 }
 }
 
 
 func (s *DockerSuite) TestAttachDisconnect(c *check.C) {
 func (s *DockerSuite) TestAttachDisconnect(c *check.C) {

+ 18 - 15
integration-cli/docker_cli_attach_unix_test.go

@@ -27,14 +27,14 @@ func (s *DockerSuite) TestAttachClosedOnContainerStop(c *check.C) {
 		c.Fatal(err)
 		c.Fatal(err)
 	}
 	}
 
 
-	done := make(chan struct{})
-
+	errChan := make(chan error)
 	go func() {
 	go func() {
-		defer close(done)
+		defer close(errChan)
 
 
 		_, tty, err := pty.Open()
 		_, tty, err := pty.Open()
 		if err != nil {
 		if err != nil {
-			c.Fatalf("could not open pty: %v", err)
+			errChan <- err
+			return
 		}
 		}
 		attachCmd := exec.Command(dockerBinary, "attach", id)
 		attachCmd := exec.Command(dockerBinary, "attach", id)
 		attachCmd.Stdin = tty
 		attachCmd.Stdin = tty
@@ -42,7 +42,8 @@ func (s *DockerSuite) TestAttachClosedOnContainerStop(c *check.C) {
 		attachCmd.Stderr = tty
 		attachCmd.Stderr = tty
 
 
 		if err := attachCmd.Run(); err != nil {
 		if err := attachCmd.Run(); err != nil {
-			c.Fatalf("attach returned error %s", err)
+			errChan <- err
+			return
 		}
 		}
 	}()
 	}()
 
 
@@ -51,7 +52,8 @@ func (s *DockerSuite) TestAttachClosedOnContainerStop(c *check.C) {
 		c.Fatalf("error thrown while waiting for container: %s, %v", out, err)
 		c.Fatalf("error thrown while waiting for container: %s, %v", out, err)
 	}
 	}
 	select {
 	select {
-	case <-done:
+	case err := <-errChan:
+		c.Assert(err, check.IsNil)
 	case <-time.After(attachWait):
 	case <-time.After(attachWait):
 		c.Fatal("timed out without attach returning")
 		c.Fatal("timed out without attach returning")
 	}
 	}
@@ -71,12 +73,10 @@ func (s *DockerSuite) TestAttachAfterDetach(c *check.C) {
 	cmd.Stdout = tty
 	cmd.Stdout = tty
 	cmd.Stderr = tty
 	cmd.Stderr = tty
 
 
-	detached := make(chan struct{})
+	errChan := make(chan error)
 	go func() {
 	go func() {
-		if err := cmd.Run(); err != nil {
-			c.Fatalf("attach returned error %s", err)
-		}
-		close(detached)
+		errChan <- cmd.Run()
+		close(errChan)
 	}()
 	}()
 
 
 	time.Sleep(500 * time.Millisecond)
 	time.Sleep(500 * time.Millisecond)
@@ -87,7 +87,12 @@ func (s *DockerSuite) TestAttachAfterDetach(c *check.C) {
 	time.Sleep(100 * time.Millisecond)
 	time.Sleep(100 * time.Millisecond)
 	cpty.Write([]byte{17})
 	cpty.Write([]byte{17})
 
 
-	<-detached
+	select {
+	case err := <-errChan:
+		c.Assert(err, check.IsNil)
+	case <-time.After(5 * time.Second):
+		c.Fatal("timeout while detaching")
+	}
 
 
 	cpty, tty, err = pty.Open()
 	cpty, tty, err = pty.Open()
 	if err != nil {
 	if err != nil {
@@ -119,9 +124,7 @@ func (s *DockerSuite) TestAttachAfterDetach(c *check.C) {
 
 
 	select {
 	select {
 	case err := <-readErr:
 	case err := <-readErr:
-		if err != nil {
-			c.Fatal(err)
-		}
+		c.Assert(err, check.IsNil)
 	case <-time.After(2 * time.Second):
 	case <-time.After(2 * time.Second):
 		c.Fatal("timeout waiting for attach read")
 		c.Fatal("timeout waiting for attach read")
 	}
 	}

+ 27 - 44
integration-cli/docker_cli_build_test.go

@@ -15,7 +15,6 @@ import (
 	"runtime"
 	"runtime"
 	"strconv"
 	"strconv"
 	"strings"
 	"strings"
-	"sync"
 	"text/template"
 	"text/template"
 	"time"
 	"time"
 
 
@@ -764,17 +763,17 @@ ADD test_file .`,
 	}
 	}
 	defer ctx.Close()
 	defer ctx.Close()
 
 
-	done := make(chan struct{})
+	errChan := make(chan error)
 	go func() {
 	go func() {
-		if _, err := buildImageFromContext(name, ctx, true); err != nil {
-			c.Fatal(err)
-		}
-		close(done)
+		_, err := buildImageFromContext(name, ctx, true)
+		errChan <- err
+		close(errChan)
 	}()
 	}()
 	select {
 	select {
 	case <-time.After(5 * time.Second):
 	case <-time.After(5 * time.Second):
 		c.Fatal("Build with adding to workdir timed out")
 		c.Fatal("Build with adding to workdir timed out")
-	case <-done:
+	case err := <-errChan:
+		c.Assert(err, check.IsNil)
 	}
 	}
 }
 }
 
 
@@ -1365,17 +1364,17 @@ COPY test_file .`,
 	}
 	}
 	defer ctx.Close()
 	defer ctx.Close()
 
 
-	done := make(chan struct{})
+	errChan := make(chan error)
 	go func() {
 	go func() {
-		if _, err := buildImageFromContext(name, ctx, true); err != nil {
-			c.Fatal(err)
-		}
-		close(done)
+		_, err := buildImageFromContext(name, ctx, true)
+		errChan <- err
+		close(errChan)
 	}()
 	}()
 	select {
 	select {
 	case <-time.After(5 * time.Second):
 	case <-time.After(5 * time.Second):
 		c.Fatal("Build with adding to workdir timed out")
 		c.Fatal("Build with adding to workdir timed out")
-	case <-done:
+	case err := <-errChan:
+		c.Assert(err, check.IsNil)
 	}
 	}
 }
 }
 
 
@@ -1829,9 +1828,6 @@ func (s *DockerSuite) TestBuildForceRm(c *check.C) {
 // * When docker events sees container start, close the "docker build" command
 // * When docker events sees container start, close the "docker build" command
 // * Wait for docker events to emit a dying event.
 // * Wait for docker events to emit a dying event.
 func (s *DockerSuite) TestBuildCancelationKillsSleep(c *check.C) {
 func (s *DockerSuite) TestBuildCancelationKillsSleep(c *check.C) {
-	var wg sync.WaitGroup
-	defer wg.Wait()
-
 	name := "testbuildcancelation"
 	name := "testbuildcancelation"
 
 
 	// (Note: one year, will never finish)
 	// (Note: one year, will never finish)
@@ -1849,26 +1845,21 @@ func (s *DockerSuite) TestBuildCancelationKillsSleep(c *check.C) {
 	containerID := make(chan string)
 	containerID := make(chan string)
 
 
 	startEpoch := daemonTime(c).Unix()
 	startEpoch := daemonTime(c).Unix()
+	// Watch for events since epoch.
+	eventsCmd := exec.Command(
+		dockerBinary, "events",
+		"--since", strconv.FormatInt(startEpoch, 10))
+	stdout, err := eventsCmd.StdoutPipe()
+	if err != nil {
+		c.Fatal(err)
+	}
+	if err := eventsCmd.Start(); err != nil {
+		c.Fatal(err)
+	}
+	defer eventsCmd.Process.Kill()
 
 
-	wg.Add(1)
 	// Goroutine responsible for watching start/die events from `docker events`
 	// Goroutine responsible for watching start/die events from `docker events`
 	go func() {
 	go func() {
-		defer wg.Done()
-		// Watch for events since epoch.
-		eventsCmd := exec.Command(
-			dockerBinary, "events",
-			"--since", strconv.FormatInt(startEpoch, 10))
-		stdout, err := eventsCmd.StdoutPipe()
-		err = eventsCmd.Start()
-		if err != nil {
-			c.Fatalf("failed to start 'docker events': %s", err)
-		}
-
-		go func() {
-			<-finish
-			eventsCmd.Process.Kill()
-		}()
-
 		cid := <-containerID
 		cid := <-containerID
 
 
 		matchStart := regexp.MustCompile(cid + `(.*) start$`)
 		matchStart := regexp.MustCompile(cid + `(.*) start$`)
@@ -1886,19 +1877,13 @@ func (s *DockerSuite) TestBuildCancelationKillsSleep(c *check.C) {
 				close(eventDie)
 				close(eventDie)
 			}
 			}
 		}
 		}
-
-		err = eventsCmd.Wait()
-		if err != nil && !IsKilled(err) {
-			c.Fatalf("docker events had bad exit status: %s", err)
-		}
 	}()
 	}()
 
 
 	buildCmd := exec.Command(dockerBinary, "build", "-t", name, ".")
 	buildCmd := exec.Command(dockerBinary, "build", "-t", name, ".")
 	buildCmd.Dir = ctx.Dir
 	buildCmd.Dir = ctx.Dir
 
 
 	stdoutBuild, err := buildCmd.StdoutPipe()
 	stdoutBuild, err := buildCmd.StdoutPipe()
-	err = buildCmd.Start()
-	if err != nil {
+	if err := buildCmd.Start(); err != nil {
 		c.Fatalf("failed to run build: %s", err)
 		c.Fatalf("failed to run build: %s", err)
 	}
 	}
 
 
@@ -1923,14 +1908,12 @@ func (s *DockerSuite) TestBuildCancelationKillsSleep(c *check.C) {
 
 
 	// Send a kill to the `docker build` command.
 	// Send a kill to the `docker build` command.
 	// Causes the underlying build to be cancelled due to socket close.
 	// Causes the underlying build to be cancelled due to socket close.
-	err = buildCmd.Process.Kill()
-	if err != nil {
+	if err := buildCmd.Process.Kill(); err != nil {
 		c.Fatalf("error killing build command: %s", err)
 		c.Fatalf("error killing build command: %s", err)
 	}
 	}
 
 
 	// Get the exit status of `docker build`, check it exited because killed.
 	// Get the exit status of `docker build`, check it exited because killed.
-	err = buildCmd.Wait()
-	if err != nil && !IsKilled(err) {
+	if err := buildCmd.Wait(); err != nil && !IsKilled(err) {
 		c.Fatalf("wait failed during build run: %T %s", err, err)
 		c.Fatalf("wait failed during build run: %T %s", err, err)
 	}
 	}
 
 

+ 12 - 27
integration-cli/docker_cli_events_test.go

@@ -75,8 +75,7 @@ func (s *DockerSuite) TestEventsLimit(c *check.C) {
 		waitGroup.Add(1)
 		waitGroup.Add(1)
 		go func() {
 		go func() {
 			defer waitGroup.Done()
 			defer waitGroup.Done()
-			err := exec.Command(dockerBinary, args...).Run()
-			errChan <- err
+			errChan <- exec.Command(dockerBinary, args...).Run()
 		}()
 		}()
 	}
 	}
 
 
@@ -229,8 +228,7 @@ func (s *DockerSuite) TestEventsImageImport(c *check.C) {
 	if err != nil {
 	if err != nil {
 		c.Fatal(err)
 		c.Fatal(err)
 	}
 	}
-	err = eventsCmd.Start()
-	if err != nil {
+	if err := eventsCmd.Start(); err != nil {
 		c.Fatal(err)
 		c.Fatal(err)
 	}
 	}
 	defer eventsCmd.Process.Kill()
 	defer eventsCmd.Process.Kill()
@@ -424,30 +422,23 @@ func (s *DockerSuite) TestEventsFilterContainer(c *check.C) {
 func (s *DockerSuite) TestEventsStreaming(c *check.C) {
 func (s *DockerSuite) TestEventsStreaming(c *check.C) {
 	start := daemonTime(c).Unix()
 	start := daemonTime(c).Unix()
 
 
-	finish := make(chan struct{})
-	defer close(finish)
 	id := make(chan string)
 	id := make(chan string)
 	eventCreate := make(chan struct{})
 	eventCreate := make(chan struct{})
 	eventStart := make(chan struct{})
 	eventStart := make(chan struct{})
 	eventDie := make(chan struct{})
 	eventDie := make(chan struct{})
 	eventDestroy := make(chan struct{})
 	eventDestroy := make(chan struct{})
 
 
-	go func() {
-		eventsCmd := exec.Command(dockerBinary, "events", "--since", strconv.FormatInt(start, 10))
-		stdout, err := eventsCmd.StdoutPipe()
-		if err != nil {
-			c.Fatal(err)
-		}
-		err = eventsCmd.Start()
-		if err != nil {
-			c.Fatalf("failed to start 'docker events': %s", err)
-		}
-
-		go func() {
-			<-finish
-			eventsCmd.Process.Kill()
-		}()
+	eventsCmd := exec.Command(dockerBinary, "events", "--since", strconv.FormatInt(start, 10))
+	stdout, err := eventsCmd.StdoutPipe()
+	if err != nil {
+		c.Fatal(err)
+	}
+	if err := eventsCmd.Start(); err != nil {
+		c.Fatalf("failed to start 'docker events': %s", err)
+	}
+	defer eventsCmd.Process.Kill()
 
 
+	go func() {
 		containerID := <-id
 		containerID := <-id
 
 
 		matchCreate := regexp.MustCompile(containerID + `: \(from busybox:latest\) create$`)
 		matchCreate := regexp.MustCompile(containerID + `: \(from busybox:latest\) create$`)
@@ -468,11 +459,6 @@ func (s *DockerSuite) TestEventsStreaming(c *check.C) {
 				close(eventDestroy)
 				close(eventDestroy)
 			}
 			}
 		}
 		}
-
-		err = eventsCmd.Wait()
-		if err != nil && !IsKilled(err) {
-			c.Fatalf("docker events had bad exit status: %s", err)
-		}
 	}()
 	}()
 
 
 	runCmd := exec.Command(dockerBinary, "run", "-d", "busybox:latest", "true")
 	runCmd := exec.Command(dockerBinary, "run", "-d", "busybox:latest", "true")
@@ -516,5 +502,4 @@ func (s *DockerSuite) TestEventsStreaming(c *check.C) {
 	case <-eventDestroy:
 	case <-eventDestroy:
 		// ignore, done
 		// ignore, done
 	}
 	}
-
 }
 }

+ 34 - 19
integration-cli/docker_cli_exec_test.go

@@ -74,15 +74,14 @@ func (s *DockerSuite) TestExecInteractive(c *check.C) {
 	if err := stdin.Close(); err != nil {
 	if err := stdin.Close(); err != nil {
 		c.Fatal(err)
 		c.Fatal(err)
 	}
 	}
-	finish := make(chan struct{})
+	errChan := make(chan error)
 	go func() {
 	go func() {
-		if err := execCmd.Wait(); err != nil {
-			c.Fatal(err)
-		}
-		close(finish)
+		errChan <- execCmd.Wait()
+		close(errChan)
 	}()
 	}()
 	select {
 	select {
-	case <-finish:
+	case err := <-errChan:
+		c.Assert(err, check.IsNil)
 	case <-time.After(1 * time.Second):
 	case <-time.After(1 * time.Second):
 		c.Fatal("docker exec failed to exit on stdin close")
 		c.Fatal("docker exec failed to exit on stdin close")
 	}
 	}
@@ -278,25 +277,29 @@ func (s *DockerSuite) TestExecTtyWithoutStdin(c *check.C) {
 		}
 		}
 	}()
 	}()
 
 
-	done := make(chan struct{})
+	errChan := make(chan error)
 	go func() {
 	go func() {
-		defer close(done)
+		defer close(errChan)
 
 
 		cmd := exec.Command(dockerBinary, "exec", "-ti", id, "true")
 		cmd := exec.Command(dockerBinary, "exec", "-ti", id, "true")
 		if _, err := cmd.StdinPipe(); err != nil {
 		if _, err := cmd.StdinPipe(); err != nil {
-			c.Fatal(err)
+			errChan <- err
+			return
 		}
 		}
 
 
 		expected := "cannot enable tty mode"
 		expected := "cannot enable tty mode"
 		if out, _, err := runCommandWithOutput(cmd); err == nil {
 		if out, _, err := runCommandWithOutput(cmd); err == nil {
-			c.Fatal("exec should have failed")
+			errChan <- fmt.Errorf("exec should have failed")
+			return
 		} else if !strings.Contains(out, expected) {
 		} else if !strings.Contains(out, expected) {
-			c.Fatalf("exec failed with error %q: expected %q", out, expected)
+			errChan <- fmt.Errorf("exec failed with error %q: expected %q", out, expected)
+			return
 		}
 		}
 	}()
 	}()
 
 
 	select {
 	select {
-	case <-done:
+	case err := <-errChan:
+		c.Assert(err, check.IsNil)
 	case <-time.After(3 * time.Second):
 	case <-time.After(3 * time.Second):
 		c.Fatal("exec is running but should have failed")
 		c.Fatal("exec is running but should have failed")
 	}
 	}
@@ -326,17 +329,22 @@ func (s *DockerSuite) TestExecStopNotHanging(c *check.C) {
 		c.Fatal(err)
 		c.Fatal(err)
 	}
 	}
 
 
-	wait := make(chan struct{})
+	type dstop struct {
+		out []byte
+		err error
+	}
+
+	ch := make(chan dstop)
 	go func() {
 	go func() {
-		if out, err := exec.Command(dockerBinary, "stop", "testing").CombinedOutput(); err != nil {
-			c.Fatal(out, err)
-		}
-		close(wait)
+		out, err := exec.Command(dockerBinary, "stop", "testing").CombinedOutput()
+		ch <- dstop{out, err}
+		close(ch)
 	}()
 	}()
 	select {
 	select {
 	case <-time.After(3 * time.Second):
 	case <-time.After(3 * time.Second):
 		c.Fatal("Container stop timed out")
 		c.Fatal("Container stop timed out")
-	case <-wait:
+	case s := <-ch:
+		c.Assert(s.err, check.IsNil)
 	}
 	}
 }
 }
 
 
@@ -359,6 +367,7 @@ func (s *DockerSuite) TestExecCgroup(c *check.C) {
 	var wg sync.WaitGroup
 	var wg sync.WaitGroup
 	var mu sync.Mutex
 	var mu sync.Mutex
 	execCgroups := []sort.StringSlice{}
 	execCgroups := []sort.StringSlice{}
+	errChan := make(chan error)
 	// exec a few times concurrently to get consistent failure
 	// exec a few times concurrently to get consistent failure
 	for i := 0; i < 5; i++ {
 	for i := 0; i < 5; i++ {
 		wg.Add(1)
 		wg.Add(1)
@@ -366,7 +375,8 @@ func (s *DockerSuite) TestExecCgroup(c *check.C) {
 			cmd := exec.Command(dockerBinary, "exec", "testing", "cat", "/proc/self/cgroup")
 			cmd := exec.Command(dockerBinary, "exec", "testing", "cat", "/proc/self/cgroup")
 			out, _, err := runCommandWithOutput(cmd)
 			out, _, err := runCommandWithOutput(cmd)
 			if err != nil {
 			if err != nil {
-				c.Fatal(out, err)
+				errChan <- err
+				return
 			}
 			}
 			cg := sort.StringSlice(strings.Split(string(out), "\n"))
 			cg := sort.StringSlice(strings.Split(string(out), "\n"))
 
 
@@ -377,6 +387,11 @@ func (s *DockerSuite) TestExecCgroup(c *check.C) {
 		}()
 		}()
 	}
 	}
 	wg.Wait()
 	wg.Wait()
+	close(errChan)
+
+	for err := range errChan {
+		c.Assert(err, check.IsNil)
+	}
 
 
 	for _, cg := range execCgroups {
 	for _, cg := range execCgroups {
 		if !reflect.DeepEqual(cg, containerCgroups) {
 		if !reflect.DeepEqual(cg, containerCgroups) {

+ 8 - 15
integration-cli/docker_cli_logs_test.go

@@ -260,16 +260,15 @@ func (s *DockerSuite) TestLogsFollowStopped(c *check.C) {
 		c.Fatal(err)
 		c.Fatal(err)
 	}
 	}
 
 
-	ch := make(chan struct{})
+	errChan := make(chan error)
 	go func() {
 	go func() {
-		if err := logsCmd.Wait(); err != nil {
-			c.Fatal(err)
-		}
-		close(ch)
+		errChan <- logsCmd.Wait()
+		close(errChan)
 	}()
 	}()
 
 
 	select {
 	select {
-	case <-ch:
+	case err := <-errChan:
+		c.Assert(err, check.IsNil)
 	case <-time.After(1 * time.Second):
 	case <-time.After(1 * time.Second):
 		c.Fatal("Following logs is hanged")
 		c.Fatal("Following logs is hanged")
 	}
 	}
@@ -298,9 +297,7 @@ func (s *DockerSuite) TestLogsFollowSlowStdoutConsumer(c *check.C) {
 	logCmd := exec.Command(dockerBinary, "logs", "-f", cleanedContainerID)
 	logCmd := exec.Command(dockerBinary, "logs", "-f", cleanedContainerID)
 
 
 	stdout, err := logCmd.StdoutPipe()
 	stdout, err := logCmd.StdoutPipe()
-	if err != nil {
-		c.Fatal(err)
-	}
+	c.Assert(err, check.IsNil)
 
 
 	if err := logCmd.Start(); err != nil {
 	if err := logCmd.Start(); err != nil {
 		c.Fatal(err)
 		c.Fatal(err)
@@ -308,15 +305,11 @@ func (s *DockerSuite) TestLogsFollowSlowStdoutConsumer(c *check.C) {
 
 
 	// First read slowly
 	// First read slowly
 	bytes1, err := consumeWithSpeed(stdout, 10, 50*time.Millisecond, stopSlowRead)
 	bytes1, err := consumeWithSpeed(stdout, 10, 50*time.Millisecond, stopSlowRead)
-	if err != nil {
-		c.Fatal(err)
-	}
+	c.Assert(err, check.IsNil)
 
 
 	// After the container has finished we can continue reading fast
 	// After the container has finished we can continue reading fast
 	bytes2, err := consumeWithSpeed(stdout, 32*1024, 0, nil)
 	bytes2, err := consumeWithSpeed(stdout, 32*1024, 0, nil)
-	if err != nil {
-		c.Fatal(err)
-	}
+	c.Assert(err, check.IsNil)
 
 
 	actual := bytes1 + bytes2
 	actual := bytes1 + bytes2
 	expected := 200000
 	expected := 200000

+ 0 - 1
integration-cli/docker_cli_ps_test.go

@@ -255,7 +255,6 @@ func assertContainerList(out string, expected []string) bool {
 }
 }
 
 
 func (s *DockerSuite) TestPsListContainersSize(c *check.C) {
 func (s *DockerSuite) TestPsListContainersSize(c *check.C) {
-
 	cmd := exec.Command(dockerBinary, "run", "-d", "busybox", "echo", "hello")
 	cmd := exec.Command(dockerBinary, "run", "-d", "busybox", "echo", "hello")
 	runCommandWithOutput(cmd)
 	runCommandWithOutput(cmd)
 	cmd = exec.Command(dockerBinary, "ps", "-s", "-n=1")
 	cmd = exec.Command(dockerBinary, "ps", "-s", "-n=1")

+ 30 - 25
integration-cli/docker_cli_run_test.go

@@ -756,17 +756,22 @@ func (s *DockerSuite) TestRunTwoConcurrentContainers(c *check.C) {
 	group := sync.WaitGroup{}
 	group := sync.WaitGroup{}
 	group.Add(2)
 	group.Add(2)
 
 
+	errChan := make(chan error, 2)
 	for i := 0; i < 2; i++ {
 	for i := 0; i < 2; i++ {
 		go func() {
 		go func() {
 			defer group.Done()
 			defer group.Done()
 			cmd := exec.Command(dockerBinary, "run", "busybox", "sleep", "2")
 			cmd := exec.Command(dockerBinary, "run", "busybox", "sleep", "2")
-			if _, err := runCommand(cmd); err != nil {
-				c.Fatal(err)
-			}
+			_, err := runCommand(cmd)
+			errChan <- err
 		}()
 		}()
 	}
 	}
 
 
 	group.Wait()
 	group.Wait()
+	close(errChan)
+
+	for err := range errChan {
+		c.Assert(err, check.IsNil)
+	}
 }
 }
 
 
 func (s *DockerSuite) TestRunEnvironment(c *check.C) {
 func (s *DockerSuite) TestRunEnvironment(c *check.C) {
@@ -1851,22 +1856,20 @@ func (s *DockerSuite) TestRunExitOnStdinClose(c *check.C) {
 	if err := stdin.Close(); err != nil {
 	if err := stdin.Close(); err != nil {
 		c.Fatal(err)
 		c.Fatal(err)
 	}
 	}
-	finish := make(chan struct{})
+	finish := make(chan error)
 	go func() {
 	go func() {
-		if err := runCmd.Wait(); err != nil {
-			c.Fatal(err)
-		}
+		finish <- runCmd.Wait()
 		close(finish)
 		close(finish)
 	}()
 	}()
 	select {
 	select {
-	case <-finish:
+	case err := <-finish:
+		c.Assert(err, check.IsNil)
 	case <-time.After(1 * time.Second):
 	case <-time.After(1 * time.Second):
 		c.Fatal("docker run failed to exit on stdin close")
 		c.Fatal("docker run failed to exit on stdin close")
 	}
 	}
 	state, err := inspectField(name, "State.Running")
 	state, err := inspectField(name, "State.Running")
-	if err != nil {
-		c.Fatal(err)
-	}
+	c.Assert(err, check.IsNil)
+
 	if state != "false" {
 	if state != "false" {
 		c.Fatal("Container must be stopped after stdin closing")
 		c.Fatal("Container must be stopped after stdin closing")
 	}
 	}
@@ -2762,25 +2765,29 @@ func (s *DockerSuite) TestRunPortFromDockerRangeInUse(c *check.C) {
 }
 }
 
 
 func (s *DockerSuite) TestRunTtyWithPipe(c *check.C) {
 func (s *DockerSuite) TestRunTtyWithPipe(c *check.C) {
-	done := make(chan struct{})
+	errChan := make(chan error)
 	go func() {
 	go func() {
-		defer close(done)
+		defer close(errChan)
 
 
 		cmd := exec.Command(dockerBinary, "run", "-ti", "busybox", "true")
 		cmd := exec.Command(dockerBinary, "run", "-ti", "busybox", "true")
 		if _, err := cmd.StdinPipe(); err != nil {
 		if _, err := cmd.StdinPipe(); err != nil {
-			c.Fatal(err)
+			errChan <- err
+			return
 		}
 		}
 
 
 		expected := "cannot enable tty mode"
 		expected := "cannot enable tty mode"
 		if out, _, err := runCommandWithOutput(cmd); err == nil {
 		if out, _, err := runCommandWithOutput(cmd); err == nil {
-			c.Fatal("run should have failed")
+			errChan <- fmt.Errorf("run should have failed")
+			return
 		} else if !strings.Contains(out, expected) {
 		} else if !strings.Contains(out, expected) {
-			c.Fatalf("run failed with error %q: expected %q", out, expected)
+			errChan <- fmt.Errorf("run failed with error %q: expected %q", out, expected)
+			return
 		}
 		}
 	}()
 	}()
 
 
 	select {
 	select {
-	case <-done:
+	case err := <-errChan:
+		c.Assert(err, check.IsNil)
 	case <-time.After(3 * time.Second):
 	case <-time.After(3 * time.Second):
 		c.Fatal("container is running but should have failed")
 		c.Fatal("container is running but should have failed")
 	}
 	}
@@ -2875,19 +2882,19 @@ func (s *DockerSuite) TestRunAllowPortRangeThroughPublish(c *check.C) {
 }
 }
 
 
 func (s *DockerSuite) TestRunOOMExitCode(c *check.C) {
 func (s *DockerSuite) TestRunOOMExitCode(c *check.C) {
-	done := make(chan struct{})
+	errChan := make(chan error)
 	go func() {
 	go func() {
-		defer close(done)
-
+		defer close(errChan)
 		runCmd := exec.Command(dockerBinary, "run", "-m", "4MB", "busybox", "sh", "-c", "x=a; while true; do x=$x$x$x$x; done")
 		runCmd := exec.Command(dockerBinary, "run", "-m", "4MB", "busybox", "sh", "-c", "x=a; while true; do x=$x$x$x$x; done")
 		out, exitCode, _ := runCommandWithOutput(runCmd)
 		out, exitCode, _ := runCommandWithOutput(runCmd)
 		if expected := 137; exitCode != expected {
 		if expected := 137; exitCode != expected {
-			c.Fatalf("wrong exit code for OOM container: expected %d, got %d (output: %q)", expected, exitCode, out)
+			errChan <- fmt.Errorf("wrong exit code for OOM container: expected %d, got %d (output: %q)", expected, exitCode, out)
 		}
 		}
 	}()
 	}()
 
 
 	select {
 	select {
-	case <-done:
+	case err := <-errChan:
+		c.Assert(err, check.IsNil)
 	case <-time.After(30 * time.Second):
 	case <-time.After(30 * time.Second):
 		c.Fatal("Timeout waiting for container to die on OOM")
 		c.Fatal("Timeout waiting for container to die on OOM")
 	}
 	}
@@ -3030,9 +3037,7 @@ func (s *DockerSuite) TestRunPidHostWithChildIsKillable(c *check.C) {
 	}()
 	}()
 	select {
 	select {
 	case err := <-errchan:
 	case err := <-errchan:
-		if err != nil {
-			c.Fatal(err)
-		}
+		c.Assert(err, check.IsNil)
 	case <-time.After(5 * time.Second):
 	case <-time.After(5 * time.Second):
 		c.Fatal("Kill container timed out")
 		c.Fatal("Kill container timed out")
 	}
 	}

+ 6 - 5
integration-cli/docker_cli_run_unix_test.go

@@ -29,21 +29,22 @@ func (s *DockerSuite) TestRunRedirectStdout(c *check.C) {
 		cmd.Stdin = tty
 		cmd.Stdin = tty
 		cmd.Stdout = tty
 		cmd.Stdout = tty
 		cmd.Stderr = tty
 		cmd.Stderr = tty
-		ch := make(chan struct{})
 		if err := cmd.Start(); err != nil {
 		if err := cmd.Start(); err != nil {
 			c.Fatalf("start err: %v", err)
 			c.Fatalf("start err: %v", err)
 		}
 		}
+		ch := make(chan error)
 		go func() {
 		go func() {
-			if err := cmd.Wait(); err != nil {
-				c.Fatalf("wait err=%v", err)
-			}
+			ch <- cmd.Wait()
 			close(ch)
 			close(ch)
 		}()
 		}()
 
 
 		select {
 		select {
 		case <-time.After(10 * time.Second):
 		case <-time.After(10 * time.Second):
 			c.Fatal("command timeout")
 			c.Fatal("command timeout")
-		case <-ch:
+		case err := <-ch:
+			if err != nil {
+				c.Fatalf("wait err=%v", err)
+			}
 		}
 		}
 	}
 	}
 
 

+ 4 - 3
integration-cli/docker_cli_start_test.go

@@ -20,18 +20,19 @@ func (s *DockerSuite) TestStartAttachReturnsOnError(c *check.C) {
 		c.Fatal("Expected error but got none")
 		c.Fatal("Expected error but got none")
 	}
 	}
 
 
-	ch := make(chan struct{})
+	ch := make(chan error)
 	go func() {
 	go func() {
 		// Attempt to start attached to the container that won't start
 		// Attempt to start attached to the container that won't start
 		// This should return an error immediately since the container can't be started
 		// This should return an error immediately since the container can't be started
 		if _, err := runCommand(exec.Command(dockerBinary, "start", "-a", "test2")); err == nil {
 		if _, err := runCommand(exec.Command(dockerBinary, "start", "-a", "test2")); err == nil {
-			c.Fatal("Expected error but got none")
+			ch <- fmt.Errorf("Expected error but got none")
 		}
 		}
 		close(ch)
 		close(ch)
 	}()
 	}()
 
 
 	select {
 	select {
-	case <-ch:
+	case err := <-ch:
+		c.Assert(err, check.IsNil)
 	case <-time.After(time.Second):
 	case <-time.After(time.Second):
 		c.Fatalf("Attach did not exit properly")
 		c.Fatalf("Attach did not exit properly")
 	}
 	}