浏览代码

Merge pull request #7564 from unclejack/integcli-add_utils

integration cli: add some utility functions and use them
Victor Vieux 11 年之前
父节点
当前提交
99caa68a46
共有 3 个文件被更改,包括 95 次插入70 次删除
  1. 6 42
      integration-cli/docker_cli_build_test.go
  2. 53 1
      integration-cli/docker_utils.go
  3. 36 27
      integration-cli/utils.go

+ 6 - 42
integration-cli/docker_cli_build_test.go

@@ -106,27 +106,9 @@ func TestBuildAddSingleFileToWorkdir(t *testing.T) {
 		t.Fatal(err)
 	}
 	f.Close()
-	buildCmd := exec.Command(dockerBinary, "build", "-t", "testaddimg", ".")
-	buildCmd.Dir = buildDirectory
-	done := make(chan error)
-	go func() {
-		out, exitCode, err := runCommandWithOutput(buildCmd)
-		if err != nil || exitCode != 0 {
-			done <- fmt.Errorf("build failed to complete: %s %v", out, err)
-			return
-		}
-		done <- nil
-	}()
-	select {
-	case <-time.After(5 * time.Second):
-		if err := buildCmd.Process.Kill(); err != nil {
-			fmt.Printf("could not kill build (pid=%d): %v\n", buildCmd.Process.Pid, err)
-		}
-		t.Fatal("build timed out")
-	case err := <-done:
-		if err != nil {
-			t.Fatal(err)
-		}
+	_, exitCode, err := dockerCmdInDirWithTimeout(5*time.Second, buildDirectory, "build", "-t", "testaddimg", ".")
+	if err != nil || exitCode != 0 {
+		t.Fatalf("build failed: %s", err)
 	}
 
 	deleteImages("testaddimg")
@@ -343,27 +325,9 @@ func TestBuildCopySingleFileToWorkdir(t *testing.T) {
 		t.Fatal(err)
 	}
 	f.Close()
-	buildCmd := exec.Command(dockerBinary, "build", "-t", "testcopyimg", ".")
-	buildCmd.Dir = buildDirectory
-	done := make(chan error)
-	go func() {
-		out, exitCode, err := runCommandWithOutput(buildCmd)
-		if err != nil || exitCode != 0 {
-			done <- fmt.Errorf("build failed to complete: %s %v", out, err)
-			return
-		}
-		done <- nil
-	}()
-	select {
-	case <-time.After(5 * time.Second):
-		if err := buildCmd.Process.Kill(); err != nil {
-			fmt.Printf("could not kill build (pid=%d): %v\n", buildCmd.Process.Pid, err)
-		}
-		t.Fatal("build timed out")
-	case err := <-done:
-		if err != nil {
-			t.Fatal(err)
-		}
+	_, exitCode, err := dockerCmdInDirWithTimeout(5*time.Second, buildDirectory, "build", "-t", "testcopyimg", ".")
+	if err != nil || exitCode != 0 {
+		t.Fatalf("build failed: %s", err)
 	}
 
 	deleteImages("testcopyimg")

+ 53 - 1
integration-cli/docker_utils.go

@@ -345,12 +345,34 @@ func dockerCmd(t *testing.T, args ...string) (string, int, error) {
 	return out, status, err
 }
 
+// execute a docker ocmmand with a timeout
+func dockerCmdWithTimeout(timeout time.Duration, args ...string) (string, int, error) {
+	out, status, err := runCommandWithOutputAndTimeout(exec.Command(dockerBinary, args...), timeout)
+	if err != nil {
+		return out, status, fmt.Errorf("'%s' failed with errors: %v : %q)", strings.Join(args, " "), err, out)
+	}
+	return out, status, err
+}
+
 // execute a docker command in a directory
 func dockerCmdInDir(t *testing.T, path string, args ...string) (string, int, error) {
 	dockerCommand := exec.Command(dockerBinary, args...)
 	dockerCommand.Dir = path
 	out, status, err := runCommandWithOutput(dockerCommand)
-	errorOut(err, t, fmt.Sprintf("'%s' failed with errors: %v (%v)", strings.Join(args, " "), err, out))
+	if err != nil {
+		return out, status, fmt.Errorf("'%s' failed with errors: %v : %q)", strings.Join(args, " "), err, out)
+	}
+	return out, status, err
+}
+
+// execute a docker command in a directory with a timeout
+func dockerCmdInDirWithTimeout(timeout time.Duration, path string, args ...string) (string, int, error) {
+	dockerCommand := exec.Command(dockerBinary, args...)
+	dockerCommand.Dir = path
+	out, status, err := runCommandWithOutputAndTimeout(dockerCommand, timeout)
+	if err != nil {
+		return out, status, fmt.Errorf("'%s' failed with errors: %v : %q)", strings.Join(args, " "), err, out)
+	}
 	return out, status, err
 }
 
@@ -486,6 +508,36 @@ func getIDByName(name string) (string, error) {
 	return inspectField(name, "Id")
 }
 
+// getContainerState returns the exit code of the container
+// and true if it's running
+// the exit code should be ignored if it's running
+func getContainerState(t *testing.T, id string) (int, bool, error) {
+	var (
+		exitStatus int
+		running    bool
+	)
+	out, exitCode, err := dockerCmd(t, "inspect", "--format={{.State.Running}} {{.State.ExitCode}}", id)
+	if err != nil || exitCode != 0 {
+		return 0, false, fmt.Errorf("'%s' doesn't exist: %s", id, err)
+	}
+
+	out = strings.Trim(out, "\n")
+	splitOutput := strings.Split(out, " ")
+	if len(splitOutput) != 2 {
+		return 0, false, fmt.Errorf("failed to get container state: output is broken")
+	}
+	if splitOutput[0] == "true" {
+		running = true
+	}
+	if n, err := strconv.Atoi(splitOutput[1]); err == nil {
+		exitStatus = n
+	} else {
+		return 0, false, fmt.Errorf("failed to get container state: couldn't parse integer")
+	}
+
+	return exitStatus, running, nil
+}
+
 func buildImageWithOut(name, dockerfile string, useCache bool) (string, string, error) {
 	args := []string{"build", "-t", name}
 	if !useCache {

+ 36 - 27
integration-cli/utils.go

@@ -28,9 +28,7 @@ func getExitCode(err error) (int, error) {
 	return exitCode, fmt.Errorf("failed to get exit code")
 }
 
-func runCommandWithOutput(cmd *exec.Cmd) (output string, exitCode int, err error) {
-	exitCode = 0
-	out, err := cmd.CombinedOutput()
+func processExitCode(err error) (exitCode int) {
 	if err != nil {
 		var exiterr error
 		if exitCode, exiterr = getExitCode(err); exiterr != nil {
@@ -39,6 +37,13 @@ func runCommandWithOutput(cmd *exec.Cmd) (output string, exitCode int, err error
 			exitCode = 127
 		}
 	}
+	return
+}
+
+func runCommandWithOutput(cmd *exec.Cmd) (output string, exitCode int, err error) {
+	exitCode = 0
+	out, err := cmd.CombinedOutput()
+	exitCode = processExitCode(err)
 	output = string(out)
 	return
 }
@@ -51,45 +56,49 @@ func runCommandWithStdoutStderr(cmd *exec.Cmd) (stdout string, stderr string, ex
 	cmd.Stderr = &stderrBuffer
 	cmd.Stdout = &stdoutBuffer
 	err = cmd.Run()
+	exitCode = processExitCode(err)
 
-	if err != nil {
-		var exiterr error
-		if exitCode, exiterr = getExitCode(err); exiterr != nil {
-			// TODO: Fix this so we check the error's text.
-			// we've failed to retrieve exit code, so we set it to 127
-			exitCode = 127
-		}
-	}
 	stdout = stdoutBuffer.String()
 	stderr = stderrBuffer.String()
 	return
 }
 
+var ErrCmdTimeout = fmt.Errorf("command timed out")
+
+func runCommandWithOutputAndTimeout(cmd *exec.Cmd, timeout time.Duration) (output string, exitCode int, err error) {
+	done := make(chan error)
+	go func() {
+		output, exitCode, err = runCommandWithOutput(cmd)
+		if err != nil || exitCode != 0 {
+			done <- fmt.Errorf("failed to run command: %s", err)
+			return
+		}
+		done <- nil
+	}()
+	select {
+	case <-time.After(timeout):
+		killFailed := cmd.Process.Kill()
+		if killFailed == nil {
+			fmt.Printf("failed to kill (pid=%d): %v\n", cmd.Process.Pid, err)
+		}
+		err = ErrCmdTimeout
+	case <-done:
+		break
+	}
+	return
+}
+
 func runCommand(cmd *exec.Cmd) (exitCode int, err error) {
 	exitCode = 0
 	err = cmd.Run()
-	if err != nil {
-		var exiterr error
-		if exitCode, exiterr = getExitCode(err); exiterr != nil {
-			// TODO: Fix this so we check the error's text.
-			// we've failed to retrieve exit code, so we set it to 127
-			exitCode = 127
-		}
-	}
+	exitCode = processExitCode(err)
 	return
 }
 
 func startCommand(cmd *exec.Cmd) (exitCode int, err error) {
 	exitCode = 0
 	err = cmd.Start()
-	if err != nil {
-		var exiterr error
-		if exitCode, exiterr = getExitCode(err); exiterr != nil {
-			// TODO: Fix this so we check the error's text.
-			// we've failed to retrieve exit code, so we set it to 127
-			exitCode = 127
-		}
-	}
+	exitCode = processExitCode(err)
 	return
 }