8000 Add more gRPC interop test logging (#61532) · dotnet/aspnetcore@bd6f77d · GitHub
[go: up one dir, main page]

Skip to content

Commit bd6f77d

Browse files
authored
Add more gRPC interop test logging (#61532)
1 parent 9f2b088 commit bd6f77d

File tree

4 files changed

+81
-2
lines changed

4 files changed

+81
-2
lines changed

src/Grpc/Interop/test/InteropTests/Helpers/ClientProcess.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ public ClientProcess(ITestOutputHelper output, string path, string serverPort, s
3131
_process.EnableRaisingEvents = true;
3232
_process.OutputDataReceived += Process_OutputDataReceived;
3333
_process.ErrorDataReceived += Process_ErrorDataReceived;
34+
35+
output.WriteLine($"Starting process: {ProcessDebugHelper.GetDebugCommand(_process.StartInfo)}");
3436
_process.Start();
3537

3638
_processEx = new ProcessEx(output, _process, timeout: Timeout.InfiniteTimeSpan);
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.Diagnostics;
5+
6+
namespace InteropTests.Helpers;
7+
8+
public static class ProcessDebugHelper
9+
{
10+
public static string GetDebugCommand(ProcessStartInfo psi)
11+
{
12+
// Quote the file name if it contains spaces or special characters
13+
var fileName = QuoteIfNeeded(psi.FileName);
14+
15+
// Arguments are typically already passed as a single string
16+
var arguments = psi.Arguments;
17+
18+
return $"{fileName} {arguments}".Trim();
19+
}
20+
21+
private static string QuoteIfNeeded(string value)
22+
{
23+
if (string.IsNullOrWhiteSpace(value))
24+
{
25+
return "\"\"";
26+
}
27+
28+
// Add quotes if value contains spaces or special characters
29+
if (value.Contains(' ') || value.Contains('"'))
30+
{
31+
return $"\"{value.Replace("\"", "\\\"")}\"";
32+
}
33+
34+
return value;
35+
}
36+
}

src/Grpc/Interop/test/InteropTests/Helpers/WebsiteProcess.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ public WebsiteProcess(string path, ITestOutputHelper output)
3636
_process.EnableRaisingEvents = true;
3737
_process.OutputDataReceived += Process_OutputDataReceived;
3838
_process.ErrorDataReceived += Process_ErrorDataReceived;
39+
40+
output.WriteLine($"Starting process: {ProcessDebugHelper.GetDebugCommand(_process.StartInfo)}");
3941
_process.Start();
4042

4143
_processEx = new ProcessEx(output, _process, Timeout.InfiniteTimeSpan);

src/Grpc/Interop/test/InteropTests/InteropTests.cs

Lines changed: 41 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ namespace InteropTests;
99

1010
// All interop test cases, minus GCE authentication specific tests.
1111
// Tests are separate methods so that they can be quarantined separately.
12+
[Retry]
1213
public class InteropTests
1314
{
1415
private static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(100);
@@ -83,13 +84,48 @@ public InteropTests(ITestOutputHelper output)
8384

8485
private async Task InteropTestCase(string name)
8586
{
87+
// Building interop tests processes can be flaky. Sometimes it times out.
88+
// To mitigate this, we retry the test case a few times on timeout.
89+
const int maxRetries = 3;
90+
var attempt = 0;
91+
92+
while (true)
93+
{
94+
attempt++;
95+
96+
try
97+
{
98+
await InteropTestCaseCore(name);
99+
break; // Exit loop on success
100+
}
101+
catch (TimeoutException ex)
102+
{
103+
_output.WriteLine($"Attempt {attempt} failed: {ex.Message}");
104+
105+
if (attempt == maxRetries)
106+
{
107+
_output.WriteLine("Maximum retry attempts reached. Giving up.");
108+
throw;
109+
}
110+
else
111+
{
112+
await Task.Delay(TimeSpan.FromSeconds(1));
113+
}
114+
}
115+
}
116+
}
117+
118+
private async Task InteropTestCaseCore(string name)
119+
{
120+
_output.WriteLine($"Starting {nameof(WebsiteProcess)}.");
86121
using (var serverProcess = new WebsiteProcess(_serverPath, _output))
87122
{
88123
try
89124
{
125+
_output.WriteLine($"Waiting for {nameof(WebsiteProcess)} to be ready.");
90126
await serverProcess.WaitForReady().TimeoutAfter(DefaultTimeout);
91127
}
92-
catch (Exception ex)
128+
catch (Exception ex) when (ex is not TimeoutException)
93129
{
94130
var errorMessage = $@"Error while running server process.
95131
@@ -102,17 +138,20 @@ private async Task InteropTestCase(string name)
102138
throw new InvalidOperationException(errorMessage, ex);
103139
}
104140

141+
_output.WriteLine($"Starting {nameof(ClientProcess)}.");
105142
using (var clientProcess = new ClientProcess(_output, _clientPath, serverProcess.ServerPort, name))
106143
{
107144
try
108145
{
146+
_output.WriteLine($"Waiting for {nameof(ClientProcess)} to be ready.");
109147
await clientProcess.WaitForReadyAsync().TimeoutAfter(DefaultTimeout);
110148

149+
_output.WriteLine($"Waiting for {nameof(ClientProcess)} to exit.");
111150
await clientProcess.WaitForExitAsync().TimeoutAfter(DefaultTimeout);
112151

113152
Assert.Equal(0, clientProcess.ExitCode);
114153
}
115-
catch (Exception ex)
154+
catch (Exception ex) when (ex is not TimeoutException)
116155
{
117156
var errorMessage = $@"Error while running client process.
118157

0 commit comments

Comments
 (0)
0