From ad1b756db9c85f22e5a820bcb2fdc9e28661fb33 Mon Sep 17 00:00:00 2001 From: ThatBen Date: Fri, 25 Apr 2025 11:08:38 +0200 Subject: [PATCH] Revert "while better the new plan is still a mess" This reverts commit 2dfdfac2bb52e4ff919ee5f1b3986a839d71b0a2. # Conflicts: # Tests/FrameworkTests/LifecycelyTest.cs --- .../OverwatchSupport/CodexTranscriptWriter.cs | 15 +- .../CodexTranscriptWriterConfig.cs | 4 +- .../MarketplaceAutoBootstrapDistTest.cs | 39 ++- Tests/DistTestCore/DistTest.cs | 124 +++++++--- .../DistTestLifecycleComponents.cs | 97 -------- Tests/DistTestCore/Logs/FixtureLog.cs | 13 +- Tests/DistTestCore/Logs/TestLog.cs | 2 + Tests/DistTestCore/TestLifecycle.cs | 30 +-- .../AutoBootstrapDistTest.cs | 62 ++--- Tests/ExperimentalTests/CodexDistTest.cs | 223 ++++++++++++------ .../CodexLogTrackerProvider.cs | 73 ------ Tests/FrameworkTests/Parallelism.cs | 6 - 12 files changed, 297 insertions(+), 391 deletions(-) delete mode 100644 Tests/DistTestCore/DistTestLifecycleComponents.cs delete mode 100644 Tests/ExperimentalTests/CodexLogTrackerProvider.cs delete mode 100644 Tests/FrameworkTests/Parallelism.cs diff --git a/ProjectPlugins/CodexPlugin/OverwatchSupport/CodexTranscriptWriter.cs b/ProjectPlugins/CodexPlugin/OverwatchSupport/CodexTranscriptWriter.cs index 53ac1496..afd8d1a2 100644 --- a/ProjectPlugins/CodexPlugin/OverwatchSupport/CodexTranscriptWriter.cs +++ b/ProjectPlugins/CodexPlugin/OverwatchSupport/CodexTranscriptWriter.cs @@ -23,27 +23,16 @@ namespace CodexPlugin.OverwatchSupport converter = new CodexLogConverter(writer, config, identityMap); } - public void Finalize() + public void Finalize(string outputFilepath) { log.Log("Finalizing Codex transcript..."); writer.AddHeader(CodexHeaderKey, CreateCodexHeader()); - writer.Write(GetOutputFullPath()); + writer.Write(outputFilepath); log.Log("Done"); } - private string GetOutputFullPath() - { - var outputPath = Path.GetDirectoryName(log.GetFullName()); - if (outputPath == null) throw new Exception("Logfile path is null"); - var filename = Path.GetFileNameWithoutExtension(log.GetFullName()); - if (string.IsNullOrEmpty(filename)) throw new Exception("Logfile name is null or empty"); - var outputFile = Path.Combine(outputPath, filename + "_" + config.OutputFilename); - if (!outputFile.EndsWith(".owts")) outputFile += ".owts"; - return outputFile; - } - public ICodexNodeHooks CreateHooks(string nodeName) { nodeName = Str.Between(nodeName, "'", "'"); diff --git a/ProjectPlugins/CodexPlugin/OverwatchSupport/CodexTranscriptWriterConfig.cs b/ProjectPlugins/CodexPlugin/OverwatchSupport/CodexTranscriptWriterConfig.cs index 8c5e7bf0..247494c8 100644 --- a/ProjectPlugins/CodexPlugin/OverwatchSupport/CodexTranscriptWriterConfig.cs +++ b/ProjectPlugins/CodexPlugin/OverwatchSupport/CodexTranscriptWriterConfig.cs @@ -2,13 +2,11 @@ { public class CodexTranscriptWriterConfig { - public CodexTranscriptWriterConfig(string outputFilename, bool includeBlockReceivedEvents) + public CodexTranscriptWriterConfig(bool includeBlockReceivedEvents) { - OutputFilename = outputFilename; IncludeBlockReceivedEvents = includeBlockReceivedEvents; } - public string OutputFilename { get; } public bool IncludeBlockReceivedEvents { get; } } } diff --git a/Tests/CodexReleaseTests/MarketTests/MarketplaceAutoBootstrapDistTest.cs b/Tests/CodexReleaseTests/MarketTests/MarketplaceAutoBootstrapDistTest.cs index f6e8a9ca..a5ec0885 100644 --- a/Tests/CodexReleaseTests/MarketTests/MarketplaceAutoBootstrapDistTest.cs +++ b/Tests/CodexReleaseTests/MarketTests/MarketplaceAutoBootstrapDistTest.cs @@ -10,41 +10,18 @@ using Utils; namespace CodexReleaseTests.MarketTests { - public class MarketplaceTestComponent : ILifecycleComponent - { - public IGethNode Geth { get; } - public ICodexContracts Contracts { get; } - - public void Start(ILifecycleComponentAccess access) - { - throw new NotImplementedException(); - } - - public void Stop(ILifecycleComponentAccess access, DistTestResult result) - { - throw new NotImplementedException(); - } - } - public abstract class MarketplaceAutoBootstrapDistTest : AutoBootstrapDistTest { + private readonly Dictionary handles = new Dictionary(); protected const int StartingBalanceTST = 1000; protected const int StartingBalanceEth = 10; - protected override void CreateComponents(ILifecycleComponentCollector collector) - { - base.CreateComponents(collector); - - - collector.AddComponent(new MarketplaceTestComponent()); - } - protected override void LifecycleStart(TestLifecycle lifecycle) { base.LifecycleStart(lifecycle); var geth = StartGethNode(s => s.IsMiner()); var contracts = Ci.StartCodexContracts(geth, BootstrapNode.Version); - handles.Add(lifecycle, new MarketplaceTestComponent(geth, contracts)); + handles.Add(lifecycle, new MarketplaceHandle(geth, contracts)); } protected override void LifecycleStop(TestLifecycle lifecycle, DistTestResult result) @@ -346,5 +323,17 @@ namespace CodexReleaseTests.MarketTests public SlotFilledEventDTO SlotFilledEvent { get; } public ICodexNode Host { get; } } + + private class MarketplaceHandle + { + public MarketplaceHandle(IGethNode geth, ICodexContracts contracts) + { + Geth = geth; + Contracts = contracts; + } + + public IGethNode Geth { get; } + public ICodexContracts Contracts { get; } + } } } diff --git a/Tests/DistTestCore/DistTest.cs b/Tests/DistTestCore/DistTest.cs index 9a969532..534eb74a 100644 --- a/Tests/DistTestCore/DistTest.cs +++ b/Tests/DistTestCore/DistTest.cs @@ -19,8 +19,9 @@ namespace DistTestCore private readonly Assembly[] testAssemblies; private readonly FixtureLog fixtureLog; private readonly StatusLog statusLog; + private readonly object lifecycleLock = new object(); private readonly EntryPoint globalEntryPoint; - private readonly DistTestLifecycleComponents lifecycleComponents = new DistTestLifecycleComponents(); + private readonly Dictionary lifecycles = new Dictionary(); private readonly string deployId; public DistTest() @@ -88,12 +89,7 @@ namespace DistTestCore { try { - var testName = GetCurrentTestName(); - fixtureLog.WriteLogTag(); - Stopwatch.Measure(fixtureLog, $"Setup for {testName}", () => - { - lifecycleComponents.Setup(testName, CreateComponents); - }); + CreateNewTestLifecycle(); } catch (Exception ex) { @@ -108,7 +104,7 @@ namespace DistTestCore { try { - Stopwatch.Measure(fixtureLog, $"Teardown for {GetCurrentTestName()}", DisposeTestLifecycle); + DisposeTestLifecycle(); } catch (Exception ex) { @@ -175,49 +171,80 @@ namespace DistTestCore { } - protected virtual void CreateComponents(ILifecycleComponentCollector collector) - { - var testNamespace = TestNamespacePrefix + Guid.NewGuid().ToString(); - var lifecycle = new TestLifecycle( - fixtureLog.CreateTestLog(), - configuration, - GetWebCallTimeSet(), - GetK8sTimeSet(), - testNamespace, - GetCurrentTestName(), - deployId, - ShouldWaitForCleanup()); - - collector.AddComponent(lifecycle); - } - - protected virtual void DestroyComponents(TestLifecycle lifecycle, DistTestResult testResult) + protected virtual void LifecycleStart(TestLifecycle lifecycle) { } - public T Get() where T : ILifecycleComponent + protected virtual void LifecycleStop(TestLifecycle lifecycle, DistTestResult testResult) { - return lifecycleComponents.Get(GetCurrentTestName()); } - private TestLifecycle Get() + protected virtual void CollectStatusLogData(TestLifecycle lifecycle, Dictionary data) { - return Get(); + } + + protected TestLifecycle Get() + { + lock (lifecycleLock) + { + return lifecycles[GetCurrentTestName()]; + } + } + + private void CreateNewTestLifecycle() + { + var testName = GetCurrentTestName(); + fixtureLog.WriteLogTag(); + Stopwatch.Measure(fixtureLog, $"Setup for {testName}", () => + { + lock (lifecycleLock) + { + var testNamespace = TestNamespacePrefix + Guid.NewGuid().ToString(); + var lifecycle = new TestLifecycle( + fixtureLog.CreateTestLog(), + configuration, + GetWebCallTimeSet(), + GetK8sTimeSet(), + testNamespace, + deployId, + ShouldWaitForCleanup()); + lifecycles.Add(testName, lifecycle); + LifecycleStart(lifecycle); + } + }); } private void DisposeTestLifecycle() { - var testName = GetCurrentTestName(); - var results = GetTestResult(); var lifecycle = Get(); + var testResult = GetTestResult(); var testDuration = lifecycle.GetTestDuration(); var data = lifecycle.GetPluginMetadata(); - fixtureLog.Log($"{GetCurrentTestName()} = {results} ({testDuration})"); - statusLog.ConcludeTest(results, testDuration, data); + CollectStatusLogData(lifecycle, data); + fixtureLog.Log($"{GetCurrentTestName()} = {testResult} ({testDuration})"); + statusLog.ConcludeTest(testResult, testDuration, data); + Stopwatch.Measure(fixtureLog, $"Teardown for {GetCurrentTestName()}", () => + { + WriteEndTestLog(lifecycle.Log); - lifecycleComponents.TearDown(testName, results); + IncludeLogsOnTestFailure(lifecycle); + LifecycleStop(lifecycle, testResult); + lifecycle.DeleteAllResources(); + lifecycles.Remove(GetCurrentTestName()); + }); } + private void WriteEndTestLog(TestLog log) + { + var result = TestContext.CurrentContext.Result; + + Log($"*** Finished: {GetCurrentTestName()} = {result.Outcome.Status}"); + if (!string.IsNullOrEmpty(result.Message)) + { + Log(result.Message); + Log($"{result.StackTrace}"); + } + } private IWebCallTimeSet GetWebCallTimeSet() { @@ -269,6 +296,28 @@ namespace DistTestCore .ToArray(); } + private void IncludeLogsOnTestFailure(TestLifecycle lifecycle) + { + var testStatus = TestContext.CurrentContext.Result.Outcome.Status; + if (ShouldDownloadAllLogs(testStatus)) + { + lifecycle.Log.Log("Downloading all container logs..."); + lifecycle.DownloadAllLogs(); + } + } + + private bool ShouldDownloadAllLogs(TestStatus testStatus) + { + if (configuration.AlwaysDownloadContainerLogs) return true; + if (!IsDownloadingLogsEnabled()) return false; + if (testStatus == TestStatus.Failed) + { + return true; + } + + return false; + } + private string GetCurrentTestName() { return $"[{TestContext.CurrentContext.Test.Name}]"; @@ -279,8 +328,7 @@ namespace DistTestCore var success = TestContext.CurrentContext.Result.Outcome.Status == TestStatus.Passed; var status = TestContext.CurrentContext.Result.Outcome.Status.ToString(); var result = TestContext.CurrentContext.Result.Message; - var trace = TestContext.CurrentContext.Result.StackTrace; - return new DistTestResult(success, status, result ?? string.Empty, trace ?? string.Empty); + return new DistTestResult(success, status, result ?? string.Empty); } private bool IsDownloadingLogsEnabled() @@ -291,18 +339,16 @@ namespace DistTestCore public class DistTestResult { - public DistTestResult(bool success, string status, string result, string trace) + public DistTestResult(bool success, string status, string result) { Success = success; Status = status; Result = result; - Trace = trace; } public bool Success { get; } public string Status { get; } public string Result { get; } - public string Trace { get; } public override string ToString() { diff --git a/Tests/DistTestCore/DistTestLifecycleComponents.cs b/Tests/DistTestCore/DistTestLifecycleComponents.cs deleted file mode 100644 index 203a891c..00000000 --- a/Tests/DistTestCore/DistTestLifecycleComponents.cs +++ /dev/null @@ -1,97 +0,0 @@ -namespace DistTestCore -{ - public interface ILifecycleComponent - { - void Start(ILifecycleComponentAccess access); - void Stop(ILifecycleComponentAccess access, DistTestResult result); - } - - public interface ILifecycleComponentCollector - { - void AddComponent(ILifecycleComponent component); - } - - public interface ILifecycleComponentAccess - { - T Get() where T : ILifecycleComponent; - } - - public class DistTestLifecycleComponents - { - private readonly object _lock = new object(); - private readonly Dictionary> components = new(); - - public void Setup(string testName, Action initializer) - { - var newComponents = new Dictionary(); - lock (_lock) - { - components.Add(testName, newComponents); - var collector = new Collector(newComponents); - initializer(collector); - } - - var access = new ScopedAccess(this, testName); - foreach (var component in newComponents.Values) - { - component.Start(access); - } - } - - public T Get(string testName) where T : ILifecycleComponent - { - var type = typeof(T); - lock (_lock) - { - return (T)components[testName][type]; - } - } - - public void TearDown(string testName, DistTestResult result) - { - var access = new ScopedAccess(this, testName); - var closingComponents = components[testName]; - foreach (var component in closingComponents.Values) - { - component.Stop(access, result); - } - - lock (_lock) - { - components.Remove(testName); - } - } - - private class Collector : ILifecycleComponentCollector - { - private readonly Dictionary components; - - public Collector(Dictionary components) - { - this.components = components; - } - - public void AddComponent(ILifecycleComponent component) - { - components.Add(component.GetType(), component); - } - } - - private class ScopedAccess : ILifecycleComponentAccess - { - private readonly DistTestLifecycleComponents parent; - private readonly string testName; - - public ScopedAccess(DistTestLifecycleComponents parent, string testName) - { - this.parent = parent; - this.testName = testName; - } - - public T Get() where T : ILifecycleComponent - { - return parent.Get(testName); - } - } - } -} diff --git a/Tests/DistTestCore/Logs/FixtureLog.cs b/Tests/DistTestCore/Logs/FixtureLog.cs index f90147d8..9d3c77d3 100644 --- a/Tests/DistTestCore/Logs/FixtureLog.cs +++ b/Tests/DistTestCore/Logs/FixtureLog.cs @@ -4,25 +4,26 @@ namespace DistTestCore.Logs { public class FixtureLog : BaseTestLog { + private readonly ILog backingLog; + private readonly string deployId; + public FixtureLog(ILog backingLog, string deployId) : base(backingLog, deployId) { + this.backingLog = backingLog; + this.deployId = deployId; } public TestLog CreateTestLog(string name = "") { - var result = TestLog.Create(this, name); - result.Log(NameUtils.GetRawFixtureName()); - return result; + return TestLog.Create(this, name); } public static FixtureLog Create(LogConfig config, DateTime start, string deployId, string name = "") { var fullName = NameUtils.GetFixtureFullName(config, start, name); var log = CreateMainLog(fullName, name); - var result = new FixtureLog(log, deployId); - result.Log(NameUtils.GetRawFixtureName()); - return result; + return new FixtureLog(log, deployId); } } } diff --git a/Tests/DistTestCore/Logs/TestLog.cs b/Tests/DistTestCore/Logs/TestLog.cs index 6a334138..0dca1464 100644 --- a/Tests/DistTestCore/Logs/TestLog.cs +++ b/Tests/DistTestCore/Logs/TestLog.cs @@ -1,4 +1,5 @@ using Logging; +using System.Xml.Linq; namespace DistTestCore.Logs { @@ -7,6 +8,7 @@ namespace DistTestCore.Logs public TestLog(ILog backingLog, string methodName, string deployId, string name = "") : base(backingLog, deployId) { + backingLog.Log($"*** Begin: {methodName}"); } public static TestLog Create(FixtureLog parentLog, string name = "") diff --git a/Tests/DistTestCore/TestLifecycle.cs b/Tests/DistTestCore/TestLifecycle.cs index 550b6151..3d642d20 100644 --- a/Tests/DistTestCore/TestLifecycle.cs +++ b/Tests/DistTestCore/TestLifecycle.cs @@ -10,24 +10,22 @@ using WebUtils; namespace DistTestCore { - public class TestLifecycle : IK8sHooks, ILifecycleComponent + public class TestLifecycle : IK8sHooks { private const string TestsType = "dist-tests"; private readonly EntryPoint entryPoint; private readonly Dictionary metadata; private readonly List runningContainers = new(); - private readonly string testName; private readonly string deployId; private readonly List stoppedContainerLogs = new List(); - public TestLifecycle(TestLog log, Configuration configuration, IWebCallTimeSet webCallTimeSet, IK8sTimeSet k8sTimeSet, string testNamespace, string testName, string deployId, bool waitForCleanup) + public TestLifecycle(TestLog log, Configuration configuration, IWebCallTimeSet webCallTimeSet, IK8sTimeSet k8sTimeSet, string testNamespace, string deployId, bool waitForCleanup) { Log = log; Configuration = configuration; WebCallTimeSet = webCallTimeSet; K8STimeSet = k8sTimeSet; TestNamespace = testNamespace; - this.testName = testName; TestStart = DateTime.UtcNow; entryPoint = new EntryPoint(log, configuration.GetK8sConfiguration(k8sTimeSet, this, testNamespace), configuration.GetFileManagerFolder(), webCallTimeSet, k8sTimeSet); @@ -38,28 +36,6 @@ namespace DistTestCore log.WriteLogTag(); } - public void Start(ILifecycleComponentAccess access) - { - Log.Log($"*** Begin: {testName}"); - } - - public void Stop(ILifecycleComponentAccess access, DistTestResult result) - { - Log.Log($"*** Finished: {testName} = {result.Status}"); - if (!string.IsNullOrEmpty(result.Result)) - { - Log.Log(result.Result); - Log.Log($"{result.Trace}"); - } - - if (!result.Success) - { - DownloadAllLogs(); - } - - DeleteAllResources(); - } - public DateTime TestStart { get; } public TestLog Log { get; } public Configuration Configuration { get; } @@ -69,7 +45,7 @@ namespace DistTestCore public bool WaitForCleanup { get; } public CoreInterface CoreInterface { get; } - private void DeleteAllResources() + public void DeleteAllResources() { entryPoint.Decommission( deleteKubernetesResources: true, diff --git a/Tests/ExperimentalTests/AutoBootstrapDistTest.cs b/Tests/ExperimentalTests/AutoBootstrapDistTest.cs index a2477597..d8ac6805 100644 --- a/Tests/ExperimentalTests/AutoBootstrapDistTest.cs +++ b/Tests/ExperimentalTests/AutoBootstrapDistTest.cs @@ -4,56 +4,46 @@ using DistTestCore; namespace CodexTests { - public class AutoBootstrapComponent : ILifecycleComponent - { - public ICodexNode? BootstrapNode { get; private set; } = null; - - public void Start(ILifecycleComponentAccess access) - { - if (BootstrapNode != null) return; - - var tl = access.Get(); - var ci = tl.CoreInterface; - var testNamespace = tl.TestNamespace; - - BootstrapNode = ci.StartCodexNode(s => s.WithName("BOOTSTRAP_" + testNamespace)); - } - - public void ApplyBootstrapNode(ICodexSetup setup) - { - if (BootstrapNode == null) return; - - setup.WithBootstrapNode(BootstrapNode); - } - - public void Stop(ILifecycleComponentAccess access, DistTestResult result) - { - if (BootstrapNode == null) return; - BootstrapNode.Stop(waitTillStopped: false); - } - } - public class AutoBootstrapDistTest : CodexDistTest { + private readonly Dictionary bootstrapNodes = new Dictionary(); + private bool isBooting = false; - protected override void CreateComponents(ILifecycleComponentCollector collector) + protected override void LifecycleStart(TestLifecycle tl) { - base.CreateComponents(collector); - collector.AddComponent(new AutoBootstrapComponent()); + base.LifecycleStart(tl); + if (!bootstrapNodes.ContainsKey(tl)) + { + isBooting = true; + bootstrapNodes.Add(tl, StartCodex(s => s.WithName("BOOTSTRAP_" + tl.TestNamespace))); + isBooting = false; + } + } + + protected override void LifecycleStop(TestLifecycle lifecycle, DistTestResult result) + { + bootstrapNodes.Remove(lifecycle); + base.LifecycleStop(lifecycle, result); } protected override void OnCodexSetup(ICodexSetup setup) { - Get().ApplyBootstrapNode(setup); + if (isBooting) return; + + var node = BootstrapNode; + if (node != null) setup.WithBootstrapNode(node); } protected ICodexNode BootstrapNode { get { - var bn = Get().BootstrapNode; - if (bn == null) throw new InvalidOperationException("BootstrapNode accessed before initialized."); - return bn; + var tl = Get(); + if (bootstrapNodes.TryGetValue(tl, out var node)) + { + return node; + } + throw new InvalidOperationException("Bootstrap node not yet started."); } } } diff --git a/Tests/ExperimentalTests/CodexDistTest.cs b/Tests/ExperimentalTests/CodexDistTest.cs index 40e711fc..d27216d3 100644 --- a/Tests/ExperimentalTests/CodexDistTest.cs +++ b/Tests/ExperimentalTests/CodexDistTest.cs @@ -1,5 +1,6 @@ using BlockchainUtils; using CodexClient; +using CodexClient.Hooks; using CodexContractsPlugin; using CodexNetDeployer; using CodexPlugin; @@ -16,74 +17,86 @@ using Newtonsoft.Json; using NUnit.Framework; using NUnit.Framework.Constraints; using OverwatchTranscript; +using Utils; namespace CodexTests { - public class CodexDistTestComponents : ILifecycleComponent + public class CodexLogTrackerProvider : ICodexHooksProvider { - private readonly object nodesLock = new object(); + private readonly Action addNode; - public CodexDistTestComponents(CodexTranscriptWriter? writer) + public CodexLogTrackerProvider(Action addNode) { - Writer = writer; + this.addNode = addNode; } - public CodexTranscriptWriter? Writer { get; } - public BlockCache Cache { get; } = new(); - public List Nodes { get; } = new(); - - public void Start(ILifecycleComponentAccess access) + // See TestLifecycle.cs DownloadAllLogs() + public ICodexNodeHooks CreateHooks(string nodeName) { - var ci = access.Get().CoreInterface; - ci.AddCodexHooksProvider(new CodexLogTrackerProvider(n => + return new CodexLogTracker(addNode); + } + + public class CodexLogTracker : ICodexNodeHooks + { + private readonly Action addNode; + + public CodexLogTracker(Action addNode) { - lock (nodesLock) - { - Nodes.Add(n); - } - })); - } - - public void Stop(ILifecycleComponentAccess access, DistTestResult result) - { - var tl = access.Get(); - var log = tl.Log; - var logFiles = tl.DownloadAllLogs(); - - TeardownTranscript(log, logFiles, result); - - // todo: on not success: go to nodes and dl logs? - // or fix disttest failure log download so we can always have logs even for non-codexes? - } - - private void TeardownTranscript(TestLog log, IDownloadedLog[] logFiles, DistTestResult result) - { - if (Writer == null) return; - - Writer.AddResult(result.Success, result.Result); - - try - { - Stopwatch.Measure(log, "Transcript.ProcessLogs", () => - { - Writer.ProcessLogs(logFiles); - }); - - Stopwatch.Measure(log, $"Transcript.Finalize", () => - { - Writer.IncludeFile(log.GetFullName()); - Writer.Finalize(); - }); + this.addNode = addNode; } - catch (Exception ex) + + public void OnFileDownloaded(ByteSize size, ContentId cid) + { + } + + public void OnFileDownloading(ContentId cid) + { + } + + public void OnFileUploaded(string uid, ByteSize size, ContentId cid) + { + } + + public void OnFileUploading(string uid, ByteSize size) + { + } + + public void OnNodeStarted(ICodexNode node, string peerId, string nodeId) + { + addNode(node); + } + + public void OnNodeStarting(DateTime startUtc, string image, EthAccount? ethAccount) + { + } + + public void OnNodeStopping() + { + } + + public void OnStorageAvailabilityCreated(StorageAvailability response) + { + } + + public void OnStorageContractSubmitted(StoragePurchaseContract storagePurchaseContract) + { + } + + public void OnStorageContractUpdated(StoragePurchase purchaseStatus) { - log.Error("Failure during transcript teardown: " + ex); } } } public class CodexDistTest : DistTest { + private static readonly object _lock = new object(); + private static readonly Dictionary writers = new Dictionary(); + private static readonly Dictionary blockCaches = new Dictionary(); + + // this entire structure is not good and needs to be destroyed at the earliest convenience: + private static readonly Dictionary> nodes = new Dictionary>(); + public CodexDistTest() { ProjectPlugin.Load(); @@ -99,12 +112,34 @@ namespace CodexTests localBuilder.Build(); } - protected override void CreateComponents(ILifecycleComponentCollector collector) + protected override void LifecycleStart(TestLifecycle lifecycle) { - base.CreateComponents(collector); - collector.AddComponent(new CodexDistTestComponents( - SetupTranscript() - )); + base.LifecycleStart(lifecycle); + SetupTranscript(lifecycle); + + Ci.AddCodexHooksProvider(new CodexLogTrackerProvider(n => + { + lock (_lock) + { + if (!nodes.ContainsKey(lifecycle)) nodes.Add(lifecycle, new List()); + nodes[lifecycle].Add(n); + } + })); + } + + protected override void LifecycleStop(TestLifecycle lifecycle, DistTestResult result) + { + base.LifecycleStop(lifecycle, result); + TeardownTranscript(lifecycle, result); + + if (!result.Success) + { + lock (_lock) + { + var codexNodes = nodes[lifecycle]; + foreach (var node in codexNodes) node.DownloadLog(); + } + } } public ICodexNode StartCodex() @@ -138,11 +173,6 @@ namespace CodexTests return Ci.StartGethNode(GetBlockCache(), setup); } - private BlockCache GetBlockCache() - { - return Get().Cache; - } - public PeerConnectionTestHelpers CreatePeerConnectionTestHelpers() { return new PeerConnectionTestHelpers(GetTestLog()); @@ -150,7 +180,7 @@ namespace CodexTests public PeerDownloadTestHelpers CreatePeerDownloadTestHelpers() { - return new PeerDownloadTestHelpers(GetTestLog(), Get().GetFileManager()); + return new PeerDownloadTestHelpers(GetTestLog(), Get().GetFileManager()); } public void AssertBalance(ICodexContracts contracts, ICodexNode codexNode, Constraint constraint, string msg = "") @@ -228,20 +258,81 @@ namespace CodexTests return null; } - private CodexTranscriptWriter? SetupTranscript() + private void SetupTranscript(TestLifecycle lifecycle) { var attr = GetTranscriptAttributeOfCurrentTest(); - if (attr == null) return null; + if (attr == null) return; var config = new CodexTranscriptWriterConfig( - attr.OutputFilename, attr.IncludeBlockReceivedEvents ); - var log = new LogPrefixer(GetTestLog(), "(Transcript) "); + var log = new LogPrefixer(lifecycle.Log, "(Transcript) "); var writer = new CodexTranscriptWriter(log, config, Transcript.NewWriter(log)); Ci.AddCodexHooksProvider(writer); - return writer; + lock (_lock) + { + writers.Add(lifecycle, writer); + } + } + + private void TeardownTranscript(TestLifecycle lifecycle, DistTestResult result) + { + var attr = GetTranscriptAttributeOfCurrentTest(); + if (attr == null) return; + + var outputFilepath = GetOutputFullPath(lifecycle, attr); + + CodexTranscriptWriter writer = null!; + lock (_lock) + { + writer = writers[lifecycle]; + writers.Remove(lifecycle); + } + + writer.AddResult(result.Success, result.Result); + + try + { + Stopwatch.Measure(lifecycle.Log, "Transcript.ProcessLogs", () => + { + writer.ProcessLogs(lifecycle.DownloadAllLogs()); + }); + + Stopwatch.Measure(lifecycle.Log, $"Transcript.Finalize: {outputFilepath}", () => + { + writer.IncludeFile(lifecycle.Log.GetFullName()); + writer.Finalize(outputFilepath); + }); + } + catch (Exception ex) + { + lifecycle.Log.Error("Failure during transcript teardown: " + ex); + } + } + + private string GetOutputFullPath(TestLifecycle lifecycle, CreateTranscriptAttribute attr) + { + var outputPath = Path.GetDirectoryName(lifecycle.Log.GetFullName()); + if (outputPath == null) throw new Exception("Logfile path is null"); + var filename = Path.GetFileNameWithoutExtension(lifecycle.Log.GetFullName()); + if (string.IsNullOrEmpty(filename)) throw new Exception("Logfile name is null or empty"); + var outputFile = Path.Combine(outputPath, filename + "_" + attr.OutputFilename); + if (!outputFile.EndsWith(".owts")) outputFile += ".owts"; + return outputFile; + } + + private BlockCache GetBlockCache() + { + var lifecycle = Get(); + lock (_lock) + { + if (!blockCaches.ContainsKey(lifecycle)) + { + blockCaches[lifecycle] = new BlockCache(); + } + } + return blockCaches[lifecycle]; } } diff --git a/Tests/ExperimentalTests/CodexLogTrackerProvider.cs b/Tests/ExperimentalTests/CodexLogTrackerProvider.cs deleted file mode 100644 index 1b2fdd66..00000000 --- a/Tests/ExperimentalTests/CodexLogTrackerProvider.cs +++ /dev/null @@ -1,73 +0,0 @@ -using CodexClient; -using CodexClient.Hooks; -using Utils; - -namespace CodexTests -{ - public class CodexLogTrackerProvider : ICodexHooksProvider - { - private readonly Action addNode; - - public CodexLogTrackerProvider(Action addNode) - { - this.addNode = addNode; - } - - // See TestLifecycle.cs DownloadAllLogs() - public ICodexNodeHooks CreateHooks(string nodeName) - { - return new CodexLogTracker(addNode); - } - - public class CodexLogTracker : ICodexNodeHooks - { - private readonly Action addNode; - - public CodexLogTracker(Action addNode) - { - this.addNode = addNode; - } - - public void OnFileDownloaded(ByteSize size, ContentId cid) - { - } - - public void OnFileDownloading(ContentId cid) - { - } - - public void OnFileUploaded(string uid, ByteSize size, ContentId cid) - { - } - - public void OnFileUploading(string uid, ByteSize size) - { - } - - public void OnNodeStarted(ICodexNode node, string peerId, string nodeId) - { - addNode(node); - } - - public void OnNodeStarting(DateTime startUtc, string image, EthAccount? ethAccount) - { - } - - public void OnNodeStopping() - { - } - - public void OnStorageAvailabilityCreated(StorageAvailability response) - { - } - - public void OnStorageContractSubmitted(StoragePurchaseContract storagePurchaseContract) - { - } - - public void OnStorageContractUpdated(StoragePurchase purchaseStatus) - { - } - } - } -} diff --git a/Tests/FrameworkTests/Parallelism.cs b/Tests/FrameworkTests/Parallelism.cs deleted file mode 100644 index 8a877f41..00000000 --- a/Tests/FrameworkTests/Parallelism.cs +++ /dev/null @@ -1,6 +0,0 @@ -using NUnit.Framework; - -[assembly: LevelOfParallelism(100)] -namespace FrameworkTests -{ -}