183f04694STyler Dauwalder #include "RegistrarThreadManagerTest.h" 283f04694STyler Dauwalder 383f04694STyler Dauwalder #include <cppunit/Test.h> 483f04694STyler Dauwalder #include <cppunit/TestCaller.h> 583f04694STyler Dauwalder #include <cppunit/TestSuite.h> 683f04694STyler Dauwalder #include <TestApp.h> 783f04694STyler Dauwalder #include <TestUtils.h> 883f04694STyler Dauwalder 9*77b9927bSIngo Weinhold #ifndef TEST_R5 1083f04694STyler Dauwalder #include <RegistrarThread.h> 1183f04694STyler Dauwalder #include <RegistrarThreadManager.h> 1283f04694STyler Dauwalder #endif // !TEST_R5 1383f04694STyler Dauwalder 1483f04694STyler Dauwalder #include <stdio.h> 1583f04694STyler Dauwalder 1683f04694STyler Dauwalder // Suite 1783f04694STyler Dauwalder CppUnit::Test* 1883f04694STyler Dauwalder RegistrarThreadManagerTest::Suite() { 1983f04694STyler Dauwalder CppUnit::TestSuite *suite = new CppUnit::TestSuite(); 2083f04694STyler Dauwalder typedef CppUnit::TestCaller<RegistrarThreadManagerTest> TC; 2183f04694STyler Dauwalder 22cc24797bSTyler Dauwalder suite->addTest( new TC("RegistrarThreadManager::Shutdown Test", 2383f04694STyler Dauwalder &RegistrarThreadManagerTest::ShutdownTest) ); 24cc24797bSTyler Dauwalder suite->addTest( new TC("RegistrarThreadManager::Thread Limit Test", 25cc24797bSTyler Dauwalder &RegistrarThreadManagerTest::ThreadLimitTest) ); 2683f04694STyler Dauwalder 2783f04694STyler Dauwalder 2883f04694STyler Dauwalder return suite; 2983f04694STyler Dauwalder } 3083f04694STyler Dauwalder 31*77b9927bSIngo Weinhold #ifndef TEST_R5 3283f04694STyler Dauwalder // Base test thread class 3383f04694STyler Dauwalder class TestThread : public RegistrarThread { 3483f04694STyler Dauwalder public: 3583f04694STyler Dauwalder TestThread(const char *name, int32 priority, BMessenger managerMessenger) 3683f04694STyler Dauwalder : RegistrarThread(name, priority, managerMessenger) 3783f04694STyler Dauwalder { 3883f04694STyler Dauwalder } 3983f04694STyler Dauwalder 4083f04694STyler Dauwalder void DoSomethingUseless() { 4183f04694STyler Dauwalder fIntVal++; 4283f04694STyler Dauwalder snooze(1000); 4383f04694STyler Dauwalder } 4483f04694STyler Dauwalder 4583f04694STyler Dauwalder private: 4683f04694STyler Dauwalder int64 fIntVal; 4783f04694STyler Dauwalder }; 4883f04694STyler Dauwalder 4983f04694STyler Dauwalder // Test thread that terminates quickly 5083f04694STyler Dauwalder class TerminatingThread : public TestThread { 5183f04694STyler Dauwalder public: 5283f04694STyler Dauwalder TerminatingThread(const char *name, int32 priority, BMessenger managerMessenger) 5383f04694STyler Dauwalder : TestThread(name, priority, managerMessenger) 5483f04694STyler Dauwalder { 5583f04694STyler Dauwalder } 5683f04694STyler Dauwalder 5783f04694STyler Dauwalder protected: 5883f04694STyler Dauwalder virtual status_t ThreadFunction() { 5983f04694STyler Dauwalder DoSomethingUseless(); 6083f04694STyler Dauwalder fIsFinished = true; 6183f04694STyler Dauwalder return B_OK; 6283f04694STyler Dauwalder } 6383f04694STyler Dauwalder }; 6483f04694STyler Dauwalder 6583f04694STyler Dauwalder // Test thread that never terminates, but pays attention 6683f04694STyler Dauwalder // to its fShouldExit member 6783f04694STyler Dauwalder class WellBehavedInfiniteThread : public TestThread { 6883f04694STyler Dauwalder public: 6983f04694STyler Dauwalder WellBehavedInfiniteThread(const char *name, int32 priority, BMessenger managerMessenger) 7083f04694STyler Dauwalder : TestThread(name, priority, managerMessenger) 7183f04694STyler Dauwalder { 7283f04694STyler Dauwalder } 7383f04694STyler Dauwalder 7483f04694STyler Dauwalder protected: 7583f04694STyler Dauwalder virtual status_t ThreadFunction() { 7683f04694STyler Dauwalder while (true) { 7783f04694STyler Dauwalder DoSomethingUseless(); 7883f04694STyler Dauwalder if (fShouldExit) 7983f04694STyler Dauwalder break; 8083f04694STyler Dauwalder } 8183f04694STyler Dauwalder fIsFinished = true; 8283f04694STyler Dauwalder return B_OK; 8383f04694STyler Dauwalder } 8483f04694STyler Dauwalder }; 8583f04694STyler Dauwalder 8683f04694STyler Dauwalder // Test thread that never terminates and completely ignores 8783f04694STyler Dauwalder // its fShouldExit member 8883f04694STyler Dauwalder class NaughtyInfiniteThread : public TestThread { 8983f04694STyler Dauwalder public: 9083f04694STyler Dauwalder NaughtyInfiniteThread(const char *name, int32 priority, BMessenger managerMessenger) 9183f04694STyler Dauwalder : TestThread(name, priority, managerMessenger) 9283f04694STyler Dauwalder { 9383f04694STyler Dauwalder } 9483f04694STyler Dauwalder 9583f04694STyler Dauwalder protected: 9683f04694STyler Dauwalder virtual status_t ThreadFunction() { 9783f04694STyler Dauwalder while (true) { 9883f04694STyler Dauwalder DoSomethingUseless(); 9983f04694STyler Dauwalder } 10083f04694STyler Dauwalder fIsFinished = true; 10183f04694STyler Dauwalder return B_OK; 10283f04694STyler Dauwalder } 10383f04694STyler Dauwalder }; 10483f04694STyler Dauwalder #endif // !TEST_R5 10583f04694STyler Dauwalder 10683f04694STyler Dauwalder 10783f04694STyler Dauwalder // setUp 10883f04694STyler Dauwalder void 10983f04694STyler Dauwalder RegistrarThreadManagerTest::setUp() 11083f04694STyler Dauwalder { 11183f04694STyler Dauwalder BTestCase::setUp(); 112*77b9927bSIngo Weinhold #ifndef TEST_R5 11383f04694STyler Dauwalder // Setup our application 11483f04694STyler Dauwalder fApplication = new BTestApp("application/x-vnd.obos.RegistrarThreadManagerTest"); 11583f04694STyler Dauwalder if (fApplication->Init() != B_OK) { 11683f04694STyler Dauwalder fprintf(stderr, "Failed to initialize application (perhaps the obos registrar isn't running?).\n"); 11783f04694STyler Dauwalder delete fApplication; 11883f04694STyler Dauwalder fApplication = NULL; 11983f04694STyler Dauwalder } 12083f04694STyler Dauwalder #endif // !TEST_R5 12183f04694STyler Dauwalder } 12283f04694STyler Dauwalder 12383f04694STyler Dauwalder // tearDown 12483f04694STyler Dauwalder void 12583f04694STyler Dauwalder RegistrarThreadManagerTest::tearDown() 12683f04694STyler Dauwalder { 127*77b9927bSIngo Weinhold #ifndef TEST_R5 12883f04694STyler Dauwalder // Terminate the Application 12983f04694STyler Dauwalder if (fApplication) { 13083f04694STyler Dauwalder fApplication->Terminate(); 13183f04694STyler Dauwalder delete fApplication; 13283f04694STyler Dauwalder fApplication = NULL; 13383f04694STyler Dauwalder } 13483f04694STyler Dauwalder #endif // !TEST_R5 13583f04694STyler Dauwalder BTestCase::tearDown(); 13683f04694STyler Dauwalder } 13783f04694STyler Dauwalder 13883f04694STyler Dauwalder void 13983f04694STyler Dauwalder RegistrarThreadManagerTest::ShutdownTest() 14083f04694STyler Dauwalder { 141*77b9927bSIngo Weinhold #ifdef TEST_R5 14283f04694STyler Dauwalder Outputf("(no tests performed for R5 version)\n"); 14383f04694STyler Dauwalder #else 14483f04694STyler Dauwalder NextSubTest(); 14583f04694STyler Dauwalder status_t err = B_OK; 14683f04694STyler Dauwalder NextSubTest(); 14783f04694STyler Dauwalder RegistrarThreadManager manager; 14883f04694STyler Dauwalder NextSubTest(); 14983f04694STyler Dauwalder CHK(fApplication && fApplication->InitCheck() == B_OK); 15083f04694STyler Dauwalder NextSubTest(); 15183f04694STyler Dauwalder // fApplication->AddHandler(&manager); 15283f04694STyler Dauwalder NextSubTest(); 15383f04694STyler Dauwalder BMessenger managerMessenger(NULL, fApplication, &err); 154*77b9927bSIngo Weinhold // TODO: Do something about this... 155*77b9927bSIngo Weinhold if (err != B_OK) { 156*77b9927bSIngo Weinhold fprintf(stderr, "Fails because we try to init an Haiku BMessenger with a " 157*77b9927bSIngo Weinhold "BLooper from R5's libbe (more precisely a BTestApp living in libcppunit, " 158*77b9927bSIngo Weinhold "which is only linked against R5's libbe).\n"); 159*77b9927bSIngo Weinhold } 16083f04694STyler Dauwalder NextSubTest(); 16183f04694STyler Dauwalder CHK(err == B_OK && managerMessenger.IsValid()); 16283f04694STyler Dauwalder NextSubTest(); 16383f04694STyler Dauwalder 16483f04694STyler Dauwalder // Launch a bunch of threads 16583f04694STyler Dauwalder const uint termThreads = 2; 16683f04694STyler Dauwalder const uint niceThreads = 2; 16783f04694STyler Dauwalder const uint evilThreads = 2; 16883f04694STyler Dauwalder 16983f04694STyler Dauwalder for (uint i = 0; i < termThreads; i++) { 17083f04694STyler Dauwalder NextSubTest(); 17183f04694STyler Dauwalder char name[1024]; 17283f04694STyler Dauwalder sprintf(name, "terminating #%d", i); 17383f04694STyler Dauwalder RegistrarThread *thread = new TerminatingThread(name, B_NORMAL_PRIORITY, managerMessenger); 17483f04694STyler Dauwalder CHK(thread != NULL); 17583f04694STyler Dauwalder CHK(thread->InitCheck() == B_OK); 17683f04694STyler Dauwalder CHK(manager.LaunchThread(thread) == B_OK); 17783f04694STyler Dauwalder } 17883f04694STyler Dauwalder 17983f04694STyler Dauwalder for (uint i = 0; i < niceThreads; i++) { 18083f04694STyler Dauwalder NextSubTest(); 18183f04694STyler Dauwalder char name[1024]; 18283f04694STyler Dauwalder sprintf(name, "nice #%d", i); 18383f04694STyler Dauwalder RegistrarThread *thread = new WellBehavedInfiniteThread(name, B_NORMAL_PRIORITY, managerMessenger); 18483f04694STyler Dauwalder CHK(thread != NULL); 18583f04694STyler Dauwalder CHK(thread->InitCheck() == B_OK); 18683f04694STyler Dauwalder CHK(manager.LaunchThread(thread) == B_OK); 18783f04694STyler Dauwalder } 18883f04694STyler Dauwalder 18983f04694STyler Dauwalder for (uint i = 0; i < evilThreads; i++) { 19083f04694STyler Dauwalder NextSubTest(); 19183f04694STyler Dauwalder char name[1024]; 19283f04694STyler Dauwalder sprintf(name, "evil #%d", i); 19383f04694STyler Dauwalder RegistrarThread *thread = new NaughtyInfiniteThread(name, B_NORMAL_PRIORITY, managerMessenger); 19483f04694STyler Dauwalder CHK(thread != NULL); 19583f04694STyler Dauwalder CHK(thread->InitCheck() == B_OK); 19683f04694STyler Dauwalder CHK(manager.LaunchThread(thread) == B_OK); 19783f04694STyler Dauwalder } 19883f04694STyler Dauwalder 19983f04694STyler Dauwalder // Check the number of threads before doing a cleanup 20083f04694STyler Dauwalder NextSubTest(); // <= 13 20183f04694STyler Dauwalder CHK(manager.ThreadCount() == (termThreads + niceThreads + evilThreads)); 20283f04694STyler Dauwalder 20383f04694STyler Dauwalder // Do the cleanup and check again (the terminating threads 20483f04694STyler Dauwalder // should be gone) 20583f04694STyler Dauwalder NextSubTest(); 20683f04694STyler Dauwalder snooze(500000); // give them time to terminate 20783f04694STyler Dauwalder CHK(manager.CleanupThreads() == B_OK); 20883f04694STyler Dauwalder CHK(manager.ThreadCount() == (niceThreads + evilThreads)); 20983f04694STyler Dauwalder 21083f04694STyler Dauwalder // Now do a shutdown and check again (the nice infinite threads 21183f04694STyler Dauwalder // should be gone) 21283f04694STyler Dauwalder NextSubTest(); 21383f04694STyler Dauwalder CHK(manager.ShutdownThreads() == B_OK); 21483f04694STyler Dauwalder snooze(1000000); // give them time to quit nicely 21583f04694STyler Dauwalder CHK(manager.CleanupThreads() == B_OK); 21683f04694STyler Dauwalder CHK(manager.ThreadCount() == evilThreads); 21783f04694STyler Dauwalder 21883f04694STyler Dauwalder 21983f04694STyler Dauwalder // Now finally kill any remaining threads (which should rid us of 22083f04694STyler Dauwalder // the naughty infinite threads) 22183f04694STyler Dauwalder NextSubTest(); 22283f04694STyler Dauwalder CHK(manager.KillThreads() == B_OK); 22383f04694STyler Dauwalder CHK(manager.ThreadCount() == 0); 22483f04694STyler Dauwalder 22583f04694STyler Dauwalder #endif // !TEST_R5 22683f04694STyler Dauwalder } 22783f04694STyler Dauwalder 228cc24797bSTyler Dauwalder void 229cc24797bSTyler Dauwalder RegistrarThreadManagerTest::ThreadLimitTest() 230cc24797bSTyler Dauwalder { 231*77b9927bSIngo Weinhold #ifdef TEST_R5 232cc24797bSTyler Dauwalder Outputf("(no tests performed for R5 version)\n"); 233cc24797bSTyler Dauwalder #else 234cc24797bSTyler Dauwalder NextSubTest(); 235cc24797bSTyler Dauwalder status_t err = B_OK; 236cc24797bSTyler Dauwalder RegistrarThreadManager manager; 237cc24797bSTyler Dauwalder CHK(fApplication && fApplication->InitCheck() == B_OK); 238cc24797bSTyler Dauwalder BMessenger managerMessenger(NULL, fApplication, &err); 239*77b9927bSIngo Weinhold // TODO: Do something about this... 240*77b9927bSIngo Weinhold if (err != B_OK) { 241*77b9927bSIngo Weinhold fprintf(stderr, "Fails because we try to init an Haiku BMessenger with a " 242*77b9927bSIngo Weinhold "BLooper from R5's libbe (more precisely a BTestApp living in libcppunit, " 243*77b9927bSIngo Weinhold "which is only linked against R5's libbe).\n"); 244*77b9927bSIngo Weinhold } 245cc24797bSTyler Dauwalder CHK(err == B_OK && managerMessenger.IsValid()); 246cc24797bSTyler Dauwalder 247cc24797bSTyler Dauwalder const uint termThreads = 2; 248cc24797bSTyler Dauwalder 249cc24797bSTyler Dauwalder // This test is only useful if the thread limit of the manager 250cc24797bSTyler Dauwalder // class is > kTermThreads 251cc24797bSTyler Dauwalder CHK(termThreads < RegistrarThreadManager::kThreadLimit); 252cc24797bSTyler Dauwalder 253cc24797bSTyler Dauwalder // Launch some terminating threads 254cc24797bSTyler Dauwalder uint i; 255cc24797bSTyler Dauwalder for (i = 0; i < termThreads; i++) { 256cc24797bSTyler Dauwalder NextSubTest(); 257cc24797bSTyler Dauwalder char name[1024]; 258cc24797bSTyler Dauwalder sprintf(name, "terminating #%d", i); 259cc24797bSTyler Dauwalder RegistrarThread *thread = new TerminatingThread(name, B_NORMAL_PRIORITY, managerMessenger); 260cc24797bSTyler Dauwalder CHK(thread != NULL); 261cc24797bSTyler Dauwalder CHK(thread->InitCheck() == B_OK); 262cc24797bSTyler Dauwalder CHK(manager.LaunchThread(thread) == B_OK); 263cc24797bSTyler Dauwalder } 264cc24797bSTyler Dauwalder 265cc24797bSTyler Dauwalder // Now fill up the manager with non-terminating threads 266cc24797bSTyler Dauwalder for (; i < RegistrarThreadManager::kThreadLimit; i++) { 267cc24797bSTyler Dauwalder NextSubTest(); 268cc24797bSTyler Dauwalder char name[1024]; 269cc24797bSTyler Dauwalder sprintf(name, "nice #%d", i); 270cc24797bSTyler Dauwalder RegistrarThread *thread = new WellBehavedInfiniteThread(name, B_NORMAL_PRIORITY, managerMessenger); 271cc24797bSTyler Dauwalder CHK(thread != NULL); 272cc24797bSTyler Dauwalder CHK(thread->InitCheck() == B_OK); 273cc24797bSTyler Dauwalder CHK(manager.LaunchThread(thread) == B_OK); 274cc24797bSTyler Dauwalder } 275cc24797bSTyler Dauwalder CHK(manager.ThreadCount() == RegistrarThreadManager::kThreadLimit); 276cc24797bSTyler Dauwalder 277cc24797bSTyler Dauwalder // Now try to launch just one more... 278cc24797bSTyler Dauwalder NextSubTest(); 279cc24797bSTyler Dauwalder { 280cc24797bSTyler Dauwalder char *name = "hopeless thread"; 281cc24797bSTyler Dauwalder RegistrarThread *thread = new WellBehavedInfiniteThread(name, B_NORMAL_PRIORITY, managerMessenger); 282cc24797bSTyler Dauwalder CHK(thread != NULL); 283cc24797bSTyler Dauwalder CHK(thread->InitCheck() == B_OK); 284cc24797bSTyler Dauwalder CHK(manager.LaunchThread(thread) == B_NO_MORE_THREADS); 285cc24797bSTyler Dauwalder delete thread; 286cc24797bSTyler Dauwalder } 287cc24797bSTyler Dauwalder 288cc24797bSTyler Dauwalder // Now wait a little bit for our terminating threads to quit, 289cc24797bSTyler Dauwalder // cleanup after them, and make sure we can now launch that 290cc24797bSTyler Dauwalder // many threads again 291cc24797bSTyler Dauwalder NextSubTest(); 292cc24797bSTyler Dauwalder snooze(500000); 293cc24797bSTyler Dauwalder manager.CleanupThreads(); 294cc24797bSTyler Dauwalder 295cc24797bSTyler Dauwalder for (i = 0; i < termThreads; i++) { 296cc24797bSTyler Dauwalder NextSubTest(); 297cc24797bSTyler Dauwalder char name[1024]; 298cc24797bSTyler Dauwalder sprintf(name, "2nd round nice #%d", i); 299cc24797bSTyler Dauwalder RegistrarThread *thread = new TerminatingThread(name, B_NORMAL_PRIORITY, managerMessenger); 300cc24797bSTyler Dauwalder CHK(thread != NULL); 301cc24797bSTyler Dauwalder CHK(thread->InitCheck() == B_OK); 302cc24797bSTyler Dauwalder CHK(manager.LaunchThread(thread) == B_OK); 303cc24797bSTyler Dauwalder } 304cc24797bSTyler Dauwalder 305cc24797bSTyler Dauwalder // Now try once more to launch just one more... 306cc24797bSTyler Dauwalder NextSubTest(); 307cc24797bSTyler Dauwalder { 308cc24797bSTyler Dauwalder char *name = "hopeless thread"; 309cc24797bSTyler Dauwalder RegistrarThread *thread = new WellBehavedInfiniteThread(name, B_NORMAL_PRIORITY, managerMessenger); 310cc24797bSTyler Dauwalder CHK(thread != NULL); 311cc24797bSTyler Dauwalder CHK(thread->InitCheck() == B_OK); 312cc24797bSTyler Dauwalder CHK(manager.LaunchThread(thread) == B_NO_MORE_THREADS); 313cc24797bSTyler Dauwalder delete thread; 314cc24797bSTyler Dauwalder } 315cc24797bSTyler Dauwalder 316cc24797bSTyler Dauwalder // Cleanup 317cc24797bSTyler Dauwalder NextSubTest(); 318cc24797bSTyler Dauwalder manager.ShutdownThreads(); 319cc24797bSTyler Dauwalder snooze(500000); 320cc24797bSTyler Dauwalder 321cc24797bSTyler Dauwalder #endif // !TEST_R5 322cc24797bSTyler Dauwalder } 323