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