xref: /haiku/src/tests/kits/app/RegistrarThreadManagerTest.cpp (revision 51978af14a173e7fae0563b562be5603bc652aeb)
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