Mercurial > pub > ImplabNet
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 |
