while better the new plan is still a mess

This commit is contained in:
ThatBen 2025-04-23 14:18:11 +02:00
parent 7eb3bbd1de
commit 2dfdfac2bb
No known key found for this signature in database
GPG Key ID: 62C543548433D43E
13 changed files with 549 additions and 461 deletions

View File

@ -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, "'", "'");

View File

@ -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; }
}
}

View File

@ -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<TestLifecycle, MarketplaceHandle> handles = new Dictionary<TestLifecycle, MarketplaceHandle>();
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; }
}
}
}

View File

@ -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<string, TestLifecycle> lifecycles = new Dictionary<string, TestLifecycle>();
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<T>() where T : ILifecycleComponent
{
return lifecycleComponents.Get<T>(GetCurrentTestName());
}
protected virtual void CollectStatusLogData(TestLifecycle lifecycle, Dictionary<string, string> 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<TestLifecycle>();
}
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()
{

View File

@ -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<T>() where T : ILifecycleComponent;
}
public class DistTestLifecycleComponents
{
private readonly object _lock = new object();
private readonly Dictionary<string, Dictionary<Type, ILifecycleComponent>> components = new();
public void Setup(string testName, Action<ILifecycleComponentCollector> initializer)
{
var newComponents = new Dictionary<Type, ILifecycleComponent>();
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<T>(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<Type, ILifecycleComponent> components;
public Collector(Dictionary<Type, ILifecycleComponent> 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<T>() where T : ILifecycleComponent
{
return parent.Get<T>(testName);
}
}
}
}

View File

@ -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;
}
}
}

View File

@ -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 = "")

View File

@ -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<string, string> metadata;
private readonly List<RunningPod> runningContainers = new();
private readonly string testName;
private readonly string deployId;
private readonly List<IDownloadedLog> stoppedContainerLogs = new List<IDownloadedLog>();
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,

View File

@ -4,46 +4,56 @@ using DistTestCore;
namespace CodexTests
{
public class AutoBootstrapDistTest : CodexDistTest
public class AutoBootstrapComponent : ILifecycleComponent
{
private readonly Dictionary<TestLifecycle, ICodexNode> bootstrapNodes = new Dictionary<TestLifecycle, ICodexNode>();
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<TestLifecycle>();
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<AutoBootstrapComponent>().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<AutoBootstrapComponent>().BootstrapNode;
if (bn == null) throw new InvalidOperationException("BootstrapNode accessed before initialized.");
return bn;
}
}
}

View File

@ -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<ICodexNode> addNode;
private readonly object nodesLock = new object();
public CodexLogTrackerProvider(Action<ICodexNode> 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<ICodexNode> Nodes { get; } = new();
public void Start(ILifecycleComponentAccess access)
{
return new CodexLogTracker(addNode);
var ci = access.Get<TestLifecycle>().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<ICodexNode> addNode;
var tl = access.Get<TestLifecycle>();
var log = tl.Log;
var logFiles = tl.DownloadAllLogs();
public CodexLogTracker(Action<ICodexNode> 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<TestLifecycle, CodexTranscriptWriter> writers = new Dictionary<TestLifecycle, CodexTranscriptWriter>();
private static readonly Dictionary<TestLifecycle, BlockCache> blockCaches = new Dictionary<TestLifecycle, BlockCache>();
// this entire structure is not good and needs to be destroyed at the earliest convenience:
private static readonly Dictionary<TestLifecycle, List<ICodexNode>> nodes = new Dictionary<TestLifecycle, List<ICodexNode>>();
public CodexDistTest()
{
ProjectPlugin.Load<CodexPlugin.CodexPlugin>();
@ -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<ICodexNode>());
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<CodexDistTestComponents>().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<TestLifecycle>().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;
}
}

View File

@ -0,0 +1,73 @@
using CodexClient;
using CodexClient.Hooks;
using Utils;
namespace CodexTests
{
public class CodexLogTrackerProvider : ICodexHooksProvider
{
private readonly Action<ICodexNode> addNode;
public CodexLogTrackerProvider(Action<ICodexNode> addNode)
{
this.addNode = addNode;
}
// See TestLifecycle.cs DownloadAllLogs()
public ICodexNodeHooks CreateHooks(string nodeName)
{
return new CodexLogTracker(addNode);
}
public class CodexLogTracker : ICodexNodeHooks
{
private readonly Action<ICodexNode> addNode;
public CodexLogTracker(Action<ICodexNode> 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)
{
}
}
}
}

View File

@ -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<int, Dictionary<Type, ITestLifecycleComponent>> anyFields = new();
public class Base
{
private readonly Dictionary<int, Dictionary<Type, ITestLifecycleComponent>> anyFields = new();
// public void Setup()
// {
// var testId = 23;
public void Setup()
{
var testId = 23;
// var fields = new Dictionary<Type, ITestLifecycleComponent>();
// anyFields.Add(testId, fields);
// YieldFields(field =>
// {
// fields.Add(field.GetType(), field);
// });
var fields = new Dictionary<Type, ITestLifecycleComponent>();
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<T>()
// {
// int testId = 123;
// var fields = anyFields[testId];
// var type = typeof(T);
// var result = fields[type];
// return (T)result;
// }
public T Get<T>()
{
int testId = 123;
var fields = anyFields[testId];
var type = typeof(T);
var result = fields[type];
return (T)result;
}
// public BaseFields GetBaseField()
// {
// return Get<BaseFields>();
// }
public BaseFields GetBaseField()
{
return Get<BaseFields>();
}
// protected virtual void YieldFields(Action<ITestLifecycleComponent> giveField)
// {
// giveField(new BaseFields());
// }
// }
protected virtual void YieldFields(Action<ITestLifecycleComponent> giveField)
{
giveField(new BaseFields());
}
}
// public class Mid : Base
// {
// protected override void YieldFields(Action<ITestLifecycleComponent> giveField)
// {
// base.YieldFields(giveField);
// giveField(new MidFields());
// }
public class Mid : Base
{
protected override void YieldFields(Action<ITestLifecycleComponent> giveField)
{
base.YieldFields(giveField);
giveField(new MidFields());
}
// public MidFields GetMid()
// {
// return Get<MidFields>();
// }
// }
public MidFields GetMid()
{
return Get<MidFields>();
}
}
// public class Top : Mid
// {
// protected override void YieldFields(Action<ITestLifecycleComponent> giveField)
// {
// base.YieldFields(giveField);
// giveField(new TopFields());
// }
public class Top : Mid
{
protected override void YieldFields(Action<ITestLifecycleComponent> giveField)
{
base.YieldFields(giveField);
giveField(new TopFields());
}
// public TopFields GetTop()
// {
// return Get<TopFields>();
// }
// }
public TopFields GetTop()
{
return Get<TopFields>();
}
}
// 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;
// }
//}

View File

@ -0,0 +1,6 @@
using NUnit.Framework;
[assembly: LevelOfParallelism(100)]
namespace FrameworkTests
{
}