diff --git a/CodexNetDeployer/Deployer.cs b/CodexNetDeployer/Deployer.cs index f69c967..5745dd9 100644 --- a/CodexNetDeployer/Deployer.cs +++ b/CodexNetDeployer/Deployer.cs @@ -1,6 +1,7 @@ using DistTestCore; using DistTestCore.Codex; using KubernetesWorkflow; +using Logging; namespace CodexNetDeployer { @@ -52,7 +53,7 @@ namespace CodexNetDeployer { var lifecycleConfig = new DistTestCore.Configuration ( - kubeConfigFile: null, //config.KubeConfigFile, + kubeConfigFile: config.KubeConfigFile, logPath: "null", logDebug: false, dataFilesPath: "notUsed", @@ -62,7 +63,7 @@ namespace CodexNetDeployer var kubeConfig = new KubernetesWorkflow.Configuration( k8sNamespacePrefix: config.KubeNamespace, - kubeConfigFile: null, //config.KubeConfigFile, + kubeConfigFile: config.KubeConfigFile, operationTimeout: timeset.K8sOperationTimeout(), retryDelay: timeset.WaitForK8sServiceDelay()); diff --git a/ContinuousTests/Configuration.cs b/ContinuousTests/Configuration.cs index 46b96cb..c4d5b7a 100644 --- a/ContinuousTests/Configuration.cs +++ b/ContinuousTests/Configuration.cs @@ -18,6 +18,9 @@ namespace ContinuousTests [Uniform("keep", "k", "KEEP", false, "Set to '1' to retain logs of successful tests.")] public bool KeepPassedTestLogs { get; set; } = false; + [Uniform("kube-config", "kc", "KUBECONFIG", true, "Path to Kubeconfig file.")] + public string KubeConfigFile { get; set; } = string.Empty; + public CodexDeployment CodexDeployment { get; set; } = null!; } diff --git a/ContinuousTests/ContinuousTest.cs b/ContinuousTests/ContinuousTest.cs index c278aad..3f0c90e 100644 --- a/ContinuousTests/ContinuousTest.cs +++ b/ContinuousTests/ContinuousTest.cs @@ -15,21 +15,24 @@ namespace ContinuousTests protected const int MinuteOne = 60; protected const int MinuteFive = MinuteOne * 5; protected const int HourOne = MinuteOne * 60; + protected const int HourThree = HourOne * 3; protected const int DayOne = HourOne * 24; protected const int DayThree = DayOne * 3; private const string UploadFailedMessage = "Unable to store block"; - public void Initialize(CodexNode[] nodes, BaseLog log, FileManager fileManager) + public void Initialize(CodexNode[] nodes, BaseLog log, FileManager fileManager, Configuration configuration) { Nodes = nodes; Log = log; FileManager = fileManager; + Configuration = configuration; } public CodexNode[] Nodes { get; private set; } = null!; public BaseLog Log { get; private set; } = null!; public IFileManager FileManager { get; private set; } = null!; + public Configuration Configuration { get; private set; } = null!; public virtual ITimeSet TimeSet { get { return new DefaultTimeSet(); } } public abstract int RequiredNumberOfNodes { get; } diff --git a/ContinuousTests/SingleTestRun.cs b/ContinuousTests/SingleTestRun.cs index 708286e..7e8d0a4 100644 --- a/ContinuousTests/SingleTestRun.cs +++ b/ContinuousTests/SingleTestRun.cs @@ -111,12 +111,12 @@ namespace ContinuousTests private void InitializeTest(string name) { Log($" > Running TestMoment '{name}'"); - handle.Test.Initialize(nodes, fixtureLog, fileManager); + handle.Test.Initialize(nodes, fixtureLog, fileManager, config); } private void DecommissionTest() { - handle.Test.Initialize(null!, null!, null!); + handle.Test.Initialize(null!, null!, null!, null!); } private void Log(string msg) diff --git a/ContinuousTests/Tests/MarketplaceTest.cs b/ContinuousTests/Tests/MarketplaceTest.cs index 03243c8..578e94d 100644 --- a/ContinuousTests/Tests/MarketplaceTest.cs +++ b/ContinuousTests/Tests/MarketplaceTest.cs @@ -1,25 +1,130 @@ -using DistTestCore.Codex; +using DistTestCore; +using DistTestCore.Codex; +using DistTestCore.Marketplace; +using KubernetesWorkflow; +using Logging; +using NUnit.Framework; namespace ContinuousTests.Tests { - //public class MarketplaceTest : ContinuousTest - //{ - // public override int RequiredNumberOfNodes => 1; - // public override TimeSpan RunTestEvery => TimeSpan.FromDays(1); - // public override TestFailMode TestFailMode => TestFailMode.AlwaysRunAllMoments; + public class MarketplaceTest : ContinuousTest + { + public override int RequiredNumberOfNodes => 1; + public override TimeSpan RunTestEvery => TimeSpan.FromDays(4); + public override TestFailMode TestFailMode => TestFailMode.AlwaysRunAllMoments; - // [TestMoment(t: Zero)] - // public void NodePostsStorageRequest() - // { - // //var c = new KubernetesWorkflow.WorkflowCreator(Log, new KubernetesWorkflow.Configuration()); - // //var flow = c.CreateWorkflow(); - // //var rc = flow.Start(10, KubernetesWorkflow.Location.Unspecified, new CodexContainerRecipe(), new KubernetesWorkflow.StartupConfig()); - // } + public const int EthereumAccountIndex = 200; // TODO: Check against all other account indices of all other tests. - // [TestMoment(t: DayThree)] - // public void NodeDownloadsStorageRequestData() - // { + private const string MarketplaceTestNamespace = "codex-continuous-marketplace"; - // } - //} + private readonly ByteSize fileSize = 100.MB(); + private readonly TestToken pricePerBytePerSecond = 1.TestTokens(); + + private TestFile file = null!; + private ContentId? cid; + private TestToken startingBalance = null!; + private string purchaseId = string.Empty; + + [TestMoment(t: Zero)] + public void NodePostsStorageRequest() + { + var contractDuration = TimeSpan.FromDays(3) + TimeSpan.FromHours(1); + decimal totalDurationSeconds = Convert.ToDecimal(contractDuration.TotalSeconds); + var expectedTotalCost = pricePerBytePerSecond.Amount * totalDurationSeconds; + + file = FileManager.GenerateTestFile(fileSize); + + var (workflowCreator, lifecycle) = CreateFacilities(); + var flow = workflowCreator.CreateWorkflow(); + var startupConfig = new StartupConfig(); + var codexStartConfig = new CodexStartupConfig(CodexLogLevel.Debug); + codexStartConfig.MarketplaceConfig = new MarketplaceInitialConfig(0.Eth(), 0.TestTokens(), false); + codexStartConfig.MarketplaceConfig.AccountIndexOverride = EthereumAccountIndex; + startupConfig.Add(codexStartConfig); + startupConfig.Add(Configuration.CodexDeployment.GethStartResult); + var rc = flow.Start(1, Location.Unspecified, new CodexContainerRecipe(), startupConfig); + + try + { + var account = Configuration.CodexDeployment.GethStartResult.MarketplaceNetwork.Bootstrap.AllAccounts.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 marketAccess = new MarketplaceAccess(lifecycle, marketplaceNetwork, account, codexAccess); + + cid = UploadFile(codexAccess.Node, file); + Assert.That(cid, Is.Not.Null); + + startingBalance = marketAccess.GetBalance(); + + purchaseId = marketAccess.RequestStorage( + contentId: cid!, + pricePerBytePerSecond: pricePerBytePerSecond, + requiredCollateral: 100.TestTokens(), + minRequiredNumberOfNodes: 3, + proofProbability: 10, + duration: contractDuration); + + Assert.That(!string.IsNullOrEmpty(purchaseId)); + } + finally + { + flow.Stop(rc); + } + } + + [TestMoment(t: DayThree)] + public void StoredDataIsAvailableAfterThreeDays() + { + var (workflowCreator, lifecycle) = CreateFacilities(); + var flow = workflowCreator.CreateWorkflow(); + var startupConfig = new StartupConfig(); + var codexStartConfig = new CodexStartupConfig(CodexLogLevel.Debug); + startupConfig.Add(codexStartConfig); + var rc = flow.Start(1, Location.Unspecified, new CodexContainerRecipe(), startupConfig); + + try + { + var container = rc.Containers[0]; + var codexAccess = new CodexAccess(lifecycle, container); + + var result = DownloadContent(codexAccess.Node, cid!); + + file.AssertIsEqual(result); + } + finally + { + flow.Stop(rc); + } + } + + private (WorkflowCreator, TestLifecycle) CreateFacilities() + { + var lifecycleConfig = new DistTestCore.Configuration + ( + kubeConfigFile: Configuration.KubeConfigFile, + logPath: "null", + logDebug: false, + dataFilesPath: "notUsed", + codexLogLevel: CodexLogLevel.Debug, + runnerLocation: TestRunnerLocation.InternalToCluster + ); + + var kubeConfig = new KubernetesWorkflow.Configuration( + k8sNamespacePrefix: MarketplaceTestNamespace, + kubeConfigFile: Configuration.KubeConfigFile, + operationTimeout: TimeSet.K8sOperationTimeout(), + retryDelay: TimeSet.WaitForK8sServiceDelay()); + + var workflowCreator = new WorkflowCreator(Log, kubeConfig, testNamespacePostfix: string.Empty); + var lifecycle = new TestLifecycle(new NullLog(), lifecycleConfig, TimeSet, workflowCreator); + + return (workflowCreator, lifecycle); + } + } } diff --git a/CodexNetDeployer/NullLog.cs b/Logging/NullLog.cs similarity index 84% rename from CodexNetDeployer/NullLog.cs rename to Logging/NullLog.cs index 8417d39..5323508 100644 --- a/CodexNetDeployer/NullLog.cs +++ b/Logging/NullLog.cs @@ -1,6 +1,4 @@ -using Logging; - -namespace CodexNetDeployer +namespace Logging { public class NullLog : TestLog { @@ -15,12 +13,10 @@ namespace CodexNetDeployer public override void Log(string message) { - //Console.WriteLine(message); } public override void Debug(string message = "", int skipFrames = 0) { - //Console.WriteLine(message); } public override void Error(string message)