Merge branch 'master' into feature/bot-upgrade
# Conflicts: # Tests/CodexTests/BasicTests/ExampleTests.cs
This commit is contained in:
commit
8c8b1748ee
|
@ -1,4 +1,4 @@
|
|||
name: Docker - Reusable
|
||||
name: Reusable - Docker
|
||||
|
||||
|
||||
on:
|
||||
|
@ -66,26 +66,26 @@ jobs:
|
|||
PLATFORM: ${{ format('{0}/{1}', 'linux', matrix.target.arch) }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Docker - Meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.DOCKER_REPO }}
|
||||
|
||||
- name: Docker - Set up Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Docker - Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
||||
- name: Docker - Build and Push by digest
|
||||
id: build
|
||||
uses: docker/build-push-action@v4
|
||||
uses: docker/build-push-action@v5
|
||||
with:
|
||||
context: .
|
||||
file: ${{ env.DOCKER_FILE }}
|
||||
|
@ -101,9 +101,9 @@ jobs:
|
|||
touch "/tmp/digests/${digest#sha256:}"
|
||||
|
||||
- name: Docker - Upload digest
|
||||
uses: actions/upload-artifact@v3
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: digests
|
||||
name: digests-${{ matrix.target.arch }}
|
||||
path: /tmp/digests/*
|
||||
if-no-files-found: error
|
||||
retention-days: 1
|
||||
|
@ -139,17 +139,18 @@ jobs:
|
|||
fi
|
||||
|
||||
- name: Docker - Download digests
|
||||
uses: actions/download-artifact@v3
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: digests
|
||||
pattern: digests-*
|
||||
merge-multiple: true
|
||||
path: /tmp/digests
|
||||
|
||||
- name: Docker - Set up Buildx
|
||||
uses: docker/setup-buildx-action@v2
|
||||
uses: docker/setup-buildx-action@v3
|
||||
|
||||
- name: Docker - Meta
|
||||
id: meta
|
||||
uses: docker/metadata-action@v4
|
||||
uses: docker/metadata-action@v5
|
||||
with:
|
||||
images: ${{ env.DOCKER_REPO }}
|
||||
flavor: |
|
||||
|
@ -161,7 +162,7 @@ jobs:
|
|||
type=sha,enable=${{ env.TAG_SHA }}
|
||||
|
||||
- name: Docker - Login to Docker Hub
|
||||
uses: docker/login-action@v2
|
||||
uses: docker/login-action@v3
|
||||
with:
|
||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
||||
|
|
|
@ -91,7 +91,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: ${{ inputs.workflow_source }}
|
||||
|
||||
|
@ -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@v3
|
||||
uses: azure/setup-kubectl@v4
|
||||
with:
|
||||
version: ${{ env.KUBE_VERSION }}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ jobs:
|
|||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Variables
|
||||
run: |
|
||||
|
@ -57,7 +57,7 @@ jobs:
|
|||
[[ -n "${{ inputs.command }}" ]] && COMMAND="${{ inputs.command }}" || COMMAND="${{ env.COMMAND }}"
|
||||
|
||||
- name: Kubectl - Install ${{ env.KUBE_VERSION }}
|
||||
uses: azure/setup-kubectl@v3
|
||||
uses: azure/setup-kubectl@v4
|
||||
with:
|
||||
version: ${{ env.KUBE_VERSION }}
|
||||
|
||||
|
|
|
@ -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";
|
||||
|
|
|
@ -6,8 +6,12 @@ namespace CodexPlugin
|
|||
{
|
||||
public class CodexDeployment
|
||||
{
|
||||
public CodexDeployment(CodexInstance[] codexInstances, GethDeployment gethDeployment, CodexContractsDeployment codexContractsDeployment, RunningContainers? prometheusContainer, RunningContainers? discordBotContainer, DeploymentMetadata metadata)
|
||||
public CodexDeployment(CodexInstance[] codexInstances, GethDeployment gethDeployment,
|
||||
CodexContractsDeployment codexContractsDeployment, RunningContainers? prometheusContainer,
|
||||
RunningContainers? discordBotContainer, DeploymentMetadata metadata,
|
||||
String id)
|
||||
{
|
||||
Id = id;
|
||||
CodexInstances = codexInstances;
|
||||
GethDeployment = gethDeployment;
|
||||
CodexContractsDeployment = codexContractsDeployment;
|
||||
|
@ -16,6 +20,7 @@ namespace CodexPlugin
|
|||
Metadata = metadata;
|
||||
}
|
||||
|
||||
public String Id { get; }
|
||||
public CodexInstance[] CodexInstances { get; }
|
||||
public GethDeployment GethDeployment { get; }
|
||||
public CodexContractsDeployment CodexContractsDeployment { get; }
|
||||
|
@ -38,7 +43,10 @@ namespace CodexPlugin
|
|||
|
||||
public class DeploymentMetadata
|
||||
{
|
||||
public DeploymentMetadata(string name, DateTime startUtc, DateTime finishedUtc, string kubeNamespace, int numberOfCodexNodes, int numberOfValidators, int storageQuotaMB, CodexLogLevel codexLogLevel, int initialTestTokens, int minPrice, int maxCollateral, int maxDuration, int blockTTL, int blockMI, int blockMN)
|
||||
public DeploymentMetadata(string name, DateTime startUtc, DateTime finishedUtc, string kubeNamespace,
|
||||
int numberOfCodexNodes, int numberOfValidators, int storageQuotaMB, CodexLogLevel codexLogLevel,
|
||||
int initialTestTokens, int minPrice, int maxCollateral, int maxDuration, int blockTTL, int blockMI,
|
||||
int blockMN)
|
||||
{
|
||||
Name = name;
|
||||
StartUtc = startUtc;
|
||||
|
@ -73,4 +81,4 @@ namespace CodexPlugin
|
|||
public int BlockMI { get; }
|
||||
public int BlockMN { get; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -56,7 +56,8 @@ namespace CodexPlugin
|
|||
|
||||
if (response == "Purchasing not available" ||
|
||||
response == "Expiry required" ||
|
||||
response == "Expiry needs to be in future")
|
||||
response == "Expiry needs to be in future" ||
|
||||
response == "Expiry has to be before the request's end (now + duration)")
|
||||
{
|
||||
throw new InvalidOperationException(response);
|
||||
}
|
||||
|
|
|
@ -27,10 +27,11 @@ namespace ContinuousTests
|
|||
var startTime = DateTime.UtcNow;
|
||||
|
||||
var overviewLog = new LogSplitter(
|
||||
new FixtureLog(logConfig, startTime, "Overview"),
|
||||
new FixtureLog(logConfig, startTime, config.CodexDeployment.Id, "Overview"),
|
||||
new ConsoleLog()
|
||||
);
|
||||
var statusLog = new StatusLog(logConfig, startTime, "continuous-tests", "ContinuousTestRun");
|
||||
var statusLog = new StatusLog(logConfig, startTime, "continuous-tests", config.CodexDeployment.Id,
|
||||
"ContinuousTestRun");
|
||||
|
||||
overviewLog.Log("Initializing...");
|
||||
|
||||
|
|
|
@ -25,7 +25,9 @@ namespace ContinuousTests
|
|||
private readonly string testName;
|
||||
private static int failureCount = 0;
|
||||
|
||||
public SingleTestRun(EntryPointFactory entryPointFactory, TaskFactory taskFactory, Configuration config, ILog overviewLog, StatusLog statusLog, TestHandle handle, StartupChecker startupChecker, CancellationToken cancelToken)
|
||||
public SingleTestRun(EntryPointFactory entryPointFactory,
|
||||
TaskFactory taskFactory, Configuration config, ILog overviewLog, StatusLog statusLog, TestHandle handle,
|
||||
StartupChecker startupChecker, CancellationToken cancelToken, string deployId)
|
||||
{
|
||||
this.taskFactory = taskFactory;
|
||||
this.config = config;
|
||||
|
@ -34,8 +36,9 @@ namespace ContinuousTests
|
|||
this.handle = handle;
|
||||
this.cancelToken = cancelToken;
|
||||
testName = handle.Test.GetType().Name;
|
||||
fixtureLog = new FixtureLog(new LogConfig(config.LogPath), DateTime.UtcNow, testName);
|
||||
entryPoint = entryPointFactory.CreateEntryPoint(config.KubeConfigFile, config.DataPath, config.CodexDeployment.Metadata.KubeNamespace, fixtureLog);
|
||||
fixtureLog = new FixtureLog(new LogConfig(config.LogPath), DateTime.UtcNow, deployId, testName);
|
||||
entryPoint = entryPointFactory.CreateEntryPoint(config.KubeConfigFile, config.DataPath,
|
||||
config.CodexDeployment.Metadata.KubeNamespace, fixtureLog);
|
||||
ApplyLogReplacements(fixtureLog, startupChecker);
|
||||
|
||||
nodes = CreateRandomNodes();
|
||||
|
@ -80,6 +83,7 @@ namespace ContinuousTests
|
|||
{
|
||||
fixtureLog.Delete();
|
||||
}
|
||||
|
||||
resultHandler(true);
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
@ -114,6 +118,7 @@ namespace ContinuousTests
|
|||
{
|
||||
effectiveStart = config.CodexDeployment.Metadata.StartUtc.Subtract(TimeSpan.FromSeconds(30));
|
||||
}
|
||||
|
||||
var effectiveEnd = DateTime.UtcNow;
|
||||
var elasticSearchLogDownloader = new ElasticSearchLogDownloader(entryPoint.Tools, fixtureLog);
|
||||
|
||||
|
@ -122,14 +127,17 @@ namespace ContinuousTests
|
|||
var container = node.Container;
|
||||
var deploymentName = container.RunningContainers.StartResult.Deployment.Name;
|
||||
var namespaceName = container.RunningContainers.StartResult.Cluster.Configuration.KubernetesNamespace;
|
||||
var openingLine = $"{namespaceName} - {deploymentName} = {node.Container.Name} = {node.GetDebugInfo().id}";
|
||||
elasticSearchLogDownloader.Download(fixtureLog.CreateSubfile(), node.Container, effectiveStart, effectiveEnd, openingLine);
|
||||
var openingLine =
|
||||
$"{namespaceName} - {deploymentName} = {node.Container.Name} = {node.GetDebugInfo().id}";
|
||||
elasticSearchLogDownloader.Download(fixtureLog.CreateSubfile(), node.Container, effectiveStart,
|
||||
effectiveEnd, openingLine);
|
||||
}
|
||||
}
|
||||
|
||||
private void ApplyLogReplacements(FixtureLog fixtureLog, StartupChecker startupChecker)
|
||||
{
|
||||
foreach (var replacement in startupChecker.LogReplacements) fixtureLog.AddStringReplace(replacement.From, replacement.To);
|
||||
foreach (var replacement in startupChecker.LogReplacements)
|
||||
fixtureLog.AddStringReplace(replacement.From, replacement.To);
|
||||
}
|
||||
|
||||
private void RunTestMoments()
|
||||
|
@ -161,9 +169,11 @@ namespace ContinuousTests
|
|||
{
|
||||
ThrowFailTest();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fixtureLog.Log("Test run has been cancelled.");
|
||||
}
|
||||
|
||||
|
@ -193,6 +203,7 @@ namespace ContinuousTests
|
|||
result.Add("testname", testName);
|
||||
result.Add("message", message);
|
||||
result.Add("involvedpods", string.Join(",", nodes.Select(n => n.GetName())));
|
||||
result.Add("involvedpodnames", string.Join(",", nodes.Select(n => n.GetPodInfo().Name)));
|
||||
|
||||
var error = message.Split(Environment.NewLine).First();
|
||||
if (error.Contains(":")) error = error.Substring(1 + error.LastIndexOf(":"));
|
||||
|
@ -222,6 +233,7 @@ namespace ContinuousTests
|
|||
{
|
||||
return UnpackException(a.InnerExceptions.First());
|
||||
}
|
||||
|
||||
if (exception is TargetInvocationException t)
|
||||
{
|
||||
return UnpackException(t.InnerException!);
|
||||
|
@ -294,7 +306,8 @@ namespace ContinuousTests
|
|||
{
|
||||
result[i] = containers.PickOneRandom();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -23,7 +23,8 @@ namespace ContinuousTests
|
|||
|
||||
public void Check()
|
||||
{
|
||||
var log = new FixtureLog(new LogConfig(config.LogPath), DateTime.UtcNow, "StartupChecks");
|
||||
var log = new FixtureLog(new LogConfig(config.LogPath), DateTime.UtcNow, config.CodexDeployment.Id,
|
||||
"StartupChecks");
|
||||
log.Log("Starting continuous test run...");
|
||||
IncludeDeploymentConfiguration(log);
|
||||
log.Log("Checking configuration...");
|
||||
|
@ -46,13 +47,15 @@ namespace ContinuousTests
|
|||
{
|
||||
var podInfo = workflow.GetPodInfo(container);
|
||||
log.Log($"Codex environment variables for '{container.Name}':");
|
||||
log.Log($"Namespace: {container.RunningContainers.StartResult.Cluster.Configuration.KubernetesNamespace} - " +
|
||||
log.Log(
|
||||
$"Namespace: {container.RunningContainers.StartResult.Cluster.Configuration.KubernetesNamespace} - " +
|
||||
$"Pod name: {podInfo.Name} - Deployment name: {instance.Containers.StartResult.Deployment.Name}");
|
||||
var codexVars = container.Recipe.EnvVars;
|
||||
foreach (var vars in codexVars) log.Log(vars.ToString());
|
||||
log.Log("");
|
||||
}
|
||||
}
|
||||
|
||||
log.Log($"Deployment metadata: {JsonConvert.SerializeObject(deployment.Metadata)}");
|
||||
log.Log("");
|
||||
}
|
||||
|
@ -64,6 +67,7 @@ namespace ContinuousTests
|
|||
{
|
||||
throw new Exception("Unable to find any tests.");
|
||||
}
|
||||
|
||||
foreach (var test in tests)
|
||||
{
|
||||
cancelToken.ThrowIfCancellationRequested();
|
||||
|
@ -87,7 +91,8 @@ namespace ContinuousTests
|
|||
|
||||
private void CheckCodexNodes(BaseLog log, Configuration config)
|
||||
{
|
||||
var nodes = entryPoint.CreateInterface().WrapCodexContainers(config.CodexDeployment.CodexInstances.Select(i => i.Containers).ToArray());
|
||||
var nodes = entryPoint.CreateInterface()
|
||||
.WrapCodexContainers(config.CodexDeployment.CodexInstances.Select(i => i.Containers).ToArray());
|
||||
var pass = true;
|
||||
foreach (var n in nodes)
|
||||
{
|
||||
|
@ -106,6 +111,7 @@ namespace ContinuousTests
|
|||
pass = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!pass)
|
||||
{
|
||||
throw new Exception("Not all codex nodes responded.");
|
||||
|
@ -126,6 +132,7 @@ namespace ContinuousTests
|
|||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -145,7 +152,8 @@ namespace ContinuousTests
|
|||
propertyName: nameof(ContinuousTest.CustomK8sNamespace));
|
||||
}
|
||||
|
||||
private void DuplicatesCheck(ContinuousTest[] tests, List<string> errors, Func<ContinuousTest, bool> considerCondition, Func<ContinuousTest, object> getValue, string propertyName)
|
||||
private void DuplicatesCheck(ContinuousTest[] tests, List<string> errors,
|
||||
Func<ContinuousTest, bool> considerCondition, Func<ContinuousTest, object> getValue, string propertyName)
|
||||
{
|
||||
foreach (var test in tests)
|
||||
{
|
||||
|
@ -155,7 +163,8 @@ namespace ContinuousTests
|
|||
if (duplicates.Any())
|
||||
{
|
||||
duplicates.Add(test);
|
||||
errors.Add($"Tests '{string.Join(",", duplicates.Select(d => d.Name))}' have the same '{propertyName}'. These must be unique.");
|
||||
errors.Add(
|
||||
$"Tests '{string.Join(",", duplicates.Select(d => d.Name))}' have the same '{propertyName}'. These must be unique.");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
@ -170,14 +179,16 @@ namespace ContinuousTests
|
|||
{
|
||||
if (test.RequiredNumberOfNodes < 1)
|
||||
{
|
||||
errors.Add($"Test '{test.Name}' requires {test.RequiredNumberOfNodes} nodes. Test must require > 0 nodes, or -1 to select all nodes.");
|
||||
errors.Add(
|
||||
$"Test '{test.Name}' requires {test.RequiredNumberOfNodes} nodes. Test must require > 0 nodes, or -1 to select all nodes.");
|
||||
}
|
||||
else if (test.RequiredNumberOfNodes > config.CodexDeployment.CodexInstances.Length)
|
||||
{
|
||||
errors.Add($"Test '{test.Name}' requires {test.RequiredNumberOfNodes} nodes. Deployment only has {config.CodexDeployment.CodexInstances.Length}");
|
||||
errors.Add(
|
||||
$"Test '{test.Name}' requires {test.RequiredNumberOfNodes} nodes. Deployment only has {config.CodexDeployment.CodexInstances.Length}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -77,7 +77,8 @@ namespace ContinuousTests
|
|||
{
|
||||
var test = (ContinuousTest)Activator.CreateInstance(testType)!;
|
||||
var handle = new TestHandle(test);
|
||||
var run = new SingleTestRun(entryPointFactory, taskFactory, config, overviewLog, statusLog, handle, startupChecker, cancelToken);
|
||||
var run = new SingleTestRun(entryPointFactory, taskFactory, config, overviewLog, statusLog, handle,
|
||||
startupChecker, cancelToken, config.CodexDeployment.Id);
|
||||
|
||||
runFinishedHandle.Reset();
|
||||
run.Run(runFinishedHandle, result =>
|
||||
|
|
|
@ -23,5 +23,6 @@ namespace CodexTests
|
|||
}
|
||||
|
||||
protected ICodexNode? BootstrapNode { get; private set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ using GethPlugin;
|
|||
using Nethereum.Hex.HexConvertors.Extensions;
|
||||
using NUnit.Framework;
|
||||
using Utils;
|
||||
using Request = CodexContractsPlugin.Marketplace.Request;
|
||||
|
||||
namespace CodexTests.BasicTests
|
||||
{
|
||||
|
@ -23,6 +24,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)
|
||||
|
@ -38,6 +40,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));
|
||||
|
||||
|
@ -89,29 +92,12 @@ namespace CodexTests.BasicTests
|
|||
|
||||
purchaseContract.WaitForStorageContractStarted(fileSize);
|
||||
|
||||
var blockRange = geth.ConvertTimeRangeToBlockRange(GetTestRunTimeRange());
|
||||
|
||||
var requests = contracts.GetStorageRequests(blockRange);
|
||||
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(blockRange);
|
||||
Assert.That(requestFulfilledEvents.Length, Is.EqualTo(1));
|
||||
CollectionAssert.AreEqual(request.RequestId, requestFulfilledEvents[0].RequestId);
|
||||
var filledSlotEvents = contracts.GetSlotFilledEvents(blockRange);
|
||||
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();
|
||||
|
||||
|
@ -119,12 +105,57 @@ 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");
|
||||
// waiting for block retransmit fix: CheckLogForErrors(seller, buyer);
|
||||
}
|
||||
|
||||
//CheckLogForErrors(seller, buyer);
|
||||
[Test]
|
||||
public void GethBootstrapTest()
|
||||
{
|
||||
var boot = Ci.StartGethNode(s => s.WithName("boot").IsMiner());
|
||||
var disconnected = Ci.StartGethNode(s => s.WithName("disconnected"));
|
||||
var follow = Ci.StartGethNode(s => s.WithBootstrapNode(boot).WithName("follow"));
|
||||
|
||||
Thread.Sleep(12000);
|
||||
|
||||
var bootN = boot.GetSyncedBlockNumber();
|
||||
var discN = disconnected.GetSyncedBlockNumber();
|
||||
var followN = follow.GetSyncedBlockNumber();
|
||||
|
||||
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);
|
||||
|
|
|
@ -20,16 +20,19 @@ namespace DistTestCore
|
|||
private readonly object lifecycleLock = new object();
|
||||
private readonly EntryPoint globalEntryPoint;
|
||||
private readonly Dictionary<string, TestLifecycle> lifecycles = new Dictionary<string, TestLifecycle>();
|
||||
private readonly string deployId;
|
||||
|
||||
public DistTest()
|
||||
{
|
||||
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
|
||||
testAssemblies = assemblies.Where(a => a.FullName!.ToLowerInvariant().Contains("test")).ToArray();
|
||||
|
||||
deployId = NameUtils.MakeDeployId();
|
||||
|
||||
var logConfig = configuration.GetLogConfig();
|
||||
var startTime = DateTime.UtcNow;
|
||||
fixtureLog = new FixtureLog(logConfig, startTime);
|
||||
statusLog = new StatusLog(logConfig, startTime, "dist-tests");
|
||||
fixtureLog = new FixtureLog(logConfig, startTime, deployId);
|
||||
statusLog = new StatusLog(logConfig, startTime, "dist-tests", deployId);
|
||||
|
||||
globalEntryPoint = new EntryPoint(fixtureLog, configuration.GetK8sConfiguration(new DefaultTimeSet(), TestNamespacePrefix), configuration.GetFileManagerFolder());
|
||||
|
||||
|
@ -181,7 +184,7 @@ namespace DistTestCore
|
|||
lock (lifecycleLock)
|
||||
{
|
||||
var testNamespace = TestNamespacePrefix + Guid.NewGuid().ToString();
|
||||
var lifecycle = new TestLifecycle(fixtureLog.CreateTestLog(), configuration, GetTimeSet(), testNamespace);
|
||||
var lifecycle = new TestLifecycle(fixtureLog.CreateTestLog(), configuration, GetTimeSet(), testNamespace, deployId);
|
||||
lifecycles.Add(testName, lifecycle);
|
||||
LifecycleStart(lifecycle);
|
||||
}
|
||||
|
|
|
@ -5,13 +5,18 @@ namespace DistTestCore.Logs
|
|||
public abstract class BaseTestLog : BaseLog
|
||||
{
|
||||
private bool hasFailed;
|
||||
private readonly string deployId;
|
||||
|
||||
protected BaseTestLog(string deployId)
|
||||
{
|
||||
this.deployId = deployId;
|
||||
}
|
||||
|
||||
public void WriteLogTag()
|
||||
{
|
||||
var runId = NameUtils.GetRunId();
|
||||
var category = NameUtils.GetCategoryName();
|
||||
var name = NameUtils.GetTestMethodName();
|
||||
LogFile.WriteRaw($"{runId} {category} {name}");
|
||||
LogFile.WriteRaw($"{deployId} {category} {name}");
|
||||
}
|
||||
|
||||
public void MarkAsFailed()
|
||||
|
|
|
@ -5,15 +5,17 @@ namespace DistTestCore.Logs
|
|||
public class FixtureLog : BaseTestLog
|
||||
{
|
||||
private readonly string fullName;
|
||||
private readonly string deployId;
|
||||
|
||||
public FixtureLog(LogConfig config, DateTime start, string name = "")
|
||||
public FixtureLog(LogConfig config, DateTime start, string deployId, string name = "") : base(deployId)
|
||||
{
|
||||
this.deployId = deployId;
|
||||
fullName = NameUtils.GetFixtureFullName(config, start, name);
|
||||
}
|
||||
|
||||
public TestLog CreateTestLog(string name = "")
|
||||
{
|
||||
return new TestLog(fullName, name);
|
||||
return new TestLog(fullName, deployId, name);
|
||||
}
|
||||
|
||||
public void DeleteFolder()
|
||||
|
@ -26,4 +28,4 @@ namespace DistTestCore.Logs
|
|||
return fullName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -6,16 +6,18 @@ namespace DistTestCore.Logs
|
|||
{
|
||||
public class StatusLog
|
||||
{
|
||||
private readonly object fileLock = new object();
|
||||
private readonly object fileLock = new();
|
||||
private readonly string deployId;
|
||||
private readonly string fullName;
|
||||
private readonly string fixtureName;
|
||||
private readonly string testType;
|
||||
|
||||
public StatusLog(LogConfig config, DateTime start, string testType, string name = "")
|
||||
public StatusLog(LogConfig config, DateTime start, string testType, string deployId, string name = "")
|
||||
{
|
||||
fullName = NameUtils.GetFixtureFullName(config, start, name) + "_STATUS.log";
|
||||
fixtureName = NameUtils.GetRawFixtureName();
|
||||
this.testType = testType;
|
||||
this.deployId = deployId;
|
||||
}
|
||||
|
||||
public void ConcludeTest(string resultStatus, TimeSpan testDuration, Dictionary<string, string> data)
|
||||
|
@ -26,7 +28,7 @@ namespace DistTestCore.Logs
|
|||
public void ConcludeTest(string resultStatus, string testDuration, Dictionary<string, string> data)
|
||||
{
|
||||
data.Add("timestamp", DateTime.UtcNow.ToString("o"));
|
||||
data.Add("runid", NameUtils.GetRunId());
|
||||
data.Add("deployid", deployId);
|
||||
data.Add("status", resultStatus);
|
||||
data.Add("category", NameUtils.GetCategoryName());
|
||||
data.Add("fixturename", fixtureName);
|
||||
|
|
|
@ -2,12 +2,11 @@
|
|||
{
|
||||
public class TestLog : BaseTestLog
|
||||
{
|
||||
private readonly string methodName;
|
||||
private readonly string fullName;
|
||||
|
||||
public TestLog(string folder, string name = "")
|
||||
public TestLog(string folder, string deployId, string name = "") : base(deployId)
|
||||
{
|
||||
methodName = NameUtils.GetTestMethodName(name);
|
||||
var methodName = NameUtils.GetTestMethodName(name);
|
||||
fullName = Path.Combine(folder, methodName);
|
||||
|
||||
Log($"*** Begin: {methodName}");
|
||||
|
|
|
@ -5,14 +5,6 @@ namespace DistTestCore
|
|||
{
|
||||
public static class NameUtils
|
||||
{
|
||||
private static readonly string defaultRunId;
|
||||
|
||||
static NameUtils()
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
defaultRunId = now.ToString("yyyyMMdd-hhmmss");
|
||||
}
|
||||
|
||||
public static string GetTestMethodName(string name = "")
|
||||
{
|
||||
if (!string.IsNullOrEmpty(name)) return name;
|
||||
|
@ -48,9 +40,9 @@ namespace DistTestCore
|
|||
return GetEnvVar("TESTID", "EnvVar-TESTID-NotSet");
|
||||
}
|
||||
|
||||
public static string GetRunId()
|
||||
public static string MakeDeployId()
|
||||
{
|
||||
return GetEnvVar("RUNID", defaultRunId);
|
||||
return DateTime.UtcNow.ToString("yyyyMMdd-hhmmss");
|
||||
}
|
||||
|
||||
private static string GetEnvVar(string name, string defaultValue)
|
||||
|
|
|
@ -12,10 +12,11 @@ namespace DistTestCore
|
|||
{
|
||||
private const string TestsType = "dist-tests";
|
||||
private readonly EntryPoint entryPoint;
|
||||
private readonly Dictionary<string, string> metadata;
|
||||
private readonly List<RunningContainers> runningContainers = new List<RunningContainers>();
|
||||
private readonly Dictionary<string, string> metadata;
|
||||
private readonly List<RunningContainers> runningContainers = new();
|
||||
private readonly string deployId;
|
||||
|
||||
public TestLifecycle(TestLog log, Configuration configuration, ITimeSet timeSet, string testNamespace)
|
||||
public TestLifecycle(TestLog log, Configuration configuration, ITimeSet timeSet, string testNamespace, string deployId)
|
||||
{
|
||||
Log = log;
|
||||
Configuration = configuration;
|
||||
|
@ -25,6 +26,7 @@ namespace DistTestCore
|
|||
entryPoint = new EntryPoint(log, configuration.GetK8sConfiguration(timeSet, this, testNamespace), configuration.GetFileManagerFolder(), timeSet);
|
||||
metadata = entryPoint.GetPluginMetadata();
|
||||
CoreInterface = entryPoint.CreateInterface();
|
||||
this.deployId = deployId;
|
||||
|
||||
log.WriteLogTag();
|
||||
}
|
||||
|
@ -76,7 +78,7 @@ namespace DistTestCore
|
|||
public void OnContainerRecipeCreated(ContainerRecipe recipe)
|
||||
{
|
||||
recipe.PodLabels.Add("tests-type", TestsType);
|
||||
recipe.PodLabels.Add("runid", NameUtils.GetRunId());
|
||||
recipe.PodLabels.Add("deployid", deployId);
|
||||
recipe.PodLabels.Add("testid", NameUtils.GetTestId());
|
||||
recipe.PodLabels.Add("category", NameUtils.GetCategoryName());
|
||||
recipe.PodLabels.Add("fixturename", NameUtils.GetRawFixtureName());
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
using ArgsUniform;
|
||||
using CodexPlugin;
|
||||
using DistTestCore;
|
||||
|
||||
namespace CodexNetDeployer
|
||||
{
|
||||
|
@ -16,6 +17,9 @@ namespace CodexNetDeployer
|
|||
|
||||
[Uniform("kube-namespace", "kn", "KUBENAMESPACE", true, "Kubernetes namespace to be used for deployment.")]
|
||||
public string KubeNamespace { get; set; } = string.Empty;
|
||||
|
||||
[Uniform("deploy-id", "di", "DEPLOYID", false, "ID of the deployment. (default) to current time)")]
|
||||
public string DeployId { get; set; } = NameUtils.MakeDeployId();
|
||||
|
||||
[Uniform("deploy-file", "df", "DEPLOYFILE", false, "Output deployment JSON file that will be written. Defaults to 'codex-deployment.json'.")]
|
||||
public string DeployFile { get; set; } = "codex-deployment.json";
|
||||
|
|
|
@ -45,6 +45,7 @@ namespace CodexNetDeployer
|
|||
Console.CursorLeft = longestKey + 5;
|
||||
Console.WriteLine($"= {entry.Value}");
|
||||
}
|
||||
|
||||
Log("");
|
||||
}
|
||||
|
||||
|
@ -84,7 +85,8 @@ namespace CodexNetDeployer
|
|||
|
||||
var discordBotContainer = DeployDiscordBot(ci, gethDeployment, contractsDeployment);
|
||||
|
||||
return new CodexDeployment(codexInstances, gethDeployment, contractsDeployment, metricsService, discordBotContainer, CreateMetadata(startUtc));
|
||||
return new CodexDeployment(codexInstances, gethDeployment, contractsDeployment, metricsService,
|
||||
discordBotContainer, CreateMetadata(startUtc), config.DeployId);
|
||||
}
|
||||
|
||||
private EntryPoint CreateEntryPoint(ILog log)
|
||||
|
@ -98,7 +100,7 @@ namespace CodexNetDeployer
|
|||
kubernetesNamespace: config.KubeNamespace);
|
||||
|
||||
var result = new EntryPoint(log, configuration, string.Empty, new FastHttpTimeSet());
|
||||
configuration.Hooks = new K8sHook(config.TestsTypePodLabel, result.GetPluginMetadata());
|
||||
configuration.Hooks = new K8sHook(config.TestsTypePodLabel, config.DeployId, result.GetPluginMetadata());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
@ -120,7 +122,8 @@ namespace CodexNetDeployer
|
|||
});
|
||||
}
|
||||
|
||||
private RunningContainers? DeployDiscordBot(CoreInterface ci, GethDeployment gethDeployment, CodexContractsDeployment contractsDeployment)
|
||||
private RunningContainers? DeployDiscordBot(CoreInterface ci, GethDeployment gethDeployment,
|
||||
CodexContractsDeployment contractsDeployment)
|
||||
{
|
||||
if (!config.DeployDiscordBot) return null;
|
||||
Log("Deploying Discord bot...");
|
||||
|
@ -202,7 +205,8 @@ namespace CodexNetDeployer
|
|||
foreach (var startResult in startResults)
|
||||
{
|
||||
var watcher = startResult.CodexNode.CrashWatcher;
|
||||
if (watcher == null) throw new Exception("Expected each CodexNode container to be created with a crash-watcher.");
|
||||
if (watcher == null)
|
||||
throw new Exception("Expected each CodexNode container to be created with a crash-watcher.");
|
||||
if (watcher.HasContainerCrashed()) crashes.Add(startResult.CodexNode.Container);
|
||||
}
|
||||
|
||||
|
@ -212,7 +216,8 @@ namespace CodexNetDeployer
|
|||
}
|
||||
else
|
||||
{
|
||||
Log($"Check failed. The following containers have crashed: {string.Join(",", crashes.Select(c => c.Name))}");
|
||||
Log(
|
||||
$"Check failed. The following containers have crashed: {string.Join(",", crashes.Select(c => c.Name))}");
|
||||
throw new Exception("Deployment failed: One or more containers crashed.");
|
||||
}
|
||||
}
|
||||
|
@ -270,4 +275,4 @@ namespace CodexNetDeployer
|
|||
return TimeSpan.FromSeconds(30);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,11 +8,13 @@ namespace CodexNetDeployer
|
|||
public class K8sHook : IK8sHooks
|
||||
{
|
||||
private readonly string testsTypeLabel;
|
||||
private readonly string deployId;
|
||||
private readonly Dictionary<string, string> metadata;
|
||||
|
||||
public K8sHook(string testsTypeLabel, Dictionary<string, string> metadata)
|
||||
public K8sHook(string testsTypeLabel, string deployId, Dictionary<string, string> metadata)
|
||||
{
|
||||
this.testsTypeLabel = testsTypeLabel;
|
||||
this.deployId = deployId;
|
||||
this.metadata = metadata;
|
||||
}
|
||||
|
||||
|
@ -27,7 +29,7 @@ namespace CodexNetDeployer
|
|||
public void OnContainerRecipeCreated(ContainerRecipe recipe)
|
||||
{
|
||||
recipe.PodLabels.Add("tests-type", testsTypeLabel);
|
||||
recipe.PodLabels.Add("runid", NameUtils.GetRunId());
|
||||
recipe.PodLabels.Add("deployid", deployId);
|
||||
recipe.PodLabels.Add("testid", NameUtils.GetTestId());
|
||||
|
||||
foreach (var pair in metadata)
|
||||
|
|
Loading…
Reference in New Issue