Esempio n. 1
0
func isKilled(err error) bool {
	return integration.IsKilled(err)
}
// Test that an infinite sleep during a build is killed if the client disconnects.
// This test is fairly hairy because there are lots of ways to race.
// Strategy:
// * Monitor the output of docker events starting from before
// * Run a 1-year-long sleep from a docker build.
// * When docker events sees container start, close the "docker build" command
// * Wait for docker events to emit a dying event.
func (s *DockerSuite) TestBuildCancellationKillsSleep(c *check.C) {
	testRequires(c, DaemonIsLinux)
	name := "testbuildcancellation"

	observer, err := newEventObserver(c)
	c.Assert(err, checker.IsNil)
	err = observer.Start()
	c.Assert(err, checker.IsNil)
	defer observer.Stop()

	// (Note: one year, will never finish)
	ctx, err := fakeContext("FROM busybox\nRUN sleep 31536000", nil)
	if err != nil {
		c.Fatal(err)
	}
	defer ctx.Close()

	buildCmd := exec.Command(dockerBinary, "build", "-t", name, ".")
	buildCmd.Dir = ctx.Dir

	stdoutBuild, err := buildCmd.StdoutPipe()
	if err := buildCmd.Start(); err != nil {
		c.Fatalf("failed to run build: %s", err)
	}

	matchCID := regexp.MustCompile("Running in (.+)")
	scanner := bufio.NewScanner(stdoutBuild)

	outputBuffer := new(bytes.Buffer)
	var buildID string
	for scanner.Scan() {
		line := scanner.Text()
		outputBuffer.WriteString(line)
		outputBuffer.WriteString("\n")
		if matches := matchCID.FindStringSubmatch(line); len(matches) > 0 {
			buildID = matches[1]
			break
		}
	}

	if buildID == "" {
		c.Fatalf("Unable to find build container id in build output:\n%s", outputBuffer.String())
	}

	testActions := map[string]chan bool{
		"start": make(chan bool, 1),
		"die":   make(chan bool, 1),
	}

	matcher := matchEventLine(buildID, "container", testActions)
	processor := processEventMatch(testActions)
	go observer.Match(matcher, processor)

	select {
	case <-time.After(10 * time.Second):
		observer.CheckEventError(c, buildID, "start", matcher)
	case <-testActions["start"]:
		// ignore, done
	}

	// Send a kill to the `docker build` command.
	// Causes the underlying build to be cancelled due to socket close.
	if err := buildCmd.Process.Kill(); err != nil {
		c.Fatalf("error killing build command: %s", err)
	}

	// Get the exit status of `docker build`, check it exited because killed.
	if err := buildCmd.Wait(); err != nil && !integration.IsKilled(err) {
		c.Fatalf("wait failed during build run: %T %s", err, err)
	}

	select {
	case <-time.After(10 * time.Second):
		observer.CheckEventError(c, buildID, "die", matcher)
	case <-testActions["die"]:
		// ignore, done
	}
}