Repository navigation
tests: refactors redirection tests to avoid race condition - #14342
Conversation
There was a problem hiding this comment.
Pull request overview
This PR refactors two redirect-related unit tests to use a shared loopback redirect server helper, aiming to eliminate test flakiness/race conditions seen when multiple tests create/tear down their own listeners.
Changes:
- Replaced per-test
HttpListener-based redirect setups with a sharedRedirectLoopbackServerhelper. - Updated redirect tests to use the helper’s
BaseUriand to assert redirect-target access via a shared flag. - Added a new TCP-based loopback server utility under the unit test support folder.
Reviewed changes
Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| dotnet/src/Plugins/Plugins.UnitTests/Web/WebFileDownloadPluginTests.cs | Uses the new loopback helper instead of an inline HttpListener redirect server. |
| dotnet/src/Plugins/Plugins.UnitTests/Core/HttpPluginTests.cs | Uses the new loopback helper to validate redirects aren’t followed without relying on shared ports/listeners. |
| dotnet/src/Plugins/Plugins.UnitTests/Support/RedirectLoopbackServer.cs | Introduces a reusable TCP loopback server that serves a 302 from /start and tracks whether the redirect target was requested. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Co-authored-by: Copilot Autofix powered by AI <[email protected]>
There was a problem hiding this comment.
MAF Automated Review — Iteration 1
Result: No findings
Scope: full PR (2 commit(s)): 2c018ec638d2, f8847407170a
Model: claude-opus-4.8
Overview
This test-only change replaces two flaky redirect tests — each of which spun up an HttpListener on a Random-guessed port with a fire-and-forget Task.Run loop — with a shared internal RedirectLoopbackServer helper bound to an ephemeral loopback port and torn down deterministically via IAsyncDisposable/await using. The redesign removes the actual race (colliding guessed ports across parallel test classes) and makes teardown deterministic by awaiting the server task. Correctness of the "redirect is not followed" assertion is anchored by the plugins' non-redirecting HttpClient (AllowAutoRedirect=false), so exactly one well-formed GET /start reaches the helper and /secret is never contacted. The project builds cleanly on the declared net10.0 target, and all TFM-gated socket/reader overloads resolve. The two residual robustness gaps in the helper (a Split(' ')[1] crash / false-positive contacted-flag, and unguarded HandleRequestAsync faults surfacing through DisposeAsync) are real but confined to abnormal loopback conditions and are already tracked verbatim by the two unresolved reviewer threads, so no new publishable finding remains.
Reviewed the supplied pull-request change set across correctness, security/reliability, architecture, and failure behavior.
No publishable findings remained after source verification for this scope.
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 3 out of 3 changed files in this pull request and generated no new comments.
Suppressed comments (1)
dotnet/src/Plugins/Plugins.UnitTests/Support/RedirectLoopbackServer.cs:112
HandleRequestAsyncparses the request line withrequestLine?.Split(' ')[1], which can throwIndexOutOfRangeExceptionfor malformed / truncated requests (andnullrequestLine will also incorrectly markRedirectTargetContacted). This can make the new loopback server flaky and cause tests to fail during disposal when_serverTaskfaults. Also,RedirectTargetContactedis currently set for any non-/startrequest, not just the redirect target path, which can produce false positives if the client ever requests another resource.
var requestTarget = requestLine?.Split(' ')[1];
if (requestTarget == "/start")
{
var response = $"HTTP/1.1 302 Found\r\nLocation: {new Uri(this.BaseUri, this._redirectTargetPath.TrimStart('/'))}\r\nContent-Length: 0\r\nConnection: close\r\n\r\n";
await stream.WriteAsync(Encoding.ASCII.GetBytes(response), cancellationToken).ConfigureAwait(false);
while working on #14340 I noticed some flaky unit tests are you can see in https://github.com/microsoft/semantic-kernel/actions/runs/32982261836/job/98221741513?pr=14340. This PR refactors the involved tests so they don't run into each other