diff --git a/api/client/events.go b/api/client/events.go index c2a6ab3bb1..fb3e6903bd 100644 --- a/api/client/events.go +++ b/api/client/events.go @@ -4,6 +4,7 @@ import ( "encoding/json" "fmt" "io" + "sort" "strings" "time" @@ -99,7 +100,13 @@ func printOutput(event eventtypes.Message, output io.Writer) { if len(event.Actor.Attributes) > 0 { var attrs []string - for k, v := range event.Actor.Attributes { + var keys []string + for k := range event.Actor.Attributes { + keys = append(keys, k) + } + sort.Strings(keys) + for _, k := range keys { + v := event.Actor.Attributes[k] attrs = append(attrs, fmt.Sprintf("%s=%s", k, v)) } fmt.Fprintf(output, " (%s)", strings.Join(attrs, ", ")) diff --git a/integration-cli/docker_cli_events_test.go b/integration-cli/docker_cli_events_test.go index 80ff40e92e..a559a54707 100644 --- a/integration-cli/docker_cli_events_test.go +++ b/integration-cli/docker_cli_events_test.go @@ -140,6 +140,33 @@ func (s *DockerSuite) TestEventsContainerEvents(c *check.C) { c.Assert(containerEvents[4], checker.Equals, "destroy", check.Commentf(out)) } +func (s *DockerSuite) TestEventsContainerEventsAttrSort(c *check.C) { + since := daemonTime(c).Unix() + containerID, _ := dockerCmd(c, "run", "-d", "--name", "container-events-test", "busybox", "true") + containerID = strings.TrimSpace(containerID) + + out, _ := dockerCmd(c, "events", fmt.Sprintf("--since=%d", since), fmt.Sprintf("--until=%d", daemonTime(c).Unix())) + events := strings.Split(out, "\n") + + nEvents := len(events) + c.Assert(nEvents, checker.GreaterOrEqualThan, 3) //Missing expected event + matchedEvents := 0 + for _, event := range events { + matches := parseEventText(event) + if matches["id"] != containerID { + continue + } + 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) +} + func (s *DockerSuite) TestEventsContainerEventsSinceUnixEpoch(c *check.C) { dockerCmd(c, "run", "--rm", "--name", "since-epoch-test", "busybox", "true") timeBeginning := time.Unix(0, 0).Format(time.RFC3339Nano)