Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix build host when only the .net 6 SDK is installed #73818

Merged
merged 3 commits into from
Jun 5, 2024
Merged
Show file tree
Hide file tree
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
16 changes: 15 additions & 1 deletion src/Tools/PrepareTests/TestDiscovery.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using System.IO.Pipes;
using System.Threading.Tasks;
using System.Threading;
using System.Text;

namespace PrepareTests;
internal class TestDiscovery
Expand Down Expand Up @@ -85,14 +86,22 @@ static bool RunWorker(string dotnetPath, string pathToWorker, string pathToAssem
pipeClient.StartInfo.FileName = pathToWorker;
}

var errorOutput = new StringBuilder();

using (var pipeServer = new AnonymousPipeServerStream(PipeDirection.Out, HandleInheritability.Inheritable))
{
// Pass the client process a handle to the server.
arguments.Add(pipeServer.GetClientHandleAsString());
pipeClient.StartInfo.Arguments = string.Join(" ", arguments);
pipeClient.StartInfo.UseShellExecute = false;

// Errors will be logged to stderr, redirect to us so we can capture it.
Copy link
Member Author

Choose a reason for hiding this comment

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

errors were getting swallowed so it was just failing with no info. this ensures error output from the discovery worker is captured

pipeClient.StartInfo.RedirectStandardError = true;
pipeClient.ErrorDataReceived += PipeClient_ErrorDataReceived;
pipeClient.Start();

pipeClient.BeginErrorReadLine();

pipeServer.DisposeLocalCopyOfClientHandle();

try
Expand Down Expand Up @@ -120,10 +129,15 @@ static bool RunWorker(string dotnetPath, string pathToWorker, string pathToAssem

if (!success)
{
Console.WriteLine($"Failed to discover tests in {pathToAssembly}");
Console.WriteLine($"Failed to discover tests in {pathToAssembly}:{Environment.NewLine}{errorOutput}");
}

return success;

void PipeClient_ErrorDataReceived(object sender, DataReceivedEventArgs e)
{
errorOutput.AppendLine(e.Data);
}
}

private static List<string> GetAssemblies(string binDirectory, bool isUnix)
Expand Down
105 changes: 57 additions & 48 deletions src/Tools/TestDiscoveryWorker/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,76 +24,85 @@
return ExitFailure;
}

using var pipeClient = new AnonymousPipeClientStream(PipeDirection.In, args[0]);
using var sr = new StreamReader(pipeClient);
string? output;

// Wait for 'sync message' from the server.
do
try
Copy link
Member Author

Choose a reason for hiding this comment

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

similar change to ensure exception details are captured if something goes wrong.

{
output = await sr.ReadLineAsync().ConfigureAwait(false);
}
while (!(output?.StartsWith("ASSEMBLY", StringComparison.OrdinalIgnoreCase) == true));
using var pipeClient = new AnonymousPipeClientStream(PipeDirection.In, args[0]);
using var sr = new StreamReader(pipeClient);
string? output;

if ((output = await sr.ReadLineAsync().ConfigureAwait(false)) is not null)
{
var assemblyFileName = output;
// Wait for 'sync message' from the server.
do
{
output = await sr.ReadLineAsync().ConfigureAwait(false);
}
while (!(output?.StartsWith("ASSEMBLY", StringComparison.OrdinalIgnoreCase) == true));

#if NET6_0_OR_GREATER
var resolver = new System.Runtime.Loader.AssemblyDependencyResolver(assemblyFileName);
System.Runtime.Loader.AssemblyLoadContext.Default.Resolving += (context, assemblyName) =>
if ((output = await sr.ReadLineAsync().ConfigureAwait(false)) is not null)
{
var assemblyPath = resolver.ResolveAssemblyToPath(assemblyName);
if (assemblyPath is not null)
var assemblyFileName = output;

#if NET6_0_OR_GREATER
var resolver = new System.Runtime.Loader.AssemblyDependencyResolver(assemblyFileName);
System.Runtime.Loader.AssemblyLoadContext.Default.Resolving += (context, assemblyName) =>
{
return context.LoadFromAssemblyPath(assemblyPath);
}
var assemblyPath = resolver.ResolveAssemblyToPath(assemblyName);
if (assemblyPath is not null)
{
return context.LoadFromAssemblyPath(assemblyPath);
}

return null;
};
return null;
};
#endif

string testDescriptor = Path.GetFileName(assemblyFileName);
string testDescriptor = Path.GetFileName(assemblyFileName);
#if NET
testDescriptor += " (.NET Core)";
testDescriptor += " (.NET Core)";
#else
testDescriptor += " (.NET Framework)";
#endif

await Console.Out.WriteLineAsync($"Discovering tests in {testDescriptor}...").ConfigureAwait(false);
await Console.Out.WriteLineAsync($"Discovering tests in {testDescriptor}...").ConfigureAwait(false);

using var xunit = new XunitFrontController(AppDomainSupport.IfAvailable, assemblyFileName, shadowCopy: false);
var configuration = ConfigReader.Load(assemblyFileName);
var sink = new Sink();
xunit.Find(includeSourceInformation: false,
messageSink: sink,
discoveryOptions: TestFrameworkOptions.ForDiscovery(configuration));
using var xunit = new XunitFrontController(AppDomainSupport.IfAvailable, assemblyFileName, shadowCopy: false);
var configuration = ConfigReader.Load(assemblyFileName);
var sink = new Sink();
xunit.Find(includeSourceInformation: false,
messageSink: sink,
discoveryOptions: TestFrameworkOptions.ForDiscovery(configuration));

var testsToWrite = new HashSet<string>();
await foreach (var fullyQualifiedName in sink.GetTestCaseNamesAsync())
{
testsToWrite.Add(fullyQualifiedName);
}
var testsToWrite = new HashSet<string>();
await foreach (var fullyQualifiedName in sink.GetTestCaseNamesAsync())
{
testsToWrite.Add(fullyQualifiedName);
}

if (sink.AnyWriteFailures)
{
await Console.Error.WriteLineAsync($"Channel failed to write for '{assemblyFileName}'").ConfigureAwait(false);
return ExitFailure;
}
if (sink.AnyWriteFailures)
{
await Console.Error.WriteLineAsync($"Channel failed to write for '{assemblyFileName}'").ConfigureAwait(false);
return ExitFailure;
}

#if NET6_0_OR_GREATER
await Console.Out.WriteLineAsync($"Discovered {testsToWrite.Count} tests in {testDescriptor}").ConfigureAwait(false);
await Console.Out.WriteLineAsync($"Discovered {testsToWrite.Count} tests in {testDescriptor}").ConfigureAwait(false);
#else
await Console.Out.WriteLineAsync($"Discovered {testsToWrite.Count} tests in {testDescriptor}").ConfigureAwait(false);
await Console.Out.WriteLineAsync($"Discovered {testsToWrite.Count} tests in {testDescriptor}").ConfigureAwait(false);
#endif

var directory = Path.GetDirectoryName(assemblyFileName);
using var fileStream = File.Create(Path.Combine(directory!, "testlist.json"));
await JsonSerializer.SerializeAsync(fileStream, testsToWrite).ConfigureAwait(false);
return ExitSuccess;
}
var directory = Path.GetDirectoryName(assemblyFileName);
using var fileStream = File.Create(Path.Combine(directory!, "testlist.json"));
await JsonSerializer.SerializeAsync(fileStream, testsToWrite).ConfigureAwait(false);
return ExitSuccess;
}

return ExitFailure;
return ExitFailure;
}
catch (Exception ex)
{
// Write the exception details to stderr so the host process can pick it up.
await Console.Error.WriteLineAsync(ex.ToString()).ConfigureAwait(false);
return 1;
}

file class Sink : IMessageSink
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,9 @@
<PackageReference Include="Microsoft.Build.Tasks.Core" VersionOverride="17.3.2" ExcludeAssets="Runtime" PrivateAssets="All" />
<PackageReference Include="Microsoft.Build.Locator" PrivateAssets="All" />
<PackageReference Include="System.CommandLine" />
<PackageReference Include="System.Collections.Immutable" />
<PackageReference Include="Newtonsoft.Json" />
<PackageReference Include="System.Threading.Tasks.Extensions" Condition="'$(TargetFrameworkIdentifier)' != '.NETCoreApp'" />
dibarbet marked this conversation as resolved.
Show resolved Hide resolved
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\..\Compilers\Core\Portable\InternalUtilities\*.cs" Link="InternalUtilities\%(FileName).cs" />
Expand Down
Loading