github.com/wozhu6104/docker@v20.10.10+incompatible/integration-cli/docker_cli_events_test.go (about)

     1  package main
     2  
     3  import (
     4  	"bufio"
     5  	"context"
     6  	"encoding/json"
     7  	"fmt"
     8  	"io"
     9  	"io/ioutil"
    10  	"os"
    11  	"os/exec"
    12  	"strconv"
    13  	"strings"
    14  	"testing"
    15  	"time"
    16  
    17  	"github.com/docker/docker/api/types"
    18  	eventtypes "github.com/docker/docker/api/types/events"
    19  	"github.com/docker/docker/client"
    20  	eventstestutils "github.com/docker/docker/daemon/events/testutils"
    21  	"github.com/docker/docker/integration-cli/cli"
    22  	"github.com/docker/docker/integration-cli/cli/build"
    23  	"gotest.tools/v3/assert"
    24  	is "gotest.tools/v3/assert/cmp"
    25  	"gotest.tools/v3/icmd"
    26  )
    27  
    28  func (s *DockerSuite) TestEventsTimestampFormats(c *testing.T) {
    29  	name := "events-time-format-test"
    30  
    31  	// Start stopwatch, generate an event
    32  	start := daemonTime(c)
    33  	time.Sleep(1100 * time.Millisecond) // so that first event occur in different second from since (just for the case)
    34  	dockerCmd(c, "run", "--rm", "--name", name, "busybox", "true")
    35  	time.Sleep(1100 * time.Millisecond) // so that until > since
    36  	end := daemonTime(c)
    37  
    38  	// List of available time formats to --since
    39  	unixTs := func(t time.Time) string { return fmt.Sprintf("%v", t.Unix()) }
    40  	rfc3339 := func(t time.Time) string { return t.Format(time.RFC3339) }
    41  	duration := func(t time.Time) string { return time.Since(t).String() }
    42  
    43  	// --since=$start must contain only the 'untag' event
    44  	for _, f := range []func(time.Time) string{unixTs, rfc3339, duration} {
    45  		since, until := f(start), f(end)
    46  		out, _ := dockerCmd(c, "events", "--since="+since, "--until="+until)
    47  		events := strings.Split(out, "\n")
    48  		events = events[:len(events)-1]
    49  
    50  		nEvents := len(events)
    51  		assert.Assert(c, nEvents >= 5)
    52  		containerEvents := eventActionsByIDAndType(c, events, name, "container")
    53  		assert.Assert(c, is.DeepEqual(containerEvents, []string{"create", "attach", "start", "die", "destroy"}), out)
    54  	}
    55  }
    56  
    57  func (s *DockerSuite) TestEventsUntag(c *testing.T) {
    58  	image := "busybox"
    59  	dockerCmd(c, "tag", image, "utest:tag1")
    60  	dockerCmd(c, "tag", image, "utest:tag2")
    61  	dockerCmd(c, "rmi", "utest:tag1")
    62  	dockerCmd(c, "rmi", "utest:tag2")
    63  
    64  	result := icmd.RunCmd(icmd.Cmd{
    65  		Command: []string{dockerBinary, "events", "--since=1"},
    66  		Timeout: time.Millisecond * 2500,
    67  	})
    68  	result.Assert(c, icmd.Expected{Timeout: true})
    69  
    70  	events := strings.Split(result.Stdout(), "\n")
    71  	nEvents := len(events)
    72  	// The last element after the split above will be an empty string, so we
    73  	// get the two elements before the last, which are the untags we're
    74  	// looking for.
    75  	for _, v := range events[nEvents-3 : nEvents-1] {
    76  		assert.Check(c, strings.Contains(v, "untag"), "event should be untag")
    77  	}
    78  }
    79  
    80  func (s *DockerSuite) TestEventsContainerEvents(c *testing.T) {
    81  	dockerCmd(c, "run", "--rm", "--name", "container-events-test", "busybox", "true")
    82  
    83  	out, _ := dockerCmd(c, "events", "--until", daemonUnixTime(c))
    84  	events := strings.Split(out, "\n")
    85  	events = events[:len(events)-1]
    86  
    87  	containerEvents := eventActionsByIDAndType(c, events, "container-events-test", "container")
    88  	if len(containerEvents) > 5 {
    89  		containerEvents = containerEvents[:5]
    90  	}
    91  	assert.Assert(c, is.DeepEqual(containerEvents, []string{"create", "attach", "start", "die", "destroy"}), out)
    92  }
    93  
    94  func (s *DockerSuite) TestEventsContainerEventsAttrSort(c *testing.T) {
    95  	since := daemonUnixTime(c)
    96  	dockerCmd(c, "run", "--rm", "--name", "container-events-test", "busybox", "true")
    97  
    98  	out, _ := dockerCmd(c, "events", "--filter", "container=container-events-test", "--since", since, "--until", daemonUnixTime(c))
    99  	events := strings.Split(out, "\n")
   100  
   101  	nEvents := len(events)
   102  	assert.Assert(c, nEvents >= 3)
   103  	matchedEvents := 0
   104  	for _, event := range events {
   105  		matches := eventstestutils.ScanMap(event)
   106  		if matches["eventType"] == "container" && matches["action"] == "create" {
   107  			matchedEvents++
   108  			assert.Check(c, strings.Contains(out, "(image=busybox, name=container-events-test)"), "Event attributes not sorted")
   109  
   110  		} else if matches["eventType"] == "container" && matches["action"] == "start" {
   111  			matchedEvents++
   112  			assert.Check(c, strings.Contains(out, "(image=busybox, name=container-events-test)"), "Event attributes not sorted")
   113  		}
   114  	}
   115  	assert.Equal(c, matchedEvents, 2, "missing events for container container-events-test:\n%s", out)
   116  }
   117  
   118  func (s *DockerSuite) TestEventsContainerEventsSinceUnixEpoch(c *testing.T) {
   119  	dockerCmd(c, "run", "--rm", "--name", "since-epoch-test", "busybox", "true")
   120  	timeBeginning := time.Unix(0, 0).Format(time.RFC3339Nano)
   121  	timeBeginning = strings.Replace(timeBeginning, "Z", ".000000000Z", -1)
   122  	out, _ := dockerCmd(c, "events", "--since", timeBeginning, "--until", daemonUnixTime(c))
   123  	events := strings.Split(out, "\n")
   124  	events = events[:len(events)-1]
   125  
   126  	nEvents := len(events)
   127  	assert.Assert(c, nEvents >= 5)
   128  	containerEvents := eventActionsByIDAndType(c, events, "since-epoch-test", "container")
   129  	assert.Assert(c, is.DeepEqual(containerEvents, []string{"create", "attach", "start", "die", "destroy"}), out)
   130  }
   131  
   132  func (s *DockerSuite) TestEventsImageTag(c *testing.T) {
   133  	time.Sleep(1 * time.Second) // because API has seconds granularity
   134  	since := daemonUnixTime(c)
   135  	image := "testimageevents:tag"
   136  	dockerCmd(c, "tag", "busybox", image)
   137  
   138  	out, _ := dockerCmd(c, "events",
   139  		"--since", since, "--until", daemonUnixTime(c))
   140  
   141  	events := strings.Split(strings.TrimSpace(out), "\n")
   142  	assert.Equal(c, len(events), 1, "was expecting 1 event. out=%s", out)
   143  	event := strings.TrimSpace(events[0])
   144  
   145  	matches := eventstestutils.ScanMap(event)
   146  	assert.Assert(c, matchEventID(matches, image), "matches: %v\nout:\n%s", matches, out)
   147  	assert.Equal(c, matches["action"], "tag")
   148  }
   149  
   150  func (s *DockerSuite) TestEventsImagePull(c *testing.T) {
   151  	// TODO Windows: Enable this test once pull and reliable image names are available
   152  	testRequires(c, DaemonIsLinux)
   153  	since := daemonUnixTime(c)
   154  	testRequires(c, Network)
   155  
   156  	dockerCmd(c, "pull", "hello-world")
   157  
   158  	out, _ := dockerCmd(c, "events",
   159  		"--since", since, "--until", daemonUnixTime(c))
   160  
   161  	events := strings.Split(strings.TrimSpace(out), "\n")
   162  	event := strings.TrimSpace(events[len(events)-1])
   163  	matches := eventstestutils.ScanMap(event)
   164  	assert.Equal(c, matches["id"], "hello-world:latest")
   165  	assert.Equal(c, matches["action"], "pull")
   166  }
   167  
   168  func (s *DockerSuite) TestEventsImageImport(c *testing.T) {
   169  	// TODO Windows CI. This should be portable once export/import are
   170  	// more reliable (@swernli)
   171  	testRequires(c, DaemonIsLinux)
   172  
   173  	out, _ := dockerCmd(c, "run", "-d", "busybox", "true")
   174  	cleanedContainerID := strings.TrimSpace(out)
   175  
   176  	since := daemonUnixTime(c)
   177  	out, err := RunCommandPipelineWithOutput(
   178  		exec.Command(dockerBinary, "export", cleanedContainerID),
   179  		exec.Command(dockerBinary, "import", "-"),
   180  	)
   181  	assert.NilError(c, err, "import failed with output: %q", out)
   182  	imageRef := strings.TrimSpace(out)
   183  
   184  	out, _ = dockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c), "--filter", "event=import")
   185  	events := strings.Split(strings.TrimSpace(out), "\n")
   186  	assert.Equal(c, len(events), 1)
   187  	matches := eventstestutils.ScanMap(events[0])
   188  	assert.Equal(c, matches["id"], imageRef, "matches: %v\nout:\n%s\n", matches, out)
   189  	assert.Equal(c, matches["action"], "import", "matches: %v\nout:\n%s\n", matches, out)
   190  }
   191  
   192  func (s *DockerSuite) TestEventsImageLoad(c *testing.T) {
   193  	testRequires(c, DaemonIsLinux)
   194  	myImageName := "footest:v1"
   195  	dockerCmd(c, "tag", "busybox", myImageName)
   196  	since := daemonUnixTime(c)
   197  
   198  	out, _ := dockerCmd(c, "images", "-q", "--no-trunc", myImageName)
   199  	longImageID := strings.TrimSpace(out)
   200  	assert.Assert(c, longImageID != "", "Id should not be empty")
   201  
   202  	dockerCmd(c, "save", "-o", "saveimg.tar", myImageName)
   203  	dockerCmd(c, "rmi", myImageName)
   204  	out, _ = dockerCmd(c, "images", "-q", myImageName)
   205  	noImageID := strings.TrimSpace(out)
   206  	assert.Equal(c, noImageID, "", "Should not have any image")
   207  	dockerCmd(c, "load", "-i", "saveimg.tar")
   208  
   209  	result := icmd.RunCommand("rm", "-rf", "saveimg.tar")
   210  	result.Assert(c, icmd.Success)
   211  
   212  	out, _ = dockerCmd(c, "images", "-q", "--no-trunc", myImageName)
   213  	imageID := strings.TrimSpace(out)
   214  	assert.Equal(c, imageID, longImageID, "Should have same image id as before")
   215  
   216  	out, _ = dockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c), "--filter", "event=load")
   217  	events := strings.Split(strings.TrimSpace(out), "\n")
   218  	assert.Equal(c, len(events), 1)
   219  	matches := eventstestutils.ScanMap(events[0])
   220  	assert.Equal(c, matches["id"], imageID, "matches: %v\nout:\n%s\n", matches, out)
   221  	assert.Equal(c, matches["action"], "load", "matches: %v\nout:\n%s\n", matches, out)
   222  
   223  	out, _ = dockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c), "--filter", "event=save")
   224  	events = strings.Split(strings.TrimSpace(out), "\n")
   225  	assert.Equal(c, len(events), 1)
   226  	matches = eventstestutils.ScanMap(events[0])
   227  	assert.Equal(c, matches["id"], imageID, "matches: %v\nout:\n%s\n", matches, out)
   228  	assert.Equal(c, matches["action"], "save", "matches: %v\nout:\n%s\n", matches, out)
   229  }
   230  
   231  func (s *DockerSuite) TestEventsPluginOps(c *testing.T) {
   232  	testRequires(c, DaemonIsLinux, IsAmd64, Network)
   233  
   234  	since := daemonUnixTime(c)
   235  
   236  	dockerCmd(c, "plugin", "install", pNameWithTag, "--grant-all-permissions")
   237  	dockerCmd(c, "plugin", "disable", pNameWithTag)
   238  	dockerCmd(c, "plugin", "remove", pNameWithTag)
   239  
   240  	out, _ := dockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c))
   241  	events := strings.Split(out, "\n")
   242  	events = events[:len(events)-1]
   243  
   244  	assert.Assert(c, len(events) >= 4)
   245  
   246  	pluginEvents := eventActionsByIDAndType(c, events, pNameWithTag, "plugin")
   247  	assert.Assert(c, is.DeepEqual(pluginEvents, []string{"pull", "enable", "disable", "remove"}), out)
   248  }
   249  
   250  func (s *DockerSuite) TestEventsFilters(c *testing.T) {
   251  	since := daemonUnixTime(c)
   252  	dockerCmd(c, "run", "--rm", "busybox", "true")
   253  	dockerCmd(c, "run", "--rm", "busybox", "true")
   254  	out, _ := dockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c), "--filter", "event=die")
   255  	parseEvents(c, out, "die")
   256  
   257  	out, _ = dockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c), "--filter", "event=die", "--filter", "event=start")
   258  	parseEvents(c, out, "die|start")
   259  
   260  	// make sure we at least got 2 start events
   261  	count := strings.Count(out, "start")
   262  	assert.Assert(c, count >= 2, "should have had 2 start events but had %d, out: %s", count, out)
   263  }
   264  
   265  func (s *DockerSuite) TestEventsFilterImageName(c *testing.T) {
   266  	since := daemonUnixTime(c)
   267  
   268  	out, _ := dockerCmd(c, "run", "--name", "container_1", "-d", "busybox:latest", "true")
   269  	container1 := strings.TrimSpace(out)
   270  
   271  	out, _ = dockerCmd(c, "run", "--name", "container_2", "-d", "busybox", "true")
   272  	container2 := strings.TrimSpace(out)
   273  
   274  	name := "busybox"
   275  	out, _ = dockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c), "--filter", fmt.Sprintf("image=%s", name))
   276  	events := strings.Split(out, "\n")
   277  	events = events[:len(events)-1]
   278  	assert.Assert(c, len(events) != 0, "Expected events but found none for the image busybox:latest")
   279  	count1 := 0
   280  	count2 := 0
   281  
   282  	for _, e := range events {
   283  		if strings.Contains(e, container1) {
   284  			count1++
   285  		} else if strings.Contains(e, container2) {
   286  			count2++
   287  		}
   288  	}
   289  	assert.Assert(c, count1 != 0, "Expected event from container but got %d from %s", count1, container1)
   290  	assert.Assert(c, count2 != 0, "Expected event from container but got %d from %s", count2, container2)
   291  }
   292  
   293  func (s *DockerSuite) TestEventsFilterLabels(c *testing.T) {
   294  	since := strconv.FormatUint(uint64(daemonTime(c).Unix()), 10)
   295  	label := "io.docker.testing=foo"
   296  
   297  	out, exit := dockerCmd(c, "create", "-l", label, "busybox")
   298  	assert.Equal(c, exit, 0)
   299  	container1 := strings.TrimSpace(out)
   300  
   301  	out, exit = dockerCmd(c, "create", "busybox")
   302  	assert.Equal(c, exit, 0)
   303  	container2 := strings.TrimSpace(out)
   304  
   305  	// fetch events with `--until`, so that the client detaches after a second
   306  	// instead of staying attached, waiting for more events to arrive.
   307  	out, _ = dockerCmd(
   308  		c,
   309  		"events",
   310  		"--since", since,
   311  		"--until", strconv.FormatUint(uint64(daemonTime(c).Add(time.Second).Unix()), 10),
   312  		"--filter", "label="+label,
   313  	)
   314  
   315  	events := strings.Split(strings.TrimSpace(out), "\n")
   316  	assert.Assert(c, len(events) > 0)
   317  
   318  	var found bool
   319  	for _, e := range events {
   320  		if strings.Contains(e, container1) {
   321  			found = true
   322  		}
   323  		assert.Assert(c, !strings.Contains(e, container2))
   324  	}
   325  	assert.Assert(c, found)
   326  }
   327  
   328  func (s *DockerSuite) TestEventsFilterImageLabels(c *testing.T) {
   329  	since := daemonUnixTime(c)
   330  	name := "labelfiltertest"
   331  	label := "io.docker.testing=image"
   332  
   333  	// Build a test image.
   334  	buildImageSuccessfully(c, name, build.WithDockerfile(fmt.Sprintf(`
   335  		FROM busybox:latest
   336  		LABEL %s`, label)))
   337  	dockerCmd(c, "tag", name, "labelfiltertest:tag1")
   338  	dockerCmd(c, "tag", name, "labelfiltertest:tag2")
   339  	dockerCmd(c, "tag", "busybox:latest", "labelfiltertest:tag3")
   340  
   341  	out, _ := dockerCmd(
   342  		c,
   343  		"events",
   344  		"--since", since,
   345  		"--until", daemonUnixTime(c),
   346  		"--filter", fmt.Sprintf("label=%s", label),
   347  		"--filter", "type=image")
   348  
   349  	events := strings.Split(strings.TrimSpace(out), "\n")
   350  
   351  	// 2 events from the "docker tag" command, another one is from "docker build"
   352  	assert.Equal(c, len(events), 3, "Events == %s", events)
   353  	for _, e := range events {
   354  		assert.Check(c, strings.Contains(e, "labelfiltertest"))
   355  	}
   356  }
   357  
   358  func (s *DockerSuite) TestEventsFilterContainer(c *testing.T) {
   359  	since := daemonUnixTime(c)
   360  	nameID := make(map[string]string)
   361  
   362  	for _, name := range []string{"container_1", "container_2"} {
   363  		dockerCmd(c, "run", "--name", name, "busybox", "true")
   364  		id := inspectField(c, name, "Id")
   365  		nameID[name] = id
   366  	}
   367  
   368  	until := daemonUnixTime(c)
   369  
   370  	checkEvents := func(id string, events []string) error {
   371  		if len(events) != 4 { // create, attach, start, die
   372  			return fmt.Errorf("expected 4 events, got %v", events)
   373  		}
   374  		for _, event := range events {
   375  			matches := eventstestutils.ScanMap(event)
   376  			if !matchEventID(matches, id) {
   377  				return fmt.Errorf("expected event for container id %s: %s - parsed container id: %s", id, event, matches["id"])
   378  			}
   379  		}
   380  		return nil
   381  	}
   382  
   383  	for name, ID := range nameID {
   384  		// filter by names
   385  		out, _ := dockerCmd(c, "events", "--since", since, "--until", until, "--filter", "container="+name)
   386  		events := strings.Split(strings.TrimSuffix(out, "\n"), "\n")
   387  		assert.NilError(c, checkEvents(ID, events))
   388  
   389  		// filter by ID's
   390  		out, _ = dockerCmd(c, "events", "--since", since, "--until", until, "--filter", "container="+ID)
   391  		events = strings.Split(strings.TrimSuffix(out, "\n"), "\n")
   392  		assert.NilError(c, checkEvents(ID, events))
   393  	}
   394  }
   395  
   396  func (s *DockerSuite) TestEventsCommit(c *testing.T) {
   397  	// Problematic on Windows as cannot commit a running container
   398  	testRequires(c, DaemonIsLinux)
   399  
   400  	out := runSleepingContainer(c)
   401  	cID := strings.TrimSpace(out)
   402  	cli.WaitRun(c, cID)
   403  
   404  	cli.DockerCmd(c, "commit", "-m", "test", cID)
   405  	cli.DockerCmd(c, "stop", cID)
   406  	cli.WaitExited(c, cID, 5*time.Second)
   407  
   408  	until := daemonUnixTime(c)
   409  	out = cli.DockerCmd(c, "events", "-f", "container="+cID, "--until="+until).Combined()
   410  	assert.Assert(c, strings.Contains(out, "commit"), "Missing 'commit' log event")
   411  }
   412  
   413  func (s *DockerSuite) TestEventsCopy(c *testing.T) {
   414  	// Build a test image.
   415  	buildImageSuccessfully(c, "cpimg", build.WithDockerfile(`
   416  		  FROM busybox
   417  		  RUN echo HI > /file`))
   418  	id := getIDByName(c, "cpimg")
   419  
   420  	// Create an empty test file.
   421  	tempFile, err := ioutil.TempFile("", "test-events-copy-")
   422  	assert.NilError(c, err)
   423  	defer os.Remove(tempFile.Name())
   424  
   425  	assert.NilError(c, tempFile.Close())
   426  
   427  	dockerCmd(c, "create", "--name=cptest", id)
   428  
   429  	dockerCmd(c, "cp", "cptest:/file", tempFile.Name())
   430  
   431  	until := daemonUnixTime(c)
   432  	out, _ := dockerCmd(c, "events", "--since=0", "-f", "container=cptest", "--until="+until)
   433  	assert.Assert(c, strings.Contains(out, "archive-path"), "Missing 'archive-path' log event")
   434  
   435  	dockerCmd(c, "cp", tempFile.Name(), "cptest:/filecopy")
   436  
   437  	until = daemonUnixTime(c)
   438  	out, _ = dockerCmd(c, "events", "-f", "container=cptest", "--until="+until)
   439  	assert.Assert(c, strings.Contains(out, "extract-to-dir"), "Missing 'extract-to-dir' log event")
   440  }
   441  
   442  func (s *DockerSuite) TestEventsResize(c *testing.T) {
   443  	out := runSleepingContainer(c, "-d")
   444  	cID := strings.TrimSpace(out)
   445  	assert.NilError(c, waitRun(cID))
   446  
   447  	cli, err := client.NewClientWithOpts(client.FromEnv)
   448  	assert.NilError(c, err)
   449  	defer cli.Close()
   450  
   451  	options := types.ResizeOptions{
   452  		Height: 80,
   453  		Width:  24,
   454  	}
   455  	err = cli.ContainerResize(context.Background(), cID, options)
   456  	assert.NilError(c, err)
   457  
   458  	dockerCmd(c, "stop", cID)
   459  
   460  	until := daemonUnixTime(c)
   461  	out, _ = dockerCmd(c, "events", "-f", "container="+cID, "--until="+until)
   462  	assert.Assert(c, strings.Contains(out, "resize"), "Missing 'resize' log event")
   463  }
   464  
   465  func (s *DockerSuite) TestEventsAttach(c *testing.T) {
   466  	// TODO Windows CI: Figure out why this test fails intermittently (TP5).
   467  	testRequires(c, DaemonIsLinux)
   468  
   469  	out := cli.DockerCmd(c, "run", "-di", "busybox", "cat").Combined()
   470  	cID := strings.TrimSpace(out)
   471  	cli.WaitRun(c, cID)
   472  
   473  	cmd := exec.Command(dockerBinary, "attach", cID)
   474  	stdin, err := cmd.StdinPipe()
   475  	assert.NilError(c, err)
   476  	defer stdin.Close()
   477  	stdout, err := cmd.StdoutPipe()
   478  	assert.NilError(c, err)
   479  	defer stdout.Close()
   480  	assert.NilError(c, cmd.Start())
   481  	defer func() {
   482  		cmd.Process.Kill()
   483  		cmd.Wait()
   484  	}()
   485  
   486  	// Make sure we're done attaching by writing/reading some stuff
   487  	_, err = stdin.Write([]byte("hello\n"))
   488  	assert.NilError(c, err)
   489  	out, err = bufio.NewReader(stdout).ReadString('\n')
   490  	assert.NilError(c, err)
   491  	assert.Equal(c, strings.TrimSpace(out), "hello")
   492  
   493  	assert.NilError(c, stdin.Close())
   494  
   495  	cli.DockerCmd(c, "kill", cID)
   496  	cli.WaitExited(c, cID, 5*time.Second)
   497  
   498  	until := daemonUnixTime(c)
   499  	out = cli.DockerCmd(c, "events", "-f", "container="+cID, "--until="+until).Combined()
   500  	assert.Assert(c, strings.Contains(out, "attach"), "Missing 'attach' log event")
   501  }
   502  
   503  func (s *DockerSuite) TestEventsRename(c *testing.T) {
   504  	out, _ := dockerCmd(c, "run", "--name", "oldName", "busybox", "true")
   505  	cID := strings.TrimSpace(out)
   506  	dockerCmd(c, "rename", "oldName", "newName")
   507  
   508  	until := daemonUnixTime(c)
   509  	// filter by the container id because the name in the event will be the new name.
   510  	out, _ = dockerCmd(c, "events", "-f", "container="+cID, "--until", until)
   511  	assert.Assert(c, strings.Contains(out, "rename"), "Missing 'rename' log event")
   512  }
   513  
   514  func (s *DockerSuite) TestEventsTop(c *testing.T) {
   515  	// Problematic on Windows as Windows does not support top
   516  	testRequires(c, DaemonIsLinux)
   517  
   518  	out := runSleepingContainer(c, "-d")
   519  	cID := strings.TrimSpace(out)
   520  	assert.NilError(c, waitRun(cID))
   521  
   522  	dockerCmd(c, "top", cID)
   523  	dockerCmd(c, "stop", cID)
   524  
   525  	until := daemonUnixTime(c)
   526  	out, _ = dockerCmd(c, "events", "-f", "container="+cID, "--until="+until)
   527  	assert.Assert(c, strings.Contains(out, "top"), "Missing 'top' log event")
   528  }
   529  
   530  // #14316
   531  func (s *DockerRegistrySuite) TestEventsImageFilterPush(c *testing.T) {
   532  	// Problematic to port for Windows CI during TP5 timeframe until
   533  	// supporting push
   534  	testRequires(c, DaemonIsLinux)
   535  	testRequires(c, Network)
   536  	repoName := fmt.Sprintf("%v/dockercli/testf", privateRegistryURL)
   537  
   538  	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
   539  	cID := strings.TrimSpace(out)
   540  	assert.NilError(c, waitRun(cID))
   541  
   542  	dockerCmd(c, "commit", cID, repoName)
   543  	dockerCmd(c, "stop", cID)
   544  	dockerCmd(c, "push", repoName)
   545  
   546  	until := daemonUnixTime(c)
   547  	out, _ = dockerCmd(c, "events", "-f", "image="+repoName, "-f", "event=push", "--until", until)
   548  	assert.Assert(c, strings.Contains(out, repoName), "Missing 'push' log event for %s", repoName)
   549  }
   550  
   551  func (s *DockerSuite) TestEventsFilterType(c *testing.T) {
   552  	// FIXME(vdemeester) fails on e2e run
   553  	testRequires(c, testEnv.IsLocalDaemon)
   554  	since := daemonUnixTime(c)
   555  	name := "labelfiltertest"
   556  	label := "io.docker.testing=image"
   557  
   558  	// Build a test image.
   559  	buildImageSuccessfully(c, name, build.WithDockerfile(fmt.Sprintf(`
   560  		FROM busybox:latest
   561  		LABEL %s`, label)))
   562  	dockerCmd(c, "tag", name, "labelfiltertest:tag1")
   563  	dockerCmd(c, "tag", name, "labelfiltertest:tag2")
   564  	dockerCmd(c, "tag", "busybox:latest", "labelfiltertest:tag3")
   565  
   566  	out, _ := dockerCmd(
   567  		c,
   568  		"events",
   569  		"--since", since,
   570  		"--until", daemonUnixTime(c),
   571  		"--filter", fmt.Sprintf("label=%s", label),
   572  		"--filter", "type=image")
   573  
   574  	events := strings.Split(strings.TrimSpace(out), "\n")
   575  
   576  	// 2 events from the "docker tag" command, another one is from "docker build"
   577  	assert.Equal(c, len(events), 3, "Events == %s", events)
   578  	for _, e := range events {
   579  		assert.Check(c, strings.Contains(e, "labelfiltertest"))
   580  	}
   581  
   582  	out, _ = dockerCmd(
   583  		c,
   584  		"events",
   585  		"--since", since,
   586  		"--until", daemonUnixTime(c),
   587  		"--filter", fmt.Sprintf("label=%s", label),
   588  		"--filter", "type=container")
   589  	events = strings.Split(strings.TrimSpace(out), "\n")
   590  
   591  	// Events generated by the container that builds the image
   592  	assert.Equal(c, len(events), 2, "Events == %s", events)
   593  
   594  	out, _ = dockerCmd(
   595  		c,
   596  		"events",
   597  		"--since", since,
   598  		"--until", daemonUnixTime(c),
   599  		"--filter", "type=network")
   600  	events = strings.Split(strings.TrimSpace(out), "\n")
   601  	assert.Assert(c, len(events) >= 1, "Events == %s", events)
   602  }
   603  
   604  // #25798
   605  func (s *DockerSuite) TestEventsSpecialFiltersWithExecCreate(c *testing.T) {
   606  	since := daemonUnixTime(c)
   607  	runSleepingContainer(c, "--name", "test-container", "-d")
   608  	waitRun("test-container")
   609  
   610  	dockerCmd(c, "exec", "test-container", "echo", "hello-world")
   611  
   612  	out, _ := dockerCmd(
   613  		c,
   614  		"events",
   615  		"--since", since,
   616  		"--until", daemonUnixTime(c),
   617  		"--filter",
   618  		"event='exec_create: echo hello-world'",
   619  	)
   620  
   621  	events := strings.Split(strings.TrimSpace(out), "\n")
   622  	assert.Equal(c, len(events), 1, out)
   623  
   624  	out, _ = dockerCmd(
   625  		c,
   626  		"events",
   627  		"--since", since,
   628  		"--until", daemonUnixTime(c),
   629  		"--filter",
   630  		"event=exec_create",
   631  	)
   632  	assert.Equal(c, len(events), 1, out)
   633  }
   634  
   635  func (s *DockerSuite) TestEventsFilterImageInContainerAction(c *testing.T) {
   636  	since := daemonUnixTime(c)
   637  	dockerCmd(c, "run", "--name", "test-container", "-d", "busybox", "true")
   638  	waitRun("test-container")
   639  
   640  	out, _ := dockerCmd(c, "events", "--filter", "image=busybox", "--since", since, "--until", daemonUnixTime(c))
   641  	events := strings.Split(strings.TrimSpace(out), "\n")
   642  	assert.Assert(c, len(events) > 1, out)
   643  }
   644  
   645  func (s *DockerSuite) TestEventsContainerRestart(c *testing.T) {
   646  	dockerCmd(c, "run", "-d", "--name=testEvent", "--restart=on-failure:3", "busybox", "false")
   647  
   648  	// wait until test2 is auto removed.
   649  	waitTime := 10 * time.Second
   650  	if testEnv.OSType == "windows" {
   651  		// Windows takes longer...
   652  		waitTime = 90 * time.Second
   653  	}
   654  
   655  	err := waitInspect("testEvent", "{{ .State.Restarting }} {{ .State.Running }}", "false false", waitTime)
   656  	assert.NilError(c, err)
   657  
   658  	var (
   659  		createCount int
   660  		startCount  int
   661  		dieCount    int
   662  	)
   663  	out, _ := dockerCmd(c, "events", "--since=0", "--until", daemonUnixTime(c), "-f", "container=testEvent")
   664  	events := strings.Split(strings.TrimSpace(out), "\n")
   665  
   666  	nEvents := len(events)
   667  	assert.Assert(c, nEvents >= 1)
   668  	actions := eventActionsByIDAndType(c, events, "testEvent", "container")
   669  
   670  	for _, a := range actions {
   671  		switch a {
   672  		case "create":
   673  			createCount++
   674  		case "start":
   675  			startCount++
   676  		case "die":
   677  			dieCount++
   678  		}
   679  	}
   680  	assert.Equal(c, createCount, 1, "testEvent should be created 1 times: %v", actions)
   681  	assert.Equal(c, startCount, 4, "testEvent should start 4 times: %v", actions)
   682  	assert.Equal(c, dieCount, 4, "testEvent should die 4 times: %v", actions)
   683  }
   684  
   685  func (s *DockerSuite) TestEventsSinceInTheFuture(c *testing.T) {
   686  	dockerCmd(c, "run", "--name", "test-container", "-d", "busybox", "true")
   687  	waitRun("test-container")
   688  
   689  	since := daemonTime(c)
   690  	until := since.Add(time.Duration(-24) * time.Hour)
   691  	out, _, err := dockerCmdWithError("events", "--filter", "image=busybox", "--since", parseEventTime(since), "--until", parseEventTime(until))
   692  
   693  	assert.ErrorContains(c, err, "")
   694  	assert.Assert(c, strings.Contains(out, "cannot be after `until`"))
   695  }
   696  
   697  func (s *DockerSuite) TestEventsUntilInThePast(c *testing.T) {
   698  	since := daemonUnixTime(c)
   699  
   700  	dockerCmd(c, "run", "--name", "test-container", "-d", "busybox", "true")
   701  	waitRun("test-container")
   702  
   703  	until := daemonUnixTime(c)
   704  
   705  	dockerCmd(c, "run", "--name", "test-container2", "-d", "busybox", "true")
   706  	waitRun("test-container2")
   707  
   708  	out, _ := dockerCmd(c, "events", "--filter", "image=busybox", "--since", since, "--until", until)
   709  
   710  	assert.Assert(c, !strings.Contains(out, "test-container2"))
   711  	assert.Assert(c, strings.Contains(out, "test-container"))
   712  }
   713  
   714  func (s *DockerSuite) TestEventsFormat(c *testing.T) {
   715  	since := daemonUnixTime(c)
   716  	dockerCmd(c, "run", "--rm", "busybox", "true")
   717  	dockerCmd(c, "run", "--rm", "busybox", "true")
   718  	out, _ := dockerCmd(c, "events", "--since", since, "--until", daemonUnixTime(c), "--format", "{{json .}}")
   719  	dec := json.NewDecoder(strings.NewReader(out))
   720  	// make sure we got 2 start events
   721  	startCount := 0
   722  	for {
   723  		var err error
   724  		var ev eventtypes.Message
   725  		if err = dec.Decode(&ev); err == io.EOF {
   726  			break
   727  		}
   728  		assert.NilError(c, err)
   729  		if ev.Status == "start" {
   730  			startCount++
   731  		}
   732  	}
   733  
   734  	assert.Equal(c, startCount, 2, "should have had 2 start events but had %d, out: %s", startCount, out)
   735  }
   736  
   737  func (s *DockerSuite) TestEventsFormatBadFunc(c *testing.T) {
   738  	// make sure it fails immediately, without receiving any event
   739  	result := dockerCmdWithResult("events", "--format", "{{badFuncString .}}")
   740  	result.Assert(c, icmd.Expected{
   741  		Error:    "exit status 64",
   742  		ExitCode: 64,
   743  		Err:      "Error parsing format: template: :1: function \"badFuncString\" not defined",
   744  	})
   745  }
   746  
   747  func (s *DockerSuite) TestEventsFormatBadField(c *testing.T) {
   748  	// make sure it fails immediately, without receiving any event
   749  	result := dockerCmdWithResult("events", "--format", "{{.badFieldString}}")
   750  	result.Assert(c, icmd.Expected{
   751  		Error:    "exit status 64",
   752  		ExitCode: 64,
   753  		Err:      "Error parsing format: template: :1:2: executing \"\" at <.badFieldString>: can't evaluate field badFieldString in type *events.Message",
   754  	})
   755  }