Skip to content

Commit

Permalink
Add runtime trait for skipping test based on .NET using a Mono or Cor…
Browse files Browse the repository at this point in the history
…eCLR runtime.
  • Loading branch information
tmds authored and omajid committed Jun 14, 2023
1 parent c332f7e commit 467aca7
Show file tree
Hide file tree
Showing 6 changed files with 88 additions and 19 deletions.
16 changes: 10 additions & 6 deletions Turkey.Tests/ProgramTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -55,29 +55,33 @@ public static IEnumerable<object[]> SystemTraits_MemberData()
string expectedArch = $"arch={OSArchitectureName}";

// default traits.
yield return new object[] { runtimeVersion, sdkVersion, Array.Empty<string>(), Array.Empty<string>(), CombineTraits() };
yield return new object[] { runtimeVersion, sdkVersion, Array.Empty<string>(), false, Array.Empty<string>(), CombineTraits() };

// 'runtime=mono'
yield return new object[] { runtimeVersion, sdkVersion, Array.Empty<string>(), true, Array.Empty<string>(), CombineTraits(isMonoRuntime: true) };

// 'os=..' and 'rid=...' are added for the platform rids.
yield return new object[] { runtimeVersion, sdkVersion, new[] { "linux-x64", "fedora.37-x64", "linux-musl-x64" }, Array.Empty<string>(),
yield return new object[] { runtimeVersion, sdkVersion, new[] { "linux-x64", "fedora.37-x64", "linux-musl-x64" }, false, Array.Empty<string>(),
CombineTraits(new[] { "os=linux", "os=fedora.37", "os=linux-musl",
"rid=linux-x64", "rid=fedora.37-x64", "rid=linux-musl-x64" } ) };

// additional traits are added.
yield return new object[] { runtimeVersion, sdkVersion, Array.Empty<string>(), new[] { "blue", "green" },
yield return new object[] { runtimeVersion, sdkVersion, Array.Empty<string>(), false, new[] { "blue", "green" },
CombineTraits(new[] { "blue", "green" } ) };

string[] CombineTraits(string[] expectedAdditionalTraits = null)
string[] CombineTraits(string[] expectedAdditionalTraits = null, bool isMonoRuntime = false)
=> expectedVersionTraits
.Concat(new[] { expectedArch })
.Concat(isMonoRuntime ? new[] { "runtime=mono" } : new[] { "runtime=coreclr" })
.Concat(expectedAdditionalTraits ?? Array.Empty<string>())
.ToArray();
}

[Theory]
[MemberData(nameof(SystemTraits_MemberData))]
public void SystemTraits(Version runtimeVersion, Version sdkVersion, string[] rids, string[] additionalTraits, string[] expectedTraits)
public void SystemTraits(Version runtimeVersion, Version sdkVersion, string[] rids, bool isMonoRuntime, string[] additionalTraits, string[] expectedTraits)
{
IReadOnlySet<string> systemTraits = Program.CreateTraits(runtimeVersion, sdkVersion, new List<string>(rids), additionalTraits);
IReadOnlySet<string> systemTraits = Program.CreateTraits(runtimeVersion, sdkVersion, new List<string>(rids), isMonoRuntime, additionalTraits);

Assert.Equal(expectedTraits.OrderBy(s => s), systemTraits.OrderBy(s => s));
}
Expand Down
9 changes: 8 additions & 1 deletion Turkey.Tests/TestParserTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ public class TestParserTests
public void DisabledTestShouldBeSkipped()
{
TestParser parser = new TestParser();
SystemUnderTest system = new SystemUnderTest(null, null, null, null, null);
SystemUnderTest system = new SystemUnderTest(null, null, null, null, null, null);
TestDescriptor test = new TestDescriptor()
{
Enabled = false,
Expand All @@ -40,6 +40,7 @@ public void TestShouldBeRunForSameOrHigherVersions(string version, bool expected
{
TestParser parser = new TestParser();
SystemUnderTest system = new SystemUnderTest(
dotnet: null,
runtimeVersion: Version.Parse(version),
sdkVersion: null,
platformIds: new List<string>(),
Expand Down Expand Up @@ -76,6 +77,7 @@ public void VersionSpecificTestShouldBeRunForSameMajorMinorVersion(string versio
{
TestParser parser = new TestParser();
SystemUnderTest system = new SystemUnderTest(
dotnet: null,
runtimeVersion: Version.Parse(version),
sdkVersion: null,
platformIds: new List<string>(),
Expand Down Expand Up @@ -114,6 +116,7 @@ public void VersionSpecificTestWithWildcardShouldBeRunForSameMajorVersion(string
{
TestParser parser = new TestParser();
SystemUnderTest system = new SystemUnderTest(
dotnet: null,
runtimeVersion: Version.Parse(version),
sdkVersion: null,
platformIds: new List<string>(),
Expand All @@ -137,6 +140,7 @@ public void MissingIgnoredRIDsIsOkay()
{
TestParser parser = new TestParser();
SystemUnderTest system = new SystemUnderTest(
dotnet: null,
runtimeVersion: Version.Parse("2.1"),
sdkVersion: null,
platformIds: new string[] { "linux" }.ToList(),
Expand Down Expand Up @@ -166,6 +170,7 @@ public void TestShouldNotRunOnIgnoredPlatforms(string[] currentPlatforms, string
{
TestParser parser = new TestParser();
SystemUnderTest system = new SystemUnderTest(
dotnet: null,
runtimeVersion: Version.Parse("2.1"),
sdkVersion: null,
platformIds: currentPlatforms.ToList(),
Expand All @@ -192,6 +197,7 @@ public void SdkTestsShouldRunOnlyWithSdk(string sdkVersion, bool requiresSdk, bo
{
TestParser parser = new TestParser();
SystemUnderTest system = new SystemUnderTest(
dotnet: null,
runtimeVersion: Version.Parse("3.1"),
sdkVersion: Version.Parse(sdkVersion),
platformIds: new List<string>(),
Expand Down Expand Up @@ -250,6 +256,7 @@ public void SkipTestForTraits(string[] systemTraits, string[] skipWhen, bool exp
TestParser parser = new TestParser();

SystemUnderTest system = new SystemUnderTest(
dotnet: null,
runtimeVersion: Version.Parse("3.1"),
sdkVersion: null,
platformIds: null,
Expand Down
65 changes: 58 additions & 7 deletions Turkey/DotNet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,29 @@ namespace Turkey
{
public class DotNet
{
private string _dotnetPath;

public DotNet()
{
_dotnetPath = FindProgramInPath("dotnet");
if (_dotnetPath is not null)
{
// resolve link target.
_dotnetPath = new FileInfo(_dotnetPath).ResolveLinkTarget(returnFinalTarget: true)?.FullName ?? _dotnetPath;
}
}

private string DotnetFileName => _dotnetPath ?? throw new FileNotFoundException("dotnet");

private string DotnetRoot => Path.GetDirectoryName(DotnetFileName);

public List<Version> RuntimeVersions
{
get
{
ProcessStartInfo startInfo = new ProcessStartInfo()
{
FileName = "dotnet",
FileName = DotnetFileName,
RedirectStandardOutput = true,
RedirectStandardError = true,
Arguments = "--list-runtimes",
Expand Down Expand Up @@ -45,13 +61,16 @@ public Version LatestRuntimeVersion
}
}

public bool IsMonoRuntime(Version runtimeVersion)
=> IsMonoRuntime(DotnetRoot, runtimeVersion);

public List<Version> SdkVersions
{
get
{
ProcessStartInfo startInfo = new ProcessStartInfo()
{
FileName = "dotnet",
FileName = DotnetFileName,
RedirectStandardOutput = true,
RedirectStandardError = true,
Arguments = "--list-sdks",
Expand Down Expand Up @@ -79,7 +98,7 @@ public Version LatestSdkVersion
}
}

public static Task<int> BuildAsync(DirectoryInfo workingDirectory, IReadOnlyDictionary<string, string> environment, Action<string> logger, CancellationToken token)
public Task<int> BuildAsync(DirectoryInfo workingDirectory, IReadOnlyDictionary<string, string> environment, Action<string> logger, CancellationToken token)
{
var arguments = new string[]
{
Expand All @@ -91,18 +110,18 @@ public static Task<int> BuildAsync(DirectoryInfo workingDirectory, IReadOnlyDict
return RunDotNetCommandAsync(workingDirectory, arguments, environment, logger, token);
}

public static Task<int> RunAsync(DirectoryInfo workingDirectory, IReadOnlyDictionary<string, string> environment, Action<string> logger, CancellationToken token)
public Task<int> RunAsync(DirectoryInfo workingDirectory, IReadOnlyDictionary<string, string> environment, Action<string> logger, CancellationToken token)
=> RunDotNetCommandAsync(workingDirectory, new string[] { "run", "--no-restore", "--no-build"} , environment, logger, token);

public static Task<int> TestAsync(DirectoryInfo workingDirectory, IReadOnlyDictionary<string, string> environment, Action<string> logger, CancellationToken token)
public Task<int> TestAsync(DirectoryInfo workingDirectory, IReadOnlyDictionary<string, string> environment, Action<string> logger, CancellationToken token)
=> RunDotNetCommandAsync(workingDirectory, new string[] { "test", "--no-restore", "--no-build"} , environment, logger, token);

private static async Task<int> RunDotNetCommandAsync(DirectoryInfo workingDirectory, string[] commands, IReadOnlyDictionary<string, string> environment, Action<string> logger, CancellationToken token)
private async Task<int> RunDotNetCommandAsync(DirectoryInfo workingDirectory, string[] commands, IReadOnlyDictionary<string, string> environment, Action<string> logger, CancellationToken token)
{
var arguments = string.Join(" ", commands);
ProcessStartInfo startInfo = new ProcessStartInfo()
{
FileName = "dotnet",
FileName = DotnetFileName,
Arguments = arguments,
WorkingDirectory = workingDirectory.FullName,
RedirectStandardOutput = true,
Expand All @@ -117,5 +136,37 @@ private static async Task<int> RunDotNetCommandAsync(DirectoryInfo workingDirect

return await ProcessRunner.RunAsync(startInfo, logger, token);
}

private static bool IsMonoRuntime(string dotnetRoot, Version version)
{
string[] runtimeDirectories = Directory.GetDirectories(Path.Combine(dotnetRoot, "shared", "Microsoft.NETCore.App"))
.Where(dir => Version.Parse(Path.GetFileName(dir)) == version)
.ToArray();
if (runtimeDirectories.Length == 0)
{
throw new DirectoryNotFoundException($"No runtime directory for {version} found in {dotnetRoot}.");
}

if (runtimeDirectories.Length > 1)
{
throw new DirectoryNotFoundException($"Multiple runtime directories found for {version} in {dotnetRoot}.");
}

string runtimeDir = runtimeDirectories[0];
return File.Exists(Path.Combine(runtimeDir, "mono-gc.h"));
}

private static string? FindProgramInPath(string program)
{
string[] paths = Environment.GetEnvironmentVariable("PATH")?.Split(':', StringSplitOptions.RemoveEmptyEntries) ?? Array.Empty<string>();
foreach (string p in paths)
{
if (Path.Combine(p, program) is var filename && File.Exists(filename))
{
return filename;
}
}
return null;
}
}
}
8 changes: 6 additions & 2 deletions Turkey/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,11 @@ public static async Task<int> Run(string testRoot,
var sanitizer = new EnvironmentVariableSanitizer();
var envVars = sanitizer.SanitizeCurrentEnvironmentVariables();

var traits = CreateTraits(dotnet.LatestRuntimeVersion, dotnet.LatestSdkVersion, platformIds, trait);
var traits = CreateTraits(dotnet.LatestRuntimeVersion, dotnet.LatestSdkVersion, platformIds, dotnet.IsMonoRuntime(dotnet.LatestRuntimeVersion), trait);
Console.WriteLine($"Tests matching these traits will be skipped: {string.Join(", ", traits.OrderBy(s => s))}.");

SystemUnderTest system = new SystemUnderTest(
dotnet,
runtimeVersion: dotnet.LatestRuntimeVersion,
sdkVersion: dotnet.LatestSdkVersion,
platformIds: platformIds,
Expand Down Expand Up @@ -195,7 +196,7 @@ public static async Task<string> GenerateNuGetConfigIfNeededAsync(string additio
return null;
}

public static IReadOnlySet<string> CreateTraits(Version runtimeVersion, Version sdkVersion, List<string> rids, IEnumerable<string> additionalTraits)
public static IReadOnlySet<string> CreateTraits(Version runtimeVersion, Version sdkVersion, List<string> rids, bool isMonoRuntime, IEnumerable<string> additionalTraits)
{
var traits = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

Expand All @@ -217,6 +218,9 @@ public static IReadOnlySet<string> CreateTraits(Version runtimeVersion, Version
string arch = RuntimeInformation.OSArchitecture.ToString().ToLowerInvariant();
traits.Add($"arch={arch}");

// Add 'runtime=' trait.
traits.Add($"runtime={(isMonoRuntime ? "mono" : "coreclr")}");

// Add additional traits.
foreach (var skipTrait in additionalTraits)
{
Expand Down
5 changes: 4 additions & 1 deletion Turkey/TestRunner.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,16 @@ public class SystemUnderTest
public List<string> CurrentPlatformIds { get; }
public IReadOnlyDictionary<string, string> EnvironmentVariables;
public IReadOnlySet<string> Traits { get; }
public DotNet Dotnet { get; }

public SystemUnderTest(Version runtimeVersion,
public SystemUnderTest(DotNet dotnet,
Version runtimeVersion,
Version sdkVersion,
List<string> platformIds,
IReadOnlyDictionary<string, string> environmentVariables,
IReadOnlySet<string> traits)
{
Dotnet = dotnet;
RuntimeVersion = runtimeVersion;
SdkVersion = sdkVersion;
CurrentPlatformIds = platformIds ?? new List<string>();
Expand Down
4 changes: 2 additions & 2 deletions Turkey/XUnitTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ protected override async Task<TestResult> InternalRunAsync(Action<string> logger


private Task<int> BuildProjectAsync(Action<string> logger, CancellationToken token)
=> DotNet.BuildAsync(Directory, SystemUnderTest.EnvironmentVariables, logger, token);
=> SystemUnderTest.Dotnet.BuildAsync(Directory, SystemUnderTest.EnvironmentVariables, logger, token);

private Task<int> RunTestProjectAsync(Action<string> logger, CancellationToken token)
=> DotNet.TestAsync(Directory, SystemUnderTest.EnvironmentVariables, logger, token);
=> SystemUnderTest.Dotnet.TestAsync(Directory, SystemUnderTest.EnvironmentVariables, logger, token);
}
}

0 comments on commit 467aca7

Please sign in to comment.