github.com/rsampaio/docker@v0.7.2-0.20150827203920-fdc73cc3fc31/integration-cli/docker_cli_events_test.go (about)

     1  package main
     2  
     3  import (
     4  	"bufio"
     5  	"fmt"
     6  	"io/ioutil"
     7  	"net/http"
     8  	"os"
     9  	"os/exec"
    10  	"regexp"
    11  	"strconv"
    12  	"strings"
    13  	"sync"
    14  	"time"
    15  
    16  	"github.com/go-check/check"
    17  )
    18  
    19  func (s *DockerSuite) TestEventsTimestampFormats(c *check.C) {
    20  	image := "busybox"
    21  
    22  	// Start stopwatch, generate an event
    23  	time.Sleep(1 * time.Second) // so that we don't grab events from previous test occured in the same second
    24  	start := daemonTime(c)
    25  	dockerCmd(c, "tag", image, "timestamptest:1")
    26  	dockerCmd(c, "rmi", "timestamptest:1")
    27  	time.Sleep(1 * time.Second) // so that until > since
    28  	end := daemonTime(c)
    29  
    30  	// List of available time formats to --since
    31  	unixTs := func(t time.Time) string { return fmt.Sprintf("%v", t.Unix()) }
    32  	rfc3339 := func(t time.Time) string { return t.Format(time.RFC3339) }
    33  	duration := func(t time.Time) string { return time.Now().Sub(t).String() }
    34  
    35  	// --since=$start must contain only the 'untag' event
    36  	for _, f := range []func(time.Time) string{unixTs, rfc3339, duration} {
    37  		since, until := f(start), f(end)
    38  		out, _ := dockerCmd(c, "events", "--since="+since, "--until="+until)
    39  		events := strings.Split(strings.TrimSpace(out), "\n")
    40  		if len(events) != 2 {
    41  			c.Fatalf("unexpected events, was expecting only 2 events tag/untag (since=%s, until=%s) out=%s", since, until, out)
    42  		}
    43  		if !strings.Contains(out, "untag") {
    44  			c.Fatalf("expected 'untag' event not found (since=%s, until=%s) out=%s", since, until, out)
    45  		}
    46  	}
    47  
    48  }
    49  
    50  func (s *DockerSuite) TestEventsUntag(c *check.C) {
    51  	image := "busybox"
    52  	dockerCmd(c, "tag", image, "utest:tag1")
    53  	dockerCmd(c, "tag", image, "utest:tag2")
    54  	dockerCmd(c, "rmi", "utest:tag1")
    55  	dockerCmd(c, "rmi", "utest:tag2")
    56  	eventsCmd := exec.Command(dockerBinary, "events", "--since=1")
    57  	out, exitCode, _, err := runCommandWithOutputForDuration(eventsCmd, time.Duration(time.Millisecond*200))
    58  	if exitCode != 0 || err != nil {
    59  		c.Fatalf("Failed to get events - exit code %d: %s", exitCode, err)
    60  	}
    61  	events := strings.Split(out, "\n")
    62  	nEvents := len(events)
    63  	// The last element after the split above will be an empty string, so we
    64  	// get the two elements before the last, which are the untags we're
    65  	// looking for.
    66  	for _, v := range events[nEvents-3 : nEvents-1] {
    67  		if !strings.Contains(v, "untag") {
    68  			c.Fatalf("event should be untag, not %#v", v)
    69  		}
    70  	}
    71  }
    72  
    73  func (s *DockerSuite) TestEventsContainerFailStartDie(c *check.C) {
    74  
    75  	out, _ := dockerCmd(c, "images", "-q")
    76  	image := strings.Split(out, "\n")[0]
    77  	if _, _, err := dockerCmdWithError("run", "--name", "testeventdie", image, "blerg"); err == nil {
    78  		c.Fatalf("Container run with command blerg should have failed, but it did not")
    79  	}
    80  
    81  	out, _ = dockerCmd(c, "events", "--since=0", fmt.Sprintf("--until=%d", daemonTime(c).Unix()))
    82  	events := strings.Split(out, "\n")
    83  	if len(events) <= 1 {
    84  		c.Fatalf("Missing expected event")
    85  	}
    86  
    87  	startEvent := strings.Fields(events[len(events)-3])
    88  	dieEvent := strings.Fields(events[len(events)-2])
    89  
    90  	if startEvent[len(startEvent)-1] != "start" {
    91  		c.Fatalf("event should be start, not %#v", startEvent)
    92  	}
    93  	if dieEvent[len(dieEvent)-1] != "die" {
    94  		c.Fatalf("event should be die, not %#v", dieEvent)
    95  	}
    96  
    97  }
    98  
    99  func (s *DockerSuite) TestEventsLimit(c *check.C) {
   100  
   101  	var waitGroup sync.WaitGroup
   102  	errChan := make(chan error, 17)
   103  
   104  	args := []string{"run", "--rm", "busybox", "true"}
   105  	for i := 0; i < 17; i++ {
   106  		waitGroup.Add(1)
   107  		go func() {
   108  			defer waitGroup.Done()
   109  			errChan <- exec.Command(dockerBinary, args...).Run()
   110  		}()
   111  	}
   112  
   113  	waitGroup.Wait()
   114  	close(errChan)
   115  
   116  	for err := range errChan {
   117  		if err != nil {
   118  			c.Fatalf("%q failed with error: %v", strings.Join(args, " "), err)
   119  		}
   120  	}
   121  
   122  	out, _ := dockerCmd(c, "events", "--since=0", fmt.Sprintf("--until=%d", daemonTime(c).Unix()))
   123  	events := strings.Split(out, "\n")
   124  	nEvents := len(events) - 1
   125  	if nEvents != 64 {
   126  		c.Fatalf("events should be limited to 64, but received %d", nEvents)
   127  	}
   128  }
   129  
   130  func (s *DockerSuite) TestEventsContainerEvents(c *check.C) {
   131  	dockerCmd(c, "run", "--rm", "busybox", "true")
   132  	out, _ := dockerCmd(c, "events", "--since=0", fmt.Sprintf("--until=%d", daemonTime(c).Unix()))
   133  	events := strings.Split(out, "\n")
   134  	events = events[:len(events)-1]
   135  	if len(events) < 5 {
   136  		c.Fatalf("Missing expected event")
   137  	}
   138  	createEvent := strings.Fields(events[len(events)-5])
   139  	attachEvent := strings.Fields(events[len(events)-4])
   140  	startEvent := strings.Fields(events[len(events)-3])
   141  	dieEvent := strings.Fields(events[len(events)-2])
   142  	destroyEvent := strings.Fields(events[len(events)-1])
   143  	if createEvent[len(createEvent)-1] != "create" {
   144  		c.Fatalf("event should be create, not %#v", createEvent)
   145  	}
   146  	if attachEvent[len(createEvent)-1] != "attach" {
   147  		c.Fatalf("event should be attach, not %#v", attachEvent)
   148  	}
   149  	if startEvent[len(startEvent)-1] != "start" {
   150  		c.Fatalf("event should be start, not %#v", startEvent)
   151  	}
   152  	if dieEvent[len(dieEvent)-1] != "die" {
   153  		c.Fatalf("event should be die, not %#v", dieEvent)
   154  	}
   155  	if destroyEvent[len(destroyEvent)-1] != "destroy" {
   156  		c.Fatalf("event should be destroy, not %#v", destroyEvent)
   157  	}
   158  
   159  }
   160  
   161  func (s *DockerSuite) TestEventsContainerEventsSinceUnixEpoch(c *check.C) {
   162  	dockerCmd(c, "run", "--rm", "busybox", "true")
   163  	timeBeginning := time.Unix(0, 0).Format(time.RFC3339Nano)
   164  	timeBeginning = strings.Replace(timeBeginning, "Z", ".000000000Z", -1)
   165  	out, _ := dockerCmd(c, "events", fmt.Sprintf("--since='%s'", timeBeginning),
   166  		fmt.Sprintf("--until=%d", daemonTime(c).Unix()))
   167  	events := strings.Split(out, "\n")
   168  	events = events[:len(events)-1]
   169  	if len(events) < 5 {
   170  		c.Fatalf("Missing expected event")
   171  	}
   172  	createEvent := strings.Fields(events[len(events)-5])
   173  	attachEvent := strings.Fields(events[len(events)-4])
   174  	startEvent := strings.Fields(events[len(events)-3])
   175  	dieEvent := strings.Fields(events[len(events)-2])
   176  	destroyEvent := strings.Fields(events[len(events)-1])
   177  	if createEvent[len(createEvent)-1] != "create" {
   178  		c.Fatalf("event should be create, not %#v", createEvent)
   179  	}
   180  	if attachEvent[len(attachEvent)-1] != "attach" {
   181  		c.Fatalf("event should be attach, not %#v", attachEvent)
   182  	}
   183  	if startEvent[len(startEvent)-1] != "start" {
   184  		c.Fatalf("event should be start, not %#v", startEvent)
   185  	}
   186  	if dieEvent[len(dieEvent)-1] != "die" {
   187  		c.Fatalf("event should be die, not %#v", dieEvent)
   188  	}
   189  	if destroyEvent[len(destroyEvent)-1] != "destroy" {
   190  		c.Fatalf("event should be destroy, not %#v", destroyEvent)
   191  	}
   192  
   193  }
   194  
   195  func (s *DockerSuite) TestEventsImageUntagDelete(c *check.C) {
   196  	name := "testimageevents"
   197  	_, err := buildImage(name,
   198  		`FROM scratch
   199  		MAINTAINER "docker"`,
   200  		true)
   201  	if err != nil {
   202  		c.Fatal(err)
   203  	}
   204  	if err := deleteImages(name); err != nil {
   205  		c.Fatal(err)
   206  	}
   207  	out, _ := dockerCmd(c, "events", "--since=0", fmt.Sprintf("--until=%d", daemonTime(c).Unix()))
   208  	events := strings.Split(out, "\n")
   209  
   210  	events = events[:len(events)-1]
   211  	if len(events) < 2 {
   212  		c.Fatalf("Missing expected event")
   213  	}
   214  	untagEvent := strings.Fields(events[len(events)-2])
   215  	deleteEvent := strings.Fields(events[len(events)-1])
   216  	if untagEvent[len(untagEvent)-1] != "untag" {
   217  		c.Fatalf("untag should be untag, not %#v", untagEvent)
   218  	}
   219  	if deleteEvent[len(deleteEvent)-1] != "delete" {
   220  		c.Fatalf("delete should be delete, not %#v", deleteEvent)
   221  	}
   222  }
   223  
   224  func (s *DockerSuite) TestEventsImageTag(c *check.C) {
   225  	time.Sleep(1 * time.Second) // because API has seconds granularity
   226  	since := daemonTime(c).Unix()
   227  	image := "testimageevents:tag"
   228  	dockerCmd(c, "tag", "busybox", image)
   229  
   230  	out, _ := dockerCmd(c, "events",
   231  		fmt.Sprintf("--since=%d", since),
   232  		fmt.Sprintf("--until=%d", daemonTime(c).Unix()))
   233  
   234  	events := strings.Split(strings.TrimSpace(out), "\n")
   235  	if len(events) != 1 {
   236  		c.Fatalf("was expecting 1 event. out=%s", out)
   237  	}
   238  	event := strings.TrimSpace(events[0])
   239  	expectedStr := image + ": tag"
   240  
   241  	if !strings.HasSuffix(event, expectedStr) {
   242  		c.Fatalf("wrong event format. expected='%s' got=%s", expectedStr, event)
   243  	}
   244  
   245  }
   246  
   247  func (s *DockerSuite) TestEventsImagePull(c *check.C) {
   248  	since := daemonTime(c).Unix()
   249  	testRequires(c, Network)
   250  
   251  	dockerCmd(c, "pull", "hello-world")
   252  
   253  	out, _ := dockerCmd(c, "events",
   254  		fmt.Sprintf("--since=%d", since),
   255  		fmt.Sprintf("--until=%d", daemonTime(c).Unix()))
   256  
   257  	events := strings.Split(strings.TrimSpace(out), "\n")
   258  	event := strings.TrimSpace(events[len(events)-1])
   259  
   260  	if !strings.HasSuffix(event, "hello-world:latest: pull") {
   261  		c.Fatalf("Missing pull event - got:%q", event)
   262  	}
   263  
   264  }
   265  
   266  func (s *DockerSuite) TestEventsImageImport(c *check.C) {
   267  	since := daemonTime(c).Unix()
   268  
   269  	id := make(chan string)
   270  	eventImport := make(chan struct{})
   271  	eventsCmd := exec.Command(dockerBinary, "events", "--since", strconv.FormatInt(since, 10))
   272  	stdout, err := eventsCmd.StdoutPipe()
   273  	if err != nil {
   274  		c.Fatal(err)
   275  	}
   276  	if err := eventsCmd.Start(); err != nil {
   277  		c.Fatal(err)
   278  	}
   279  	defer eventsCmd.Process.Kill()
   280  
   281  	go func() {
   282  		containerID := <-id
   283  
   284  		matchImport := regexp.MustCompile(containerID + `: import$`)
   285  		scanner := bufio.NewScanner(stdout)
   286  		for scanner.Scan() {
   287  			if matchImport.MatchString(scanner.Text()) {
   288  				close(eventImport)
   289  			}
   290  		}
   291  	}()
   292  
   293  	out, _ := dockerCmd(c, "run", "-d", "busybox", "true")
   294  	cleanedContainerID := strings.TrimSpace(out)
   295  
   296  	out, _, err = runCommandPipelineWithOutput(
   297  		exec.Command(dockerBinary, "export", cleanedContainerID),
   298  		exec.Command(dockerBinary, "import", "-"),
   299  	)
   300  	if err != nil {
   301  		c.Errorf("import failed with errors: %v, output: %q", err, out)
   302  	}
   303  	newContainerID := strings.TrimSpace(out)
   304  	id <- newContainerID
   305  
   306  	select {
   307  	case <-time.After(5 * time.Second):
   308  		c.Fatal("failed to observe image import in timely fashion")
   309  	case <-eventImport:
   310  		// ignore, done
   311  	}
   312  }
   313  
   314  func (s *DockerSuite) TestEventsFilters(c *check.C) {
   315  	parseEvents := func(out, match string) {
   316  		events := strings.Split(out, "\n")
   317  		events = events[:len(events)-1]
   318  		for _, event := range events {
   319  			eventFields := strings.Fields(event)
   320  			eventName := eventFields[len(eventFields)-1]
   321  			if ok, err := regexp.MatchString(match, eventName); err != nil || !ok {
   322  				c.Fatalf("event should match %s, got %#v, err: %v", match, eventFields, err)
   323  			}
   324  		}
   325  	}
   326  
   327  	since := daemonTime(c).Unix()
   328  	dockerCmd(c, "run", "--rm", "busybox", "true")
   329  	dockerCmd(c, "run", "--rm", "busybox", "true")
   330  	out, _ := dockerCmd(c, "events", fmt.Sprintf("--since=%d", since), fmt.Sprintf("--until=%d", daemonTime(c).Unix()), "--filter", "event=die")
   331  	parseEvents(out, "die")
   332  
   333  	out, _ = dockerCmd(c, "events", fmt.Sprintf("--since=%d", since), fmt.Sprintf("--until=%d", daemonTime(c).Unix()), "--filter", "event=die", "--filter", "event=start")
   334  	parseEvents(out, "((die)|(start))")
   335  
   336  	// make sure we at least got 2 start events
   337  	count := strings.Count(out, "start")
   338  	if count < 2 {
   339  		c.Fatalf("should have had 2 start events but had %d, out: %s", count, out)
   340  	}
   341  
   342  }
   343  
   344  func (s *DockerSuite) TestEventsFilterImageName(c *check.C) {
   345  	since := daemonTime(c).Unix()
   346  
   347  	out, _ := dockerCmd(c, "run", "--name", "container_1", "-d", "busybox:latest", "true")
   348  	container1 := strings.TrimSpace(out)
   349  
   350  	out, _ = dockerCmd(c, "run", "--name", "container_2", "-d", "busybox", "true")
   351  	container2 := strings.TrimSpace(out)
   352  
   353  	name := "busybox"
   354  	out, _ = dockerCmd(c, "events", fmt.Sprintf("--since=%d", since), fmt.Sprintf("--until=%d", daemonTime(c).Unix()), "--filter", fmt.Sprintf("image=%s", name))
   355  	events := strings.Split(out, "\n")
   356  	events = events[:len(events)-1]
   357  	if len(events) == 0 {
   358  		c.Fatalf("Expected events but found none for the image busybox:latest")
   359  	}
   360  	count1 := 0
   361  	count2 := 0
   362  
   363  	for _, e := range events {
   364  		if strings.Contains(e, container1) {
   365  			count1++
   366  		} else if strings.Contains(e, container2) {
   367  			count2++
   368  		}
   369  	}
   370  	if count1 == 0 || count2 == 0 {
   371  		c.Fatalf("Expected events from each container but got %d from %s and %d from %s", count1, container1, count2, container2)
   372  	}
   373  
   374  }
   375  
   376  func (s *DockerSuite) TestEventsFilterContainer(c *check.C) {
   377  	since := fmt.Sprintf("%d", daemonTime(c).Unix())
   378  	nameID := make(map[string]string)
   379  
   380  	for _, name := range []string{"container_1", "container_2"} {
   381  		dockerCmd(c, "run", "--name", name, "busybox", "true")
   382  		id, err := inspectField(name, "Id")
   383  		if err != nil {
   384  			c.Fatal(err)
   385  		}
   386  		nameID[name] = id
   387  	}
   388  
   389  	until := fmt.Sprintf("%d", daemonTime(c).Unix())
   390  
   391  	checkEvents := func(id string, events []string) error {
   392  		if len(events) != 4 { // create, attach, start, die
   393  			return fmt.Errorf("expected 3 events, got %v", events)
   394  		}
   395  		for _, event := range events {
   396  			e := strings.Fields(event)
   397  			if len(e) < 3 {
   398  				return fmt.Errorf("got malformed event: %s", event)
   399  			}
   400  
   401  			// Check the id
   402  			parsedID := strings.TrimSuffix(e[1], ":")
   403  			if parsedID != id {
   404  				return fmt.Errorf("expected event for container id %s: %s - parsed container id: %s", id, event, parsedID)
   405  			}
   406  		}
   407  		return nil
   408  	}
   409  
   410  	for name, ID := range nameID {
   411  		// filter by names
   412  		out, _ := dockerCmd(c, "events", "--since", since, "--until", until, "--filter", "container="+name)
   413  		events := strings.Split(strings.TrimSuffix(out, "\n"), "\n")
   414  		if err := checkEvents(ID, events); err != nil {
   415  			c.Fatal(err)
   416  		}
   417  
   418  		// filter by ID's
   419  		out, _ = dockerCmd(c, "events", "--since", since, "--until", until, "--filter", "container="+ID)
   420  		events = strings.Split(strings.TrimSuffix(out, "\n"), "\n")
   421  		if err := checkEvents(ID, events); err != nil {
   422  			c.Fatal(err)
   423  		}
   424  	}
   425  }
   426  
   427  func (s *DockerSuite) TestEventsStreaming(c *check.C) {
   428  	start := daemonTime(c).Unix()
   429  
   430  	id := make(chan string)
   431  	eventCreate := make(chan struct{})
   432  	eventStart := make(chan struct{})
   433  	eventDie := make(chan struct{})
   434  	eventDestroy := make(chan struct{})
   435  
   436  	eventsCmd := exec.Command(dockerBinary, "events", "--since", strconv.FormatInt(start, 10))
   437  	stdout, err := eventsCmd.StdoutPipe()
   438  	if err != nil {
   439  		c.Fatal(err)
   440  	}
   441  	if err := eventsCmd.Start(); err != nil {
   442  		c.Fatalf("failed to start 'docker events': %s", err)
   443  	}
   444  	defer eventsCmd.Process.Kill()
   445  
   446  	go func() {
   447  		containerID := <-id
   448  
   449  		matchCreate := regexp.MustCompile(containerID + `: \(from busybox:latest\) create$`)
   450  		matchStart := regexp.MustCompile(containerID + `: \(from busybox:latest\) start$`)
   451  		matchDie := regexp.MustCompile(containerID + `: \(from busybox:latest\) die$`)
   452  		matchDestroy := regexp.MustCompile(containerID + `: \(from busybox:latest\) destroy$`)
   453  
   454  		scanner := bufio.NewScanner(stdout)
   455  		for scanner.Scan() {
   456  			switch {
   457  			case matchCreate.MatchString(scanner.Text()):
   458  				close(eventCreate)
   459  			case matchStart.MatchString(scanner.Text()):
   460  				close(eventStart)
   461  			case matchDie.MatchString(scanner.Text()):
   462  				close(eventDie)
   463  			case matchDestroy.MatchString(scanner.Text()):
   464  				close(eventDestroy)
   465  			}
   466  		}
   467  	}()
   468  
   469  	out, _ := dockerCmd(c, "run", "-d", "busybox:latest", "true")
   470  	cleanedContainerID := strings.TrimSpace(out)
   471  	id <- cleanedContainerID
   472  
   473  	select {
   474  	case <-time.After(5 * time.Second):
   475  		c.Fatal("failed to observe container create in timely fashion")
   476  	case <-eventCreate:
   477  		// ignore, done
   478  	}
   479  
   480  	select {
   481  	case <-time.After(5 * time.Second):
   482  		c.Fatal("failed to observe container start in timely fashion")
   483  	case <-eventStart:
   484  		// ignore, done
   485  	}
   486  
   487  	select {
   488  	case <-time.After(5 * time.Second):
   489  		c.Fatal("failed to observe container die in timely fashion")
   490  	case <-eventDie:
   491  		// ignore, done
   492  	}
   493  
   494  	dockerCmd(c, "rm", cleanedContainerID)
   495  
   496  	select {
   497  	case <-time.After(5 * time.Second):
   498  		c.Fatal("failed to observe container destroy in timely fashion")
   499  	case <-eventDestroy:
   500  		// ignore, done
   501  	}
   502  }
   503  
   504  func (s *DockerSuite) TestEventsCommit(c *check.C) {
   505  	since := daemonTime(c).Unix()
   506  
   507  	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
   508  	cID := strings.TrimSpace(out)
   509  	c.Assert(waitRun(cID), check.IsNil)
   510  
   511  	dockerCmd(c, "commit", "-m", "test", cID)
   512  	dockerCmd(c, "stop", cID)
   513  
   514  	out, _ = dockerCmd(c, "events", "--since=0", "-f", "container="+cID, "--until="+strconv.Itoa(int(since)))
   515  	if !strings.Contains(out, " commit\n") {
   516  		c.Fatalf("Missing 'commit' log event\n%s", out)
   517  	}
   518  }
   519  
   520  func (s *DockerSuite) TestEventsCopy(c *check.C) {
   521  	since := daemonTime(c).Unix()
   522  
   523  	// Build a test image.
   524  	id, err := buildImage("cpimg", `
   525  		  FROM busybox
   526  		  RUN echo HI > /tmp/file`, true)
   527  	if err != nil {
   528  		c.Fatalf("Couldn't create image: %q", err)
   529  	}
   530  
   531  	// Create an empty test file.
   532  	tempFile, err := ioutil.TempFile("", "test-events-copy-")
   533  	if err != nil {
   534  		c.Fatal(err)
   535  	}
   536  	defer os.Remove(tempFile.Name())
   537  
   538  	if err := tempFile.Close(); err != nil {
   539  		c.Fatal(err)
   540  	}
   541  
   542  	dockerCmd(c, "create", "--name=cptest", id)
   543  
   544  	dockerCmd(c, "cp", "cptest:/tmp/file", tempFile.Name())
   545  
   546  	out, _ := dockerCmd(c, "events", "--since=0", "-f", "container=cptest", "--until="+strconv.Itoa(int(since)))
   547  	if !strings.Contains(out, " archive-path\n") {
   548  		c.Fatalf("Missing 'archive-path' log event\n%s", out)
   549  	}
   550  
   551  	dockerCmd(c, "cp", tempFile.Name(), "cptest:/tmp/filecopy")
   552  
   553  	out, _ = dockerCmd(c, "events", "--since=0", "-f", "container=cptest", "--until="+strconv.Itoa(int(since)))
   554  	if !strings.Contains(out, " extract-to-dir\n") {
   555  		c.Fatalf("Missing 'extract-to-dir' log event\n%s", out)
   556  	}
   557  }
   558  
   559  func (s *DockerSuite) TestEventsResize(c *check.C) {
   560  	since := daemonTime(c).Unix()
   561  
   562  	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
   563  	cID := strings.TrimSpace(out)
   564  	c.Assert(waitRun(cID), check.IsNil)
   565  
   566  	endpoint := "/containers/" + cID + "/resize?h=80&w=24"
   567  	status, _, err := sockRequest("POST", endpoint, nil)
   568  	c.Assert(status, check.Equals, http.StatusOK)
   569  	c.Assert(err, check.IsNil)
   570  
   571  	dockerCmd(c, "stop", cID)
   572  
   573  	out, _ = dockerCmd(c, "events", "--since=0", "-f", "container="+cID, "--until="+strconv.Itoa(int(since)))
   574  	if !strings.Contains(out, " resize\n") {
   575  		c.Fatalf("Missing 'resize' log event\n%s", out)
   576  	}
   577  }
   578  
   579  func (s *DockerSuite) TestEventsAttach(c *check.C) {
   580  	since := daemonTime(c).Unix()
   581  
   582  	out, _ := dockerCmd(c, "run", "-di", "busybox", "/bin/cat")
   583  	cID := strings.TrimSpace(out)
   584  
   585  	cmd := exec.Command(dockerBinary, "attach", cID)
   586  	stdin, err := cmd.StdinPipe()
   587  	c.Assert(err, check.IsNil)
   588  	defer stdin.Close()
   589  	stdout, err := cmd.StdoutPipe()
   590  	c.Assert(err, check.IsNil)
   591  	defer stdout.Close()
   592  	c.Assert(cmd.Start(), check.IsNil)
   593  	defer cmd.Process.Kill()
   594  
   595  	// Make sure we're done attaching by writing/reading some stuff
   596  	if _, err := stdin.Write([]byte("hello\n")); err != nil {
   597  		c.Fatal(err)
   598  	}
   599  	out, err = bufio.NewReader(stdout).ReadString('\n')
   600  	c.Assert(err, check.IsNil)
   601  	if strings.TrimSpace(out) != "hello" {
   602  		c.Fatalf("expected 'hello', got %q", out)
   603  	}
   604  
   605  	c.Assert(stdin.Close(), check.IsNil)
   606  
   607  	dockerCmd(c, "stop", cID)
   608  
   609  	out, _ = dockerCmd(c, "events", "--since=0", "-f", "container="+cID, "--until="+strconv.Itoa(int(since)))
   610  	if !strings.Contains(out, " attach\n") {
   611  		c.Fatalf("Missing 'attach' log event\n%s", out)
   612  	}
   613  }
   614  
   615  func (s *DockerSuite) TestEventsRename(c *check.C) {
   616  	since := daemonTime(c).Unix()
   617  
   618  	dockerCmd(c, "run", "--name", "oldName", "busybox", "true")
   619  	dockerCmd(c, "rename", "oldName", "newName")
   620  
   621  	out, _ := dockerCmd(c, "events", "--since=0", "-f", "container=newName", "--until="+strconv.Itoa(int(since)))
   622  	if !strings.Contains(out, " rename\n") {
   623  		c.Fatalf("Missing 'rename' log event\n%s", out)
   624  	}
   625  }
   626  
   627  func (s *DockerSuite) TestEventsTop(c *check.C) {
   628  	since := daemonTime(c).Unix()
   629  
   630  	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
   631  	cID := strings.TrimSpace(out)
   632  	c.Assert(waitRun(cID), check.IsNil)
   633  
   634  	dockerCmd(c, "top", cID)
   635  	dockerCmd(c, "stop", cID)
   636  
   637  	out, _ = dockerCmd(c, "events", "--since=0", "-f", "container="+cID, "--until="+strconv.Itoa(int(since)))
   638  	if !strings.Contains(out, " top\n") {
   639  		c.Fatalf("Missing 'top' log event\n%s", out)
   640  	}
   641  }
   642  
   643  // #13753
   644  func (s *DockerSuite) TestEventsDefaultEmpty(c *check.C) {
   645  	dockerCmd(c, "run", "busybox")
   646  	out, _ := dockerCmd(c, "events", fmt.Sprintf("--until=%d", daemonTime(c).Unix()))
   647  	c.Assert(strings.TrimSpace(out), check.Equals, "")
   648  }
   649  
   650  // #14316
   651  func (s *DockerRegistrySuite) TestEventsImageFilterPush(c *check.C) {
   652  	testRequires(c, Network)
   653  	since := daemonTime(c).Unix()
   654  	repoName := fmt.Sprintf("%v/dockercli/testf", privateRegistryURL)
   655  
   656  	out, _ := dockerCmd(c, "run", "-d", "busybox", "top")
   657  	cID := strings.TrimSpace(out)
   658  	c.Assert(waitRun(cID), check.IsNil)
   659  
   660  	dockerCmd(c, "commit", cID, repoName)
   661  	dockerCmd(c, "stop", cID)
   662  	dockerCmd(c, "push", repoName)
   663  
   664  	out, _ = dockerCmd(c, "events", "--since=0", "-f", "image="+repoName, "-f", "event=push", "--until="+strconv.Itoa(int(since)))
   665  	if !strings.Contains(out, repoName+": push\n") {
   666  		c.Fatalf("Missing 'push' log event for image %s\n%s", repoName, out)
   667  	}
   668  }