Fun with assembly loading

This commit is contained in:
benbierens 2023-09-12 11:25:04 +02:00
parent 0f86642524
commit c995732f35
No known key found for this signature in database
GPG Key ID: FE44815D96D0A1AA
10 changed files with 108 additions and 46 deletions

View File

@ -4,7 +4,7 @@ using Logging;
namespace CodexPlugin
{
public class Plugin : IProjectPlugin
public class CodexPlugin : IProjectPlugin
{
private CodexStarter codexStarter = null!;
@ -18,8 +18,6 @@ namespace CodexPlugin
public void Initialize(IPluginTools tools)
{
codexStarter = new CodexStarter(tools);
DistTestExtensions.Plugin = this;
}
public void Finalize(ILog log)

View File

@ -1,30 +0,0 @@
using DistTestCore;
using KubernetesWorkflow;
namespace CodexPlugin
{
public static class DistTestExtensions
{
public static Plugin Plugin { get; internal set; } = null!;
public static RunningContainers[] StartCodexNodes(this DistTest distTest, int number, Action<ICodexSetup> setup)
{
return Plugin.StartCodexNodes(number, setup);
}
public static ICodexNodeGroup WrapCodexContainers(this DistTest distTest, RunningContainers[] containers)
{
return Plugin.WrapCodexContainers(containers);
}
public static IOnlineCodexNode SetupCodexNode(this DistTest distTest, Action<ICodexSetup> setup)
{
return Plugin.SetupCodexNode(setup);
}
public static ICodexNodeGroup SetupCodexNodes(this DistTest distTest, int number)
{
return Plugin.SetupCodexNodes(number);
}
}
}

View File

@ -0,0 +1,33 @@
using DistTestCore;
using KubernetesWorkflow;
namespace CodexPlugin
{
public static class PluginInterfaceExtensions
{
public static RunningContainers[] StartCodexNodes(this PluginInterface pluginInterface, int number, Action<ICodexSetup> setup)
{
return Plugin(pluginInterface).StartCodexNodes(number, setup);
}
public static ICodexNodeGroup WrapCodexContainers(this PluginInterface pluginInterface, RunningContainers[] containers)
{
return Plugin(pluginInterface).WrapCodexContainers(containers);
}
public static IOnlineCodexNode SetupCodexNode(this PluginInterface pluginInterface, Action<ICodexSetup> setup)
{
return Plugin(pluginInterface).SetupCodexNode(setup);
}
public static ICodexNodeGroup SetupCodexNodes(this PluginInterface pluginInterface, int number)
{
return Plugin(pluginInterface).SetupCodexNodes(number);
}
private static CodexPlugin Plugin(PluginInterface pluginInterface)
{
return pluginInterface.GetPlugin<CodexPlugin>();
}
}
}

View File

@ -9,7 +9,7 @@ using Utils;
namespace DistTestCore
{
[Parallelizable(ParallelScope.All)]
public abstract class DistTest
public abstract class DistTest : PluginInterface
{
private const string TestsType = "dist-tests";
private readonly Configuration configuration = new Configuration();
@ -153,6 +153,11 @@ namespace DistTestCore
// return Get().CodexStarter.RunningGroups.SelectMany(g => g.Nodes);
//}
public override T GetPlugin<T>()
{
return Get().GetPlugin<T>();
}
private void AnnouncePlugins(FixtureLog fixtureLog)
{
PluginManager.AnnouncePlugins(fixtureLog);

View File

@ -0,0 +1,7 @@
namespace DistTestCore
{
public abstract class PluginInterface
{
public abstract T GetPlugin<T>() where T : IProjectPlugin;
}
}

View File

@ -1,6 +1,7 @@
using FileUtils;
using KubernetesWorkflow;
using Logging;
using System.Reflection;
using Utils;
namespace DistTestCore
@ -34,6 +35,11 @@ namespace DistTestCore
{
foreach (var plugin in projectPlugins) plugin.Finalize(log);
}
public T GetPlugin<T>() where T : IProjectPlugin
{
return (T)projectPlugins.Single(p => p.GetType() == typeof(T));
}
}
public static class PluginFinder
@ -45,10 +51,37 @@ namespace DistTestCore
if (pluginTypes != null) return pluginTypes;
// Reflection can be costly. Do this only once.
FindAndLoadPluginAssemblies();
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
pluginTypes = assemblies.SelectMany(a => a.GetTypes().Where(t => typeof(IProjectPlugin).IsAssignableFrom(t))).ToArray();
pluginTypes = assemblies.SelectMany(a => a.GetTypes().Where(t =>
typeof(IProjectPlugin).IsAssignableFrom(t) &&
!t.IsAbstract)
).ToArray();
return pluginTypes;
}
private static void FindAndLoadPluginAssemblies()
{
var files = Directory.GetFiles(".");
foreach (var file in files)
{
var f = file.ToLowerInvariant();
if (f.Contains("plugin") && f.EndsWith("dll"))
{
var name = Path.GetFileNameWithoutExtension(file);
try
{
Assembly.Load(name);
}
catch (Exception ex)
{
throw new Exception($"Failed to load plugin from file '{name}'.", ex);
}
}
}
}
}
public interface IProjectPlugin

View File

@ -32,6 +32,11 @@ namespace DistTestCore
public string TestNamespace { get; }
public IFileManager FileManager { get; }
public T GetPlugin<T>() where T : IProjectPlugin
{
return pluginManager.GetPlugin<T>();
}
public Http CreateHttp(Address address, string baseUrl, Action<HttpClient> onClientCreated, string? logAlias = null)
{
return new Http(Log, TimeSet, address, baseUrl, onClientCreated, logAlias);

19
Logging/BaseTestLog.cs Normal file
View File

@ -0,0 +1,19 @@
namespace Logging
{
public abstract class BaseTestLog : BaseLog
{
private bool hasFailed;
public BaseTestLog(bool debug)
: base(debug)
{
}
public void MarkAsFailed()
{
if (hasFailed) return;
hasFailed = true;
LogFile.ConcatToFilename("_FAILED");
}
}
}

View File

@ -1,12 +1,12 @@
namespace Logging
{
public class FixtureLog : TestLog
public class FixtureLog : BaseTestLog
{
private readonly string fullName;
private readonly LogConfig config;
public FixtureLog(LogConfig config, DateTime start, string name = "")
: base(config.LogRoot, config.DebugEnabled)
: base(config.DebugEnabled)
{
fullName = NameUtils.GetFixtureFullName(config, start, name);
this.config = config;

View File

@ -1,10 +1,9 @@
namespace Logging
{
public class TestLog : BaseLog
public class TestLog : BaseTestLog
{
private readonly string methodName;
private readonly string fullName;
private bool hasFailed;
public TestLog(string folder, bool debug, string name = "")
: base(debug)
@ -15,13 +14,6 @@
Log($"*** Begin: {methodName}");
}
public void MarkAsFailed()
{
if (hasFailed) return;
hasFailed = true;
LogFile.ConcatToFilename("_FAILED");
}
protected override string GetFullName()
{
return fullName;