Repository navigation
[tests] Use local servers for networking tests - #12022
Conversation
Replace httpbin.org and badssl.com dependencies in networking tests with local loopback HTTP/HTTPS servers, including self-signed TLS coverage. Update the LinkDesc HttpClient regression to post to a local listener. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
This PR updates networking-related tests to stop depending on external internet endpoints (httpbin.org/badssl.com) by introducing local loopback HTTP/HTTPS test servers and switching existing redirect/decompression/SSL-validation tests to use them. This improves test reliability in constrained or offline environments and reduces external flakiness.
Changes:
- Added reusable local HTTP/HTTPS test server helpers for Mono.Android.NET-Tests.
- Migrated AndroidMessageHandler redirect/decompression and invalid-certificate tests to use local servers instead of external hosts.
- Updated the LinkDesc HttpClient regression app/test to POST to a local HttpListener endpoint and adjusted the manifest to allow cleartext traffic + INTERNET permission.
Show a summary per file
| File | Description |
|---|---|
| tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs | Enables cleartext + INTERNET permission for the LinkDesc regression app so it can talk to local HTTP endpoints. |
| tests/MSBuildDeviceIntegration/Resources/LinkDescTest/HttpClientTest.cs | Replaces external POST target with a local HttpListener-based loopback server. |
| tests/Mono.Android-Tests/Mono.Android-Tests/Xamarin.Android.Net/LocalTestServers.cs | Introduces local HTTP and HTTPS server helpers for test scenarios (compression, redirects, self-signed certs). |
| tests/Mono.Android-Tests/Mono.Android-Tests/Xamarin.Android.Net/AndroidMessageHandlerTests.cs | Switches decompression, redirect, and SSL callback tests to local servers. |
| tests/Mono.Android-Tests/Mono.Android-Tests/Xamarin.Android.Net/AndroidHandlerTestBase.cs | Updates redirect tests to use local loopback servers. |
| tests/Mono.Android-Tests/Mono.Android-Tests/System.Net/SslTest.cs | Removes httpbin from the external URL list to reduce dependency on that service. |
| tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj | Adds the new LocalTestServers.cs to the test project build. |
Copilot's findings
- Files reviewed: 7/7 changed files
- Comments generated: 4
Bind local HTTP listeners to loopback, dispose LinkDesc HTTP resources, backdate self-signed certificates further, and assert policy errors in the HTTPS redirect callback test. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Share local test server exception handling and shutdown logic, and add intent-level helpers for redirect and OK responses to remove repeated listener setup in networking tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Add local HTTP test-server endpoint helpers for the networking tests and LinkDesc HttpClient regression. Scope the generated app's cleartext allowance to localhost via network security config instead of enabling app-wide cleartext traffic. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use declaration-style using statements in the local HTTP test helpers and redirect tests to reduce nesting. Opt the generated LinkTestLib project into C# 8 so its embedded helper can use using declarations. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove the extra LocalHttpTestServer wrapper from Mono.Android networking tests. LocalTestServer now owns shared lifecycle/error handling, LocalHttpServer owns HTTP listener behavior and test endpoints, and LocalHttpsServer remains the HTTPS/self-signed transport helper. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Replace the Mono.Android HttpListener-based LocalHttpServer with a TCP-based request parser/router shared by LocalHttpsServer. HTTPS now exposes the same /ok and /redirect-to endpoints as HTTP, with TLS layered via SslStream. Rename the generated LinkDesc helper to LinkDescHttpServer to avoid confusion with the Mono.Android helpers. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Use BaseAddress with httpbin-style relative redirect endpoints in networking tests, name the HTTPS certificate host argument, and rename the generated LinkDesc helper back to LocalHttpServer with a /post endpoint. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Remove the duplicate LinkDesc local HTTP server and compile the shared Mono.Android LocalTestServers helper into the generated LinkTestLib project. Make the shared helper netstandard2.0-compatible for the LinkDesc library while keeping HTTPS/Brotli support for the Mono.Android tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
/review |
|
✅ Android PR Reviewer completed successfully! |
There was a problem hiding this comment.
🤖 Code Review — ⚠️ Needs Changes
Nice cleanup. Replacing httpbin.org / badssl.com with in-process loopback servers removes a real source of external-network flakiness, and LocalTestServers.cs is well thought through:
- Per-response
Connection: closecorrectly forces a fresh TLS handshake, which is what keepsServerCertificateCustomValidationCallback_RedirectsassertingcallbackCounter == 2. - Handler exceptions are captured off the accept loop and surfaced via
AssertNoUnhandledExceptions(), and dispose-timeIOException/ObjectDisposedExceptionare correctly ignored once the handler completed. - Self-signed cert generation with SANs and the HTTPS host pinned to
localhost(matching the cert) is a sensible design.
CI: ✅ All dotnet-android checks are green on bd7911c. mergeable_state: blocked reflects the pending maintainer review, not a CI failure.
Findings (see inline):
⚠️ 1 warning — LinkDescnetwork_security_config.xmlwhitelists cleartext forlocalhost, butLocalHttpServeruses127.0.0.1; the LinkDescHttpClientTestwill hitCleartext ... not permittedonceCustomLinkDescriptionPreserveis un-ignored.- 💡 2 suggestions — port-selection race in
GetAvailablePort()(re-introduces a flaky window); reduced fidelity ofNoServerCertificateCustomValidationCallback_ThrowsWhenThereIsCertificateHostnameMismatch.
Worth double-checking before merge: the two tests that actually exercise the loopback servers end-to-end aren't part of the green CI legs — CustomLinkDescriptionPreserve is ignored for all runtime variants (per the PR description), and the SSL-category AndroidMessageHandlerTests run on a physical device rather than the emulator legs. So the green checks above don't fully validate the new cleartext/loopback paths.
Prioritized: the network-security-config vs. server-host mismatch is the one to fix; the other two are optional.
Generated by Android PR Reviewer for #12022 · 209.6 AIC · ⌖ 27.5 AIC · ⊞ 6.8K
Comment /review to run again
Bind local test listeners directly to ephemeral ports and align the loopback cleartext configuration. Trust the local certificate before asserting a hostname mismatch so the test isolates name validation. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 9721cbaf-7e53-4fb0-b12c-6c9de7483f9d
> Re-opened as a direct PR (supersedes #12098) so the `dotnet-android` pipeline runs automatically without `/azp run` approval. ### Context Following up on #12022 (which migrated most on-device networking tests off live external URLs to the loopback `LocalHttpServer`/`LocalHttpsServer`) and #12058 (which handles `SslTest.HttpsShouldWork`), a few on-device tests were still reaching out to the public internet. Those requests made the tests flaky whenever the external endpoints were slow, rate-limited, or unavailable. This migrates the remaining tests to local loopback servers. ### Tests migrated | Test | Was hitting | | ---- | ----------- | | `SslTest.SslWithinTasksShouldWork` | `dotnet.microsoft.com` | | `ProxyTest.QuoteInvalidQuoteUrlsShouldWork` | `msftconnecttest.com` | | `AndroidMessageHandlerTests.ServerCertificateCustomValidationCallback_ApproveRequest` | `www.microsoft.com` | | `AndroidMessageHandlerTests.ServerCertificateCustomValidationCallback_RejectRequest` | `www.microsoft.com` | | `AndroidMessageHandlerTests.AndroidMessageHandlerSendsClientCertificate` | `corefx-net-tls.azurewebsites.net` | | `AndroidMessageHandlerIntegrationTests.GetString_Many` | `google.com` | | `HttpClientHandlerTestBase.Disposed` | `google.com` | | `WebSocketTests.TestSocketConnection` | `echo.websocket.org` (was `[Ignore]`d) | `ProxyTest` keeps its original point — an unescaped `|` in the query string (`?query&foo|bar`) — now exercised against the local `/ok` endpoint. `WebSocketTests` was previously disabled because the public echo server no longer exists; it is re-enabled against a local server. ### Test infrastructure (`LocalTestServers.cs`) - **Client certificates (mutual TLS)**: `LocalHttpsServer.Start (requestClientCertificate: true)` now requests a client certificate during the TLS handshake, and a new `/echo-client-certificate` endpoint returns the certificate the server received (base64 DER). This replaces the external `EchoClientCertificate.ashx` endpoint. - **`LocalWebSocketServer`**: a loopback WebSocket echo server that performs the upgrade handshake and echoes messages back (uses `WebSocket.CreateFromStream` after a manual `101 Switching Protocols` response). ### Notes - `HttpsShouldWork` is intentionally left to #12058. - The `http://10.255.255.1` cancellation/timeout tests deliberately use an unroutable address (not the public internet) and are unchanged. - Cosmetic external hostnames that were never actually contacted (`CancelRequestViaProxy`'s base address behind a dead proxy, and `DisallowAutoRedirect`'s redirect target) were pointed at `localhost`. The new server logic (HTTP, HTTPS, mutual-TLS echo, and WebSocket echo) was verified end-to-end against `HttpClient` and `ClientWebSocket` on desktop .NET.
|
/backport to release/10.0.1xx |
|
Started backporting to |
|
@jonathanpeppers backporting to git am output$ git cherry-pick bef2665f349676bec98143a1285c97533236a75b
Auto-merging tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs
CONFLICT (content): Merge conflict in tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs
Auto-merging tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj
CONFLICT (content): Merge conflict in tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj
Auto-merging tests/Mono.Android-Tests/Mono.Android-Tests/Xamarin.Android.Net/AndroidClientHandlerTests.cs
Auto-merging tests/Mono.Android-Tests/Mono.Android-Tests/Xamarin.Android.Net/AndroidMessageHandlerTests.cs
CONFLICT (content): Merge conflict in tests/Mono.Android-Tests/Mono.Android-Tests/Xamarin.Android.Net/AndroidMessageHandlerTests.cs
error: could not apply bef2665f3... [tests] Use local servers for networking tests (#12022)
hint: After resolving the conflicts, mark them with
hint: "git add/rm <pathspec>", then run
hint: "git cherry-pick --continue".
hint: You can instead skip this commit with "git cherry-pick --skip".
hint: To abort and get back to the state before "git cherry-pick",
hint: run "git cherry-pick --abort".
hint: Disable this message with "git config set advice.mergeConflict false"
$ git am --3way --empty=keep --ignore-whitespace --keep-non-patch changes.patch
Applying: [tests] Use local servers for networking tests
Using index info to reconstruct a base tree...
M tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs
M tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj
A tests/Mono.Android-Tests/Mono.Android-Tests/Xamarin.Android.Net/AndroidHandlerTestBase.cs
M tests/Mono.Android-Tests/Mono.Android-Tests/Xamarin.Android.Net/AndroidMessageHandlerTests.cs
Falling back to patching base and 3-way merge...
Auto-merging tests/MSBuildDeviceIntegration/Tests/InstallAndRunTests.cs
Auto-merging tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj
CONFLICT (content): Merge conflict in tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj
Auto-merging tests/Mono.Android-Tests/Mono.Android-Tests/Xamarin.Android.Net/AndroidClientHandlerTests.cs
CONFLICT (content): Merge conflict in tests/Mono.Android-Tests/Mono.Android-Tests/Xamarin.Android.Net/AndroidClientHandlerTests.cs
Auto-merging tests/Mono.Android-Tests/Mono.Android-Tests/Xamarin.Android.Net/AndroidMessageHandlerTests.cs
CONFLICT (content): Merge conflict in tests/Mono.Android-Tests/Mono.Android-Tests/Xamarin.Android.Net/AndroidMessageHandlerTests.cs
error: Failed to merge in the changes.
hint: Use 'git am --show-current-patch=diff' to see the failed patch
hint: When you have resolved this problem, run "git am --continue".
hint: If you prefer to skip this patch, run "git am --skip" instead.
hint: To restore the original branch and stop patching, run "git am --abort".
hint: Disable this message with "git config set advice.mergeConflict false"
Patch failed at 0001 [tests] Use local servers for networking tests
Error: The process '/usr/bin/git' failed with exit code 128 |
Summary
Validation
make all./dotnet-local.sh build -t:Install -c Debug tests/Mono.Android-Tests/Mono.Android-Tests/Mono.Android.NET-Tests.csproj -p:Device=R58Y30HZ65V -p:IncludeCategories=SSL(cd tests/Mono.Android-Tests/Mono.Android-Tests && ../../../dotnet-local.sh test Mono.Android.NET-Tests.csproj --no-build -c Debug --report-trx --results-directory ../../../bin/TestDebug/TestResults -p:Device=R58Y30HZ65V -p:IncludeCategories=SSL)— 25 passed./dotnet-local.sh test bin/TestDebug/MSBuildDeviceIntegration/net10.0/MSBuildDeviceIntegration.dll --filter "FullyQualifiedName~InstallAndRunTests.CustomLinkDescriptionPreserve"— 4 skipped (test is currently ignored for all runtime variants)