Extracts node-running logic from marketplace test

This commit is contained in:
benbierens 2023-06-28 11:48:05 +02:00
parent f7edfd4eee
commit 9a3f45e60d
No known key found for this signature in database
GPG Key ID: FE44815D96D0A1AA
3 changed files with 150 additions and 117 deletions

View File

@ -1,6 +1,7 @@
using DistTestCore; using DistTestCore;
using DistTestCore.Codex; using DistTestCore.Codex;
using Logging; using Logging;
using Utils;
namespace ContinuousTests namespace ContinuousTests
{ {
@ -27,6 +28,15 @@ namespace ContinuousTests
Log = log; Log = log;
FileManager = fileManager; FileManager = fileManager;
Configuration = configuration; 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!; public CodexNode[] Nodes { get; private set; } = null!;
@ -34,6 +44,7 @@ namespace ContinuousTests
public IFileManager FileManager { get; private set; } = null!; public IFileManager FileManager { get; private set; } = null!;
public Configuration Configuration { get; private set; } = null!; public Configuration Configuration { get; private set; } = null!;
public virtual ITimeSet TimeSet { get { return new DefaultTimeSet(); } } public virtual ITimeSet TimeSet { get { return new DefaultTimeSet(); } }
public NodeRunner NodeRunner { get; private set; } = null!;
public abstract int RequiredNumberOfNodes { get; } public abstract int RequiredNumberOfNodes { get; }
public abstract TimeSpan RunTestEvery { get; } public abstract TimeSpan RunTestEvery { get; }

View File

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

View File

@ -1,8 +1,5 @@
using DistTestCore; using DistTestCore;
using DistTestCore.Codex; using DistTestCore.Codex;
using DistTestCore.Marketplace;
using KubernetesWorkflow;
using Logging;
using Newtonsoft.Json; using Newtonsoft.Json;
using NUnit.Framework; using NUnit.Framework;
@ -33,40 +30,12 @@ namespace ContinuousTests.Tests
file = FileManager.GenerateTestFile(fileSize); file = FileManager.GenerateTestFile(fileSize);
var (workflowCreator, lifecycle) = CreateFacilities(); NodeRunner.RunNode((codexAccess, marketplaceAccess) =>
var flow = workflowCreator.CreateWorkflow();
try
{ {
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); cid = UploadFile(codexAccess.Node, file);
Assert.That(cid, Is.Not.Null); Assert.That(cid, Is.Not.Null);
purchaseId = marketAccess.RequestStorage( purchaseId = marketplaceAccess.RequestStorage(
contentId: cid!, contentId: cid!,
pricePerSlotPerSecond: pricePerSlotPerSecond, pricePerSlotPerSecond: pricePerSlotPerSecond,
requiredCollateral: 100.TestTokens(), requiredCollateral: 100.TestTokens(),
@ -74,103 +43,50 @@ namespace ContinuousTests.Tests
proofProbability: 10, proofProbability: 10,
duration: contractDuration); duration: contractDuration);
Log($"PurchaseId: '{purchaseId}'");
Assert.That(!string.IsNullOrEmpty(purchaseId)); Assert.That(!string.IsNullOrEmpty(purchaseId));
var lastState = ""; WaitForContractToStart(codexAccess, purchaseId);
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();
}
} }
[TestMoment(t: MinuteFive * 2)] [TestMoment(t: MinuteFive * 2)]
public void StoredDataIsAvailableAfterThreeDays() public void StoredDataIsAvailableAfterThreeDays()
{ {
var (workflowCreator, lifecycle) = CreateFacilities(); NodeRunner.RunNode((codexAccess, marketplaceAccess) =>
var flow = workflowCreator.CreateWorkflow();
try
{ {
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!); var result = DownloadContent(codexAccess.Node, cid!);
file.AssertIsEqual(result); 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);
}
} }
} }