diff --git a/ContinuousTests/Configuration.cs b/ContinuousTests/Configuration.cs new file mode 100644 index 0000000..5ccb845 --- /dev/null +++ b/ContinuousTests/Configuration.cs @@ -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(); + 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(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."); + } + } + } +} diff --git a/ContinuousTests/ContinuousTestRunner.cs b/ContinuousTests/ContinuousTestRunner.cs new file mode 100644 index 0000000..caa9fbf --- /dev/null +++ b/ContinuousTests/ContinuousTestRunner.cs @@ -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(); + 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; + } + } +} diff --git a/ContinuousTests/ContinuousTests.csproj b/ContinuousTests/ContinuousTests.csproj new file mode 100644 index 0000000..593bf86 --- /dev/null +++ b/ContinuousTests/ContinuousTests.csproj @@ -0,0 +1,19 @@ + + + + Exe + net7.0 + enable + enable + + + + + + + + + + + + diff --git a/ContinuousTests/IContinuousTest.cs b/ContinuousTests/IContinuousTest.cs new file mode 100644 index 0000000..0374ffd --- /dev/null +++ b/ContinuousTests/IContinuousTest.cs @@ -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(); + } +} diff --git a/ContinuousTests/Program.cs b/ContinuousTests/Program.cs new file mode 100644 index 0000000..d3fcb1d --- /dev/null +++ b/ContinuousTests/Program.cs @@ -0,0 +1,10 @@ +using ContinuousTests; + +public class Program +{ + public static void Main(string[] args) + { + var runner = new ContinuousTestRunner(); + runner.Run(); + } +} diff --git a/ContinuousTests/TestFinder.cs b/ContinuousTests/TestFinder.cs new file mode 100644 index 0000000..349e957 --- /dev/null +++ b/ContinuousTests/TestFinder.cs @@ -0,0 +1,24 @@ +namespace ContinuousTests +{ + public class TestFinder + { + private readonly List testList = new List(); + + 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!); + } + } + } +} diff --git a/ContinuousTests/TestRun.cs b/ContinuousTests/TestRun.cs new file mode 100644 index 0000000..9138744 --- /dev/null +++ b/ContinuousTests/TestRun.cs @@ -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(List remainingItems) + { + var i = random.Next(0, remainingItems.Count); + var result = remainingItems[i]; + remainingItems.RemoveAt(i); + return result; + } + } +} diff --git a/DistTestCore/Codex/CodexAccess.cs b/DistTestCore/Codex/CodexAccess.cs index 4d6f1da..ee0e2a5 100644 --- a/DistTestCore/Codex/CodexAccess.cs +++ b/DistTestCore/Codex/CodexAccess.cs @@ -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("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(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("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(); - public SwitchPeerResponse[] switchPeers { get; set; } = Array.Empty(); - 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(); - } - - 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(); - } - - 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;} } } diff --git a/DistTestCore/Codex/CodexNode.cs b/DistTestCore/Codex/CodexNode.cs new file mode 100644 index 0000000..510c2fb --- /dev/null +++ b/DistTestCore/Codex/CodexNode.cs @@ -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("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(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("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(); + public SwitchPeerResponse[] switchPeers { get; set; } = Array.Empty(); + 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(); + } + + 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(); + } + + 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; } + } +} diff --git a/DistTestCore/Configuration.cs b/DistTestCore/Configuration.cs index 8f39381..af76127 100644 --- a/DistTestCore/Configuration.cs +++ b/DistTestCore/Configuration.cs @@ -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) { diff --git a/DistTestCore/FileManager.cs b/DistTestCore/FileManager.cs index 5ebae09..8d8c55f 100644 --- a/DistTestCore/FileManager.cs +++ b/DistTestCore/FileManager.cs @@ -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> fileSetStack = new List>(); - 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; diff --git a/DistTestCore/Http.cs b/DistTestCore/Http.cs index 30bf48c..2aa5085 100644 --- a/DistTestCore/Http.cs +++ b/DistTestCore/Http.cs @@ -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; diff --git a/DistTestCore/Marketplace/MarketplaceAccess.cs b/DistTestCore/Marketplace/MarketplaceAccess.cs index 7bac8b2..29730a6 100644 --- a/DistTestCore/Marketplace/MarketplaceAccess.cs +++ b/DistTestCore/Marketplace/MarketplaceAccess.cs @@ -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}"); diff --git a/DistTestCore/OnlineCodexNode.cs b/DistTestCore/OnlineCodexNode.cs index d53f2c2..adc7dfc 100644 --- a/DistTestCore/OnlineCodexNode.cs +++ b/DistTestCore/OnlineCodexNode.cs @@ -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 diff --git a/KubernetesWorkflow/RunningContainers.cs b/KubernetesWorkflow/RunningContainers.cs index 0b7b3fd..6e2224d 100644 --- a/KubernetesWorkflow/RunningContainers.cs +++ b/KubernetesWorkflow/RunningContainers.cs @@ -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; } - } } diff --git a/KubernetesWorkflow/StartupWorkflow.cs b/KubernetesWorkflow/StartupWorkflow.cs index 59fe617..8a223cf 100644 --- a/KubernetesWorkflow/StartupWorkflow.cs +++ b/KubernetesWorkflow/StartupWorkflow.cs @@ -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); } diff --git a/Utils/Address.cs b/Utils/Address.cs new file mode 100644 index 0000000..510afeb --- /dev/null +++ b/Utils/Address.cs @@ -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; } + } +} diff --git a/cs-codex-dist-testing.sln b/cs-codex-dist-testing.sln index 4bc64fc..7946ff4 100644 --- a/cs-codex-dist-testing.sln +++ b/cs-codex-dist-testing.sln @@ -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