github.com/rish1988/moby@v25.0.2+incompatible/integration/system/event_test.go (about)

     1  package system // import "github.com/docker/docker/integration/system"
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"errors"
     7  	"io"
     8  	"net/http"
     9  	"net/url"
    10  	"strconv"
    11  	"testing"
    12  	"time"
    13  
    14  	"github.com/docker/docker/api/types"
    15  	"github.com/docker/docker/api/types/events"
    16  	"github.com/docker/docker/api/types/filters"
    17  	"github.com/docker/docker/api/types/mount"
    18  	"github.com/docker/docker/api/types/strslice"
    19  	"github.com/docker/docker/api/types/volume"
    20  	"github.com/docker/docker/integration/internal/container"
    21  	"github.com/docker/docker/pkg/jsonmessage"
    22  	"github.com/docker/docker/testutil/request"
    23  	req "github.com/docker/docker/testutil/request"
    24  	"gotest.tools/v3/assert"
    25  	is "gotest.tools/v3/assert/cmp"
    26  	"gotest.tools/v3/skip"
    27  )
    28  
    29  func TestEventsExecDie(t *testing.T) {
    30  	skip.If(t, testEnv.DaemonInfo.OSType == "windows", "FIXME. Suspect may need to wait until container is running before exec")
    31  	ctx := setupTest(t)
    32  	client := testEnv.APIClient()
    33  
    34  	cID := container.Run(ctx, t, client)
    35  
    36  	id, err := client.ContainerExecCreate(ctx, cID,
    37  		types.ExecConfig{
    38  			Cmd: strslice.StrSlice([]string{"echo", "hello"}),
    39  		},
    40  	)
    41  	assert.NilError(t, err)
    42  
    43  	msg, errs := client.Events(ctx, types.EventsOptions{
    44  		Filters: filters.NewArgs(
    45  			filters.Arg("container", cID),
    46  			filters.Arg("event", string(events.ActionExecDie)),
    47  		),
    48  	})
    49  
    50  	err = client.ContainerExecStart(ctx, id.ID,
    51  		types.ExecStartCheck{
    52  			Detach: true,
    53  			Tty:    false,
    54  		},
    55  	)
    56  	assert.NilError(t, err)
    57  
    58  	select {
    59  	case m := <-msg:
    60  		assert.Equal(t, m.Type, events.ContainerEventType)
    61  		assert.Equal(t, m.Actor.ID, cID)
    62  		assert.Equal(t, m.Action, events.ActionExecDie)
    63  		assert.Equal(t, m.Actor.Attributes["execID"], id.ID)
    64  		assert.Equal(t, m.Actor.Attributes["exitCode"], "0")
    65  	case err = <-errs:
    66  		assert.NilError(t, err)
    67  	case <-time.After(time.Second * 3):
    68  		t.Fatal("timeout hit")
    69  	}
    70  }
    71  
    72  // Test case for #18888: Events messages have been switched from generic
    73  // `JSONMessage` to `events.Message` types. The switch does not break the
    74  // backward compatibility so old `JSONMessage` could still be used.
    75  // This test verifies that backward compatibility maintains.
    76  func TestEventsBackwardsCompatible(t *testing.T) {
    77  	skip.If(t, testEnv.DaemonInfo.OSType == "windows", "Windows doesn't support back-compat messages")
    78  	ctx := setupTest(t)
    79  	client := testEnv.APIClient()
    80  
    81  	since := request.DaemonTime(ctx, t, client, testEnv)
    82  	ts := strconv.FormatInt(since.Unix(), 10)
    83  
    84  	cID := container.Create(ctx, t, client)
    85  
    86  	// In case there is no events, the API should have responded immediately (not blocking),
    87  	// The test here makes sure the response time is less than 3 sec.
    88  	expectedTime := time.Now().Add(3 * time.Second)
    89  	emptyResp, emptyBody, err := req.Get(ctx, "/events")
    90  	assert.NilError(t, err)
    91  	defer emptyBody.Close()
    92  	assert.Check(t, is.DeepEqual(http.StatusOK, emptyResp.StatusCode))
    93  	assert.Check(t, time.Now().Before(expectedTime), "timeout waiting for events api to respond, should have responded immediately")
    94  
    95  	// We also test to make sure the `events.Message` is compatible with `JSONMessage`
    96  	q := url.Values{}
    97  	q.Set("since", ts)
    98  	_, body, err := req.Get(ctx, "/events?"+q.Encode())
    99  	assert.NilError(t, err)
   100  	defer body.Close()
   101  
   102  	dec := json.NewDecoder(body)
   103  	var containerCreateEvent *jsonmessage.JSONMessage
   104  	for {
   105  		var event jsonmessage.JSONMessage
   106  		if err := dec.Decode(&event); err != nil {
   107  			if err == io.EOF {
   108  				break
   109  			}
   110  			assert.NilError(t, err)
   111  		}
   112  		if event.Status == "create" && event.ID == cID {
   113  			containerCreateEvent = &event
   114  			break
   115  		}
   116  	}
   117  
   118  	assert.Check(t, containerCreateEvent != nil)
   119  	assert.Check(t, is.Equal("create", containerCreateEvent.Status))
   120  	assert.Check(t, is.Equal(cID, containerCreateEvent.ID))
   121  	assert.Check(t, is.Equal("busybox", containerCreateEvent.From))
   122  }
   123  
   124  // TestEventsVolumeCreate verifies that volume create events are only fired
   125  // once: when creating the volume, and not when attaching to a container.
   126  func TestEventsVolumeCreate(t *testing.T) {
   127  	skip.If(t, testEnv.DaemonInfo.OSType == "windows", "FIXME: Windows doesn't trigger the events? Could be a race")
   128  
   129  	ctx := setupTest(t)
   130  	ctx, cancel := context.WithCancel(ctx)
   131  	defer cancel()
   132  
   133  	client := testEnv.APIClient()
   134  
   135  	since := request.DaemonUnixTime(ctx, t, client, testEnv)
   136  	volName := t.Name()
   137  	getEvents := func(messages <-chan events.Message, errs <-chan error) ([]events.Message, error) {
   138  		var evts []events.Message
   139  
   140  		for {
   141  			select {
   142  			case m := <-messages:
   143  				evts = append(evts, m)
   144  			case err := <-errs:
   145  				if err == io.EOF {
   146  					return evts, nil
   147  				}
   148  				return nil, err
   149  			case <-time.After(time.Second * 3):
   150  				return nil, errors.New("timeout hit")
   151  			}
   152  		}
   153  	}
   154  
   155  	_, err := client.VolumeCreate(ctx, volume.CreateOptions{Name: volName})
   156  	assert.NilError(t, err)
   157  
   158  	filter := filters.NewArgs(
   159  		filters.Arg("type", "volume"),
   160  		filters.Arg("event", "create"),
   161  		filters.Arg("volume", volName),
   162  	)
   163  	messages, errs := client.Events(ctx, types.EventsOptions{
   164  		Since:   since,
   165  		Until:   request.DaemonUnixTime(ctx, t, client, testEnv),
   166  		Filters: filter,
   167  	})
   168  
   169  	volEvents, err := getEvents(messages, errs)
   170  	assert.NilError(t, err)
   171  	assert.Equal(t, len(volEvents), 1, "expected volume create event when creating a volume")
   172  
   173  	container.Create(ctx, t, client, container.WithMount(mount.Mount{
   174  		Type:   mount.TypeVolume,
   175  		Source: volName,
   176  		Target: "/tmp/foo",
   177  	}))
   178  
   179  	messages, errs = client.Events(ctx, types.EventsOptions{
   180  		Since:   since,
   181  		Until:   request.DaemonUnixTime(ctx, t, client, testEnv),
   182  		Filters: filter,
   183  	})
   184  
   185  	volEvents, err = getEvents(messages, errs)
   186  	assert.NilError(t, err)
   187  	assert.Equal(t, len(volEvents), 1, "expected volume create event to be fired only once")
   188  }