Compare commits

..
Author SHA1 Message Date
benbierens 17564957cb POC: codex commit blamer 2024-02-26 12:50:51 +01:00
26 changed files with 321 additions and 208 deletions
+1 -1
View File
@@ -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@v4
uses: azure/setup-kubectl@releases/v4.0.0
with:
version: ${{ env.KUBE_VERSION }}
+1 -1
View File
@@ -57,7 +57,7 @@ jobs:
[[ -n "${{ inputs.command }}" ]] && COMMAND="${{ inputs.command }}" || COMMAND="${{ env.COMMAND }}"
- name: Kubectl - Install ${{ env.KUBE_VERSION }}
uses: azure/setup-kubectl@v4
uses: azure/setup-kubectl@releases/v4.0.0
with:
version: ${{ env.KUBE_VERSION }}
+2 -1
View File
@@ -1,4 +1,5 @@
.vs
obj
bin
.vscode
.vscode
Tools/CommitBlamer/CodexTestLogs
+1 -1
View File
@@ -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 `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.
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.
+1 -1
View File
@@ -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/CodexContinuousTests/Tests`
1. Add new code files to `Tests/CodexContinousTests/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-965529d-dist-tests";
public static string DockerImage { get; } = "codexstorage/codex-contracts-eth:sha-b5f3399-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; }
+1 -1
View File
@@ -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/ContinuousTests
## Tests/ContinousTests
A console application that runs tests in an endless loop against a persistent deployment of Codex nodes.
Read more [HERE](/Tests/CodexContinuousTests/README.md)
+7 -23
View File
@@ -1,8 +1,7 @@
using CodexContractsPlugin;
using CodexPlugin;
using CodexPlugin;
using Core;
using DistTestCore;
using FileUtils;
using GethPlugin;
using Logging;
using MetricsPlugin;
@@ -33,7 +32,7 @@ namespace ContinuousTests
if (nodes != null)
{
NodeRunner = new NodeRunner(Nodes, configuration, Log);
NodeRunner = new NodeRunner(Nodes, configuration, Log, CustomK8sNamespace);
}
else
{
@@ -58,23 +57,15 @@ namespace ContinuousTests
{
if (Configuration.CodexDeployment.PrometheusContainer == null) throw new Exception("Expected prometheus to be part of Codex deployment.");
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);
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);
}
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
{
@@ -83,13 +74,6 @@ 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,6 +51,8 @@ namespace ContinuousTests
overviewLog.Log("");
var allTests = testFactory.CreateTests();
ClearAllCustomNamespaces(allTests, overviewLog);
var filteredTests = FilterTests(allTests, overviewLog);
if (!filteredTests.Any())
{
@@ -134,6 +136,21 @@ 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,6 +25,7 @@ namespace ContinuousTests
);
return new EntryPoint(log, lifecycleConfig, dataFilePath);
//DefaultContainerRecipe.TestsType = "continuous-tests";
}
private static string? GetKubeConfig(string kubeConfigFile)
+23 -19
View File
@@ -13,12 +13,14 @@ 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)
public NodeRunner(ICodexNode[] nodes, Configuration config, ILog log, string customNamespace)
{
this.nodes = nodes;
this.config = config;
this.log = log;
this.customNamespace = customNamespace;
}
public IDownloadedLog DownloadLog(RunningContainer container, int? tailLines = null)
@@ -39,34 +41,36 @@ 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
{
operation(node);
}
catch
{
DownloadLog(node.Container);
node.Stop();
throw;
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;
}
}
finally
{
node.Stop();
entryPoint.Tools.CreateWorkflow().DeleteNamespace();
}
}
private EntryPoint CreateEntryPoint()
{
return entryPointFactory.CreateEntryPoint(config.KubeConfigFile, config.DataPath, config.CodexDeployment.Metadata.KubeNamespace, log);
return entryPointFactory.CreateEntryPoint(config.KubeConfigFile, config.DataPath, customNamespace, log);
}
}
}
+1 -1
View File
@@ -4,7 +4,7 @@ public class Program
{
public static void Main(string[] args)
{
Console.WriteLine("Codex Continuous-Test-Runner.");
Console.WriteLine("Codex Continous-Test-Runner.");
var runner = new ContinuousTestRunner(args, Cancellation.Cts.Token);
@@ -1,68 +1,64 @@
using CodexContractsPlugin;
using CodexPlugin;
using FileUtils;
using NUnit.Framework;
using Utils;
//using DistTestCore;
//using DistTestCore.Codex;
//using Newtonsoft.Json;
//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";
/// manual test locally.
// private readonly uint numberOfSlots = 3;
// private readonly ByteSize fileSize = 10.MB();
// private readonly TestToken pricePerSlotPerSecond = 10.TestTokens();
// private TestFile file = null!;
// private ContentId? cid;
// private string purchaseId = string.Empty;
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;
// [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;
private readonly uint numberOfSlots = 3;
private readonly ByteSize fileSize = 10.MB();
private readonly TestToken pricePerSlotPerSecond = 10.TestTokens();
// file = FileManager.GenerateTestFile(fileSize);
private TrackedFile file = null!;
private ContentId? cid;
private string purchaseId = string.Empty;
// NodeRunner.RunNode((codexAccess, marketplaceAccess) =>
// {
// cid = UploadFile(codexAccess.Node, file);
// Assert.That(cid, Is.Not.Null);
[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;
// purchaseId = marketplaceAccess.RequestStorage(
// contentId: cid!,
// pricePerSlotPerSecond: pricePerSlotPerSecond,
// requiredCollateral: 100.TestTokens(),
// minRequiredNumberOfNodes: numberOfSlots,
// proofProbability: 10,
// duration: contractDuration);
file = FileManager.GenerateFile(fileSize);
// Assert.That(!string.IsNullOrEmpty(purchaseId));
NodeRunner.RunNode(
s => s.WithName("Buyer"),
node =>
{
cid = node.UploadFile(file);
Assert.That(cid, Is.Not.Null);
// WaitForContractToStart(codexAccess, purchaseId);
// });
// }
purchaseId = node.Marketplace.RequestStorage(
contentId: cid!,
pricePerSlotPerSecond: pricePerSlotPerSecond,
requiredCollateral: 100.TestTokens(),
minRequiredNumberOfNodes: numberOfSlots,
proofProbability: 10,
duration: contractDuration);
// [TestMoment(t: MinuteFive + MinuteOne)]
// public void StoredDataIsAvailableAfterThreeDays()
// {
// NodeRunner.RunNode((codexAccess, marketplaceAccess) =>
// {
// var result = DownloadFile(codexAccess.Node, cid!);
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);
});
}
}
}
// file.AssertIsEqual(result);
// });
// }
// }
//}
@@ -1,51 +1,54 @@
using CodexPlugin;
using FileUtils;
using NUnit.Framework;
using Utils;
//using DistTestCore;
//using DistTestCore.Codex;
//using NUnit.Framework;
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();
//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;
private TrackedFile file = null!;
private ContentId cid = null!;
// private TestFile file = null!;
// private ContentId cid = null!;
private ICodexNode UploadBootstapNode { get { return Nodes[0]; } }
private ICodexNode DownloadBootstapNode { get { return Nodes[1]; } }
private ICodexNode IntermediateNode { get { return Nodes[2]; } }
// private CodexAccess UploadBootstapNode { get { return Nodes[0]; } }
// private CodexAccess DownloadBootstapNode { get { return Nodes[1]; } }
// private CodexAccess IntermediateNode { get { return Nodes[2]; } }
[TestMoment(t: 0)]
public void UploadWithTransientNode()
{
file = FileManager.GenerateFile(10.MB());
// [TestMoment(t: 0)]
// public void UploadWithTransientNode()
// {
// file = FileManager.GenerateTestFile(10.MB());
NodeRunner.RunNode(UploadBootstapNode,
s => s.WithName("TransientUploader"),
node =>
{
cid = node.UploadFile(file);
Assert.That(cid, Is.Not.Null);
// NodeRunner.RunNode(UploadBootstapNode, (codexAccess, marketplaceAccess, lifecycle) =>
// {
// cid = UploadFile(codexAccess, file)!;
// Assert.That(cid, Is.Not.Null);
var resultFile = IntermediateNode.DownloadContent(cid);
file.AssertIsEqual(resultFile);
});
}
// var dlt = Task.Run(() =>
// {
// Thread.Sleep(10000);
// lifecycle.DownloadLog(codexAccess.Container);
// });
[TestMoment(t: MinuteOne)]
public void DownloadWithTransientNode()
{
NodeRunner.RunNode(DownloadBootstapNode,
s => s.WithName("TransientDownloader"),
node =>
{
var resultFile = node.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);
// });
// }
// }
//}
@@ -1,6 +1,7 @@
using CodexPlugin;
using FileUtils;
using Logging;
using Newtonsoft.Json;
using NUnit.Framework;
using Utils;
@@ -21,6 +22,9 @@ 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]);
@@ -34,9 +38,27 @@ namespace ContinuousTests.Tests
{
TrackedFile? dl = null;
LogBytesPerMillisecond(() => dl = Nodes[1].DownloadContent(cid!));
try
{
LogBytesPerMillisecond(() => dl = Nodes[1].DownloadContent(cid!));
file.AssertIsEqual(dl);
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))}");
}
private void LogStoredBytes(ICodexNode node)
@@ -65,5 +87,11 @@ 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
Continuous Test-net is deployed to the kubernetes cluster with the following configuration:
Continous 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
Continuous Test-net is deployed to the kubernetes cluster with the following configuration:
Continous 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
Continuous Test-net is deployed to the kubernetes cluster with the following configuration:
Continous Test-net is deployed to the kubernetes cluster with the following configuration:
5x Codex Nodes:
- Log-level: Trace
+25 -41
View File
@@ -6,7 +6,6 @@ using MetricsPlugin;
using Nethereum.Hex.HexConvertors.Extensions;
using NUnit.Framework;
using Utils;
using Request = CodexContractsPlugin.Marketplace.Request;
namespace CodexTests.BasicTests
{
@@ -61,7 +60,6 @@ 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)
@@ -77,7 +75,6 @@ namespace CodexTests.BasicTests
var testFile = GenerateTestFile(fileSize);
var buyer = AddCodex(s => s
.WithName("Buyer")
.WithBootstrapNode(seller)
.EnableMarketplace(geth, contracts, initialEth: 10.Eth(), initialTokens: buyerInitialBalance));
@@ -93,12 +90,27 @@ 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 request = GetOnChainStorageRequest(contracts);
AssertStorageRequest(request, contracts, buyer);
AssertSlotFilledEvents(contracts, request, seller);
AssertContractSlot(contracts, request, 0, 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));
var slotHost = contracts.GetSlotHost(request, 0);
Assert.That(slotHost, Is.EqualTo(seller.EthAddress));
purchaseContract.WaitForStorageContractFinished();
@@ -106,7 +118,12 @@ namespace CodexTests.BasicTests
AssertBalance(contracts, buyer, Is.LessThan(buyerInitialBalance), "Buyer was not charged for storage.");
Assert.That(contracts.GetRequestState(request), Is.EqualTo(RequestState.Finished));
// waiting for block retransmit fix: CheckLogForErrors(seller, buyer);
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);
}
[Test]
@@ -125,38 +142,5 @@ 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(2, 5)] int numberOfNodes,
[Values(1, 10)] int sizeMBs)
[Values(3, 5)] int numberOfNodes,
[Values(10, 80)] int sizeMBs)
{
AddCodex(numberOfNodes);
@@ -32,6 +32,7 @@ namespace CodexTests.PeerDiscoveryTests
[TestCase(3)]
[TestCase(5)]
[TestCase(10)]
[TestCase(20)]
public void NodeChainTest(int chainLength)
{
var node = Ci.StartCodexNode();
@@ -39,6 +39,7 @@ namespace CodexTests.PeerDiscoveryTests
[TestCase(2)]
[TestCase(3)]
[TestCase(10)]
[TestCase(20)]
public void VariableNodes(int number)
{
AddCodex(number);
+19
View File
@@ -0,0 +1,19 @@
<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>
+74
View File
@@ -0,0 +1,74 @@
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;
}
}
+7 -7
View File
@@ -35,8 +35,6 @@ 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}"
@@ -59,6 +57,8 @@ 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,10 +113,6 @@ 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
@@ -161,6 +157,10 @@ 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,7 +178,6 @@ 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}
@@ -190,6 +189,7 @@ 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}