diff --git a/ProjectPlugins/CodexPlugin/OverwatchSupport/CodexTranscriptWriter.cs b/ProjectPlugins/CodexPlugin/OverwatchSupport/CodexTranscriptWriter.cs index afd8d1a2..53ac1496 100644 --- a/ProjectPlugins/CodexPlugin/OverwatchSupport/CodexTranscriptWriter.cs +++ b/ProjectPlugins/CodexPlugin/OverwatchSupport/CodexTranscriptWriter.cs @@ -23,16 +23,27 @@ namespace CodexPlugin.OverwatchSupport converter = new CodexLogConverter(writer, config, identityMap); } - public void Finalize(string outputFilepath) + public void Finalize() { log.Log("Finalizing Codex transcript..."); writer.AddHeader(CodexHeaderKey, CreateCodexHeader()); - writer.Write(outputFilepath); + writer.Write(GetOutputFullPath()); 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 247494c8..8c5e7bf0 100644 --- a/ProjectPlugins/CodexPlugin/OverwatchSupport/CodexTranscriptWriterConfig.cs +++ b/ProjectPlugins/CodexPlugin/OverwatchSupport/CodexTranscriptWriterConfig.cs @@ -2,11 +2,13 @@ { public class CodexTranscriptWriterConfig { - public CodexTranscriptWriterConfig(bool includeBlockReceivedEvents) + public CodexTranscriptWriterConfig(string outputFilename, 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 a5ec0885..f6e8a9ca 100644 --- a/Tests/CodexReleaseTests/MarketTests/MarketplaceAutoBootstrapDistTest.cs +++ b/Tests/CodexReleaseTests/MarketTests/MarketplaceAutoBootstrapDistTest.cs @@ -10,18 +10,41 @@ 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 MarketplaceHandle(geth, contracts)); + handles.Add(lifecycle, new MarketplaceTestComponent(geth, contracts)); } protected override void LifecycleStop(TestLifecycle lifecycle, DistTestResult result) @@ -323,17 +346,5 @@ 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 534eb74a..9a969532 100644 --- a/Tests/DistTestCore/DistTest.cs +++ b/Tests/DistTestCore/DistTest.cs @@ -19,9 +19,8 @@ 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 Dictionary lifecycles = new Dictionary(); + private readonly DistTestLifecycleComponents lifecycleComponents = new DistTestLifecycleComponents(); private readonly string deployId; public DistTest() @@ -89,7 +88,12 @@ namespace DistTestCore { try { - CreateNewTestLifecycle(); + var testName = GetCurrentTestName(); + fixtureLog.WriteLogTag(); + Stopwatch.Measure(fixtureLog, $"Setup for {testName}", () => + { + lifecycleComponents.Setup(testName, CreateComponents); + }); } catch (Exception ex) { @@ -104,7 +108,7 @@ namespace DistTestCore { try { - DisposeTestLifecycle(); + Stopwatch.Measure(fixtureLog, $"Teardown for {GetCurrentTestName()}", DisposeTestLifecycle); } catch (Exception ex) { @@ -171,80 +175,49 @@ namespace DistTestCore { } - protected virtual void LifecycleStart(TestLifecycle lifecycle) + 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 LifecycleStop(TestLifecycle lifecycle, DistTestResult testResult) + public T Get() where T : ILifecycleComponent { + return lifecycleComponents.Get(GetCurrentTestName()); } - protected virtual void CollectStatusLogData(TestLifecycle lifecycle, Dictionary data) + private TestLifecycle 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); - } - }); + return Get(); } private void DisposeTestLifecycle() { + var testName = GetCurrentTestName(); + var results = GetTestResult(); var lifecycle = Get(); - var testResult = GetTestResult(); var testDuration = lifecycle.GetTestDuration(); var data = lifecycle.GetPluginMetadata(); - CollectStatusLogData(lifecycle, data); - fixtureLog.Log($"{GetCurrentTestName()} = {testResult} ({testDuration})"); - statusLog.ConcludeTest(testResult, testDuration, data); - Stopwatch.Measure(fixtureLog, $"Teardown for {GetCurrentTestName()}", () => - { - WriteEndTestLog(lifecycle.Log); + fixtureLog.Log($"{GetCurrentTestName()} = {results} ({testDuration})"); + statusLog.ConcludeTest(results, testDuration, data); - IncludeLogsOnTestFailure(lifecycle); - LifecycleStop(lifecycle, testResult); - lifecycle.DeleteAllResources(); - lifecycles.Remove(GetCurrentTestName()); - }); + lifecycleComponents.TearDown(testName, results); } - 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() { @@ -296,28 +269,6 @@ 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}]"; @@ -328,7 +279,8 @@ 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; - return new DistTestResult(success, status, result ?? string.Empty); + var trace = TestContext.CurrentContext.Result.StackTrace; + return new DistTestResult(success, status, result ?? string.Empty, trace ?? string.Empty); } private bool IsDownloadingLogsEnabled() @@ -339,16 +291,18 @@ namespace DistTestCore public class DistTestResult { - public DistTestResult(bool success, string status, string result) + public DistTestResult(bool success, string status, string result, string trace) { 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 new file mode 100644 index 00000000..203a891c --- /dev/null +++ b/Tests/DistTestCore/DistTestLifecycleComponents.cs @@ -0,0 +1,97 @@ +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 9d3c77d3..f90147d8 100644 --- a/Tests/DistTestCore/Logs/FixtureLog.cs +++ b/Tests/DistTestCore/Logs/FixtureLog.cs @@ -4,26 +4,25 @@ 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 = "") { - return TestLog.Create(this, name); + var result = TestLog.Create(this, name); + result.Log(NameUtils.GetRawFixtureName()); + return result; } public static FixtureLog Create(LogConfig config, DateTime start, string deployId, string name = "") { var fullName = NameUtils.GetFixtureFullName(config, start, name); var log = CreateMainLog(fullName, name); - return new FixtureLog(log, deployId); + var result = new FixtureLog(log, deployId); + result.Log(NameUtils.GetRawFixtureName()); + return result; } } } diff --git a/Tests/DistTestCore/Logs/TestLog.cs b/Tests/DistTestCore/Logs/TestLog.cs index 0dca1464..6a334138 100644 --- a/Tests/DistTestCore/Logs/TestLog.cs +++ b/Tests/DistTestCore/Logs/TestLog.cs @@ -1,5 +1,4 @@ using Logging; -using System.Xml.Linq; namespace DistTestCore.Logs { @@ -8,7 +7,6 @@ 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 3d642d20..550b6151 100644 --- a/Tests/DistTestCore/TestLifecycle.cs +++ b/Tests/DistTestCore/TestLifecycle.cs @@ -10,22 +10,24 @@ using WebUtils; namespace DistTestCore { - public class TestLifecycle : IK8sHooks + public class TestLifecycle : IK8sHooks, ILifecycleComponent { 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 deployId, bool waitForCleanup) + public TestLifecycle(TestLog log, Configuration configuration, IWebCallTimeSet webCallTimeSet, IK8sTimeSet k8sTimeSet, string testNamespace, string testName, 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); @@ -36,6 +38,28 @@ 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; } @@ -45,7 +69,7 @@ namespace DistTestCore public bool WaitForCleanup { get; } public CoreInterface CoreInterface { get; } - public void DeleteAllResources() + private void DeleteAllResources() { entryPoint.Decommission( deleteKubernetesResources: true, diff --git a/Tests/ExperimentalTests/AutoBootstrapDistTest.cs b/Tests/ExperimentalTests/AutoBootstrapDistTest.cs index d8ac6805..a2477597 100644 --- a/Tests/ExperimentalTests/AutoBootstrapDistTest.cs +++ b/Tests/ExperimentalTests/AutoBootstrapDistTest.cs @@ -4,46 +4,56 @@ using DistTestCore; namespace CodexTests { - public class AutoBootstrapDistTest : CodexDistTest + public class AutoBootstrapComponent : ILifecycleComponent { - private readonly Dictionary bootstrapNodes = new Dictionary(); - private bool isBooting = false; + public ICodexNode? BootstrapNode { get; private set; } = null; - protected override void LifecycleStart(TestLifecycle tl) + public void Start(ILifecycleComponentAccess access) { - base.LifecycleStart(tl); - if (!bootstrapNodes.ContainsKey(tl)) - { - isBooting = true; - bootstrapNodes.Add(tl, StartCodex(s => s.WithName("BOOTSTRAP_" + tl.TestNamespace))); - isBooting = false; - } + if (BootstrapNode != null) return; + + var tl = access.Get(); + var ci = tl.CoreInterface; + var testNamespace = tl.TestNamespace; + + BootstrapNode = ci.StartCodexNode(s => s.WithName("BOOTSTRAP_" + testNamespace)); } - protected override void LifecycleStop(TestLifecycle lifecycle, DistTestResult result) + public void ApplyBootstrapNode(ICodexSetup setup) { - bootstrapNodes.Remove(lifecycle); - base.LifecycleStop(lifecycle, result); + 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 + { + + protected override void CreateComponents(ILifecycleComponentCollector collector) + { + base.CreateComponents(collector); + collector.AddComponent(new AutoBootstrapComponent()); } protected override void OnCodexSetup(ICodexSetup setup) { - if (isBooting) return; - - var node = BootstrapNode; - if (node != null) setup.WithBootstrapNode(node); + Get().ApplyBootstrapNode(setup); } protected ICodexNode BootstrapNode { get { - var tl = Get(); - if (bootstrapNodes.TryGetValue(tl, out var node)) - { - return node; - } - throw new InvalidOperationException("Bootstrap node not yet started."); + var bn = Get().BootstrapNode; + if (bn == null) throw new InvalidOperationException("BootstrapNode accessed before initialized."); + return bn; } } } diff --git a/Tests/ExperimentalTests/CodexDistTest.cs b/Tests/ExperimentalTests/CodexDistTest.cs index d27216d3..40e711fc 100644 --- a/Tests/ExperimentalTests/CodexDistTest.cs +++ b/Tests/ExperimentalTests/CodexDistTest.cs @@ -1,6 +1,5 @@ using BlockchainUtils; using CodexClient; -using CodexClient.Hooks; using CodexContractsPlugin; using CodexNetDeployer; using CodexPlugin; @@ -17,86 +16,74 @@ using Newtonsoft.Json; using NUnit.Framework; using NUnit.Framework.Constraints; using OverwatchTranscript; -using Utils; namespace CodexTests { - public class CodexLogTrackerProvider : ICodexHooksProvider + public class CodexDistTestComponents : ILifecycleComponent { - private readonly Action addNode; + private readonly object nodesLock = new object(); - public CodexLogTrackerProvider(Action addNode) + public CodexDistTestComponents(CodexTranscriptWriter? writer) { - this.addNode = addNode; + Writer = writer; } - // See TestLifecycle.cs DownloadAllLogs() - public ICodexNodeHooks CreateHooks(string nodeName) + public CodexTranscriptWriter? Writer { get; } + public BlockCache Cache { get; } = new(); + public List Nodes { get; } = new(); + + public void Start(ILifecycleComponentAccess access) { - return new CodexLogTracker(addNode); + var ci = access.Get().CoreInterface; + ci.AddCodexHooksProvider(new CodexLogTrackerProvider(n => + { + lock (nodesLock) + { + Nodes.Add(n); + } + })); } - public class CodexLogTracker : ICodexNodeHooks + public void Stop(ILifecycleComponentAccess access, DistTestResult result) { - private readonly Action addNode; + var tl = access.Get(); + var log = tl.Log; + var logFiles = tl.DownloadAllLogs(); - public CodexLogTracker(Action addNode) + 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 { - this.addNode = addNode; + Stopwatch.Measure(log, "Transcript.ProcessLogs", () => + { + Writer.ProcessLogs(logFiles); + }); + + Stopwatch.Measure(log, $"Transcript.Finalize", () => + { + Writer.IncludeFile(log.GetFullName()); + Writer.Finalize(); + }); } - - 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) + catch (Exception ex) { + 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(); @@ -112,34 +99,12 @@ namespace CodexTests localBuilder.Build(); } - protected override void LifecycleStart(TestLifecycle lifecycle) + protected override void CreateComponents(ILifecycleComponentCollector collector) { - 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(); - } - } + base.CreateComponents(collector); + collector.AddComponent(new CodexDistTestComponents( + SetupTranscript() + )); } public ICodexNode StartCodex() @@ -173,6 +138,11 @@ namespace CodexTests return Ci.StartGethNode(GetBlockCache(), setup); } + private BlockCache GetBlockCache() + { + return Get().Cache; + } + public PeerConnectionTestHelpers CreatePeerConnectionTestHelpers() { return new PeerConnectionTestHelpers(GetTestLog()); @@ -180,7 +150,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 = "") @@ -258,81 +228,20 @@ namespace CodexTests return null; } - private void SetupTranscript(TestLifecycle lifecycle) + private CodexTranscriptWriter? SetupTranscript() { var attr = GetTranscriptAttributeOfCurrentTest(); - if (attr == null) return; + if (attr == null) return null; var config = new CodexTranscriptWriterConfig( + attr.OutputFilename, attr.IncludeBlockReceivedEvents ); - var log = new LogPrefixer(lifecycle.Log, "(Transcript) "); + var log = new LogPrefixer(GetTestLog(), "(Transcript) "); var writer = new CodexTranscriptWriter(log, config, Transcript.NewWriter(log)); Ci.AddCodexHooksProvider(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]; + return writer; } } diff --git a/Tests/ExperimentalTests/CodexLogTrackerProvider.cs b/Tests/ExperimentalTests/CodexLogTrackerProvider.cs new file mode 100644 index 00000000..1b2fdd66 --- /dev/null +++ b/Tests/ExperimentalTests/CodexLogTrackerProvider.cs @@ -0,0 +1,73 @@ +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/LifecycelyTest.cs b/Tests/FrameworkTests/LifecycelyTest.cs index ef90a48c..6c11e14f 100644 --- a/Tests/FrameworkTests/LifecycelyTest.cs +++ b/Tests/FrameworkTests/LifecycelyTest.cs @@ -1,64 +1,64 @@ -using NUnit.Framework; +//using NUnit.Framework; -namespace FrameworkTests -{ - [Parallelizable(ParallelScope.All)] - [TestFixture(10)] - [TestFixture(20)] - [TestFixture(30)] - public class LifecycelyTest - { - public LifecycelyTest(int num) - { - Log("ctor", GetCurrentTestName(), num); - this.num = num; - } +//namespace FrameworkTests +//{ +// [Parallelizable(ParallelScope.All)] +// [TestFixture(10)] +// [TestFixture(20)] +// [TestFixture(30)] +// public class LifecycelyTest +// { +// public LifecycelyTest(int num) +// { +// Log("ctor", GetCurrentTestName(), num); +// this.num = num; +// } - [SetUp] - public void Setup() - { - Log(nameof(Setup), GetCurrentTestName()); - } +// [SetUp] +// public void Setup() +// { +// Log(nameof(Setup), GetCurrentTestName()); +// } - [TearDown] - public void TearDown() - { - Log(nameof(TearDown), GetCurrentTestName()); - } +// [TearDown] +// public void TearDown() +// { +// Log(nameof(TearDown), GetCurrentTestName()); +// } - [Test] - public void A() - { - Log(nameof(A), "Run"); - SleepRandom(); - Log(nameof(A), "Finish"); - } +// [Test] +// public void A() +// { +// Log(nameof(A), "Run"); +// SleepRandom(); +// Log(nameof(A), "Finish"); +// } - [Test] - public void B() - { - Log(nameof(B), "Run"); - SleepRandom(); - Log(nameof(B), "Finish"); - } +// [Test] +// public void B() +// { +// Log(nameof(B), "Run"); +// SleepRandom(); +// Log(nameof(B), "Finish"); +// } - [Test] - public void C() - { - Log(nameof(C), "Run"); - SleepRandom(); - Log(nameof(C), "Finish"); - } +// [Test] +// public void C() +// { +// Log(nameof(C), "Run"); +// SleepRandom(); +// Log(nameof(C), "Finish"); +// } - [Test] - [Combinatorial] - public void Multi( - [Values(1, 2, 3)] int num) - { - Log(nameof(Multi), "Run", num); - SleepRandom(); - Log(nameof(Multi), "Finish", num); - } +// [Test] +// [Combinatorial] +// public void Multi( +// [Values(1, 2, 3)] int num) +// { +// Log(nameof(Multi), "Run", num); +// SleepRandom(); +// Log(nameof(Multi), "Finish", num); +// } @@ -71,46 +71,46 @@ namespace FrameworkTests - private static readonly Random r = new Random(); - private readonly int num; +// private static readonly Random r = new Random(); +// private readonly int num; - private void SleepRandom() - { - Thread.Sleep(TimeSpan.FromSeconds(5.0)); - Thread.Sleep(TimeSpan.FromMilliseconds(r.Next(100, 1000))); - } +// private void SleepRandom() +// { +// Thread.Sleep(TimeSpan.FromSeconds(5.0)); +// Thread.Sleep(TimeSpan.FromMilliseconds(r.Next(100, 1000))); +// } - private void Log(string scope, string msg) - { - ALog.Log($"{num} {scope} {msg}"); - } +// private void Log(string scope, string msg) +// { +// ALog.Log($"{num} {scope} {msg}"); +// } - private void Log(string scope, string msg, int num) - { - ALog.Log($"{this.num} {scope} {msg} {num}"); - } +// private void Log(string scope, string msg, int num) +// { +// ALog.Log($"{this.num} {scope} {msg} {num}"); +// } - private string GetCurrentTestName() - { - return $"[{TestContext.CurrentContext.Test.Name}]"; - } - } +// private string GetCurrentTestName() +// { +// return $"[{TestContext.CurrentContext.Test.Name}]"; +// } +// } - public class ALog - { - private static readonly object _lock = new object(); +// public class ALog +// { +// private static readonly object _lock = new object(); - public static void Log(string msg) - { - lock (_lock) - { - File.AppendAllLines("C:\\Users\\vexor\\Desktop\\Alog.txt", [msg]); - } - } - } +// public static void Log(string msg) +// { +// lock (_lock) +// { +// File.AppendAllLines("C:\\Users\\vexor\\Desktop\\Alog.txt", [msg]); +// } +// } +// } @@ -122,105 +122,99 @@ namespace FrameworkTests - public interface ITestLifecycleComponent - { - void Start(); - void Stop(string results); - } +// public class Base +// { +// private readonly Dictionary> anyFields = new(); - public class Base - { - private readonly Dictionary> anyFields = new(); +// public void Setup() +// { +// var testId = 23; - public void Setup() - { - var testId = 23; +// var fields = new Dictionary(); +// anyFields.Add(testId, fields); +// YieldFields(field => +// { +// fields.Add(field.GetType(), field); +// }); - var fields = new Dictionary(); - anyFields.Add(testId, fields); - YieldFields(field => - { - fields.Add(field.GetType(), field); - }); +// foreach (var field in fields.Values) +// { +// field.Start(); +// } +// } - foreach (var field in fields.Values) - { - field.Start(); - } - } +// public void TearDown() +// { +// var testId = 23; - public void TearDown() - { - var testId = 23; +// // foreach stop - // foreach stop +// anyFields.Remove(testId); +// } - anyFields.Remove(testId); - } +// public T Get() +// { +// int testId = 123; +// var fields = anyFields[testId]; +// var type = typeof(T); +// var result = fields[type]; +// return (T)result; +// } - public T Get() - { - int testId = 123; - var fields = anyFields[testId]; - var type = typeof(T); - var result = fields[type]; - return (T)result; - } +// public BaseFields GetBaseField() +// { +// return Get(); +// } - public BaseFields GetBaseField() - { - return Get(); - } +// protected virtual void YieldFields(Action giveField) +// { +// giveField(new BaseFields()); +// } +// } - protected virtual void YieldFields(Action giveField) - { - giveField(new BaseFields()); - } - } +// public class Mid : Base +// { +// protected override void YieldFields(Action giveField) +// { +// base.YieldFields(giveField); +// giveField(new MidFields()); +// } - public class Mid : Base - { - protected override void YieldFields(Action giveField) - { - base.YieldFields(giveField); - giveField(new MidFields()); - } +// public MidFields GetMid() +// { +// return Get(); +// } +// } - public MidFields GetMid() - { - return Get(); - } - } +// public class Top : Mid +// { +// protected override void YieldFields(Action giveField) +// { +// base.YieldFields(giveField); +// giveField(new TopFields()); +// } - public class Top : Mid - { - protected override void YieldFields(Action giveField) - { - base.YieldFields(giveField); - giveField(new TopFields()); - } +// public TopFields GetTop() +// { +// return Get(); +// } +// } - public TopFields GetTop() - { - return Get(); - } - } +// public class BaseFields : ITestLifecycleComponent +// { +// public string EntryPoint { get; set; } = string.Empty; +// public string Log { get; set; } = string.Empty; +// } - public class BaseFields : ITestLifecycleComponent - { - public string EntryPoint { get; set; } = string.Empty; - public string Log { get; set; } = string.Empty; - } +// public class MidFields : ITestLifecycleComponent +// { +// public string Nodes { get; set; } = string.Empty; +// } - public class MidFields : ITestLifecycleComponent - { - public string Nodes { get; set; } = string.Empty; - } - - public class TopFields : ITestLifecycleComponent - { - public string Geth { get; set; } = string.Empty; - public string Contracts { get; set; } = string.Empty; - } -} +// public class TopFields : ITestLifecycleComponent +// { +// public string Geth { get; set; } = string.Empty; +// public string Contracts { get; set; } = string.Empty; +// } +//} diff --git a/Tests/FrameworkTests/Parallelism.cs b/Tests/FrameworkTests/Parallelism.cs new file mode 100644 index 00000000..8a877f41 --- /dev/null +++ b/Tests/FrameworkTests/Parallelism.cs @@ -0,0 +1,6 @@ +using NUnit.Framework; + +[assembly: LevelOfParallelism(100)] +namespace FrameworkTests +{ +}