// ThreadTest.cs - NUnit Test Cases for the System.Threading.Thread class // // Authors // Eduardo Garcia Cebollero (kiwnix@yahoo.es) // Sebastien Pouliot // // (C) Eduardo Garcia Cebollero. // (C) Ximian, Inc. http://www.ximian.com // (C) 2004 Novell (http://www.novell.com) // using NUnit.Framework; using System; using System.Security.Principal; using System.Threading; namespace MonoTests.System.Threading { // These tests seem to hang the 2.0 framework. So they are disabled for now // Don't reenable them until you can run a few thousand times on an SMP box. [Category ("NotWorking")] public class ThreadedPrincipalTest : Assertion { public static void NoPrincipal () { AppDomain.CurrentDomain.SetPrincipalPolicy (PrincipalPolicy.NoPrincipal); IPrincipal p = Thread.CurrentPrincipal; AssertNull ("Thread.CurrentPrincipal-1", p); Thread.CurrentPrincipal = new GenericPrincipal (new GenericIdentity ("mono"), null); AssertNotNull ("Thread.CurrentPrincipal-2", Thread.CurrentPrincipal); Thread.CurrentPrincipal = null; AssertNull ("Thread.CurrentPrincipal-3", Thread.CurrentPrincipal); // in this case we can return to null } public static void UnauthenticatedPrincipal () { AppDomain.CurrentDomain.SetPrincipalPolicy (PrincipalPolicy.UnauthenticatedPrincipal); IPrincipal p = Thread.CurrentPrincipal; AssertNotNull ("Thread.CurrentPrincipal", p); Assert ("Type", (p is GenericPrincipal)); AssertEquals ("Name", String.Empty, p.Identity.Name); AssertEquals ("AuthenticationType", String.Empty, p.Identity.AuthenticationType); Assert ("IsAuthenticated", !p.Identity.IsAuthenticated); Thread.CurrentPrincipal = new GenericPrincipal (new GenericIdentity ("mono"), null); AssertNotNull ("Thread.CurrentPrincipal-2", Thread.CurrentPrincipal); Thread.CurrentPrincipal = null; AssertNotNull ("Thread.CurrentPrincipal-3", Thread.CurrentPrincipal); // in this case we can't return to null } public static void WindowsPrincipal () { AppDomain.CurrentDomain.SetPrincipalPolicy (PrincipalPolicy.WindowsPrincipal); IPrincipal p = Thread.CurrentPrincipal; AssertNotNull ("Thread.CurrentPrincipal", p); Assert ("Type", (p is WindowsPrincipal)); AssertNotNull ("Name", p.Identity.Name); AssertNotNull ("AuthenticationType", p.Identity.AuthenticationType); Assert ("IsAuthenticated", p.Identity.IsAuthenticated); // note: we can switch from a WindowsPrincipal to a GenericPrincipal Thread.CurrentPrincipal = new GenericPrincipal (new GenericIdentity ("mono"), null); AssertNotNull ("Thread.CurrentPrincipal-2", Thread.CurrentPrincipal); Thread.CurrentPrincipal = null; AssertNotNull ("Thread.CurrentPrincipal-3", Thread.CurrentPrincipal); // in this case we can't return to null } public static void CopyOnNewThread () { AssertNotNull ("Thread.CurrentPrincipal", Thread.CurrentPrincipal); AssertEquals ("Identity", "good", Thread.CurrentPrincipal.Identity.Name); } } [TestFixture] [Category ("NotWorking")] public class ThreadTest : Assertion { //Some Classes to test as threads private class C1Test { public int cnt; public Thread thread1; public bool endm1; public bool endm2; public C1Test() { thread1 = (Thread)null; this.cnt = 0; endm1 = endm2 = false; } public void TestMethod() { while (cnt < 10) { cnt++; } endm1 = true; } public void TestMethod2() { if (!(thread1==(Thread)null) ) { thread1.Join(); } endm2 = true; } } private class C2Test { public int cnt; public bool run = false; public C2Test() { this.cnt = 0; } public void TestMethod() { run = true; while (true) { if (cnt < 1000) cnt++; else cnt = 0; } } } private class C3Test { public C1Test sub_class; public Thread sub_thread; public C3Test() { sub_class = new C1Test(); sub_thread = new Thread(new ThreadStart(sub_class.TestMethod)); } public void TestMethod1() { sub_thread.Start(); Thread.Sleep (100); sub_thread.Abort(); } } private class C4Test { public C1Test class1; public C1Test class2; public Thread thread1; public Thread thread2; public bool T1ON ; public bool T2ON ; public C4Test() { T1ON = false; T2ON = false; class1 = new C1Test(); class2 = new C1Test(); thread1 = new Thread(new ThreadStart(class1.TestMethod)); thread2 = new Thread(new ThreadStart(class2.TestMethod)); } public void TestMethod1() { thread1.Start(); TestUtil.WaitForAlive (thread1, "wait1"); T1ON = true; thread2.Start(); TestUtil.WaitForAlive (thread2, "wait2"); T2ON = true; thread1.Abort(); TestUtil.WaitForNotAlive (thread1, "wait3"); T1ON = false; thread2.Abort(); TestUtil.WaitForNotAlive (thread2, "wait4"); T2ON = false; } public void TestMethod2() { thread1.Start(); thread1.Join(); } } public void TestCtor1() { C1Test test1 = new C1Test(); try { Thread TestThread = new Thread(new ThreadStart(test1.TestMethod)); } catch (Exception e) { Fail ("#01 Unexpected Exception Thrown: " + e.ToString ()); } } [Category("NotDotNet")] public void TestStart() { { C1Test test1 = new C1Test(); Thread TestThread = new Thread(new ThreadStart(test1.TestMethod)); try { TestThread.Start(); } catch (Exception e) { Fail ("#12 Unexpected Exception Thrown: " + e.ToString ()); } TestThread.Join(); AssertEquals("#13 Thread Not started: ", 10,test1.cnt); } { bool errorThrown = false; C2Test test1 = new C2Test(); Thread TestThread = new Thread(new ThreadStart(test1.TestMethod)); TestThread.Start(); TestThread.Abort(); try { TestThread.Start(); } catch(ThreadStateException) { errorThrown = true; } Assert ("#14 no ThreadStateException trown", errorThrown); } { C2Test test1 = new C2Test(); Thread TestThread = new Thread(new ThreadStart(test1.TestMethod)); TestThread.Start(); while(!test1.run); bool started = (TestThread.ThreadState == ThreadState.Running); AssertEquals("#15 Thread Is not in the correct state: ", started , test1.run); TestThread.Abort(); } } public void TestApartment() { C2Test test1 = new C2Test(); Thread TestThread = new Thread(new ThreadStart(test1.TestMethod)); ApartmentState before = TestThread.ApartmentState; TestThread.Start(); TestUtil.WaitForAlive (TestThread, "wait5"); ApartmentState after = TestThread.ApartmentState; TestThread.Abort(); AssertEquals("#21 Apartment State Changed when not needed",before,after); } [Category("NotDotNet")] public void TestApartmentState() { C2Test test1 = new C2Test(); Thread TestThread = new Thread(new ThreadStart(test1.TestMethod)); ApartmentState before = TestThread.ApartmentState; TestThread.Start(); TestUtil.WaitForAlive (TestThread, "wait6"); ApartmentState after = TestThread.ApartmentState; TestThread.Abort(); AssertEquals("#31 Apartment State Changed when not needed: ",before,after); } public void TestPriority1() { C2Test test1 = new C2Test(); Thread TestThread = new Thread(new ThreadStart(test1.TestMethod)); try { TestThread.Priority=ThreadPriority.BelowNormal; ThreadPriority after = TestThread.Priority; TestThread.Start(); TestUtil.WaitForAlive (TestThread, "wait7"); ThreadPriority before = TestThread.Priority; AssertEquals("#41 Unexpected Priority Change: ",before,after); } finally { TestThread.Abort(); } } [Test] public void AbortUnstarted () { C2Test test1 = new C2Test(); Thread th = new Thread (new ThreadStart (test1.TestMethod)); th.Abort (); th.Start (); } [Category("NotWorking")] // this is a MonoTODO -> no support for Priority public void TestPriority2() { C2Test test1 = new C2Test(); Thread TestThread = new Thread(new ThreadStart(test1.TestMethod)); try { AssertEquals("#42 Incorrect Priority in New thread: ",ThreadPriority.Normal, TestThread.Priority); TestThread.Start(); TestUtil.WaitForAliveOrStop (TestThread, "wait8"); AssertEquals("#43 Incorrect Priority in Started thread: ",ThreadPriority.Normal, TestThread.Priority); } finally { TestThread.Abort(); } AssertEquals("#44 Incorrect Priority in Aborted thread: ",ThreadPriority.Normal, TestThread.Priority); } [Category("NotWorking")] // this is a MonoTODO -> no support for Priority public void TestPriority3() { C2Test test1 = new C2Test(); Thread TestThread = new Thread(new ThreadStart(test1.TestMethod)); try { TestThread.Start(); TestThread.Priority = ThreadPriority.Lowest; AssertEquals("#45A Incorrect Priority:",ThreadPriority.Lowest,TestThread.Priority); TestThread.Priority = ThreadPriority.BelowNormal; AssertEquals("#45B Incorrect Priority:",ThreadPriority.BelowNormal,TestThread.Priority); TestThread.Priority = ThreadPriority.Normal; AssertEquals("#45C Incorrect Priority:",ThreadPriority.Normal,TestThread.Priority); TestThread.Priority = ThreadPriority.AboveNormal; AssertEquals("#45D Incorrect Priority:",ThreadPriority.AboveNormal,TestThread.Priority); TestThread.Priority = ThreadPriority.Highest; AssertEquals("#45E Incorrect Priority:",ThreadPriority.Highest,TestThread.Priority); } finally { TestThread.Abort(); } } public void TestIsBackground1() { C2Test test1 = new C2Test(); Thread TestThread = new Thread(new ThreadStart(test1.TestMethod)); try { TestThread.Start(); TestUtil.WaitForAlive (TestThread, "wait9"); bool state = TestThread.IsBackground; Assert("#51 IsBackground not set at the default state: ",!(state)); } finally { TestThread.Abort(); } } public void TestIsBackground2() { C2Test test1 = new C2Test(); Thread TestThread = new Thread(new ThreadStart(test1.TestMethod)); TestThread.IsBackground = true; try { TestThread.Start(); } finally { TestThread.Abort(); } Assert("#52 Is Background Changed ot Start ",TestThread.IsBackground); } public void TestName() { C2Test test1 = new C2Test(); Thread TestThread = new Thread(new ThreadStart(test1.TestMethod)); try { TestThread.Start(); TestUtil.WaitForAlive (TestThread, "wait10"); string name = TestThread.Name; AssertEquals("#61 Name set when mustn't be set: ", name, (string)null); string newname = "Testing...."; TestThread.Name = newname; AssertEquals("#62 Name not set when must be set: ",TestThread.Name,newname); } finally { TestThread.Abort(); } } [Category("NotDotNet")] public void TestNestedThreads1() { C3Test test1 = new C3Test(); Thread TestThread = new Thread(new ThreadStart(test1.TestMethod1)); try { TestThread.Start(); TestUtil.WaitForAlive (TestThread, "wait11"); } catch(Exception e) { Fail("#71 Unexpected Exception" + e.Message); } finally { TestThread.Abort(); } } public void TestNestedThreads2() { C4Test test1 = new C4Test(); Thread TestThread = new Thread(new ThreadStart(test1.TestMethod1)); try { TestThread.Start(); } catch(Exception e) { Fail("#81 Unexpected Exception" + e.ToString()); } finally { TestThread.Abort(); } } public void TestJoin1() { C1Test test1 = new C1Test(); C1Test test2 = new C1Test(); Thread thread1 = new Thread(new ThreadStart(test1.TestMethod)); Thread thread2 = new Thread(new ThreadStart(test1.TestMethod2)); try { thread1.Start(); thread2.Start(); thread2.Join(); } catch(Exception e) { Fail("#91 Unexpected Exception " + e.ToString()); } finally { thread1.Abort(); thread2.Abort(); } } public void TestThreadState() { //TODO: Test The rest of the possible transitions C2Test test1 = new C2Test(); Thread TestThread = new Thread(new ThreadStart(test1.TestMethod)); AssertEquals("#101 Wrong Thread State",ThreadState.Unstarted,TestThread.ThreadState); try { TestThread.Start(); //while(!TestThread.IsAlive); //In the MS Documentation this is not necessary //but in the MS SDK it is Assert("#102 Wrong Thread State: " + TestThread.ThreadState.ToString(), TestThread.ThreadState == ThreadState.Running || (TestThread.ThreadState & ThreadState.Unstarted) != 0); } finally { TestThread.Abort(); } TestUtil.WaitForNotAlive (TestThread, "wait12"); // Docs say state will be Stopped, but Aborted happens sometimes (?) Assert("#103 Wrong Thread State: " + TestThread.ThreadState.ToString(), (ThreadState.Stopped & TestThread.ThreadState) != 0 || (ThreadState.Aborted & TestThread.ThreadState) != 0); } [Test] public void CurrentPrincipal_PrincipalPolicy_NoPrincipal () { // note: switching from PrincipalPolicy won't work inside the same thread // because as soon as a Principal object is created the Policy doesn't matter anymore Thread t = new Thread (new ThreadStart (ThreadedPrincipalTest.NoPrincipal)); try { t.Start (); t.Join (); } catch { t.Abort (); } } [Test] public void CurrentPrincipal_PrincipalPolicy_UnauthenticatedPrincipal () { // note: switching from PrincipalPolicy won't work inside the same thread // because as soon as a Principal object is created the Policy doesn't matter anymore Thread t = new Thread (new ThreadStart (ThreadedPrincipalTest.UnauthenticatedPrincipal)); try { t.Start (); t.Join (); } catch { t.Abort (); } } [Test] public void CurrentPrincipal_PrincipalPolicy_WindowsPrincipal () { // note: switching from PrincipalPolicy won't work inside the same thread // because as soon as a Principal object is created the Policy doesn't matter anymore Thread t = new Thread (new ThreadStart (ThreadedPrincipalTest.WindowsPrincipal)); try { t.Start (); t.Join (); } catch { t.Abort (); } } [Test] public void IPrincipal_CopyOnNewThread () { Thread.CurrentPrincipal = new GenericPrincipal (new GenericIdentity ("bad"), null); Thread t = new Thread (new ThreadStart (ThreadedPrincipalTest.CopyOnNewThread)); try { Thread.CurrentPrincipal = new GenericPrincipal (new GenericIdentity ("good"), null); t.Start (); t.Join (); } catch { t.Abort (); } } int counter = 0; [Category("NotDotNet")] public void TestSuspend () { Thread t = new Thread (new ThreadStart (DoCount)); t.IsBackground = true; t.Start (); CheckIsRunning ("t1", t); t.Suspend (); WaitSuspended ("t2", t); CheckIsNotRunning ("t3", t); t.Resume (); WaitResumed ("t4", t); CheckIsRunning ("t5", t); t.Abort (); TestUtil.WaitForNotAlive (t, "wait13"); CheckIsNotRunning ("t6", t); } [Category("NotDotNet")] [Category("NotWorking")] public void TestSuspendAbort () { Thread t = new Thread (new ThreadStart (DoCount)); t.IsBackground = true; t.Start (); CheckIsRunning ("t1", t); t.Suspend (); WaitSuspended ("t2", t); CheckIsNotRunning ("t3", t); t.Abort (); int n=0; while (t.IsAlive && n < 200) { Thread.Sleep (10); n++; } Assert ("Timeout while waiting for abort", n < 200); CheckIsNotRunning ("t6", t); } void CheckIsRunning (string s, Thread t) { int c = counter; Thread.Sleep (100); Assert (s, counter > c); } void CheckIsNotRunning (string s, Thread t) { int c = counter; Thread.Sleep (100); Assert (s, counter == c); } void WaitSuspended (string s, Thread t) { int n=0; ThreadState state = t.ThreadState; while ((state & ThreadState.Suspended) == 0) { Assert (s + ": expected SuspendRequested state", (state & ThreadState.SuspendRequested) != 0); Thread.Sleep (10); n++; Assert (s + ": failed to suspend", n < 100); state = t.ThreadState; } Assert (s + ": SuspendRequested state not expected", (state & ThreadState.SuspendRequested) == 0); } void WaitResumed (string s, Thread t) { int n=0; while ((t.ThreadState & ThreadState.Suspended) != 0) { Thread.Sleep (10); n++; Assert (s + ": failed to resume", n < 100); } } public void DoCount () { while (true) { counter++; Thread.Sleep (1); } } } public class TestUtil { public static void WaitForNotAlive (Thread t, string s) { WhileAlive (t, true, s); } public static void WaitForAlive (Thread t, string s) { WhileAlive (t, false, s); } public static bool WaitForAliveOrStop (Thread t, string s) { return WhileAliveOrStop (t, false, s); } public static void WhileAlive (Thread t, bool alive, string s) { DateTime ti = DateTime.Now; while (t.IsAlive == alive) { if ((DateTime.Now - ti).TotalSeconds > 10) { if (alive) Assertion.Fail ("Timeout while waiting for not alive state. " + s); else Assertion.Fail ("Timeout while waiting for alive state. " + s); } } } public static bool WhileAliveOrStop (Thread t, bool alive, string s) { DateTime ti = DateTime.Now; while (t.IsAlive == alive) { if (t.ThreadState == ThreadState.Stopped) return false; if ((DateTime.Now - ti).TotalSeconds > 10) { if (alive) Assertion.Fail ("Timeout while waiting for not alive state. " + s); else Assertion.Fail ("Timeout while waiting for alive state. " + s); } } return true; } } }