Initial setup for continuous test runner

This commit is contained in:
benbierens 2023-06-21 08:28:40 +02:00
parent 62d646836d
commit d23f5aa29d
No known key found for this signature in database
GPG Key ID: FE44815D96D0A1AA
18 changed files with 588 additions and 192 deletions

View File

@ -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.");
}
}
}
}

View File

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

View File

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

View File

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

View File

@ -0,0 +1,10 @@
using ContinuousTests;
public class Program
{
public static void Main(string[] args)
{
var runner = new ContinuousTestRunner();
runner.Run();
}
}

View File

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

View File

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

View File

@ -10,68 +10,19 @@ namespace DistTestCore.Codex
{ {
this.lifecycle = lifecycle; this.lifecycle = lifecycle;
Container = runningContainer; Container = runningContainer;
var address = lifecycle.Configuration.GetAddress(Container);
Node = new CodexNode(lifecycle.Log, lifecycle.TimeSet, address);
} }
public RunningContainer Container { get; } public RunningContainer Container { get; }
public CodexNode Node { 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 void EnsureOnline() public void EnsureOnline()
{ {
try 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."); if (debugInfo == null || string.IsNullOrEmpty(debugInfo.id)) throw new InvalidOperationException("Unable to get debug-info from codex node at startup.");
var nodePeerId = debugInfo.id; var nodePeerId = debugInfo.id;
@ -85,106 +36,5 @@ namespace DistTestCore.Codex
throw new InvalidOperationException($"Failed to start codex node. Test infra failure.", e); 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;}
} }
} }

View File

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

View File

@ -1,5 +1,6 @@
using DistTestCore.Codex; using DistTestCore.Codex;
using KubernetesWorkflow; using KubernetesWorkflow;
using Utils;
namespace DistTestCore namespace DistTestCore
{ {
@ -52,7 +53,7 @@ namespace DistTestCore
return runnerLocation; return runnerLocation;
} }
public RunningContainerAddress GetAddress(RunningContainer container) public Address GetAddress(RunningContainer container)
{ {
if (GetTestRunnerLocation() == TestRunnerLocation.InternalToCluster) if (GetTestRunnerLocation() == TestRunnerLocation.InternalToCluster)
{ {

View File

@ -19,11 +19,11 @@ namespace DistTestCore
public const int ChunkSize = 1024 * 1024 * 100; public const int ChunkSize = 1024 * 1024 * 100;
private static NumberSource folderNumberSource = new NumberSource(0); private static NumberSource folderNumberSource = new NumberSource(0);
private readonly Random random = new Random(); private readonly Random random = new Random();
private readonly TestLog log; private readonly BaseLog log;
private readonly string folder; private readonly string folder;
private readonly List<List<TestFile>> fileSetStack = new List<List<TestFile>>(); 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")); folder = Path.Combine(configuration.GetFileManagerFolder(), folderNumberSource.GetNextNumber().ToString("D5"));
@ -142,9 +142,9 @@ namespace DistTestCore
public class TestFile 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; this.log = log;
Filename = filename; Filename = filename;

View File

@ -1,5 +1,4 @@
using KubernetesWorkflow; using Logging;
using Logging;
using Newtonsoft.Json; using Newtonsoft.Json;
using System.Net.Http.Headers; using System.Net.Http.Headers;
using System.Net.Http.Json; using System.Net.Http.Json;
@ -11,11 +10,11 @@ namespace DistTestCore
{ {
private readonly BaseLog log; private readonly BaseLog log;
private readonly ITimeSet timeSet; private readonly ITimeSet timeSet;
private readonly RunningContainerAddress address; private readonly Address address;
private readonly string baseUrl; private readonly string baseUrl;
private readonly TimeSpan? timeoutOverride; 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.log = log;
this.timeSet = timeSet; this.timeSet = timeSet;

View File

@ -50,7 +50,7 @@ namespace DistTestCore.Marketplace
$"proofProbability: {proofProbability}, " + $"proofProbability: {proofProbability}, " +
$"duration: {Time.FormatDuration(duration)})"); $"duration: {Time.FormatDuration(duration)})");
var response = codexAccess.RequestStorage(request, contentId.Id); var response = codexAccess.Node.RequestStorage(request, contentId.Id);
if (response == "Purchasing not available") if (response == "Purchasing not available")
{ {
@ -78,7 +78,7 @@ namespace DistTestCore.Marketplace
$"maxCollateral: {maxCollateral}, " + $"maxCollateral: {maxCollateral}, " +
$"maxDuration: {Time.FormatDuration(maxDuration)})"); $"maxDuration: {Time.FormatDuration(maxDuration)})");
var response = codexAccess.SalesAvailability(request); var response = codexAccess.Node.SalesAvailability(request);
Log($"Storage successfully made available. Id: {response.id}"); Log($"Storage successfully made available. Id: {response.id}");

View File

@ -49,7 +49,7 @@ namespace DistTestCore
public CodexDebugResponse GetDebugInfo() public CodexDebugResponse GetDebugInfo()
{ {
var debugInfo = CodexAccess.GetDebugInfo(); var debugInfo = CodexAccess.Node.GetDebugInfo();
var known = string.Join(",", debugInfo.table.nodes.Select(n => n.peerId)); var known = string.Join(",", debugInfo.table.nodes.Select(n => n.peerId));
Log($"Got DebugInfo with id: '{debugInfo.id}'. This node knows: {known}"); Log($"Got DebugInfo with id: '{debugInfo.id}'. This node knows: {known}");
return debugInfo; return debugInfo;
@ -57,12 +57,12 @@ namespace DistTestCore
public CodexDebugPeerResponse GetDebugPeer(string peerId) public CodexDebugPeerResponse GetDebugPeer(string peerId)
{ {
return CodexAccess.GetDebugPeer(peerId); return CodexAccess.Node.GetDebugPeer(peerId);
} }
public CodexDebugPeerResponse GetDebugPeer(string peerId, TimeSpan timeout) public CodexDebugPeerResponse GetDebugPeer(string peerId, TimeSpan timeout)
{ {
return CodexAccess.GetDebugPeer(peerId, timeout); return CodexAccess.Node.GetDebugPeer(peerId, timeout);
} }
public ContentId UploadFile(TestFile file) public ContentId UploadFile(TestFile file)
@ -72,7 +72,7 @@ namespace DistTestCore
var logMessage = $"Uploading file {file.Describe()}..."; var logMessage = $"Uploading file {file.Describe()}...";
var response = Stopwatch.Measure(lifecycle.Log, logMessage, () => var response = Stopwatch.Measure(lifecycle.Log, logMessage, () =>
{ {
return CodexAccess.UploadFile(fileStream); return CodexAccess.Node.UploadFile(fileStream);
}); });
if (response.StartsWith(UploadFailedMessage)) if (response.StartsWith(UploadFailedMessage))
@ -101,7 +101,7 @@ namespace DistTestCore
Log($"Connecting to peer {peer.GetName()}..."); Log($"Connecting to peer {peer.GetName()}...");
var peerInfo = node.GetDebugInfo(); 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."); Assert.That(response, Is.EqualTo(SuccessfullyConnectedMessage), "Unable to connect codex nodes.");
Log($"Successfully connected to peer {peer.GetName()}."); Log($"Successfully connected to peer {peer.GetName()}.");
@ -141,7 +141,7 @@ namespace DistTestCore
using var fileStream = File.OpenWrite(file.Filename); using var fileStream = File.OpenWrite(file.Filename);
try try
{ {
using var downloadStream = CodexAccess.DownloadFile(contentId); using var downloadStream = CodexAccess.Node.DownloadFile(contentId);
downloadStream.CopyTo(fileStream); downloadStream.CopyTo(fileStream);
} }
catch catch

View File

@ -1,4 +1,6 @@
namespace KubernetesWorkflow using Utils;
namespace KubernetesWorkflow
{ {
public class RunningContainers public class RunningContainers
{ {
@ -21,7 +23,7 @@
public class RunningContainer 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; Pod = pod;
Recipe = recipe; Recipe = recipe;
@ -35,8 +37,8 @@
public RunningPod Pod { get; } public RunningPod Pod { get; }
public ContainerRecipe Recipe { get; } public ContainerRecipe Recipe { get; }
public Port[] ServicePorts { get; } public Port[] ServicePorts { get; }
public RunningContainerAddress ClusterExternalAddress { get; } public Address ClusterExternalAddress { get; }
public RunningContainerAddress ClusterInternalAddress { get; } public Address ClusterInternalAddress { get; }
private string GetContainerName(ContainerRecipe recipe, StartupConfig startupConfig) 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; }
}
} }

View File

@ -1,4 +1,5 @@
using Logging; using Logging;
using Utils;
namespace KubernetesWorkflow namespace KubernetesWorkflow
{ {
@ -87,20 +88,20 @@ namespace KubernetesWorkflow
}).ToArray(); }).ToArray();
} }
private RunningContainerAddress GetContainerExternalAddress(RunningPod pod, Port[] servicePorts) private Address GetContainerExternalAddress(RunningPod pod, Port[] servicePorts)
{ {
return new RunningContainerAddress( return new Address(
pod.Cluster.HostAddress, pod.Cluster.HostAddress,
GetServicePort(servicePorts)); GetServicePort(servicePorts));
} }
private RunningContainerAddress GetContainerInternalAddress(ContainerRecipe recipe) private Address GetContainerInternalAddress(ContainerRecipe recipe)
{ {
var serviceName = "service-" + numberSource.WorkflowNumber; var serviceName = "service-" + numberSource.WorkflowNumber;
var namespaceName = cluster.Configuration.K8sNamespacePrefix + testNamespace; var namespaceName = cluster.Configuration.K8sNamespacePrefix + testNamespace;
var port = GetInternalPort(recipe); var port = GetInternalPort(recipe);
return new RunningContainerAddress( return new Address(
$"http://{serviceName}.{namespaceName}.svc.cluster.local", $"http://{serviceName}.{namespaceName}.svc.cluster.local",
port); port);
} }

14
Utils/Address.cs Normal file
View File

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

View File

@ -17,6 +17,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Logging", "Logging\Logging.
EndProject EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NethereumWorkflow", "Nethereum\NethereumWorkflow.csproj", "{D6C3555E-D52D-4993-A87B-71AB650398FD}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NethereumWorkflow", "Nethereum\NethereumWorkflow.csproj", "{D6C3555E-D52D-4993-A87B-71AB650398FD}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ContinuousTests", "ContinuousTests\ContinuousTests.csproj", "{025B7074-0A09-4FCC-9BB9-03AE2A961EA1}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU 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}.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.ActiveCfg = Release|Any CPU
{D6C3555E-D52D-4993-A87B-71AB650398FD}.Release|Any CPU.Build.0 = 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 EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE