From d28a171e780e885f2a865782618038037a54ea99 Mon Sep 17 00:00:00 2001 From: Pranav Senthilnathan Date: Wed, 29 Jul 2026 12:11:16 -0700 Subject: [PATCH] Speed up CLI argument escaping tests Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 323a2062-9493-4be4-a710-f6c2b9e15a49 --- .../Program.cs | 7 +++ .../Transport/StdioClientTransportTests.cs | 43 ++++++++++++------- 2 files changed, 34 insertions(+), 16 deletions(-) diff --git a/tests/ModelContextProtocol.TestServer/Program.cs b/tests/ModelContextProtocol.TestServer/Program.cs index d04f2167a..6812fe5d5 100644 --- a/tests/ModelContextProtocol.TestServer/Program.cs +++ b/tests/ModelContextProtocol.TestServer/Program.cs @@ -34,6 +34,13 @@ private static ILoggerFactory CreateLoggerFactory() private static async Task Main(string[] args) { + if (args.Contains("--echo-cli-arg-and-exit")) + { + Console.Error.WriteLine($"CLI_ARG:{JsonSerializer.Serialize(ParseCliArgument(args))}"); + Console.Error.Flush(); + return; + } + Log.Logger.Information("Starting server..."); string? cliArg = ParseCliArgument(args); diff --git a/tests/ModelContextProtocol.Tests/Transport/StdioClientTransportTests.cs b/tests/ModelContextProtocol.Tests/Transport/StdioClientTransportTests.cs index a709688b4..60ce9cf5a 100644 --- a/tests/ModelContextProtocol.Tests/Transport/StdioClientTransportTests.cs +++ b/tests/ModelContextProtocol.Tests/Transport/StdioClientTransportTests.cs @@ -152,7 +152,9 @@ public async Task EscapesCliArgumentsCorrectly(string? cliArgumentValue) { Assert.Skip("mono runtime does not handle arguments ending with backslash correctly."); } - + + const string OutputPrefix = "CLI_ARG:"; + var capturedArgument = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); string cliArgument = $"--cli-arg={cliArgumentValue}"; string testServerExecutable = Path.Combine(AppContext.BaseDirectory, "TestServer.exe"); string testServerDll = Path.Combine(AppContext.BaseDirectory, "TestServer.dll"); @@ -168,25 +170,34 @@ public async Task EscapesCliArgumentsCorrectly(string? cliArgumentValue) }, Arguments = (PlatformDetection.IsMonoRuntime, PlatformDetection.IsWindows) switch { - (true, _) => [testServerExecutable, cliArgument], - (_, true) => [cliArgument], - _ => [testServerDll, cliArgument], + (true, _) => [testServerExecutable, "--echo-cli-arg-and-exit", cliArgument], + (_, true) => ["--echo-cli-arg-and-exit", cliArgument], + _ => [testServerDll, "--echo-cli-arg-and-exit", cliArgument], + }, + StandardErrorLines = line => + { + if (line.StartsWith(OutputPrefix, StringComparison.Ordinal)) + { + capturedArgument.TrySetResult(line[OutputPrefix.Length..]); + } }, }; var transport = new StdioClientTransport(options, LoggerFactory); - - // Act: Create client (handshake) and list tools to ensure full round trip works with the argument present. - await using var client = await McpClient.CreateAsync(transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken); - var tools = await client.ListToolsAsync(cancellationToken: TestContext.Current.CancellationToken); - - // Assert - Assert.NotNull(tools); - Assert.NotEmpty(tools); - - var result = await client.CallToolAsync("echoCliArg", cancellationToken: TestContext.Current.CancellationToken); - var content = Assert.IsType(Assert.Single(result.Content)); - Assert.Equal(cliArgumentValue ?? "", content.Text); + await using var session = await transport.ConnectAsync(TestContext.Current.CancellationToken); + + string serializedArgument = await capturedArgument.Task.WaitAsync( + TestConstants.DefaultTimeout, + TestContext.Current.CancellationToken); + JsonElement parsedArgument = JsonElement.Parse(serializedArgument); + Assert.Equal(cliArgumentValue ?? "", parsedArgument.GetString()); + + var exception = await Assert.ThrowsAsync( + async () => await session.MessageReader.Completion.WaitAsync( + TestConstants.DefaultTimeout, + TestContext.Current.CancellationToken)); + var completionDetails = Assert.IsType(exception.Details); + Assert.Equal(0, completionDetails.ExitCode); } [Fact(Skip = "Platform not supported by this test.", SkipUnless = nameof(IsStdErrCallbackSupported))]