-
Notifications
You must be signed in to change notification settings - Fork 1.4k
fix(coderd/x/agenthooks/dispatch): deflake TestDispatcherTimeoutNoRetry #28050
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -197,19 +197,22 @@ func TestDispatcherTimeoutNoRetry(t *testing.T) { | |
|
|
||
| event := newTestEvent(t, agenthooks.EventStop, agenthooks.StopData{}) | ||
| var requests atomic.Int32 | ||
| release := make(chan struct{}) | ||
| server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { | ||
| // A real server cannot guarantee the handler runs before the short | ||
| // dispatch deadline on a loaded machine, so the transport records the | ||
| // attempt synchronously. The successful response with a body that blocks | ||
| // until the deadline expires keeps the read-path timeout branch covered. | ||
| client := &http.Client{Transport: roundTripFunc(func(req *http.Request) (*http.Response, error) { | ||
| requests.Add(1) | ||
| w.WriteHeader(http.StatusOK) | ||
| assert.NoError(t, http.NewResponseController(w).Flush()) | ||
| <-release | ||
| })) | ||
| t.Cleanup(server.Close) | ||
| return &http.Response{ | ||
| StatusCode: http.StatusOK, | ||
| Body: contextBlockedBody{ctx: req.Context()}, | ||
| Request: req, | ||
| }, nil | ||
| })} | ||
|
|
||
| _, _, err := newTestDispatcher(t, server.Client(), server.URL, 50*time.Millisecond).Dispatch( | ||
| _, _, err := newTestDispatcher(t, client, "https://hooks.example.com/coder", 50*time.Millisecond).Dispatch( | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why change the server URL here?
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| testutil.Context(t, testutil.WaitLong), event, | ||
| ) | ||
| close(release) | ||
| assertDispatchErrorClass(t, err, ResultTimeout) | ||
| require.Equal(t, int32(1), requests.Load()) | ||
| } | ||
|
|
@@ -709,6 +712,15 @@ func (f roundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) { | |
| return f(req) | ||
| } | ||
|
|
||
| type contextBlockedBody struct{ ctx context.Context } | ||
|
|
||
| func (b contextBlockedBody) Read([]byte) (int, error) { | ||
| <-b.ctx.Done() | ||
| return 0, b.ctx.Err() | ||
| } | ||
|
|
||
| func (contextBlockedBody) Close() error { return nil } | ||
|
|
||
| func TestDispatcherCapacityClassRequired(t *testing.T) { | ||
| t.Parallel() | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would just waiting for
req.Context()to expire in theroundTripFunchave the same effect here?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Assertion-wise, yes: blocking in
RoundTripuntilreq.Context()expires also yieldstimeout, just via theclient.Doerror path instead of the body read. I verified that variant passes.The reason for the body-blocking stub is branch coverage: this test is the only one exercising the
readErrtimeout case in the dispatcher (the other timeout tests cancel before or duringDo). The original httptest version also timed out mid-read (handler flushed headers, then blocked), and Codex's earlier comment on this PR flagged keeping that path covered. Measured both ways with thereadErrtimeout case deliberately misclassified asprotocol_error: theRoundTrip-blocking variant still passes (coverage lost), the body-blocking stub fails as expected.