diff --git a/DistTestCore/ByteSize.cs b/DistTestCore/ByteSize.cs index dc288bc9..8d47cf25 100644 --- a/DistTestCore/ByteSize.cs +++ b/DistTestCore/ByteSize.cs @@ -1,14 +1,23 @@ -namespace DistTestCore +using Utils; + +namespace DistTestCore { public class ByteSize { + public ByteSize(long sizeInBytes) { + if (sizeInBytes < 0) throw new ArgumentException("Cannot create ByteSize object with size less than 0. Was: " + sizeInBytes); SizeInBytes = sizeInBytes; } public long SizeInBytes { get; } + public long ToMB() + { + return SizeInBytes / (1024 * 1024); + } + public override bool Equals(object? obj) { return obj is ByteSize size && SizeInBytes == size.SizeInBytes; @@ -21,7 +30,7 @@ public override string ToString() { - return $"{SizeInBytes} bytes"; + return Formatter.FormatByteSize(SizeInBytes); } } diff --git a/DistTestCore/Codex/CodexContainerRecipe.cs b/DistTestCore/Codex/CodexContainerRecipe.cs index e92c93c6..f3279274 100644 --- a/DistTestCore/Codex/CodexContainerRecipe.cs +++ b/DistTestCore/Codex/CodexContainerRecipe.cs @@ -5,15 +5,19 @@ namespace DistTestCore.Codex { public class CodexContainerRecipe : ContainerRecipeFactory { - #if Arm64 +#if Arm64 public const string DockerImage = "codexstorage/nim-codex:sha-7b88ea0"; - #else - //public const string DockerImage = "codexstorage/nim-codex:sha-7b88ea0"; - public const string DockerImage = "codexstorage/nim-codex:sha-7b88ea0"; - #endif +#else + public const string DockerImage = "thatbenbierens/nim-codex:dhting"; + //public const string DockerImage = "codexstorage/nim-codex:sha-7b88ea0"; +#endif public const string MetricsPortTag = "metrics_port"; public const string DiscoveryPortTag = "discovery-port"; + // Used by tests for time-constraint assersions. + public static readonly TimeSpan MaxUploadTimePerMegabyte = TimeSpan.FromSeconds(2.0); + public static readonly TimeSpan MaxDownloadTimePerMegabyte = TimeSpan.FromSeconds(2.0); + protected override string Image => DockerImage; protected override void Initialize(StartupConfig startupConfig) diff --git a/DistTestCore/DistTest.cs b/DistTestCore/DistTest.cs index bf4d59fc..a93c180d 100644 --- a/DistTestCore/DistTest.cs +++ b/DistTestCore/DistTest.cs @@ -10,7 +10,6 @@ using System.Reflection; namespace DistTestCore { - [SetUpFixture] [Parallelizable(ParallelScope.All)] public abstract class DistTest { @@ -87,9 +86,9 @@ namespace DistTestCore } } - public TestFile GenerateTestFile(ByteSize size) + public TestFile GenerateTestFile(ByteSize size, string label = "") { - return Get().FileManager.GenerateTestFile(size); + return Get().FileManager.GenerateTestFile(size, label); } /// diff --git a/DistTestCore/FileManager.cs b/DistTestCore/FileManager.cs index 97cf27cc..5ebae093 100644 --- a/DistTestCore/FileManager.cs +++ b/DistTestCore/FileManager.cs @@ -1,13 +1,14 @@ using Logging; using NUnit.Framework; +using System.Runtime.InteropServices; using Utils; namespace DistTestCore { public interface IFileManager { - TestFile CreateEmptyTestFile(); - TestFile GenerateTestFile(ByteSize size); + TestFile CreateEmptyTestFile(string label = ""); + TestFile GenerateTestFile(ByteSize size, string label = ""); void DeleteAllTestFiles(); void PushFileSet(); void PopFileSet(); @@ -15,7 +16,7 @@ namespace DistTestCore public class FileManager : IFileManager { - public const int ChunkSize = 1024 * 1024; + public const int ChunkSize = 1024 * 1024 * 100; private static NumberSource folderNumberSource = new NumberSource(0); private readonly Random random = new Random(); private readonly TestLog log; @@ -30,19 +31,20 @@ namespace DistTestCore this.log = log; } - public TestFile CreateEmptyTestFile() + public TestFile CreateEmptyTestFile(string label = "") { - var result = new TestFile(Path.Combine(folder, Guid.NewGuid().ToString() + "_test.bin")); + var path = Path.Combine(folder, Guid.NewGuid().ToString() + "_test.bin"); + var result = new TestFile(log, path, label); File.Create(result.Filename).Close(); if (fileSetStack.Any()) fileSetStack.Last().Add(result); return result; } - public TestFile GenerateTestFile(ByteSize size) + public TestFile GenerateTestFile(ByteSize size, string label) { - var result = CreateEmptyTestFile(); - GenerateFileBytes(result, size); - log.Log($"Generated {size.SizeInBytes} bytes of content for file '{result.Filename}'."); + var sw = Stopwatch.Begin(log); + var result = GenerateFile(size, label); + sw.End($"Generated file '{result.Describe()}'."); return result; } @@ -72,14 +74,50 @@ namespace DistTestCore } } + private TestFile GenerateFile(ByteSize size, string label) + { + var result = CreateEmptyTestFile(label); + CheckSpaceAvailable(result, size); + + GenerateFileBytes(result, size); + return result; + } + + private void CheckSpaceAvailable(TestFile testFile, ByteSize size) + { + var file = new FileInfo(testFile.Filename); + var drive = new DriveInfo(file.Directory!.Root.FullName); + + var spaceAvailable = drive.TotalFreeSpace; + + if (spaceAvailable < size.SizeInBytes) + { + var msg = $"Inconclusive: Not enough disk space to perform test. " + + $"{Formatter.FormatByteSize(size.SizeInBytes)} required. " + + $"{Formatter.FormatByteSize(spaceAvailable)} available."; + + log.Log(msg); + Assert.Inconclusive(msg); + } + } + private void GenerateFileBytes(TestFile result, ByteSize size) { long bytesLeft = size.SizeInBytes; + int chunkSize = ChunkSize; while (bytesLeft > 0) { - var length = Math.Min(bytesLeft, ChunkSize); - AppendRandomBytesToFile(result, length); - bytesLeft -= length; + try + { + var length = Math.Min(bytesLeft, chunkSize); + AppendRandomBytesToFile(result, length); + bytesLeft -= length; + } + catch + { + chunkSize = chunkSize / 2; + if (chunkSize < 1024) throw; + } } } @@ -104,20 +142,39 @@ namespace DistTestCore public class TestFile { - public TestFile(string filename) + private readonly TestLog log; + + public TestFile(TestLog log, string filename, string label) { + this.log = log; Filename = filename; + Label = label; } public string Filename { get; } - - public long GetFileSize() - { - var info = new FileInfo(Filename); - return info.Length; - } + public string Label { get; } public void AssertIsEqual(TestFile? actual) + { + var sw = Stopwatch.Begin(log); + try + { + AssertEqual(actual); + } + finally + { + sw.End($"{nameof(TestFile)}.{nameof(AssertIsEqual)}"); + } + } + + public string Describe() + { + var sizePostfix = $" ({Formatter.FormatByteSize(GetFileSize())})"; + if (!string.IsNullOrEmpty(Label)) return Label + sizePostfix; + return $"'{Filename}'{sizePostfix}"; + } + + private void AssertEqual(TestFile? actual) { if (actual == null) Assert.Fail("TestFile is null."); if (actual == this || actual!.Filename == Filename) Assert.Fail("TestFile is compared to itself."); @@ -138,10 +195,25 @@ namespace DistTestCore readExpected = streamExpected.Read(bytesExpected, 0, FileManager.ChunkSize); readActual = streamActual.Read(bytesActual, 0, FileManager.ChunkSize); - if (readExpected == 0 && readActual == 0) return; + if (readExpected == 0 && readActual == 0) + { + log.Log($"OK: '{Describe()}' is equal to '{actual.Describe()}'."); + return; + } + Assert.That(readActual, Is.EqualTo(readExpected), "Unable to read buffers of equal length."); - CollectionAssert.AreEqual(bytesExpected, bytesActual, "Files are not binary-equal."); + + for (var i = 0; i < readActual; i++) + { + if (bytesExpected[i] != bytesActual[i]) Assert.Fail("File contents not equal."); + } } } + + private long GetFileSize() + { + var info = new FileInfo(Filename); + return info.Length; + } } } diff --git a/DistTestCore/Helpers/PeerConnectionTestHelpers.cs b/DistTestCore/Helpers/PeerConnectionTestHelpers.cs index 54f3c435..5eb0cdf9 100644 --- a/DistTestCore/Helpers/PeerConnectionTestHelpers.cs +++ b/DistTestCore/Helpers/PeerConnectionTestHelpers.cs @@ -16,10 +16,18 @@ namespace DistTestCore.Helpers public void AssertFullyConnected(IEnumerable nodes) { - AssertFullyConnected(nodes.ToArray()); + var n = nodes.ToArray(); + + AssertFullyConnected(n); + + for (int i = 0; i < 5; i++) + { + Time.Sleep(TimeSpan.FromSeconds(30)); + AssertFullyConnected(n); + } } - public void AssertFullyConnected(params IOnlineCodexNode[] nodes) + private void AssertFullyConnected(IOnlineCodexNode[] nodes) { test.Log($"Asserting peers are fully-connected for nodes: '{string.Join(",", nodes.Select(n => n.GetName()))}'..."); var entries = CreateEntries(nodes); diff --git a/DistTestCore/Helpers/PeerDownloadTestHelpers.cs b/DistTestCore/Helpers/PeerDownloadTestHelpers.cs index 6929cebc..2626d5f2 100644 --- a/DistTestCore/Helpers/PeerDownloadTestHelpers.cs +++ b/DistTestCore/Helpers/PeerDownloadTestHelpers.cs @@ -1,4 +1,7 @@ -namespace DistTestCore.Helpers +using DistTestCore.Codex; +using NUnit.Framework; + +namespace DistTestCore.Helpers { public class PeerDownloadTestHelpers { @@ -9,14 +12,11 @@ this.test = test; } - public void AssertFullDownloadInterconnectivity(IEnumerable nodes) - { - AssertFullDownloadInterconnectivity(nodes, 1.MB()); - } - public void AssertFullDownloadInterconnectivity(IEnumerable nodes, ByteSize testFileSize) { test.Log($"Asserting full download interconnectivity for nodes: '{string.Join(",", nodes.Select(n => n.GetName()))}'..."); + var start = DateTime.UtcNow; + foreach (var node in nodes) { var uploader = node; @@ -29,12 +29,27 @@ } test.Log($"Success! Full download interconnectivity for nodes: {string.Join(",", nodes.Select(n => n.GetName()))}"); + var timeTaken = DateTime.UtcNow - start; + + AssertTimePerMB(timeTaken, nodes.Count(), testFileSize); + } + + private void AssertTimePerMB(TimeSpan timeTaken, int numberOfNodes, ByteSize size) + { + var numberOfDownloads = numberOfNodes * (numberOfNodes - 1); + var timePerDownload = timeTaken / numberOfDownloads; + float sizeInMB = size.ToMB(); + var timePerMB = timePerDownload / sizeInMB; + + test.Log($"Performed {numberOfDownloads} downloads of {size} in {timeTaken.TotalSeconds} seconds, for an average of {timePerMB.TotalSeconds} seconds per MB."); + + Assert.That(timePerMB, Is.LessThan(CodexContainerRecipe.MaxDownloadTimePerMegabyte), "MaxDownloadTimePerMegabyte performance threshold breached."); } private void PerformTest(IOnlineCodexNode uploader, IOnlineCodexNode[] downloaders, ByteSize testFileSize) { - // 1 test file per downloader. - var files = downloaders.Select(d => test.GenerateTestFile(testFileSize)).ToArray(); + // Generate 1 test file per downloader. + var files = downloaders.Select(d => GenerateTestFile(uploader, d, testFileSize)).ToArray(); // Upload all the test files to the uploader. var contentIds = files.Select(uploader.UploadFile).ToArray(); @@ -43,10 +58,18 @@ for (var i = 0; i < downloaders.Length; i++) { var expectedFile = files[i]; - var downloadedFile = downloaders[i].DownloadContent(contentIds[i]); + var downloadedFile = downloaders[i].DownloadContent(contentIds[i], $"{expectedFile.Label}DOWNLOADED"); expectedFile.AssertIsEqual(downloadedFile); } } + + private TestFile GenerateTestFile(IOnlineCodexNode uploader, IOnlineCodexNode downloader, ByteSize testFileSize) + { + var up = uploader.GetName().Replace("<", "").Replace(">", ""); + var down = downloader.GetName().Replace("<", "").Replace(">", ""); + var label = $"FROM{up}TO{down}"; + return test.GenerateTestFile(testFileSize, label); + } } } diff --git a/DistTestCore/Marketplace/MarketplaceAccessFactory.cs b/DistTestCore/Marketplace/MarketplaceAccessFactory.cs index 5ad52eb5..ac595567 100644 --- a/DistTestCore/Marketplace/MarketplaceAccessFactory.cs +++ b/DistTestCore/Marketplace/MarketplaceAccessFactory.cs @@ -1,5 +1,4 @@ using DistTestCore.Codex; -using Logging; namespace DistTestCore.Marketplace { diff --git a/DistTestCore/OnlineCodexNode.cs b/DistTestCore/OnlineCodexNode.cs index 6e12c79a..d53f2c2a 100644 --- a/DistTestCore/OnlineCodexNode.cs +++ b/DistTestCore/OnlineCodexNode.cs @@ -2,6 +2,7 @@ using DistTestCore.Logs; using DistTestCore.Marketplace; using DistTestCore.Metrics; +using Logging; using NUnit.Framework; namespace DistTestCore @@ -13,7 +14,7 @@ namespace DistTestCore CodexDebugPeerResponse GetDebugPeer(string peerId); CodexDebugPeerResponse GetDebugPeer(string peerId, TimeSpan timeout); ContentId UploadFile(TestFile file); - TestFile? DownloadContent(ContentId contentId); + TestFile? DownloadContent(ContentId contentId, string fileLabel = ""); void ConnectToPeer(IOnlineCodexNode node); ICodexNodeLog DownloadLog(); IMetricsAccess Metrics { get; } @@ -66,23 +67,31 @@ namespace DistTestCore public ContentId UploadFile(TestFile file) { - Log($"Uploading file of size {file.GetFileSize()}..."); using var fileStream = File.OpenRead(file.Filename); - var response = CodexAccess.UploadFile(fileStream); + + var logMessage = $"Uploading file {file.Describe()}..."; + var response = Stopwatch.Measure(lifecycle.Log, logMessage, () => + { + return CodexAccess.UploadFile(fileStream); + }); + if (response.StartsWith(UploadFailedMessage)) { Assert.Fail("Node failed to store block."); } + var logReplacement = $"(CID:{file.Describe()})"; + Log($"ContentId '{response}' is {logReplacement}"); + lifecycle.Log.AddStringReplace(response, logReplacement); Log($"Uploaded file. Received contentId: '{response}'."); return new ContentId(response); } - public TestFile? DownloadContent(ContentId contentId) + public TestFile? DownloadContent(ContentId contentId, string fileLabel = "") { - Log($"Downloading for contentId: '{contentId.Id}'..."); - var file = lifecycle.FileManager.CreateEmptyTestFile(); - DownloadToFile(contentId.Id, file); - Log($"Downloaded file of size {file.GetFileSize()} to '{file.Filename}'."); + var logMessage = $"Downloading for contentId: '{contentId.Id}'..."; + var file = lifecycle.FileManager.CreateEmptyTestFile(fileLabel); + Stopwatch.Measure(lifecycle.Log, logMessage, () => DownloadToFile(contentId.Id, file)); + Log($"Downloaded file {file.Describe()} to '{file.Filename}'."); return file; } diff --git a/DistTestCore/Timing.cs b/DistTestCore/Timing.cs index cff8b09f..c395d07a 100644 --- a/DistTestCore/Timing.cs +++ b/DistTestCore/Timing.cs @@ -31,7 +31,7 @@ namespace DistTestCore public TimeSpan HttpCallRetryDelay() { - return TimeSpan.FromSeconds(3); + return TimeSpan.FromSeconds(1); } public TimeSpan WaitForK8sServiceDelay() @@ -64,7 +64,7 @@ namespace DistTestCore public TimeSpan HttpCallRetryDelay() { - return TimeSpan.FromMinutes(5); + return TimeSpan.FromSeconds(2); } public TimeSpan WaitForK8sServiceDelay() diff --git a/KubernetesWorkflow/K8sController.cs b/KubernetesWorkflow/K8sController.cs index e0f8627b..61742917 100644 --- a/KubernetesWorkflow/K8sController.cs +++ b/KubernetesWorkflow/K8sController.cs @@ -391,6 +391,7 @@ namespace KubernetesWorkflow { Name = recipe.Name, Image = recipe.Image, + ImagePullPolicy = "Always", Ports = CreateContainerPorts(recipe), Env = CreateEnv(recipe) }; diff --git a/Logging/Stopwatch.cs b/Logging/Stopwatch.cs index 9f8a346d..f62f7f63 100644 --- a/Logging/Stopwatch.cs +++ b/Logging/Stopwatch.cs @@ -23,6 +23,14 @@ namespace Logging sw.End(); } + public static T Measure(BaseLog log, string name, Func action, bool debug = false) + { + var sw = Begin(log, name, debug); + var result = action(); + sw.End(); + return result; + } + public static Stopwatch Begin(BaseLog log) { return Begin(log, ""); diff --git a/LongTests/BasicTests/LargeFileTests.cs b/LongTests/BasicTests/LargeFileTests.cs index 3149ee33..9eb3a898 100644 --- a/LongTests/BasicTests/LargeFileTests.cs +++ b/LongTests/BasicTests/LargeFileTests.cs @@ -1,24 +1,74 @@ using DistTestCore; +using DistTestCore.Codex; using NUnit.Framework; +using NUnit.Framework.Interfaces; namespace TestsLong.BasicTests { [TestFixture] public class LargeFileTests : DistTest { - [Test, UseLongTimeouts] - public void OneClientLargeFileTest() + #region Abort test run after first failure + + private bool stop; + + [SetUp] + public void SetUp() { - var primary = SetupCodexNode(s => s - .WithStorageQuota(20.GB())); + if (stop) + { + Assert.Inconclusive("Previous test failed"); + } + } - var testFile = GenerateTestFile(10.GB()); + [TearDown] + public void TearDown() + { + if (TestContext.CurrentContext.Result.Outcome.Status == TestStatus.Failed) + { + stop = true; + } + } - var contentId = primary.UploadFile(testFile); + #endregion - var downloadedFile = primary.DownloadContent(contentId); + [TestCase( 1 * 1)] // 1 MB + [TestCase( 1 * 10)] + [TestCase( 1 * 100)] + [TestCase( 1 * 1024)] // 1 GB + [TestCase( 1024 * 10)] + [TestCase( 1024 * 100)] + [TestCase( 1024 * 1024)] // 1 TB :O + [UseLongTimeouts] + public void DownloadCorrectnessTest(long size) + { + var sizeMB = size.MB(); - testFile.AssertIsEqual(downloadedFile); + var expectedFile = GenerateTestFile(sizeMB); + + var node = SetupCodexNode(s => s.WithStorageQuota((size + 10).MB())); + + var uploadStart = DateTime.UtcNow; + var cid = node.UploadFile(expectedFile); + var downloadStart = DateTime.UtcNow; + var actualFile = node.DownloadContent(cid); + var downloadFinished = DateTime.UtcNow; + + expectedFile.AssertIsEqual(actualFile); + AssertTimeConstraint(uploadStart, downloadStart, downloadFinished, size); + } + + private void AssertTimeConstraint(DateTime uploadStart, DateTime downloadStart, DateTime downloadFinished, long size) + { + float sizeInMB = size; + var uploadTimePerMB = (uploadStart - downloadStart) / sizeInMB; + var downloadTimePerMB = (downloadStart - downloadFinished) / sizeInMB; + + Assert.That(uploadTimePerMB, Is.LessThan(CodexContainerRecipe.MaxUploadTimePerMegabyte), + "MaxUploadTimePerMegabyte performance threshold breached."); + + Assert.That(downloadTimePerMB, Is.LessThan(CodexContainerRecipe.MaxDownloadTimePerMegabyte), + "MaxDownloadTimePerMegabyte performance threshold breached."); } } } diff --git a/LongTests/BasicTests/TestInfraTests.cs b/LongTests/BasicTests/TestInfraTests.cs index 9b3111fa..a6f68e35 100644 --- a/LongTests/BasicTests/TestInfraTests.cs +++ b/LongTests/BasicTests/TestInfraTests.cs @@ -26,26 +26,5 @@ namespace TestsLong.BasicTests Assert.That(!string.IsNullOrEmpty(n.GetDebugInfo().id)); } } - - [Test, UseLongTimeouts] - public void DownloadConsistencyTest() - { - var primary = SetupCodexNode(s => s - .WithStorageQuota(2.MB())); - - var testFile = GenerateTestFile(1.MB()); - - var contentId = primary.UploadFile(testFile); - - var files = new List(); - for (var i = 0; i < 100; i++) - { - files.Add(primary.DownloadContent(contentId)); - } - - Assert.That(files.All(f => f != null)); - Assert.That(files.All(f => f!.GetFileSize() == testFile.GetFileSize())); - foreach (var file in files) file!.AssertIsEqual(testFile); - } } } diff --git a/LongTests/Parallelism.cs b/LongTests/Parallelism.cs new file mode 100644 index 00000000..f45d8f2e --- /dev/null +++ b/LongTests/Parallelism.cs @@ -0,0 +1,6 @@ +using NUnit.Framework; + +[assembly: LevelOfParallelism(1)] +namespace Tests +{ +} diff --git a/Tests/DownloadConnectivityTests/FullyConnectedDownloadTests.cs b/Tests/DownloadConnectivityTests/FullyConnectedDownloadTests.cs new file mode 100644 index 00000000..ff3f62e2 --- /dev/null +++ b/Tests/DownloadConnectivityTests/FullyConnectedDownloadTests.cs @@ -0,0 +1,20 @@ +using DistTestCore; +using NUnit.Framework; + +namespace Tests.DownloadConnectivityTests +{ + [TestFixture] + public class FullyConnectedDownloadTests : AutoBootstrapDistTest + { + [Test] + [Combinatorial] + public void FullyConnectedDownloadTest( + [Values(3, 10, 20)] int numberOfNodes, + [Values(1, 10, 100)] int sizeMBs) + { + for (var i = 0; i < numberOfNodes; i++) SetupCodexNode(); + + PeerDownloadTestHelpers.AssertFullDownloadInterconnectivity(GetAllOnlineCodexNodes(), sizeMBs.MB()); + } + } +} diff --git a/Tests/PeerDiscoveryTests/LayeredDiscoveryTests.cs b/Tests/PeerDiscoveryTests/LayeredDiscoveryTests.cs index 306d305e..aeb414a6 100644 --- a/Tests/PeerDiscoveryTests/LayeredDiscoveryTests.cs +++ b/Tests/PeerDiscoveryTests/LayeredDiscoveryTests.cs @@ -1,7 +1,6 @@ using DistTestCore; using DistTestCore.Helpers; using NUnit.Framework; -using Utils; namespace Tests.PeerDiscoveryTests { @@ -35,7 +34,6 @@ namespace Tests.PeerDiscoveryTests [TestCase(5)] [TestCase(10)] [TestCase(20)] - [TestCase(50)] public void NodeChainTest(int chainLength) { var node = SetupCodexNode(); @@ -45,18 +43,11 @@ namespace Tests.PeerDiscoveryTests } AssertAllNodesConnected(); - - for (int i = 0; i < 5; i++) - { - Time.Sleep(TimeSpan.FromSeconds(30)); - AssertAllNodesConnected(); - } } private void AssertAllNodesConnected() { PeerConnectionTestHelpers.AssertFullyConnected(GetAllOnlineCodexNodes()); - //PeerDownloadTestHelpers.AssertFullDownloadInterconnectivity(GetAllOnlineCodexNodes()); } } } diff --git a/Tests/PeerDiscoveryTests/PeerDiscoveryTests.cs b/Tests/PeerDiscoveryTests/PeerDiscoveryTests.cs index a77cc3aa..57b79cf6 100644 --- a/Tests/PeerDiscoveryTests/PeerDiscoveryTests.cs +++ b/Tests/PeerDiscoveryTests/PeerDiscoveryTests.cs @@ -18,16 +18,6 @@ namespace Tests.PeerDiscoveryTests Assert.That(result.IsPeerFound, Is.False); } - [TestCase(2)] - [TestCase(3)] - [TestCase(10)] - public void VariableNodes(int number) - { - SetupCodexNodes(number); - - AssertAllNodesConnected(); - } - [TestCase(2)] [TestCase(3)] [TestCase(10)] @@ -42,32 +32,9 @@ namespace Tests.PeerDiscoveryTests AssertAllNodesConnected(); } - [TestCase(3, 3)] - [TestCase(3, 5)] - [TestCase(3, 10)] - [TestCase(5, 10)] - [TestCase(3, 20)] - [TestCase(5, 20)] - public void StagedVariableNodes(int numberOfNodes, int numberOfStages) - { - for (var i = 0; i < numberOfStages; i++) - { - SetupCodexNodes(numberOfNodes); - - AssertAllNodesConnected(); - } - - for (int i = 0; i < 5; i++) - { - Time.Sleep(TimeSpan.FromSeconds(30)); - AssertAllNodesConnected(); - } - } - private void AssertAllNodesConnected() { PeerConnectionTestHelpers.AssertFullyConnected(GetAllOnlineCodexNodes()); - //PeerDownloadTestHelpers.AssertFullDownloadInterconnectivity(GetAllOnlineCodexNodes()); } } } diff --git a/Utils/Formatter.cs b/Utils/Formatter.cs new file mode 100644 index 00000000..1ea15503 --- /dev/null +++ b/Utils/Formatter.cs @@ -0,0 +1,16 @@ +namespace Utils +{ + public static class Formatter + { + private static readonly string[] sizeSuffixes = { "B", "KB", "MB", "GB", "TB", "PB", "EB" }; + + public static string FormatByteSize(long bytes) + { + if (bytes == 0) return "0" + sizeSuffixes[0]; + + var sizeOrder = Convert.ToInt32(Math.Floor(Math.Log(bytes, 1024))); + var digit = Math.Round(bytes / Math.Pow(1024, sizeOrder), 1); + return digit.ToString() + sizeSuffixes[sizeOrder]; + } + } +}