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