diff --git a/integration-cli/docker_api_events_test.go b/integration-cli/docker_api_events_test.go deleted file mode 100644 index a95422f581..0000000000 --- a/integration-cli/docker_api_events_test.go +++ /dev/null @@ -1,74 +0,0 @@ -package main - -import ( - "encoding/json" - "io" - "net/http" - "net/url" - "strconv" - "strings" - "time" - - "github.com/docker/docker/integration-cli/checker" - "github.com/docker/docker/integration-cli/request" - "github.com/docker/docker/pkg/jsonmessage" - "github.com/go-check/check" -) - -func (s *DockerSuite) TestEventsAPIEmptyOutput(c *check.C) { - type apiResp struct { - resp *http.Response - err error - } - chResp := make(chan *apiResp) - go func() { - resp, body, err := request.Get("/events") - body.Close() - chResp <- &apiResp{resp, err} - }() - - select { - case r := <-chResp: - c.Assert(r.err, checker.IsNil) - c.Assert(r.resp.StatusCode, checker.Equals, http.StatusOK) - case <-time.After(3 * time.Second): - c.Fatal("timeout waiting for events api to respond, should have responded immediately") - } -} - -func (s *DockerSuite) TestEventsAPIBackwardsCompatible(c *check.C) { - since := daemonTime(c).Unix() - ts := strconv.FormatInt(since, 10) - - out := runSleepingContainer(c, "--name=foo", "-d") - containerID := strings.TrimSpace(out) - c.Assert(waitRun(containerID), checker.IsNil) - - q := url.Values{} - q.Set("since", ts) - - _, body, err := request.Get("/events?" + q.Encode()) - c.Assert(err, checker.IsNil) - defer body.Close() - - dec := json.NewDecoder(body) - var containerCreateEvent *jsonmessage.JSONMessage - for { - var event jsonmessage.JSONMessage - if err := dec.Decode(&event); err != nil { - if err == io.EOF { - break - } - c.Fatal(err) - } - if event.Status == "create" && event.ID == containerID { - containerCreateEvent = &event - break - } - } - - c.Assert(containerCreateEvent, checker.Not(checker.IsNil)) - c.Assert(containerCreateEvent.Status, checker.Equals, "create") - c.Assert(containerCreateEvent.ID, checker.Equals, containerID) - c.Assert(containerCreateEvent.From, checker.Equals, "busybox") -} diff --git a/integration/internal/request/client.go b/integration/internal/request/client.go index 367db14c59..34e589ec86 100644 --- a/integration/internal/request/client.go +++ b/integration/internal/request/client.go @@ -20,8 +20,8 @@ func NewAPIClient(t *testing.T, ops ...func(*client.Client) error) client.APICli return clt } -// daemonTime provides the current time on the daemon host -func daemonTime(ctx context.Context, t *testing.T, client client.APIClient, testEnv *environment.Execution) time.Time { +// DaemonTime provides the current time on the daemon host +func DaemonTime(ctx context.Context, t *testing.T, client client.APIClient, testEnv *environment.Execution) time.Time { if testEnv.IsLocalDaemon() { return time.Now() } @@ -37,6 +37,6 @@ func daemonTime(ctx context.Context, t *testing.T, client client.APIClient, test // DaemonUnixTime returns the current time on the daemon host with nanoseconds precision. // It return the time formatted how the client sends timestamps to the server. func DaemonUnixTime(ctx context.Context, t *testing.T, client client.APIClient, testEnv *environment.Execution) string { - dt := daemonTime(ctx, t, client, testEnv) + dt := DaemonTime(ctx, t, client, testEnv) return fmt.Sprintf("%d.%09d", dt.Unix(), int64(dt.Nanosecond())) } diff --git a/integration/system/event_test.go b/integration/system/event_test.go index 7f04195690..688d7c27de 100644 --- a/integration/system/event_test.go +++ b/integration/system/event_test.go @@ -2,15 +2,22 @@ package system // import "github.com/docker/docker/integration/system" import ( "context" + "encoding/json" + "io" + "net/http" + "net/url" + "strconv" "testing" - "time" "github.com/docker/docker/api/types" "github.com/docker/docker/api/types/filters" "github.com/docker/docker/api/types/strslice" + req "github.com/docker/docker/integration-cli/request" "github.com/docker/docker/integration/internal/container" "github.com/docker/docker/integration/internal/request" + "github.com/docker/docker/pkg/jsonmessage" + "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) @@ -58,3 +65,55 @@ func TestEvents(t *testing.T) { } } + +// Test case for #18888: Events messages have been switched from generic +// `JSONMessage` to `events.Message` types. The switch does not break the +// backward compatibility so old `JSONMessage` could still be used. +// This test verifies that backward compatibility maintains. +func TestEventsBackwardsCompatible(t *testing.T) { + defer setupTest(t)() + ctx := context.Background() + client := request.NewAPIClient(t) + + since := request.DaemonTime(ctx, t, client, testEnv) + ts := strconv.FormatInt(since.Unix(), 10) + + cID := container.Create(t, ctx, client) + + // In case there is no events, the API should have responded immediately (not blocking), + // The test here makes sure the response time is less than 3 sec. + expectedTime := time.Now().Add(3 * time.Second) + emptyResp, emptyBody, err := req.Get("/events") + require.NoError(t, err) + defer emptyBody.Close() + assert.Equal(t, http.StatusOK, emptyResp.StatusCode) + assert.True(t, time.Now().Before(expectedTime), "timeout waiting for events api to respond, should have responded immediately") + + // We also test to make sure the `events.Message` is compatible with `JSONMessage` + q := url.Values{} + q.Set("since", ts) + _, body, err := req.Get("/events?" + q.Encode()) + require.NoError(t, err) + defer body.Close() + + dec := json.NewDecoder(body) + var containerCreateEvent *jsonmessage.JSONMessage + for { + var event jsonmessage.JSONMessage + if err := dec.Decode(&event); err != nil { + if err == io.EOF { + break + } + t.Fatal(err) + } + if event.Status == "create" && event.ID == cID { + containerCreateEvent = &event + break + } + } + + assert.NotNil(t, containerCreateEvent) + assert.Equal(t, "create", containerCreateEvent.Status) + assert.Equal(t, cID, containerCreateEvent.ID) + assert.Equal(t, "busybox", containerCreateEvent.From) +}