diff --git a/Framework/Core/EntryPoint.cs b/Framework/Core/EntryPoint.cs index 5ce9af1..7977eb3 100644 --- a/Framework/Core/EntryPoint.cs +++ b/Framework/Core/EntryPoint.cs @@ -38,9 +38,10 @@ namespace Core return new CoreInterface(this); } - public void Decommission() + public void Decommission(bool deleteKubernetesResources, bool deleteTrackedFiles) { - manager.DecommissionPlugins(); + manager.DecommissionPlugins(deleteKubernetesResources, deleteTrackedFiles); + Tools.Decommission(deleteKubernetesResources, deleteTrackedFiles); } internal T GetPlugin() where T : IProjectPlugin diff --git a/Framework/Core/PluginManager.cs b/Framework/Core/PluginManager.cs index 7de080f..e2b2a5c 100644 --- a/Framework/Core/PluginManager.cs +++ b/Framework/Core/PluginManager.cs @@ -2,11 +2,11 @@ { internal class PluginManager { - private readonly List projectPlugins = new List(); + private readonly List pairs = new List(); internal void InstantiatePlugins(Type[] pluginTypes, IToolsFactory provider) { - projectPlugins.Clear(); + pairs.Clear(); foreach (var pluginType in pluginTypes) { var tools = provider.CreateTools(); @@ -18,15 +18,15 @@ internal void AnnouncePlugins() { - foreach (var plugin in projectPlugins) plugin.Announce(); + foreach (var pair in pairs) pair.Plugin.Announce(); } internal PluginMetadata GatherPluginMetadata() { var metadata = new PluginMetadata(); - foreach (var plugin in projectPlugins) + foreach (var pair in pairs) { - if (plugin is IHasMetadata m) + if (pair.Plugin is IHasMetadata m) { m.AddMetadata(metadata); } @@ -34,20 +34,24 @@ return metadata; } - internal void DecommissionPlugins() + internal void DecommissionPlugins(bool deleteKubernetesResources, bool deleteTrackedFiles) { - foreach (var plugin in projectPlugins) plugin.Decommission(); + foreach (var pair in pairs) + { + pair.Plugin.Decommission(); + pair.Tools.Decommission(deleteKubernetesResources, deleteTrackedFiles); + } } internal T GetPlugin() where T : IProjectPlugin { - return (T)projectPlugins.Single(p => p.GetType() == typeof(T)); + return (T)pairs.Single(p => p.Plugin.GetType() == typeof(T)).Plugin; } private IProjectPlugin InstantiatePlugins(Type pluginType, PluginTools tools) { var plugin = (IProjectPlugin)Activator.CreateInstance(pluginType, args: tools)!; - projectPlugins.Add(plugin); + pairs.Add(new PluginToolsPair(plugin, tools)); return plugin; } @@ -58,5 +62,17 @@ tools.ApplyLogPrefix(hasLogPrefix.LogPrefix); } } + + private class PluginToolsPair + { + public PluginToolsPair(IProjectPlugin plugin, IPluginTools tools) + { + Plugin = plugin; + Tools = tools; + } + + public IProjectPlugin Plugin { get; } + public IPluginTools Tools { get; } + } } } diff --git a/Framework/Core/PluginTools.cs b/Framework/Core/PluginTools.cs index dd0360c..5fd0ab8 100644 --- a/Framework/Core/PluginTools.cs +++ b/Framework/Core/PluginTools.cs @@ -7,6 +7,7 @@ namespace Core { public interface IPluginTools : IWorkflowTool, ILogTool, IHttpFactoryTool, IFileTool { + void Decommission(bool deleteKubernetesResources, bool deleteTrackedFiles); } public interface IWorkflowTool @@ -65,6 +66,12 @@ namespace Core return workflowCreator.CreateWorkflow(namespaceOverride); } + public void Decommission(bool deleteKubernetesResources, bool deleteTrackedFiles) + { + if (deleteKubernetesResources) CreateWorkflow().DeleteNamespace(); + if (deleteTrackedFiles) fileManager.DeleteAllFiles(); + } + public IFileManager GetFileManager() { return fileManager; diff --git a/Framework/FileUtils/FileManager.cs b/Framework/FileUtils/FileManager.cs index 7723ae6..9b25c56 100644 --- a/Framework/FileUtils/FileManager.cs +++ b/Framework/FileUtils/FileManager.cs @@ -18,6 +18,7 @@ namespace FileUtils private static NumberSource folderNumberSource = new NumberSource(0); private readonly Random random = new Random(); private readonly ILog log; + private readonly string rootFolder; private readonly string folder; private readonly List> fileSetStack = new List>(); @@ -25,13 +26,15 @@ namespace FileUtils { folder = Path.Combine(rootFolder, folderNumberSource.GetNextNumber().ToString("D5")); - EnsureDirectory(); this.log = log; + this.rootFolder = rootFolder; } public TrackedFile CreateEmptyFile(string label = "") { - var path = Path.Combine(folder, Guid.NewGuid().ToString() + "_test.bin"); + var path = Path.Combine(folder, Guid.NewGuid().ToString() + ".bin"); + EnsureDirectory(); + var result = new TrackedFile(log, path, label); File.Create(result.Filename).Close(); if (fileSetStack.Any()) fileSetStack.Last().Add(result); @@ -79,12 +82,11 @@ namespace FileUtils foreach (var file in pop) { - try - { - File.Delete(file.Filename); - } - catch { } + File.Delete(file.Filename); } + + // If the folder is now empty, delete it too. + if (!Directory.GetFiles(folder).Any()) DeleteDirectory(); } private TrackedFile GenerateRandomFile(ByteSize size, string label) @@ -144,12 +146,12 @@ namespace FileUtils private void EnsureDirectory() { - if (!Directory.Exists(folder)) Directory.CreateDirectory(folder); + Directory.CreateDirectory(folder); } private void DeleteDirectory() { - Directory.Delete(folder, true); + if (Directory.Exists(folder)) Directory.Delete(folder, true); } } } diff --git a/Framework/Logging/ConsoleLog.cs b/Framework/Logging/ConsoleLog.cs new file mode 100644 index 0000000..61e6115 --- /dev/null +++ b/Framework/Logging/ConsoleLog.cs @@ -0,0 +1,19 @@ +namespace Logging +{ + public class ConsoleLog : BaseLog + { + public ConsoleLog() : base(false) + { + } + + protected override string GetFullName() + { + return "CONSOLE"; + } + + public override void Log(string message) + { + Console.WriteLine(message); + } + } +} diff --git a/Framework/Logging/LogSplitter.cs b/Framework/Logging/LogSplitter.cs new file mode 100644 index 0000000..6d24d5b --- /dev/null +++ b/Framework/Logging/LogSplitter.cs @@ -0,0 +1,42 @@ +namespace Logging +{ + public class LogSplitter : ILog + { + private readonly ILog[] targetLogs; + + public LogSplitter(params ILog[] targetLogs) + { + this.targetLogs = targetLogs; + } + + public void AddStringReplace(string from, string to) + { + OnAll(l => l.AddStringReplace(from, to)); + } + + public LogFile CreateSubfile(string ext = "log") + { + return targetLogs.First().CreateSubfile(ext); + } + + public void Debug(string message = "", int skipFrames = 0) + { + OnAll(l => l.Debug(message, skipFrames + 2)); + } + + public void Error(string message) + { + OnAll(l => l.Error(message)); + } + + public void Log(string message) + { + OnAll(l => l.Log(message)); + } + + private void OnAll(Action action) + { + foreach (var t in targetLogs) action(t); + } + } +} diff --git a/Tests/CodexContinuousTests/ContinuousTest.cs b/Tests/CodexContinuousTests/ContinuousTest.cs index e4122fc..2bef6db 100644 --- a/Tests/CodexContinuousTests/ContinuousTest.cs +++ b/Tests/CodexContinuousTests/ContinuousTest.cs @@ -59,7 +59,6 @@ namespace ContinuousTests return GetType().Name; } } - } public enum TestFailMode diff --git a/Tests/CodexContinuousTests/ContinuousTestRunner.cs b/Tests/CodexContinuousTests/ContinuousTestRunner.cs index 470dbbb..a0589b2 100644 --- a/Tests/CodexContinuousTests/ContinuousTestRunner.cs +++ b/Tests/CodexContinuousTests/ContinuousTestRunner.cs @@ -19,21 +19,29 @@ namespace ContinuousTests public void Run() { - var overviewLog = new FixtureLog(new LogConfig(config.LogPath, false), DateTime.UtcNow, "Overview"); + var overviewLog = new LogSplitter( + new FixtureLog(new LogConfig(config.LogPath, false), DateTime.UtcNow, "Overview"), + new ConsoleLog() + ); + + overviewLog.Log("Initializing..."); var entryPoint = entryPointFactory.CreateEntryPoint(config.KubeConfigFile, config.DataPath, config.CodexDeployment.Metadata.KubeNamespace, overviewLog); entryPoint.Announce(); + overviewLog.Log("Initialized. Performing startup checks..."); + var startupChecker = new StartupChecker(entryPoint, config, cancelToken); startupChecker.Check(); var taskFactory = new TaskFactory(); - overviewLog.Log("Continuous tests starting..."); + overviewLog.Log("Startup checks passed. Continuous tests starting..."); + overviewLog.Log(""); var allTests = testFactory.CreateTests(); ClearAllCustomNamespaces(allTests, overviewLog); - var testLoops = allTests.Select(t => new TestLoop(entryPoint, taskFactory, config, overviewLog, t.GetType(), t.RunTestEvery, startupChecker, cancelToken)).ToArray(); + var testLoops = allTests.Select(t => new TestLoop(entryPointFactory, taskFactory, config, overviewLog, t.GetType(), t.RunTestEvery, startupChecker, cancelToken)).ToArray(); foreach (var testLoop in testLoops) { @@ -51,12 +59,12 @@ namespace ContinuousTests overviewLog.Log("All tasks cancelled."); } - private void ClearAllCustomNamespaces(ContinuousTest[] allTests, FixtureLog log) + private void ClearAllCustomNamespaces(ContinuousTest[] allTests, ILog log) { foreach (var test in allTests) ClearAllCustomNamespaces(test, log); } - private void ClearAllCustomNamespaces(ContinuousTest test, FixtureLog log) + private void ClearAllCustomNamespaces(ContinuousTest test, ILog log) { if (string.IsNullOrEmpty(test.CustomK8sNamespace)) return; diff --git a/Tests/CodexContinuousTests/Program.cs b/Tests/CodexContinuousTests/Program.cs index 273f13a..3db3b15 100644 --- a/Tests/CodexContinuousTests/Program.cs +++ b/Tests/CodexContinuousTests/Program.cs @@ -5,7 +5,6 @@ public class Program public static void Main(string[] args) { Console.WriteLine("Codex Continous-Test-Runner."); - Console.WriteLine("Running..."); var runner = new ContinuousTestRunner(args, Cancellation.Cts.Token); @@ -20,14 +19,14 @@ public class Program runner.Run(); Console.WriteLine("Done."); } - - public static class Cancellation - { - static Cancellation() - { - Cts = new CancellationTokenSource(); - } - - public static CancellationTokenSource Cts { get; } - } +} + +public static class Cancellation +{ + static Cancellation() + { + Cts = new CancellationTokenSource(); + } + + public static CancellationTokenSource Cts { get; } } diff --git a/Tests/CodexContinuousTests/SingleTestRun.cs b/Tests/CodexContinuousTests/SingleTestRun.cs index 319318d..7a233db 100644 --- a/Tests/CodexContinuousTests/SingleTestRun.cs +++ b/Tests/CodexContinuousTests/SingleTestRun.cs @@ -3,8 +3,6 @@ using Utils; using KubernetesWorkflow; using NUnit.Framework.Internal; using System.Reflection; -using static Program; -using FileUtils; using CodexPlugin; using DistTestCore.Logs; using Core; @@ -17,18 +15,16 @@ namespace ContinuousTests private readonly EntryPoint entryPoint; private readonly TaskFactory taskFactory; private readonly Configuration config; - private readonly BaseLog overviewLog; + private readonly ILog overviewLog; private readonly TestHandle handle; private readonly CancellationToken cancelToken; private readonly ICodexNode[] nodes; private readonly FixtureLog fixtureLog; private readonly string testName; - private readonly string dataFolder; private static int failureCount = 0; - public SingleTestRun(EntryPoint entryPoint, TaskFactory taskFactory, Configuration config, BaseLog overviewLog, TestHandle handle, StartupChecker startupChecker, CancellationToken cancelToken) + public SingleTestRun(EntryPointFactory entryPointFactory, TaskFactory taskFactory, Configuration config, ILog overviewLog, TestHandle handle, StartupChecker startupChecker, CancellationToken cancelToken) { - this.entryPoint = entryPoint; this.taskFactory = taskFactory; this.config = config; this.overviewLog = overviewLog; @@ -36,10 +32,10 @@ namespace ContinuousTests this.cancelToken = cancelToken; testName = handle.Test.GetType().Name; fixtureLog = new FixtureLog(new LogConfig(config.LogPath, true), DateTime.UtcNow, testName); + entryPoint = entryPointFactory.CreateEntryPoint(config.KubeConfigFile, config.DataPath, config.CodexDeployment.Metadata.KubeNamespace, fixtureLog); ApplyLogReplacements(fixtureLog, startupChecker); nodes = CreateRandomNodes(); - dataFolder = config.DataPath + "-" + Guid.NewGuid(); } public void Run(EventWaitHandle runFinishedHandle) @@ -49,8 +45,11 @@ namespace ContinuousTests try { RunTest(); - entryPoint.Tools.GetFileManager().DeleteAllFiles(); - Directory.Delete(dataFolder, true); + + entryPoint.Decommission( + deleteKubernetesResources: false, // This would delete the continuous test net. + deleteTrackedFiles: true + ); runFinishedHandle.Set(); } catch (Exception ex) diff --git a/Tests/CodexContinuousTests/TestLoop.cs b/Tests/CodexContinuousTests/TestLoop.cs index 2861481..48f66ca 100644 --- a/Tests/CodexContinuousTests/TestLoop.cs +++ b/Tests/CodexContinuousTests/TestLoop.cs @@ -1,23 +1,22 @@ -using Core; -using Logging; +using Logging; namespace ContinuousTests { public class TestLoop { - private readonly EntryPoint entryPoint; + private readonly EntryPointFactory entryPointFactory; private readonly TaskFactory taskFactory; private readonly Configuration config; - private readonly BaseLog overviewLog; + private readonly ILog overviewLog; private readonly Type testType; private readonly TimeSpan runsEvery; private readonly StartupChecker startupChecker; private readonly CancellationToken cancelToken; private readonly EventWaitHandle runFinishedHandle = new EventWaitHandle(true, EventResetMode.ManualReset); - public TestLoop(Core.EntryPoint entryPoint, TaskFactory taskFactory, Configuration config, BaseLog overviewLog, Type testType, TimeSpan runsEvery, StartupChecker startupChecker, CancellationToken cancelToken) + public TestLoop(EntryPointFactory entryPointFactory, TaskFactory taskFactory, Configuration config, ILog overviewLog, Type testType, TimeSpan runsEvery, StartupChecker startupChecker, CancellationToken cancelToken) { - this.entryPoint = entryPoint; + this.entryPointFactory = entryPointFactory; this.taskFactory = taskFactory; this.config = config; this.overviewLog = overviewLog; @@ -63,7 +62,7 @@ namespace ContinuousTests { var test = (ContinuousTest)Activator.CreateInstance(testType)!; var handle = new TestHandle(test); - var run = new SingleTestRun(entryPoint, taskFactory, config, overviewLog, handle, startupChecker, cancelToken); + var run = new SingleTestRun(entryPointFactory, taskFactory, config, overviewLog, handle, startupChecker, cancelToken); runFinishedHandle.Reset(); run.Run(runFinishedHandle); diff --git a/Tests/DistTestCore/DistTest.cs b/Tests/DistTestCore/DistTest.cs index a1a4ef5..8e9932a 100644 --- a/Tests/DistTestCore/DistTest.cs +++ b/Tests/DistTestCore/DistTest.cs @@ -62,7 +62,11 @@ namespace DistTestCore [OneTimeTearDown] public void GlobalTearDown() { - globalEntryPoint.Decommission(); + globalEntryPoint.Decommission( + // There shouldn't be any of either, but clean everything up regardless. + deleteKubernetesResources: true, + deleteTrackedFiles: true + ); } [SetUp] diff --git a/Tests/DistTestCore/TestLifecycle.cs b/Tests/DistTestCore/TestLifecycle.cs index 1f5bf17..c0904c1 100644 --- a/Tests/DistTestCore/TestLifecycle.cs +++ b/Tests/DistTestCore/TestLifecycle.cs @@ -33,9 +33,10 @@ namespace DistTestCore public void DeleteAllResources() { - entryPoint.Tools.CreateWorkflow().DeleteNamespace(); - entryPoint.Tools.GetFileManager().DeleteAllFiles(); - entryPoint.Decommission(); + entryPoint.Decommission( + deleteKubernetesResources: true, + deleteTrackedFiles: true + ); } public TrackedFile GenerateTestFile(ByteSize size, string label = "") diff --git a/Tools/CodexNetDeployer/PeerConnectivityChecker.cs b/Tools/CodexNetDeployer/PeerConnectivityChecker.cs index 8e20a4a..87bdc31 100644 --- a/Tools/CodexNetDeployer/PeerConnectivityChecker.cs +++ b/Tools/CodexNetDeployer/PeerConnectivityChecker.cs @@ -14,21 +14,4 @@ namespace CodexNetDeployer checker.AssertFullyConnected(nodes); } } - - public class ConsoleLog : BaseLog - { - public ConsoleLog() : base(false) - { - } - - protected override string GetFullName() - { - return "CONSOLE"; - } - - public override void Log(string message) - { - Console.WriteLine(message); - } - } }