Goal and rationale
ServerModeManager.Build (src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/ServerModeManager.cs) had zero direct unit coverage. It resolves the JSON-RPC client host/port from command-line options and constructs the MessageHandlerFactory used to connect back to the IDE/client in server mode — a small but critical wiring path (missing --client-port throws, --client-host defaults to the loopback address for "localhost", and explicit host/port are passed through).
Approach
Added ServerModeManagerTests.cs with 3 tests covering all 3 branches:
Build_MissingClientPortOption_Throws — verifies the documented InvalidOperationException/PlatformResources.MissingClientPortFoJsonRpc message.
Build_ClientPortOptionWithoutClientHost_DefaultsHostToLoopbackAddress — verifies the "localhost" → 127.0.0.1 substitution (worked around a known slow-DNS-resolve issue).
Build_ClientPortAndClientHostOptions_UsesProvidedHostAndPort — verifies explicit host/port pass-through.
Constructed a real CommandLineHandler via CommandLineParser.Parse (same pattern as the existing DotnetTestHelperTests.cs/CommandLineHandlerTests.cs), and a ServiceProvider with mocked ILoggerFactory/IOutputDevice. Since _host/_port on the returned MessageHandlerFactory are private, they're asserted via reflection.
Also added the missing PlatformResources.MissingClientPortFoJsonRpc hand-maintained accessor to the IS_MTP_UNIT_TESTS block in PlatformResources.cs (required so the unit test project can read the exact resource string — no other API surface changed).
Coverage impact
Microsoft.Testing.Platform.UnitTests net8.0 suite: 2648 total (was 2645 on main, +3 new tests), 0 failed, 22 skipped (pre-existing).
Trade-offs
Small reflection use for private-field assertions is consistent with several existing tests in this project (e.g. DotnetTestDataConsumerTests.cs). No new dependencies, no behavior changes.
Reproducibility
./build.sh -restore
export PATH="$PWD/.dotnet:$PATH"
dotnet build test/UnitTests/Microsoft.Testing.Platform.UnitTests/Microsoft.Testing.Platform.UnitTests.csproj -c Debug
./artifacts/bin/Microsoft.Testing.Platform.UnitTests/Debug/net8.0/Microsoft.Testing.Platform.UnitTests
Test Status
Build succeeded (0 warnings/errors). Full suite passed as noted above. dotnet format whitespace TestFx.slnx --verify-no-changes --include <files> clean (only the expected harmless F#-project warning).
Note
This was originally intended as a pull request, but the git push operation failed.
Original error: The process '/usr/bin/git' failed with exit code 128
Workflow Run: View run details and download bundle artifact
The bundle file is available in the agent artifact in the workflow run linked above.
Create the pull request manually
# Download the artifact from the workflow run
gh run download ' 36356926698' -n agent -D ' /tmp/agent-36356926698'
# Resolve the bundle source ref, fetch it into a temporary ref, then create the local branch
bundle_path=' /tmp/agent-36356926698/aw-test-assist-server-mode-manager-tests.bundle'
temp_ref=' refs/bundles/create-pr-test-assist-server-mode-manager-tests-89f8d5764e91c75c-9b103e6f'
target_ref=' refs/heads/test-assist/server-mode-manager-tests-89f8d5764e91c75c'
bundle_source_ref=$( git bundle list-heads " $bundle_path " | awk ' $2 ~ /^refs\/heads\// { print $2 }' )
if [ -z " $bundle_source_ref " ]; then
bundle_source_ref=$( git bundle list-heads " $bundle_path " | awk ' $2 == "HEAD" { print $2 }' )
fi
if [ " $( printf ' %s\n' " $bundle_source_ref " | sed ' /^$/d' | wc -l | tr -d ' ' ) " != " 1" ]; then
echo " Expected exactly one bundle source ref, found: $bundle_source_ref " >&2
exit 1
fi
git fetch " $bundle_path " " ${bundle_source_ref} :${temp_ref} "
git update-ref " $target_ref " " $temp_ref "
git checkout ' test-assist/server-mode-manager-tests-89f8d5764e91c75c'
# Ensure the working tree matches the updated branch
git reset --hard
# Remove the temporary bundle ref
git update-ref -d " $temp_ref "
# Push the branch to the target remote
git push ' origin' ' test-assist/server-mode-manager-tests-89f8d5764e91c75c'
# Create the pull request
gh pr create --title ' [test-improver] Add unit tests for ServerModeManager.Build' --base ' main' --head ' test-assist/server-mode-manager-tests-89f8d5764e91c75c' --repo ' microsoft/testfx'
Warning
Firewall blocked 90 domains
The following domains were blocked by the firewall during workflow execution:
0t3vsblobprodcus362.vsblob.vsassets.io
11vvsblobprodcus336.vsblob.vsassets.io
1javsblobprodcus364.vsblob.vsassets.io
1k9vsblobprodcus379.vsblob.vsassets.io
1oavsblobprodcus350.vsblob.vsassets.io
1p7vsblobprodcus324.vsblob.vsassets.io
1s1vsblobprodcus386.vsblob.vsassets.io
2kmvsblobprodcus39.vsblob.vsassets.io
2zrvsblobprodcus388.vsblob.vsassets.io
37bvsblobprodcus311.vsblob.vsassets.io
37cvsblobprodcus359.vsblob.vsassets.io
4m6vsblobprodcus384.vsblob.vsassets.io
4myvsblobprodcus32.vsblob.vsassets.io
4vyvsblobprodcus361.vsblob.vsassets.io
4zjvsblobprodcus390.vsblob.vsassets.io
51yvsblobprodcus36.vsblob.vsassets.io
5dkvsblobprodcus355.vsblob.vsassets.io
5rqvsblobprodcus385.vsblob.vsassets.io
6s7vsblobprodcus313.vsblob.vsassets.io
7devsblobprodcus323.vsblob.vsassets.io
7k6vsblobprodcus337.vsblob.vsassets.io
7tjvsblobprodcus341.vsblob.vsassets.io
80zvsblobprodcus35.vsblob.vsassets.io
8xbvsblobprodcus382.vsblob.vsassets.io
96bvsblobprodcus338.vsblob.vsassets.io
ajhvsblobprodcus363.vsblob.vsassets.io
bcnvsblobprodcus378.vsblob.vsassets.io
builds.dotnet.microsoft.com
c50vsblobprodcus330.vsblob.vsassets.io
c78vsblobprodcus322.vsblob.vsassets.io
cflvsblobprodcus383.vsblob.vsassets.io
ci.dot.net
ckzvsblobprodcus347.vsblob.vsassets.io
d0svsblobprodcus381.vsblob.vsassets.io
data.nuget.org
dlbvsblobprodcus316.vsblob.vsassets.io
e7bvsblobprodcus348.vsblob.vsassets.io
fdpvsblobprodcus345.vsblob.vsassets.io
frdvsblobprodcus327.vsblob.vsassets.io
gbsvsblobprodcus365.vsblob.vsassets.io
gervsblobprodcus329.vsblob.vsassets.io
h6tvsblobprodcus346.vsblob.vsassets.io
i1qvsblobprodcus353.vsblob.vsassets.io
imzvsblobprodcus368.vsblob.vsassets.io
jd4vsblobprodcus366.vsblob.vsassets.io
josvsblobprodcus372.vsblob.vsassets.io
jrqvsblobprodcus343.vsblob.vsassets.io
k0ivsblobprodcus356.vsblob.vsassets.io
k4kvsblobprodcus344.vsblob.vsassets.io
kgfvsblobprodcus314.vsblob.vsassets.io
kh4vsblobprodcus325.vsblob.vsassets.io
kijvsblobprodcus387.vsblob.vsassets.io
kmuvsblobprodcus389.vsblob.vsassets.io
kxqvsblobprodcus376.vsblob.vsassets.io
l49vsblobprodcus358.vsblob.vsassets.io
l7avsblobprodcus319.vsblob.vsassets.io
ljcvsblobprodcus317.vsblob.vsassets.io
lylvsblobprodcus31.vsblob.vsassets.io
m16vsblobprodcus374.vsblob.vsassets.io
m6xvsblobprodcus342.vsblob.vsassets.io
m8dvsblobprodcus37.vsblob.vsassets.io
mfjvsblobprodcus373.vsblob.vsassets.io
n3kvsblobprodcus335.vsblob.vsassets.io
nn8vsblobprodcus340.vsblob.vsassets.io
o3svsblobprodcus318.vsblob.vsassets.io
ofvvsblobprodcus315.vsblob.vsassets.io
p2ovsblobprodcus312.vsblob.vsassets.io
pc2vsblobprodcus360.vsblob.vsassets.io
pdfvsblobprodcus380.vsblob.vsassets.io
pe3vsblobprodcus354.vsblob.vsassets.io
pe4vsblobprodcus351.vsblob.vsassets.io
pkgs.dev.azure.com
rcxvsblobprodcus328.vsblob.vsassets.io
s4uvsblobprodcus326.vsblob.vsassets.io
s8mvsblobprodcus38.vsblob.vsassets.io
se1vsblobprodcus349.vsblob.vsassets.io
sqdvsblobprodcus333.vsblob.vsassets.io
st8vsblobprodcus339.vsblob.vsassets.io
tphvsblobprodcus375.vsblob.vsassets.io
u3hvsblobprodcus371.vsblob.vsassets.io
u6ovsblobprodcus377.vsblob.vsassets.io
ukkvsblobprodcus352.vsblob.vsassets.io
uy6vsblobprodcus34.vsblob.vsassets.io
v53vsblobprodcus320.vsblob.vsassets.io
vb4vsblobprodcus33.vsblob.vsassets.io
vwvvsblobprodcus334.vsblob.vsassets.io
x3yvsblobprodcus370.vsblob.vsassets.io
xupvsblobprodcus332.vsblob.vsassets.io
yluvsblobprodcus367.vsblob.vsassets.io
yttvsblobprodcus357.vsblob.vsassets.io
To allow these domains, add them to the network.allowed list in your workflow frontmatter:
network :
allowed :
- defaults
- " 0t3vsblobprodcus362.vsblob.vsassets.io"
- " 11vvsblobprodcus336.vsblob.vsassets.io"
- " 1javsblobprodcus364.vsblob.vsassets.io"
- " 1k9vsblobprodcus379.vsblob.vsassets.io"
- " 1oavsblobprodcus350.vsblob.vsassets.io"
- " 1p7vsblobprodcus324.vsblob.vsassets.io"
- " 1s1vsblobprodcus386.vsblob.vsassets.io"
- " 2kmvsblobprodcus39.vsblob.vsassets.io"
- " 2zrvsblobprodcus388.vsblob.vsassets.io"
- " 37bvsblobprodcus311.vsblob.vsassets.io"
- " 37cvsblobprodcus359.vsblob.vsassets.io"
- " 4m6vsblobprodcus384.vsblob.vsassets.io"
- " 4myvsblobprodcus32.vsblob.vsassets.io"
- " 4vyvsblobprodcus361.vsblob.vsassets.io"
- " 4zjvsblobprodcus390.vsblob.vsassets.io"
- " 51yvsblobprodcus36.vsblob.vsassets.io"
- " 5dkvsblobprodcus355.vsblob.vsassets.io"
- " 5rqvsblobprodcus385.vsblob.vsassets.io"
- " 6s7vsblobprodcus313.vsblob.vsassets.io"
- " 7devsblobprodcus323.vsblob.vsassets.io"
- " 7k6vsblobprodcus337.vsblob.vsassets.io"
- " 7tjvsblobprodcus341.vsblob.vsassets.io"
- " 80zvsblobprodcus35.vsblob.vsassets.io"
- " 8xbvsblobprodcus382.vsblob.vsassets.io"
- " 96bvsblobprodcus338.vsblob.vsassets.io"
- " ajhvsblobprodcus363.vsblob.vsassets.io"
- " bcnvsblobprodcus378.vsblob.vsassets.io"
- " builds.dotnet.microsoft.com"
- " c50vsblobprodcus330.vsblob.vsassets.io"
- " c78vsblobprodcus322.vsblob.vsassets.io"
- " cflvsblobprodcus383.vsblob.vsassets.io"
- " ci.dot.net"
- " ckzvsblobprodcus347.vsblob.vsassets.io"
- " d0svsblobprodcus381.vsblob.vsassets.io"
- " data.nuget.org"
- " dlbvsblobprodcus316.vsblob.vsassets.io"
- " e7bvsblobprodcus348.vsblob.vsassets.io"
- " fdpvsblobprodcus345.vsblob.vsassets.io"
- " frdvsblobprodcus327.vsblob.vsassets.io"
- " gbsvsblobprodcus365.vsblob.vsassets.io"
- " gervsblobprodcus329.vsblob.vsassets.io"
- " h6tvsblobprodcus346.vsblob.vsassets.io"
- " i1qvsblobprodcus353.vsblob.vsassets.io"
- " imzvsblobprodcus368.vsblob.vsassets.io"
- " jd4vsblobprodcus366.vsblob.vsassets.io"
- " josvsblobprodcus372.vsblob.vsassets.io"
- " jrqvsblobprodcus343.vsblob.vsassets.io"
- " k0ivsblobprodcus356.vsblob.vsassets.io"
- " k4kvsblobprodcus344.vsblob.vsassets.io"
- " kgfvsblobprodcus314.vsblob.vsassets.io"
- " kh4vsblobprodcus325.vsblob.vsassets.io"
- " kijvsblobprodcus387.vsblob.vsassets.io"
- " kmuvsblobprodcus389.vsblob.vsassets.io"
- " kxqvsblobprodcus376.vsblob.vsassets.io"
- " l49vsblobprodcus358.vsblob.vsassets.io"
- " l7avsblobprodcus319.vsblob.vsassets.io"
- " ljcvsblobprodcus317.vsblob.vsassets.io"
- " lylvsblobprodcus31.vsblob.vsassets.io"
- " m16vsblobprodcus374.vsblob.vsassets.io"
- " m6xvsblobprodcus342.vsblob.vsassets.io"
- " m8dvsblobprodcus37.vsblob.vsassets.io"
- " mfjvsblobprodcus373.vsblob.vsassets.io"
- " n3kvsblobprodcus335.vsblob.vsassets.io"
- " nn8vsblobprodcus340.vsblob.vsassets.io"
- " o3svsblobprodcus318.vsblob.vsassets.io"
- " ofvvsblobprodcus315.vsblob.vsassets.io"
- " p2ovsblobprodcus312.vsblob.vsassets.io"
- " pc2vsblobprodcus360.vsblob.vsassets.io"
- " pdfvsblobprodcus380.vsblob.vsassets.io"
- " pe3vsblobprodcus354.vsblob.vsassets.io"
- " pe4vsblobprodcus351.vsblob.vsassets.io"
- " pkgs.dev.azure.com"
- " rcxvsblobprodcus328.vsblob.vsassets.io"
- " s4uvsblobprodcus326.vsblob.vsassets.io"
- " s8mvsblobprodcus38.vsblob.vsassets.io"
- " se1vsblobprodcus349.vsblob.vsassets.io"
- " sqdvsblobprodcus333.vsblob.vsassets.io"
- " st8vsblobprodcus339.vsblob.vsassets.io"
- " tphvsblobprodcus375.vsblob.vsassets.io"
- " u3hvsblobprodcus371.vsblob.vsassets.io"
- " u6ovsblobprodcus377.vsblob.vsassets.io"
- " ukkvsblobprodcus352.vsblob.vsassets.io"
- " uy6vsblobprodcus34.vsblob.vsassets.io"
- " v53vsblobprodcus320.vsblob.vsassets.io"
- " vb4vsblobprodcus33.vsblob.vsassets.io"
- " vwvvsblobprodcus334.vsblob.vsassets.io"
- " x3yvsblobprodcus370.vsblob.vsassets.io"
- " xupvsblobprodcus332.vsblob.vsassets.io"
- " yluvsblobprodcus367.vsblob.vsassets.io"
- " yttvsblobprodcus357.vsblob.vsassets.io"
See Network Configuration for more information.
🤖 Automated content by GitHub Copilot. Generated by the Test Improver workflow. · copilot · auto · 373 AIC · ⌖ 25.7 AIC · ⊞ 20.5K · [◷]( · ◷ )
Comment /test-assist to run again
Add this agentic workflow to your repo
To install this agentic workflow, run
gh aw add githubnext/agentics/workflows/test-improver.md@main
Goal and rationale
ServerModeManager.Build(src/Platform/Microsoft.Testing.Platform/ServerMode/JsonRpc/ServerModeManager.cs) had zero direct unit coverage. It resolves the JSON-RPC client host/port from command-line options and constructs theMessageHandlerFactoryused to connect back to the IDE/client in server mode — a small but critical wiring path (missing--client-portthrows,--client-hostdefaults to the loopback address for"localhost", and explicit host/port are passed through).Approach
Added
ServerModeManagerTests.cswith 3 tests covering all 3 branches:Build_MissingClientPortOption_Throws— verifies the documentedInvalidOperationException/PlatformResources.MissingClientPortFoJsonRpcmessage.Build_ClientPortOptionWithoutClientHost_DefaultsHostToLoopbackAddress— verifies the"localhost"→127.0.0.1substitution (worked around a known slow-DNS-resolve issue).Build_ClientPortAndClientHostOptions_UsesProvidedHostAndPort— verifies explicit host/port pass-through.Constructed a real
CommandLineHandlerviaCommandLineParser.Parse(same pattern as the existingDotnetTestHelperTests.cs/CommandLineHandlerTests.cs), and aServiceProviderwith mockedILoggerFactory/IOutputDevice. Since_host/_porton the returnedMessageHandlerFactoryare private, they're asserted via reflection.Also added the missing
PlatformResources.MissingClientPortFoJsonRpchand-maintained accessor to theIS_MTP_UNIT_TESTSblock inPlatformResources.cs(required so the unit test project can read the exact resource string — no other API surface changed).Coverage impact
Microsoft.Testing.Platform.UnitTestsnet8.0 suite: 2648 total (was 2645 onmain, +3 new tests), 0 failed, 22 skipped (pre-existing).Trade-offs
Small reflection use for private-field assertions is consistent with several existing tests in this project (e.g.
DotnetTestDataConsumerTests.cs). No new dependencies, no behavior changes.Reproducibility
Test Status
Build succeeded (0 warnings/errors). Full suite passed as noted above.
dotnet format whitespace TestFx.slnx --verify-no-changes --include <files>clean (only the expected harmless F#-project warning).Note
This was originally intended as a pull request, but the git push operation failed.
Original error: The process '/usr/bin/git' failed with exit code 128
Workflow Run: View run details and download bundle artifact
The bundle file is available in the
agentartifact in the workflow run linked above.Create the pull request manually
Warning
Firewall blocked 90 domains
The following domains were blocked by the firewall during workflow execution:
0t3vsblobprodcus362.vsblob.vsassets.io11vvsblobprodcus336.vsblob.vsassets.io1javsblobprodcus364.vsblob.vsassets.io1k9vsblobprodcus379.vsblob.vsassets.io1oavsblobprodcus350.vsblob.vsassets.io1p7vsblobprodcus324.vsblob.vsassets.io1s1vsblobprodcus386.vsblob.vsassets.io2kmvsblobprodcus39.vsblob.vsassets.io2zrvsblobprodcus388.vsblob.vsassets.io37bvsblobprodcus311.vsblob.vsassets.io37cvsblobprodcus359.vsblob.vsassets.io4m6vsblobprodcus384.vsblob.vsassets.io4myvsblobprodcus32.vsblob.vsassets.io4vyvsblobprodcus361.vsblob.vsassets.io4zjvsblobprodcus390.vsblob.vsassets.io51yvsblobprodcus36.vsblob.vsassets.io5dkvsblobprodcus355.vsblob.vsassets.io5rqvsblobprodcus385.vsblob.vsassets.io6s7vsblobprodcus313.vsblob.vsassets.io7devsblobprodcus323.vsblob.vsassets.io7k6vsblobprodcus337.vsblob.vsassets.io7tjvsblobprodcus341.vsblob.vsassets.io80zvsblobprodcus35.vsblob.vsassets.io8xbvsblobprodcus382.vsblob.vsassets.io96bvsblobprodcus338.vsblob.vsassets.ioajhvsblobprodcus363.vsblob.vsassets.iobcnvsblobprodcus378.vsblob.vsassets.iobuilds.dotnet.microsoft.comc50vsblobprodcus330.vsblob.vsassets.ioc78vsblobprodcus322.vsblob.vsassets.iocflvsblobprodcus383.vsblob.vsassets.ioci.dot.netckzvsblobprodcus347.vsblob.vsassets.iod0svsblobprodcus381.vsblob.vsassets.iodata.nuget.orgdlbvsblobprodcus316.vsblob.vsassets.ioe7bvsblobprodcus348.vsblob.vsassets.iofdpvsblobprodcus345.vsblob.vsassets.iofrdvsblobprodcus327.vsblob.vsassets.iogbsvsblobprodcus365.vsblob.vsassets.iogervsblobprodcus329.vsblob.vsassets.ioh6tvsblobprodcus346.vsblob.vsassets.ioi1qvsblobprodcus353.vsblob.vsassets.ioimzvsblobprodcus368.vsblob.vsassets.iojd4vsblobprodcus366.vsblob.vsassets.iojosvsblobprodcus372.vsblob.vsassets.iojrqvsblobprodcus343.vsblob.vsassets.iok0ivsblobprodcus356.vsblob.vsassets.iok4kvsblobprodcus344.vsblob.vsassets.iokgfvsblobprodcus314.vsblob.vsassets.iokh4vsblobprodcus325.vsblob.vsassets.iokijvsblobprodcus387.vsblob.vsassets.iokmuvsblobprodcus389.vsblob.vsassets.iokxqvsblobprodcus376.vsblob.vsassets.iol49vsblobprodcus358.vsblob.vsassets.iol7avsblobprodcus319.vsblob.vsassets.ioljcvsblobprodcus317.vsblob.vsassets.iolylvsblobprodcus31.vsblob.vsassets.iom16vsblobprodcus374.vsblob.vsassets.iom6xvsblobprodcus342.vsblob.vsassets.iom8dvsblobprodcus37.vsblob.vsassets.iomfjvsblobprodcus373.vsblob.vsassets.ion3kvsblobprodcus335.vsblob.vsassets.ionn8vsblobprodcus340.vsblob.vsassets.ioo3svsblobprodcus318.vsblob.vsassets.ioofvvsblobprodcus315.vsblob.vsassets.iop2ovsblobprodcus312.vsblob.vsassets.iopc2vsblobprodcus360.vsblob.vsassets.iopdfvsblobprodcus380.vsblob.vsassets.iope3vsblobprodcus354.vsblob.vsassets.iope4vsblobprodcus351.vsblob.vsassets.iopkgs.dev.azure.comrcxvsblobprodcus328.vsblob.vsassets.ios4uvsblobprodcus326.vsblob.vsassets.ios8mvsblobprodcus38.vsblob.vsassets.iose1vsblobprodcus349.vsblob.vsassets.iosqdvsblobprodcus333.vsblob.vsassets.iost8vsblobprodcus339.vsblob.vsassets.iotphvsblobprodcus375.vsblob.vsassets.iou3hvsblobprodcus371.vsblob.vsassets.iou6ovsblobprodcus377.vsblob.vsassets.ioukkvsblobprodcus352.vsblob.vsassets.iouy6vsblobprodcus34.vsblob.vsassets.iov53vsblobprodcus320.vsblob.vsassets.iovb4vsblobprodcus33.vsblob.vsassets.iovwvvsblobprodcus334.vsblob.vsassets.iox3yvsblobprodcus370.vsblob.vsassets.ioxupvsblobprodcus332.vsblob.vsassets.ioyluvsblobprodcus367.vsblob.vsassets.ioyttvsblobprodcus357.vsblob.vsassets.ioTo allow these domains, add them to the
network.allowedlist in your workflow frontmatter:See Network Configuration for more information.
Add this agentic workflow to your repo
To install this agentic workflow, run