RunnableComponentTests.cs
264 lines
| 8.5 KiB
| text/x-csharp
|
CSharpLexer
cin
|
r289 | using System; | ||
using System.Threading; | ||||
using System.Threading.Tasks; | ||||
using Implab.Components; | ||||
using Xunit; | ||||
namespace Implab.Test { | ||||
public class RunnableComponentTests { | ||||
[Fact] | ||||
public async Task SimpleStartStop() { | ||||
using (var m = new MockPollComponent(true)) { | ||||
m.StartWorker = async (ct) => await Task.Yield(); | ||||
m.StopWorker = async (ct) => await Task.Yield(); | ||||
Assert.Equal(ExecutionState.Ready, m.State); | ||||
Assert.NotNull(m.Completion); | ||||
m.Start(); | ||||
await m.Completion; | ||||
Assert.Equal(ExecutionState.Running, m.State); | ||||
m.Stop(); | ||||
await m.Completion; | ||||
Assert.Equal(ExecutionState.Stopped, m.State); | ||||
} | ||||
} | ||||
[Fact] | ||||
public async Task SyncStart() { | ||||
using (var m = new MockPollComponent(true)) { | ||||
m.Start(); | ||||
Assert.Equal(ExecutionState.Running, m.State); | ||||
await m.Completion; | ||||
} | ||||
} | ||||
[Fact] | ||||
public async Task AsyncStarting() { | ||||
using (var m = new MockPollComponent(true)) { | ||||
var signal = Safe.CreateTask(); | ||||
m.StartWorker = async (ct) => await signal; | ||||
m.Start(); | ||||
Assert.Equal(ExecutionState.Starting, m.State); | ||||
Assert.False(m.Completion.IsCompleted); | ||||
signal.Start(); | ||||
await m.Completion; | ||||
Assert.Equal(ExecutionState.Running, m.State); | ||||
} | ||||
} | ||||
[Fact] | ||||
public async Task FailWhileStarting() { | ||||
using (var m = new MockPollComponent(true)) { | ||||
const string failMessage = "Fail me"; | ||||
var signal = new Task(() => { | ||||
throw new Exception(failMessage); | ||||
}); | ||||
m.StartWorker = async (ct) => await signal; | ||||
m.Start(); | ||||
Assert.Equal(ExecutionState.Starting, m.State); | ||||
Assert.False(m.Completion.IsCompleted); | ||||
signal.Start(); | ||||
try { | ||||
await m.Completion; | ||||
Assert.True(false); | ||||
} catch (Exception e) { | ||||
Assert.Equal(failMessage, e.Message); | ||||
} | ||||
Assert.Equal(ExecutionState.Failed, m.State); | ||||
} | ||||
} | ||||
[Fact] | ||||
public async Task SyncStop() { | ||||
using (var m = new MockPollComponent(true)) { | ||||
m.Start(); | ||||
Assert.Equal(ExecutionState.Running, m.State); | ||||
m.Stop(); | ||||
Assert.Equal(ExecutionState.Stopped, m.State); | ||||
await m.Completion; | ||||
} | ||||
} | ||||
[Fact] | ||||
public async Task AsyncStopping() { | ||||
using (var m = new MockPollComponent(true)) { | ||||
var signal = Safe.CreateTask(); | ||||
m.StopWorker = async (ct) => await signal; | ||||
// Start | ||||
m.Start(); | ||||
Assert.Equal(ExecutionState.Running, m.State); | ||||
// Stop | ||||
m.Stop(); | ||||
Assert.Equal(ExecutionState.Stopping, m.State); | ||||
Assert.False(m.Completion.IsCompleted); | ||||
signal.Start(); | ||||
await m.Completion; | ||||
Assert.Equal(ExecutionState.Stopped, m.State); | ||||
} | ||||
} | ||||
[Fact] | ||||
public async Task FailWhileStopping() { | ||||
using (var m = new MockPollComponent(true)) { | ||||
const string failMessage = "Fail me"; | ||||
var signal = new Task(() => { | ||||
throw new Exception(failMessage); | ||||
}); | ||||
m.StopWorker = async (ct) => await signal; | ||||
// Start | ||||
m.Start(); | ||||
Assert.Equal(ExecutionState.Running, m.State); | ||||
// Stop | ||||
m.Stop(); | ||||
Assert.Equal(ExecutionState.Stopping, m.State); | ||||
Assert.False(m.Completion.IsCompleted); | ||||
signal.Start(); | ||||
try { | ||||
await m.Completion; | ||||
Assert.True(false); | ||||
} catch (Exception e) { | ||||
Assert.Equal(failMessage, e.Message); | ||||
} | ||||
Assert.Equal(ExecutionState.Failed, m.State); | ||||
} | ||||
} | ||||
[Fact] | ||||
public async Task ThrowOnInvalidTrasition() { | ||||
using (var m = new MockPollComponent(false)) { | ||||
var started = Safe.CreateTask(); | ||||
var stopped = Safe.CreateTask(); | ||||
m.StartWorker = async (ct) => await started; | ||||
m.StopWorker = async (ct) => await stopped; | ||||
Assert.Throws<InvalidOperationException>(() => m.Start()); | ||||
// Initialize | ||||
m.Initialize(); | ||||
await m.Completion; | ||||
// Start | ||||
m.Start(); | ||||
Assert.Equal(ExecutionState.Starting, m.State); | ||||
// Check invalid transitions | ||||
Assert.Throws<InvalidOperationException>(() => m.Start()); | ||||
// Component can be stopped before started | ||||
// m.Stop(CancellationToken.None); | ||||
// Running | ||||
started.Start(); | ||||
await m.Completion; | ||||
Assert.Equal(ExecutionState.Running, m.State); | ||||
Assert.Throws<InvalidOperationException>(() => m.Start()); | ||||
// Stop | ||||
m.Stop(); | ||||
// Check invalid transitions | ||||
Assert.Throws<InvalidOperationException>(() => m.Start()); | ||||
Assert.Throws<InvalidOperationException>(() => m.Stop()); | ||||
// Stopped | ||||
stopped.Start(); | ||||
await m.Completion; | ||||
Assert.Equal(ExecutionState.Stopped, m.State); | ||||
// Check invalid transitions | ||||
Assert.Throws<InvalidOperationException>(() => m.Start()); | ||||
Assert.Throws<InvalidOperationException>(() => m.Stop()); | ||||
} | ||||
} | ||||
[Fact] | ||||
public async Task CancelStart() { | ||||
using (var m = new MockPollComponent(true)) { | ||||
m.StartWorker = (ct) => Safe.CreateTask(ct); | ||||
m.Start(); | ||||
var start = m.Completion; | ||||
Assert.Equal(ExecutionState.Starting, m.State); | ||||
m.Stop(); | ||||
await m.Completion; | ||||
Assert.Equal(ExecutionState.Stopped, m.State); | ||||
Assert.True(start.IsCompleted); | ||||
Assert.True(start.IsCanceled); | ||||
} | ||||
} | ||||
[Fact] | ||||
public async Task AwaitWorker() { | ||||
using (var m = new MockPollComponent(true)) { | ||||
var worker = Safe.CreateTask(); | ||||
m.PollWorker = (ct) => worker; | ||||
m.Start(CancellationToken.None); | ||||
await m.Completion; | ||||
Assert.Equal(ExecutionState.Running, m.State); | ||||
m.Stop(CancellationToken.None); | ||||
Assert.Equal(ExecutionState.Stopping, m.State); | ||||
worker.Start(); | ||||
await m.Completion; | ||||
Assert.Equal(ExecutionState.Stopped, m.State); | ||||
} | ||||
} | ||||
[Fact] | ||||
public async Task CancelWorker() { | ||||
using (var m = new MockPollComponent(true)) { | ||||
var worker = Safe.CreateTask(); | ||||
var started = Safe.CreateTask(); | ||||
m.PollWorker = async (ct) => { | ||||
started.Start(); | ||||
await worker; | ||||
ct.ThrowIfCancellationRequested(); | ||||
}; | ||||
m.Start(CancellationToken.None); | ||||
await m.Completion; | ||||
await started; // await for the poll worker to start | ||||
Assert.Equal(ExecutionState.Running, m.State); | ||||
m.Stop(CancellationToken.None); | ||||
Assert.Equal(ExecutionState.Stopping, m.State); | ||||
worker.Start(); | ||||
await m.Completion; | ||||
Assert.Equal(ExecutionState.Stopped, m.State); | ||||
} | ||||
} | ||||
} | ||||
} | ||||