Extracts node-running logic from marketplace test
This commit is contained in:
parent
f7edfd4eee
commit
9a3f45e60d
|
@ -1,6 +1,7 @@
|
|||
using DistTestCore;
|
||||
using DistTestCore.Codex;
|
||||
using Logging;
|
||||
using Utils;
|
||||
|
||||
namespace ContinuousTests
|
||||
{
|
||||
|
@ -27,6 +28,15 @@ namespace ContinuousTests
|
|||
Log = log;
|
||||
FileManager = fileManager;
|
||||
Configuration = configuration;
|
||||
|
||||
if (nodes != null)
|
||||
{
|
||||
NodeRunner = new NodeRunner(Nodes.ToList().PickOneRandom(), configuration, TimeSet, Log, CustomK8sNamespace, EthereumAccountIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
NodeRunner = null!;
|
||||
}
|
||||
}
|
||||
|
||||
public CodexNode[] Nodes { get; private set; } = null!;
|
||||
|
@ -34,6 +44,7 @@ namespace ContinuousTests
|
|||
public IFileManager FileManager { get; private set; } = null!;
|
||||
public Configuration Configuration { get; private set; } = null!;
|
||||
public virtual ITimeSet TimeSet { get { return new DefaultTimeSet(); } }
|
||||
public NodeRunner NodeRunner { get; private set; } = null!;
|
||||
|
||||
public abstract int RequiredNumberOfNodes { get; }
|
||||
public abstract TimeSpan RunTestEvery { get; }
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
using DistTestCore.Codex;
|
||||
using DistTestCore.Marketplace;
|
||||
using DistTestCore;
|
||||
using KubernetesWorkflow;
|
||||
using NUnit.Framework;
|
||||
using Logging;
|
||||
|
||||
namespace ContinuousTests
|
||||
{
|
||||
public class NodeRunner
|
||||
{
|
||||
private readonly CodexNode bootstrapNode;
|
||||
private readonly Configuration config;
|
||||
private readonly ITimeSet timeSet;
|
||||
private readonly BaseLog log;
|
||||
private readonly string customNamespace;
|
||||
private readonly int ethereumAccountIndex;
|
||||
|
||||
public NodeRunner(CodexNode bootstrapNode, Configuration config, ITimeSet timeSet, BaseLog log, string customNamespace, int ethereumAccountIndex)
|
||||
{
|
||||
this.bootstrapNode = bootstrapNode;
|
||||
this.config = config;
|
||||
this.timeSet = timeSet;
|
||||
this.log = log;
|
||||
this.customNamespace = customNamespace;
|
||||
this.ethereumAccountIndex = ethereumAccountIndex;
|
||||
}
|
||||
|
||||
public void RunNode(Action<CodexAccess, MarketplaceAccess> operation)
|
||||
{
|
||||
RunNode(operation, 0.TestTokens());
|
||||
}
|
||||
|
||||
public void RunNode(Action<CodexAccess, MarketplaceAccess> operation, TestToken mintTestTokens)
|
||||
{
|
||||
var (workflowCreator, lifecycle) = CreateFacilities();
|
||||
var flow = workflowCreator.CreateWorkflow();
|
||||
|
||||
try
|
||||
{
|
||||
var debugInfo = bootstrapNode.GetDebugInfo();
|
||||
Assert.That(!string.IsNullOrEmpty(debugInfo.spr));
|
||||
|
||||
var startupConfig = new StartupConfig();
|
||||
var codexStartConfig = new CodexStartupConfig(CodexLogLevel.Trace);
|
||||
codexStartConfig.MarketplaceConfig = new MarketplaceInitialConfig(0.Eth(), 0.TestTokens(), false);
|
||||
codexStartConfig.MarketplaceConfig.AccountIndexOverride = ethereumAccountIndex;
|
||||
codexStartConfig.BootstrapSpr = debugInfo.spr;
|
||||
startupConfig.Add(codexStartConfig);
|
||||
startupConfig.Add(config.CodexDeployment.GethStartResult);
|
||||
var rc = flow.Start(1, Location.Unspecified, new CodexContainerRecipe(), startupConfig);
|
||||
|
||||
var account = config.CodexDeployment.GethStartResult.CompanionNode.Accounts[ethereumAccountIndex];
|
||||
|
||||
var marketplaceNetwork = config.CodexDeployment.GethStartResult.MarketplaceNetwork;
|
||||
if (mintTestTokens.Amount > 0)
|
||||
{
|
||||
var tokenAddress = marketplaceNetwork.Marketplace.TokenAddress;
|
||||
var interaction = marketplaceNetwork.Bootstrap.StartInteraction(lifecycle);
|
||||
interaction.MintTestTokens(new[] { account.Account }, mintTestTokens.Amount, tokenAddress);
|
||||
}
|
||||
|
||||
var container = rc.Containers[0];
|
||||
var codexAccess = new CodexAccess(lifecycle, container);
|
||||
var marketAccess = new MarketplaceAccess(lifecycle, marketplaceNetwork, account, codexAccess);
|
||||
|
||||
operation(codexAccess, marketAccess);
|
||||
}
|
||||
finally
|
||||
{
|
||||
flow.DeleteTestResources();
|
||||
}
|
||||
}
|
||||
|
||||
private (WorkflowCreator, TestLifecycle) CreateFacilities()
|
||||
{
|
||||
var kubeConfig = GetKubeConfig(config.KubeConfigFile);
|
||||
var lifecycleConfig = new DistTestCore.Configuration
|
||||
(
|
||||
kubeConfigFile: kubeConfig,
|
||||
logPath: "null",
|
||||
logDebug: false,
|
||||
dataFilesPath: config.LogPath,
|
||||
codexLogLevel: CodexLogLevel.Debug,
|
||||
runnerLocation: TestRunnerLocation.ExternalToCluster
|
||||
);
|
||||
|
||||
var kubeFlowConfig = new KubernetesWorkflow.Configuration(
|
||||
k8sNamespacePrefix: customNamespace,
|
||||
kubeConfigFile: kubeConfig,
|
||||
operationTimeout: timeSet.K8sOperationTimeout(),
|
||||
retryDelay: timeSet.WaitForK8sServiceDelay());
|
||||
|
||||
var workflowCreator = new WorkflowCreator(log, kubeFlowConfig, testNamespacePostfix: string.Empty);
|
||||
var lifecycle = new TestLifecycle(new NullLog(), lifecycleConfig, timeSet, workflowCreator);
|
||||
|
||||
return (workflowCreator, lifecycle);
|
||||
}
|
||||
|
||||
private static string? GetKubeConfig(string kubeConfigFile)
|
||||
{
|
||||
if (string.IsNullOrEmpty(kubeConfigFile) || kubeConfigFile.ToLowerInvariant() == "null") return null;
|
||||
return kubeConfigFile;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,5 @@
|
|||
using DistTestCore;
|
||||
using DistTestCore.Codex;
|
||||
using DistTestCore.Marketplace;
|
||||
using KubernetesWorkflow;
|
||||
using Logging;
|
||||
using Newtonsoft.Json;
|
||||
using NUnit.Framework;
|
||||
|
||||
|
@ -33,40 +30,12 @@ namespace ContinuousTests.Tests
|
|||
|
||||
file = FileManager.GenerateTestFile(fileSize);
|
||||
|
||||
var (workflowCreator, lifecycle) = CreateFacilities();
|
||||
var flow = workflowCreator.CreateWorkflow();
|
||||
|
||||
try
|
||||
NodeRunner.RunNode((codexAccess, marketplaceAccess) =>
|
||||
{
|
||||
var debugInfo = Nodes[0].GetDebugInfo();
|
||||
Assert.That(!string.IsNullOrEmpty(debugInfo.spr));
|
||||
|
||||
var startupConfig = new StartupConfig();
|
||||
var codexStartConfig = new CodexStartupConfig(CodexLogLevel.Trace);
|
||||
codexStartConfig.MarketplaceConfig = new MarketplaceInitialConfig(0.Eth(), 0.TestTokens(), false);
|
||||
codexStartConfig.MarketplaceConfig.AccountIndexOverride = EthereumAccountIndex;
|
||||
codexStartConfig.BootstrapSpr = debugInfo.spr;
|
||||
startupConfig.Add(codexStartConfig);
|
||||
startupConfig.Add(Configuration.CodexDeployment.GethStartResult);
|
||||
var rc = flow.Start(1, Location.Unspecified, new CodexContainerRecipe(), startupConfig);
|
||||
|
||||
var account = Configuration.CodexDeployment.GethStartResult.CompanionNode.Accounts[EthereumAccountIndex];
|
||||
var tokenAddress = Configuration.CodexDeployment.GethStartResult.MarketplaceNetwork.Marketplace.TokenAddress;
|
||||
|
||||
var interaction = Configuration.CodexDeployment.GethStartResult.MarketplaceNetwork.Bootstrap.StartInteraction(lifecycle);
|
||||
interaction.MintTestTokens(new[] { account.Account }, expectedTotalCost, tokenAddress);
|
||||
|
||||
var container = rc.Containers[0];
|
||||
var marketplaceNetwork = Configuration.CodexDeployment.GethStartResult.MarketplaceNetwork;
|
||||
var codexAccess = new CodexAccess(lifecycle, container);
|
||||
var myNodeInfo = codexAccess.Node.GetDebugInfo();
|
||||
|
||||
var marketAccess = new MarketplaceAccess(lifecycle, marketplaceNetwork, account, codexAccess);
|
||||
|
||||
cid = UploadFile(codexAccess.Node, file);
|
||||
Assert.That(cid, Is.Not.Null);
|
||||
|
||||
purchaseId = marketAccess.RequestStorage(
|
||||
purchaseId = marketplaceAccess.RequestStorage(
|
||||
contentId: cid!,
|
||||
pricePerSlotPerSecond: pricePerSlotPerSecond,
|
||||
requiredCollateral: 100.TestTokens(),
|
||||
|
@ -74,103 +43,50 @@ namespace ContinuousTests.Tests
|
|||
proofProbability: 10,
|
||||
duration: contractDuration);
|
||||
|
||||
Log($"PurchaseId: '{purchaseId}'");
|
||||
Assert.That(!string.IsNullOrEmpty(purchaseId));
|
||||
|
||||
var lastState = "";
|
||||
var waitStart = DateTime.UtcNow;
|
||||
var filesizeInMb = fileSize.SizeInBytes / 1024;
|
||||
var maxWaitTime = TimeSpan.FromSeconds(filesizeInMb * 10.0);
|
||||
while (lastState != "started")
|
||||
{
|
||||
var purchaseStatus = codexAccess.Node.GetPurchaseStatus(purchaseId);
|
||||
if (purchaseStatus != null && purchaseStatus.state != lastState)
|
||||
{
|
||||
lastState = purchaseStatus.state;
|
||||
}
|
||||
|
||||
Thread.Sleep(2000);
|
||||
|
||||
if (lastState == "errored")
|
||||
{
|
||||
Assert.Fail("Contract start failed: " + JsonConvert.SerializeObject(purchaseStatus));
|
||||
}
|
||||
|
||||
if (DateTime.UtcNow - waitStart > maxWaitTime)
|
||||
{
|
||||
Assert.Fail($"Contract was not picked up within {maxWaitTime.TotalSeconds} seconds timeout: " + JsonConvert.SerializeObject(purchaseStatus));
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
flow.DeleteTestResources();
|
||||
}
|
||||
WaitForContractToStart(codexAccess, purchaseId);
|
||||
});
|
||||
}
|
||||
|
||||
[TestMoment(t: MinuteFive * 2)]
|
||||
public void StoredDataIsAvailableAfterThreeDays()
|
||||
{
|
||||
var (workflowCreator, lifecycle) = CreateFacilities();
|
||||
var flow = workflowCreator.CreateWorkflow();
|
||||
|
||||
try
|
||||
NodeRunner.RunNode((codexAccess, marketplaceAccess) =>
|
||||
{
|
||||
var debugInfo = Nodes[0].GetDebugInfo();
|
||||
Assert.That(!string.IsNullOrEmpty(debugInfo.spr));
|
||||
|
||||
var startupConfig = new StartupConfig();
|
||||
var codexStartConfig = new CodexStartupConfig(CodexLogLevel.Debug);
|
||||
codexStartConfig.BootstrapSpr = debugInfo.spr;
|
||||
startupConfig.Add(codexStartConfig);
|
||||
var rc = flow.Start(1, Location.Unspecified, new CodexContainerRecipe(), startupConfig);
|
||||
var container = rc.Containers[0];
|
||||
var codexAccess = new CodexAccess(lifecycle, container);
|
||||
|
||||
var result = DownloadContent(codexAccess.Node, cid!);
|
||||
|
||||
file.AssertIsEqual(result);
|
||||
}
|
||||
finally
|
||||
});
|
||||
}
|
||||
|
||||
private void WaitForContractToStart(CodexAccess codexAccess, string purchaseId)
|
||||
{
|
||||
var lastState = "";
|
||||
var waitStart = DateTime.UtcNow;
|
||||
var filesizeInMb = fileSize.SizeInBytes / 1024;
|
||||
var maxWaitTime = TimeSpan.FromSeconds(filesizeInMb * 10.0);
|
||||
|
||||
while (lastState != "started")
|
||||
{
|
||||
flow.DeleteTestResources();
|
||||
var purchaseStatus = codexAccess.Node.GetPurchaseStatus(purchaseId);
|
||||
if (purchaseStatus != null && purchaseStatus.state != lastState)
|
||||
{
|
||||
lastState = purchaseStatus.state;
|
||||
}
|
||||
|
||||
Thread.Sleep(2000);
|
||||
|
||||
if (lastState == "errored")
|
||||
{
|
||||
Assert.Fail("Contract start failed: " + JsonConvert.SerializeObject(purchaseStatus));
|
||||
}
|
||||
|
||||
if (DateTime.UtcNow - waitStart > maxWaitTime)
|
||||
{
|
||||
Assert.Fail($"Contract was not picked up within {maxWaitTime.TotalSeconds} seconds timeout: " + JsonConvert.SerializeObject(purchaseStatus));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private (WorkflowCreator, TestLifecycle) CreateFacilities()
|
||||
{
|
||||
var kubeConfig = GetKubeConfig(Configuration.KubeConfigFile);
|
||||
var lifecycleConfig = new DistTestCore.Configuration
|
||||
(
|
||||
kubeConfigFile: kubeConfig,
|
||||
logPath: "null",
|
||||
logDebug: false,
|
||||
dataFilesPath: Configuration.LogPath,
|
||||
codexLogLevel: CodexLogLevel.Debug,
|
||||
runnerLocation: TestRunnerLocation.ExternalToCluster
|
||||
);
|
||||
|
||||
var kubeFlowConfig = new KubernetesWorkflow.Configuration(
|
||||
k8sNamespacePrefix: MarketplaceTestNamespace,
|
||||
kubeConfigFile: kubeConfig,
|
||||
operationTimeout: TimeSet.K8sOperationTimeout(),
|
||||
retryDelay: TimeSet.WaitForK8sServiceDelay());
|
||||
|
||||
var workflowCreator = new WorkflowCreator(base.Log, kubeFlowConfig, testNamespacePostfix: string.Empty);
|
||||
var lifecycle = new TestLifecycle(new NullLog(), lifecycleConfig, TimeSet, workflowCreator);
|
||||
|
||||
return (workflowCreator, lifecycle);
|
||||
}
|
||||
|
||||
private string? GetKubeConfig(string kubeConfigFile)
|
||||
{
|
||||
if (string.IsNullOrEmpty(kubeConfigFile) || kubeConfigFile.ToLowerInvariant() == "null") return null;
|
||||
return kubeConfigFile;
|
||||
}
|
||||
|
||||
private new void Log(string msg)
|
||||
{
|
||||
base.Log.Log(msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue