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