xref: /haiku/src/tests/kits/app/bmessenger/SendMessageTester.cpp (revision 76a5f3484abd9a293483b45f40455c0b58e6f3f0)
1 //------------------------------------------------------------------------------
2 //	SendMessageTester.cpp
3 //
4 //------------------------------------------------------------------------------
5 
6 // Standard Includes -----------------------------------------------------------
7 #include <stdio.h>
8 
9 // System Includes -------------------------------------------------------------
10 #include <Message.h>
11 #include <OS.h>
12 #include <Handler.h>
13 #include <Looper.h>
14 #include <Messenger.h>
15 
16 // Project Includes ------------------------------------------------------------
17 #include <TestUtils.h>
18 #include <ThreadedTestCaller.h>
19 #include <cppunit/TestSuite.h>
20 
21 // Local Includes --------------------------------------------------------------
22 #include "Helpers.h"
23 #include "SendMessageTester.h"
24 #include "SMInvoker.h"
25 #include "SMLooper.h"
26 #include "SMReplyTarget.h"
27 #include "SMTarget.h"
28 
29 // Local Defines ---------------------------------------------------------------
30 
31 // Globals ---------------------------------------------------------------------
32 
33 // target flavors
34 enum target_kind {
35 	TARGET_UNINITIALIZED,
36 	TARGET_LOCAL_PREFERRED,
37 	TARGET_LOCAL_SPECIFIC,
38 	TARGET_REMOTE_PREFERRED,
39 	TARGET_REMOTE_SPECIFIC,
40 };
41 
42 // tester class
43 class SMTester {
44 public:
SMTester(target_kind targetKind)45 	SMTester(target_kind targetKind)
46 		: fTargetKind(targetKind)
47 	{
48 	}
49 
~SMTester()50 	~SMTester()
51 	{
52 	}
53 
Run(SMInvoker & invoker,bigtime_t targetUnblock,bigtime_t targetReply,status_t result,bool deliverySuccess,bool replySuccess,bigtime_t duration)54 	void Run(SMInvoker &invoker, bigtime_t targetUnblock,
55 			 bigtime_t targetReply, status_t result, bool deliverySuccess,
56 			 bool replySuccess, bigtime_t duration)
57 	{
58 //printf("SMTester::Run(%lld, %lld, %lx, %d, %d, %lld)\n", targetUnblock,
59 //targetReply, result, deliverySuccess, replySuccess, duration);
60 		enum { JITTER = 10000 };
61 		enum { SETUP_LATENCY = 100000 };
62 		enum { DELIVERY_LATENCY = 10000 };
63 		enum { TARGET_HEAD_START = 1000 };
64 		if (targetUnblock == 0)
65 			targetUnblock = -TARGET_HEAD_START;
66 		// create the target
67 		SMTarget *target = NULL;
68 		switch (fTargetKind) {
69 			case TARGET_UNINITIALIZED:
70 				target = new SMTarget;
71 				break;
72 			case TARGET_LOCAL_PREFERRED:
73 				target = new LocalSMTarget(true);
74 				break;
75 			case TARGET_LOCAL_SPECIFIC:
76 				target = new LocalSMTarget(false);
77 				break;
78 			case TARGET_REMOTE_PREFERRED:
79 				target = new RemoteSMTarget(true);
80 				break;
81 			case TARGET_REMOTE_SPECIFIC:
82 				target = new RemoteSMTarget(false);
83 				break;
84 		}
85 		AutoDeleter<SMTarget> deleter(target);
86 		// create the reply target
87 		SMReplyTarget replyTarget;
88 		// init the target and send the message
89 		BHandler *replyHandler = replyTarget.Handler();
90 		BMessenger replyMessenger = replyTarget.Messenger();
91 		bigtime_t startTime = system_time() + SETUP_LATENCY;
92 		target->Init(startTime + targetUnblock, targetReply);
93 		BMessenger targetMessenger = target->Messenger();
94 		snooze_until(startTime, B_SYSTEM_TIMEBASE);
95 		status_t actualResult = invoker.Invoke(targetMessenger, replyHandler,
96 											   replyMessenger);
97 		bigtime_t actualDuration = system_time() - startTime;
98 //printf("duration: %lld vs %lld\n", actualDuration, duration);
99 		// We need to wait for the reply, if reply mode is asynchronous.
100 		snooze_until(startTime + targetUnblock + targetReply
101 					 + 2 * DELIVERY_LATENCY, B_SYSTEM_TIMEBASE);
102 		bool actualReplySuccess = invoker.ReplySuccess();
103 		if (!invoker.DirectReply())
104 			actualReplySuccess = replyTarget.ReplySuccess();
105 		// check the results
106 if (actualResult != result)
107 printf("result: %lx vs %lx\n", actualResult, result);
108 		CHK(actualResult == result);
109 		CHK(target->DeliverySuccess() == deliverySuccess);
110 		CHK(actualReplySuccess == replySuccess);
111 		CHK(actualDuration > duration - JITTER
112 			&& actualDuration < duration + JITTER);
113 	}
114 
115 private:
116 	target_kind	fTargetKind;
117 };
118 
119 
120 //------------------------------------------------------------------------------
121 
122 // constructor
SendMessageTester()123 SendMessageTester::SendMessageTester()
124 	: BThreadedTestCase(),
125 	  fHandler(NULL),
126 	  fLooper(NULL)
127 {
128 }
129 
130 // constructor
SendMessageTester(std::string name)131 SendMessageTester::SendMessageTester(std::string name)
132 	: BThreadedTestCase(name),
133 	  fHandler(NULL),
134 	  fLooper(NULL)
135 {
136 }
137 
138 // destructor
~SendMessageTester()139 SendMessageTester::~SendMessageTester()
140 {
141 	if (fLooper) {
142 		fLooper->Lock();
143 		if (fHandler) {
144 			fLooper->RemoveHandler(fHandler);
145 			delete fHandler;
146 		}
147 		fLooper->Quit();
148 	}
149 }
150 
151 // TestUninitialized
152 void
TestUninitialized()153 SendMessageTester::TestUninitialized()
154 {
155 	SMTester tester(TARGET_UNINITIALIZED);
156 	// status_t SendMessage(uint32 command, BHandler *replyTo) const
157 	NextSubTest();
158 	{
159 		SMInvoker1 invoker1(false);
160 		SMInvoker1 invoker2(true);
161 		tester.Run(invoker1, 0, 0, B_BAD_PORT_ID, false, false, 0);
162 		tester.Run(invoker2, 0, 0, B_BAD_PORT_ID, false, false, 0);
163 	}
164 	// status_t SendMessage(BMessage *message, BHandler *replyTo,
165 	//						bigtime_t timeout) const
166 	NextSubTest();
167 	{
168 		SMInvoker2 invoker1(true, false, B_INFINITE_TIMEOUT);
169 		SMInvoker2 invoker2(true, true, B_INFINITE_TIMEOUT);
170 		tester.Run(invoker1, 0, 0, B_BAD_PORT_ID, false, false, 0);
171 		tester.Run(invoker2, 0, 0, B_BAD_PORT_ID, false, false, 0);
172 	}
173 	// status_t SendMessage(BMessage *message, BMessenger replyTo,
174 	//						bigtime_t timeout) const
175 	NextSubTest();
176 	{
177 		SMInvoker3 invoker1(true, false, B_INFINITE_TIMEOUT);
178 		SMInvoker3 invoker2(true, true, B_INFINITE_TIMEOUT);
179 		tester.Run(invoker1, 0, 0, B_BAD_PORT_ID, false, false, 0);
180 		tester.Run(invoker2, 0, 0, B_BAD_PORT_ID, false, false, 0);
181 	}
182 	// status_t SendMessage(uint32 command, BMessage *reply) const
183 	NextSubTest();
184 	{
185 		SMInvoker4 invoker1(false);
186 		SMInvoker4 invoker2(true);
187 // We check the parameters first.
188 #ifdef TEST_OBOS
189 		tester.Run(invoker1, 0, 0, B_BAD_VALUE, false, false, 0);
190 #else
191 		tester.Run(invoker1, 0, 0, B_BAD_PORT_ID, false, false, 0);
192 #endif
193 		tester.Run(invoker2, 0, 0, B_BAD_PORT_ID, false, false, 0);
194 	}
195 	// status_t SendMessage(BMessage *message, BMessage *reply,
196 	//						bigtime_t deliveryTimeout,
197 	//						bigtime_t replyTimeout) const
198 	NextSubTest();
199 	{
200 		SMInvoker5 invoker1(true, false, B_INFINITE_TIMEOUT,
201 							B_INFINITE_TIMEOUT);
202 		SMInvoker5 invoker2(true, true, B_INFINITE_TIMEOUT,
203 							B_INFINITE_TIMEOUT);
204 #ifdef TEST_OBOS
205 		tester.Run(invoker1, 0, 0, B_BAD_VALUE, false, false, 0);
206 #else
207 		tester.Run(invoker1, 0, 0, B_BAD_PORT_ID, false, false, 0);
208 #endif
209 		tester.Run(invoker2, 0, 0, B_BAD_PORT_ID, false, false, 0);
210 	}
211 }
212 
213 // TestInitialized
214 void
TestInitialized(SMTester & tester)215 SendMessageTester::TestInitialized(SMTester &tester)
216 {
217 	// status_t SendMessage(uint32 command, BHandler *replyTo) const
218 	NextSubTest();
219 	{
220 		SMInvoker1 invoker1(false);
221 		SMInvoker1 invoker2(true);
222 		tester.Run(invoker1, 0, 0, B_OK, true, false, 0);
223 		tester.Run(invoker2, 0, 0, B_OK, true, true, 0);
224 	}
225 	// status_t SendMessage(BMessage *message, BHandler *replyTo,
226 	//						bigtime_t timeout) const
227 	NextSubTest();
228 	{
229 // R5 crashes when passing a NULL message.
230 #ifndef TEST_R5
231 		SMInvoker2 invoker1(false, false, B_INFINITE_TIMEOUT);
232 		tester.Run(invoker1, 0, 0, B_BAD_VALUE, false, false, 0);
233 #endif
234 	}
235 	NextSubTest();
236 	{
237 		SMInvoker2 invoker1(true, false, B_INFINITE_TIMEOUT);
238 		SMInvoker2 invoker2(true, true, B_INFINITE_TIMEOUT);
239 		tester.Run(invoker1, 0, 0, B_OK, true, false, 0);
240 		tester.Run(invoker2, 0, 0, B_OK, true, true, 0);
241 	}
242 	NextSubTest();
243 	{
244 		SMInvoker2 invoker1(true, false, 0);
245 		SMInvoker2 invoker2(true, true, 0);
246 		tester.Run(invoker1, 0, 0, B_OK, true, false, 0);
247 		tester.Run(invoker2, 0, 0, B_OK, true, true, 0);
248 		tester.Run(invoker1, 20000, 0, B_WOULD_BLOCK, false, false, 0);
249 		tester.Run(invoker2, 20000, 0, B_WOULD_BLOCK, false, false, 0);
250 	}
251 	NextSubTest();
252 	{
253 		SMInvoker2 invoker1(true, false, 20000);
254 		SMInvoker2 invoker2(true, true, 20000);
255 		tester.Run(invoker1, 10000, 0, B_OK, true, false, 10000);
256 		tester.Run(invoker2, 10000, 0, B_OK, true, true, 10000);
257 		tester.Run(invoker1, 40000, 0, B_TIMED_OUT, false, false, 20000);
258 		tester.Run(invoker2, 40000, 0, B_TIMED_OUT, false, false, 20000);
259 	}
260 	// status_t SendMessage(BMessage *message, BMessenger replyTo,
261 	//						bigtime_t timeout) const
262 	NextSubTest();
263 	{
264 // R5 crashes when passing a NULL message.
265 #ifndef TEST_R5
266 		SMInvoker3 invoker1(false, false, B_INFINITE_TIMEOUT);
267 		tester.Run(invoker1, 0, 0, B_BAD_VALUE, false, false, 0);
268 #endif
269 	}
270 	NextSubTest();
271 	{
272 		SMInvoker3 invoker1(true, false, B_INFINITE_TIMEOUT);
273 		SMInvoker3 invoker2(true, true, B_INFINITE_TIMEOUT);
274 		tester.Run(invoker1, 0, 0, B_OK, true, false, 0);
275 		tester.Run(invoker2, 0, 0, B_OK, true, true, 0);
276 	}
277 	NextSubTest();
278 	{
279 		SMInvoker3 invoker1(true, false, 0);
280 		SMInvoker3 invoker2(true, true, 0);
281 		tester.Run(invoker1, 0, 0, B_OK, true, false, 0);
282 		tester.Run(invoker2, 0, 0, B_OK, true, true, 0);
283 		tester.Run(invoker1, 20000, 0, B_WOULD_BLOCK, false, false, 0);
284 		tester.Run(invoker2, 20000, 0, B_WOULD_BLOCK, false, false, 0);
285 	}
286 	NextSubTest();
287 	{
288 		SMInvoker3 invoker1(true, false, 20000);
289 		SMInvoker3 invoker2(true, true, 20000);
290 		tester.Run(invoker1, 10000, 0, B_OK, true, false, 10000);
291 		tester.Run(invoker2, 10000, 0, B_OK, true, true, 10000);
292 		tester.Run(invoker1, 40000, 0, B_TIMED_OUT, false, false, 20000);
293 		tester.Run(invoker2, 40000, 0, B_TIMED_OUT, false, false, 20000);
294 	}
295 	// status_t SendMessage(uint32 command, BMessage *reply) const
296 	NextSubTest();
297 	{
298 // R5 crashes when passing a NULL reply message
299 #ifndef TEST_R5
300 		SMInvoker4 invoker1(false);
301 #endif
302 		SMInvoker4 invoker2(true);
303 #ifndef TEST_R5
304 		tester.Run(invoker1, 20000, 20000, B_BAD_VALUE, false, false, 0);
305 #endif
306 		tester.Run(invoker2, 20000, 20000, B_OK, true, true, 40000);
307 	}
308 	// status_t SendMessage(BMessage *message, BMessage *reply,
309 	//						bigtime_t deliveryTimeout,
310 	//						bigtime_t replyTimeout) const
311 	NextSubTest();
312 	{
313 // R5 crashes when passing a NULL message.
314 #ifndef TEST_R5
315 		SMInvoker5 invoker1(false, true, B_INFINITE_TIMEOUT,
316 							B_INFINITE_TIMEOUT);
317 		tester.Run(invoker1, 0, 0, B_BAD_VALUE, false, false, 0);
318 #endif
319 	}
320 	NextSubTest();
321 	{
322 		SMInvoker5 invoker1(true, true, B_INFINITE_TIMEOUT,
323 							B_INFINITE_TIMEOUT);
324 		SMInvoker5 invoker2(true, true, B_INFINITE_TIMEOUT, 0);
325 		SMInvoker5 invoker3(true, true, B_INFINITE_TIMEOUT, 20000);
326 		tester.Run(invoker1, 0, 0, B_OK, true, true, 0);
327 		tester.Run(invoker1, 10000, 0, B_OK, true, true, 10000);
328 		tester.Run(invoker1, 0, 10000, B_OK, true, true, 10000);
329 		// These two are race-conditional: The sending task must be pre-empted
330 		// before reading from the reply port and the target must reply before
331 		// the sending task gets another time slice.
332 //		tester.Run(invoker2, 0, 0, B_OK, true, true, 0);
333 //		tester.Run(invoker2, 10000, 0, B_OK, true, true, 10000);
334 		tester.Run(invoker2, 0, 10000, B_WOULD_BLOCK, true, false, 0);
335 		tester.Run(invoker3, 0, 10000, B_OK, true, true, 10000);
336 		tester.Run(invoker3, 20000, 10000, B_OK, true, true, 30000);
337 		tester.Run(invoker3, 0, 30000, B_TIMED_OUT, true, false, 20000);
338 	}
339 	NextSubTest();
340 	{
341 		SMInvoker5 invoker1(true, true, 0, B_INFINITE_TIMEOUT);
342 		SMInvoker5 invoker2(true, true, 0, 0);
343 		SMInvoker5 invoker3(true, true, 0, 20000);
344 		tester.Run(invoker1, 0, 0, B_OK, true, true, 0);
345 		tester.Run(invoker1, 10000, 0, B_WOULD_BLOCK, false, false, 0);
346 		tester.Run(invoker1, 0, 10000, B_OK, true, true, 10000);
347 		// This one is race-conditional: The sending task must be pre-empted
348 		// before reading from the reply port and the target must reply before
349 		// the sending task gets another time slice.
350 //		tester.Run(invoker2, 0, 0, B_OK, true, true, 0);
351 		tester.Run(invoker2, 10000, 0, B_WOULD_BLOCK, false, false, 0);
352 		tester.Run(invoker2, 0, 10000, B_WOULD_BLOCK, true, false, 0);
353 		tester.Run(invoker3, 0, 10000, B_OK, true, true, 10000);
354 		tester.Run(invoker3, 10000, 10000, B_WOULD_BLOCK, false, false, 0);
355 		tester.Run(invoker3, 0, 30000, B_TIMED_OUT, true, false, 20000);
356 	}
357 	NextSubTest();
358 	{
359 		SMInvoker5 invoker1(true, true, 20000, B_INFINITE_TIMEOUT);
360 		SMInvoker5 invoker2(true, true, 20000, 0);
361 		SMInvoker5 invoker3(true, true, 20000, 20000);
362 		tester.Run(invoker1, 0, 0, B_OK, true, true, 0);
363 		tester.Run(invoker1, 10000, 0, B_OK, true, true, 10000);
364 		tester.Run(invoker1, 30000, 0, B_TIMED_OUT, false, false, 20000);
365 		tester.Run(invoker1, 10000, 20000, B_OK, true, true, 30000);
366 		// These two are race-conditional: The sending task must be pre-empted
367 		// before reading from the reply port and the target must reply before
368 		// the sending task gets another time slice.
369 //		tester.Run(invoker2, 0, 0, B_OK, true, true, 0);
370 //		tester.Run(invoker2, 10000, 0, B_OK, true, true, 0);
371 		tester.Run(invoker2, 30000, 0, B_TIMED_OUT, false, false, 20000);
372 		tester.Run(invoker2, 0, 10000, B_WOULD_BLOCK, true, false, 0);
373 		tester.Run(invoker3, 10000, 10000, B_OK, true, true, 20000);
374 		tester.Run(invoker3, 30000, 10000, B_TIMED_OUT, false, false, 20000);
375 		tester.Run(invoker3, 10000, 30000, B_TIMED_OUT, true, false, 30000);
376 	}
377 }
378 
379 /*
380 	The different SendMessage() flavors.
381  */
SendMessageTest1()382 void SendMessageTester::SendMessageTest1()
383 {
384 	TestUninitialized();
385 	target_kind targetKinds[] = {
386 		TARGET_LOCAL_PREFERRED,
387 		TARGET_LOCAL_SPECIFIC,
388 		TARGET_REMOTE_PREFERRED,
389 		TARGET_REMOTE_SPECIFIC
390 	};
391 	int32 targetKindCount = sizeof(targetKinds) / sizeof(target_kind);
392 	for (int32 i = 0; i < targetKindCount; i++) {
393 		SMTester tester(targetKinds[i]);
394 		TestInitialized(tester);
395 	}
396 }
397 
398 
Suite()399 Test* SendMessageTester::Suite()
400 {
401 	typedef BThreadedTestCaller<SendMessageTester> TC;
402 
403 	TestSuite* testSuite = new TestSuite;
404 
405 	ADD_TEST4(BMessenger, testSuite, SendMessageTester, SendMessageTest1);
406 
407 	return testSuite;
408 }
409 
410 
411