Instantiate node-handles for each individual test. Allows for time-set selection.

This commit is contained in:
benbierens 2023-06-21 09:27:59 +02:00
parent d23f5aa29d
commit 978d2d3a84
No known key found for this signature in database
GPG Key ID: FE44815D96D0A1AA
9 changed files with 175 additions and 94 deletions

View File

@ -0,0 +1,22 @@
using DistTestCore;
using DistTestCore.Codex;
using Logging;
using Utils;
namespace ContinuousTests
{
public class CodexNodeFactory
{
public CodexNode[] Create(string[] urls, BaseLog log, ITimeSet timeSet)
{
return urls.Select(url =>
{
var cutIndex = url.LastIndexOf(':');
var host = url.Substring(0, cutIndex);
var port = url.Substring(cutIndex + 1);
var address = new Address(host, Convert.ToInt32(port));
return new CodexNode(log, timeSet, address);
}).ToArray();
}
}
}

View File

@ -40,7 +40,7 @@ namespace ContinuousTests
if (!string.IsNullOrEmpty(logPath) && !string.IsNullOrEmpty(codexUrls) && !string.IsNullOrEmpty(sleep)) if (!string.IsNullOrEmpty(logPath) && !string.IsNullOrEmpty(codexUrls) && !string.IsNullOrEmpty(sleep))
{ {
var urls = codexUrls.Split(';', StringSplitOptions.RemoveEmptyEntries); var urls = codexUrls.Split(';', StringSplitOptions.RemoveEmptyEntries);
var ms = 0; int ms;
if (int.TryParse(sleep, out ms)) if (int.TryParse(sleep, out ms))
{ {
if (urls.Length > 0) if (urls.Length > 0)

View File

@ -0,0 +1,82 @@
using DistTestCore;
using DistTestCore.Codex;
using Logging;
namespace ContinuousTests
{
public abstract class ContinuousTestLongTimeouts : ContinuousTest
{
public override ITimeSet TimeSet => new LongTimeSet();
}
public abstract class ContinuousTest
{
private const string UploadFailedMessage = "Unable to store block";
public void Initialize(CodexNode[] nodes, BaseLog log, FileManager fileManager)
{
Nodes = nodes;
Log = log;
FileManager = fileManager;
}
public CodexNode[] Nodes { get; private set; } = null!;
public BaseLog Log { get; private set; } = null!;
public IFileManager FileManager { get; private set; } = null!;
public virtual ITimeSet TimeSet { get { return new DefaultTimeSet(); } }
public abstract int RequiredNumberOfNodes { get; }
public string Name
{
get
{
return GetType().Name;
}
}
public abstract void Run();
public ContentId? UploadFile(CodexNode node, TestFile file)
{
using var fileStream = File.OpenRead(file.Filename);
var logMessage = $"Uploading file {file.Describe()}...";
var response = Stopwatch.Measure(Log, logMessage, () =>
{
return node.UploadFile(fileStream);
});
if (response.StartsWith(UploadFailedMessage))
{
return null;
}
Log.Log($"Uploaded file. Received contentId: '{response}'.");
return new ContentId(response);
}
public TestFile DownloadContent(CodexNode node, ContentId contentId, string fileLabel = "")
{
var logMessage = $"Downloading for contentId: '{contentId.Id}'...";
var file = FileManager.CreateEmptyTestFile(fileLabel);
Stopwatch.Measure(Log, logMessage, () => DownloadToFile(node, contentId.Id, file));
Log.Log($"Downloaded file {file.Describe()} to '{file.Filename}'.");
return file;
}
private void DownloadToFile(CodexNode node, string contentId, TestFile file)
{
using var fileStream = File.OpenWrite(file.Filename);
try
{
using var downloadStream = node.DownloadFile(contentId);
downloadStream.CopyTo(fileStream);
}
catch
{
Log.Log($"Failed to download file '{contentId}'.");
throw;
}
}
}
}

View File

@ -1,14 +1,14 @@
using DistTestCore; using DistTestCore;
using DistTestCore.Codex; using DistTestCore.Codex;
using Logging; using Logging;
using Utils;
namespace ContinuousTests namespace ContinuousTests
{ {
public class ContinuousTestRunner public class ContinuousTestRunner
{ {
private readonly ConfigLoader configLoader = new ConfigLoader(); private readonly ConfigLoader configLoader = new ConfigLoader();
private readonly TestFinder testFinder = new TestFinder(); private readonly TestFactory testFactory = new TestFactory();
private readonly CodexNodeFactory codexNodeFactory = new CodexNodeFactory();
public void Run() public void Run()
{ {
@ -19,13 +19,13 @@ namespace ContinuousTests
log.Log("Checking configuration..."); log.Log("Checking configuration...");
PreflightCheck(config); PreflightCheck(config);
log.Log("Contacting Codex nodes..."); log.Log("Contacting Codex nodes...");
var nodes = CreateCodexNodes(log, new LongTimeSet(), config); CheckCodexNodes(log, config);
log.Log("OK"); log.Log("All OK.");
log.Log(""); log.Log("");
while (true) while (true)
{ {
var run = new TestRun(config, log, testFinder, nodes); var run = new TestRun(config, log, testFactory);
try try
{ {
@ -42,7 +42,7 @@ namespace ContinuousTests
private void PreflightCheck(Configuration config) private void PreflightCheck(Configuration config)
{ {
var tests = testFinder.GetTests(); var tests = testFactory.CreateTests();
if (!tests.Any()) if (!tests.Any())
{ {
throw new Exception("Unable to find any tests."); throw new Exception("Unable to find any tests.");
@ -57,20 +57,20 @@ namespace ContinuousTests
} }
} }
if (!Directory.Exists(config.LogPath))
{
Directory.CreateDirectory(config.LogPath);
}
if (errors.Any()) if (errors.Any())
{ {
throw new Exception("Prerun check failed: " + string.Join(", ", errors)); throw new Exception("Prerun check failed: " + string.Join(", ", errors));
} }
} }
private CodexNode[] CreateCodexNodes(BaseLog log, ITimeSet timeSet, Configuration config) private void CheckCodexNodes(BaseLog log, Configuration config)
{ {
var nodes = config.CodexUrls.Select(url => var nodes = codexNodeFactory.Create(config.CodexUrls, log, new DefaultTimeSet());
{
var address = new Address(url, 1234);
return new CodexNode(log, timeSet, address);
}).ToArray();
var pass = true; var pass = true;
foreach (var n in nodes) foreach (var n in nodes)
{ {
@ -90,8 +90,6 @@ namespace ContinuousTests
{ {
throw new Exception("Not all codex nodes responded."); throw new Exception("Not all codex nodes responded.");
} }
return nodes;
} }
private bool EnsureOnline(CodexNode n) private bool EnsureOnline(CodexNode n)

View File

@ -1,33 +0,0 @@
using DistTestCore;
using DistTestCore.Codex;
using Logging;
namespace ContinuousTests
{
public interface IContinuousTest
{
string Name { get; }
int RequiredNumberOfNodes { get; }
void Run();
}
public abstract class ContinuousTest : IContinuousTest
{
public CodexNode[] Nodes { get; set; } = null!;
public BaseLog Log { get; set; } = null!;
public FileManager FileManager { get; set; } = null!;
public abstract int RequiredNumberOfNodes { get; }
public string Name
{
get
{
return GetType().Name;
}
}
public abstract void Run();
}
}

View File

@ -0,0 +1,12 @@
namespace ContinuousTests
{
public class TestFactory
{
public ContinuousTest[] CreateTests()
{
var types = GetType().Assembly.GetTypes();
var testTypes = types.Where(t => typeof(ContinuousTest).IsAssignableFrom(t) && !t.IsAbstract);
return testTypes.Select(t => (ContinuousTest)Activator.CreateInstance(t)!).ToArray();
}
}
}

View File

@ -1,24 +0,0 @@
namespace ContinuousTests
{
public class TestFinder
{
private readonly List<IContinuousTest> testList = new List<IContinuousTest>();
public IContinuousTest[] GetTests()
{
if (!testList.Any()) FindTests();
return testList.ToArray();
}
private void FindTests()
{
var types = GetType().Assembly.GetTypes();
var testTypes = types.Where(t => typeof(IContinuousTest).IsAssignableFrom(t) && !t.IsAbstract);
foreach (var testType in testTypes)
{
var t = Activator.CreateInstance(testType);
testList.Add((IContinuousTest)t!);
}
}
}
}

View File

@ -7,29 +7,30 @@ namespace ContinuousTests
public class TestRun public class TestRun
{ {
private readonly Random random = new Random(); private readonly Random random = new Random();
private readonly CodexNodeFactory codexNodeFactory = new CodexNodeFactory();
private readonly Configuration config; private readonly Configuration config;
private readonly BaseLog log; private readonly BaseLog log;
private readonly TestFinder testFinder; private readonly TestFactory testFinder;
private readonly CodexNode[] nodes;
private readonly FileManager fileManager; private readonly FileManager fileManager;
private ITimeSet timeSet;
public TestRun(Configuration config, BaseLog log, TestFinder testFinder, CodexNode[] nodes) public TestRun(Configuration config, BaseLog log, TestFactory testFinder)
{ {
this.config = config; this.config = config;
this.log = log; this.log = log;
this.testFinder = testFinder; this.testFinder = testFinder;
this.nodes = nodes;
fileManager = new FileManager(log, new DistTestCore.Configuration()); fileManager = new FileManager(log, new DistTestCore.Configuration());
timeSet = new DefaultTimeSet();
} }
public void Run() public void Run()
{ {
var remainingTests = testFinder.GetTests().ToList(); var remainingTests = testFinder.CreateTests().ToList();
while (remainingTests.Any()) while (remainingTests.Any())
{ {
var test = PickOneRandom(remainingTests); var test = PickOneRandom(remainingTests);
var selectedNodes = SelectRandomNodes(test.RequiredNumberOfNodes); var nodes = CreateRandomNodes(test.RequiredNumberOfNodes);
AssignEssentials(test, selectedNodes); AssignEssentials(test, nodes);
fileManager.PushFileSet(); fileManager.PushFileSet();
log.Log($"Start '{test.Name}'"); log.Log($"Start '{test.Name}'");
@ -49,33 +50,34 @@ namespace ContinuousTests
} }
} }
private void AssignEssentials(IContinuousTest test, CodexNode[] nodes) private void AssignEssentials(ContinuousTest test, CodexNode[] nodes)
{ {
var t = (ContinuousTest)test; test.Initialize(nodes, log, fileManager);
t.Nodes = nodes;
t.Log = log;
t.FileManager = fileManager;
} }
private void ClearEssentials(IContinuousTest test) private void ClearEssentials(ContinuousTest test)
{ {
var t = (ContinuousTest)test; // Looks a little strange, but prevents finished test from interacting further.
t.Nodes = null!; test.Initialize(null!, null!, null!);
t.Log = null!;
t.FileManager = null!;
} }
private CodexNode[] SelectRandomNodes(int number) private string[] SelectRandomUrls(int number)
{ {
var remainingNodes = nodes.ToList(); var urls = config.CodexUrls.ToList();
var result = new CodexNode[number]; var result = new string[number];
for (var i = 0; i < number; i++) for (var i = 0; i < number; i++)
{ {
result[i] = PickOneRandom(remainingNodes); result[i] = PickOneRandom(urls);
} }
return result; return result;
} }
private CodexNode[] CreateRandomNodes(int number)
{
var urls = SelectRandomUrls(number);
return codexNodeFactory.Create(urls, log, timeSet);
}
private T PickOneRandom<T>(List<T> remainingItems) private T PickOneRandom<T>(List<T> remainingItems)
{ {
var i = random.Next(0, remainingItems.Count); var i = random.Next(0, remainingItems.Count);

View File

@ -0,0 +1,22 @@
using DistTestCore;
using NUnit.Framework;
namespace ContinuousTests.Tests
{
public class TwoClientTest : ContinuousTest
{
public override int RequiredNumberOfNodes => 2;
public override void Run()
{
var file = FileManager.GenerateTestFile(10.MB());
var cid = UploadFile(Nodes[0], file);
Assert.That(cid, Is.Not.Null);
var dl = DownloadContent(Nodes[1], cid!);
dl.AssertIsEqual(file);
}
}
}