Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -735,6 +735,9 @@ private async Task<bool> IsRedisRunningAsync()

private async Task RunSampleTestAsync(string samplePath, Func<Process, BlockingCollection<OutputLog>, Task> testAction)
{
// Build the sample project first (it may not have been built as part of the solution)
await this.BuildSampleAsync(samplePath);

Comment on lines +739 to +740
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new build step runs before the per-test timeout/cancellation used by the sample validation logic. If dotnet build hangs (e.g., restore stall, MSBuild issue), these tests may never time out and can wedge CI. Consider threading a CancellationToken into RunSampleTestAsync/BuildSampleAsync (or using a dedicated build timeout) and passing it to WaitForExitAsync(token).

Suggested change
await this.BuildSampleAsync(samplePath);
TimeSpan buildTimeout = TimeSpan.FromMinutes(5);
Task buildTask = this.BuildSampleAsync(samplePath);
if (await Task.WhenAny(buildTask, Task.Delay(buildTimeout)) != buildTask)
{
throw new TimeoutException($"Building sample at '{samplePath}' exceeded timeout of {buildTimeout}.");
}
await buildTask;

Copilot uses AI. Check for mistakes.
// Generate a unique TaskHub name for this sample test to prevent cross-test interference
// when multiple tests run together and share the same DTS emulator.
string uniqueTaskHubName = $"sample-{Guid.NewGuid().ToString("N").Substring(0, 6)}";
Expand Down Expand Up @@ -813,12 +816,39 @@ private async Task WriteInputAsync(Process process, string input, CancellationTo
return null;
}

private async Task BuildSampleAsync(string samplePath)
{
this._outputHelper.WriteLine($"Building sample at {samplePath}...");

ProcessStartInfo buildInfo = new()
{
FileName = "dotnet",
Arguments = $"build --framework {s_dotnetTargetFramework}",
WorkingDirectory = samplePath,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
};

using Process buildProcess = new() { StartInfo = buildInfo };
buildProcess.Start();
await buildProcess.WaitForExitAsync();

if (buildProcess.ExitCode != 0)
{
string stderr = await buildProcess.StandardError.ReadToEndAsync();
throw new InvalidOperationException($"Failed to build sample at {samplePath}: {stderr}");
Comment on lines +835 to +840
Copy link

Copilot AI Feb 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BuildSampleAsync redirects stdout/stderr but never drains stdout (and only reads stderr after the process exits). If dotnet build produces enough output, the child process can block on a full pipe and WaitForExitAsync() can hang the test run. Consider either not redirecting stdout/stderr, or asynchronously reading both streams (and including the output in the failure message/logs).

Suggested change
await buildProcess.WaitForExitAsync();
if (buildProcess.ExitCode != 0)
{
string stderr = await buildProcess.StandardError.ReadToEndAsync();
throw new InvalidOperationException($"Failed to build sample at {samplePath}: {stderr}");
Task<string> standardOutputTask = buildProcess.StandardOutput.ReadToEndAsync();
Task<string> standardErrorTask = buildProcess.StandardError.ReadToEndAsync();
await Task.WhenAll(buildProcess.WaitForExitAsync(), standardOutputTask, standardErrorTask);
if (buildProcess.ExitCode != 0)
{
string stdout = await standardOutputTask;
string stderr = await standardErrorTask;
throw new InvalidOperationException(
$"Failed to build sample at {samplePath}:{Environment.NewLine}" +
$"STDOUT:{Environment.NewLine}{stdout}{Environment.NewLine}" +
$"STDERR:{Environment.NewLine}{stderr}");

Copilot uses AI. Check for mistakes.
}

this._outputHelper.WriteLine($"Build completed for {samplePath}.");
}

private Process StartConsoleApp(string samplePath, BlockingCollection<OutputLog> logs, string taskHubName)
{
ProcessStartInfo startInfo = new()
{
FileName = "dotnet",
Arguments = $"run --framework {s_dotnetTargetFramework}",
Arguments = $"run --no-build --framework {s_dotnetTargetFramework}",
WorkingDirectory = samplePath,
UseShellExecute = false,
RedirectStandardOutput = true,
Expand Down
Loading