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
34enum 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
43class SMTester {
44public:
45	SMTester(target_kind targetKind)
46		: fTargetKind(targetKind)
47	{
48	}
49
50	~SMTester()
51	{
52	}
53
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
106if (actualResult != result)
107printf("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
115private:
116	target_kind	fTargetKind;
117};
118
119
120//------------------------------------------------------------------------------
121
122// constructor
123SendMessageTester::SendMessageTester()
124	: BThreadedTestCase(),
125	  fHandler(NULL),
126	  fLooper(NULL)
127{
128}
129
130// constructor
131SendMessageTester::SendMessageTester(std::string name)
132	: BThreadedTestCase(name),
133	  fHandler(NULL),
134	  fLooper(NULL)
135{
136}
137
138// destructor
139SendMessageTester::~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
152void
153SendMessageTester::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
214void
215SendMessageTester::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 */
382void 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
399Test* 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