Setting up cancelling
This commit is contained in:
parent
efc638a0f9
commit
eaa218f8e0
@ -21,12 +21,13 @@ namespace ContinuousTests
|
|||||||
|
|
||||||
private const string UploadFailedMessage = "Unable to store block";
|
private const string UploadFailedMessage = "Unable to store block";
|
||||||
|
|
||||||
public void Initialize(CodexNode[] nodes, BaseLog log, FileManager fileManager, Configuration configuration)
|
public void Initialize(CodexNode[] nodes, BaseLog log, FileManager fileManager, Configuration configuration, CancellationToken cancelToken)
|
||||||
{
|
{
|
||||||
Nodes = nodes;
|
Nodes = nodes;
|
||||||
Log = log;
|
Log = log;
|
||||||
FileManager = fileManager;
|
FileManager = fileManager;
|
||||||
Configuration = configuration;
|
Configuration = configuration;
|
||||||
|
CancelToken = cancelToken;
|
||||||
|
|
||||||
if (nodes != null)
|
if (nodes != null)
|
||||||
{
|
{
|
||||||
@ -43,6 +44,7 @@ namespace ContinuousTests
|
|||||||
public IFileManager FileManager { get; private set; } = null!;
|
public IFileManager FileManager { get; private set; } = null!;
|
||||||
public Configuration Configuration { get; private set; } = null!;
|
public Configuration Configuration { get; private set; } = null!;
|
||||||
public virtual ITimeSet TimeSet { get { return new DefaultTimeSet(); } }
|
public virtual ITimeSet TimeSet { get { return new DefaultTimeSet(); } }
|
||||||
|
public CancellationToken CancelToken { get; private set; } = null;
|
||||||
public NodeRunner NodeRunner { get; private set; } = null!;
|
public NodeRunner NodeRunner { get; private set; } = null!;
|
||||||
|
|
||||||
public abstract int RequiredNumberOfNodes { get; }
|
public abstract int RequiredNumberOfNodes { get; }
|
||||||
|
@ -10,34 +10,41 @@ namespace ContinuousTests
|
|||||||
private readonly TestFactory testFactory = new TestFactory();
|
private readonly TestFactory testFactory = new TestFactory();
|
||||||
private readonly Configuration config;
|
private readonly Configuration config;
|
||||||
private readonly StartupChecker startupChecker;
|
private readonly StartupChecker startupChecker;
|
||||||
|
private readonly CancellationToken cancelToken;
|
||||||
|
|
||||||
public ContinuousTestRunner(string[] args)
|
public ContinuousTestRunner(string[] args, CancellationToken cancelToken)
|
||||||
{
|
{
|
||||||
config = configLoader.Load(args);
|
config = configLoader.Load(args);
|
||||||
startupChecker = new StartupChecker(config);
|
startupChecker = new StartupChecker(config);
|
||||||
|
this.cancelToken = cancelToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Run()
|
public void Run()
|
||||||
{
|
{
|
||||||
startupChecker.Check();
|
startupChecker.Check();
|
||||||
|
|
||||||
|
var taskFactory = new TaskFactory();
|
||||||
var overviewLog = new FixtureLog(new LogConfig(config.LogPath, false), "Overview");
|
var overviewLog = new FixtureLog(new LogConfig(config.LogPath, false), "Overview");
|
||||||
overviewLog.Log("Continuous tests starting...");
|
overviewLog.Log("Continuous tests starting...");
|
||||||
var allTests = testFactory.CreateTests();
|
var allTests = testFactory.CreateTests();
|
||||||
|
|
||||||
ClearAllCustomNamespaces(allTests, overviewLog);
|
ClearAllCustomNamespaces(allTests, overviewLog);
|
||||||
|
|
||||||
var testLoop = allTests.Select(t => new TestLoop(config, overviewLog, t.GetType(), t.RunTestEvery)).ToArray();
|
var testLoops = allTests.Select(t => new TestLoop(taskFactory, config, overviewLog, t.GetType(), t.RunTestEvery, cancelToken)).ToArray();
|
||||||
|
|
||||||
foreach (var t in testLoop)
|
foreach (var testLoop in testLoops)
|
||||||
{
|
{
|
||||||
overviewLog.Log("Launching test-loop for " + t.Name);
|
cancelToken.ThrowIfCancellationRequested();
|
||||||
t.Begin();
|
|
||||||
|
overviewLog.Log("Launching test-loop for " + testLoop.Name);
|
||||||
|
testLoop.Begin();
|
||||||
Thread.Sleep(TimeSpan.FromSeconds(15));
|
Thread.Sleep(TimeSpan.FromSeconds(15));
|
||||||
}
|
}
|
||||||
|
|
||||||
overviewLog.Log("All test-loops launched.");
|
overviewLog.Log("All test-loops launched.");
|
||||||
while (true) Thread.Sleep((2 ^ 31) - 1);
|
cancelToken.WaitHandle.WaitOne();
|
||||||
|
overviewLog.Log("Cancelling all test-loops...");
|
||||||
|
taskFactory.WaitAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ClearAllCustomNamespaces(ContinuousTest[] allTests, FixtureLog log)
|
private void ClearAllCustomNamespaces(ContinuousTest[] allTests, FixtureLog log)
|
||||||
|
@ -6,7 +6,19 @@ public class Program
|
|||||||
{
|
{
|
||||||
Console.WriteLine("Codex Continous-Test-Runner.");
|
Console.WriteLine("Codex Continous-Test-Runner.");
|
||||||
Console.WriteLine("Running...");
|
Console.WriteLine("Running...");
|
||||||
var runner = new ContinuousTestRunner(args);
|
|
||||||
|
var cts = new CancellationTokenSource();
|
||||||
|
var runner = new ContinuousTestRunner(args, cts.Token);
|
||||||
|
|
||||||
|
Console.CancelKeyPress += (sender, e) =>
|
||||||
|
{
|
||||||
|
Console.WriteLine("Stopping...");
|
||||||
|
e.Cancel = true;
|
||||||
|
|
||||||
|
cts.Cancel();
|
||||||
|
};
|
||||||
|
|
||||||
runner.Run();
|
runner.Run();
|
||||||
|
Console.WriteLine("Done.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,21 +12,24 @@ namespace ContinuousTests
|
|||||||
{
|
{
|
||||||
private readonly CodexNodeFactory codexNodeFactory = new CodexNodeFactory();
|
private readonly CodexNodeFactory codexNodeFactory = new CodexNodeFactory();
|
||||||
private readonly List<Exception> exceptions = new List<Exception>();
|
private readonly List<Exception> exceptions = new List<Exception>();
|
||||||
|
private readonly TaskFactory taskFactory;
|
||||||
private readonly Configuration config;
|
private readonly Configuration config;
|
||||||
private readonly BaseLog overviewLog;
|
private readonly BaseLog overviewLog;
|
||||||
private readonly TestHandle handle;
|
private readonly TestHandle handle;
|
||||||
|
private readonly CancellationToken cancelToken;
|
||||||
private readonly CodexNode[] nodes;
|
private readonly CodexNode[] nodes;
|
||||||
private readonly FileManager fileManager;
|
private readonly FileManager fileManager;
|
||||||
private readonly FixtureLog fixtureLog;
|
private readonly FixtureLog fixtureLog;
|
||||||
private readonly string testName;
|
private readonly string testName;
|
||||||
private readonly string dataFolder;
|
private readonly string dataFolder;
|
||||||
|
|
||||||
public SingleTestRun(Configuration config, BaseLog overviewLog, TestHandle handle)
|
public SingleTestRun(TaskFactory taskFactory, Configuration config, BaseLog overviewLog, TestHandle handle, CancellationToken cancelToken)
|
||||||
{
|
{
|
||||||
|
this.taskFactory = taskFactory;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.overviewLog = overviewLog;
|
this.overviewLog = overviewLog;
|
||||||
this.handle = handle;
|
this.handle = handle;
|
||||||
|
this.cancelToken = cancelToken;
|
||||||
testName = handle.Test.GetType().Name;
|
testName = handle.Test.GetType().Name;
|
||||||
fixtureLog = new FixtureLog(new LogConfig(config.LogPath, false), testName);
|
fixtureLog = new FixtureLog(new LogConfig(config.LogPath, false), testName);
|
||||||
|
|
||||||
@ -37,7 +40,7 @@ namespace ContinuousTests
|
|||||||
|
|
||||||
public void Run()
|
public void Run()
|
||||||
{
|
{
|
||||||
Task.Run(() =>
|
taskFactory.Run(() =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -75,6 +78,8 @@ namespace ContinuousTests
|
|||||||
var t = earliestMoment;
|
var t = earliestMoment;
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
cancelToken.ThrowIfCancellationRequested();
|
||||||
|
|
||||||
RunMoment(t);
|
RunMoment(t);
|
||||||
|
|
||||||
if (handle.Test.TestFailMode == TestFailMode.StopAfterFirstFailure && exceptions.Any())
|
if (handle.Test.TestFailMode == TestFailMode.StopAfterFirstFailure && exceptions.Any())
|
||||||
@ -86,9 +91,10 @@ namespace ContinuousTests
|
|||||||
var nextMoment = handle.GetNextMoment(t);
|
var nextMoment = handle.GetNextMoment(t);
|
||||||
if (nextMoment != null)
|
if (nextMoment != null)
|
||||||
{
|
{
|
||||||
Log($" > Next TestMoment in {nextMoment.Value} seconds...");
|
var delta = TimeSpan.FromSeconds(nextMoment.Value - t);
|
||||||
t += nextMoment.Value;
|
Log($" > Next TestMoment in {Time.FormatDuration(delta)} seconds...");
|
||||||
Thread.Sleep(nextMoment.Value * 1000);
|
cancelToken.WaitHandle.WaitOne(delta);
|
||||||
|
t = nextMoment.Value;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -144,12 +150,12 @@ namespace ContinuousTests
|
|||||||
private void InitializeTest(string name)
|
private void InitializeTest(string name)
|
||||||
{
|
{
|
||||||
Log($" > Running TestMoment '{name}'");
|
Log($" > Running TestMoment '{name}'");
|
||||||
handle.Test.Initialize(nodes, fixtureLog, fileManager, config);
|
handle.Test.Initialize(nodes, fixtureLog, fileManager, config, cancelToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DecommissionTest()
|
private void DecommissionTest()
|
||||||
{
|
{
|
||||||
handle.Test.Initialize(null!, null!, null!, null!);
|
handle.Test.Initialize(null!, null!, null!, null!, cancelToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Log(string msg)
|
private void Log(string msg)
|
||||||
|
39
ContinuousTests/TaskFactory.cs
Normal file
39
ContinuousTests/TaskFactory.cs
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
namespace ContinuousTests
|
||||||
|
{
|
||||||
|
public class TaskFactory
|
||||||
|
{
|
||||||
|
private readonly object taskLock = new();
|
||||||
|
private readonly List<Task> activeTasks = new List<Task>();
|
||||||
|
|
||||||
|
public void Run(Action action)
|
||||||
|
{
|
||||||
|
lock (taskLock)
|
||||||
|
{
|
||||||
|
activeTasks.Add(Task.Run(action).ContinueWith(CleanupTask, null));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void WaitAll()
|
||||||
|
{
|
||||||
|
var tasks = activeTasks.ToArray();
|
||||||
|
Task.WaitAll(tasks);
|
||||||
|
|
||||||
|
var moreTasks = false;
|
||||||
|
lock (taskLock)
|
||||||
|
{
|
||||||
|
activeTasks.RemoveAll(task => task.IsCompleted);
|
||||||
|
moreTasks = activeTasks.Any();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (moreTasks) WaitAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CleanupTask(Task completedTask, object? arg)
|
||||||
|
{
|
||||||
|
lock (taskLock)
|
||||||
|
{
|
||||||
|
activeTasks.Remove(completedTask);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -4,18 +4,21 @@ namespace ContinuousTests
|
|||||||
{
|
{
|
||||||
public class TestLoop
|
public class TestLoop
|
||||||
{
|
{
|
||||||
|
private readonly TaskFactory taskFactory;
|
||||||
private readonly Configuration config;
|
private readonly Configuration config;
|
||||||
private readonly BaseLog overviewLog;
|
private readonly BaseLog overviewLog;
|
||||||
private readonly Type testType;
|
private readonly Type testType;
|
||||||
private readonly TimeSpan runsEvery;
|
private readonly TimeSpan runsEvery;
|
||||||
|
private readonly CancellationToken cancelToken;
|
||||||
|
|
||||||
public TestLoop(Configuration config, BaseLog overviewLog, Type testType, TimeSpan runsEvery)
|
public TestLoop(TaskFactory taskFactory, Configuration config, BaseLog overviewLog, Type testType, TimeSpan runsEvery, CancellationToken cancelToken)
|
||||||
{
|
{
|
||||||
|
this.taskFactory = taskFactory;
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.overviewLog = overviewLog;
|
this.overviewLog = overviewLog;
|
||||||
this.testType = testType;
|
this.testType = testType;
|
||||||
this.runsEvery = runsEvery;
|
this.runsEvery = runsEvery;
|
||||||
|
this.cancelToken = cancelToken;
|
||||||
Name = testType.Name;
|
Name = testType.Name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -23,17 +26,23 @@ namespace ContinuousTests
|
|||||||
|
|
||||||
public void Begin()
|
public void Begin()
|
||||||
{
|
{
|
||||||
Task.Run(() =>
|
taskFactory.Run(() =>
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
|
cancelToken.ThrowIfCancellationRequested();
|
||||||
StartTest();
|
StartTest();
|
||||||
Thread.Sleep(runsEvery);
|
|
||||||
|
cancelToken.WaitHandle.WaitOne(runsEvery);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch(Exception ex)
|
catch (OperationCanceledException)
|
||||||
|
{
|
||||||
|
overviewLog.Log("Test-loop " + testType.Name + " is cancelled.");
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
overviewLog.Error("Test infra failure: TestLoop failed with " + ex);
|
overviewLog.Error("Test infra failure: TestLoop failed with " + ex);
|
||||||
Environment.Exit(-1);
|
Environment.Exit(-1);
|
||||||
@ -45,7 +54,7 @@ namespace ContinuousTests
|
|||||||
{
|
{
|
||||||
var test = (ContinuousTest)Activator.CreateInstance(testType)!;
|
var test = (ContinuousTest)Activator.CreateInstance(testType)!;
|
||||||
var handle = new TestHandle(test);
|
var handle = new TestHandle(test);
|
||||||
var run = new SingleTestRun(config, overviewLog, handle);
|
var run = new SingleTestRun(taskFactory, config, overviewLog, handle, cancelToken);
|
||||||
run.Run();
|
run.Run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user