xref: /haiku/src/tests/kits/app/RegistrarThreadManagerTest.cpp (revision 4c8e85b316c35a9161f5a1c50ad70bc91c83a76f)
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 #ifndef 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 #ifndef 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 #ifndef 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 Haiku 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 #ifndef 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 #ifdef 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 // TODO: Do something about this...
155 if (err != B_OK) {
156 fprintf(stderr, "Fails because we try to init an Haiku BMessenger with a "
157 "BLooper from R5's libbe (more precisely a BTestApp living in libcppunit, "
158 "which is only linked against R5's libbe).\n");
159 }
160 	NextSubTest();
161 	CHK(err == B_OK && managerMessenger.IsValid());
162 	NextSubTest();
163 
164 	// Launch a bunch of threads
165 	const uint termThreads = 2;
166 	const uint niceThreads = 2;
167 	const uint evilThreads = 2;
168 
169 	for (uint i = 0; i < termThreads; i++) {
170 		NextSubTest();
171 		char name[1024];
172 		sprintf(name, "terminating #%d", i);
173 		RegistrarThread *thread = new TerminatingThread(name, B_NORMAL_PRIORITY, managerMessenger);
174 		CHK(thread != NULL);
175 		CHK(thread->InitCheck() == B_OK);
176 		CHK(manager.LaunchThread(thread) == B_OK);
177 	}
178 
179 	for (uint i = 0; i < niceThreads; i++) {
180 		NextSubTest();
181 		char name[1024];
182 		sprintf(name, "nice #%d", i);
183 		RegistrarThread *thread = new WellBehavedInfiniteThread(name, B_NORMAL_PRIORITY, managerMessenger);
184 		CHK(thread != NULL);
185 		CHK(thread->InitCheck() == B_OK);
186 		CHK(manager.LaunchThread(thread) == B_OK);
187 	}
188 
189 	for (uint i = 0; i < evilThreads; i++) {
190 		NextSubTest();
191 		char name[1024];
192 		sprintf(name, "evil #%d", i);
193 		RegistrarThread *thread = new NaughtyInfiniteThread(name, B_NORMAL_PRIORITY, managerMessenger);
194 		CHK(thread != NULL);
195 		CHK(thread->InitCheck() == B_OK);
196 		CHK(manager.LaunchThread(thread) == B_OK);
197 	}
198 
199 	// Check the number of threads before doing a cleanup
200 	NextSubTest();	// <= 13
201 	CHK(manager.ThreadCount() == (termThreads + niceThreads + evilThreads));
202 
203 	// Do the cleanup and check again (the terminating threads
204 	// should be gone)
205 	NextSubTest();
206 	snooze(500000);		// give them time to terminate
207 	CHK(manager.CleanupThreads() == B_OK);
208 	CHK(manager.ThreadCount() == (niceThreads + evilThreads));
209 
210 	// Now do a shutdown and check again (the nice infinite threads
211 	// should be gone)
212 	NextSubTest();
213 	CHK(manager.ShutdownThreads() == B_OK);
214 	snooze(1000000);	// give them time to quit nicely
215 	CHK(manager.CleanupThreads() == B_OK);
216 	CHK(manager.ThreadCount() == evilThreads);
217 
218 
219 	// Now finally kill any remaining threads (which should rid us of
220 	// the naughty infinite threads)
221 	NextSubTest();
222 	CHK(manager.KillThreads() == B_OK);
223 	CHK(manager.ThreadCount() == 0);
224 
225 #endif	// !TEST_R5
226 }
227 
228 void
229 RegistrarThreadManagerTest::ThreadLimitTest()
230 {
231 #ifdef TEST_R5
232 	Outputf("(no tests performed for R5 version)\n");
233 #else
234 	NextSubTest();
235 	status_t err = B_OK;
236 	RegistrarThreadManager manager;
237 	CHK(fApplication && fApplication->InitCheck() == B_OK);
238 	BMessenger managerMessenger(NULL, fApplication, &err);
239 // TODO: Do something about this...
240 if (err != B_OK) {
241 fprintf(stderr, "Fails because we try to init an Haiku BMessenger with a "
242 "BLooper from R5's libbe (more precisely a BTestApp living in libcppunit, "
243 "which is only linked against R5's libbe).\n");
244 }
245 	CHK(err == B_OK && managerMessenger.IsValid());
246 
247 	const uint termThreads = 2;
248 
249 	// This test is only useful if the thread limit of the manager
250 	// class is > kTermThreads
251 	CHK(termThreads < RegistrarThreadManager::kThreadLimit);
252 
253 	// Launch some terminating threads
254 	uint i;
255 	for (i = 0; i < termThreads; i++) {
256 		NextSubTest();
257 		char name[1024];
258 		sprintf(name, "terminating #%d", i);
259 		RegistrarThread *thread = new TerminatingThread(name, B_NORMAL_PRIORITY, managerMessenger);
260 		CHK(thread != NULL);
261 		CHK(thread->InitCheck() == B_OK);
262 		CHK(manager.LaunchThread(thread) == B_OK);
263 	}
264 
265 	// Now fill up the manager with non-terminating threads
266 	for (; i < RegistrarThreadManager::kThreadLimit; i++) {
267 		NextSubTest();
268 		char name[1024];
269 		sprintf(name, "nice #%d", i);
270 		RegistrarThread *thread = new WellBehavedInfiniteThread(name, B_NORMAL_PRIORITY, managerMessenger);
271 		CHK(thread != NULL);
272 		CHK(thread->InitCheck() == B_OK);
273 		CHK(manager.LaunchThread(thread) == B_OK);
274 	}
275 	CHK(manager.ThreadCount() == RegistrarThreadManager::kThreadLimit);
276 
277 	// Now try to launch just one more...
278 	NextSubTest();
279 	{
280 		char *name = "hopeless thread";
281 		RegistrarThread *thread = new WellBehavedInfiniteThread(name, B_NORMAL_PRIORITY, managerMessenger);
282 		CHK(thread != NULL);
283 		CHK(thread->InitCheck() == B_OK);
284 		CHK(manager.LaunchThread(thread) == B_NO_MORE_THREADS);
285 		delete thread;
286 	}
287 
288 	// Now wait a little bit for our terminating threads to quit,
289 	// cleanup after them, and make sure we can now launch that
290 	// many threads again
291 	NextSubTest();
292 	snooze(500000);
293 	manager.CleanupThreads();
294 
295 	for (i = 0; i < termThreads; i++) {
296 		NextSubTest();
297 		char name[1024];
298 		sprintf(name, "2nd round nice #%d", i);
299 		RegistrarThread *thread = new TerminatingThread(name, B_NORMAL_PRIORITY, managerMessenger);
300 		CHK(thread != NULL);
301 		CHK(thread->InitCheck() == B_OK);
302 		CHK(manager.LaunchThread(thread) == B_OK);
303 	}
304 
305 	// Now try once more to launch just one more...
306 	NextSubTest();
307 	{
308 		char *name = "hopeless thread";
309 		RegistrarThread *thread = new WellBehavedInfiniteThread(name, B_NORMAL_PRIORITY, managerMessenger);
310 		CHK(thread != NULL);
311 		CHK(thread->InitCheck() == B_OK);
312 		CHK(manager.LaunchThread(thread) == B_NO_MORE_THREADS);
313 		delete thread;
314 	}
315 
316 	// Cleanup
317 	NextSubTest();
318 	manager.ShutdownThreads();
319 	snooze(500000);
320 
321 #endif	// !TEST_R5
322 }
323