Skip to content

Commit 8f472b0

Browse files
authored
Merge pull request #1337 from svg2003/issue-1330-v4
Issue 1330 v4
2 parents b92df46 + 38d141e commit 8f472b0

File tree

2 files changed

+101
-9
lines changed

2 files changed

+101
-9
lines changed

src/NUnitEngine/nunit.engine.core/Internal/TestAssemblyLoadContext.cs

+30-7
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ namespace NUnit.Engine.Internal
1212
{
1313
internal sealed class TestAssemblyLoadContext : AssemblyLoadContext
1414
{
15+
private static readonly Logger log = InternalTrace.GetLogger(typeof(TestAssemblyLoadContext));
16+
1517
private readonly string _testAssemblyPath;
1618
private readonly string _basePath;
1719
private readonly TestAssemblyResolver _resolver;
@@ -27,19 +29,16 @@ public TestAssemblyLoadContext(string testAssemblyPath)
2729

2830
protected override Assembly Load(AssemblyName name)
2931
{
30-
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
31-
var loadedAssembly = assemblies.FirstOrDefault(x => x.GetName().Name == name.Name);
32-
if (loadedAssembly != null)
33-
{
34-
return loadedAssembly;
35-
}
32+
log.Debug("Loading {0} assembly", name);
3633

37-
loadedAssembly = base.Load(name);
34+
var loadedAssembly = base.Load(name);
3835
if (loadedAssembly != null)
3936
{
37+
log.Info("Assembly {0} ({1}) is loaded using default base.Load()", name, GetAssemblyLocationInfo(loadedAssembly));
4038
return loadedAssembly;
4139
}
4240

41+
4342
var runtimeResolverPath = _runtimeResolver.ResolveAssemblyToPath(name);
4443
if (string.IsNullOrEmpty(runtimeResolverPath) == false &&
4544
File.Exists(runtimeResolverPath))
@@ -49,12 +48,15 @@ protected override Assembly Load(AssemblyName name)
4948

5049
if (loadedAssembly != null)
5150
{
51+
log.Info("Assembly {0} ({1}) is loaded using the deps.json info", name, GetAssemblyLocationInfo(loadedAssembly));
5252
return loadedAssembly;
5353
}
5454

5555
loadedAssembly = _resolver.Resolve(this, name);
5656
if (loadedAssembly != null)
5757
{
58+
log.Info("Assembly {0} ({1}) is loaded using the TestAssembliesResolver", name, GetAssemblyLocationInfo(loadedAssembly));
59+
5860
return loadedAssembly;
5961
}
6062

@@ -68,8 +70,29 @@ protected override Assembly Load(AssemblyName name)
6870
loadedAssembly = LoadFromAssemblyPath(assemblyPath);
6971
}
7072

73+
if (loadedAssembly != null)
74+
{
75+
log.Info("Assembly {0} ({1}) is loaded using base path", name, GetAssemblyLocationInfo(loadedAssembly));
76+
return loadedAssembly;
77+
}
78+
7179
return loadedAssembly;
7280
}
81+
82+
private static string GetAssemblyLocationInfo(Assembly assembly)
83+
{
84+
if (assembly.IsDynamic)
85+
{
86+
return $"Dynamic {assembly.FullName}";
87+
}
88+
89+
if (string.IsNullOrEmpty(assembly.Location))
90+
{
91+
return $"No location for {assembly.FullName}";
92+
}
93+
94+
return $"{assembly.FullName} from {assembly.Location}";
95+
}
7396
}
7497
}
7598

src/NUnitEngine/nunit.engine.core/Internal/TestAssemblyResolver.cs

+71-2
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@ namespace NUnit.Engine.Internal
1717
{
1818
internal sealed class TestAssemblyResolver : IDisposable
1919
{
20+
private static readonly Logger log = InternalTrace.GetLogger(typeof(TestAssemblyResolver));
21+
2022
private readonly ICompilationAssemblyResolver _assemblyResolver;
2123
private readonly DependencyContext _dependencyContext;
2224
private readonly AssemblyLoadContext _loadContext;
@@ -62,6 +64,14 @@ public Assembly Resolve(AssemblyLoadContext context, AssemblyName name)
6264

6365
private Assembly OnResolving(AssemblyLoadContext context, AssemblyName name)
6466
{
67+
context = context ?? _loadContext;
68+
69+
if (TryLoadFromTrustedPlatformAssemblies(context, name, out var loadedAssembly))
70+
{
71+
log.Info("'{0}' assembly is loaded from trusted path '{1}'", name, loadedAssembly.Location);
72+
return loadedAssembly;
73+
}
74+
6575
foreach (var library in _dependencyContext.RuntimeLibraries)
6676
{
6777
var wrapper = new CompilationLibrary(
@@ -79,24 +89,81 @@ private Assembly OnResolving(AssemblyLoadContext context, AssemblyName name)
7989
foreach (var assemblyPath in assemblies)
8090
{
8191
if (name.Name == Path.GetFileNameWithoutExtension(assemblyPath))
82-
return _loadContext.LoadFromAssemblyPath(assemblyPath);
92+
{
93+
loadedAssembly = context.LoadFromAssemblyPath(assemblyPath);
94+
log.Info("'{0}' ({1}) assembly is loaded from runtime libraries {2} dependencies",
95+
name,
96+
loadedAssembly.Location,
97+
library.Name);
98+
99+
return loadedAssembly;
100+
}
83101
}
84102
}
85103

104+
if (name.Version == null)
105+
{
106+
return null;
107+
}
108+
86109
foreach (string frameworkDirectory in AdditionalFrameworkDirectories)
87110
{
88111
var versionDir = FindBestVersionDir(frameworkDirectory, name.Version);
112+
89113
if (versionDir != null)
90114
{
91115
string candidate = Path.Combine(frameworkDirectory, versionDir, name.Name + ".dll");
92116
if (File.Exists(candidate))
93-
return _loadContext.LoadFromAssemblyPath(candidate);
117+
{
118+
loadedAssembly = context.LoadFromAssemblyPath(candidate);
119+
log.Info("'{0}' ({1}) assembly is loaded from AdditionalFrameworkDirectory {2} dependencies with best candidate version {3}",
120+
name,
121+
loadedAssembly.Location,
122+
frameworkDirectory,
123+
versionDir);
124+
125+
return loadedAssembly;
126+
}
127+
else
128+
{
129+
log.Debug("Best version dir for {0} is {1}, but there is no {2} file", frameworkDirectory, versionDir, candidate);
130+
}
94131
}
95132
}
96133

134+
log.Info("Cannot resolve assembly '{0}'", name);
97135
return null;
98136
}
99137

138+
private static bool TryLoadFromTrustedPlatformAssemblies(AssemblyLoadContext context, AssemblyName assemblyName, out Assembly loadedAssembly)
139+
{
140+
// https://learn.microsoft.com/en-us/dotnet/core/dependency-loading/default-probing
141+
loadedAssembly = null;
142+
var trustedAssemblies = System.AppContext.GetData("TRUSTED_PLATFORM_ASSEMBLIES") as string;
143+
if (string.IsNullOrEmpty(trustedAssemblies))
144+
{
145+
return false;
146+
}
147+
148+
var separator = RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? ";" : ":";
149+
foreach (var assemblyPath in trustedAssemblies.Split(separator))
150+
{
151+
var fileName = Path.GetFileNameWithoutExtension(assemblyPath);
152+
if (string.Equals(fileName, assemblyName.Name, StringComparison.InvariantCultureIgnoreCase) == false)
153+
{
154+
continue;
155+
}
156+
157+
if (File.Exists(assemblyPath))
158+
{
159+
loadedAssembly = context.LoadFromAssemblyPath(assemblyPath);
160+
return true;
161+
}
162+
}
163+
164+
return false;
165+
}
166+
100167
private static string GetDotNetInstallDirectory()
101168
{
102169
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
@@ -119,9 +186,11 @@ private static string FindBestVersionDir(string libraryDir, Version targetVersio
119186
{
120187
Version version;
121188
if (TryGetVersionFromString(Path.GetFileName(subdir), out version))
189+
{
122190
if (version >= targetVersion)
123191
if (bestVersion.Major == 0 || bestVersion > version)
124192
bestVersion = version;
193+
}
125194
}
126195

127196
return bestVersion.Major > 0

0 commit comments

Comments
 (0)