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