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