Skip to content

Commit

Permalink
Merge pull request #45 from TestCentric/issue-36
Browse files Browse the repository at this point in the history
Issue 36
  • Loading branch information
CharliePoole authored Feb 27, 2024
2 parents 2d49a14 + 579c85b commit c8d2147
Show file tree
Hide file tree
Showing 9 changed files with 317 additions and 148 deletions.
2 changes: 1 addition & 1 deletion src/TestCentric.Agent.Core.Tests/TestAgentRunnerTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ public void Load()
[Test]
public void CountTestCases()
{
int count = _runner.CountTestCases(TestFilter.Empty);
int count = _runner.CountTestCases(TestFilter.Empty);
Assert.That(count, Is.EqualTo(MockAssembly.Tests));
CheckPackageLoading();
}
Expand Down
144 changes: 0 additions & 144 deletions src/TestCentric.Agent.Core/Internal/TestAssemblyResolver.cs

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// ***********************************************************************
// Copyright (c) Charlie Poole and TestCentric contributors.
// Licensed under the MIT License. See LICENSE file in root directory.
// ***********************************************************************

#if NETCOREAPP3_1_OR_GREATER

using System.IO;
using System.Reflection;
using System.Runtime.Loader;

namespace TestCentric.Engine.Internal
{
internal abstract class AdditionalRuntimesResolutionStrategy : ResolutionStrategy
{
private static readonly Logger log = InternalTrace.GetLogger(nameof(AdditionalRuntimesResolutionStrategy));

protected abstract string RuntimeName { get; }

public AdditionalRuntimesResolutionStrategy(TestAssemblyResolver resolver) : base(resolver) { }

public override Assembly TryLoadAssembly(AssemblyLoadContext context, AssemblyName assemblyName)
{
// This strategy requires a version, which may not be present
if (assemblyName.Version == null)
return null;

var runtimeDir = DotNetRuntimes.GetBestRuntime(RuntimeName, assemblyName.Version).Location;
if (runtimeDir != null)
{
string candidate = Path.Combine(runtimeDir, assemblyName.Name + ".dll");
if (File.Exists(candidate))
{
log.Debug($"{RuntimeName} Resolved to {candidate}");
return LoadContext.LoadFromAssemblyPath(candidate);
}
}

log.Debug($"{RuntimeName} Failed!");
return null;
}
}

internal class AspNetCoreResolutionStrategy : AdditionalRuntimesResolutionStrategy
{
public AspNetCoreResolutionStrategy(TestAssemblyResolver resolver) : base(resolver) { }

protected override string RuntimeName => "Microsoft.AspNetCore.App";
}

internal class WindowsDesktopResolutionStrategy : AdditionalRuntimesResolutionStrategy
{
public WindowsDesktopResolutionStrategy(TestAssemblyResolver resolver) : base(resolver) { }

protected override string RuntimeName => "Microsoft.WindowsDesktop.App";
}
}
#endif
48 changes: 48 additions & 0 deletions src/TestCentric.Agent.Core/Resolvers/ResolutionStrategy.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// ***********************************************************************
// Copyright (c) Charlie Poole and TestCentric contributors.
// Licensed under the MIT License. See LICENSE file in root directory.
// ***********************************************************************

#if NETCOREAPP3_1_OR_GREATER

using System;
using System.Reflection;
using System.Runtime.Loader;
using TestCentric.Engine.Internal;

namespace TestCentric.Engine.Internal
{
public abstract class ResolutionStrategy
{
private int _totalCalls;

internal TestAssemblyLoadContext LoadContext { get; }
internal string TestAssemblyPath { get; }


internal ResolutionStrategy(TestAssemblyResolver resolver)
{
LoadContext = resolver.LoadContext;
TestAssemblyPath = resolver.TestAssemblyPath;
}

public bool TryLoadAssembly(AssemblyLoadContext context, AssemblyName assemblyName, out Assembly loadedAssembly)
{
_totalCalls++;

loadedAssembly = TryLoadAssembly(context, assemblyName);
return loadedAssembly != null;
}

public abstract Assembly TryLoadAssembly(AssemblyLoadContext context, AssemblyName assemblyName);

public void WriteReport()
{
Console.WriteLine();
Console.WriteLine(GetType().Name);
Console.WriteLine();
Console.WriteLine($"Total Calls: {_totalCalls}");
}
}
}
#endif
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
// ***********************************************************************
// Copyright (c) Charlie Poole and TestCentric contributors.
// Licensed under the MIT License. See LICENSE file in root directory.
// ***********************************************************************

#if NETCOREAPP3_1_OR_GREATER

using Microsoft.Extensions.DependencyModel.Resolution;
using Microsoft.Extensions.DependencyModel;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.Loader;
using System.Linq;

namespace TestCentric.Engine.Internal
{
internal class RuntimeLibraryResolutionStrategy : ResolutionStrategy
{
private static readonly Logger log = InternalTrace.GetLogger(nameof(RuntimeLibraryResolutionStrategy));

private List<CompilationLibrary> _libraries = new List<CompilationLibrary>();

public RuntimeLibraryResolutionStrategy(TestAssemblyResolver resolver) : base(resolver)
{
var dependencyContext = DependencyContext.Load(LoadContext.LoadFromAssemblyPath(TestAssemblyPath));
if (dependencyContext != null)
foreach (var library in dependencyContext.RuntimeLibraries)
_libraries.Add(
new CompilationLibrary(
library.Type,
library.Name,
library.Version,
library.Hash,
library.RuntimeAssemblyGroups.SelectMany(g => g.AssetPaths),
library.Dependencies,
library.Serviceable));
}

public override Assembly TryLoadAssembly(AssemblyLoadContext context, AssemblyName assemblyName)
{
foreach (var library in _libraries)
{
var assemblies = new List<string>();
var assemblyResolver = new CompositeCompilationAssemblyResolver(new ICompilationAssemblyResolver[]
{
new AppBaseCompilationAssemblyResolver(Path.GetDirectoryName(TestAssemblyPath)),
new ReferenceAssemblyPathResolver(),
new PackageCompilationAssemblyResolver()
});

assemblyResolver.TryResolveAssemblyPaths(library, assemblies);

foreach (var assemblyPath in assemblies)
{
if (assemblyName.Name == Path.GetFileNameWithoutExtension(assemblyPath))
{
log.Debug($"Resolved to {assemblyPath}");
return LoadContext.LoadFromAssemblyPath(assemblyPath);
}
}
}

log.Debug("Failed!");
return null;
}
}
}
#endif
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,17 @@ internal sealed class TestAssemblyLoadContext : AssemblyLoadContext
{
private static readonly Logger log = InternalTrace.GetLogger(nameof(TestAssemblyLoadContext));

private readonly string _testAssemblyPath;
internal readonly string _testAssemblyPath;
private readonly string _basePath;
private readonly TestAssemblyResolver _resolver;

public TestAssemblyResolver Resolver { get; }

public TestAssemblyLoadContext(string testAssemblyPath)
{
_testAssemblyPath = testAssemblyPath;
_resolver = new TestAssemblyResolver(this, testAssemblyPath);
_basePath = Path.GetDirectoryName(testAssemblyPath);

Resolver = new TestAssemblyResolver(this, testAssemblyPath);
}

protected override Assembly Load(AssemblyName name)
Expand Down
Loading

0 comments on commit c8d2147

Please sign in to comment.