func parseEvents(c *check.C, out, match string) { events := strings.Split(strings.TrimSpace(out), "\n") for _, event := range events { matches := eventstestutils.ScanMap(event) matched, err := regexp.MatchString(match, matches["action"]) c.Assert(err, checker.IsNil) c.Assert(matched, checker.True, check.Commentf("Matcher: %s did not match %s", match, matches["action"])) } }
// eventActionsByIDAndType returns the actions for a given id and type. // It fails if the text is not in the event format. func eventActionsByIDAndType(c *check.C, events []string, id, eventType string) []string { var filtered []string for _, event := range events { matches := eventstestutils.ScanMap(event) c.Assert(matches, checker.Not(checker.IsNil)) if matchIDAndEventType(matches, id, eventType) { filtered = append(filtered, matches["action"]) } } return filtered }
func (s *DockerSuite) TestEventsImageLoad(c *check.C) { testRequires(c, DaemonIsLinux) myImageName := "footest:v1" dockerCmd(c, "tag", "busybox", myImageName) since := daemonUnixTime(c) out, _ := dockerCmd(c, "images", "-q", "--no-trunc", myImageName) longImageID := strings.TrimSpace(out) c.Assert(longImageID, checker.Not(check.Equals), "", check.Commentf("Id should not be empty")) dockerCmd(c, "save", "-o", "saveimg.tar", myImageName) dockerCmd(c, "rmi", myImageName) out, _ = dockerCmd(c, "images", "-q", myImageName) noImageID := strings.TrimSpace(out) c.Assert(noImageID, checker.Equals, "", check.Commentf("Should not have any image")) dockerCmd(c, "load", "-i", "saveimg.tar") result := icmd.RunCommand("rm", "-rf", "saveimg.tar") c.Assert(result, icmd.Matches, icmd.Success) out, _ = dockerCmd(c, "images", "-q", "--no-trunc", myImageName) imageID := strings.TrimSpace(out) c.Assert(imageID, checker.Equals, longImageID, check.Commentf("Should have same image id as before")) out, _ = dockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c), "--filter", "event=load") events := strings.Split(strings.TrimSpace(out), "\n") c.Assert(events, checker.HasLen, 1) matches := eventstestutils.ScanMap(events[0]) c.Assert(matches["id"], checker.Equals, imageID, check.Commentf("matches: %v\nout:\n%s\n", matches, out)) c.Assert(matches["action"], checker.Equals, "load", check.Commentf("matches: %v\nout:\n%s\n", matches, out)) out, _ = dockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c), "--filter", "event=save") events = strings.Split(strings.TrimSpace(out), "\n") c.Assert(events, checker.HasLen, 1) matches = eventstestutils.ScanMap(events[0]) c.Assert(matches["id"], checker.Equals, imageID, check.Commentf("matches: %v\nout:\n%s\n", matches, out)) c.Assert(matches["action"], checker.Equals, "save", check.Commentf("matches: %v\nout:\n%s\n", matches, out)) }
// matchEventLine matches a text with the event regular expression. // It returns the matches and true if the regular expression matches with the given id and event type. // It returns an empty map and false if there is no match. func matchEventLine(id, eventType string, actions map[string]chan bool) eventMatcher { return func(text string) (map[string]string, bool) { matches := eventstestutils.ScanMap(text) if len(matches) == 0 { return matches, false } if matchIDAndEventType(matches, id, eventType) { if _, ok := actions[matches["action"]]; ok { return matches, true } } return matches, false } }
func (s *DockerSuite) TestEventsImageTag(c *check.C) { time.Sleep(1 * time.Second) // because API has seconds granularity since := daemonUnixTime(c) image := "testimageevents:tag" dockerCmd(c, "tag", "busybox", image) out, _ := dockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c)) events := strings.Split(strings.TrimSpace(out), "\n") c.Assert(events, checker.HasLen, 1, check.Commentf("was expecting 1 event. out=%s", out)) event := strings.TrimSpace(events[0]) matches := eventstestutils.ScanMap(event) c.Assert(matchEventID(matches, image), checker.True, check.Commentf("matches: %v\nout:\n%s", matches, out)) c.Assert(matches["action"], checker.Equals, "tag") }
func (s *DockerSuite) TestEventsImagePull(c *check.C) { // TODO Windows: Enable this test once pull and reliable image names are available testRequires(c, DaemonIsLinux) since := daemonUnixTime(c) testRequires(c, Network) dockerCmd(c, "pull", "hello-world") out, _ := dockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c)) events := strings.Split(strings.TrimSpace(out), "\n") event := strings.TrimSpace(events[len(events)-1]) matches := eventstestutils.ScanMap(event) c.Assert(matches["id"], checker.Equals, "hello-world:latest") c.Assert(matches["action"], checker.Equals, "pull") }
func (s *DockerSuite) TestEventsContainerEventsAttrSort(c *check.C) { since := daemonUnixTime(c) dockerCmd(c, "run", "--rm", "--name", "container-events-test", "busybox", "true") out, _ := dockerCmd(c, "events", "--filter", "container=container-events-test", "--since", since, "--until", daemonUnixTime(c)) events := strings.Split(out, "\n") nEvents := len(events) c.Assert(nEvents, checker.GreaterOrEqualThan, 3) //Missing expected event matchedEvents := 0 for _, event := range events { matches := eventstestutils.ScanMap(event) if matches["eventType"] == "container" && matches["action"] == "create" { matchedEvents++ c.Assert(out, checker.Contains, "(image=busybox, name=container-events-test)", check.Commentf("Event attributes not sorted")) } else if matches["eventType"] == "container" && matches["action"] == "start" { matchedEvents++ c.Assert(out, checker.Contains, "(image=busybox, name=container-events-test)", check.Commentf("Event attributes not sorted")) } } c.Assert(matchedEvents, checker.Equals, 2, check.Commentf("missing events for container container-events-test:\n%s", out)) }
func (s *DockerSuite) TestEventsImageImport(c *check.C) { // TODO Windows CI. This should be portable once export/import are // more reliable (@swernli) testRequires(c, DaemonIsLinux) out, _ := dockerCmd(c, "run", "-d", "busybox", "true") cleanedContainerID := strings.TrimSpace(out) since := daemonUnixTime(c) out, _, err := runCommandPipelineWithOutput( exec.Command(dockerBinary, "export", cleanedContainerID), exec.Command(dockerBinary, "import", "-"), ) c.Assert(err, checker.IsNil, check.Commentf("import failed with output: %q", out)) imageRef := strings.TrimSpace(out) out, _ = dockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c), "--filter", "event=import") events := strings.Split(strings.TrimSpace(out), "\n") c.Assert(events, checker.HasLen, 1) matches := eventstestutils.ScanMap(events[0]) c.Assert(matches["id"], checker.Equals, imageRef, check.Commentf("matches: %v\nout:\n%s\n", matches, out)) c.Assert(matches["action"], checker.Equals, "import", check.Commentf("matches: %v\nout:\n%s\n", matches, out)) }
func (s *DockerSuite) TestEventsFilterContainer(c *check.C) { since := daemonUnixTime(c) nameID := make(map[string]string) for _, name := range []string{"container_1", "container_2"} { dockerCmd(c, "run", "--name", name, "busybox", "true") id := inspectField(c, name, "Id") nameID[name] = id } until := daemonUnixTime(c) checkEvents := func(id string, events []string) error { if len(events) != 4 { // create, attach, start, die return fmt.Errorf("expected 4 events, got %v", events) } for _, event := range events { matches := eventstestutils.ScanMap(event) if !matchEventID(matches, id) { return fmt.Errorf("expected event for container id %s: %s - parsed container id: %s", id, event, matches["id"]) } } return nil } for name, ID := range nameID { // filter by names out, _ := dockerCmd(c, "events", "--since", since, "--until", until, "--filter", "container="+name) events := strings.Split(strings.TrimSuffix(out, "\n"), "\n") c.Assert(checkEvents(ID, events), checker.IsNil) // filter by ID's out, _ = dockerCmd(c, "events", "--since", since, "--until", until, "--filter", "container="+ID) events = strings.Split(strings.TrimSuffix(out, "\n"), "\n") c.Assert(checkEvents(ID, events), checker.IsNil) } }
// parseEventAction parses an event text and returns the action. // It fails if the text is not in the event format. func parseEventAction(c *check.C, text string) string { matches := eventstestutils.ScanMap(text) return matches["action"] }