comparison Implab.Test/PollingComponentTests.cs @ 203:4d9830a9bbb8 v2

Added 'Fail' method to RunnableComponent which allows component to move from Running to Failed state. Added PollingComponent a timer based runnable component More tests Added FailPromise a thin class to wrap exceptions Fixed error handling in SuccessPromise classes.
author cin
date Tue, 18 Oct 2016 17:49:54 +0300
parents
children 8200ab154c8a
comparison
equal deleted inserted replaced
202:2651cb9a4250 203:4d9830a9bbb8
1 using System;
2 using System.Reflection;
3 using System.Threading;
4 using Implab.Parallels;
5 using Implab.Components;
6 using Implab.Test.Mock;
7
8 #if MONO
9
10 using NUnit.Framework;
11 using TestClassAttribute = NUnit.Framework.TestFixtureAttribute;
12 using TestMethodAttribute = NUnit.Framework.TestAttribute;
13 using AssertFailedException = NUnit.Framework.AssertionException;
14 #else
15
16 using Microsoft.VisualStudio.TestTools.UnitTesting;
17
18 #endif
19
20 namespace Implab.Test {
21 [TestClass]
22 public class PollingComponentTests {
23 static void ShouldThrow(Action action) {
24 try {
25 action();
26 Assert.Fail();
27 } catch (AssertFailedException) {
28 throw;
29 } catch {
30 }
31 }
32
33 [TestMethod]
34 public void NormalFlowTest() {
35 var comp = new MockPollingComponent(TimeSpan.FromMilliseconds(1), null, false);
36
37 Assert.AreEqual(ExecutionState.Created, comp.State);
38
39 comp.Init();
40
41 Assert.AreEqual(ExecutionState.Ready, comp.State);
42
43 comp.Start().Join(1000);
44
45 Assert.AreEqual(ExecutionState.Running, comp.State);
46
47 comp.Stop().Join(1000);
48
49 Assert.AreEqual(ExecutionState.Disposed, comp.State);
50
51 }
52
53 [TestMethod]
54 public void ShouldStartTicks() {
55 var signal = new Signal();
56
57 var comp = new MockPollingComponent(TimeSpan.FromMilliseconds(1), null, true);
58 comp.MockTick = ct => {
59 signal.Set();
60 return Promise.SUCCESS;
61 };
62
63 comp.Start().Join(1000);
64 signal.Wait(1000);
65 comp.Stop().Join(1000);
66 }
67
68 [TestMethod]
69 public void StopShouldWaitForTickToComplete() {
70 var comp = new MockPollingComponent(TimeSpan.FromMilliseconds(1), null, true);
71 var signal = new Signal();
72 var promise = new Promise();
73
74 // timer should tick once
75 comp.MockTick = ct => {
76 signal.Set();
77 return promise;
78 };
79
80 // start timer
81 comp.Start().Join(1000);
82
83 signal.Wait(); // wait for tick
84
85 // try to stop component
86 var stopping = comp.Stop();
87
88 Assert.AreEqual(ExecutionState.Stopping, comp.State);
89 ShouldThrow(() => stopping.Join(100));
90 Assert.AreEqual(ExecutionState.Stopping, comp.State);
91
92 // complete operation
93 promise.Resolve();
94
95 // the component should stop normally
96 stopping.Join(1000);
97
98 Assert.AreEqual(ExecutionState.Disposed, comp.State);
99 }
100
101 [TestMethod]
102 public void ShouldRecoverAfterTickError() {
103 var ticks = 0;
104
105 var comp = new MockPollingComponent(TimeSpan.FromMilliseconds(1), null, true);
106 var signal = new Signal(); // will signal when timer fires 10 times
107
108 comp.MockTick = ct => {
109 ticks++;
110 if (ticks == 10)
111 signal.Set();
112 // each time handler dies
113 throw new Exception("tainted handler");
114 };
115
116 comp.Start();
117
118 signal.Wait(1000);
119
120 comp.Stop().Join(1000);
121
122 Assert.AreEqual(ExecutionState.Disposed, comp.State);
123 }
124
125 [TestMethod]
126 public void StopCancelHandlerOnStop() {
127 var comp = new MockPollingComponent(TimeSpan.FromMilliseconds(1), null, true);
128 var started = new Signal();
129 bool cancelled = false;
130
131 // timer should tick once
132 comp.MockTick = ct => {
133 started.Set();
134
135 while(!ct.IsCancellationRequested) {
136 Thread.Sleep(1);
137 }
138
139 cancelled = true;
140
141 throw new OperationCanceledException();
142 };
143
144 // start timer
145 comp.Start().Join(1000);
146
147 started.Wait(); // wait for tick
148
149 // try to stop component
150 comp.Stop().Join(1000);
151
152 Assert.AreEqual(true, cancelled);
153
154 Assert.AreEqual(ExecutionState.Disposed, comp.State);
155 }
156
157 [TestMethod]
158 public void FailTickOnStopShouldBeIgnored() {
159 var comp = new MockPollingComponent(TimeSpan.FromMilliseconds(1), null, true);
160 var started = new Signal();
161 var finish = new Signal();
162
163 // timer should tick once
164 comp.MockTick = ct => {
165 started.Set();
166 finish.Wait();
167 // component is in stopping state here
168 throw new Exception("Die, die, die!!!");
169 };
170
171
172 comp.MockOnError = comp.CallComponentFail;
173
174 // start timer
175 comp.Start().Join(1000);
176
177 started.Wait(); // wait for tick
178
179 // try to stop component
180 var stopping = comp.Stop();
181
182 // the component is in stopping state but it is waiting for the tick handler to complete
183 finish.Set(); // signal the tick handler to finish
184
185 // tick handler should stop rather soon
186 stopping.Join(1000);
187
188 // validate the component is disposed
189 Assert.AreEqual(ExecutionState.Disposed, comp.State);
190 }
191
192 [TestMethod]
193 public void FailTickShouldFailComponent() {
194 var comp = new MockPollingComponent(TimeSpan.FromMilliseconds(1), null, true);
195 var started = new Signal();
196 var finish = new Signal();
197
198 // timer should tick once
199 comp.MockTick = ct => {
200 started.Set();
201 throw new Exception("Die, die, die!!!");
202 };
203
204
205 comp.MockOnError = err => {
206 comp.CallComponentFail(err);
207 finish.Set();
208 };
209
210 // start timer
211 comp.Start().Join(1000);
212
213 started.Wait(); // wait for tick
214
215 finish.Wait();
216
217 // try to stop component
218 ShouldThrow(() => comp.Stop());
219
220 Assert.AreEqual(ExecutionState.Failed, comp.State);
221 Assert.IsNotNull(comp.LastError);
222 Assert.AreEqual("Die, die, die!!!", comp.LastError.Message);
223
224 comp.Dispose();
225 Assert.AreEqual(ExecutionState.Disposed, comp.State);
226 }
227
228 }
229 }
230