Merge branch 'feature/cluster-internal-and-external-container-addresses'

This commit is contained in:
benbierens 2023-06-02 08:19:10 +02:00
commit e8d99b83ff
No known key found for this signature in database
GPG Key ID: FE44815D96D0A1AA
32 changed files with 204 additions and 154 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
using DistTestCore;
using NUnit.Framework;
namespace Tests.ParallelTests
namespace TestsLong.BasicTests
{
[TestFixture]
public class UploadTests : DistTest

View File

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

View File

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

View File

@ -1,5 +1,4 @@
using DistTestCore;
using DistTestCore.Codex;
using NUnit.Framework;
using Utils;

View File

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

View File

@ -1,5 +1,4 @@
using DistTestCore;
using DistTestCore.Codex;
using DistTestCore.Helpers;
using NUnit.Framework;
using Utils;

View File

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