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