##// END OF EJS Templates
Merge pull request !2 from ImplabNet v3...
Merge pull request !2 from ImplabNet v3 Changes from branch: V3

File last commit:

r289:95896f882995 v3.0.14 v3
r294:abef3ebaa230 merge default
Show More
RunnableComponentTests.cs
264 lines | 8.5 KiB | text/x-csharp | CSharpLexer
/ Implab.Test / src / RunnableComponentTests.cs
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);
}
}
}
}