Merge pull request #4434 from BrzVlad/fix-unload-hang
[mono.git] / mcs / class / corlib / Test / System.Threading / TimerTest.cs
1 //
2 // TimerTest.cs - NUnit test cases for System.Threading.Timer
3 //
4 // Author:
5 //   Zoltan Varga (vargaz@freemail.hu)
6 //   Rafael Ferreira (raf@ophion.org)
7 //
8 // (C) 2004 Novell, Inc (http://www.novell.com)
9 //
10
11 using NUnit.Framework;
12 using System;
13 using System.Threading;
14 using System.Collections;
15
16 namespace MonoTests.System.Threading {
17         [TestFixture]
18         public class TimerTest {
19                 // this bucket is used to avoid non-theadlocal issues
20                 class Bucket {
21                         public int count;
22                         public ManualResetEventSlim mre = new ManualResetEventSlim (false); 
23                 }
24
25                 [SetUp]
26                 public void Setup ()
27                 {
28                         //creating a timer that will never run just to make sure the
29                         // scheduler is warm for the unit tests
30                         // this makes fair for the "DueTime" test since it 
31                         // doesn't have to wait for the scheduler thread to be 
32                         // created. 
33                         new Timer (o => DoNothing (o), null, Timeout.Infinite, 0);
34                 }
35
36                 void DoNothing (object foo)
37                 {
38                 }
39
40                 private void Callback2 (object foo)
41                 {
42                         Bucket b = foo as Bucket;
43                         Interlocked.Increment (ref b.count);
44                         b.mre.Set ();
45                 }
46
47
48                 [Test]
49                 public void TestDueTime ()
50                 {
51                         Bucket bucket = new Bucket();
52
53                         using (Timer t = new Timer (o => Callback2 (o), bucket, 200, Timeout.Infinite)) {
54                                 Assert.IsTrue (bucket.mre.Wait (5000), "#-1");
55                                 Assert.AreEqual (1, bucket.count, "#1");
56                         }
57                 }
58
59                 [Test]
60                 public void TestDispose ()
61                 {       
62                         Bucket bucket = new Bucket();
63
64                         using (Timer t = new Timer (o => Callback2 (o), bucket, 10, 10)) {
65                                 Assert.IsTrue (bucket.mre.Wait (5000), "#-1");
66                         }
67                         //If the callback is called after dispose, it will NRE and be reported
68                         bucket.mre = null;
69                         int c = bucket.count;
70                         Assert.IsTrue (c > 0, "#1");
71                 }
72
73                 [Test]
74                 public void TestChange ()
75                 {
76                         Bucket bucket = new Bucket();
77
78                         using (Timer t = new Timer (o => Callback2 (o), bucket, 10, 10)) {
79                                 Assert.IsTrue (bucket.mre.Wait (5000), "#-1");
80                                 int c = bucket.count;
81                                 Assert.IsTrue (c > 0, "#1 " + c);
82                                 t.Change (100000, 1000000);
83                                 c = bucket.count;
84                                 Thread.Sleep (500);
85                                 Assert.IsTrue (bucket.count <= c + 1, "#2 " + c);
86                         }
87                 }
88
89                 [Test]
90                 public void TestZeroDueTime ()
91                 {
92                         Bucket bucket = new Bucket();
93
94                         using (Timer t = new Timer (o => Callback2 (o), bucket, 0, Timeout.Infinite)) {
95                                 Assert.IsTrue (bucket.mre.Wait (5000), "#-1");
96                                 bucket.mre.Reset ();
97                                 Assert.AreEqual (1, bucket.count, "#1");
98                                 t.Change (0, Timeout.Infinite);
99                                 Assert.IsTrue (bucket.mre.Wait (5000), "#1.5");
100                                 Assert.AreEqual (2, bucket.count, "#2");
101                         }
102                 }
103
104                 [Test] // bug #320950
105                 public void TestDispose2 ()
106                 {
107                         Timer t = new Timer (o => DoNothing (o), null, 10, 10);
108                         t.Dispose ();
109                         t.Dispose ();
110                 }
111                 
112                 [Test]
113                 public void TestHeavyCreationLoad ()
114                 {
115                         Bucket b = new Bucket ();
116
117                         for (int i = 0; i < 500; ++i)
118                                 new Timer (o => Callback (o), b, 10, Timeout.Infinite);
119
120                         // 1000 * 10 msec = 10,000 msec or 10 sec - if everything goes well
121                         // we add some slack to cope with timing issues caused by system load etc.
122                         for (int i = 0; i < 20; ++i) {
123                                 if (b.count == 500)
124                                         break;
125                                 Thread.Sleep (1000);
126                         }
127
128                         Assert.AreEqual (500, b.count);
129                 }
130
131                 [Test]
132                 public void TestQuickDisposeDeadlockBug ()
133                 {
134                         Bucket b = new Bucket ();
135                         ArrayList timers = new ArrayList (500);
136
137                         for (int i = 0; i < 500; ++i) {
138                                 using (Timer t = new Timer (o => Callback (o), b, 10, Timeout.Infinite)) {
139                                         timers.Add (t);
140                                 }
141                         }
142
143                         Thread.Sleep (11 * 500);
144                 }
145
146                 [Test]
147                 public void TestInt32MaxDelay ()
148                 {
149                         Bucket b = new Bucket ();
150
151                         using (new Timer (o => Callback (o), b, Int32.MaxValue, Timeout.Infinite)) {
152                                 Thread.Sleep (50);
153                                 Assert.AreEqual (0, b.count);
154                         }
155                 }
156
157                 [Test]
158                 public void TestInt32MaxPeriod ()
159                 {
160                         Bucket b = new Bucket ();
161                         
162                         using (new Timer (o => Callback (o), b, 0, Int32.MaxValue)) {
163                                 Thread.Sleep (50);
164                                 Assert.AreEqual (1, b.count);
165                         }
166                 }
167
168                 [Test]
169                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
170                 public void TestNegativeDelay ()
171                 {
172                         Bucket b = new Bucket ();
173
174                         using (new Timer (o => Callback (o), b, -10, Timeout.Infinite)) {
175                         }
176                 }
177
178                 [Test]
179                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
180                 public void TestNegativePeriod ()
181                 {
182                         Bucket b = new Bucket ();
183
184                         using (new Timer (o => Callback (o), b, 0, -10)) {
185                         }
186                 }
187
188                 [Test]
189                 public void TestDelayZeroPeriodZero()
190                 {
191                         Bucket b = new Bucket();
192
193                         using (Timer t = new Timer(o => Callback (o),b,0,0)) {
194                                 Thread.Sleep(100);
195                                 t.Change (int.MaxValue, Timeout.Infinite);
196                                 // since period is 0 the callback should happen once (bug #340212)
197                                 Assert.AreEqual (1, b.count, "only once");
198                         }
199                 }
200
201                 [Test]
202                 [Ignore ()]
203                 public void TestDisposeOnCallback ()
204                 {
205                         // this test is bad, as the provided `state` (t1) is null and will throw an NRE inside the callback
206                         // that was ignored before 238785a3e3d510528228fc551625975bc508c2f3 and most unit test runner won't
207                         // report it since the NRE will not happen on the main thread (but Touch.Unit will)
208                         Timer t1 = null;
209                         t1 = new Timer (o => CallbackTestDisposeOnCallback (o), t1, 0, 10);
210                         Thread.Sleep (200);
211                         Assert.IsNotNull (t1);
212                         
213                 }
214
215                 private void CallbackTestDisposeOnCallback (object foo)
216                 {
217                         ((Timer) foo).Dispose ();
218                 }
219
220                 private void Callback (object foo)
221                 {
222                         Bucket b = foo as Bucket;
223                         Interlocked.Increment (ref b.count);
224                 }
225
226                 [Test]
227                 [ExpectedException (typeof (ArgumentNullException))]
228                 public void DisposeNullWaitHandle ()
229                 {
230                         using (Timer t = new Timer (o => DoNothing (o), null, 0, 0)) {
231                                 t.Dispose (null);
232                         }
233                 }
234
235                 [Test]
236                 public void Change_IntInt_Infinite ()
237                 {
238                         using (Timer t = new Timer (o => DoNothing (o), null, 0, 0)) {
239                                 t.Change ((int)Timeout.Infinite, (int)Timeout.Infinite);
240                         }
241                 }
242
243                 [Test]
244                 public void Change_IntInt_MaxValue ()
245                 {
246                         using (Timer t = new Timer (o => DoNothing (o), null, 0, 0)) {
247                                 t.Change (Int32.MaxValue, Int32.MaxValue);
248                         }
249                 }
250
251                 [Test]
252                 public void Change_UIntUInt_Infinite ()
253                 {
254                         using (Timer t = new Timer (o => DoNothing (o), null, 0, 0)) {
255                                 t.Change (unchecked ((uint) Timeout.Infinite), unchecked ((uint) Timeout.Infinite));
256                         }
257                 }
258
259                 [Test]
260                 public void Change_UIntUInt_MaxValue ()
261                 {
262                         using (Timer t = new Timer (o => DoNothing (o), null, 0, 0)) {
263                                 // UInt32.MaxValue == Timeout.Infinite == 0xffffffff
264                                 t.Change (UInt32.MaxValue, UInt32.MaxValue);
265                         }
266                 }
267
268                 [Test]
269                 public void Change_LongLong_Infinite ()
270                 {
271                         using (Timer t = new Timer (o => DoNothing (o), null, 0, 0)) {
272                                 t.Change ((long) Timeout.Infinite, (long) Timeout.Infinite);
273                         }
274                 }
275
276                 [Test]
277                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
278                 public void Change_LongLong_MaxValue ()
279                 {
280                         using (Timer t = new Timer (o => DoNothing (o), null, 0, 0)) {
281                                 t.Change (Int64.MaxValue, Int64.MaxValue);
282                         }
283                 }
284
285                 [Test]
286                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
287                 public void Change_LongLong_UInt32MaxValue ()
288                 {
289                         using (Timer t = new Timer (o => DoNothing (o), null, 0, 0)) {
290                                 // not identical to (long)-1
291                                 t.Change ((long)UInt32.MaxValue, (long)UInt32.MaxValue);
292                         }
293                 }
294
295                 [Test]
296                 public void Change_LongLong_UInt32MaxValueMinusOne ()
297                 {
298                         using (Timer t = new Timer (o => DoNothing (o), null, 0, 0)) {
299                                 // not identical to (long)-1
300                                 t.Change ((long) UInt32.MaxValue - 1, (long) UInt32.MaxValue -1);
301                         }
302                 }
303
304                 [Test]
305                 public void Change_TimeSpanTimeSpan_Infinite ()
306                 {
307                         using (Timer t = new Timer (o => DoNothing (o), null, 0, 0)) {
308                                 t.Change (new TimeSpan (-1), new TimeSpan (-1));
309                         }
310                 }
311
312                 [Test]
313                 [ExpectedException (typeof (ArgumentOutOfRangeException))]
314                 public void Change_TimeSpanTimeSpan_MaxValue ()
315                 {
316                         using (Timer t = new Timer (o => DoNothing (o), null, 0, 0)) {
317                                 t.Change (TimeSpan.MaxValue, TimeSpan.MaxValue);
318                         }
319                 }
320
321                 [Test]
322                 public void Change_TimeSpanTimeSpan_UInt32MaxValue ()
323                 {
324                         using (Timer t = new Timer (o => DoNothing (o), null, 0, 0)) {
325                                 t.Change (new TimeSpan (UInt32.MaxValue), new TimeSpan (UInt32.MaxValue));
326                         }
327                 }
328         }
329 }