#include "RegistrarThreadManagerTest.h"
#include <cppunit/Test.h>
#include <cppunit/TestCaller.h>
#include <cppunit/TestSuite.h>
#include <TestApp.h>
#include <TestUtils.h>
#ifndef TEST_R5
#include "RegistrarThread.h"
#include "RegistrarThreadManager.h"
#endif
#include <stdio.h>
CppUnit::Test*
RegistrarThreadManagerTest::Suite() {
CppUnit::TestSuite *suite = new CppUnit::TestSuite();
typedef CppUnit::TestCaller<RegistrarThreadManagerTest> TC;
suite->addTest( new TC("RegistrarThreadManager::Shutdown Test",
&RegistrarThreadManagerTest::ShutdownTest) );
suite->addTest( new TC("RegistrarThreadManager::Thread Limit Test",
&RegistrarThreadManagerTest::ThreadLimitTest) );
return suite;
}
#ifndef TEST_R5
class TestThread : public RegistrarThread {
public:
TestThread(const char *name, int32 priority, BMessenger managerMessenger)
: RegistrarThread(name, priority, managerMessenger)
{
}
void DoSomethingUseless() {
fIntVal++;
snooze(1000);
}
private:
int64 fIntVal;
};
class TerminatingThread : public TestThread {
public:
TerminatingThread(const char *name, int32 priority, BMessenger managerMessenger)
: TestThread(name, priority, managerMessenger)
{
}
protected:
virtual status_t ThreadFunction() {
DoSomethingUseless();
fIsFinished = true;
return B_OK;
}
};
class WellBehavedInfiniteThread : public TestThread {
public:
WellBehavedInfiniteThread(const char *name, int32 priority, BMessenger managerMessenger)
: TestThread(name, priority, managerMessenger)
{
}
protected:
virtual status_t ThreadFunction() {
while (true) {
DoSomethingUseless();
if (fShouldExit)
break;
}
fIsFinished = true;
return B_OK;
}
};
class NaughtyInfiniteThread : public TestThread {
public:
NaughtyInfiniteThread(const char *name, int32 priority, BMessenger managerMessenger)
: TestThread(name, priority, managerMessenger)
{
}
protected:
virtual status_t ThreadFunction() {
while (true) {
DoSomethingUseless();
}
fIsFinished = true;
return B_OK;
}
};
#endif
void
RegistrarThreadManagerTest::setUp()
{
BTestCase::setUp();
#ifndef TEST_R5
fApplication = new BTestApp("application/x-vnd.obos.RegistrarThreadManagerTest");
if (fApplication->Init() != B_OK) {
fprintf(stderr, "Failed to initialize application (perhaps the Haiku registrar isn't running?).\n");
delete fApplication;
fApplication = NULL;
}
#endif
}
void
RegistrarThreadManagerTest::tearDown()
{
#ifndef TEST_R5
if (fApplication) {
fApplication->Terminate();
delete fApplication;
fApplication = NULL;
}
#endif
BTestCase::tearDown();
}
void
RegistrarThreadManagerTest::ShutdownTest()
{
#ifdef TEST_R5
Outputf("(no tests performed for R5 version)\n");
#else
NextSubTest();
status_t err = B_OK;
NextSubTest();
RegistrarThreadManager manager;
NextSubTest();
CHK(fApplication && fApplication->InitCheck() == B_OK);
NextSubTest();
NextSubTest();
BMessenger managerMessenger(NULL, fApplication, &err);
if (err != B_OK) {
fprintf(stderr, "Fails because we try to init an Haiku BMessenger with a "
"BLooper from R5's libbe (more precisely a BTestApp living in libcppunit, "
"which is only linked against R5's libbe).\n");
}
NextSubTest();
CHK(err == B_OK && managerMessenger.IsValid());
NextSubTest();
const uint termThreads = 2;
const uint niceThreads = 2;
const uint evilThreads = 2;
for (uint i = 0; i < termThreads; i++) {
NextSubTest();
char name[1024];
sprintf(name, "terminating #%d", i);
RegistrarThread *thread = new TerminatingThread(name, B_NORMAL_PRIORITY, managerMessenger);
CHK(thread != NULL);
CHK(thread->InitCheck() == B_OK);
CHK(manager.LaunchThread(thread) == B_OK);
}
for (uint i = 0; i < niceThreads; i++) {
NextSubTest();
char name[1024];
sprintf(name, "nice #%d", i);
RegistrarThread *thread = new WellBehavedInfiniteThread(name, B_NORMAL_PRIORITY, managerMessenger);
CHK(thread != NULL);
CHK(thread->InitCheck() == B_OK);
CHK(manager.LaunchThread(thread) == B_OK);
}
for (uint i = 0; i < evilThreads; i++) {
NextSubTest();
char name[1024];
sprintf(name, "evil #%d", i);
RegistrarThread *thread = new NaughtyInfiniteThread(name, B_NORMAL_PRIORITY, managerMessenger);
CHK(thread != NULL);
CHK(thread->InitCheck() == B_OK);
CHK(manager.LaunchThread(thread) == B_OK);
}
NextSubTest();
CHK(manager.ThreadCount() == (termThreads + niceThreads + evilThreads));
NextSubTest();
snooze(500000);
CHK(manager.CleanupThreads() == B_OK);
CHK(manager.ThreadCount() == (niceThreads + evilThreads));
NextSubTest();
CHK(manager.ShutdownThreads() == B_OK);
snooze(1000000);
CHK(manager.CleanupThreads() == B_OK);
CHK(manager.ThreadCount() == evilThreads);
NextSubTest();
CHK(manager.KillThreads() == B_OK);
CHK(manager.ThreadCount() == 0);
#endif
}
void
RegistrarThreadManagerTest::ThreadLimitTest()
{
#ifdef TEST_R5
Outputf("(no tests performed for R5 version)\n");
#else
NextSubTest();
status_t err = B_OK;
RegistrarThreadManager manager;
CHK(fApplication && fApplication->InitCheck() == B_OK);
BMessenger managerMessenger(NULL, fApplication, &err);
if (err != B_OK) {
fprintf(stderr, "Fails because we try to init an Haiku BMessenger with a "
"BLooper from R5's libbe (more precisely a BTestApp living in libcppunit, "
"which is only linked against R5's libbe).\n");
}
CHK(err == B_OK && managerMessenger.IsValid());
const uint termThreads = 2;
CHK(termThreads < RegistrarThreadManager::kThreadLimit);
uint i;
for (i = 0; i < termThreads; i++) {
NextSubTest();
char name[1024];
sprintf(name, "terminating #%d", i);
RegistrarThread *thread = new TerminatingThread(name, B_NORMAL_PRIORITY, managerMessenger);
CHK(thread != NULL);
CHK(thread->InitCheck() == B_OK);
CHK(manager.LaunchThread(thread) == B_OK);
}
for (; i < RegistrarThreadManager::kThreadLimit; i++) {
NextSubTest();
char name[1024];
sprintf(name, "nice #%d", i);
RegistrarThread *thread = new WellBehavedInfiniteThread(name, B_NORMAL_PRIORITY, managerMessenger);
CHK(thread != NULL);
CHK(thread->InitCheck() == B_OK);
CHK(manager.LaunchThread(thread) == B_OK);
}
CHK(manager.ThreadCount() == RegistrarThreadManager::kThreadLimit);
NextSubTest();
{
char *name = "hopeless thread";
RegistrarThread *thread = new WellBehavedInfiniteThread(name, B_NORMAL_PRIORITY, managerMessenger);
CHK(thread != NULL);
CHK(thread->InitCheck() == B_OK);
CHK(manager.LaunchThread(thread) == B_NO_MORE_THREADS);
delete thread;
}
NextSubTest();
snooze(500000);
manager.CleanupThreads();
for (i = 0; i < termThreads; i++) {
NextSubTest();
char name[1024];
sprintf(name, "2nd round nice #%d", i);
RegistrarThread *thread = new TerminatingThread(name, B_NORMAL_PRIORITY, managerMessenger);
CHK(thread != NULL);
CHK(thread->InitCheck() == B_OK);
CHK(manager.LaunchThread(thread) == B_OK);
}
NextSubTest();
{
char *name = "hopeless thread";
RegistrarThread *thread = new WellBehavedInfiniteThread(name, B_NORMAL_PRIORITY, managerMessenger);
CHK(thread != NULL);
CHK(thread->InitCheck() == B_OK);
CHK(manager.LaunchThread(thread) == B_NO_MORE_THREADS);
delete thread;
}
NextSubTest();
manager.ShutdownThreads();
snooze(500000);
#endif
}