Compare commits
10
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
760d0211c6 | ||
|
|
32807f3f8c | ||
|
|
9ce82cb011 | ||
|
|
23396f54e0 | ||
|
|
d1a70d2465 | ||
|
|
3c8efbd0a0 | ||
|
|
247e010fba | ||
|
|
f0167a800f | ||
|
|
b35cf3139d | ||
|
|
65473d8c15 |
@@ -112,7 +112,7 @@ jobs:
|
||||
[[ -n "${{ inputs.tests_cleanup }}" ]] && echo "TESTS_CLEANUP=${{ inputs.tests_cleanup }}" >>"$GITHUB_ENV" || echo "TESTS_CLEANUP=${{ env.TESTS_CLEANUP }}" >>"$GITHUB_ENV"
|
||||
|
||||
- name: Kubectl - Install ${{ env.KUBE_VERSION }}
|
||||
uses: azure/setup-kubectl@releases/v4.0.0
|
||||
uses: azure/setup-kubectl@v4
|
||||
with:
|
||||
version: ${{ env.KUBE_VERSION }}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ jobs:
|
||||
[[ -n "${{ inputs.command }}" ]] && COMMAND="${{ inputs.command }}" || COMMAND="${{ env.COMMAND }}"
|
||||
|
||||
- name: Kubectl - Install ${{ env.KUBE_VERSION }}
|
||||
uses: azure/setup-kubectl@releases/v4.0.0
|
||||
uses: azure/setup-kubectl@v4
|
||||
with:
|
||||
version: ${{ env.KUBE_VERSION }}
|
||||
|
||||
|
||||
+1
-2
@@ -1,5 +1,4 @@
|
||||
.vs
|
||||
obj
|
||||
bin
|
||||
.vscode
|
||||
Tools/CommitBlamer/CodexTestLogs
|
||||
.vscode
|
||||
@@ -82,5 +82,5 @@ public static class CoreInterfaceExtensions
|
||||
}
|
||||
```
|
||||
|
||||
The primary reason to decouple deploying and wrapping functionalities is that some use cases require these steps to be performed by separate applications, and different moments in time. For this reason, whatever is returned by the deploy methods should be serializable. After deserialization at some later time, it should then be valid input for the wrap method. The Codex continuous tests system is a clear example of this use case: The `CodexNetDeployer` tool uses deploy methods to create Codex nodes. Then it writes the returned objects to a JSON file. Some time later, the `CodexContinousTests` application uses this JSON file to reconstruct the objects created by the deploy methods. It then uses the wrap methods to create accessors and interactors, which are used for testing.
|
||||
The primary reason to decouple deploying and wrapping functionalities is that some use cases require these steps to be performed by separate applications, and different moments in time. For this reason, whatever is returned by the deploy methods should be serializable. After deserialization at some later time, it should then be valid input for the wrap method. The Codex continuous tests system is a clear example of this use case: The `CodexNetDeployer` tool uses deploy methods to create Codex nodes. Then it writes the returned objects to a JSON file. Some time later, the `CodexContinuousTests` application uses this JSON file to reconstruct the objects created by the deploy methods. It then uses the wrap methods to create accessors and interactors, which are used for testing.
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ Do you want to write some tests using this distributed test setup? Great! Here's
|
||||
1. When using the auto-bootstrap, you have no control over the bootstrap node from your tests. You can't (for example) shut it down during the course of the test. If you need this level of control for your scenario, use the `CodexDistTest` instead.
|
||||
1. If your test needs a long time to run, add the `[UseLongTimeouts]` function attribute. This will greatly increase maximum time-out values for operations like for example uploading and downloading files.
|
||||
### Continuous tests
|
||||
1. Add new code files to `Tests/CodexContinousTests/Tests`
|
||||
1. Add new code files to `Tests/CodexContinuousTests/Tests`
|
||||
1. Inherrit from `ContinuousTest`
|
||||
1. Define one or more methods and decorate them with the `[TestMoment(...)]` attribute.
|
||||
1. The TestMoment takes a number of seconds as argument. Each moment will be executed by the continuous test runner applying the given seconds as delay. (Non-cumulative. So two moments at T:10 will be executed one after another without delay, in this case the order of execution should not be depended upon.)
|
||||
|
||||
@@ -7,7 +7,7 @@ namespace CodexContractsPlugin
|
||||
{
|
||||
public class CodexContractsContainerRecipe : ContainerRecipeFactory
|
||||
{
|
||||
public static string DockerImage { get; } = "codexstorage/codex-contracts-eth:sha-b5f3399-dist-tests";
|
||||
public static string DockerImage { get; } = "codexstorage/codex-contracts-eth:sha-965529d-dist-tests";
|
||||
|
||||
public const string MarketplaceAddressFilename = "/hardhat/deployments/codexdisttestnetwork/Marketplace.json";
|
||||
public const string MarketplaceArtifactFilename = "/hardhat/artifacts/contracts/Marketplace.sol/Marketplace.json";
|
||||
|
||||
@@ -9,7 +9,7 @@ namespace CodexPlugin
|
||||
public CodexDeployment(CodexInstance[] codexInstances, GethDeployment gethDeployment,
|
||||
CodexContractsDeployment codexContractsDeployment, RunningContainers? prometheusContainer,
|
||||
RunningContainers? discordBotContainer, DeploymentMetadata metadata,
|
||||
String id)
|
||||
string id)
|
||||
{
|
||||
Id = id;
|
||||
CodexInstances = codexInstances;
|
||||
@@ -20,7 +20,7 @@ namespace CodexPlugin
|
||||
Metadata = metadata;
|
||||
}
|
||||
|
||||
public String Id { get; }
|
||||
public string Id { get; }
|
||||
public CodexInstance[] CodexInstances { get; }
|
||||
public GethDeployment GethDeployment { get; }
|
||||
public CodexContractsDeployment CodexContractsDeployment { get; }
|
||||
|
||||
@@ -12,7 +12,7 @@ Nethereum: v4.14.0
|
||||
These are test assemblies that use NUnit3 to perform tests against transient Codex nodes.
|
||||
Read more [HERE](/Tests/CodexTests/README.md)
|
||||
|
||||
## Tests/ContinousTests
|
||||
## Tests/ContinuousTests
|
||||
A console application that runs tests in an endless loop against a persistent deployment of Codex nodes.
|
||||
Read more [HERE](/Tests/CodexContinuousTests/README.md)
|
||||
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
using CodexPlugin;
|
||||
using CodexContractsPlugin;
|
||||
using CodexPlugin;
|
||||
using Core;
|
||||
using DistTestCore;
|
||||
using FileUtils;
|
||||
using GethPlugin;
|
||||
using Logging;
|
||||
using MetricsPlugin;
|
||||
|
||||
@@ -32,7 +33,7 @@ namespace ContinuousTests
|
||||
|
||||
if (nodes != null)
|
||||
{
|
||||
NodeRunner = new NodeRunner(Nodes, configuration, Log, CustomK8sNamespace);
|
||||
NodeRunner = new NodeRunner(Nodes, configuration, Log);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -57,15 +58,23 @@ namespace ContinuousTests
|
||||
{
|
||||
if (Configuration.CodexDeployment.PrometheusContainer == null) throw new Exception("Expected prometheus to be part of Codex deployment.");
|
||||
|
||||
var entryPointFactory = new EntryPointFactory();
|
||||
var entryPoint = entryPointFactory.CreateEntryPoint(Configuration.KubeConfigFile, Configuration.DataPath, Configuration.CodexDeployment.Metadata.KubeNamespace, Log);
|
||||
return entryPoint.CreateInterface().WrapMetricsCollector(Configuration.CodexDeployment.PrometheusContainer, target);
|
||||
var ci = CreateCi();
|
||||
return ci.WrapMetricsCollector(Configuration.CodexDeployment.PrometheusContainer, target);
|
||||
}
|
||||
|
||||
public (IGethNode, ICodexContracts) CreateMarketplaceAccess()
|
||||
{
|
||||
var ci = CreateCi();
|
||||
|
||||
var geth = ci.WrapGethDeployment(Configuration.CodexDeployment.GethDeployment);
|
||||
var contracts = ci.WrapCodexContractsDeployment(geth, Configuration.CodexDeployment.CodexContractsDeployment);
|
||||
|
||||
return (geth, contracts);
|
||||
}
|
||||
|
||||
public abstract int RequiredNumberOfNodes { get; }
|
||||
public abstract TimeSpan RunTestEvery { get; }
|
||||
public abstract TestFailMode TestFailMode { get; }
|
||||
public virtual string CustomK8sNamespace { get { return string.Empty; } }
|
||||
|
||||
public string Name
|
||||
{
|
||||
@@ -74,6 +83,13 @@ namespace ContinuousTests
|
||||
return GetType().Name;
|
||||
}
|
||||
}
|
||||
|
||||
private CoreInterface CreateCi()
|
||||
{
|
||||
var entryPointFactory = new EntryPointFactory();
|
||||
var entryPoint = entryPointFactory.CreateEntryPoint(Configuration.KubeConfigFile, Configuration.DataPath, Configuration.CodexDeployment.Metadata.KubeNamespace, Log);
|
||||
return entryPoint.CreateInterface();
|
||||
}
|
||||
}
|
||||
|
||||
public enum TestFailMode
|
||||
|
||||
@@ -51,8 +51,6 @@ namespace ContinuousTests
|
||||
overviewLog.Log("");
|
||||
var allTests = testFactory.CreateTests();
|
||||
|
||||
ClearAllCustomNamespaces(allTests, overviewLog);
|
||||
|
||||
var filteredTests = FilterTests(allTests, overviewLog);
|
||||
if (!filteredTests.Any())
|
||||
{
|
||||
@@ -136,21 +134,6 @@ namespace ContinuousTests
|
||||
return result;
|
||||
}
|
||||
|
||||
private void ClearAllCustomNamespaces(ContinuousTest[] allTests, ILog log)
|
||||
{
|
||||
foreach (var test in allTests) ClearAllCustomNamespaces(test, log);
|
||||
}
|
||||
|
||||
private void ClearAllCustomNamespaces(ContinuousTest test, ILog log)
|
||||
{
|
||||
if (string.IsNullOrEmpty(test.CustomK8sNamespace)) return;
|
||||
|
||||
log.Log($"Clearing namespace '{test.CustomK8sNamespace}'...");
|
||||
|
||||
var entryPoint = entryPointFactory.CreateEntryPoint(config.KubeConfigFile, config.DataPath, test.CustomK8sNamespace, log);
|
||||
entryPoint.Tools.CreateWorkflow().DeleteNamespacesStartingWith(test.CustomK8sNamespace);
|
||||
}
|
||||
|
||||
private void PerformCleanup(ILog log)
|
||||
{
|
||||
if (!config.Cleanup) return;
|
||||
|
||||
@@ -25,7 +25,6 @@ namespace ContinuousTests
|
||||
);
|
||||
|
||||
return new EntryPoint(log, lifecycleConfig, dataFilePath);
|
||||
//DefaultContainerRecipe.TestsType = "continuous-tests";
|
||||
}
|
||||
|
||||
private static string? GetKubeConfig(string kubeConfigFile)
|
||||
|
||||
@@ -13,14 +13,12 @@ namespace ContinuousTests
|
||||
private readonly ICodexNode[] nodes;
|
||||
private readonly Configuration config;
|
||||
private readonly ILog log;
|
||||
private readonly string customNamespace;
|
||||
|
||||
public NodeRunner(ICodexNode[] nodes, Configuration config, ILog log, string customNamespace)
|
||||
public NodeRunner(ICodexNode[] nodes, Configuration config, ILog log)
|
||||
{
|
||||
this.nodes = nodes;
|
||||
this.config = config;
|
||||
this.log = log;
|
||||
this.customNamespace = customNamespace;
|
||||
}
|
||||
|
||||
public IDownloadedLog DownloadLog(RunningContainer container, int? tailLines = null)
|
||||
@@ -41,36 +39,34 @@ namespace ContinuousTests
|
||||
// Therefore, we use the image of the bootstrap node.
|
||||
CodexContainerRecipe.DockerImageOverride = bootstrapNode.Container.Recipe.Image;
|
||||
|
||||
var debugInfo = bootstrapNode.GetDebugInfo();
|
||||
Assert.That(!string.IsNullOrEmpty(debugInfo.spr));
|
||||
|
||||
var node = entryPoint.CreateInterface().StartCodexNode(s =>
|
||||
{
|
||||
setup(s);
|
||||
s.WithBootstrapNode(bootstrapNode);
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
var debugInfo = bootstrapNode.GetDebugInfo();
|
||||
Assert.That(!string.IsNullOrEmpty(debugInfo.spr));
|
||||
|
||||
var node = entryPoint.CreateInterface().StartCodexNode(s =>
|
||||
{
|
||||
setup(s);
|
||||
s.WithBootstrapNode(bootstrapNode);
|
||||
});
|
||||
|
||||
try
|
||||
{
|
||||
operation(node);
|
||||
}
|
||||
catch
|
||||
{
|
||||
DownloadLog(node.Container);
|
||||
throw;
|
||||
}
|
||||
operation(node);
|
||||
}
|
||||
catch
|
||||
{
|
||||
DownloadLog(node.Container);
|
||||
node.Stop();
|
||||
throw;
|
||||
}
|
||||
finally
|
||||
{
|
||||
entryPoint.Tools.CreateWorkflow().DeleteNamespace();
|
||||
node.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
private EntryPoint CreateEntryPoint()
|
||||
{
|
||||
return entryPointFactory.CreateEntryPoint(config.KubeConfigFile, config.DataPath, customNamespace, log);
|
||||
return entryPointFactory.CreateEntryPoint(config.KubeConfigFile, config.DataPath, config.CodexDeployment.Metadata.KubeNamespace, log);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ public class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("Codex Continous-Test-Runner.");
|
||||
Console.WriteLine("Codex Continuous-Test-Runner.");
|
||||
|
||||
var runner = new ContinuousTestRunner(args, Cancellation.Cts.Token);
|
||||
|
||||
|
||||
@@ -1,64 +1,68 @@
|
||||
//using DistTestCore;
|
||||
//using DistTestCore.Codex;
|
||||
//using Newtonsoft.Json;
|
||||
//using NUnit.Framework;
|
||||
//using Utils;
|
||||
using CodexContractsPlugin;
|
||||
using CodexPlugin;
|
||||
using FileUtils;
|
||||
using NUnit.Framework;
|
||||
using Utils;
|
||||
|
||||
//namespace ContinuousTests.Tests
|
||||
//{
|
||||
// public class MarketplaceTest : ContinuousTest
|
||||
// {
|
||||
// public override int RequiredNumberOfNodes => 1;
|
||||
// public override TimeSpan RunTestEvery => TimeSpan.FromMinutes(10);
|
||||
// public override TestFailMode TestFailMode => TestFailMode.StopAfterFirstFailure;
|
||||
// public override int EthereumAccountIndex => 200;
|
||||
// public override string CustomK8sNamespace => "codex-continuous-marketplace";
|
||||
|
||||
// private readonly uint numberOfSlots = 3;
|
||||
// private readonly ByteSize fileSize = 10.MB();
|
||||
// private readonly TestToken pricePerSlotPerSecond = 10.TestTokens();
|
||||
/// manual test locally.
|
||||
|
||||
// private TestFile file = null!;
|
||||
// private ContentId? cid;
|
||||
// private string purchaseId = string.Empty;
|
||||
|
||||
// [TestMoment(t: Zero)]
|
||||
// public void NodePostsStorageRequest()
|
||||
// {
|
||||
// var contractDuration = TimeSpan.FromMinutes(8);
|
||||
// decimal totalDurationSeconds = Convert.ToDecimal(contractDuration.TotalSeconds);
|
||||
// var expectedTotalCost = numberOfSlots * pricePerSlotPerSecond.Amount * (totalDurationSeconds + 1) * 1000000;
|
||||
namespace ContinuousTests.Tests
|
||||
{
|
||||
public class MarketplaceTest : ContinuousTest
|
||||
{
|
||||
public override int RequiredNumberOfNodes => 1;
|
||||
public override TimeSpan RunTestEvery => TimeSpan.FromMinutes(10);
|
||||
public override TestFailMode TestFailMode => TestFailMode.StopAfterFirstFailure;
|
||||
|
||||
// file = FileManager.GenerateTestFile(fileSize);
|
||||
private readonly uint numberOfSlots = 3;
|
||||
private readonly ByteSize fileSize = 10.MB();
|
||||
private readonly TestToken pricePerSlotPerSecond = 10.TestTokens();
|
||||
|
||||
// NodeRunner.RunNode((codexAccess, marketplaceAccess) =>
|
||||
// {
|
||||
// cid = UploadFile(codexAccess.Node, file);
|
||||
// Assert.That(cid, Is.Not.Null);
|
||||
private TrackedFile file = null!;
|
||||
private ContentId? cid;
|
||||
private string purchaseId = string.Empty;
|
||||
|
||||
// purchaseId = marketplaceAccess.RequestStorage(
|
||||
// contentId: cid!,
|
||||
// pricePerSlotPerSecond: pricePerSlotPerSecond,
|
||||
// requiredCollateral: 100.TestTokens(),
|
||||
// minRequiredNumberOfNodes: numberOfSlots,
|
||||
// proofProbability: 10,
|
||||
// duration: contractDuration);
|
||||
[TestMoment(t: Zero)]
|
||||
public void NodePostsStorageRequest()
|
||||
{
|
||||
var contractDuration = TimeSpan.FromMinutes(8);
|
||||
decimal totalDurationSeconds = Convert.ToDecimal(contractDuration.TotalSeconds);
|
||||
var expectedTotalCost = numberOfSlots * pricePerSlotPerSecond.Amount * (totalDurationSeconds + 1) * 1000000;
|
||||
|
||||
// Assert.That(!string.IsNullOrEmpty(purchaseId));
|
||||
file = FileManager.GenerateFile(fileSize);
|
||||
|
||||
// WaitForContractToStart(codexAccess, purchaseId);
|
||||
// });
|
||||
// }
|
||||
NodeRunner.RunNode(
|
||||
s => s.WithName("Buyer"),
|
||||
node =>
|
||||
{
|
||||
cid = node.UploadFile(file);
|
||||
Assert.That(cid, Is.Not.Null);
|
||||
|
||||
// [TestMoment(t: MinuteFive + MinuteOne)]
|
||||
// public void StoredDataIsAvailableAfterThreeDays()
|
||||
// {
|
||||
// NodeRunner.RunNode((codexAccess, marketplaceAccess) =>
|
||||
// {
|
||||
// var result = DownloadFile(codexAccess.Node, cid!);
|
||||
purchaseId = node.Marketplace.RequestStorage(
|
||||
contentId: cid!,
|
||||
pricePerSlotPerSecond: pricePerSlotPerSecond,
|
||||
requiredCollateral: 100.TestTokens(),
|
||||
minRequiredNumberOfNodes: numberOfSlots,
|
||||
proofProbability: 10,
|
||||
duration: contractDuration);
|
||||
|
||||
// file.AssertIsEqual(result);
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
Assert.That(!string.IsNullOrEmpty(purchaseId));
|
||||
|
||||
WaitForContractToStart(codexAccess, purchaseId);
|
||||
});
|
||||
}
|
||||
|
||||
[TestMoment(t: MinuteFive + MinuteOne)]
|
||||
public void StoredDataIsAvailableAfterThreeDays()
|
||||
{
|
||||
NodeRunner.RunNode((codexAccess, marketplaceAccess) =>
|
||||
{
|
||||
var result = DownloadFile(codexAccess.Node, cid!);
|
||||
|
||||
file.AssertIsEqual(result);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,54 +1,51 @@
|
||||
//using DistTestCore;
|
||||
//using DistTestCore.Codex;
|
||||
//using NUnit.Framework;
|
||||
using CodexPlugin;
|
||||
using FileUtils;
|
||||
using NUnit.Framework;
|
||||
using Utils;
|
||||
|
||||
//namespace ContinuousTests.Tests
|
||||
//{
|
||||
// public class TransientNodeTest : ContinuousTest
|
||||
// {
|
||||
// public override int RequiredNumberOfNodes => 3;
|
||||
// public override TimeSpan RunTestEvery => TimeSpan.FromMinutes(1);
|
||||
// public override TestFailMode TestFailMode => TestFailMode.StopAfterFirstFailure;
|
||||
// public override string CustomK8sNamespace => nameof(TransientNodeTest).ToLowerInvariant();
|
||||
// public override int EthereumAccountIndex => 201;
|
||||
namespace ContinuousTests.Tests
|
||||
{
|
||||
public class TransientNodeTest : ContinuousTest
|
||||
{
|
||||
public override int RequiredNumberOfNodes => 3;
|
||||
public override TimeSpan RunTestEvery => TimeSpan.FromMinutes(1);
|
||||
public override TestFailMode TestFailMode => TestFailMode.StopAfterFirstFailure;
|
||||
public override string CustomK8sNamespace => nameof(TransientNodeTest).ToLowerInvariant();
|
||||
|
||||
// private TestFile file = null!;
|
||||
// private ContentId cid = null!;
|
||||
private TrackedFile file = null!;
|
||||
private ContentId cid = null!;
|
||||
|
||||
// private CodexAccess UploadBootstapNode { get { return Nodes[0]; } }
|
||||
// private CodexAccess DownloadBootstapNode { get { return Nodes[1]; } }
|
||||
// private CodexAccess IntermediateNode { get { return Nodes[2]; } }
|
||||
private ICodexNode UploadBootstapNode { get { return Nodes[0]; } }
|
||||
private ICodexNode DownloadBootstapNode { get { return Nodes[1]; } }
|
||||
private ICodexNode IntermediateNode { get { return Nodes[2]; } }
|
||||
|
||||
// [TestMoment(t: 0)]
|
||||
// public void UploadWithTransientNode()
|
||||
// {
|
||||
// file = FileManager.GenerateTestFile(10.MB());
|
||||
[TestMoment(t: 0)]
|
||||
public void UploadWithTransientNode()
|
||||
{
|
||||
file = FileManager.GenerateFile(10.MB());
|
||||
|
||||
// NodeRunner.RunNode(UploadBootstapNode, (codexAccess, marketplaceAccess, lifecycle) =>
|
||||
// {
|
||||
// cid = UploadFile(codexAccess, file)!;
|
||||
// Assert.That(cid, Is.Not.Null);
|
||||
NodeRunner.RunNode(UploadBootstapNode,
|
||||
s => s.WithName("TransientUploader"),
|
||||
node =>
|
||||
{
|
||||
cid = node.UploadFile(file);
|
||||
Assert.That(cid, Is.Not.Null);
|
||||
|
||||
// var dlt = Task.Run(() =>
|
||||
// {
|
||||
// Thread.Sleep(10000);
|
||||
// lifecycle.DownloadLog(codexAccess.Container);
|
||||
// });
|
||||
var resultFile = IntermediateNode.DownloadContent(cid);
|
||||
file.AssertIsEqual(resultFile);
|
||||
});
|
||||
}
|
||||
|
||||
// var resultFile = DownloadFile(IntermediateNode, cid);
|
||||
// dlt.Wait();
|
||||
// file.AssertIsEqual(resultFile);
|
||||
// });
|
||||
// }
|
||||
|
||||
// [TestMoment(t: 30)]
|
||||
// public void DownloadWithTransientNode()
|
||||
// {
|
||||
// NodeRunner.RunNode(DownloadBootstapNode, (codexAccess, marketplaceAccess, lifecycle) =>
|
||||
// {
|
||||
// var resultFile = DownloadFile(codexAccess, cid);
|
||||
// file.AssertIsEqual(resultFile);
|
||||
// });
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
[TestMoment(t: MinuteOne)]
|
||||
public void DownloadWithTransientNode()
|
||||
{
|
||||
NodeRunner.RunNode(DownloadBootstapNode,
|
||||
s => s.WithName("TransientDownloader"),
|
||||
node =>
|
||||
{
|
||||
var resultFile = node.DownloadContent(cid);
|
||||
file.AssertIsEqual(resultFile);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using CodexPlugin;
|
||||
using FileUtils;
|
||||
using Logging;
|
||||
using Newtonsoft.Json;
|
||||
using NUnit.Framework;
|
||||
using Utils;
|
||||
|
||||
@@ -22,9 +21,6 @@ namespace ContinuousTests.Tests
|
||||
[TestMoment(t: Zero)]
|
||||
public void UploadTestFile()
|
||||
{
|
||||
LogBlockExchangeStatus(Nodes[0], "Before upload");
|
||||
LogBlockExchangeStatus(Nodes[1], "Before upload");
|
||||
|
||||
file = FileManager.GenerateFile(size);
|
||||
|
||||
LogStoredBytes(Nodes[0]);
|
||||
@@ -38,27 +34,9 @@ namespace ContinuousTests.Tests
|
||||
{
|
||||
TrackedFile? dl = null;
|
||||
|
||||
try
|
||||
{
|
||||
LogBytesPerMillisecond(() => dl = Nodes[1].DownloadContent(cid!));
|
||||
LogBytesPerMillisecond(() => dl = Nodes[1].DownloadContent(cid!));
|
||||
|
||||
file.AssertIsEqual(dl);
|
||||
}
|
||||
catch
|
||||
{
|
||||
LogRepoStore(Nodes[0]);
|
||||
LogRepoStore(Nodes[1]);
|
||||
throw;
|
||||
}
|
||||
|
||||
LogBlockExchangeStatus(Nodes[0], "After download");
|
||||
LogBlockExchangeStatus(Nodes[1], "After download");
|
||||
}
|
||||
|
||||
private void LogRepoStore(ICodexNode codexNode)
|
||||
{
|
||||
//var response = codexNode.GetDebugRepoStore();
|
||||
//Log.Log($"{codexNode.GetName()} has {string.Join(",", response.Select(r => r.cid))}");
|
||||
file.AssertIsEqual(dl);
|
||||
}
|
||||
|
||||
private void LogStoredBytes(ICodexNode node)
|
||||
@@ -87,11 +65,5 @@ namespace ContinuousTests.Tests
|
||||
var bytesPerMs = totalBytes / totalMs;
|
||||
Log.Log($"Bytes per millisecond: {bytesPerMs}");
|
||||
}
|
||||
|
||||
private void LogBlockExchangeStatus(ICodexNode codexNode, string msg)
|
||||
{
|
||||
//var response = codexNode.GetDebugBlockExchange();
|
||||
//Log.Log($"{codexNode.GetName()} {msg}: {JsonConvert.SerializeObject(response)}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ Report for: 08-2023
|
||||
(Stopped: The number of tests that can successfully run on the test-net is not high enough to justify the cost of leaving it running.)
|
||||
|
||||
## Deployment Configuration
|
||||
Continous Test-net is deployed to the kubernetes cluster with the following configuration:
|
||||
Continuous Test-net is deployed to the kubernetes cluster with the following configuration:
|
||||
|
||||
5x Codex Nodes:
|
||||
- Log-level: Trace
|
||||
|
||||
@@ -11,7 +11,7 @@ Report for: 07-2023
|
||||
(Faulted: Tests fail with such frequency that the information gathered does not justify the cost of leaving the test-net running.)
|
||||
|
||||
## Deployment Configuration
|
||||
Continous Test-net is deployed to the kubernetes cluster with the following configuration:
|
||||
Continuous Test-net is deployed to the kubernetes cluster with the following configuration:
|
||||
|
||||
5x Codex Nodes:
|
||||
- Log-level: Trace
|
||||
|
||||
@@ -11,7 +11,7 @@ Report for: 09-2023
|
||||
(Stopped: The number of tests that can successfully run on the test-net is not high enough to justify the cost of leaving it running.)
|
||||
|
||||
## Deployment Configuration
|
||||
Continous Test-net is deployed to the kubernetes cluster with the following configuration:
|
||||
Continuous Test-net is deployed to the kubernetes cluster with the following configuration:
|
||||
|
||||
5x Codex Nodes:
|
||||
- Log-level: Trace
|
||||
|
||||
@@ -6,6 +6,7 @@ using MetricsPlugin;
|
||||
using Nethereum.Hex.HexConvertors.Extensions;
|
||||
using NUnit.Framework;
|
||||
using Utils;
|
||||
using Request = CodexContractsPlugin.Marketplace.Request;
|
||||
|
||||
namespace CodexTests.BasicTests
|
||||
{
|
||||
@@ -60,6 +61,7 @@ namespace CodexTests.BasicTests
|
||||
var contracts = Ci.StartCodexContracts(geth);
|
||||
|
||||
var seller = AddCodex(s => s
|
||||
.WithName("Seller")
|
||||
.WithLogLevel(CodexLogLevel.Trace, new CodexLogCustomTopics(CodexLogLevel.Error, CodexLogLevel.Error, CodexLogLevel.Warn))
|
||||
.WithStorageQuota(11.GB())
|
||||
.EnableMarketplace(geth, contracts, initialEth: 10.Eth(), initialTokens: sellerInitialBalance, isValidator: true)
|
||||
@@ -75,6 +77,7 @@ namespace CodexTests.BasicTests
|
||||
var testFile = GenerateTestFile(fileSize);
|
||||
|
||||
var buyer = AddCodex(s => s
|
||||
.WithName("Buyer")
|
||||
.WithBootstrapNode(seller)
|
||||
.EnableMarketplace(geth, contracts, initialEth: 10.Eth(), initialTokens: buyerInitialBalance));
|
||||
|
||||
@@ -90,27 +93,12 @@ namespace CodexTests.BasicTests
|
||||
|
||||
purchaseContract.WaitForStorageContractStarted(fileSize);
|
||||
|
||||
var requests = contracts.GetStorageRequests(GetTestRunTimeRange());
|
||||
Assert.That(requests.Length, Is.EqualTo(1));
|
||||
var request = requests.Single();
|
||||
Assert.That(contracts.GetRequestState(request), Is.EqualTo(RequestState.Started));
|
||||
Assert.That(request.ClientAddress, Is.EqualTo(buyer.EthAddress));
|
||||
Assert.That(request.Ask.Slots, Is.EqualTo(1));
|
||||
|
||||
AssertBalance(contracts, seller, Is.LessThan(sellerInitialBalance), "Collateral was not placed.");
|
||||
|
||||
var requestFulfilledEvents = contracts.GetRequestFulfilledEvents(GetTestRunTimeRange());
|
||||
Assert.That(requestFulfilledEvents.Length, Is.EqualTo(1));
|
||||
CollectionAssert.AreEqual(request.RequestId, requestFulfilledEvents[0].RequestId);
|
||||
var filledSlotEvents = contracts.GetSlotFilledEvents(GetTestRunTimeRange());
|
||||
Assert.That(filledSlotEvents.Length, Is.EqualTo(1));
|
||||
var filledSlotEvent = filledSlotEvents.Single();
|
||||
Assert.That(filledSlotEvent.SlotIndex.IsZero);
|
||||
Assert.That(filledSlotEvent.RequestId.ToHex(), Is.EqualTo(request.RequestId.ToHex()));
|
||||
Assert.That(filledSlotEvent.Host, Is.EqualTo(seller.EthAddress));
|
||||
|
||||
var slotHost = contracts.GetSlotHost(request, 0);
|
||||
Assert.That(slotHost, Is.EqualTo(seller.EthAddress));
|
||||
var request = GetOnChainStorageRequest(contracts);
|
||||
AssertStorageRequest(request, contracts, buyer);
|
||||
AssertSlotFilledEvents(contracts, request, seller);
|
||||
AssertContractSlot(contracts, request, 0, seller);
|
||||
|
||||
purchaseContract.WaitForStorageContractFinished();
|
||||
|
||||
@@ -118,12 +106,7 @@ namespace CodexTests.BasicTests
|
||||
AssertBalance(contracts, buyer, Is.LessThan(buyerInitialBalance), "Buyer was not charged for storage.");
|
||||
Assert.That(contracts.GetRequestState(request), Is.EqualTo(RequestState.Finished));
|
||||
|
||||
var log = Ci.DownloadLog(seller);
|
||||
log.AssertLogContains("Received a request to store a slot!");
|
||||
log.AssertLogContains("Received proof challenge");
|
||||
log.AssertLogContains("Collecting input for proof");
|
||||
|
||||
//CheckLogForErrors(seller, buyer);
|
||||
// waiting for block retransmit fix: CheckLogForErrors(seller, buyer);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -142,5 +125,38 @@ namespace CodexTests.BasicTests
|
||||
Assert.That(bootN, Is.EqualTo(followN));
|
||||
Assert.That(discN, Is.LessThan(bootN));
|
||||
}
|
||||
|
||||
private void AssertSlotFilledEvents(ICodexContracts contracts, Request request, ICodexNode seller)
|
||||
{
|
||||
var requestFulfilledEvents = contracts.GetRequestFulfilledEvents(GetTestRunTimeRange());
|
||||
Assert.That(requestFulfilledEvents.Length, Is.EqualTo(1));
|
||||
CollectionAssert.AreEqual(request.RequestId, requestFulfilledEvents[0].RequestId);
|
||||
var filledSlotEvents = contracts.GetSlotFilledEvents(GetTestRunTimeRange());
|
||||
Assert.That(filledSlotEvents.Length, Is.EqualTo(1));
|
||||
var filledSlotEvent = filledSlotEvents.Single();
|
||||
Assert.That(filledSlotEvent.SlotIndex.IsZero);
|
||||
Assert.That(filledSlotEvent.RequestId.ToHex(), Is.EqualTo(request.RequestId.ToHex()));
|
||||
Assert.That(filledSlotEvent.Host, Is.EqualTo(seller.EthAddress));
|
||||
}
|
||||
|
||||
private void AssertStorageRequest(Request request, ICodexContracts contracts, ICodexNode buyer)
|
||||
{
|
||||
Assert.That(contracts.GetRequestState(request), Is.EqualTo(RequestState.Started));
|
||||
Assert.That(request.ClientAddress, Is.EqualTo(buyer.EthAddress));
|
||||
Assert.That(request.Ask.Slots, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
private Request GetOnChainStorageRequest(ICodexContracts contracts)
|
||||
{
|
||||
var requests = contracts.GetStorageRequests(GetTestRunTimeRange());
|
||||
Assert.That(requests.Length, Is.EqualTo(1));
|
||||
return requests.Single();
|
||||
}
|
||||
|
||||
private void AssertContractSlot(ICodexContracts contracts, Request request, int contractSlotIndex, ICodexNode expectedSeller)
|
||||
{
|
||||
var slotHost = contracts.GetSlotHost(request, contractSlotIndex);
|
||||
Assert.That(slotHost, Is.EqualTo(expectedSeller.EthAddress));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@ namespace CodexTests.DownloadConnectivityTests
|
||||
[Test]
|
||||
[Combinatorial]
|
||||
public void FullyConnectedDownloadTest(
|
||||
[Values(3, 5)] int numberOfNodes,
|
||||
[Values(10, 80)] int sizeMBs)
|
||||
[Values(2, 5)] int numberOfNodes,
|
||||
[Values(1, 10)] int sizeMBs)
|
||||
{
|
||||
AddCodex(numberOfNodes);
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@ namespace CodexTests.PeerDiscoveryTests
|
||||
[TestCase(3)]
|
||||
[TestCase(5)]
|
||||
[TestCase(10)]
|
||||
[TestCase(20)]
|
||||
public void NodeChainTest(int chainLength)
|
||||
{
|
||||
var node = Ci.StartCodexNode();
|
||||
|
||||
@@ -39,7 +39,6 @@ namespace CodexTests.PeerDiscoveryTests
|
||||
[TestCase(2)]
|
||||
[TestCase(3)]
|
||||
[TestCase(10)]
|
||||
[TestCase(20)]
|
||||
public void VariableNodes(int number)
|
||||
{
|
||||
AddCodex(number);
|
||||
|
||||
@@ -1,19 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="LibGit2Sharp" Version="0.28.0" />
|
||||
<PackageReference Include="NUnit" Version="3.13.3" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Tests\CodexTests\CodexTests.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,74 +0,0 @@
|
||||
using LibGit2Sharp;
|
||||
using CodexTests.BasicTests;
|
||||
using CodexPlugin;
|
||||
using System.Diagnostics;
|
||||
|
||||
public static class Program
|
||||
{
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("Hello, World!");
|
||||
|
||||
var codexPath = @"D:\Projects\nim-codex";
|
||||
|
||||
using var repo = new Repository(codexPath);
|
||||
var masterBranch = repo.Branches.Single(b => b.FriendlyName == "master");
|
||||
var take = masterBranch.Commits.Take(10).ToArray();
|
||||
foreach (var c in take)
|
||||
{
|
||||
RunWith(c);
|
||||
}
|
||||
|
||||
Console.ReadLine();
|
||||
}
|
||||
|
||||
private static void RunWith(Commit c)
|
||||
{
|
||||
var shortSha = c.Sha.Substring(0, 7);
|
||||
var image = $"codexstorage/nim-codex:sha-{shortSha}-dist-tests";
|
||||
CodexContainerRecipe.DockerImageOverride = image;
|
||||
|
||||
if (!DoesExist(image))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Console.WriteLine("Running test for: " + c.MessageShort);
|
||||
|
||||
var test = new ExampleTests();
|
||||
test.GlobalSetup();
|
||||
test.SetUpDistTest();
|
||||
|
||||
try
|
||||
{
|
||||
test.CodexLogExample();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine("test ex: " + ex);
|
||||
}
|
||||
|
||||
test.TearDownDistTest();
|
||||
test.GlobalTearDown();
|
||||
|
||||
Console.WriteLine("Test passed");
|
||||
}
|
||||
catch (Exception a)
|
||||
{
|
||||
Console.WriteLine("ex: " + a);
|
||||
}
|
||||
}
|
||||
|
||||
private static bool DoesExist(string image)
|
||||
{
|
||||
var info = new ProcessStartInfo("docker", "image pull " + image);
|
||||
info.RedirectStandardOutput = false;
|
||||
var process = Process.Start(info);
|
||||
process.WaitForExit();
|
||||
|
||||
return process.ExitCode == 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MetricsPlugin", "ProjectPlu
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CodexContinuousTests", "Tests\CodexContinuousTests\CodexContinuousTests.csproj", "{ADEC06CF-6F3A-44C5-AA57-EAB94124AC82}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CodexTestsLong", "Tests\CodexLongTests\CodexTestsLong.csproj", "{0C2D067F-053C-45A8-AE0D-4EB388E77C89}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CodexTests", "Tests\CodexTests\CodexTests.csproj", "{562EC700-6984-4C9A-83BF-3BF4E3EB1A64}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DistTestCore", "Tests\DistTestCore\DistTestCore.csproj", "{E849B7BA-FDCC-4CFF-998F-845ED2F1BF40}"
|
||||
@@ -57,8 +59,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "GethConnector", "Framework\
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DiscordRewards", "Framework\DiscordRewards\DiscordRewards.csproj", "{B07820C4-309F-4454-BCC1-1D4902C9C67B}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "CommitBlamer", "Tools\CommitBlamer\CommitBlamer.csproj", "{DC08EAA2-42F4-49EE-90C8-44673094BE0A}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@@ -113,6 +113,10 @@ Global
|
||||
{ADEC06CF-6F3A-44C5-AA57-EAB94124AC82}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{ADEC06CF-6F3A-44C5-AA57-EAB94124AC82}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{ADEC06CF-6F3A-44C5-AA57-EAB94124AC82}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0C2D067F-053C-45A8-AE0D-4EB388E77C89}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0C2D067F-053C-45A8-AE0D-4EB388E77C89}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0C2D067F-053C-45A8-AE0D-4EB388E77C89}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0C2D067F-053C-45A8-AE0D-4EB388E77C89}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{562EC700-6984-4C9A-83BF-3BF4E3EB1A64}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{562EC700-6984-4C9A-83BF-3BF4E3EB1A64}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{562EC700-6984-4C9A-83BF-3BF4E3EB1A64}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
@@ -157,10 +161,6 @@ Global
|
||||
{B07820C4-309F-4454-BCC1-1D4902C9C67B}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B07820C4-309F-4454-BCC1-1D4902C9C67B}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B07820C4-309F-4454-BCC1-1D4902C9C67B}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{DC08EAA2-42F4-49EE-90C8-44673094BE0A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{DC08EAA2-42F4-49EE-90C8-44673094BE0A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{DC08EAA2-42F4-49EE-90C8-44673094BE0A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{DC08EAA2-42F4-49EE-90C8-44673094BE0A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
@@ -178,6 +178,7 @@ Global
|
||||
{8B39F251-F948-40AE-8922-3D8C4E529A86} = {8F1F1C2A-E313-4E0C-BE40-58FB0BA91124}
|
||||
{8DE8FF65-23CB-4FB3-8BE5-6C0BEC4BAA97} = {8F1F1C2A-E313-4E0C-BE40-58FB0BA91124}
|
||||
{ADEC06CF-6F3A-44C5-AA57-EAB94124AC82} = {88C2A621-8A98-4D07-8625-7900FC8EF89E}
|
||||
{0C2D067F-053C-45A8-AE0D-4EB388E77C89} = {88C2A621-8A98-4D07-8625-7900FC8EF89E}
|
||||
{562EC700-6984-4C9A-83BF-3BF4E3EB1A64} = {88C2A621-8A98-4D07-8625-7900FC8EF89E}
|
||||
{E849B7BA-FDCC-4CFF-998F-845ED2F1BF40} = {88C2A621-8A98-4D07-8625-7900FC8EF89E}
|
||||
{3417D508-E2F4-4974-8988-BB124046D9E2} = {7591C5B3-D86E-4AE4-8ED2-B272D17FE7E3}
|
||||
@@ -189,7 +190,6 @@ Global
|
||||
{570C0DBE-0EF1-47B5-9A3B-E1F7895722A5} = {7591C5B3-D86E-4AE4-8ED2-B272D17FE7E3}
|
||||
{F730DA73-1C92-4107-BCFB-D33759DAB0C3} = {81AE04BC-CBFA-4E6F-B039-8208E9AFAAE7}
|
||||
{B07820C4-309F-4454-BCC1-1D4902C9C67B} = {81AE04BC-CBFA-4E6F-B039-8208E9AFAAE7}
|
||||
{DC08EAA2-42F4-49EE-90C8-44673094BE0A} = {7591C5B3-D86E-4AE4-8ED2-B272D17FE7E3}
|
||||
EndGlobalSection
|
||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||
SolutionGuid = {237BF0AA-9EC4-4659-AD9A-65DEB974250C}
|
||||
|
||||
Reference in New Issue
Block a user