diff --git a/NUnitConsole.sln b/NUnitConsole.sln index 375b8a565..af5116a20 100644 --- a/NUnitConsole.sln +++ b/NUnitConsole.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio Version 16 -VisualStudioVersion = 16.0.29728.190 +# Visual Studio Version 17 +VisualStudioVersion = 17.1.32228.430 MinimumVisualStudioVersion = 10.0.40219.1 Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{49D441DF-39FD-4F4D-AECA-86CF8EFE23AF}" ProjectSection(SolutionItems) = preProject @@ -20,6 +20,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution src\Directory.Build.props = src\Directory.Build.props GitReleaseManager.yaml = GitReleaseManager.yaml GitVersion.yml = GitVersion.yml + global.json = global.json header-check.cake = header-check.cake LICENSE.txt = LICENSE.txt NetFXTests.nunit = NetFXTests.nunit diff --git a/appveyor.yml b/appveyor.yml index 5eefdac67..4779791b4 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,6 +5,20 @@ branches: except: - /^azure-/ +install: + - ps: $urlNet70RC = "https://download.visualstudio.microsoft.com/download/pr/b3b5dce4-d810-4477-a8a3-97cbb0bdf3ea/91d0dd167239cfdfb48ae18166f444d4/dotnet-sdk-7.0.100-rc.1.22431.12-win-x64.zip" + - ps: echo "Download from $urlNet70RC" + - ps: $env:DOTNET_INSTALL_DIR = "$pwd\.dotnetsdk" + - ps: mkdir $env:DOTNET_INSTALL_DIR -Force | Out-Null + - ps: echo "Created directory $env:DOTNET_INSTALL_DIR" + - ps: echo "Starting download" + - ps: $tempFileNet70RC = [System.IO.Path]::Combine([System.IO.Path]::GetTempPath(), [System.IO.Path]::GetRandomFileName()) + - ps: (New-Object System.Net.WebClient).DownloadFile($urlNet70RC, $tempFileNet70RC) + - ps: Add-Type -AssemblyName System.IO.Compression.FileSystem; [System.IO.Compression.ZipFile]::ExtractToDirectory($tempFileNet70RC, $env:DOTNET_INSTALL_DIR) + - ps: echo "Download complete" + - ps: $env:Path = "$env:DOTNET_INSTALL_DIR;$env:Path" + - ps: dotnet --info + build_script: - ps: .\build.ps1 --target=Appveyor --configuration=Release diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 0edc93152..53c68f448 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -12,6 +12,12 @@ jobs: steps: + - task: UseDotNet@2 + displayName: 'Install .NET 7.0' + inputs: + version: 7.x + includePreviewVersions: true + - task: UseDotNet@2 displayName: 'Install .NET 6.0' inputs: @@ -69,6 +75,12 @@ jobs: vmImage: ubuntu-20.04 steps: + - task: UseDotNet@2 + displayName: 'Install .NET 7.0' + inputs: + version: 7.x + includePreviewVersions: true + - task: UseDotNet@2 displayName: 'Install .NET 6.0' inputs: @@ -118,6 +130,12 @@ jobs: vmImage: macOS-11 steps: + - task: UseDotNet@2 + displayName: 'Install .NET 7.0' + inputs: + version: 7.x + includePreviewVersions: true + - task: UseDotNet@2 displayName: 'Install .NET 6.0' inputs: diff --git a/build.cake b/build.cake index 96350d17b..d786c9d8f 100644 --- a/build.cake +++ b/build.cake @@ -109,18 +109,25 @@ public void BuildSolution() .WithProperty("TargetFramework", "netstandard2.0") .WithProperty("PublishDir", BIN_DIR + "netstandard2.0")); - DisplayBanner("Publishing ENGINE Project for NETSTANDARD2.0"); - MSBuild(ENGINE_PROJECT, CreateMSBuildSettings("Publish") - .WithProperty("TargetFramework", "netstandard2.0") - .WithProperty("PublishDir", BIN_DIR + "netstandard2.0")); + DisplayBanner("Publishing ENGINE Project"); + foreach (var framework in new[] { "netstandard2.0", "netcoreapp3.1" }) + MSBuild(ENGINE_PROJECT, CreateMSBuildSettings("Publish") + .WithProperty("TargetFramework", framework) + .WithProperty("PublishDir", BIN_DIR + framework)); - DisplayBanner("Publishing ENGINE TESTS Project for NETCOREAPP2.1"); - MSBuild(ENGINE_TESTS_PROJECT, CreateMSBuildSettings("Publish") - .WithProperty("TargetFramework", "netcoreapp2.1") - .WithProperty("PublishDir", BIN_DIR + "netcoreapp2.1")); + DisplayBanner("Publishing ENGINE TESTS Project"); + foreach (var framework in new[] { "netcoreapp2.1", "netcoreapp3.1" }) + MSBuild(ENGINE_TESTS_PROJECT, CreateMSBuildSettings("Publish") + .WithProperty("TargetFramework", framework) + .WithProperty("PublishDir", BIN_DIR + framework)); + + DisplayBanner("Publishing MOCK ASSEMBLY Project for NET7.0"); + MSBuild(MOCK_ASSEMBLY_PROJECT, CreateMSBuildSettings("Publish") + .WithProperty("TargetFramework", "net7.0") + .WithProperty("PublishDir", BIN_DIR + "net7.0")); // TODO: May not be needed - foreach (var framework in new[] { "netcoreapp3.1", "net5.0" }) + foreach (var framework in new[] { "netcoreapp3.1", "net5.0", "net7.0" }) { DisplayBanner($"Publishing AGENT Project for {framework.ToUpper()}"); MSBuild(AGENT_PROJECT, CreateMSBuildSettings("Publish") @@ -138,7 +145,7 @@ private void BuildEachProjectSeparately() BuildProject(AGENT_PROJECT); BuildProject(AGENT_X86_PROJECT); - BuildProject(ENGINE_TESTS_PROJECT, "net35", "netcoreapp2.1"); + BuildProject(ENGINE_TESTS_PROJECT, "net35", "netcoreapp2.1", "netcoreapp3.1"); BuildProject(ENGINE_CORE_TESTS_PROJECT, "net35", "netcoreapp2.1", "netcoreapp3.1", "net5.0", "net6.0"); BuildProject(CONSOLE_TESTS_PROJECT, "net35", "net6.0"); @@ -305,6 +312,19 @@ Task("TestNetStandard20Engine") RunDotnetNUnitLiteTests(NETCORE_ENGINE_TESTS, "netcoreapp2.1"); }); +////////////////////////////////////////////////////////////////////// +// TEST NETCORE 3.1 ENGINE +////////////////////////////////////////////////////////////////////// + +Task("TestNetCore31Engine") + .Description("Tests the .NET Core 3.1 Engine") + .IsDependentOn("Build") + .OnError(exception => { UnreportedErrors.Add(exception.Message); }) + .Does(() => + { + RunDotnetNUnitLiteTests(NETCORE_ENGINE_TESTS, "netcoreapp3.1"); + }); + ////////////////////////////////////////////////////////////////////// // TEST .NET 2.0 CONSOLE ////////////////////////////////////////////////////////////////////// @@ -739,7 +759,8 @@ Task("TestEngineCore") Task("TestEngine") .Description("Builds and tests the engine assembly") .IsDependentOn("TestNet20Engine") - .IsDependentOn("TestNetStandard20Engine"); + .IsDependentOn("TestNetStandard20Engine") + .IsDependentOn("TestNetCore31Engine"); Task("Test") .Description("Builds and tests the engine and console runner") diff --git a/cake/package-definitions.cake b/cake/package-definitions.cake index 93db0d309..6265ffb87 100644 --- a/cake/package-definitions.cake +++ b/cake/package-definitions.cake @@ -28,6 +28,7 @@ public void InitializePackageDefinitions(ICakeContext context) NetCore31Test, Net50Test, Net60Test, + Net70Test, NetCore21PlusNetCore31Test, NetCore21PlusNetCore31PlusNet50PlusNet60Test, Net40PlusNet60Test @@ -71,7 +72,8 @@ public void InitializePackageDefinitions(ICakeContext context) HasDirectory("tools/agents/net40").WithFiles(AGENT_FILES).AndFile("nunit.agent.addins"), HasDirectory("tools/agents/netcoreapp3.1").WithFiles(AGENT_FILES_NETCORE).AndFile("nunit.agent.addins"), HasDirectory("tools/agents/net5.0").WithFiles(AGENT_FILES_NETCORE).AndFile("nunit.agent.addins"), - HasDirectory("tools/agents/net6.0").WithFiles(AGENT_FILES_NETCORE).AndFile("nunit.agent.addins") + HasDirectory("tools/agents/net6.0").WithFiles(AGENT_FILES_NETCORE).AndFile("nunit.agent.addins"), + HasDirectory("tools/agents/net7.0").WithFiles(AGENT_FILES_NETCORE).AndFile("nunit.agent.addins") }, symbols: new PackageCheck[] { HasDirectory("tools").WithFiles(ENGINE_PDB_FILES).AndFile("nunit3-console.pdb"), @@ -79,7 +81,8 @@ public void InitializePackageDefinitions(ICakeContext context) HasDirectory("tools/agents/net40").WithFiles(AGENT_PDB_FILES), HasDirectory("tools/agents/netcoreapp3.1").WithFiles(AGENT_PDB_FILES_NETCORE), HasDirectory("tools/agents/net5.0").WithFiles(AGENT_PDB_FILES_NETCORE), - HasDirectory("tools/agents/net6.0").WithFiles(AGENT_PDB_FILES_NETCORE) + HasDirectory("tools/agents/net6.0").WithFiles(AGENT_PDB_FILES_NETCORE), + HasDirectory("tools/agents/net7.0").WithFiles(AGENT_PDB_FILES_NETCORE) }, executable: "tools/nunit3-console.exe", tests: StandardRunnerTests), @@ -110,7 +113,8 @@ public void InitializePackageDefinitions(ICakeContext context) HasDirectory("tools/agents/net40").WithFiles(AGENT_FILES).AndFile("nunit.agent.addins"), HasDirectory("tools/agents/netcoreapp3.1").WithFiles(AGENT_FILES_NETCORE).AndFile("nunit.agent.addins"), HasDirectory("tools/agents/net5.0").WithFiles(AGENT_FILES_NETCORE).AndFile("nunit.agent.addins"), - HasDirectory("tools/agents/net6.0").WithFiles(AGENT_FILES_NETCORE).AndFile("nunit.agent.addins") + HasDirectory("tools/agents/net6.0").WithFiles(AGENT_FILES_NETCORE).AndFile("nunit.agent.addins"), + HasDirectory("tools/agents/net7.0").WithFiles(AGENT_FILES_NETCORE).AndFile("nunit.agent.addins") }, executable: "tools/nunit3-console.exe", tests: StandardRunnerTests), @@ -123,6 +127,12 @@ public void InitializePackageDefinitions(ICakeContext context) checks: new PackageCheck[] { HasDirectory("NUnit.org").WithFiles("LICENSE.txt", "NOTICES.txt", "nunit.ico"), HasDirectory("NUnit.org/nunit-console").WithFiles(CONSOLE_FILES).AndFiles(ENGINE_FILES).AndFile("nunit.bundle.addins"), + HasDirectory("NUnit.org/nunit-console/agents/net20").WithFiles("nunit-agent.exe", "nunit-agent.exe.config"), + HasDirectory("NUnit.org/nunit-console/agents/net40").WithFiles("nunit-agent.exe", "nunit-agent.exe.config"), + HasDirectory("NUnit.org/nunit-console/agents/netcoreapp3.1").WithFile("nunit-agent.dll"), + HasDirectory("NUnit.org/nunit-console/agents/net5.0").WithFile("nunit-agent.dll"), + HasDirectory("NUnit.org/nunit-console/agents/net6.0").WithFile("nunit-agent.dll"), + //HasDirectory("NUnit.org/nunit-console/agents/net7.0").WithFile("nunit-agent.dll"), HasDirectory("Nunit.org/nunit-console/addins").WithFiles("nunit.core.dll", "nunit.core.interfaces.dll", "nunit.v2.driver.dll", "nunit-project-loader.dll", "vs-project-loader.dll", "nunit-v2-result-writer.dll", "teamcity-event-listener.dll") }, executable: "NUnit.org/nunit-console/nunit3-console.exe", @@ -139,7 +149,7 @@ public void InitializePackageDefinitions(ICakeContext context) HasDirectory("bin/net35").WithFiles(CONSOLE_FILES).AndFiles(ENGINE_FILES).AndFile("nunit3-console.pdb").AndFiles(ENGINE_PDB_FILES), HasDirectory("bin/netstandard2.0").WithFiles(ENGINE_FILES).AndFiles(ENGINE_PDB_FILES), HasDirectory("bin/netcoreapp2.1").WithFiles(ENGINE_FILES).AndFiles(ENGINE_PDB_FILES), - HasDirectory("bin/netcoreapp3.1").WithFiles(ENGINE_CORE_FILES).AndFiles(ENGINE_CORE_PDB_FILES), + HasDirectory("bin/netcoreapp3.1").WithFiles(ENGINE_FILES).AndFiles(ENGINE_PDB_FILES), //HasDirectory("bin/net5.0").WithFiles(ENGINE_FILES).AndFiles(ENGINE_PDB_FILES), HasDirectory("bin/agents/net20").WithFiles(AGENT_FILES).AndFiles(AGENT_PDB_FILES), HasDirectory("bin/agents/net40").WithFiles(AGENT_FILES).AndFiles(AGENT_PDB_FILES), @@ -160,14 +170,17 @@ public void InitializePackageDefinitions(ICakeContext context) HasFiles("LICENSE.txt", "NOTICES.txt"), HasDirectory("lib/net20").WithFiles(ENGINE_FILES), HasDirectory("lib/netstandard2.0").WithFiles(ENGINE_FILES), + HasDirectory("lib/netcoreapp3.1").WithFiles(ENGINE_FILES), HasDirectory("contentFiles/any/lib/net20").WithFile("nunit.engine.nuget.addins"), HasDirectory("contentFiles/any/lib/netstandard2.0").WithFile("nunit.engine.nuget.addins"), + HasDirectory("contentFiles/any/lib/netcoreapp3.1").WithFile("nunit.engine.nuget.addins"), HasDirectory("contentFiles/any/agents/net20").WithFiles(AGENT_FILES).AndFile("nunit.agent.addins"), HasDirectory("contentFiles/any/agents/net40").WithFiles(AGENT_FILES).AndFile("nunit.agent.addins") }, symbols: new PackageCheck[] { HasDirectory("lib/net20").WithFiles(ENGINE_PDB_FILES), HasDirectory("lib/netstandard2.0").WithFiles(ENGINE_PDB_FILES), + HasDirectory("lib/netcoreapp3.1").WithFiles(ENGINE_PDB_FILES), HasDirectory("contentFiles/any/agents/net20").WithFiles(AGENT_PDB_FILES), HasDirectory("contentFiles/any/agents/net40").WithFiles(AGENT_PDB_FILES) }), diff --git a/cake/package-tests.cake b/cake/package-tests.cake index e28e90434..ccdb4e864 100644 --- a/cake/package-tests.cake +++ b/cake/package-tests.cake @@ -48,6 +48,12 @@ static PackageTest Net60Test = new PackageTest( "net6.0/mock-assembly.dll", MockAssemblyExpectedResult(1)); +static PackageTest Net70Test = new PackageTest( + "Net70Test", + "Run mock-assembly.dll under .NET 7.0", + "net7.0/mock-assembly.dll", + MockAssemblyExpectedResult(1)); + static PackageTest Net50Test = new PackageTest( "Net50Test", "Run mock-assembly.dll under .NET 5.0", diff --git a/cake/versioning.cake b/cake/versioning.cake index 12f0c9813..aded97410 100644 --- a/cake/versioning.cake +++ b/cake/versioning.cake @@ -77,6 +77,10 @@ public class BuildVersion string branchName = _gitVersion.BranchName; + // Treat version3 branch as an alternate "main" + if (branchName == "version3") + label = "dev"; + // We don't currently use this pattern, but check in case we do later. if (branchName.StartsWith("feature/")) branchName = branchName.Substring(8); diff --git a/choco/nunit-console-runner.nuspec b/choco/nunit-console-runner.nuspec index f8f321b5e..2739816f6 100644 --- a/choco/nunit-console-runner.nuspec +++ b/choco/nunit-console-runner.nuspec @@ -92,5 +92,15 @@ + + + + + + + + + + diff --git a/global.json b/global.json index 69d60238d..c18e8aeca 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.101", - "rollForward": "patch" + "version": "7.0.100-rc.1.22431.12", + "rollForward": "feature" } } \ No newline at end of file diff --git a/msi/nunit/engine-files.wxi b/msi/nunit/engine-files.wxi index 457244bd6..c8791fcdc 100644 --- a/msi/nunit/engine-files.wxi +++ b/msi/nunit/engine-files.wxi @@ -49,6 +49,7 @@ + @@ -174,5 +175,34 @@ Source="$(var.InstallImage)bin/net6.0/testcentric.engine.metadata.dll" /> + + + + + + + + + + + + + + + + + + diff --git a/msi/nunit/runner-directories.wxi b/msi/nunit/runner-directories.wxi index 1f4eab58e..c3483e20e 100644 --- a/msi/nunit/runner-directories.wxi +++ b/msi/nunit/runner-directories.wxi @@ -16,6 +16,7 @@ + diff --git a/nuget/engine/nunit.engine.nuspec b/nuget/engine/nunit.engine.nuspec index 271016e96..60c86602d 100644 --- a/nuget/engine/nunit.engine.nuspec +++ b/nuget/engine/nunit.engine.nuspec @@ -92,6 +92,15 @@ + + + + + + + + + diff --git a/nuget/runners/nunit.console-runner.nuspec b/nuget/runners/nunit.console-runner.nuspec index 032d4d088..2d58e7123 100644 --- a/nuget/runners/nunit.console-runner.nuspec +++ b/nuget/runners/nunit.console-runner.nuspec @@ -93,6 +93,19 @@ + + + + + + + + + + + + + diff --git a/src/NUnitConsole/nunit3-console/Program.cs b/src/NUnitConsole/nunit3-console/Program.cs index c9c5d6d3e..c0c8a4d10 100644 --- a/src/NUnitConsole/nunit3-console/Program.cs +++ b/src/NUnitConsole/nunit3-console/Program.cs @@ -106,8 +106,9 @@ public static int Main(string[] args) if (Options.WorkDirectory != null) engine.WorkDirectory = Options.WorkDirectory; - if (Options.InternalTraceLevel != null) - engine.InternalTraceLevel = (InternalTraceLevel)Enum.Parse(typeof(InternalTraceLevel), Options.InternalTraceLevel); + engine.InternalTraceLevel = Options.InternalTraceLevel != null + ? (InternalTraceLevel)Enum.Parse(typeof(InternalTraceLevel), Options.InternalTraceLevel) + : InternalTraceLevel.Off; try { diff --git a/src/NUnitEngine/mock-assembly/mock-assembly.csproj b/src/NUnitEngine/mock-assembly/mock-assembly.csproj index f60671084..aef70f591 100644 --- a/src/NUnitEngine/mock-assembly/mock-assembly.csproj +++ b/src/NUnitEngine/mock-assembly/mock-assembly.csproj @@ -2,7 +2,7 @@ NUnit.Tests - net35;net40;netcoreapp2.1;netcoreapp3.1;net5.0;net6.0 + net35;net40;netcoreapp2.1;netcoreapp3.1;net5.0;net6.0;net7.0 true ..\..\nunit.snk false diff --git a/src/NUnitEngine/nunit-agent/Program.cs b/src/NUnitEngine/nunit-agent/Program.cs index 4c98c0591..f66171d31 100644 --- a/src/NUnitEngine/nunit-agent/Program.cs +++ b/src/NUnitEngine/nunit-agent/Program.cs @@ -61,7 +61,6 @@ public static void Main(string[] args) } var logName = $"nunit-agent_{pid}.log"; - InternalTrace.Initialize(Path.Combine(workDirectory, logName), traceLevel); log = InternalTrace.GetLogger(typeof(NUnitTestAgent)); log.Info("Agent process {0} starting", pid); @@ -71,7 +70,13 @@ public static void Main(string[] args) LocateAgencyProcess(agencyPid); -#if NETCOREAPP3_1 +#if NET7_0 + log.Info($"Running .NET 7.0 agent under {RuntimeInformation.FrameworkDescription}"); +#elif NET6_0 + log.Info($"Running .NET 6.0 agent under {RuntimeInformation.FrameworkDescription}"); +#elif NET5_0 + log.Info($"Running .NET 5.0 agent under {RuntimeInformation.FrameworkDescription}"); +#elif NETCOREAPP3_1 log.Info($"Running .NET Core 3.1 agent under {RuntimeInformation.FrameworkDescription}"); #elif NET40 log.Info($"Running .NET 4.0 agent under {RuntimeFramework.CurrentFramework.DisplayName}"); diff --git a/src/NUnitEngine/nunit-agent/nunit-agent.csproj b/src/NUnitEngine/nunit-agent/nunit-agent.csproj index aeca8e54a..317315028 100644 --- a/src/NUnitEngine/nunit-agent/nunit-agent.csproj +++ b/src/NUnitEngine/nunit-agent/nunit-agent.csproj @@ -3,7 +3,7 @@ Exe nunit.agent - net20;net40;netcoreapp3.1;net5.0;net6.0 + net20;net40;netcoreapp3.1;net5.0;net6.0;net7.0 app.manifest ..\..\..\nunit.ico false diff --git a/src/NUnitEngine/nunit.engine.core/Internal/RuntimeFrameworks/NetCoreFrameworkLocator.cs b/src/NUnitEngine/nunit.engine.core/Internal/RuntimeFrameworks/NetCoreFrameworkLocator.cs new file mode 100644 index 000000000..420dd4a6a --- /dev/null +++ b/src/NUnitEngine/nunit.engine.core/Internal/RuntimeFrameworks/NetCoreFrameworkLocator.cs @@ -0,0 +1,127 @@ +// Copyright (c) Charlie Poole, Rob Prouse and Contributors. MIT License - see LICENSE.txt + +#if NETFRAMEWORK +using Microsoft.Win32; +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Text; + +namespace NUnit.Engine.Internal.RuntimeFrameworks +{ + internal static class NetCoreFrameworkLocator + { + static Logger log = InternalTrace.GetLogger(typeof(NetCoreFrameworkLocator)); + + public static IEnumerable FindDotNetCoreFrameworks() + { + List alreadyFound = new List(); + + foreach (string dirName in GetRuntimeDirectories()) + { + Version newVersion; + if (TryGetVersionFromString(dirName, out newVersion) && !alreadyFound.Contains(newVersion)) + { + alreadyFound.Add(newVersion); + // HACK: Avoid Exception for an unknown version - see issue #1223 + // Requires change in RuntimeFramework.GetClrVersionForFramework() + if (newVersion.Major <= 7) + yield return new RuntimeFramework(RuntimeType.NetCore, newVersion); + else + log.Error($"Found .NET {newVersion.ToString(2)}, which is not yet supported."); + } + } + + foreach (string line in GetRuntimeList()) + { + Version newVersion; + if (TryGetVersionFromString(line, out newVersion) && !alreadyFound.Contains(newVersion)) + { + alreadyFound.Add(newVersion); + yield return new RuntimeFramework(RuntimeType.NetCore, newVersion); + } + } + } + + private static IEnumerable GetRuntimeDirectories() + { + string installDir = GetDotNetInstallDirectory(); + + if (installDir != null && Directory.Exists(installDir) && + File.Exists(Path.Combine(installDir, "dotnet.exe"))) + { + string runtimeDir = Path.Combine(installDir, Path.Combine("shared", "Microsoft.NETCore.App")); + if (Directory.Exists(runtimeDir)) + foreach (var dir in new DirectoryInfo(runtimeDir).GetDirectories()) + yield return dir.Name; + } + } + + private static IEnumerable GetRuntimeList() + { + var process = new Process + { + StartInfo = new ProcessStartInfo + { + FileName = "dotnet", + Arguments = "--list-runtimes", + UseShellExecute = false, + RedirectStandardOutput = true, + CreateNoWindow = true + } + }; + + process.Start(); + + const string PREFIX = "Microsoft.NETCore.App "; + const int VERSION_START = 22; + + while (!process.StandardOutput.EndOfStream) + { + var line = process.StandardOutput.ReadLine(); + if (line.StartsWith(PREFIX)) + yield return line.Substring(VERSION_START); + } + } + + private static string GetDotNetInstallDirectory() + { + if (Path.DirectorySeparatorChar == '\\') + { + // Running on Windows so use registry + RegistryKey key = Registry.LocalMachine.OpenSubKey(@"Software\dotnet\SetUp\InstalledVersions\x64\sharedHost\"); + return (string)key?.GetValue("Path"); + } + else + return "/usr/shared/dotnet/"; + } + + private static bool TryGetVersionFromString(string text, out Version newVersion) + { + const string VERSION_CHARS = ".0123456789"; + + int len = 0; + foreach (char c in text) + { + if (VERSION_CHARS.IndexOf(c) >= 0) + len++; + else + break; + } + + try + { + var fullVersion = new Version(text.Substring(0, len)); + newVersion = new Version(fullVersion.Major, fullVersion.Minor); + return true; + } + catch + { + newVersion = new Version(); + return false; + } + } + } +} +#endif diff --git a/src/NUnitEngine/nunit.engine.core/Internal/RuntimeFrameworks/DotNetFrameworkLocator.cs b/src/NUnitEngine/nunit.engine.core/Internal/RuntimeFrameworks/NetFrameworkLocator.cs similarity index 98% rename from src/NUnitEngine/nunit.engine.core/Internal/RuntimeFrameworks/DotNetFrameworkLocator.cs rename to src/NUnitEngine/nunit.engine.core/Internal/RuntimeFrameworks/NetFrameworkLocator.cs index 92560e38a..200275d12 100644 --- a/src/NUnitEngine/nunit.engine.core/Internal/RuntimeFrameworks/DotNetFrameworkLocator.cs +++ b/src/NUnitEngine/nunit.engine.core/Internal/RuntimeFrameworks/NetFrameworkLocator.cs @@ -7,7 +7,7 @@ namespace NUnit.Engine.Internal.RuntimeFrameworks { - internal static class DotNetFrameworkLocator + internal static class NetFrameworkLocator { // Note: this method cannot be generalized past V4, because (a) it has // specific code for detecting .NET 4.5 and (b) we don't know what diff --git a/src/NUnitEngine/nunit.engine.core/RuntimeFramework.cs b/src/NUnitEngine/nunit.engine.core/RuntimeFramework.cs index 33fc7116b..42782f462 100644 --- a/src/NUnitEngine/nunit.engine.core/RuntimeFramework.cs +++ b/src/NUnitEngine/nunit.engine.core/RuntimeFramework.cs @@ -134,6 +134,7 @@ public RuntimeFramework(RuntimeType runtime, Version version, string profile) // Version 0.0 means any version so we can't deduce anything if (version != DefaultVersion) { + Debug.Assert(IsFrameworkVersion(version)); if (IsFrameworkVersion(version)) ClrVersion = GetClrVersionForFramework(version); else @@ -201,6 +202,8 @@ private Version GetClrVersionForFramework(Version frameworkVersion) return new Version(5, 0, 1); case 6: return new Version(6, 0, 0); + case 7: + return new Version(7, 0, 0); } break; } @@ -549,10 +552,10 @@ private static void FindAvailableFrameworks() _availableFrameworks = new List(); if (Environment.OSVersion.Platform == PlatformID.Win32NT) - _availableFrameworks.AddRange(DotNetFrameworkLocator.FindDotNetFrameworks()); + _availableFrameworks.AddRange(NetFrameworkLocator.FindDotNetFrameworks()); FindDefaultMonoFramework(); - FindDotNetCoreFrameworks(); + _availableFrameworks.AddRange(NetCoreFrameworkLocator.FindDotNetCoreFrameworks()); } private static void FindDefaultMonoFramework() @@ -674,73 +677,6 @@ private static void AddMonoFramework(Version frameworkVersion, string profile) _availableFrameworks.Add(framework); } - - private static void FindDotNetCoreFrameworks() - { - const string WINDOWS_INSTALL_DIR = "C:\\Program Files\\dotnet\\"; - const string LINUX_INSTALL_DIR = "/usr/shared/dotnet/"; - string INSTALL_DIR = Path.DirectorySeparatorChar == '\\' - ? WINDOWS_INSTALL_DIR - : LINUX_INSTALL_DIR; - - if (!Directory.Exists(INSTALL_DIR)) - return; - if (!File.Exists(Path.Combine(INSTALL_DIR, "dotnet.exe"))) - return; - - string runtimeDir = Path.Combine(INSTALL_DIR, Path.Combine("shared", "Microsoft.NETCore.App")); - if (!Directory.Exists(runtimeDir)) - return; - - var dirList = new DirectoryInfo(runtimeDir).GetDirectories(); - var dirNames = new List(); - foreach (var dir in dirList) - dirNames.Add(dir.Name); - var runtimes = GetNetCoreRuntimesFromDirectoryNames(dirNames); - - _availableFrameworks.AddRange(runtimes); - } - - // Deal with oddly named directories, which may sometimes appear when previews are installed - internal static IList GetNetCoreRuntimesFromDirectoryNames(IEnumerable dirNames) - { - const string VERSION_CHARS = ".0123456789"; - var runtimes = new List(); - - foreach (string dirName in dirNames) - { - int len = 0; - foreach (char c in dirName) - { - if (VERSION_CHARS.IndexOf(c) >= 0) - len++; - else - break; - } - - if (len == 0) - continue; - - Version fullVersion = null; - try - { - fullVersion = new Version(dirName.Substring(0, len)); - } - catch - { - continue; - } - - var newVersion = new Version(fullVersion.Major, fullVersion.Minor); - int count = runtimes.Count; - if (count > 0 && runtimes[count - 1].FrameworkVersion == newVersion) - continue; - - runtimes.Add(new RuntimeFramework(RuntimeType.NetCore, newVersion)); - } - - return runtimes; - } } } #endif diff --git a/src/NUnitEngine/nunit.engine.tests/Transport/Tcp/TcpServerTests.cs b/src/NUnitEngine/nunit.engine.tests/Transport/Tcp/TcpServerTests.cs new file mode 100644 index 000000000..a53dc5abd --- /dev/null +++ b/src/NUnitEngine/nunit.engine.tests/Transport/Tcp/TcpServerTests.cs @@ -0,0 +1,71 @@ +// Copyright (c) Charlie Poole, Rob Prouse and Contributors. MIT License - see LICENSE.txt + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Net.Sockets; +using System.Text; +using System.Threading; +using NUnit.Framework; + +namespace NUnit.Engine.Communication.Transports.Tcp +{ + public class TcpServerTests + { + private TcpServer _server; + private List _serverConnections; + + [SetUp] + public void StartServer() + { + _serverConnections = new List(); + _server = new TcpServer(); + _server.ClientConnected += (c, g) => _serverConnections.Add(c); + _server.Start(); + } + + [TearDown] + public void StopServer() + { + _server.Stop(); + } + + [Test] + public void SingleClientConnection() + { + using (TcpClient client = new TcpClient()) + { + client.Connect(_server.EndPoint); + client.Client.Send(new Guid().ToByteArray()); + + Thread.Sleep(1); // Allow the connection event to run + Assert.That(_serverConnections.Count, Is.EqualTo(1), "Should have received 1 connection event"); + Assert.That(_serverConnections[0].Connected, "Server is not connected to client"); + + Assert.True(client.Connected, "Client is not connected to server"); + } + } + + [Test] + public void MultipleClientConnections() + { + TcpClient[] clients = new[] { new TcpClient(), new TcpClient(), new TcpClient() }; + int num = clients.Length; + + foreach (var client in clients) + { + client.Connect(_server.EndPoint); + client.Client.Send(new Guid().ToByteArray()); + } + + Thread.Sleep(1); // Allow the connection events to run + Assert.That(_serverConnections.Count, Is.EqualTo(num), $"Should have received {num} connection events"); + + for (int i = 0; i < num; i++) + { + Assert.That(_serverConnections[i].Connected, $"Server is not connected to client {i+1}"); + Assert.True(clients[i].Connected, $"Client {i+1} is not connected to server"); + } + } + } +} diff --git a/src/NUnitEngine/nunit.engine.tests/nunit.engine.tests.csproj b/src/NUnitEngine/nunit.engine.tests/nunit.engine.tests.csproj index e586bc682..cb3a14daa 100644 --- a/src/NUnitEngine/nunit.engine.tests/nunit.engine.tests.csproj +++ b/src/NUnitEngine/nunit.engine.tests/nunit.engine.tests.csproj @@ -2,7 +2,7 @@ NUnit.Engine.Tests - net35;netcoreapp2.1 + net35;netcoreapp2.1;netcoreapp3.1 Exe true ..\..\nunit.snk @@ -28,7 +28,7 @@ - + diff --git a/src/NUnitEngine/nunit.engine/Communication/Transports/Tcp/TcpServer.cs b/src/NUnitEngine/nunit.engine/Communication/Transports/Tcp/TcpServer.cs index 359704296..cc72a6635 100644 --- a/src/NUnitEngine/nunit.engine/Communication/Transports/Tcp/TcpServer.cs +++ b/src/NUnitEngine/nunit.engine/Communication/Transports/Tcp/TcpServer.cs @@ -14,7 +14,7 @@ public class TcpServer private const int GUID_BUFFER_SIZE = 16; - TcpListener _listenerSocket; + TcpListener _tcpListener; Thread _listenerThread; volatile bool _running; @@ -24,17 +24,21 @@ public class TcpServer public TcpServer(int port = 0) { - _listenerSocket = new TcpListener(IPAddress.Loopback, port); + _tcpListener = new TcpListener(IPAddress.Loopback, port); } - public IPEndPoint EndPoint => (IPEndPoint)_listenerSocket.LocalEndpoint; + public IPEndPoint EndPoint => (IPEndPoint)_tcpListener.LocalEndpoint; public void Start() { - _listenerSocket.Start(); + _tcpListener.Start(); _running = true; - _listenerThread = new Thread(WaitForClientConnections); + _listenerThread = new Thread(WaitForClientConnections) + { + Name = "TcpListenerTread", + IsBackground = true + }; _listenerThread.Start(); } @@ -43,7 +47,7 @@ public void Stop() try { _running = false; - _listenerSocket.Stop(); + _tcpListener.Stop(); } catch (Exception exception) { @@ -57,7 +61,7 @@ private void WaitForClientConnections() { try { - var clientSocket = _listenerSocket.AcceptSocket(); + var clientSocket = _tcpListener.AcceptSocket(); if (clientSocket.Connected) { // Upon connection, remote agent must immediately send its Id as identification. @@ -74,7 +78,7 @@ private void WaitForClientConnections() // 1. We were trying to stop the socket // 2. The connection was dropped due to some external event // In either case, we stop the socket and wait a while - _listenerSocket.Stop(); + _tcpListener.Stop(); // If we were trying to stop, that's all if (!_running) @@ -84,7 +88,7 @@ private void WaitForClientConnections() Thread.Sleep(500); try { - _listenerSocket.Start(); + _tcpListener.Start(); } catch (Exception exception) { diff --git a/src/NUnitEngine/nunit.engine/Services/AgentProcess.cs b/src/NUnitEngine/nunit.engine/Services/AgentProcess.cs index 6411d810e..b98352026 100644 --- a/src/NUnitEngine/nunit.engine/Services/AgentProcess.cs +++ b/src/NUnitEngine/nunit.engine/Services/AgentProcess.cs @@ -53,7 +53,7 @@ public AgentProcess(TestAgency agency, TestPackage package, Guid agentId) StartInfo.FileName = RuntimeFramework.MonoExePath; string monoOptions = "--runtime=v" + TargetRuntime.ClrVersion.ToString(3); monoOptions += " --debug"; - StartInfo.Arguments = string.Format("{0} \"{1}\" {2}", monoOptions, AgentExePath, AgentArgs); + StartInfo.Arguments = $"{monoOptions} \"{AgentExePath}\" {AgentArgs}"; } else if (TargetRuntime.Runtime == RuntimeType.Net) { @@ -64,7 +64,7 @@ public AgentProcess(TestAgency agency, TestPackage package, Guid agentId) else if (TargetRuntime.Runtime == RuntimeType.NetCore) { StartInfo.FileName = "dotnet"; - StartInfo.Arguments = $"{AgentExePath} {AgentArgs}"; + StartInfo.Arguments = $"\"{AgentExePath}\" {AgentArgs}"; StartInfo.LoadUserProfile = loadUserProfile; // TODO: Remove the windows limitation and the use of a hard-coded path. @@ -116,27 +116,24 @@ public static string GetTestAgentExePath(RuntimeFramework targetRuntime, bool re string runtimeDir; string agentName; - string agentExtension; int major = targetRuntime.FrameworkVersion.Major; switch (targetRuntime.Runtime) { case RuntimeType.Net: case RuntimeType.Mono: runtimeDir = major >= 4 ? "net40" : "net20"; - agentName = requires32Bit ? "nunit-agent-x86" : "nunit-agent"; - agentExtension = ".exe"; + agentName = requires32Bit ? "nunit-agent-x86.exe" : "nunit-agent.exe"; break; case RuntimeType.NetCore: - runtimeDir = major >= 6 ? "net6.0" : major == 5 ? "net5.0" : "netcoreapp3.1"; - agentName = "nunit-agent"; - agentExtension = ".dll"; + runtimeDir = major >= 7 ? "net7.0" : major == 6 ? "net6.0" : major == 5 ? "net5.0" : "netcoreapp3.1"; + agentName = "nunit-agent.dll"; break; default: log.Error($"Unknown runtime type: {targetRuntime.Runtime}"); return null; } - return Path.Combine(Path.Combine(agentsDir, runtimeDir), agentName + agentExtension); + return Path.Combine(Path.Combine(agentsDir, runtimeDir), agentName); } } } diff --git a/src/NUnitEngine/nunit.engine/Services/RuntimeFrameworkService.cs b/src/NUnitEngine/nunit.engine/Services/RuntimeFrameworkService.cs index bd5cecf99..5347ec49d 100644 --- a/src/NUnitEngine/nunit.engine/Services/RuntimeFrameworkService.cs +++ b/src/NUnitEngine/nunit.engine/Services/RuntimeFrameworkService.cs @@ -173,27 +173,6 @@ private RuntimeFramework SelectRuntimeFrameworkInner(TestPackage package) return targetFramework; } - - /// - /// Returns the best available framework that matches a target framework. - /// If the target framework has a build number specified, then an exact - /// match is needed. Otherwise, the matching framework with the highest - /// build number is used. - /// - public RuntimeFramework GetBestAvailableFramework(RuntimeFramework target) - { - RuntimeFramework result = target; - - foreach (RuntimeFramework framework in _availableRuntimes) - if (framework.Supports(target)) - { - if (framework.ClrVersion.Build > result.ClrVersion.Build) - result = framework; - } - - return result; - } - /// /// Use Mono.Cecil to get information about all assemblies and /// apply it to the package using special internal keywords. diff --git a/src/NUnitEngine/nunit.engine/nunit.engine.csproj b/src/NUnitEngine/nunit.engine/nunit.engine.csproj index e05330dd6..279782078 100644 --- a/src/NUnitEngine/nunit.engine/nunit.engine.csproj +++ b/src/NUnitEngine/nunit.engine/nunit.engine.csproj @@ -2,7 +2,7 @@ NUnit.Engine - net20;netstandard2.0 + net20;netstandard2.0;netcoreapp3.1 true ..\..\nunit.snk portable