func getHealth(c *check.C, name string) *types.Health { out, _ := dockerCmd(c, "inspect", "--format={{json .State.Health}}", name) var health types.Health err := json.Unmarshal([]byte(out), &health) c.Check(err, checker.Equals, nil) return &health }
func (s *StreamHandlerSuite) TestStreamUntilRemoved(c *check.C) { var l string var err error res := s.Get(c) c.Check(res.StatusCode, check.Equals, 200) r := bufio.NewReader(res.Body) // Write before rename s.Printf(c, "hello\n") // Read bytes written before rename l, err = r.ReadString('\n') c.Check(err, check.IsNil) c.Check(l, check.Equals, "hello\n") // Remove err = os.Remove(s.FileName) c.Assert(err, check.IsNil) // Read EOF l, err = r.ReadString('\n') // c.Check(err, check.Equals, io.ErrUnexpectedEOF) LINUX // c.Check(err, check.Equals, io.EOF) MAC c.Check(err, check.Not(check.IsNil)) c.Check(l, check.Equals, "") }
func (s *DockerSuite) TestInspectApiContainerResponse(c *check.C) { testRequires(c, DaemonIsLinux) out, _ := dockerCmd(c, "run", "-d", "busybox", "true") cleanedContainerID := strings.TrimSpace(out) keysBase := []string{"Id", "State", "Created", "Path", "Args", "Config", "Image", "NetworkSettings", "ResolvConfPath", "HostnamePath", "HostsPath", "LogPath", "Name", "Driver", "MountLabel", "ProcessLabel", "GraphDriver"} cases := []struct { version string keys []string }{ {"v1.20", append(keysBase, "Mounts")}, {"v1.19", append(keysBase, "Volumes", "VolumesRW")}, } for _, cs := range cases { body := getInspectBody(c, cs.version, cleanedContainerID) var inspectJSON map[string]interface{} err := json.Unmarshal(body, &inspectJSON) c.Assert(err, checker.IsNil, check.Commentf("Unable to unmarshal body for version %s", cs.version)) for _, key := range cs.keys { _, ok := inspectJSON[key] c.Check(ok, checker.True, check.Commentf("%s does not exist in response for version %s", key, cs.version)) } //Issue #6830: type not properly converted to JSON/back _, ok := inspectJSON["Path"].(bool) c.Assert(ok, checker.False, check.Commentf("Path of `true` should not be converted to boolean `true` via JSON marshalling")) } }
func (s *StreamHandlerSuite) TestStreamFlushesBeforeTailing(c *check.C) { s.Printf(c, "hello\n") f, err := os.Open(s.FileName) c.Assert(err, check.IsNil) _, err = f.Seek(3, os.SEEK_SET) c.Assert(err, check.IsNil) h := s.BuildHandler(f) res := s.GetFromHandler(c, h) c.Check(res.StatusCode, check.Equals, 200) r := bufio.NewReader(res.Body) l, err := r.ReadString('\n') c.Check(err, check.IsNil) c.Check(l, check.Equals, "lo\n") s.Printf(c, "world\n") l, err = r.ReadString('\n') c.Check(err, check.IsNil) c.Check(l, check.Equals, "world\n") }
func (s *DockerSuite) TestClientSetsTLSServerName(c *check.C) { c.Skip("Flakey test") // there may be more than one hit to the server for each registry request serverNameReceived := []string{} var serverName string virtualHostServer := httptest.NewTLSServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { serverNameReceived = append(serverNameReceived, r.TLS.ServerName) })) defer virtualHostServer.Close() // discard TLS handshake errors written by default to os.Stderr virtualHostServer.Config.ErrorLog = log.New(ioutil.Discard, "", 0) u, err := url.Parse(virtualHostServer.URL) c.Assert(err, check.IsNil) hostPort := u.Host serverName = strings.Split(hostPort, ":")[0] repoName := fmt.Sprintf("%v/dockercli/image:latest", hostPort) cmd := exec.Command(dockerBinary, "pull", repoName) cmd.Run() // check that the fake server was hit at least once c.Assert(len(serverNameReceived) > 0, check.Equals, true) // check that for each hit the right server name was received for _, item := range serverNameReceived { c.Check(item, check.Equals, serverName) } }
func (s *DockerCmdSuite) TestDockerCmdSuccess(c *check.C) { // Run error suite, should fail. output := String{} result := check.Run(&dockerCmdSuccessSuite{}, &check.RunConf{Output: &output}) c.Check(result.Succeeded, check.Equals, 1) c.Check(result.Failed, check.Equals, 0) }
func (s *DirectoryServerSuite) TestHandler_ServeHTTP_StreamFileFromOffsetLargerThanFile(t *check.C) { response, body := fetchStreamingResponse(t, "/path?tail=&tail_offset=1000000") t.Check(response.StatusCode, check.Equals, 200) trimmed_body := strings.Trim(body, string(0)) t.Check(len(trimmed_body), check.Equals, 0) }
func (s *StreamHandlerSuite) TestStreamUntilRenamed(c *check.C) { var l string var err error res := s.Get(c) c.Check(res.StatusCode, check.Equals, 200) r := bufio.NewReader(res.Body) // Write before rename s.Printf(c, "hello\n") // Read bytes written before rename l, err = r.ReadString('\n') c.Check(err, check.IsNil) c.Check(l, check.Equals, "hello\n") // Rename y := s.TempFileName(c) err = os.Rename(s.FileName, y) c.Assert(err, check.IsNil) // Read EOF l, err = r.ReadString('\n') c.Check(err, check.Equals, io.EOF) c.Check(l, check.Equals, "") }
// start a service, and then make its task unhealthy during running // finally, unhealthy task should be detected and killed func (s *DockerSwarmSuite) TestServiceHealthRun(c *check.C) { testRequires(c, DaemonIsLinux) // busybox doesn't work on Windows d := s.AddDaemon(c, true, true) // build image with health-check // note: use `daemon.buildImageWithOut` to build, do not use `buildImage` to build imageName := "testhealth" _, _, err := d.BuildImageWithOut(imageName, `FROM busybox RUN touch /status HEALTHCHECK --interval=1s --timeout=1s --retries=1\ CMD cat /status`, true) c.Check(err, check.IsNil) serviceName := "healthServiceRun" out, err := d.Cmd("service", "create", "--name", serviceName, imageName, "top") c.Assert(err, checker.IsNil, check.Commentf(out)) id := strings.TrimSpace(out) var tasks []swarm.Task waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) { tasks = d.GetServiceTasks(c, id) return tasks, nil }, checker.HasLen, 1) task := tasks[0] // wait for task to start waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) { task = d.GetTask(c, task.ID) return task.Status.State, nil }, checker.Equals, swarm.TaskStateRunning) containerID := task.Status.ContainerStatus.ContainerID // wait for container to be healthy waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) { out, _ := d.Cmd("inspect", "--format={{.State.Health.Status}}", containerID) return strings.TrimSpace(out), nil }, checker.Equals, "healthy") // make it fail d.Cmd("exec", containerID, "rm", "/status") // wait for container to be unhealthy waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) { out, _ := d.Cmd("inspect", "--format={{.State.Health.Status}}", containerID) return strings.TrimSpace(out), nil }, checker.Equals, "unhealthy") // Task should be terminated waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) { task = d.GetTask(c, task.ID) return task.Status.State, nil }, checker.Equals, swarm.TaskStateFailed) if !strings.Contains(task.Status.Err, container.ErrContainerUnhealthy.Error()) { c.Fatal("unhealthy task exits because of other error") } }
func (s *DeaClientSuite) TestDeaNotStarted(c *check.C) { s.StartDea(http.NotFoundHandler()) s.StopDea() r := s.Get("/") c.Check(r.StatusCode, check.Equals, http.StatusInternalServerError) c.Check(readBody(r), check.Matches, ".*unreachable") }
// start a service whose task is unhealthy at beginning // its tasks should be blocked in starting stage, until health check is passed func (s *DockerSwarmSuite) TestServiceHealthStart(c *check.C) { testRequires(c, DaemonIsLinux) // busybox doesn't work on Windows d := s.AddDaemon(c, true, true) // service started from this image won't pass health check imageName := "testhealth" _, _, err := d.BuildImageWithOut(imageName, `FROM busybox HEALTHCHECK --interval=1s --timeout=1s --retries=1024\ CMD cat /status`, true) c.Check(err, check.IsNil) serviceName := "healthServiceStart" out, err := d.Cmd("service", "create", "--name", serviceName, imageName, "top") c.Assert(err, checker.IsNil, check.Commentf(out)) id := strings.TrimSpace(out) var tasks []swarm.Task waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) { tasks = d.GetServiceTasks(c, id) return tasks, nil }, checker.HasLen, 1) task := tasks[0] // wait for task to start waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) { task = d.GetTask(c, task.ID) return task.Status.State, nil }, checker.Equals, swarm.TaskStateStarting) containerID := task.Status.ContainerStatus.ContainerID // wait for health check to work waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) { out, _ := d.Cmd("inspect", "--format={{.State.Health.FailingStreak}}", containerID) failingStreak, _ := strconv.Atoi(strings.TrimSpace(out)) return failingStreak, nil }, checker.GreaterThan, 0) // task should be blocked at starting status task = d.GetTask(c, task.ID) c.Assert(task.Status.State, check.Equals, swarm.TaskStateStarting) // make it healthy d.Cmd("exec", containerID, "touch", "/status") // Task should be at running status waitAndAssert(c, defaultReconciliationTimeout, func(c *check.C) (interface{}, check.CommentInterface) { task = d.GetTask(c, task.ID) return task.Status.State, nil }, checker.Equals, swarm.TaskStateRunning) }
func (s *MaxLatencyWriterSuite) TestWrite(c *check.C) { x := &testWriteFlusher{} y := NewMaxLatencyWriter(x, 10*time.Millisecond) c.Check(x.WriteCounter, check.Equals, 0) y.Write([]byte("x")) c.Check(x.WriteCounter, check.Equals, 1) y.Stop() }
func (s *DeaClientSuite) TestDeaStatusInternalServerError(c *check.C) { f := func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusInternalServerError) fmt.Fprintln(w, `internal server error`) } s.StartDea(http.HandlerFunc(f)) r := s.Get("/") c.Check(r.StatusCode, check.Equals, http.StatusInternalServerError) c.Check(readBody(r), check.Matches, "internal server error") }
func (s *DeaClientSuite) TestDeaStatusOK(c *check.C) { f := func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) fmt.Fprintln(w, `{ "instance_path": "/tmp/fuz" }`) } s.StartDea(http.HandlerFunc(f)) r := s.Get("/") c.Check(r.StatusCode, check.Equals, http.StatusOK) c.Check(readBody(r), check.Equals, "/tmp/fuz") }
func (s *DeaClientSuite) TestDeaInvalidJsonField(c *check.C) { f := func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) fmt.Fprintln(w, `{ "other_instance_path": "/tmp/fuz" }`) } s.StartDea(http.HandlerFunc(f)) r := s.Get("/") c.Check(r.StatusCode, check.Equals, http.StatusInternalServerError) c.Check(readBody(r), check.Matches, ".*invalid JSON") }
func (s *DeaClientSuite) TestDeaRequestPath(c *check.C) { f := func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) fmt.Fprintf(w, `{ "instance_path": "%s" }`, r.URL.String()) } s.StartDea(http.HandlerFunc(f)) r := s.Get("/some/path/?query") c.Check(r.StatusCode, check.Equals, http.StatusOK) c.Check(readBody(r), check.Equals, "/some/path/?query") }
func (s *DeaClientSuite) TestDeaStatusInternalServerErrorHeader(c *check.C) { f := func(w http.ResponseWriter, r *http.Request) { w.Header().Set("X-Hello", "World") w.WriteHeader(http.StatusInternalServerError) } s.StartDea(http.HandlerFunc(f)) r := s.Get("/") c.Check(r.StatusCode, check.Equals, http.StatusInternalServerError) c.Check(r.Header.Get("X-Hello"), check.Equals, "World") }
func (s *MaxLatencyWriterSuite) TestStop(c *check.C) { x := &testWriteFlusher{} y := NewMaxLatencyWriter(x, 10*time.Millisecond) c.Check(x.FlushCounter, check.Equals, 0) y.Stop() time.Sleep(15 * time.Millisecond) c.Check(x.FlushCounter, check.Equals, 0) }
func waitForHealthStatus(c *check.C, name string, prev string, expected string) { prev = prev + "\n" expected = expected + "\n" for { out, _ := dockerCmd(c, "inspect", "--format={{.State.Health.Status}}", name) if out == expected { return } c.Check(out, checker.Equals, prev) if out != prev { return } time.Sleep(100 * time.Millisecond) } }
func (s *DirectoryServerSuite) TestHandler_ServeHTTP_StreamFileFromValidOffset(t *check.C) { response, body := fetchStreamingResponse(t, "/path?tail=&tail_offset=0") t.Check(response.StatusCode, check.Equals, 200) // Check transfer encoding. te := response.TransferEncoding if len(te) != 1 || te[0] != "chunked" { t.Fail() } matched, _ := regexp.MatchString("^blah0blah1blah2", body) if !matched { t.Fail() } }
// #17131, #17139, #17173 func (s *DockerSuite) TestInspectApiEmptyFieldsInConfigPre121(c *check.C) { out, _ := dockerCmd(c, "run", "-d", "busybox", "true") cleanedContainerID := strings.TrimSpace(out) cases := []string{"v1.19", "v1.20"} for _, version := range cases { body := getInspectBody(c, version, cleanedContainerID) var inspectJSON map[string]interface{} err := json.Unmarshal(body, &inspectJSON) c.Assert(err, checker.IsNil, check.Commentf("Unable to unmarshal body for version %s", version)) config, ok := inspectJSON["Config"] c.Assert(ok, checker.True, check.Commentf("Unable to find 'Config'")) cfg := config.(map[string]interface{}) for _, f := range []string{"MacAddress", "NetworkDisabled", "ExposedPorts"} { _, ok := cfg[f] c.Check(ok, checker.True, check.Commentf("Api version %s expected to include %s in 'Config'", version, f)) } } }
// TestPullFromCentralRegistry pulls an image from the central registry and verifies that the client // prints all expected output. func (s *DockerHubPullSuite) TestPullFromCentralRegistry(c *check.C) { testRequires(c, DaemonIsLinux) out := s.Cmd(c, "pull", "hello-world") defer deleteImages("hello-world") c.Assert(out, checker.Contains, "Using default tag: latest", check.Commentf("expected the 'latest' tag to be automatically assumed")) c.Assert(out, checker.Contains, "Pulling from library/hello-world", check.Commentf("expected the 'library/' prefix to be automatically assumed")) c.Assert(out, checker.Contains, "Downloaded newer image for hello-world:latest") matches := regexp.MustCompile(`Digest: (.+)\n`).FindAllStringSubmatch(out, -1) c.Assert(len(matches), checker.Equals, 1, check.Commentf("expected exactly one image digest in the output")) c.Assert(len(matches[0]), checker.Equals, 2, check.Commentf("unexpected number of submatches for the digest")) _, err := digest.ParseDigest(matches[0][1]) c.Check(err, checker.IsNil, check.Commentf("invalid digest %q in output", matches[0][1])) // We should have a single entry in images. img := strings.TrimSpace(s.Cmd(c, "images")) splitImg := strings.Split(img, "\n") c.Assert(splitImg, checker.HasLen, 2) c.Assert(splitImg[1], checker.Matches, `hello-world\s+latest.*?`, check.Commentf("invalid output for `docker images` (expected image and tag name")) }
func (s *StreamHandlerSuite) TestStream(c *check.C) { res := s.Get(c) c.Check(res.StatusCode, check.Equals, 200) // The header was already sent, now write something to the file s.Printf(c, "hello\n") r := bufio.NewReader(res.Body) l, err := r.ReadString('\n') c.Check(err, check.IsNil) c.Check(l, check.Equals, "hello\n") }
func (s *StreamHandlerSuite) TestStreamFromCurrentPosition(c *check.C) { s.Printf(c, "hello\n") res := s.Get(c) c.Check(res.StatusCode, check.Equals, 200) s.Printf(c, "world\n") r := bufio.NewReader(res.Body) l, err := r.ReadString('\n') c.Check(err, check.IsNil) c.Check(l, check.Equals, "world\n") }
func (s *StreamHandlerSuite) TestStreamWithIdleTimeout(c *check.C) { var l string var err error f := s.BuildFile(c) handler := &StreamHandler{ File: f, FlushInterval: 1 * time.Millisecond, IdleTimeout: 200 * time.Millisecond, } res := s.GetFromHandler(c, handler) c.Check(res.StatusCode, check.Equals, 200) r := bufio.NewReader(res.Body) // Write before timing out time.Sleep(15 * time.Millisecond) s.Printf(c, "hi there!\n") // Read the write l, _ = r.ReadString('\n') c.Check(l, check.Equals, "hi there!\n") // Write after timing out time.Sleep(250 * time.Millisecond) // Wait again to ensure the timeout logic is no longer in use time.Sleep(250 * time.Millisecond) s.Printf(c, "what?\n") // Read an unexepected EOF _, err = r.ReadString('\n') c.Check(err, check.Equals, io.ErrUnexpectedEOF) }
func (s *DockerSuite) TestHealth(c *check.C) { testRequires(c, DaemonIsLinux) // busybox doesn't work on Windows imageName := "testhealth" _, err := buildImage(imageName, `FROM busybox RUN echo OK > /status CMD ["/bin/sleep", "120"] STOPSIGNAL SIGKILL HEALTHCHECK --interval=1s --timeout=30s \ CMD cat /status`, true) c.Check(err, check.IsNil) // No health status before starting name := "test_health" dockerCmd(c, "create", "--name", name, imageName) out, _ := dockerCmd(c, "ps", "-a", "--format={{.Status}}") c.Check(out, checker.Equals, "Created\n") // Inspect the options out, _ = dockerCmd(c, "inspect", "--format=timeout={{.Config.Healthcheck.Timeout}} "+ "interval={{.Config.Healthcheck.Interval}} "+ "retries={{.Config.Healthcheck.Retries}} "+ "test={{.Config.Healthcheck.Test}}", name) c.Check(out, checker.Equals, "timeout=30s interval=1s retries=0 test=[CMD-SHELL cat /status]\n") // Start dockerCmd(c, "start", name) waitForHealthStatus(c, name, "starting", "healthy") // Make it fail dockerCmd(c, "exec", name, "rm", "/status") waitForHealthStatus(c, name, "healthy", "unhealthy") // Inspect the status out, _ = dockerCmd(c, "inspect", "--format={{.State.Health.Status}}", name) c.Check(out, checker.Equals, "unhealthy\n") // Make it healthy again dockerCmd(c, "exec", name, "touch", "/status") waitForHealthStatus(c, name, "unhealthy", "healthy") // Remove container dockerCmd(c, "rm", "-f", name) // Disable the check from the CLI out, _ = dockerCmd(c, "create", "--name=noh", "--no-healthcheck", imageName) out, _ = dockerCmd(c, "inspect", "--format={{.Config.Healthcheck.Test}}", "noh") c.Check(out, checker.Equals, "[NONE]\n") dockerCmd(c, "rm", "noh") // Disable the check with a new build _, err = buildImage("no_healthcheck", `FROM testhealth HEALTHCHECK NONE`, true) c.Check(err, check.IsNil) out, _ = dockerCmd(c, "inspect", "--format={{.ContainerConfig.Healthcheck.Test}}", "no_healthcheck") c.Check(out, checker.Equals, "[NONE]\n") // Enable the checks from the CLI _, _ = dockerCmd(c, "run", "-d", "--name=fatal_healthcheck", "--health-interval=0.5s", "--health-retries=3", "--health-cmd=cat /status", "no_healthcheck") waitForHealthStatus(c, "fatal_healthcheck", "starting", "healthy") health := getHealth(c, "fatal_healthcheck") c.Check(health.Status, checker.Equals, "healthy") c.Check(health.FailingStreak, checker.Equals, 0) last := health.Log[len(health.Log)-1] c.Check(last.ExitCode, checker.Equals, 0) c.Check(last.Output, checker.Equals, "OK\n") // Fail the check dockerCmd(c, "exec", "fatal_healthcheck", "rm", "/status") waitForHealthStatus(c, "fatal_healthcheck", "healthy", "unhealthy") failsStr, _ := dockerCmd(c, "inspect", "--format={{.State.Health.FailingStreak}}", "fatal_healthcheck") fails, err := strconv.Atoi(strings.TrimSpace(failsStr)) c.Check(err, check.IsNil) c.Check(fails >= 3, checker.Equals, true) dockerCmd(c, "rm", "-f", "fatal_healthcheck") // Check timeout // Note: if the interval is too small, it seems that Docker spends all its time running health // checks and never gets around to killing it. _, _ = dockerCmd(c, "run", "-d", "--name=test", "--health-interval=1s", "--health-cmd=sleep 5m", "--health-timeout=1ms", imageName) waitForHealthStatus(c, "test", "starting", "unhealthy") health = getHealth(c, "test") last = health.Log[len(health.Log)-1] c.Check(health.Status, checker.Equals, "unhealthy") c.Check(last.ExitCode, checker.Equals, -1) c.Check(last.Output, checker.Equals, "Health check exceeded timeout (1ms)") dockerCmd(c, "rm", "-f", "test") // Check JSON-format _, err = buildImage(imageName, `FROM busybox RUN echo OK > /status CMD ["/bin/sleep", "120"] STOPSIGNAL SIGKILL HEALTHCHECK --interval=1s --timeout=30s \ CMD ["cat", "/my status"]`, true) c.Check(err, check.IsNil) out, _ = dockerCmd(c, "inspect", "--format={{.Config.Healthcheck.Test}}", imageName) c.Check(out, checker.Equals, "[CMD cat /my status]\n") }
func (s *DirectoryServerSuite) TestHandler_ServeHTTP_StreamFileFromNegavtiveOffset(t *check.C) { response, body := fetchStreamingResponse(t, "/path?tail=&tail_offset=-1") t.Check(response.StatusCode, check.Equals, 500) t.Check(body, check.Matches, ".*Tail offset must be a positive integer.*") }
func (s *StreamHandlerSuite) TestStreamUntilRemoved(c *check.C) { var l string var err error // Create a second file in the same directory tbd := filepath.Join(filepath.Dir(s.FileName), "to_be_deleted") _, err = os.Create(tbd) c.Check(err, check.IsNil) res := s.Get(c) c.Check(res.StatusCode, check.Equals, 200) r := bufio.NewReader(res.Body) // Write before remove s.Printf(c, "hello\n") // Remove second file - this should not cause a fail err = os.Remove(tbd) c.Check(err, check.IsNil) // Read bytes written before remove l, err = r.ReadString('\n') c.Check(err, check.IsNil) c.Check(l, check.Equals, "hello\n") // Remove err = os.Remove(s.FileName) c.Assert(err, check.IsNil) // Read EOF l, err = r.ReadString('\n') c.Check(err, check.Not(check.IsNil)) c.Check(l, check.Equals, "") }
func (cs *ContainerdSuite) TestRestart(t *check.C) { bundleName := "busybox-top" if err := CreateBusyboxBundle(bundleName, []string{"top"}); err != nil { t.Fatal(err) } totalCtr := 10 for i := 0; i < totalCtr; i++ { containerID := fmt.Sprintf("top%d", i) c, err := cs.StartContainer(containerID, bundleName) if err != nil { t.Fatal(err) } e := c.GetNextEvent() t.Assert(*e, checker.Equals, types.Event{ Type: "start-container", Id: containerID, Status: 0, Pid: "", Timestamp: e.Timestamp, }) } // restart daemon gracefully (SIGINT) cs.RestartDaemon(false) // check that status is running containers, err := cs.ListRunningContainers() if err != nil { t.Fatal(err) } sortContainers(containers) t.Assert(len(containers), checker.Equals, totalCtr) for i := 0; i < totalCtr; i++ { t.Assert(containers[i].Id, checker.Equals, fmt.Sprintf("top%d", i)) t.Assert(containers[i].Status, checker.Equals, "running") } // Now kill daemon (SIGKILL) cs.StopDaemon(true) // Sleep a second to allow thevent e timestamp to change since // it's second based <-time.After(3 * time.Second) // Kill a couple of containers killedCtr := map[int]bool{4: true, 2: true} var f func(*types.Event) deathChans := make([]chan error, len(killedCtr)) deathChansIdx := 0 for i := range killedCtr { ch := make(chan error, 1) deathChans[deathChansIdx] = ch deathChansIdx++ syscall.Kill(int(containers[i].Pids[0]), syscall.SIGKILL) // Filter to be notified of their death containerID := fmt.Sprintf("top%d", i) f = func(event *types.Event) { expectedEvent := types.Event{ Type: "exit", Id: containerID, Status: 137, Pid: "init", } expectedEvent.Timestamp = event.Timestamp if ok := t.Check(*event, checker.Equals, expectedEvent); !ok { ch <- fmt.Errorf("Unexpected event: %#v", *event) } else { ch <- nil } } cs.SetContainerEventFilter(containerID, f) } cs.RestartDaemon(true) // Ensure we got our events for i := range deathChans { done := false for done == false { select { case err := <-deathChans[i]: t.Assert(err, checker.Equals, nil) done = true case <-time.After(3 * time.Second): t.Fatal("Exit event for container not received after 3 seconds") } } } // check that status is running containers, err = cs.ListRunningContainers() if err != nil { t.Fatal(err) } sortContainers(containers) t.Assert(len(containers), checker.Equals, totalCtr-len(killedCtr)) idShift := 0 for i := 0; i < totalCtr-len(killedCtr); i++ { if _, ok := killedCtr[i+idShift]; ok { idShift++ } t.Assert(containers[i].Id, checker.Equals, fmt.Sprintf("top%d", i+idShift)) t.Assert(containers[i].Status, checker.Equals, "running") } }