diff Implab.Test/RunnableComponentTests.cs @ 262:f1696cdc3d7a v3 v3.0.8

Added IInitializable.Initialize() overload Added IRunnable.Start(), IRunnable.Start() overloads Fixed cancellation of the current operation when Stop() is called More tests
author cin
date Mon, 16 Apr 2018 02:12:39 +0300
parents 547a2fc0d93e
children
line wrap: on
line diff
--- a/Implab.Test/RunnableComponentTests.cs	Fri Apr 13 19:15:11 2018 +0300
+++ b/Implab.Test/RunnableComponentTests.cs	Mon Apr 16 02:12:39 2018 +0300
@@ -8,7 +8,7 @@
 
     public class RunnableComponentTests {
         [Fact]
-        public async Task Test1() {
+        public async Task SimpleStartStop() {
 
             using (var m = new MockPollComponent(true)) {
                 m.StartWorker = async (ct) => await Task.Yield();
@@ -16,12 +16,246 @@
 
                 Assert.Equal(ExecutionState.Ready, m.State);
                 Assert.NotNull(m.Completion);
-                
-                m.Start(CancellationToken.None);
+
+                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);
             }