diff --git a/cake/package-definitions.cake b/cake/package-definitions.cake index 494394638..63a04c04c 100644 --- a/cake/package-definitions.cake +++ b/cake/package-definitions.cake @@ -96,18 +96,18 @@ public void InitializePackageDefinitions(ICakeContext context) HasDirectory("tools/agents/nunit-agent-netcore31") .WithFiles( "nunit-agent-netcore31.dll", "nunit.engine.core.dll", - "nunit.engine.api.dll", "testcentric.engine.metadata.dll"), + "nunit.engine.api.dll", "testcentric.engine.metadata.dll", "Microsoft.Extensions.DependencyModel.dll"), HasDirectory("tools/agents/nunit-agent-net50") .WithFiles( "nunit-agent-net50.dll", "nunit.engine.core.dll", - "nunit.engine.api.dll", "testcentric.engine.metadata.dll"), + "nunit.engine.api.dll", "testcentric.engine.metadata.dll", "Microsoft.Extensions.DependencyModel.dll"), HasDirectory("tools/agents/nunit-agent-net60") .WithFiles( "nunit-agent-net60.dll", "nunit.engine.core.dll", - "nunit.engine.api.dll", "testcentric.engine.metadata.dll"), + "nunit.engine.api.dll", "testcentric.engine.metadata.dll", "Microsoft.Extensions.DependencyModel.dll"), HasDirectory("tools/agents/nunit-agent-net70") .WithFiles("nunit-agent-net70.dll", "nunit.engine.core.dll", - "nunit.engine.api.dll", "testcentric.engine.metadata.dll") + "nunit.engine.api.dll", "testcentric.engine.metadata.dll", "Microsoft.Extensions.DependencyModel.dll") }, symbols: new PackageCheck[] { HasDirectory("tools") @@ -141,7 +141,7 @@ public void InitializePackageDefinitions(ICakeContext context) HasDirectory("tools/net6.0/any") .WithFiles( "nunit4-netcore-console.exe", "nunit4-netcore-console.dll", "nunit4-netcore-console.dll.config", "nunit.console.nuget.addins", - "nunit.engine.dll", "nunit.engine.core.dll", "nunit.engine.api.dll", "testcentric.engine.metadata.dll") + "nunit.engine.dll", "nunit.engine.core.dll", "nunit.engine.api.dll", "testcentric.engine.metadata.dll", "Microsoft.Extensions.DependencyModel.dll") }, symbols: new PackageCheck[] { HasDirectory("tools/net6.0/any"). @@ -175,16 +175,20 @@ public void InitializePackageDefinitions(ICakeContext context) "nunit.engine.core.dll", "nunit.engine.api.dll", "testcentric.engine.metadata.dll"), HasDirectory("tools/agents/nunit-agent-netcore31") .WithFiles( - "nunit-agent-netcore31.dll", "nunit.engine.core.dll", "nunit.engine.api.dll", "testcentric.engine.metadata.dll"), + "nunit-agent-netcore31.dll", "nunit.engine.core.dll", "nunit.engine.api.dll", + "testcentric.engine.metadata.dll", "Microsoft.Extensions.DependencyModel.dll"), HasDirectory("tools/agents/nunit-agent-net50") .WithFiles( - "nunit-agent-net50.dll", "nunit.engine.core.dll", "nunit.engine.api.dll", "testcentric.engine.metadata.dll"), + "nunit-agent-net50.dll", "nunit.engine.core.dll", "nunit.engine.api.dll", + "testcentric.engine.metadata.dll", "Microsoft.Extensions.DependencyModel.dll"), HasDirectory("tools/agents/nunit-agent-net60") .WithFiles( - "nunit-agent-net60.dll", "nunit.engine.core.dll", "nunit.engine.api.dll", "testcentric.engine.metadata.dll"), + "nunit-agent-net60.dll", "nunit.engine.core.dll", "nunit.engine.api.dll", + "testcentric.engine.metadata.dll", "Microsoft.Extensions.DependencyModel.dll"), HasDirectory("tools/agents/nunit-agent-net70") .WithFiles( - "nunit-agent-net70.dll", "nunit.engine.core.dll", "nunit.engine.api.dll", "testcentric.engine.metadata.dll") + "nunit-agent-net70.dll", "nunit.engine.core.dll", "nunit.engine.api.dll", + "testcentric.engine.metadata.dll", "Microsoft.Extensions.DependencyModel.dll") }, executable: "tools/nunit4-console.exe", tests: StandardRunnerTests), @@ -215,20 +219,24 @@ public void InitializePackageDefinitions(ICakeContext context) "nunit.engine.core.dll", "nunit.engine.api.dll", "testcentric.engine.metadata.dll"), HasDirectory("NUnit.org/nunit-console/agents/nunit-agent-netcore31") .WithFiles( - "nunit-agent-netcore31.dll", "nunit.engine.core.dll", - "nunit.engine.api.dll", "testcentric.engine.metadata.dll"), + "nunit-agent-netcore31.dll", "nunit-agent-netcore31.dll.config", + "nunit.engine.core.dll", "nunit.engine.api.dll", "testcentric.engine.metadata.dll", + "Microsoft.Extensions.DependencyModel.dll"), HasDirectory("NUnit.org/nunit-console/agents/nunit-agent-net50") .WithFiles( - "nunit-agent-net50.dll", "nunit.engine.core.dll", - "nunit.engine.api.dll", "testcentric.engine.metadata.dll"), + "nunit-agent-net50.dll", "nunit-agent-net50.dll.config", + "nunit.engine.core.dll", "nunit.engine.api.dll", "testcentric.engine.metadata.dll", + "Microsoft.Extensions.DependencyModel.dll"), HasDirectory("NUnit.org/nunit-console/agents/nunit-agent-net60") .WithFiles( - "nunit-agent-net60.dll", "nunit.engine.core.dll", - "nunit.engine.api.dll", "testcentric.engine.metadata.dll"), + "nunit-agent-net60.dll", "nunit-agent-net60.dll.config", + "nunit.engine.core.dll", "nunit.engine.api.dll", "testcentric.engine.metadata.dll", + "Microsoft.Extensions.DependencyModel.dll"), HasDirectory("NUnit.org/nunit-console/agents/nunit-agent-net70") .WithFiles( - "nunit-agent-net70.dll", "nunit.engine.core.dll", - "nunit.engine.api.dll", "testcentric.engine.metadata.dll") + "nunit-agent-net70.dll", "nunit-agent-net70.dll.config", + "nunit.engine.core.dll", "nunit.engine.api.dll", "testcentric.engine.metadata.dll", + "Microsoft.Extensions.DependencyModel.dll") }, executable: "NUnit.org/nunit-console/nunit4-console.exe", tests: StandardRunnerTests.Concat(new[] { NUnitProjectTest })), @@ -260,19 +268,23 @@ public void InitializePackageDefinitions(ICakeContext context) "nunit-agent-net462.pdb", "nunit-agent-net462-x86.pdb", "nunit.engine.core.pdb", "nunit.engine.api.pdb"), HasDirectory("bin/agents/nunit-agent-netcore31") .WithFiles( - "nunit-agent-netcore31.dll", "nunit.engine.core.dll", "nunit.engine.api.dll", "testcentric.engine.metadata.dll", + "nunit-agent-netcore31.dll", "nunit.engine.core.dll", "nunit.engine.api.dll", + "testcentric.engine.metadata.dll", "Microsoft.Extensions.DependencyModel.dll", "nunit-agent-netcore31.pdb", "nunit.engine.core.pdb", "nunit.engine.api.pdb"), HasDirectory("bin/agents/nunit-agent-net50") .WithFiles( - "nunit-agent-net50.dll", "nunit.engine.core.dll", "nunit.engine.api.dll", "testcentric.engine.metadata.dll", + "nunit-agent-net50.dll", "nunit.engine.core.dll", "nunit.engine.api.dll", + "testcentric.engine.metadata.dll", "Microsoft.Extensions.DependencyModel.dll", "nunit-agent-net50.pdb", "nunit.engine.core.pdb", "nunit.engine.api.pdb"), HasDirectory("bin/agents/nunit-agent-net60") .WithFiles( - "nunit-agent-net60.dll", "nunit.engine.core.dll", "nunit.engine.api.dll", "testcentric.engine.metadata.dll", + "nunit-agent-net60.dll", "nunit.engine.core.dll", "nunit.engine.api.dll", + "testcentric.engine.metadata.dll", "Microsoft.Extensions.DependencyModel.dll", "nunit-agent-net60.pdb", "nunit.engine.core.pdb", "nunit.engine.api.pdb"), HasDirectory("bin/agents/nunit-agent-net70") .WithFiles( - "nunit-agent-net70.dll", "nunit.engine.core.dll", "nunit.engine.api.dll", "testcentric.engine.metadata.dll", + "nunit-agent-net70.dll", "nunit.engine.core.dll", "nunit.engine.api.dll", + "testcentric.engine.metadata.dll", "Microsoft.Extensions.DependencyModel.dll", "nunit-agent-net70.pdb", "nunit.engine.core.pdb", "nunit.engine.api.pdb") }, executable: $"bin/nunit4-console.exe", diff --git a/choco/nunit-console-runner.nuspec b/choco/nunit-console-runner.nuspec index c05a034dd..ea4cc9f6d 100644 --- a/choco/nunit-console-runner.nuspec +++ b/choco/nunit-console-runner.nuspec @@ -69,6 +69,7 @@ + @@ -78,6 +79,7 @@ + @@ -87,6 +89,7 @@ + @@ -96,5 +99,6 @@ + diff --git a/msi/nunit/engine-files.wxi b/msi/nunit/engine-files.wxi index d8265cbf0..1194b07de 100644 --- a/msi/nunit/engine-files.wxi +++ b/msi/nunit/engine-files.wxi @@ -113,9 +113,11 @@ - + + + + - + - + + + - + + + + - + + + + diff --git a/nuget/runners/nunit.console-runner.netcore.nuspec b/nuget/runners/nunit.console-runner.netcore.nuspec index c6fc2b43a..bd504781a 100644 --- a/nuget/runners/nunit.console-runner.netcore.nuspec +++ b/nuget/runners/nunit.console-runner.netcore.nuspec @@ -43,6 +43,7 @@ + diff --git a/nuget/runners/nunit.console-runner.nuspec b/nuget/runners/nunit.console-runner.nuspec index c85420f86..56689f91c 100644 --- a/nuget/runners/nunit.console-runner.nuspec +++ b/nuget/runners/nunit.console-runner.nuspec @@ -63,6 +63,7 @@ + @@ -75,6 +76,7 @@ + @@ -87,6 +89,7 @@ + @@ -99,6 +102,7 @@ + diff --git a/src/NUnitEngine/nunit.engine.core/Drivers/NUnitNetCore31Driver.cs b/src/NUnitEngine/nunit.engine.core/Drivers/NUnitNetCore31Driver.cs index 3dfacd130..10abde4cf 100644 --- a/src/NUnitEngine/nunit.engine.core/Drivers/NUnitNetCore31Driver.cs +++ b/src/NUnitEngine/nunit.engine.core/Drivers/NUnitNetCore31Driver.cs @@ -38,7 +38,7 @@ public class NUnitNetCore31Driver : IFrameworkDriver Assembly _frameworkAssembly; object _frameworkController; Type _frameworkControllerType; - CustomAssemblyLoadContext _assemblyLoadContext; + TestAssemblyLoadContext _assemblyLoadContext; /// /// An id prefix that will be passed to the test framework and used as part of the @@ -58,13 +58,7 @@ public string Load(string assemblyPath, IDictionary settings) var idPrefix = string.IsNullOrEmpty(ID) ? "" : ID + "-"; assemblyPath = Path.GetFullPath(assemblyPath); //AssemblyLoadContext requires an absolute path - _assemblyLoadContext = new CustomAssemblyLoadContext(assemblyPath); - - _assemblyLoadContext.Resolving += (context, assemblyName) => - { - var calc = context as CustomAssemblyLoadContext; - return calc?.LoadFallback(assemblyName); - }; + _assemblyLoadContext = new TestAssemblyLoadContext(assemblyPath); try { diff --git a/src/NUnitEngine/nunit.engine.core/Internal/CustomAssemblyLoadContext.cs b/src/NUnitEngine/nunit.engine.core/Internal/CustomAssemblyLoadContext.cs deleted file mode 100644 index 154ac8c40..000000000 --- a/src/NUnitEngine/nunit.engine.core/Internal/CustomAssemblyLoadContext.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) Charlie Poole, Rob Prouse and Contributors. MIT License - see LICENSE.txt - -#if NETCOREAPP3_1_OR_GREATER - -using System.Reflection; -using System.Runtime.Loader; -using System.IO; -using System.Linq; -using System; - -namespace NUnit.Engine.Internal -{ - internal class CustomAssemblyLoadContext : AssemblyLoadContext - { - private readonly AssemblyDependencyResolver _resolver; - private readonly string _basePath; - - public CustomAssemblyLoadContext(string mainAssemblyToLoadPath) - { - _resolver = new AssemblyDependencyResolver(mainAssemblyToLoadPath); - _basePath = Path.GetDirectoryName(mainAssemblyToLoadPath); - } - - protected override Assembly Load(AssemblyName name) - { - var assemblies = AppDomain.CurrentDomain.GetAssemblies(); - var loaded = assemblies.FirstOrDefault(x => x.GetName().Name == name.Name); - if (loaded != null) - return loaded; - - var assemblyPath = _resolver.ResolveAssemblyToPath(name); - return assemblyPath != null ? LoadFromAssemblyPath(assemblyPath) : null; - } - - /// - /// Loads assemblies that are dependencies, and in the same folder as the parent assembly, - /// but are not fully specified in parent assembly deps.json file. This happens when the - /// dependencies reference in the csproj file has CopyLocal=false, and for example, the - /// reference is a projectReference and has the same output directory as the parent. - /// - /// LoadFallback should be called via the CustomAssemblyLoadContext.Resolving callback when - /// a dependent assembly of that referred to in a previous 'CustomAssemblyLoadContext.Load' call - /// could not be loaded by CustomAssemblyLoadContext.Load nor by the default ALC; to which the - /// runtime will fallback when CustomAssemblyLoadContext.Load fails (to let the default ALC - /// load system assemblies). - /// - /// - /// - public Assembly LoadFallback(AssemblyName name) - { - string assemblyPath = Path.Combine(_basePath, name.Name + ".dll"); - if (File.Exists(assemblyPath)) - return LoadFromAssemblyPath(assemblyPath); - return null; - } - } -} - -#endif diff --git a/src/NUnitEngine/nunit.engine.core/Internal/TestAssemblyLoadContext.cs b/src/NUnitEngine/nunit.engine.core/Internal/TestAssemblyLoadContext.cs new file mode 100644 index 000000000..bac035bab --- /dev/null +++ b/src/NUnitEngine/nunit.engine.core/Internal/TestAssemblyLoadContext.cs @@ -0,0 +1,50 @@ +// Copyright (c) Charlie Poole, Rob Prouse and Contributors. MIT License - see LICENSE.txt + +#if NETCOREAPP3_1_OR_GREATER + +using System.Reflection; +using System.Runtime.Loader; +using System.IO; +using System; +using System.Linq; + +namespace NUnit.Engine.Internal +{ + internal sealed class TestAssemblyLoadContext : AssemblyLoadContext + { + private readonly string _testAssemblyPath; + private readonly string _basePath; + private readonly TestAssemblyResolver _resolver; + + public TestAssemblyLoadContext(string testAssemblyPath) + { + _testAssemblyPath = testAssemblyPath; + _resolver = new TestAssemblyResolver(this, testAssemblyPath); + _basePath = Path.GetDirectoryName(testAssemblyPath); + } + + protected override Assembly Load(AssemblyName name) + { + var assemblies = AppDomain.CurrentDomain.GetAssemblies(); + var loadedAssembly = assemblies.FirstOrDefault(x => x.GetName().Name == name.Name); + + if (loadedAssembly != null) + loadedAssembly = base.Load(name); + + if (loadedAssembly == null) + { + // Load assemblies that are dependencies, and in the same folder as the test assembly, + // but are not fully specified in test assembly deps.json file. This happens when the + // dependencies reference in the csproj file has CopyLocal=false, and for example, the + // reference is a projectReference and has the same output directory as the parent. + string assemblyPath = Path.Combine(_basePath, name.Name + ".dll"); + if (File.Exists(assemblyPath)) + loadedAssembly = LoadFromAssemblyPath(assemblyPath); + } + + return loadedAssembly; + } + } +} + +#endif diff --git a/src/NUnitEngine/nunit.engine.core/Internal/TestAssemblyResolver.cs b/src/NUnitEngine/nunit.engine.core/Internal/TestAssemblyResolver.cs new file mode 100644 index 000000000..3e0edaf78 --- /dev/null +++ b/src/NUnitEngine/nunit.engine.core/Internal/TestAssemblyResolver.cs @@ -0,0 +1,71 @@ +// Copyright (c) Charlie Poole, Rob Prouse and Contributors. MIT License - see LICENSE.txt + +#if NETCOREAPP3_1_OR_GREATER + +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Reflection; +using System.Runtime.Loader; +using Microsoft.Extensions.DependencyModel; +using Microsoft.Extensions.DependencyModel.Resolution; + +namespace NUnit.Engine.Internal +{ + internal sealed class TestAssemblyResolver : IDisposable + { + private readonly ICompilationAssemblyResolver _assemblyResolver; + private readonly DependencyContext _dependencyContext; + private readonly AssemblyLoadContext _loadContext; + private readonly string _basePath; + + public TestAssemblyResolver(AssemblyLoadContext loadContext, string assemblyPath) + { + _loadContext = loadContext; + _dependencyContext = DependencyContext.Load(loadContext.LoadFromAssemblyPath(assemblyPath)); + _basePath = Path.GetDirectoryName(assemblyPath); + + _assemblyResolver = new CompositeCompilationAssemblyResolver(new ICompilationAssemblyResolver[] + { + new AppBaseCompilationAssemblyResolver(Path.GetDirectoryName(assemblyPath)), + new ReferenceAssemblyPathResolver(), + new PackageCompilationAssemblyResolver() + }); + + _loadContext.Resolving += OnResolving; + } + + public void Dispose() + { + _loadContext.Resolving -= OnResolving; + } + + private Assembly OnResolving(AssemblyLoadContext context, AssemblyName name) + { + foreach (var library in _dependencyContext.RuntimeLibraries) + { + var wrapper = new CompilationLibrary( + library.Type, + library.Name, + library.Version, + library.Hash, + library.RuntimeAssemblyGroups.SelectMany(g => g.AssetPaths), + library.Dependencies, + library.Serviceable); + + var assemblies = new List(); + _assemblyResolver.TryResolveAssemblyPaths(wrapper, assemblies); + + foreach (var assemblyPath in assemblies) + { + if (name.Name == Path.GetFileNameWithoutExtension(assemblyPath)) + return _loadContext.LoadFromAssemblyPath(assemblyPath); + } + } + + return null; + } + } +} +#endif diff --git a/src/NUnitEngine/nunit.engine.core/nunit.engine.core.csproj b/src/NUnitEngine/nunit.engine.core/nunit.engine.core.csproj index f52e31300..0b6ac2802 100644 --- a/src/NUnitEngine/nunit.engine.core/nunit.engine.core.csproj +++ b/src/NUnitEngine/nunit.engine.core/nunit.engine.core.csproj @@ -20,11 +20,16 @@ - - + + - + + + + + +