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 }