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