[bcl] Add NUnitHelper.cs with API not in nunit-lite
[mono.git] / mcs / class / Mono.Posix / Test / Mono.Unix / UnixSignalTest.cs
1 //
2 // UnixSignalTest.cs - NUnit Test Cases for Mono.Unix.UnixSignal
3 //
4 // Authors:
5 //      Jonathan Pryor  <jonpryor@vt.edu>
6 //
7 // (C) 2008 Jonathan Pryor
8 //
9
10 using NUnit.Framework;
11
12 using System;
13 using System.Text;
14 using System.Threading;
15 using Mono.Unix;
16 using Mono.Unix.Android;
17 using Mono.Unix.Native;
18
19 namespace MonoTests.Mono.Unix {
20
21         [TestFixture]
22         public class UnixSignalTest {
23
24                 // helper method to create a thread waiting on a UnixSignal
25                 static Thread CreateWaitSignalThread (UnixSignal signal, int timeout)
26                 {
27                         Thread t1 = new Thread(delegate() {
28                                                 DateTime start = DateTime.Now;
29                                                 bool r = signal.WaitOne (timeout, false);
30                                                 DateTime end = DateTime.Now;
31                                                 Assert.AreEqual (signal.Count, 1);
32                                                 Assert.AreEqual (r, true);
33                                                 if ((end - start) > new TimeSpan (0, 0, timeout/1000))
34                                                         throw new InvalidOperationException ("Signal slept too long");
35                                         });
36                         return t1;
37                 }
38
39                 // helper method to create a two-thread test
40                 static void MultiThreadTest (UnixSignal signal, int timeout, ThreadStart tstart)
41                 {
42                         Thread t1 = CreateWaitSignalThread (signal, timeout);
43                         Thread t2 = new Thread (tstart);
44                         t1.Start ();
45                         t2.Start ();
46                         t1.Join ();
47                         t2.Join ();
48                 }
49
50                 [Test]
51                 public void TestNestedInvocation()
52                 {
53                         UnixSignal s = new UnixSignal(Signum.SIGINT);
54                         Thread a = new Thread(delegate() {
55                                         bool r = s.WaitOne (1000, false);
56       });
57                         Thread b = new Thread(delegate() {
58                                         bool r = s.WaitOne (500, false);
59       });
60                         a.Start();
61                         b.Start();
62                         a.Join();
63                         b.Join();
64                 }
65
66                 [Test]
67                 public void TestWaitAnyFailsWithMore64Signals()
68                 {
69                         UnixSignal s1 = new UnixSignal(Signum.SIGINT);
70                         UnixSignal[] signals = new UnixSignal[65];
71                         for (int i=0; i<65; ++i)
72                                 signals[i] = s1;
73                         
74                         Assert.That(UnixSignal.WaitAny(signals, new TimeSpan(0,0,1)), Is.EqualTo(-1));
75                 }
76
77                 [Test]
78                 public void TestConcurrentWaitOne()
79                 {
80                         UnixSignal s1 = new UnixSignal(Signum.SIGINT);
81                         UnixSignal s2 = new UnixSignal(Signum.SIGINT);
82                         Thread a = CreateWaitSignalThread(s1, 10000);
83                         Thread b = CreateWaitSignalThread(s2, 5000);
84                         Thread c = new Thread (delegate () {
85                                         Thread.Sleep (1000);
86                                         Stdlib.raise (Signum.SIGINT);
87                         });
88                         a.Start();
89                         b.Start();
90                         c.Start();
91                         a.Join();
92                         b.Join();
93                         c.Join();
94                         Assert.That(s1.Count, Is.EqualTo(1), "Expected 1 signal raised");
95                         Assert.That(s2.Count, Is.EqualTo(1), "Expected 1 signal raised");
96                 }
97
98                 [Test]
99                 public void TestConcurrentWaitOneSameInstance()
100                 {
101                         UnixSignal s1 = new UnixSignal(Signum.SIGINT);
102                         Thread a = CreateWaitSignalThread(s1, 10000);
103                         Thread b = CreateWaitSignalThread(s1, 10000);
104                         Thread c = new Thread (delegate () {
105                                         Thread.Sleep (500);
106                                         Stdlib.raise (Signum.SIGINT);
107                         });
108                         a.Start();
109                         b.Start();
110                         c.Start();
111                         a.Join();
112                         b.Join();
113                         c.Join();
114                 }
115
116                 [Test]
117                 [Category ("AndroidNotWorking")] // Crashes (silently) the runtime in similar fashion to real-time signals
118                 public void TestSignumProperty ()
119                 {
120                         UnixSignal signal1 = new UnixSignal (Signum.SIGSEGV);
121                         Assert.That (signal1.Signum, Is.EqualTo (Signum.SIGSEGV));
122                 }
123         
124                 [Test]
125                 [Category ("NotOnMac")]
126                 public void TestRealTimeCstor ()
127                 {
128                         if (!TestHelper.CanUseRealTimeSignals ())
129                                 return;
130                         RealTimeSignum rts = new RealTimeSignum (0);
131                         using (UnixSignal s = new UnixSignal (rts))
132                         {
133                                 Assert.That(s.IsRealTimeSignal);
134                                 Assert.That(s.RealTimeSignum, Is.EqualTo (rts));
135                         }
136                 }
137
138                 [Test]
139                 [ExpectedException]
140                 [Category ("NotOnMac")]
141                 public void TestSignumPropertyThrows ()
142                 {
143                         if (!TestHelper.CanUseRealTimeSignals ())
144                                 return;
145                         UnixSignal signal1 = new UnixSignal (new RealTimeSignum (0));
146                         Signum s = signal1.Signum;
147                 }
148
149                 [Test]
150                 [Category ("NotOnMac")]
151                 public void TestRealTimeSignumProperty ()
152                 {
153                         if (!TestHelper.CanUseRealTimeSignals ())
154                                 return;
155                         RealTimeSignum rts = new RealTimeSignum (0);
156                         UnixSignal signal1 = new UnixSignal (rts);
157                         Assert.That (signal1.RealTimeSignum, Is.EqualTo (rts));
158                 }
159         
160                 [Test]
161                 [ExpectedException]
162                 [Category ("NotOnMac")]
163                 public void TestRealTimePropertyThrows ()
164                 {
165                         if (!TestHelper.CanUseRealTimeSignals ())
166                                 return;
167                         UnixSignal signal1 = new UnixSignal (Signum.SIGSEGV);
168                         RealTimeSignum s = signal1.RealTimeSignum;
169                 }
170
171                 [Test]
172                 [Category ("NotOnMac")]
173                 public void TestRaiseRTMINSignal ()
174                 {
175                         if (!TestHelper.CanUseRealTimeSignals ())
176                                 return;
177                         RealTimeSignum rts = new RealTimeSignum (0);
178                         using (UnixSignal signal = new UnixSignal (rts))
179                         {
180                                 MultiThreadTest (signal, 5000, delegate() {
181                                         Thread.Sleep (1000);
182                                         Stdlib.raise (rts);
183                                         });
184                         }
185                 }
186
187                 [Test]
188                 [Category ("NotOnMac")]
189                 public void TestRaiseRTMINPlusOneSignal ()
190                 {
191                         if (!TestHelper.CanUseRealTimeSignals ())
192                                 return;
193                         /*this number is a guestimate, but it's ok*/
194                         for (int i = 1; i < 10; ++i) {
195                                 RealTimeSignum rts = new RealTimeSignum (i);
196                                 UnixSignal signal;
197                                 try {
198                                         signal  = new UnixSignal (rts);
199                                 } catch (ArgumentException) { /*skip the ones that are unavailable*/
200                                         continue;
201                                 }
202                                 using (signal)
203                                 {
204                                         MultiThreadTest (signal, 5000, delegate() {
205                                                 Thread.Sleep(1000);
206                                                 Stdlib.raise(rts);
207                                                 });
208                                 }
209                                 return;
210                         }
211                         Assert.IsTrue (false, "#1 No available RT signal");
212                 }
213
214                 [Test]
215                 [Category ("NotOnMac")]
216                 public void TestCanRegisterRTSignalMultipleTimes ()
217                 {
218                         if (!TestHelper.CanUseRealTimeSignals ())
219                                 return;
220                         /*this number is a guestimate, but it's ok*/
221                         for (int i = 1; i < 10; ++i) {
222                                 RealTimeSignum rts = new RealTimeSignum (i);
223                                 UnixSignal signal;
224                                 try {
225                                         signal  = new UnixSignal (rts);
226                                 } catch (ArgumentException) { /*skip the ones that are unavailable*/
227                                         continue;
228                                 }
229                                 try {
230                                         using (UnixSignal signal2 =  new UnixSignal (rts))
231                                         {
232                                                 //ok
233                                                 return;
234                                         }
235                                 } catch (ArgumentException) { /*skip the ones that are unavailable*/
236                                                 Assert.IsTrue (false, "#1 Could not register second signal handler");
237                                 }
238                         }
239                         Assert.IsTrue (false, "#2 No available RT signal");
240                 }
241
242                 [Test]
243                 public void TestRaise ()
244                 {
245                         Thread t1 = new Thread (delegate () {
246                                         using (UnixSignal a = new UnixSignal (Signum.SIGINT)) {
247                                                 DateTime start = DateTime.Now;
248                                                 bool r = a.WaitOne (5000, false);
249                                                 DateTime end = DateTime.Now;
250                                                 Assert.AreEqual (a.Count, 1);
251                                                 Assert.AreEqual (r, true);
252                                                 if ((end - start) > new TimeSpan (0, 0, 5))
253                                                         throw new InvalidOperationException ("Signal slept too long");
254                                         }
255                         });
256                         Thread t2 = new Thread (delegate () {
257                                         Thread.Sleep (1000);
258                                         Stdlib.raise (Signum.SIGINT);
259                         });
260                         t1.Start ();
261                         t2.Start ();
262                         t1.Join ();
263                         t2.Join ();
264                 }
265
266                 [Test]
267                 public void TestRaiseAny ()
268                 {
269                         Thread t1 = new Thread (delegate () {
270                                         using (UnixSignal a = new UnixSignal (Signum.SIGINT)) {
271                                                 DateTime start = DateTime.Now;
272                                                 int idx = UnixSignal.WaitAny (new UnixSignal[]{a}, 5000);
273                                                 DateTime end = DateTime.Now;
274                                                 Assert.AreEqual (idx, 0);
275                                                 Assert.AreEqual (a.Count, 1);
276                                                 if ((end - start) > new TimeSpan (0, 0, 5))
277                                                         throw new InvalidOperationException ("Signal slept too long");
278                                         }
279                         });
280                         Thread t2 = new Thread (delegate () {
281                                         Thread.Sleep (1000);
282                                         Stdlib.raise (Signum.SIGINT);
283                         });
284                         t1.Start ();
285                         t2.Start ();
286                         t1.Join ();
287                         t2.Join ();
288                 }
289
290                 [Test]
291                 public void TestSeparation ()
292                 {
293                         Thread t1 = new Thread (delegate () {
294                                         using (UnixSignal a = new UnixSignal (Signum.SIGINT))
295                                         using (UnixSignal b = new UnixSignal (Signum.SIGTERM)) {
296                                                 DateTime start = DateTime.Now;
297                                                 int idx = UnixSignal.WaitAny (new UnixSignal[]{a, b}, 5000);
298                                                 DateTime end = DateTime.Now;
299                                                 Assert.AreEqual (idx, 1);
300                                                 Assert.AreEqual (a.Count, 0);
301                                                 Assert.AreEqual (b.Count, 1);
302                                                 if ((end - start) > new TimeSpan (0, 0, 5))
303                                                         throw new InvalidOperationException ("Signal slept too long");
304                                         }
305                         });
306                         Thread t2 = new Thread (delegate () {
307                                         Thread.Sleep (1000);
308                                         Stdlib.raise (Signum.SIGTERM);
309                         });
310                         t1.Start ();
311                         t2.Start ();
312                         t1.Join ();
313                         t2.Join ();
314                 }
315
316                 [Test]
317                 public void TestNoEmit ()
318                 {
319                         using (UnixSignal u = new UnixSignal (Signum.SIGINT)) {
320                                 DateTime start = DateTime.Now;
321                                 bool r = u.WaitOne (5100, false);
322                                 Assert.AreEqual (r, false);
323                                 DateTime end = DateTime.Now;
324                                 if ((end - start) < new TimeSpan (0, 0, 5))
325                                         throw new InvalidOperationException ("Signal didn't block for 5s; blocked for " + (end-start).ToString());
326                         }
327                 }
328
329                 [Test]
330                 public void TestNoEmitAny ()
331                 {
332                         using (UnixSignal u = new UnixSignal (Signum.SIGINT)) {
333                                 int idx = UnixSignal.WaitAny (new UnixSignal[]{u}, 5100);
334                                 Assert.AreEqual (idx, 5100);
335                         }
336                 }
337
338                 [Test]
339                 public void TestDispose1 ()
340                 {
341                         UnixSignal a = new UnixSignal (Signum.SIGINT);
342                         UnixSignal b = new UnixSignal (Signum.SIGINT);
343
344                         Stdlib.raise (Signum.SIGINT);
345                         SleepUntilSignaled (a);
346
347                         Assert.AreEqual (a.Count, 1);
348                         Assert.AreEqual (b.Count, 1);
349
350                         a.Close ();
351                         b.Reset ();
352
353                         Stdlib.raise (Signum.SIGINT);
354                         SleepUntilSignaled (b);
355                         Assert.AreEqual (b.Count, 1);
356
357                         b.Close ();
358                 }
359
360                 static void SleepUntilSignaled (UnixSignal s)
361                 {
362                         for (int i = 0; i < 10; ++i) {
363                                 if (s.Count > 0)
364                                         break;
365                                 Thread.Sleep (100);
366                         }
367                 }
368
369                 [Test]
370                 public void TestDispose2 ()
371                 {
372                         UnixSignal a = new UnixSignal (Signum.SIGINT);
373                         UnixSignal b = new UnixSignal (Signum.SIGINT);
374
375                         Stdlib.raise (Signum.SIGINT);
376                         SleepUntilSignaled (a);
377
378                         Assert.AreEqual (a.Count, 1);
379                         Assert.AreEqual (b.Count, 1);
380
381                         b.Close ();
382                         a.Reset ();
383
384                         Stdlib.raise (Signum.SIGINT);
385                         SleepUntilSignaled (a);
386                         Assert.AreEqual (a.Count, 1);
387
388                         a.Close ();
389                 }
390
391                 [Test]
392                 [Category ("AndroidNotWorking")] // Android 4.4.4 doesn't have signal(2)
393                 public void TestSignalActionInteraction ()
394                 {
395                         using (UnixSignal a = new UnixSignal (Signum.SIGINT)) {
396                                 Stdlib.SetSignalAction (Signum.SIGINT, SignalAction.Ignore);
397                                 Stdlib.raise (Signum.SIGINT);
398                                 Assert.AreEqual (a.Count, 0); // never invoked
399                         }
400                 }
401
402                 static readonly Signum[] signals = new Signum[] {
403                         Signum.SIGHUP, Signum.SIGINT, Signum.SIGTERM, Signum.SIGCONT,
404                 };
405
406                 const int StormCount = 100000;
407
408                 [Test]
409                 public void TestRaiseStorm ()
410                 {
411                         UnixSignal[] usignals = CreateSignals (signals);
412                         Thread[] threads = new Thread[]{
413                                 CreateRaiseStormThread (StormCount/4),
414                                 CreateRaiseStormThread (StormCount/4),
415                                 CreateRaiseStormThread (StormCount/4),
416                                 CreateRaiseStormThread (StormCount/4),
417                         };
418                         foreach (Thread t in threads)
419                                 t.Start ();
420                         foreach (Thread t in threads)
421                                 t.Join ();
422                         AssertCountSet (usignals);
423                         // signal delivery might take some time, wait a bit before closing
424                         // the UnixSignal so we can ignore it and not terminate the process
425                         // when a SIGHUP/SIGTERM arrives afterwards
426                         Thread.Sleep (1000);
427                         CloseSignals (usignals);
428                 }
429
430                 static void AssertCount (UnixSignal[] usignals)
431                 {
432                         int sum = 0;
433                         foreach (UnixSignal s in usignals)
434                                 sum += s.Count;
435                         Assert.AreEqual (sum, StormCount);
436                 }
437
438                 static void AssertCountSet (UnixSignal[] usignals)
439                 {
440                         foreach (UnixSignal s in usignals) {
441                                 Assert.IsTrue (s.Count > 0);
442                         }
443                 }
444
445                 static UnixSignal[] CreateSignals (Signum[] signals)
446                 {
447                         UnixSignal[] s = new UnixSignal [signals.Length];
448                         for (int i = 0; i < signals.Length; ++i)
449                                 s [i] = new UnixSignal (signals [i]);
450                         return s;
451                 }
452
453                 static void CloseSignals (UnixSignal[] signals)
454                 {
455                         foreach (UnixSignal s in signals)
456                                 s.Close ();
457                 }
458
459                 // Create thread that issues many signals from a set of harmless signals
460                 static Thread CreateRaiseStormThread (int max)
461                 {
462                         return new Thread (delegate () {
463                                 Random r = new Random (Environment.TickCount);
464                                 for (int i = 0; i < max; ++i) {
465                                         int n = r.Next (0, signals.Length);
466                                         Stdlib.raise (signals [n]);
467                                 }
468                         });
469                 }
470
471                 [Test]
472                 public void TestAddRemove ()
473                 {
474                         UnixSignal[] usignals = CreateSignals (signals);
475
476                         Thread[] threads = new Thread[]{
477                                 CreateRaiseStormThread (StormCount),
478                                 CreateSignalCreatorThread (),
479                         };
480
481                         foreach (Thread t in threads)
482                                 t.Start ();
483                         foreach (Thread t in threads)
484                                 t.Join ();
485
486                         AssertCountSet (usignals);
487                         CloseSignals (usignals);
488                 }
489
490                 // Create thread that repeatedly registers then unregisters signal handlers
491                 static Thread CreateSignalCreatorThread ()
492                 {
493                         return new Thread (delegate () {
494                                 Random r = new Random (Environment.TickCount << 4);
495                                 for (int i = 0; i < StormCount; ++i) {
496                                         int n = r.Next (0, signals.Length);
497                                         using (new UnixSignal (signals [n]))
498                                         using (new UnixSignal (signals [(n+1)%signals.Length]))
499                                         using (new UnixSignal (signals [(n+2)%signals.Length]))
500                                         using (new UnixSignal (signals [(n+3)%signals.Length])) {
501                                         }
502                                 }
503                         });
504                 }
505
506                 [Test]
507                 public void TestWaitAny ()
508                 {
509                         UnixSignal[] usignals = CreateSignals (signals);
510
511                         Thread[] threads = new Thread[]{
512                                 CreateRaiseStormThread (StormCount),
513                                 CreateSignalCreatorThread (),
514                                 CreateWaitAnyThread (usignals [0], usignals [2]),
515                                 CreateWaitAnyThread (usignals [1], usignals [3]),
516                                 CreateWaitAnyThread (usignals [1], usignals [2]),
517                         };
518
519                         foreach (Thread t in threads)
520                                 t.Start ();
521                         foreach (Thread t in threads)
522                                 t.Join ();
523
524                         AssertCountSet (usignals);
525                         CloseSignals (usignals);
526                 }
527
528                 // Create thread that blocks until at least one of the given signals is received
529                 static Thread CreateWaitAnyThread (params UnixSignal[] usignals)
530                 {
531                         return new Thread (delegate () {
532                                 int idx = UnixSignal.WaitAny (usignals, 30000);
533                                 Assert.AreEqual (idx >= 0 && idx < usignals.Length, true);
534                         });
535                 }
536         }
537 }