1 #include "RegistrarThreadManagerTest.h" 2 3 #include <cppunit/Test.h> 4 #include <cppunit/TestCaller.h> 5 #include <cppunit/TestSuite.h> 6 #include <TestApp.h> 7 #include <TestUtils.h> 8 9 #if !TEST_R5 10 #include <RegistrarThread.h> 11 #include <RegistrarThreadManager.h> 12 #endif // !TEST_R5 13 14 #include <stdio.h> 15 16 // Suite 17 CppUnit::Test* 18 RegistrarThreadManagerTest::Suite() { 19 CppUnit::TestSuite *suite = new CppUnit::TestSuite(); 20 typedef CppUnit::TestCaller<RegistrarThreadManagerTest> TC; 21 22 suite->addTest( new TC("RegistrarThreadManager::Shutdown Test", 23 &RegistrarThreadManagerTest::ShutdownTest) ); 24 suite->addTest( new TC("RegistrarThreadManager::Thread Limit Test", 25 &RegistrarThreadManagerTest::ThreadLimitTest) ); 26 27 28 return suite; 29 } 30 31 #if !TEST_R5 32 // Base test thread class 33 class TestThread : public RegistrarThread { 34 public: 35 TestThread(const char *name, int32 priority, BMessenger managerMessenger) 36 : RegistrarThread(name, priority, managerMessenger) 37 { 38 } 39 40 void DoSomethingUseless() { 41 fIntVal++; 42 snooze(1000); 43 } 44 45 private: 46 int64 fIntVal; 47 }; 48 49 // Test thread that terminates quickly 50 class TerminatingThread : public TestThread { 51 public: 52 TerminatingThread(const char *name, int32 priority, BMessenger managerMessenger) 53 : TestThread(name, priority, managerMessenger) 54 { 55 } 56 57 protected: 58 virtual status_t ThreadFunction() { 59 DoSomethingUseless(); 60 fIsFinished = true; 61 return B_OK; 62 } 63 }; 64 65 // Test thread that never terminates, but pays attention 66 // to its fShouldExit member 67 class WellBehavedInfiniteThread : public TestThread { 68 public: 69 WellBehavedInfiniteThread(const char *name, int32 priority, BMessenger managerMessenger) 70 : TestThread(name, priority, managerMessenger) 71 { 72 } 73 74 protected: 75 virtual status_t ThreadFunction() { 76 while (true) { 77 DoSomethingUseless(); 78 if (fShouldExit) 79 break; 80 } 81 fIsFinished = true; 82 return B_OK; 83 } 84 }; 85 86 // Test thread that never terminates and completely ignores 87 // its fShouldExit member 88 class NaughtyInfiniteThread : public TestThread { 89 public: 90 NaughtyInfiniteThread(const char *name, int32 priority, BMessenger managerMessenger) 91 : TestThread(name, priority, managerMessenger) 92 { 93 } 94 95 protected: 96 virtual status_t ThreadFunction() { 97 while (true) { 98 DoSomethingUseless(); 99 } 100 fIsFinished = true; 101 return B_OK; 102 } 103 }; 104 #endif // !TEST_R5 105 106 107 // setUp 108 void 109 RegistrarThreadManagerTest::setUp() 110 { 111 BTestCase::setUp(); 112 #if !TEST_R5 113 // Setup our application 114 fApplication = new BTestApp("application/x-vnd.obos.RegistrarThreadManagerTest"); 115 if (fApplication->Init() != B_OK) { 116 fprintf(stderr, "Failed to initialize application (perhaps the obos registrar isn't running?).\n"); 117 delete fApplication; 118 fApplication = NULL; 119 } 120 #endif // !TEST_R5 121 } 122 123 // tearDown 124 void 125 RegistrarThreadManagerTest::tearDown() 126 { 127 #if !TEST_R5 128 // Terminate the Application 129 if (fApplication) { 130 fApplication->Terminate(); 131 delete fApplication; 132 fApplication = NULL; 133 } 134 #endif // !TEST_R5 135 BTestCase::tearDown(); 136 } 137 138 void 139 RegistrarThreadManagerTest::ShutdownTest() 140 { 141 #if TEST_R5 142 Outputf("(no tests performed for R5 version)\n"); 143 #else 144 NextSubTest(); 145 status_t err = B_OK; 146 NextSubTest(); 147 RegistrarThreadManager manager; 148 NextSubTest(); 149 CHK(fApplication && fApplication->InitCheck() == B_OK); 150 NextSubTest(); 151 // fApplication->AddHandler(&manager); 152 NextSubTest(); 153 BMessenger managerMessenger(NULL, fApplication, &err); 154 NextSubTest(); 155 CHK(err == B_OK && managerMessenger.IsValid()); 156 NextSubTest(); 157 158 // Launch a bunch of threads 159 const uint termThreads = 2; 160 const uint niceThreads = 2; 161 const uint evilThreads = 2; 162 163 for (uint i = 0; i < termThreads; i++) { 164 NextSubTest(); 165 char name[1024]; 166 sprintf(name, "terminating #%d", i); 167 RegistrarThread *thread = new TerminatingThread(name, B_NORMAL_PRIORITY, managerMessenger); 168 CHK(thread != NULL); 169 CHK(thread->InitCheck() == B_OK); 170 CHK(manager.LaunchThread(thread) == B_OK); 171 } 172 173 for (uint i = 0; i < niceThreads; i++) { 174 NextSubTest(); 175 char name[1024]; 176 sprintf(name, "nice #%d", i); 177 RegistrarThread *thread = new WellBehavedInfiniteThread(name, B_NORMAL_PRIORITY, managerMessenger); 178 CHK(thread != NULL); 179 CHK(thread->InitCheck() == B_OK); 180 CHK(manager.LaunchThread(thread) == B_OK); 181 } 182 183 for (uint i = 0; i < evilThreads; i++) { 184 NextSubTest(); 185 char name[1024]; 186 sprintf(name, "evil #%d", i); 187 RegistrarThread *thread = new NaughtyInfiniteThread(name, B_NORMAL_PRIORITY, managerMessenger); 188 CHK(thread != NULL); 189 CHK(thread->InitCheck() == B_OK); 190 CHK(manager.LaunchThread(thread) == B_OK); 191 } 192 193 // Check the number of threads before doing a cleanup 194 NextSubTest(); // <= 13 195 CHK(manager.ThreadCount() == (termThreads + niceThreads + evilThreads)); 196 197 // Do the cleanup and check again (the terminating threads 198 // should be gone) 199 NextSubTest(); 200 snooze(500000); // give them time to terminate 201 CHK(manager.CleanupThreads() == B_OK); 202 CHK(manager.ThreadCount() == (niceThreads + evilThreads)); 203 204 // Now do a shutdown and check again (the nice infinite threads 205 // should be gone) 206 NextSubTest(); 207 CHK(manager.ShutdownThreads() == B_OK); 208 snooze(1000000); // give them time to quit nicely 209 CHK(manager.CleanupThreads() == B_OK); 210 CHK(manager.ThreadCount() == evilThreads); 211 212 213 // Now finally kill any remaining threads (which should rid us of 214 // the naughty infinite threads) 215 NextSubTest(); 216 CHK(manager.KillThreads() == B_OK); 217 CHK(manager.ThreadCount() == 0); 218 219 #endif // !TEST_R5 220 } 221 222 void 223 RegistrarThreadManagerTest::ThreadLimitTest() 224 { 225 #if TEST_R5 226 Outputf("(no tests performed for R5 version)\n"); 227 #else 228 NextSubTest(); 229 status_t err = B_OK; 230 RegistrarThreadManager manager; 231 CHK(fApplication && fApplication->InitCheck() == B_OK); 232 BMessenger managerMessenger(NULL, fApplication, &err); 233 CHK(err == B_OK && managerMessenger.IsValid()); 234 235 const uint termThreads = 2; 236 237 // This test is only useful if the thread limit of the manager 238 // class is > kTermThreads 239 CHK(termThreads < RegistrarThreadManager::kThreadLimit); 240 241 // Launch some terminating threads 242 uint i; 243 for (i = 0; i < termThreads; i++) { 244 NextSubTest(); 245 char name[1024]; 246 sprintf(name, "terminating #%d", i); 247 RegistrarThread *thread = new TerminatingThread(name, B_NORMAL_PRIORITY, managerMessenger); 248 CHK(thread != NULL); 249 CHK(thread->InitCheck() == B_OK); 250 CHK(manager.LaunchThread(thread) == B_OK); 251 } 252 253 // Now fill up the manager with non-terminating threads 254 for (; i < RegistrarThreadManager::kThreadLimit; i++) { 255 NextSubTest(); 256 char name[1024]; 257 sprintf(name, "nice #%d", i); 258 RegistrarThread *thread = new WellBehavedInfiniteThread(name, B_NORMAL_PRIORITY, managerMessenger); 259 CHK(thread != NULL); 260 CHK(thread->InitCheck() == B_OK); 261 CHK(manager.LaunchThread(thread) == B_OK); 262 } 263 CHK(manager.ThreadCount() == RegistrarThreadManager::kThreadLimit); 264 265 // Now try to launch just one more... 266 NextSubTest(); 267 { 268 char *name = "hopeless thread"; 269 RegistrarThread *thread = new WellBehavedInfiniteThread(name, B_NORMAL_PRIORITY, managerMessenger); 270 CHK(thread != NULL); 271 CHK(thread->InitCheck() == B_OK); 272 CHK(manager.LaunchThread(thread) == B_NO_MORE_THREADS); 273 delete thread; 274 } 275 276 // Now wait a little bit for our terminating threads to quit, 277 // cleanup after them, and make sure we can now launch that 278 // many threads again 279 NextSubTest(); 280 snooze(500000); 281 manager.CleanupThreads(); 282 283 for (i = 0; i < termThreads; i++) { 284 NextSubTest(); 285 char name[1024]; 286 sprintf(name, "2nd round nice #%d", i); 287 RegistrarThread *thread = new TerminatingThread(name, B_NORMAL_PRIORITY, managerMessenger); 288 CHK(thread != NULL); 289 CHK(thread->InitCheck() == B_OK); 290 CHK(manager.LaunchThread(thread) == B_OK); 291 } 292 293 // Now try once more to launch just one more... 294 NextSubTest(); 295 { 296 char *name = "hopeless thread"; 297 RegistrarThread *thread = new WellBehavedInfiniteThread(name, B_NORMAL_PRIORITY, managerMessenger); 298 CHK(thread != NULL); 299 CHK(thread->InitCheck() == B_OK); 300 CHK(manager.LaunchThread(thread) == B_NO_MORE_THREADS); 301 delete thread; 302 } 303 304 // Cleanup 305 NextSubTest(); 306 manager.ShutdownThreads(); 307 snooze(500000); 308 309 #endif // !TEST_R5 310 } 311