Initial setup for continuous test runner
This commit is contained in:
parent
62d646836d
commit
d23f5aa29d
|
@ -0,0 +1,78 @@
|
|||
using Newtonsoft.Json;
|
||||
|
||||
namespace ContinuousTests
|
||||
{
|
||||
public class Configuration
|
||||
{
|
||||
public string LogPath { get; set; } = string.Empty;
|
||||
public string[] CodexUrls { get; set; } = Array.Empty<string>();
|
||||
public int SleepSecondsPerTest { get; set; }
|
||||
}
|
||||
|
||||
public class ConfigLoader
|
||||
{
|
||||
private const string filename = "config.json";
|
||||
|
||||
public Configuration Load()
|
||||
{
|
||||
var config = Read();
|
||||
Validate(config);
|
||||
return config;
|
||||
}
|
||||
|
||||
private Configuration Read()
|
||||
{
|
||||
if (File.Exists(filename))
|
||||
{
|
||||
var lines = File.ReadAllText(filename);
|
||||
try
|
||||
{
|
||||
var result = JsonConvert.DeserializeObject<Configuration>(lines);
|
||||
if (result != null) return result;
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
var logPath = Environment.GetEnvironmentVariable("LOGPATH");
|
||||
var codexUrls = Environment.GetEnvironmentVariable("CODEXURLS");
|
||||
var sleep = Environment.GetEnvironmentVariable("SLEEPSECONDSPERTEST");
|
||||
|
||||
if (!string.IsNullOrEmpty(logPath) && !string.IsNullOrEmpty(codexUrls) && !string.IsNullOrEmpty(sleep))
|
||||
{
|
||||
var urls = codexUrls.Split(';', StringSplitOptions.RemoveEmptyEntries);
|
||||
var ms = 0;
|
||||
if (int.TryParse(sleep, out ms))
|
||||
{
|
||||
if (urls.Length > 0)
|
||||
{
|
||||
return new Configuration { LogPath = logPath, CodexUrls = urls, SleepSecondsPerTest = ms };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
throw new Exception($"Unable to load configuration from '{filename}', and " +
|
||||
$"unable to load configuration from environment variables 'LOGPATH' and 'CODEXURLS', and 'SLEEPSECONDSPERTEST'. " +
|
||||
$"(semi-colon-separated URLs) " +
|
||||
$"Create the configuration file or set the environment veriables.");
|
||||
}
|
||||
|
||||
private void Validate(Configuration configuration)
|
||||
{
|
||||
if (configuration.SleepSecondsPerTest < 10)
|
||||
{
|
||||
Console.WriteLine("Warning: configuration.SleepMsPerTest was less than 10 seconds. Using 10 seconds instead!");
|
||||
configuration.SleepSecondsPerTest = 10;
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(configuration.LogPath))
|
||||
{
|
||||
throw new Exception($"Unvalid logpath set: '{configuration.LogPath}'");
|
||||
}
|
||||
|
||||
if (!configuration.CodexUrls.Any())
|
||||
{
|
||||
throw new Exception("No Codex URLs found.");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,111 @@
|
|||
using DistTestCore;
|
||||
using DistTestCore.Codex;
|
||||
using Logging;
|
||||
using Utils;
|
||||
|
||||
namespace ContinuousTests
|
||||
{
|
||||
public class ContinuousTestRunner
|
||||
{
|
||||
private readonly ConfigLoader configLoader = new ConfigLoader();
|
||||
private readonly TestFinder testFinder = new TestFinder();
|
||||
|
||||
public void Run()
|
||||
{
|
||||
var config = configLoader.Load();
|
||||
var log = new TestLog(config.LogPath, true);
|
||||
|
||||
log.Log("Starting continuous test run...");
|
||||
log.Log("Checking configuration...");
|
||||
PreflightCheck(config);
|
||||
log.Log("Contacting Codex nodes...");
|
||||
var nodes = CreateCodexNodes(log, new LongTimeSet(), config);
|
||||
log.Log("OK");
|
||||
log.Log("");
|
||||
|
||||
while (true)
|
||||
{
|
||||
var run = new TestRun(config, log, testFinder, nodes);
|
||||
|
||||
try
|
||||
{
|
||||
run.Run();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
log.Error($"Exception during test run: " + ex);
|
||||
}
|
||||
|
||||
Thread.Sleep(config.SleepSecondsPerTest * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
private void PreflightCheck(Configuration config)
|
||||
{
|
||||
var tests = testFinder.GetTests();
|
||||
if (!tests.Any())
|
||||
{
|
||||
throw new Exception("Unable to find any tests.");
|
||||
}
|
||||
|
||||
var errors = new List<string>();
|
||||
foreach (var test in tests)
|
||||
{
|
||||
if (test.RequiredNumberOfNodes > config.CodexUrls.Length)
|
||||
{
|
||||
errors.Add($"Test '{test.Name}' requires {test.RequiredNumberOfNodes} nodes. Configuration only has {config.CodexUrls.Length}");
|
||||
}
|
||||
}
|
||||
|
||||
if (errors.Any())
|
||||
{
|
||||
throw new Exception("Prerun check failed: " + string.Join(", ", errors));
|
||||
}
|
||||
}
|
||||
|
||||
private CodexNode[] CreateCodexNodes(BaseLog log, ITimeSet timeSet, Configuration config)
|
||||
{
|
||||
var nodes = config.CodexUrls.Select(url =>
|
||||
{
|
||||
var address = new Address(url, 1234);
|
||||
return new CodexNode(log, timeSet, address);
|
||||
}).ToArray();
|
||||
|
||||
var pass = true;
|
||||
foreach (var n in nodes)
|
||||
{
|
||||
log.Log($"Checking '{n.Address.Host}'...");
|
||||
|
||||
if (EnsureOnline(n))
|
||||
{
|
||||
log.Log("OK");
|
||||
}
|
||||
else
|
||||
{
|
||||
log.Error($"No response from '{n.Address.Host}'.");
|
||||
pass = false;
|
||||
}
|
||||
}
|
||||
if (!pass)
|
||||
{
|
||||
throw new Exception("Not all codex nodes responded.");
|
||||
}
|
||||
|
||||
return nodes;
|
||||
}
|
||||
|
||||
private bool EnsureOnline(CodexNode n)
|
||||
{
|
||||
try
|
||||
{
|
||||
var info = n.GetDebugInfo();
|
||||
if (info == null || string.IsNullOrEmpty(info.id)) return false;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\DistTestCore\DistTestCore.csproj" />
|
||||
<ProjectReference Include="..\Logging\Logging.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
|
@ -0,0 +1,33 @@
|
|||
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();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,10 @@
|
|||
using ContinuousTests;
|
||||
|
||||
public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
var runner = new ContinuousTestRunner();
|
||||
runner.Run();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
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!);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
using DistTestCore;
|
||||
using DistTestCore.Codex;
|
||||
using Logging;
|
||||
|
||||
namespace ContinuousTests
|
||||
{
|
||||
public class TestRun
|
||||
{
|
||||
private readonly Random random = new Random();
|
||||
private readonly Configuration config;
|
||||
private readonly BaseLog log;
|
||||
private readonly TestFinder testFinder;
|
||||
private readonly CodexNode[] nodes;
|
||||
private readonly FileManager fileManager;
|
||||
|
||||
public TestRun(Configuration config, BaseLog log, TestFinder testFinder, CodexNode[] nodes)
|
||||
{
|
||||
this.config = config;
|
||||
this.log = log;
|
||||
this.testFinder = testFinder;
|
||||
this.nodes = nodes;
|
||||
fileManager = new FileManager(log, new DistTestCore.Configuration());
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
var remainingTests = testFinder.GetTests().ToList();
|
||||
while (remainingTests.Any())
|
||||
{
|
||||
var test = PickOneRandom(remainingTests);
|
||||
var selectedNodes = SelectRandomNodes(test.RequiredNumberOfNodes);
|
||||
AssignEssentials(test, selectedNodes);
|
||||
fileManager.PushFileSet();
|
||||
|
||||
log.Log($"Start '{test.Name}'");
|
||||
try
|
||||
{
|
||||
test.Run();
|
||||
log.Log($"'{test.Name}' = Passed");
|
||||
}
|
||||
catch
|
||||
{
|
||||
log.Log($"'{test.Name}' = Failed");
|
||||
}
|
||||
|
||||
fileManager.PopFileSet();
|
||||
ClearEssentials(test);
|
||||
Thread.Sleep(config.SleepSecondsPerTest * 1000);
|
||||
}
|
||||
}
|
||||
|
||||
private void AssignEssentials(IContinuousTest test, CodexNode[] nodes)
|
||||
{
|
||||
var t = (ContinuousTest)test;
|
||||
t.Nodes = nodes;
|
||||
t.Log = log;
|
||||
t.FileManager = fileManager;
|
||||
}
|
||||
|
||||
private void ClearEssentials(IContinuousTest test)
|
||||
{
|
||||
var t = (ContinuousTest)test;
|
||||
t.Nodes = null!;
|
||||
t.Log = null!;
|
||||
t.FileManager = null!;
|
||||
}
|
||||
|
||||
private CodexNode[] SelectRandomNodes(int number)
|
||||
{
|
||||
var remainingNodes = nodes.ToList();
|
||||
var result = new CodexNode[number];
|
||||
for (var i = 0; i < number; i++)
|
||||
{
|
||||
result[i] = PickOneRandom(remainingNodes);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private T PickOneRandom<T>(List<T> remainingItems)
|
||||
{
|
||||
var i = random.Next(0, remainingItems.Count);
|
||||
var result = remainingItems[i];
|
||||
remainingItems.RemoveAt(i);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -10,68 +10,19 @@ namespace DistTestCore.Codex
|
|||
{
|
||||
this.lifecycle = lifecycle;
|
||||
Container = runningContainer;
|
||||
|
||||
var address = lifecycle.Configuration.GetAddress(Container);
|
||||
Node = new CodexNode(lifecycle.Log, lifecycle.TimeSet, address);
|
||||
}
|
||||
|
||||
public RunningContainer Container { get; }
|
||||
|
||||
public CodexDebugResponse GetDebugInfo()
|
||||
{
|
||||
return Http(TimeSpan.FromSeconds(2)).HttpGetJson<CodexDebugResponse>("debug/info");
|
||||
}
|
||||
|
||||
public CodexDebugPeerResponse GetDebugPeer(string peerId)
|
||||
{
|
||||
return GetDebugPeer(peerId, TimeSpan.FromSeconds(2));
|
||||
}
|
||||
|
||||
public CodexDebugPeerResponse GetDebugPeer(string peerId, TimeSpan timeout)
|
||||
{
|
||||
var http = Http(timeout);
|
||||
var str = http.HttpGetString($"debug/peer/{peerId}");
|
||||
|
||||
if (str.ToLowerInvariant() == "unable to find peer!")
|
||||
{
|
||||
return new CodexDebugPeerResponse
|
||||
{
|
||||
IsPeerFound = false
|
||||
};
|
||||
}
|
||||
|
||||
var result = http.TryJsonDeserialize<CodexDebugPeerResponse>(str);
|
||||
result.IsPeerFound = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
public string UploadFile(FileStream fileStream)
|
||||
{
|
||||
return Http().HttpPostStream("upload", fileStream);
|
||||
}
|
||||
|
||||
public Stream DownloadFile(string contentId)
|
||||
{
|
||||
return Http().HttpGetStream("download/" + contentId);
|
||||
}
|
||||
|
||||
public CodexSalesAvailabilityResponse SalesAvailability(CodexSalesAvailabilityRequest request)
|
||||
{
|
||||
return Http().HttpPostJson<CodexSalesAvailabilityRequest, CodexSalesAvailabilityResponse>("sales/availability", request);
|
||||
}
|
||||
|
||||
public string RequestStorage(CodexSalesRequestStorageRequest request, string contentId)
|
||||
{
|
||||
return Http().HttpPostJson($"storage/request/{contentId}", request);
|
||||
}
|
||||
|
||||
public string ConnectToPeer(string peerId, string peerMultiAddress)
|
||||
{
|
||||
return Http().HttpGetString($"connect/{peerId}?addrs={peerMultiAddress}");
|
||||
}
|
||||
public CodexNode Node { get; }
|
||||
|
||||
public void EnsureOnline()
|
||||
{
|
||||
try
|
||||
{
|
||||
var debugInfo = GetDebugInfo();
|
||||
var debugInfo = Node.GetDebugInfo();
|
||||
if (debugInfo == null || string.IsNullOrEmpty(debugInfo.id)) throw new InvalidOperationException("Unable to get debug-info from codex node at startup.");
|
||||
|
||||
var nodePeerId = debugInfo.id;
|
||||
|
@ -85,106 +36,5 @@ namespace DistTestCore.Codex
|
|||
throw new InvalidOperationException($"Failed to start codex node. Test infra failure.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private Http Http(TimeSpan? timeoutOverride = null)
|
||||
{
|
||||
var address = lifecycle.Configuration.GetAddress(Container);
|
||||
return new Http(lifecycle.Log, lifecycle.TimeSet, address, baseUrl: "/api/codex/v1", timeoutOverride);
|
||||
}
|
||||
}
|
||||
|
||||
public class CodexDebugResponse
|
||||
{
|
||||
public string id { get; set; } = string.Empty;
|
||||
public string[] addrs { get; set; } = new string[0];
|
||||
public string repo { get; set; } = string.Empty;
|
||||
public string spr { get; set; } = string.Empty;
|
||||
public EnginePeerResponse[] enginePeers { get; set; } = Array.Empty<EnginePeerResponse>();
|
||||
public SwitchPeerResponse[] switchPeers { get; set; } = Array.Empty<SwitchPeerResponse>();
|
||||
public CodexDebugVersionResponse codex { get; set; } = new();
|
||||
public CodexDebugTableResponse table { get; set; } = new();
|
||||
}
|
||||
|
||||
public class CodexDebugTableResponse
|
||||
{
|
||||
public CodexDebugTableNodeResponse localNode { get; set; } = new();
|
||||
public CodexDebugTableNodeResponse[] nodes { get; set; } = Array.Empty<CodexDebugTableNodeResponse>();
|
||||
}
|
||||
|
||||
public class CodexDebugTableNodeResponse
|
||||
{
|
||||
public string nodeId { get; set; } = string.Empty;
|
||||
public string peerId { get; set; } = string.Empty;
|
||||
public string record { get; set; } = string.Empty;
|
||||
public string address { get; set; } = string.Empty;
|
||||
public bool seen { get; set; }
|
||||
}
|
||||
|
||||
public class EnginePeerResponse
|
||||
{
|
||||
public string peerId { get; set; } = string.Empty;
|
||||
public EnginePeerContextResponse context { get; set; } = new();
|
||||
}
|
||||
|
||||
public class EnginePeerContextResponse
|
||||
{
|
||||
public int blocks { get; set; } = 0;
|
||||
public int peerWants { get; set; } = 0;
|
||||
public int exchanged { get; set; } = 0;
|
||||
public string lastExchange { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class SwitchPeerResponse
|
||||
{
|
||||
public string peerId { get; set; } = string.Empty;
|
||||
public string key { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class CodexDebugVersionResponse
|
||||
{
|
||||
public string version { get; set; } = string.Empty;
|
||||
public string revision { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class CodexDebugPeerResponse
|
||||
{
|
||||
public bool IsPeerFound { get; set; }
|
||||
|
||||
public string peerId { get; set; } = string.Empty;
|
||||
public long seqNo { get; set; }
|
||||
public CodexDebugPeerAddressResponse[] addresses { get; set; } = Array.Empty<CodexDebugPeerAddressResponse>();
|
||||
}
|
||||
|
||||
public class CodexDebugPeerAddressResponse
|
||||
{
|
||||
public string address { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class CodexSalesAvailabilityRequest
|
||||
{
|
||||
public string size { get; set; } = string.Empty;
|
||||
public string duration { get; set; } = string.Empty;
|
||||
public string minPrice { get; set; } = string.Empty;
|
||||
public string maxCollateral { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class CodexSalesAvailabilityResponse
|
||||
{
|
||||
public string id { get; set; } = string.Empty;
|
||||
public string size { get; set; } = string.Empty;
|
||||
public string duration { get; set; } = string.Empty;
|
||||
public string minPrice { get; set; } = string.Empty;
|
||||
public string maxCollateral { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class CodexSalesRequestStorageRequest
|
||||
{
|
||||
public string duration { get; set; } = string.Empty;
|
||||
public string proofProbability { get; set; } = string.Empty;
|
||||
public string reward { get; set; } = string.Empty;
|
||||
public string collateral { get; set; } = string.Empty;
|
||||
public string? expiry { get; set; }
|
||||
public uint? nodes { get; set; }
|
||||
public uint? tolerance { get; set;}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,173 @@
|
|||
using Logging;
|
||||
using Utils;
|
||||
|
||||
namespace DistTestCore.Codex
|
||||
{
|
||||
public class CodexNode
|
||||
{
|
||||
private readonly BaseLog log;
|
||||
private readonly ITimeSet timeSet;
|
||||
|
||||
public CodexNode(BaseLog log, ITimeSet timeSet, Address address)
|
||||
{
|
||||
this.log = log;
|
||||
this.timeSet = timeSet;
|
||||
Address = address;
|
||||
}
|
||||
|
||||
public Address Address { get; }
|
||||
|
||||
public CodexDebugResponse GetDebugInfo()
|
||||
{
|
||||
return Http(TimeSpan.FromSeconds(2)).HttpGetJson<CodexDebugResponse>("debug/info");
|
||||
}
|
||||
|
||||
public CodexDebugPeerResponse GetDebugPeer(string peerId)
|
||||
{
|
||||
return GetDebugPeer(peerId, TimeSpan.FromSeconds(2));
|
||||
}
|
||||
|
||||
public CodexDebugPeerResponse GetDebugPeer(string peerId, TimeSpan timeout)
|
||||
{
|
||||
var http = Http(timeout);
|
||||
var str = http.HttpGetString($"debug/peer/{peerId}");
|
||||
|
||||
if (str.ToLowerInvariant() == "unable to find peer!")
|
||||
{
|
||||
return new CodexDebugPeerResponse
|
||||
{
|
||||
IsPeerFound = false
|
||||
};
|
||||
}
|
||||
|
||||
var result = http.TryJsonDeserialize<CodexDebugPeerResponse>(str);
|
||||
result.IsPeerFound = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
public string UploadFile(FileStream fileStream)
|
||||
{
|
||||
return Http().HttpPostStream("upload", fileStream);
|
||||
}
|
||||
|
||||
public Stream DownloadFile(string contentId)
|
||||
{
|
||||
return Http().HttpGetStream("download/" + contentId);
|
||||
}
|
||||
|
||||
public CodexSalesAvailabilityResponse SalesAvailability(CodexSalesAvailabilityRequest request)
|
||||
{
|
||||
return Http().HttpPostJson<CodexSalesAvailabilityRequest, CodexSalesAvailabilityResponse>("sales/availability", request);
|
||||
}
|
||||
|
||||
public string RequestStorage(CodexSalesRequestStorageRequest request, string contentId)
|
||||
{
|
||||
return Http().HttpPostJson($"storage/request/{contentId}", request);
|
||||
}
|
||||
|
||||
public string ConnectToPeer(string peerId, string peerMultiAddress)
|
||||
{
|
||||
return Http().HttpGetString($"connect/{peerId}?addrs={peerMultiAddress}");
|
||||
}
|
||||
|
||||
private Http Http(TimeSpan? timeoutOverride = null)
|
||||
{
|
||||
return new Http(log, timeSet, Address, baseUrl: "/api/codex/v1", timeoutOverride);
|
||||
}
|
||||
}
|
||||
|
||||
public class CodexDebugResponse
|
||||
{
|
||||
public string id { get; set; } = string.Empty;
|
||||
public string[] addrs { get; set; } = new string[0];
|
||||
public string repo { get; set; } = string.Empty;
|
||||
public string spr { get; set; } = string.Empty;
|
||||
public EnginePeerResponse[] enginePeers { get; set; } = Array.Empty<EnginePeerResponse>();
|
||||
public SwitchPeerResponse[] switchPeers { get; set; } = Array.Empty<SwitchPeerResponse>();
|
||||
public CodexDebugVersionResponse codex { get; set; } = new();
|
||||
public CodexDebugTableResponse table { get; set; } = new();
|
||||
}
|
||||
|
||||
public class CodexDebugTableResponse
|
||||
{
|
||||
public CodexDebugTableNodeResponse localNode { get; set; } = new();
|
||||
public CodexDebugTableNodeResponse[] nodes { get; set; } = Array.Empty<CodexDebugTableNodeResponse>();
|
||||
}
|
||||
|
||||
public class CodexDebugTableNodeResponse
|
||||
{
|
||||
public string nodeId { get; set; } = string.Empty;
|
||||
public string peerId { get; set; } = string.Empty;
|
||||
public string record { get; set; } = string.Empty;
|
||||
public string address { get; set; } = string.Empty;
|
||||
public bool seen { get; set; }
|
||||
}
|
||||
|
||||
public class EnginePeerResponse
|
||||
{
|
||||
public string peerId { get; set; } = string.Empty;
|
||||
public EnginePeerContextResponse context { get; set; } = new();
|
||||
}
|
||||
|
||||
public class EnginePeerContextResponse
|
||||
{
|
||||
public int blocks { get; set; } = 0;
|
||||
public int peerWants { get; set; } = 0;
|
||||
public int exchanged { get; set; } = 0;
|
||||
public string lastExchange { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class SwitchPeerResponse
|
||||
{
|
||||
public string peerId { get; set; } = string.Empty;
|
||||
public string key { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class CodexDebugVersionResponse
|
||||
{
|
||||
public string version { get; set; } = string.Empty;
|
||||
public string revision { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class CodexDebugPeerResponse
|
||||
{
|
||||
public bool IsPeerFound { get; set; }
|
||||
|
||||
public string peerId { get; set; } = string.Empty;
|
||||
public long seqNo { get; set; }
|
||||
public CodexDebugPeerAddressResponse[] addresses { get; set; } = Array.Empty<CodexDebugPeerAddressResponse>();
|
||||
}
|
||||
|
||||
public class CodexDebugPeerAddressResponse
|
||||
{
|
||||
public string address { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class CodexSalesAvailabilityRequest
|
||||
{
|
||||
public string size { get; set; } = string.Empty;
|
||||
public string duration { get; set; } = string.Empty;
|
||||
public string minPrice { get; set; } = string.Empty;
|
||||
public string maxCollateral { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class CodexSalesAvailabilityResponse
|
||||
{
|
||||
public string id { get; set; } = string.Empty;
|
||||
public string size { get; set; } = string.Empty;
|
||||
public string duration { get; set; } = string.Empty;
|
||||
public string minPrice { get; set; } = string.Empty;
|
||||
public string maxCollateral { get; set; } = string.Empty;
|
||||
}
|
||||
|
||||
public class CodexSalesRequestStorageRequest
|
||||
{
|
||||
public string duration { get; set; } = string.Empty;
|
||||
public string proofProbability { get; set; } = string.Empty;
|
||||
public string reward { get; set; } = string.Empty;
|
||||
public string collateral { get; set; } = string.Empty;
|
||||
public string? expiry { get; set; }
|
||||
public uint? nodes { get; set; }
|
||||
public uint? tolerance { get; set; }
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
using DistTestCore.Codex;
|
||||
using KubernetesWorkflow;
|
||||
using Utils;
|
||||
|
||||
namespace DistTestCore
|
||||
{
|
||||
|
@ -52,7 +53,7 @@ namespace DistTestCore
|
|||
return runnerLocation;
|
||||
}
|
||||
|
||||
public RunningContainerAddress GetAddress(RunningContainer container)
|
||||
public Address GetAddress(RunningContainer container)
|
||||
{
|
||||
if (GetTestRunnerLocation() == TestRunnerLocation.InternalToCluster)
|
||||
{
|
||||
|
|
|
@ -19,11 +19,11 @@ namespace DistTestCore
|
|||
public const int ChunkSize = 1024 * 1024 * 100;
|
||||
private static NumberSource folderNumberSource = new NumberSource(0);
|
||||
private readonly Random random = new Random();
|
||||
private readonly TestLog log;
|
||||
private readonly BaseLog log;
|
||||
private readonly string folder;
|
||||
private readonly List<List<TestFile>> fileSetStack = new List<List<TestFile>>();
|
||||
|
||||
public FileManager(TestLog log, Configuration configuration)
|
||||
public FileManager(BaseLog log, Configuration configuration)
|
||||
{
|
||||
folder = Path.Combine(configuration.GetFileManagerFolder(), folderNumberSource.GetNextNumber().ToString("D5"));
|
||||
|
||||
|
@ -142,9 +142,9 @@ namespace DistTestCore
|
|||
|
||||
public class TestFile
|
||||
{
|
||||
private readonly TestLog log;
|
||||
private readonly BaseLog log;
|
||||
|
||||
public TestFile(TestLog log, string filename, string label)
|
||||
public TestFile(BaseLog log, string filename, string label)
|
||||
{
|
||||
this.log = log;
|
||||
Filename = filename;
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using KubernetesWorkflow;
|
||||
using Logging;
|
||||
using Logging;
|
||||
using Newtonsoft.Json;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Net.Http.Json;
|
||||
|
@ -11,11 +10,11 @@ namespace DistTestCore
|
|||
{
|
||||
private readonly BaseLog log;
|
||||
private readonly ITimeSet timeSet;
|
||||
private readonly RunningContainerAddress address;
|
||||
private readonly Address address;
|
||||
private readonly string baseUrl;
|
||||
private readonly TimeSpan? timeoutOverride;
|
||||
|
||||
public Http(BaseLog log, ITimeSet timeSet, RunningContainerAddress address, string baseUrl, TimeSpan? timeoutOverride = null)
|
||||
public Http(BaseLog log, ITimeSet timeSet, Address address, string baseUrl, TimeSpan? timeoutOverride = null)
|
||||
{
|
||||
this.log = log;
|
||||
this.timeSet = timeSet;
|
||||
|
|
|
@ -50,7 +50,7 @@ namespace DistTestCore.Marketplace
|
|||
$"proofProbability: {proofProbability}, " +
|
||||
$"duration: {Time.FormatDuration(duration)})");
|
||||
|
||||
var response = codexAccess.RequestStorage(request, contentId.Id);
|
||||
var response = codexAccess.Node.RequestStorage(request, contentId.Id);
|
||||
|
||||
if (response == "Purchasing not available")
|
||||
{
|
||||
|
@ -78,7 +78,7 @@ namespace DistTestCore.Marketplace
|
|||
$"maxCollateral: {maxCollateral}, " +
|
||||
$"maxDuration: {Time.FormatDuration(maxDuration)})");
|
||||
|
||||
var response = codexAccess.SalesAvailability(request);
|
||||
var response = codexAccess.Node.SalesAvailability(request);
|
||||
|
||||
Log($"Storage successfully made available. Id: {response.id}");
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ namespace DistTestCore
|
|||
|
||||
public CodexDebugResponse GetDebugInfo()
|
||||
{
|
||||
var debugInfo = CodexAccess.GetDebugInfo();
|
||||
var debugInfo = CodexAccess.Node.GetDebugInfo();
|
||||
var known = string.Join(",", debugInfo.table.nodes.Select(n => n.peerId));
|
||||
Log($"Got DebugInfo with id: '{debugInfo.id}'. This node knows: {known}");
|
||||
return debugInfo;
|
||||
|
@ -57,12 +57,12 @@ namespace DistTestCore
|
|||
|
||||
public CodexDebugPeerResponse GetDebugPeer(string peerId)
|
||||
{
|
||||
return CodexAccess.GetDebugPeer(peerId);
|
||||
return CodexAccess.Node.GetDebugPeer(peerId);
|
||||
}
|
||||
|
||||
public CodexDebugPeerResponse GetDebugPeer(string peerId, TimeSpan timeout)
|
||||
{
|
||||
return CodexAccess.GetDebugPeer(peerId, timeout);
|
||||
return CodexAccess.Node.GetDebugPeer(peerId, timeout);
|
||||
}
|
||||
|
||||
public ContentId UploadFile(TestFile file)
|
||||
|
@ -72,7 +72,7 @@ namespace DistTestCore
|
|||
var logMessage = $"Uploading file {file.Describe()}...";
|
||||
var response = Stopwatch.Measure(lifecycle.Log, logMessage, () =>
|
||||
{
|
||||
return CodexAccess.UploadFile(fileStream);
|
||||
return CodexAccess.Node.UploadFile(fileStream);
|
||||
});
|
||||
|
||||
if (response.StartsWith(UploadFailedMessage))
|
||||
|
@ -101,7 +101,7 @@ namespace DistTestCore
|
|||
|
||||
Log($"Connecting to peer {peer.GetName()}...");
|
||||
var peerInfo = node.GetDebugInfo();
|
||||
var response = CodexAccess.ConnectToPeer(peerInfo.id, GetPeerMultiAddress(peer, peerInfo));
|
||||
var response = CodexAccess.Node.ConnectToPeer(peerInfo.id, GetPeerMultiAddress(peer, peerInfo));
|
||||
|
||||
Assert.That(response, Is.EqualTo(SuccessfullyConnectedMessage), "Unable to connect codex nodes.");
|
||||
Log($"Successfully connected to peer {peer.GetName()}.");
|
||||
|
@ -141,7 +141,7 @@ namespace DistTestCore
|
|||
using var fileStream = File.OpenWrite(file.Filename);
|
||||
try
|
||||
{
|
||||
using var downloadStream = CodexAccess.DownloadFile(contentId);
|
||||
using var downloadStream = CodexAccess.Node.DownloadFile(contentId);
|
||||
downloadStream.CopyTo(fileStream);
|
||||
}
|
||||
catch
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
namespace KubernetesWorkflow
|
||||
using Utils;
|
||||
|
||||
namespace KubernetesWorkflow
|
||||
{
|
||||
public class RunningContainers
|
||||
{
|
||||
|
@ -21,7 +23,7 @@
|
|||
|
||||
public class RunningContainer
|
||||
{
|
||||
public RunningContainer(RunningPod pod, ContainerRecipe recipe, Port[] servicePorts, StartupConfig startupConfig, RunningContainerAddress clusterExternalAddress, RunningContainerAddress clusterInternalAddress)
|
||||
public RunningContainer(RunningPod pod, ContainerRecipe recipe, Port[] servicePorts, StartupConfig startupConfig, Address clusterExternalAddress, Address clusterInternalAddress)
|
||||
{
|
||||
Pod = pod;
|
||||
Recipe = recipe;
|
||||
|
@ -35,8 +37,8 @@
|
|||
public RunningPod Pod { get; }
|
||||
public ContainerRecipe Recipe { get; }
|
||||
public Port[] ServicePorts { get; }
|
||||
public RunningContainerAddress ClusterExternalAddress { get; }
|
||||
public RunningContainerAddress ClusterInternalAddress { get; }
|
||||
public Address ClusterExternalAddress { get; }
|
||||
public Address ClusterInternalAddress { get; }
|
||||
|
||||
private string GetContainerName(ContainerRecipe recipe, StartupConfig startupConfig)
|
||||
{
|
||||
|
@ -50,16 +52,4 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class RunningContainerAddress
|
||||
{
|
||||
public RunningContainerAddress(string host, int port)
|
||||
{
|
||||
Host = host;
|
||||
Port = port;
|
||||
}
|
||||
|
||||
public string Host { get; }
|
||||
public int Port { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using Logging;
|
||||
using Utils;
|
||||
|
||||
namespace KubernetesWorkflow
|
||||
{
|
||||
|
@ -87,20 +88,20 @@ namespace KubernetesWorkflow
|
|||
}).ToArray();
|
||||
}
|
||||
|
||||
private RunningContainerAddress GetContainerExternalAddress(RunningPod pod, Port[] servicePorts)
|
||||
private Address GetContainerExternalAddress(RunningPod pod, Port[] servicePorts)
|
||||
{
|
||||
return new RunningContainerAddress(
|
||||
return new Address(
|
||||
pod.Cluster.HostAddress,
|
||||
GetServicePort(servicePorts));
|
||||
}
|
||||
|
||||
private RunningContainerAddress GetContainerInternalAddress(ContainerRecipe recipe)
|
||||
private Address GetContainerInternalAddress(ContainerRecipe recipe)
|
||||
{
|
||||
var serviceName = "service-" + numberSource.WorkflowNumber;
|
||||
var namespaceName = cluster.Configuration.K8sNamespacePrefix + testNamespace;
|
||||
var port = GetInternalPort(recipe);
|
||||
|
||||
return new RunningContainerAddress(
|
||||
return new Address(
|
||||
$"http://{serviceName}.{namespaceName}.svc.cluster.local",
|
||||
port);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
namespace Utils
|
||||
{
|
||||
public class Address
|
||||
{
|
||||
public Address(string host, int port)
|
||||
{
|
||||
Host = host;
|
||||
Port = port;
|
||||
}
|
||||
|
||||
public string Host { get; }
|
||||
public int Port { get; }
|
||||
}
|
||||
}
|
|
@ -17,6 +17,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Logging", "Logging\Logging.
|
|||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NethereumWorkflow", "Nethereum\NethereumWorkflow.csproj", "{D6C3555E-D52D-4993-A87B-71AB650398FD}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ContinuousTests", "ContinuousTests\ContinuousTests.csproj", "{025B7074-0A09-4FCC-9BB9-03AE2A961EA1}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
|
@ -51,6 +53,10 @@ Global
|
|||
{D6C3555E-D52D-4993-A87B-71AB650398FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{D6C3555E-D52D-4993-A87B-71AB650398FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{D6C3555E-D52D-4993-A87B-71AB650398FD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{025B7074-0A09-4FCC-9BB9-03AE2A961EA1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{025B7074-0A09-4FCC-9BB9-03AE2A961EA1}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{025B7074-0A09-4FCC-9BB9-03AE2A961EA1}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{025B7074-0A09-4FCC-9BB9-03AE2A961EA1}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
|
Loading…
Reference in New Issue