Merge branch 'feature/cluster-internal-and-external-container-addresses'
This commit is contained in:
commit
e8d99b83ff
|
@ -32,6 +32,11 @@ namespace DistTestCore
|
|||
lifecycle.Log.Log($"{GetClassName()} {msg}");
|
||||
}
|
||||
|
||||
protected void Debug(string msg)
|
||||
{
|
||||
lifecycle.Log.Debug($"{GetClassName()} {msg}", 1);
|
||||
}
|
||||
|
||||
private string GetClassName()
|
||||
{
|
||||
return $"({GetType().Name})";
|
||||
|
|
|
@ -1,17 +1,14 @@
|
|||
using KubernetesWorkflow;
|
||||
using Logging;
|
||||
|
||||
namespace DistTestCore.Codex
|
||||
{
|
||||
public class CodexAccess
|
||||
{
|
||||
private readonly BaseLog log;
|
||||
private readonly ITimeSet timeSet;
|
||||
private readonly TestLifecycle lifecycle;
|
||||
|
||||
public CodexAccess(BaseLog log, ITimeSet timeSet, RunningContainer runningContainer)
|
||||
public CodexAccess(TestLifecycle lifecycle, RunningContainer runningContainer)
|
||||
{
|
||||
this.log = log;
|
||||
this.timeSet = timeSet;
|
||||
this.lifecycle = lifecycle;
|
||||
Container = runningContainer;
|
||||
}
|
||||
|
||||
|
@ -79,21 +76,20 @@ namespace DistTestCore.Codex
|
|||
|
||||
var nodePeerId = debugInfo.id;
|
||||
var nodeName = Container.Name;
|
||||
log.AddStringReplace(nodePeerId, nodeName);
|
||||
log.AddStringReplace(debugInfo.table.localNode.nodeId, nodeName);
|
||||
lifecycle.Log.AddStringReplace(nodePeerId, nodeName);
|
||||
lifecycle.Log.AddStringReplace(debugInfo.table.localNode.nodeId, nodeName);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.Error($"Failed to start codex node: {e}. Test infra failure.");
|
||||
lifecycle.Log.Error($"Failed to start codex node: {e}. Test infra failure.");
|
||||
throw new InvalidOperationException($"Failed to start codex node. Test infra failure.", e);
|
||||
}
|
||||
}
|
||||
|
||||
private Http Http(TimeSpan? timeoutOverride = null)
|
||||
{
|
||||
var ip = Container.Pod.Cluster.HostAddress;
|
||||
var port = Container.ServicePorts[0].Number;
|
||||
return new Http(log, timeSet, ip, port, baseUrl: "/api/codex/v1", timeoutOverride);
|
||||
var address = lifecycle.Configuration.GetAddress(Container);
|
||||
return new Http(lifecycle.Log, lifecycle.TimeSet, address, baseUrl: "/api/codex/v1", timeoutOverride);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using System.Runtime.InteropServices;
|
||||
using DistTestCore.Marketplace;
|
||||
using DistTestCore.Marketplace;
|
||||
using KubernetesWorkflow;
|
||||
|
||||
namespace DistTestCore.Codex
|
||||
|
@ -56,6 +55,7 @@ namespace DistTestCore.Codex
|
|||
AddEnvVar("ETH_PROVIDER", $"ws://{ip}:{port}");
|
||||
AddEnvVar("ETH_ACCOUNT", companionNodeAccount.Account);
|
||||
AddEnvVar("ETH_MARKETPLACE_ADDRESS", gethConfig.MarketplaceNetwork.Marketplace.Address);
|
||||
AddEnvVar("PERSISTENCE", "1");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -69,7 +69,7 @@ namespace DistTestCore
|
|||
|
||||
private OnlineCodexNode CreateOnlineCodexNode(RunningContainer c, ICodexNodeFactory factory)
|
||||
{
|
||||
var access = new CodexAccess(lifecycle.Log, lifecycle.TimeSet, c);
|
||||
var access = new CodexAccess(lifecycle, c);
|
||||
return factory.CreateOnlineCodexNode(access, this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,5 +34,25 @@ namespace DistTestCore
|
|||
{
|
||||
return CodexLogLevel.Trace;
|
||||
}
|
||||
|
||||
public TestRunnerLocation GetTestRunnerLocation()
|
||||
{
|
||||
return TestRunnerLocation.ExternalToCluster;
|
||||
}
|
||||
|
||||
public RunningContainerAddress GetAddress(RunningContainer container)
|
||||
{
|
||||
if (GetTestRunnerLocation() == TestRunnerLocation.InternalToCluster)
|
||||
{
|
||||
return container.ClusterInternalAddress;
|
||||
}
|
||||
return container.ClusterExternalAddress;
|
||||
}
|
||||
}
|
||||
|
||||
public enum TestRunnerLocation
|
||||
{
|
||||
ExternalToCluster,
|
||||
InternalToCluster,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ namespace DistTestCore
|
|||
|
||||
private void TransferInitialBalance(MarketplaceNetwork marketplaceNetwork, MarketplaceInitialConfig marketplaceConfig, GethCompanionNodeInfo companionNode)
|
||||
{
|
||||
var interaction = marketplaceNetwork.StartInteraction(lifecycle.Log);
|
||||
var interaction = marketplaceNetwork.StartInteraction(lifecycle);
|
||||
var tokenAddress = marketplaceNetwork.Marketplace.TokenAddress;
|
||||
|
||||
var accounts = companionNode.Accounts.Select(a => a.Account).ToArray();
|
||||
|
@ -52,7 +52,7 @@ namespace DistTestCore
|
|||
|
||||
private IMarketplaceAccessFactory CreateMarketplaceAccessFactory(MarketplaceNetwork marketplaceNetwork)
|
||||
{
|
||||
return new GethMarketplaceAccessFactory(lifecycle.Log, marketplaceNetwork);
|
||||
return new GethMarketplaceAccessFactory(lifecycle, marketplaceNetwork);
|
||||
}
|
||||
|
||||
private GethCompanionNodeInfo StartCompanionNode(CodexSetup codexSetup, MarketplaceNetwork marketplaceNetwork)
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
using NUnit.Framework.Constraints;
|
||||
using NUnit.Framework;
|
||||
using Utils;
|
||||
|
||||
namespace DistTestCore.Helpers
|
||||
{
|
||||
public static class AssertHelpers
|
||||
{
|
||||
public static void RetryAssert<T>(IResolveConstraint constraint, Func<T> actual, string message)
|
||||
{
|
||||
try
|
||||
{
|
||||
var c = constraint.Resolve();
|
||||
Time.WaitUntil(() => c.ApplyTo(actual()).IsSuccess);
|
||||
}
|
||||
catch (TimeoutException)
|
||||
{
|
||||
Assert.That(actual(), constraint, message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,4 +1,5 @@
|
|||
using Logging;
|
||||
using KubernetesWorkflow;
|
||||
using Logging;
|
||||
using Newtonsoft.Json;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Net.Http.Json;
|
||||
|
@ -10,17 +11,15 @@ namespace DistTestCore
|
|||
{
|
||||
private readonly BaseLog log;
|
||||
private readonly ITimeSet timeSet;
|
||||
private readonly string host;
|
||||
private readonly int port;
|
||||
private readonly RunningContainerAddress address;
|
||||
private readonly string baseUrl;
|
||||
private readonly TimeSpan? timeoutOverride;
|
||||
|
||||
public Http(BaseLog log, ITimeSet timeSet, string host, int port, string baseUrl, TimeSpan? timeoutOverride = null)
|
||||
public Http(BaseLog log, ITimeSet timeSet, RunningContainerAddress address, string baseUrl, TimeSpan? timeoutOverride = null)
|
||||
{
|
||||
this.log = log;
|
||||
this.timeSet = timeSet;
|
||||
this.host = host;
|
||||
this.port = port;
|
||||
this.address = address;
|
||||
this.baseUrl = baseUrl;
|
||||
this.timeoutOverride = timeoutOverride;
|
||||
if (!this.baseUrl.StartsWith("/")) this.baseUrl = "/" + this.baseUrl;
|
||||
|
@ -110,7 +109,7 @@ namespace DistTestCore
|
|||
|
||||
private string GetUrl()
|
||||
{
|
||||
return $"{host}:{port}{baseUrl}";
|
||||
return $"{address.Host}:{address.Port}{baseUrl}";
|
||||
}
|
||||
|
||||
private void Log(string url, string message)
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace DistTestCore.Marketplace
|
|||
#if Arm64
|
||||
public const string DockerImage = "emizzle/codex-contracts-deployment:latest";
|
||||
#else
|
||||
public const string DockerImage = "thatbenbierens/codex-contracts-deployment:nomint";
|
||||
public const string DockerImage = "thatbenbierens/codex-contracts-deployment:nomint2";
|
||||
#endif
|
||||
public const string MarketplaceAddressFilename = "/usr/app/deployments/codexdisttestnetwork/Marketplace.json";
|
||||
public const string MarketplaceArtifactFilename = "/usr/app/artifacts/contracts/Marketplace.sol/Marketplace.json";
|
||||
|
|
|
@ -5,7 +5,6 @@ namespace DistTestCore.Marketplace
|
|||
{
|
||||
public class CodexContractsStarter : BaseStarter
|
||||
{
|
||||
private const string readyString = "Done! Sleeping indefinitely...";
|
||||
|
||||
public CodexContractsStarter(TestLifecycle lifecycle, WorkflowCreator workflowCreator)
|
||||
: base(lifecycle, workflowCreator)
|
||||
|
@ -14,7 +13,7 @@ namespace DistTestCore.Marketplace
|
|||
|
||||
public MarketplaceInfo Start(GethBootstrapNodeInfo bootstrapNode)
|
||||
{
|
||||
LogStart("Deploying Codex contracts...");
|
||||
LogStart("Deploying Codex Marketplace...");
|
||||
|
||||
var workflow = workflowCreator.CreateWorkflow();
|
||||
var startupConfig = CreateStartupConfig(bootstrapNode.RunningContainers.Containers[0]);
|
||||
|
@ -25,26 +24,27 @@ namespace DistTestCore.Marketplace
|
|||
|
||||
WaitUntil(() =>
|
||||
{
|
||||
var logHandler = new ContractsReadyLogHandler(readyString);
|
||||
var logHandler = new ContractsReadyLogHandler(Debug);
|
||||
workflow.DownloadContainerLog(container, logHandler);
|
||||
return logHandler.Found;
|
||||
});
|
||||
Log("Contracts deployed. Extracting addresses...");
|
||||
|
||||
var extractor = new ContainerInfoExtractor(lifecycle.Log, workflow, container);
|
||||
var marketplaceAddress = extractor.ExtractMarketplaceAddress();
|
||||
var abi = extractor.ExtractMarketplaceAbi();
|
||||
|
||||
var interaction = bootstrapNode.StartInteraction(lifecycle.Log);
|
||||
var interaction = bootstrapNode.StartInteraction(lifecycle);
|
||||
var tokenAddress = interaction.GetTokenAddress(marketplaceAddress);
|
||||
|
||||
LogEnd("Contracts deployed.");
|
||||
LogEnd("Extract completed. Marketplace deployed.");
|
||||
|
||||
return new MarketplaceInfo(marketplaceAddress, abi, tokenAddress);
|
||||
}
|
||||
|
||||
private void WaitUntil(Func<bool> predicate)
|
||||
{
|
||||
Time.WaitUntil(predicate, TimeSpan.FromMinutes(2), TimeSpan.FromSeconds(1));
|
||||
Time.WaitUntil(predicate, TimeSpan.FromMinutes(3), TimeSpan.FromSeconds(2));
|
||||
}
|
||||
|
||||
private StartupConfig CreateStartupConfig(RunningContainer bootstrapContainer)
|
||||
|
@ -72,18 +72,27 @@ namespace DistTestCore.Marketplace
|
|||
|
||||
public class ContractsReadyLogHandler : LogHandler
|
||||
{
|
||||
private readonly string targetString;
|
||||
// Log should contain 'Compiled 15 Solidity files successfully' at some point.
|
||||
private const string RequiredCompiledString = "Solidity files successfully";
|
||||
// When script is done, it prints the ready-string.
|
||||
private const string ReadyString = "Done! Sleeping indefinitely...";
|
||||
private readonly Action<string> debug;
|
||||
|
||||
public ContractsReadyLogHandler(string targetString)
|
||||
public ContractsReadyLogHandler(Action<string> debug)
|
||||
{
|
||||
this.targetString = targetString;
|
||||
this.debug = debug;
|
||||
debug($"Looking for '{RequiredCompiledString}' and '{ReadyString}' in container logs...");
|
||||
}
|
||||
|
||||
public bool SeenCompileString { get; private set; }
|
||||
public bool Found { get; private set; }
|
||||
|
||||
protected override void ProcessLine(string line)
|
||||
{
|
||||
if (line.Contains(targetString)) Found = true;
|
||||
debug(line);
|
||||
if (line.Contains(RequiredCompiledString)) SeenCompileString = true;
|
||||
|
||||
if (SeenCompileString && line.Contains(ReadyString)) Found = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -79,7 +79,7 @@ namespace DistTestCore.Marketplace
|
|||
|
||||
private string FetchPubKey()
|
||||
{
|
||||
var enodeFinder = new PubKeyFinder();
|
||||
var enodeFinder = new PubKeyFinder(s => log.Debug(s));
|
||||
workflow.DownloadContainerLog(container, enodeFinder);
|
||||
return enodeFinder.GetPubKey();
|
||||
}
|
||||
|
@ -103,15 +103,24 @@ namespace DistTestCore.Marketplace
|
|||
{
|
||||
private const string openTag = "self=enode://";
|
||||
private const string openTagQuote = "self=\"enode://";
|
||||
private readonly Action<string> debug;
|
||||
private string pubKey = string.Empty;
|
||||
|
||||
public PubKeyFinder(Action<string> debug)
|
||||
{
|
||||
this.debug = debug;
|
||||
debug($"Looking for '{openTag}' in container logs...");
|
||||
}
|
||||
|
||||
public string GetPubKey()
|
||||
{
|
||||
if (string.IsNullOrEmpty(pubKey)) throw new Exception("Not found yet exception.");
|
||||
return pubKey;
|
||||
}
|
||||
|
||||
protected override void ProcessLine(string line)
|
||||
{
|
||||
debug(line);
|
||||
if (line.Contains(openTag))
|
||||
{
|
||||
ExtractPubKey(openTag, line);
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using KubernetesWorkflow;
|
||||
using Logging;
|
||||
using NethereumWorkflow;
|
||||
|
||||
namespace DistTestCore.Marketplace
|
||||
|
@ -21,13 +20,12 @@ namespace DistTestCore.Marketplace
|
|||
public string PubKey { get; }
|
||||
public Port DiscoveryPort { get; }
|
||||
|
||||
public NethereumInteraction StartInteraction(BaseLog log)
|
||||
public NethereumInteraction StartInteraction(TestLifecycle lifecycle)
|
||||
{
|
||||
var ip = RunningContainers.RunningPod.Cluster.HostAddress;
|
||||
var port = RunningContainers.Containers[0].ServicePorts[0].Number;
|
||||
var address = lifecycle.Configuration.GetAddress(RunningContainers.Containers[0]);
|
||||
var account = Account;
|
||||
|
||||
var creator = new NethereumInteractionCreator(log, ip, port, account.PrivateKey);
|
||||
var creator = new NethereumInteractionCreator(lifecycle.Log, address.Host, address.Port, account.PrivateKey);
|
||||
return creator.CreateWorkflow();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using KubernetesWorkflow;
|
||||
using Logging;
|
||||
using NethereumWorkflow;
|
||||
|
||||
namespace DistTestCore.Marketplace
|
||||
|
@ -15,13 +14,12 @@ namespace DistTestCore.Marketplace
|
|||
public RunningContainer RunningContainer { get; }
|
||||
public GethAccount[] Accounts { get; }
|
||||
|
||||
public NethereumInteraction StartInteraction(BaseLog log, GethAccount account)
|
||||
public NethereumInteraction StartInteraction(TestLifecycle lifecycle, GethAccount account)
|
||||
{
|
||||
var ip = RunningContainer.Pod.Cluster.HostAddress;
|
||||
var port = RunningContainer.ServicePorts[0].Number;
|
||||
var address = lifecycle.Configuration.GetAddress(RunningContainer);
|
||||
var privateKey = account.PrivateKey;
|
||||
|
||||
var creator = new NethereumInteractionCreator(log, ip, port, privateKey);
|
||||
var creator = new NethereumInteractionCreator(lifecycle.Log, address.Host, address.Port, privateKey);
|
||||
return creator.CreateWorkflow();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -50,7 +50,7 @@ namespace DistTestCore.Marketplace
|
|||
{
|
||||
Time.WaitUntil(() =>
|
||||
{
|
||||
var interaction = node.StartInteraction(lifecycle.Log, node.Accounts.First());
|
||||
var interaction = node.StartInteraction(lifecycle, node.Accounts.First());
|
||||
return interaction.IsSynced(marketplace.Marketplace.Address, marketplace.Marketplace.Abi);
|
||||
}, TimeSpan.FromMinutes(1), TimeSpan.FromSeconds(3));
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
using DistTestCore.Codex;
|
||||
using Logging;
|
||||
using DistTestCore.Helpers;
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework.Constraints;
|
||||
using System.Numerics;
|
||||
|
@ -17,14 +17,14 @@ namespace DistTestCore.Marketplace
|
|||
|
||||
public class MarketplaceAccess : IMarketplaceAccess
|
||||
{
|
||||
private readonly TestLog log;
|
||||
private readonly TestLifecycle lifecycle;
|
||||
private readonly MarketplaceNetwork marketplaceNetwork;
|
||||
private readonly GethAccount account;
|
||||
private readonly CodexAccess codexAccess;
|
||||
|
||||
public MarketplaceAccess(TestLog log, MarketplaceNetwork marketplaceNetwork, GethAccount account, CodexAccess codexAccess)
|
||||
public MarketplaceAccess(TestLifecycle lifecycle, MarketplaceNetwork marketplaceNetwork, GethAccount account, CodexAccess codexAccess)
|
||||
{
|
||||
this.log = log;
|
||||
this.lifecycle = lifecycle;
|
||||
this.marketplaceNetwork = marketplaceNetwork;
|
||||
this.account = account;
|
||||
this.codexAccess = codexAccess;
|
||||
|
@ -98,12 +98,12 @@ namespace DistTestCore.Marketplace
|
|||
|
||||
public void AssertThatBalance(IResolveConstraint constraint, string message = "")
|
||||
{
|
||||
Assert.That(GetBalance(), constraint, message);
|
||||
AssertHelpers.RetryAssert(constraint, GetBalance, message);
|
||||
}
|
||||
|
||||
public TestToken GetBalance()
|
||||
{
|
||||
var interaction = marketplaceNetwork.StartInteraction(log);
|
||||
var interaction = marketplaceNetwork.StartInteraction(lifecycle);
|
||||
var amount = interaction.GetBalance(marketplaceNetwork.Marketplace.TokenAddress, account.Account);
|
||||
var balance = new TestToken(amount);
|
||||
|
||||
|
@ -114,7 +114,7 @@ namespace DistTestCore.Marketplace
|
|||
|
||||
private void Log(string msg)
|
||||
{
|
||||
log.Log($"{codexAccess.Container.Name} {msg}");
|
||||
lifecycle.Log.Log($"{codexAccess.Container.Name} {msg}");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,19 +18,19 @@ namespace DistTestCore.Marketplace
|
|||
|
||||
public class GethMarketplaceAccessFactory : IMarketplaceAccessFactory
|
||||
{
|
||||
private readonly TestLog log;
|
||||
private readonly TestLifecycle lifecycle;
|
||||
private readonly MarketplaceNetwork marketplaceNetwork;
|
||||
|
||||
public GethMarketplaceAccessFactory(TestLog log, MarketplaceNetwork marketplaceNetwork)
|
||||
public GethMarketplaceAccessFactory(TestLifecycle lifecycle, MarketplaceNetwork marketplaceNetwork)
|
||||
{
|
||||
this.log = log;
|
||||
this.lifecycle = lifecycle;
|
||||
this.marketplaceNetwork = marketplaceNetwork;
|
||||
}
|
||||
|
||||
public IMarketplaceAccess CreateMarketplaceAccess(CodexAccess access)
|
||||
{
|
||||
var companionNode = GetGethCompanionNode(access);
|
||||
return new MarketplaceAccess(log, marketplaceNetwork, companionNode, access);
|
||||
return new MarketplaceAccess(lifecycle, marketplaceNetwork, companionNode, access);
|
||||
}
|
||||
|
||||
private GethAccount GetGethCompanionNode(CodexAccess access)
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using Logging;
|
||||
using NethereumWorkflow;
|
||||
using NethereumWorkflow;
|
||||
|
||||
namespace DistTestCore.Marketplace
|
||||
{
|
||||
|
@ -14,9 +13,9 @@ namespace DistTestCore.Marketplace
|
|||
public GethBootstrapNodeInfo Bootstrap { get; }
|
||||
public MarketplaceInfo Marketplace { get; }
|
||||
|
||||
public NethereumInteraction StartInteraction(BaseLog log)
|
||||
public NethereumInteraction StartInteraction(TestLifecycle lifecycle)
|
||||
{
|
||||
return Bootstrap.StartInteraction(log);
|
||||
return Bootstrap.StartInteraction(lifecycle);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using KubernetesWorkflow;
|
||||
using DistTestCore.Helpers;
|
||||
using KubernetesWorkflow;
|
||||
using Logging;
|
||||
using NUnit.Framework;
|
||||
using NUnit.Framework.Constraints;
|
||||
|
@ -28,12 +29,14 @@ namespace DistTestCore.Metrics
|
|||
|
||||
public void AssertThat(string metricName, IResolveConstraint constraint, string message = "")
|
||||
{
|
||||
var metricSet = GetMetricWithTimeout(metricName);
|
||||
var metricValue = metricSet.Values[0].Value;
|
||||
AssertHelpers.RetryAssert(constraint, () =>
|
||||
{
|
||||
var metricSet = GetMetricWithTimeout(metricName);
|
||||
var metricValue = metricSet.Values[0].Value;
|
||||
|
||||
log.Log($"{node.Name} metric '{metricName}' = {metricValue}");
|
||||
|
||||
Assert.That(metricValue, constraint, message);
|
||||
log.Log($"{node.Name} metric '{metricName}' = {metricValue}");
|
||||
return metricValue;
|
||||
}, message);
|
||||
}
|
||||
|
||||
public Metrics? GetAllMetrics()
|
||||
|
|
|
@ -28,7 +28,7 @@ namespace DistTestCore.Metrics
|
|||
|
||||
public IMetricsAccess CreateMetricsAccess(RunningContainer codexContainer)
|
||||
{
|
||||
var query = new MetricsQuery(lifecycle.Log, lifecycle.TimeSet, prometheusContainer);
|
||||
var query = new MetricsQuery(lifecycle, prometheusContainer);
|
||||
return new MetricsAccess(lifecycle.Log, lifecycle.TimeSet, query, codexContainer);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
using DistTestCore.Codex;
|
||||
using KubernetesWorkflow;
|
||||
using Logging;
|
||||
using System.Globalization;
|
||||
|
||||
namespace DistTestCore.Metrics
|
||||
|
@ -9,15 +8,16 @@ namespace DistTestCore.Metrics
|
|||
{
|
||||
private readonly Http http;
|
||||
|
||||
public MetricsQuery(BaseLog log, ITimeSet timeSet, RunningContainers runningContainers)
|
||||
public MetricsQuery(TestLifecycle lifecycle, RunningContainers runningContainers)
|
||||
{
|
||||
RunningContainers = runningContainers;
|
||||
|
||||
var address = lifecycle.Configuration.GetAddress(runningContainers.Containers[0]);
|
||||
|
||||
http = new Http(
|
||||
log,
|
||||
timeSet,
|
||||
runningContainers.RunningPod.Cluster.HostAddress,
|
||||
runningContainers.Containers[0].ServicePorts[0].Number,
|
||||
lifecycle.Log,
|
||||
lifecycle.TimeSet,
|
||||
address,
|
||||
"api/v1");
|
||||
}
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ namespace DistTestCore
|
|||
public TestLifecycle(TestLog log, Configuration configuration, ITimeSet timeSet)
|
||||
{
|
||||
Log = log;
|
||||
Configuration = configuration;
|
||||
TimeSet = timeSet;
|
||||
workflowCreator = new WorkflowCreator(log, configuration.GetK8sConfiguration(timeSet));
|
||||
|
||||
|
@ -24,6 +25,7 @@ namespace DistTestCore
|
|||
}
|
||||
|
||||
public TestLog Log { get; }
|
||||
public Configuration Configuration { get; }
|
||||
public ITimeSet TimeSet { get; }
|
||||
public FileManager FileManager { get; }
|
||||
public CodexStarter CodexStarter { get; }
|
||||
|
|
|
@ -22,7 +22,6 @@ namespace KubernetesWorkflow
|
|||
client = new K8sClient(cluster.GetK8sClientConfig());
|
||||
|
||||
K8sTestNamespace = cluster.Configuration.K8sNamespacePrefix + testNamespace;
|
||||
log.Debug($"Test namespace: '{K8sTestNamespace}'");
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
@ -60,10 +59,15 @@ namespace KubernetesWorkflow
|
|||
|
||||
public string ExecuteCommand(RunningPod pod, string containerName, string command, params string[] args)
|
||||
{
|
||||
log.Debug($"{containerName}: {command} ({string.Join(",", args)})");
|
||||
var cmdAndArgs = $"{containerName}: {command} ({string.Join(",", args)})";
|
||||
log.Debug(cmdAndArgs);
|
||||
|
||||
var runner = new CommandRunner(client, K8sTestNamespace, pod, containerName, command, args);
|
||||
runner.Run();
|
||||
return runner.GetStdOut();
|
||||
var result = runner.GetStdOut();
|
||||
|
||||
log.Debug($"{cmdAndArgs} = '{result}'");
|
||||
return result;
|
||||
}
|
||||
|
||||
public void DeleteAllResources()
|
||||
|
|
|
@ -21,18 +21,22 @@
|
|||
|
||||
public class RunningContainer
|
||||
{
|
||||
public RunningContainer(RunningPod pod, ContainerRecipe recipe, Port[] servicePorts, StartupConfig startupConfig)
|
||||
public RunningContainer(RunningPod pod, ContainerRecipe recipe, Port[] servicePorts, StartupConfig startupConfig, RunningContainerAddress clusterExternalAddress, RunningContainerAddress clusterInternalAddress)
|
||||
{
|
||||
Pod = pod;
|
||||
Recipe = recipe;
|
||||
ServicePorts = servicePorts;
|
||||
Name = GetContainerName(recipe, startupConfig);
|
||||
ClusterExternalAddress = clusterExternalAddress;
|
||||
ClusterInternalAddress = clusterInternalAddress;
|
||||
}
|
||||
|
||||
public string Name { get; }
|
||||
public RunningPod Pod { get; }
|
||||
public ContainerRecipe Recipe { get; }
|
||||
public Port[] ServicePorts { get; }
|
||||
public RunningContainerAddress ClusterExternalAddress { get; }
|
||||
public RunningContainerAddress ClusterInternalAddress { get; }
|
||||
|
||||
private string GetContainerName(ContainerRecipe recipe, StartupConfig startupConfig)
|
||||
{
|
||||
|
@ -46,4 +50,16 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class RunningContainerAddress
|
||||
{
|
||||
public RunningContainerAddress(string host, int port)
|
||||
{
|
||||
Host = host;
|
||||
Port = port;
|
||||
}
|
||||
|
||||
public string Host { get; }
|
||||
public int Port { get; }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,10 +80,43 @@ namespace KubernetesWorkflow
|
|||
var servicePorts = runningPod.GetServicePortsForContainerRecipe(r);
|
||||
log.Debug($"{r} -> service ports: {string.Join(",", servicePorts.Select(p => p.Number))}");
|
||||
|
||||
return new RunningContainer(runningPod, r, servicePorts, startupConfig);
|
||||
return new RunningContainer(runningPod, r, servicePorts, startupConfig,
|
||||
GetContainerExternalAddress(runningPod, servicePorts),
|
||||
GetContainerInternalAddress(r));
|
||||
|
||||
}).ToArray();
|
||||
}
|
||||
|
||||
private RunningContainerAddress GetContainerExternalAddress(RunningPod pod, Port[] servicePorts)
|
||||
{
|
||||
return new RunningContainerAddress(
|
||||
pod.Cluster.HostAddress,
|
||||
GetServicePort(servicePorts));
|
||||
}
|
||||
|
||||
private RunningContainerAddress GetContainerInternalAddress(ContainerRecipe recipe)
|
||||
{
|
||||
var serviceName = "service-" + numberSource.WorkflowNumber;
|
||||
var namespaceName = cluster.Configuration.K8sNamespacePrefix + testNamespace;
|
||||
var port = GetInternalPort(recipe);
|
||||
|
||||
return new RunningContainerAddress(
|
||||
$"http://{serviceName}.{namespaceName}.svc.cluster.local",
|
||||
port);
|
||||
}
|
||||
|
||||
private static int GetServicePort(Port[] servicePorts)
|
||||
{
|
||||
if (servicePorts.Any()) return servicePorts.First().Number;
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static int GetInternalPort(ContainerRecipe recipe)
|
||||
{
|
||||
if (recipe.ExposedPorts.Any()) return recipe.ExposedPorts.First().Number;
|
||||
return 0;
|
||||
}
|
||||
|
||||
private ContainerRecipe[] CreateRecipes(int numberOfContainers, ContainerRecipeFactory recipeFactory, StartupConfig startupConfig)
|
||||
{
|
||||
log.Debug();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
using DistTestCore;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Tests.ParallelTests
|
||||
namespace TestsLong.BasicTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class DownloadTests : DistTest
|
||||
|
@ -23,7 +23,7 @@ namespace Tests.ParallelTests
|
|||
var testFile = GenerateTestFile(filesizeMb.MB());
|
||||
var contentId = host.UploadFile(testFile);
|
||||
var list = new List<Task<TestFile?>>();
|
||||
|
||||
|
||||
foreach (var node in group)
|
||||
{
|
||||
list.Add(Task.Run(() => { return node.DownloadContent(contentId); }));
|
|
@ -1,7 +1,7 @@
|
|||
using DistTestCore;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace Tests.ParallelTests
|
||||
namespace TestsLong.BasicTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class UploadTests : DistTest
|
|
@ -131,7 +131,7 @@ namespace NethereumWorkflow
|
|||
public class MintTokensFunction : FunctionMessage
|
||||
{
|
||||
[Parameter("address", "holder", 1)]
|
||||
public string Holder { get; set; }
|
||||
public string Holder { get; set; } = string.Empty;
|
||||
|
||||
[Parameter("uint256", "amount", 2)]
|
||||
public BigInteger Amount { get; set; }
|
||||
|
@ -141,6 +141,6 @@ namespace NethereumWorkflow
|
|||
public class GetTokenBalanceFunction : FunctionMessage
|
||||
{
|
||||
[Parameter("address", "owner", 1)]
|
||||
public string Owner { get; set; }
|
||||
public string Owner { get; set; } = string.Empty;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace NethereumWorkflow
|
|||
private Web3 CreateWeb3()
|
||||
{
|
||||
var account = new Nethereum.Web3.Accounts.Account(privateKey);
|
||||
return new Web3(account, $"http://{ip}:{port}");
|
||||
return new Web3(account, $"{ip}:{port}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
using DistTestCore;
|
||||
using DistTestCore.Codex;
|
||||
using NUnit.Framework;
|
||||
using Utils;
|
||||
|
||||
|
|
|
@ -1,66 +0,0 @@
|
|||
using DistTestCore;
|
||||
using DistTestCore.Codex;
|
||||
using NUnit.Framework;
|
||||
using Utils;
|
||||
|
||||
namespace Tests.DurabilityTests
|
||||
{
|
||||
[TestFixture]
|
||||
public class DurabilityTests : DistTest
|
||||
{
|
||||
[Test]
|
||||
public void BootstrapNodeDisappearsTest()
|
||||
{
|
||||
var bootstrapNode = SetupCodexBootstrapNode();
|
||||
var group = SetupCodexNodes(2, s => s.WithBootstrapNode(bootstrapNode));
|
||||
var primary = group[0];
|
||||
var secondary = group[1];
|
||||
|
||||
// There is 1 minute of time f or the nodes to connect to each other.
|
||||
// (Should be easy, they're in the same pod.)
|
||||
Time.Sleep(TimeSpan.FromMinutes(6));
|
||||
bootstrapNode.BringOffline();
|
||||
|
||||
var file = GenerateTestFile(10.MB());
|
||||
var contentId = primary.UploadFile(file);
|
||||
var downloadedFile = secondary.DownloadContent(contentId);
|
||||
|
||||
file.AssertIsEqual(downloadedFile);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void DataRetentionTest()
|
||||
{
|
||||
var bootstrapNode = SetupCodexBootstrapNode();
|
||||
|
||||
var startGroup = SetupCodexNodes(2, s => s.WithBootstrapNode(bootstrapNode));
|
||||
var finishGroup = SetupCodexNodes(10, s => s.WithBootstrapNode(bootstrapNode));
|
||||
|
||||
var file = GenerateTestFile(10.MB());
|
||||
|
||||
// Both nodes in the start group have the file.
|
||||
var content = startGroup[0].UploadFile(file);
|
||||
DownloadAndAssert(content, file, startGroup[1]);
|
||||
|
||||
// Three nodes of the finish group have the file.
|
||||
DownloadAndAssert(content, file, finishGroup[0]);
|
||||
DownloadAndAssert(content, file, finishGroup[1]);
|
||||
DownloadAndAssert(content, file, finishGroup[2]);
|
||||
|
||||
// The start group goes away.
|
||||
startGroup.BringOffline();
|
||||
|
||||
// All nodes in the finish group can access the file.
|
||||
foreach (var node in finishGroup)
|
||||
{
|
||||
DownloadAndAssert(content, file, node);
|
||||
}
|
||||
}
|
||||
|
||||
private void DownloadAndAssert(ContentId content, TestFile file, IOnlineCodexNode onlineCodexNode)
|
||||
{
|
||||
var downloaded = onlineCodexNode.DownloadContent(content);
|
||||
file.AssertIsEqual(downloaded);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,4 @@
|
|||
using DistTestCore;
|
||||
using DistTestCore.Codex;
|
||||
using DistTestCore.Helpers;
|
||||
using NUnit.Framework;
|
||||
using Utils;
|
||||
|
|
|
@ -22,6 +22,11 @@
|
|||
result += $"{d.Seconds} secs";
|
||||
return result;
|
||||
}
|
||||
|
||||
public static void WaitUntil(Func<bool> predicate)
|
||||
{
|
||||
WaitUntil(predicate, TimeSpan.FromMinutes(1), TimeSpan.FromSeconds(1));
|
||||
}
|
||||
|
||||
public static void WaitUntil(Func<bool> predicate, TimeSpan timeout, TimeSpan retryTime)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue