github.com/codemac/docker@v1.2.1-0.20150518222241-6a18412d5b9c/integration-cli/docker_cli_events_test.go (about)

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