From f4532f38019acda921ee5500f69e1b1a38e5b16d Mon Sep 17 00:00:00 2001 From: benbierens Date: Fri, 17 Nov 2023 14:51:32 +0100 Subject: [PATCH] Target duration now supports timespan string format. --- Framework/Utils/Time.cs | 29 +++++++++++++++++++ Tests/CodexContinuousTests/Configuration.cs | 4 +-- .../ContinuousTestRunner.cs | 4 +-- Tests/FrameworkTests/FrameworkTests.csproj | 19 ++++++++++++ Tests/FrameworkTests/Utils/TimeTests.cs | 25 ++++++++++++++++ cs-codex-dist-testing.sln | 7 +++++ 6 files changed, 84 insertions(+), 4 deletions(-) create mode 100644 Tests/FrameworkTests/FrameworkTests.csproj create mode 100644 Tests/FrameworkTests/Utils/TimeTests.cs diff --git a/Framework/Utils/Time.cs b/Framework/Utils/Time.cs index d6df480..ca4e115 100644 --- a/Framework/Utils/Time.cs +++ b/Framework/Utils/Time.cs @@ -23,6 +23,35 @@ return result; } + public static TimeSpan ParseTimespan(string span) + { + span = span.Replace(" ", "").Replace(",", ""); + var result = TimeSpan.Zero; + var number = ""; + foreach (var c in span) + { + if (char.IsNumber(c)) number += c; + else + { + var value = Convert.ToInt32(number); + number = ""; + + if (c == 'd') result += TimeSpan.FromDays(value); + else if (c == 'h') result += TimeSpan.FromHours(value); + else if (c == 'm') result += TimeSpan.FromMinutes(value); + else if (c == 's') result += TimeSpan.FromSeconds(value); + else throw new Exception("Unknown time modifier: " + c); + } + } + + if (!string.IsNullOrEmpty(number)) + { + var value = Convert.ToInt32(number); + result += TimeSpan.FromSeconds(value); + } + return result; + } + public static void WaitUntil(Func predicate) { WaitUntil(predicate, TimeSpan.FromMinutes(1), TimeSpan.FromSeconds(1)); diff --git a/Tests/CodexContinuousTests/Configuration.cs b/Tests/CodexContinuousTests/Configuration.cs index 3e51d92..e6eb556 100644 --- a/Tests/CodexContinuousTests/Configuration.cs +++ b/Tests/CodexContinuousTests/Configuration.cs @@ -24,8 +24,8 @@ namespace ContinuousTests [Uniform("stop", "s", "STOPONFAIL", false, "If greater than zero, runner will stop after this many test failures and download all cluster container logs. 0 by default.")] public int StopOnFailure { get; set; } = 0; - [Uniform("target-duration", "td", "TARGETDURATION", false, "If greater than zero, runner will run for this many seconds before stopping.")] - public int TargetDurationSeconds { get; set; } = 0; + [Uniform("target-duration", "td", "TARGETDURATION", false, "If set, runner will run for this length of time before stopping. Supports seconds, or '1d2h3m4s' format.")] + public string TargetDurationSeconds { get; set; } = string.Empty; [Uniform("filter", "f", "FILTER", false, "If set, runs only tests whose names contain any of the filter strings. Comma-separated. Case sensitive.")] public string Filter { get; set; } = string.Empty; diff --git a/Tests/CodexContinuousTests/ContinuousTestRunner.cs b/Tests/CodexContinuousTests/ContinuousTestRunner.cs index 2838a1b..b591d30 100644 --- a/Tests/CodexContinuousTests/ContinuousTestRunner.cs +++ b/Tests/CodexContinuousTests/ContinuousTestRunner.cs @@ -102,9 +102,9 @@ namespace ContinuousTests var testData = FormatTestRuns(testLoops); overviewLog.Log("Total duration: " + testDuration); - if (config.TargetDurationSeconds > 0) + if (!string.IsNullOrEmpty(config.TargetDurationSeconds)) { - var targetDuration = TimeSpan.FromSeconds(config.TargetDurationSeconds); + var targetDuration = Time.ParseTimespan(config.TargetDurationSeconds); var wasCancelled = cancelToken.WaitHandle.WaitOne(targetDuration); if (!wasCancelled) { diff --git a/Tests/FrameworkTests/FrameworkTests.csproj b/Tests/FrameworkTests/FrameworkTests.csproj new file mode 100644 index 0000000..fbad277 --- /dev/null +++ b/Tests/FrameworkTests/FrameworkTests.csproj @@ -0,0 +1,19 @@ + + + + net7.0 + enable + enable + + + + + + + + + + + + + diff --git a/Tests/FrameworkTests/Utils/TimeTests.cs b/Tests/FrameworkTests/Utils/TimeTests.cs new file mode 100644 index 0000000..207b338 --- /dev/null +++ b/Tests/FrameworkTests/Utils/TimeTests.cs @@ -0,0 +1,25 @@ +using NUnit.Framework; +using Utils; + +namespace FrameworkTests.Utils +{ + [TestFixture] + public class TimeTests + { + [Test] + public void Timespan() + { + Assert.That(Time.ParseTimespan("10"), Is.EqualTo(TimeSpan.FromSeconds(10))); + Assert.That(Time.ParseTimespan("10s"), Is.EqualTo(TimeSpan.FromSeconds(10))); + Assert.That(Time.ParseTimespan("10m"), Is.EqualTo(TimeSpan.FromMinutes(10))); + Assert.That(Time.ParseTimespan("10d"), Is.EqualTo(TimeSpan.FromDays(10))); + Assert.That(Time.ParseTimespan("120s"), Is.EqualTo(TimeSpan.FromSeconds(120))); + Assert.That(Time.ParseTimespan("2d14h6m28s"), Is.EqualTo( + TimeSpan.FromDays(2) + + TimeSpan.FromHours(14) + + TimeSpan.FromMinutes(6) + + TimeSpan.FromSeconds(28) + )); + } + } +} diff --git a/cs-codex-dist-testing.sln b/cs-codex-dist-testing.sln index 944f83b..6b879f1 100644 --- a/cs-codex-dist-testing.sln +++ b/cs-codex-dist-testing.sln @@ -51,6 +51,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "TestClusterStarter", "Tools EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DeployAndRunPlugin", "ProjectPlugins\DeployAndRunPlugin\DeployAndRunPlugin.csproj", "{1CC5AF82-8924-4C7E-BFF1-3125D86E53FB}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "FrameworkTests", "Tests\FrameworkTests\FrameworkTests.csproj", "{25E72004-4D71-4D1E-A193-FC125D12FF96}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -137,6 +139,10 @@ Global {1CC5AF82-8924-4C7E-BFF1-3125D86E53FB}.Debug|Any CPU.Build.0 = Debug|Any CPU {1CC5AF82-8924-4C7E-BFF1-3125D86E53FB}.Release|Any CPU.ActiveCfg = Release|Any CPU {1CC5AF82-8924-4C7E-BFF1-3125D86E53FB}.Release|Any CPU.Build.0 = Release|Any CPU + {25E72004-4D71-4D1E-A193-FC125D12FF96}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {25E72004-4D71-4D1E-A193-FC125D12FF96}.Debug|Any CPU.Build.0 = Debug|Any CPU + {25E72004-4D71-4D1E-A193-FC125D12FF96}.Release|Any CPU.ActiveCfg = Release|Any CPU + {25E72004-4D71-4D1E-A193-FC125D12FF96}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -162,6 +168,7 @@ Global {FB96A58B-F7F0-490A-9A85-72A96A018042} = {8F1F1C2A-E313-4E0C-BE40-58FB0BA91124} {3E38A906-C2FC-43DC-8CA2-FC07C79CF3CA} = {7591C5B3-D86E-4AE4-8ED2-B272D17FE7E3} {1CC5AF82-8924-4C7E-BFF1-3125D86E53FB} = {8F1F1C2A-E313-4E0C-BE40-58FB0BA91124} + {25E72004-4D71-4D1E-A193-FC125D12FF96} = {88C2A621-8A98-4D07-8625-7900FC8EF89E} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {237BF0AA-9EC4-4659-AD9A-65DEB974250C}