1//------------------------------------------------------------------------------
2//	BroadcastTester.cpp
3//
4//------------------------------------------------------------------------------
5
6// Standard Includes -----------------------------------------------------------
7#include <stdio.h>
8#include <stdlib.h>
9#include <utime.h>
10
11// System Includes -------------------------------------------------------------
12#include <Message.h>
13#include <OS.h>
14#include <AppFileInfo.h>
15#include <Application.h>
16#include <File.h>
17#include <FindDirectory.h>
18#include <Handler.h>
19#include <Looper.h>
20#include <Message.h>
21#include <MessageQueue.h>
22#include <Path.h>
23#include <Roster.h>
24#include <String.h>
25
26// Project Includes ------------------------------------------------------------
27#include <TestShell.h>
28#include <TestUtils.h>
29#include <cppunit/TestAssert.h>
30
31// Local Includes --------------------------------------------------------------
32#include "AppRunner.h"
33#include "BroadcastTester.h"
34#include "LaunchTesterHelper.h"
35#include "RosterTestAppDefs.h"
36
37// Local Defines ---------------------------------------------------------------
38
39// Globals ---------------------------------------------------------------------
40
41//------------------------------------------------------------------------------
42
43static const char *testerSignature
44	= "application/x-vnd.obos-roster-broadcast-test";
45static const char *appType1	= "application/x-vnd.obos-roster-broadcast-app1";
46static const char *appType2	= "application/x-vnd.obos-roster-broadcast-app2";
47static const char *appType3	= "application/x-vnd.obos-roster-broadcast-app3";
48static const char *appType4	= "application/x-vnd.obos-roster-broadcast-app4";
49
50static const char *testDir		= "/tmp/testdir";
51static const char *appFile1		= "/tmp/testdir/app1";
52static const char *appFile2		= "/tmp/testdir/app2";
53static const char *appFile3		= "/tmp/testdir/app3";
54static const char *appFile4		= "/tmp/testdir/app4";
55
56
57// ref_for_path
58static
59entry_ref
60ref_for_path(const char *filename, bool traverse = true)
61{
62	entry_ref ref;
63	BEntry entry;
64	CHK(entry.SetTo(filename, traverse) == B_OK);
65	CHK(entry.GetRef(&ref) == B_OK);
66	return ref;
67}
68
69// create_app
70static
71entry_ref
72create_app(const char *filename, const char *signature,
73		   bool install = false, bool makeExecutable = true,
74		   uint32 appFlags = B_SINGLE_LAUNCH)
75{
76	BString testApp;
77	CHK(find_test_app("RosterBroadcastTestApp1", &testApp) == B_OK);
78	system((string("cp ") + testApp.String() + " " + filename).c_str());
79	if (makeExecutable)
80		system((string("chmod a+x ") + filename).c_str());
81	BFile file;
82	CHK(file.SetTo(filename, B_READ_WRITE) == B_OK);
83	BAppFileInfo appFileInfo;
84	CHK(appFileInfo.SetTo(&file) == B_OK);
85	if (signature)
86		CHK(appFileInfo.SetSignature(signature) == B_OK);
87	CHK(appFileInfo.SetAppFlags(appFlags) == B_OK);
88	if (install && signature)
89		CHK(BMimeType(signature).Install() == B_OK);
90	// We write the signature into a separate attribute, just in case we
91	// decide to also test files without BEOS:APP_SIG attribute.
92	BString signatureString(signature);
93	file.WriteAttrString("signature", &signatureString);
94	return ref_for_path(filename);
95}
96
97
98// setUp
99void
100BroadcastTester::setUp()
101{
102	RosterLaunchApp *app = new RosterLaunchApp(testerSignature);
103	fApplication = app;
104	app->SetHandler(new RosterBroadcastHandler);
105	system((string("mkdir ") + testDir).c_str());
106}
107
108// tearDown
109void
110BroadcastTester::tearDown()
111{
112	BMimeType(appType1).Delete();
113	BMimeType(appType2).Delete();
114	BMimeType(appType3).Delete();
115	BMimeType(appType4).Delete();
116	delete fApplication;
117	system((string("rm -rf ") + testDir).c_str());
118}
119
120// SimpleAppLauncher
121class SimpleAppLauncher : public LaunchCaller {
122public:
123	SimpleAppLauncher() : fRef() {}
124	SimpleAppLauncher(const entry_ref &ref) : fRef(ref) {}
125	virtual ~SimpleAppLauncher() {}
126	virtual status_t operator()(const char *type, BList *messages, int32 argc,
127								const char **argv, team_id *team)
128	{
129		return be_roster->Launch(&fRef, (BMessage*)NULL, team);
130	}
131	virtual bool SupportsRefs() const { return true; }
132	virtual const entry_ref *Ref() const { return &fRef; }
133
134	virtual LaunchCaller *CloneInternal()
135	{
136		return new SimpleAppLauncher;
137	}
138
139protected:
140	entry_ref fRef;
141};
142
143/*
144	status_t Broadcast(BMessage *message) const
145	@case 1			NULL message
146	@results		Should return B_BAD_VALUE.
147*/
148void BroadcastTester::BroadcastTestA1()
149{
150// R5: crashes when passing a NULL message.
151#ifndef TEST_R5
152	CHK(be_roster->Broadcast(NULL) == B_BAD_VALUE);
153#endif
154}
155
156/*
157	status_t Broadcast(BMessage *message) const
158	@case 2			valid message, several apps, one is B_ARGV_ONLY
159	@results		Should return B_OK and send the message to all (including
160					the B_ARGV_ONLY) apps. Replies go to be_app_messenger.
161*/
162void BroadcastTester::BroadcastTestA2()
163{
164	LaunchContext context;
165	BRoster roster;
166	// launch app 1
167	entry_ref ref1(create_app(appFile1, appType1));
168	SimpleAppLauncher caller1(ref1);
169	team_id team1;
170	CHK(context(caller1, appType1, &team1) == B_OK);
171	// launch app 2
172	entry_ref ref2(create_app(appFile2, appType2, false, true,
173							  B_SINGLE_LAUNCH | B_ARGV_ONLY));
174	SimpleAppLauncher caller2(ref2);
175	team_id team2;
176	CHK(context(caller2, appType2, &team2) == B_OK);
177	// launch app 3
178	entry_ref ref3(create_app(appFile3, appType3));
179	SimpleAppLauncher caller3(ref3);
180	team_id team3;
181	CHK(context(caller3, appType3, &team3) == B_OK);
182	// launch app 4
183	entry_ref ref4(create_app(appFile4, appType4));
184	SimpleAppLauncher caller4(ref4);
185	team_id team4;
186	CHK(context(caller4, appType4, &team4) == B_OK);
187	// wait for the apps to run
188	context.WaitForMessage(team1, MSG_READY_TO_RUN);
189	context.WaitForMessage(team2, MSG_READY_TO_RUN);
190	context.WaitForMessage(team3, MSG_READY_TO_RUN);
191	context.WaitForMessage(team4, MSG_READY_TO_RUN);
192	// broadcast a message
193	BMessage message(MSG_1);
194	CHK(roster.Broadcast(&message) == B_OK);
195	// wait for the apps to report the receipt of the message
196	context.WaitForMessage(team1, MSG_MESSAGE_RECEIVED);
197	context.WaitForMessage(team2, MSG_MESSAGE_RECEIVED);
198	context.WaitForMessage(team3, MSG_MESSAGE_RECEIVED);
199	context.WaitForMessage(team4, MSG_MESSAGE_RECEIVED);
200	// check the messages
201	context.Terminate();
202	// app 1
203	int32 cookie = 0;
204	CHK(context.CheckNextMessage(caller1, team1, cookie, MSG_STARTED));
205	CHK(context.CheckMainArgsMessage(caller1, team1, cookie, &ref1, false));
206	CHK(context.CheckNextMessage(caller1, team1, cookie, MSG_READY_TO_RUN));
207	CHK(context.CheckMessageMessage(caller1, team1, cookie, &message));
208	CHK(context.CheckNextMessage(caller1, team1, cookie, MSG_2));
209	CHK(context.CheckNextMessage(caller1, team1, cookie, MSG_QUIT_REQUESTED));
210	CHK(context.CheckNextMessage(caller1, team1, cookie, MSG_TERMINATED));
211	// app 2
212	cookie = 0;
213	CHK(context.CheckNextMessage(caller2, team2, cookie, MSG_STARTED));
214	CHK(context.CheckMainArgsMessage(caller2, team2, cookie, &ref2, false));
215	CHK(context.CheckNextMessage(caller2, team2, cookie, MSG_READY_TO_RUN));
216	CHK(context.CheckMessageMessage(caller2, team2, cookie, &message));
217	CHK(context.CheckNextMessage(caller2, team2, cookie, MSG_2));
218	CHK(context.CheckNextMessage(caller2, team2, cookie, MSG_QUIT_REQUESTED));
219	CHK(context.CheckNextMessage(caller2, team2, cookie, MSG_TERMINATED));
220	// app 3
221	cookie = 0;
222	CHK(context.CheckNextMessage(caller3, team3, cookie, MSG_STARTED));
223	CHK(context.CheckMainArgsMessage(caller3, team3, cookie, &ref3, false));
224	CHK(context.CheckNextMessage(caller3, team3, cookie, MSG_READY_TO_RUN));
225	CHK(context.CheckMessageMessage(caller3, team3, cookie, &message));
226	CHK(context.CheckNextMessage(caller3, team3, cookie, MSG_2));
227	CHK(context.CheckNextMessage(caller3, team3, cookie, MSG_QUIT_REQUESTED));
228	CHK(context.CheckNextMessage(caller3, team3, cookie, MSG_TERMINATED));
229	// app 4
230	cookie = 0;
231	CHK(context.CheckNextMessage(caller4, team4, cookie, MSG_STARTED));
232	CHK(context.CheckMainArgsMessage(caller4, team4, cookie, &ref4, false));
233	CHK(context.CheckNextMessage(caller4, team4, cookie, MSG_READY_TO_RUN));
234	CHK(context.CheckMessageMessage(caller4, team4, cookie, &message));
235	CHK(context.CheckNextMessage(caller4, team4, cookie, MSG_2));
236	CHK(context.CheckNextMessage(caller4, team4, cookie, MSG_QUIT_REQUESTED));
237	CHK(context.CheckNextMessage(caller4, team4, cookie, MSG_TERMINATED));
238}
239
240/*
241	status_t Broadcast(BMessage *message, BMessenger replyTo) const
242	@case 1			NULL message
243	@results		Should return B_BAD_VALUE.
244*/
245void BroadcastTester::BroadcastTestB1()
246{
247// R5: crashes when passing a NULL message.
248#ifndef TEST_R5
249	BMessenger replyTo(dynamic_cast<RosterLaunchApp*>(be_app)->Handler());
250	CHK(be_roster->Broadcast(NULL, replyTo) == B_BAD_VALUE);
251#endif
252}
253
254/*
255	status_t Broadcast(BMessage *message, BMessenger replyTo) const
256	@case 2			valid message, several apps, one is B_ARGV_ONLY
257	@results		Should return B_OK and send the message to all (including
258					the B_ARGV_ONLY) apps. Replies go to the specified
259					messenger.
260*/
261void BroadcastTester::BroadcastTestB2()
262{
263	LaunchContext context;
264	BRoster roster;
265	// launch app 1
266	entry_ref ref1(create_app(appFile1, appType1));
267	SimpleAppLauncher caller1(ref1);
268	team_id team1;
269	CHK(context(caller1, appType1, &team1) == B_OK);
270	// launch app 2
271	entry_ref ref2(create_app(appFile2, appType2, false, true,
272							  B_SINGLE_LAUNCH | B_ARGV_ONLY));
273	SimpleAppLauncher caller2(ref2);
274	team_id team2;
275	CHK(context(caller2, appType2, &team2) == B_OK);
276	// launch app 3
277	entry_ref ref3(create_app(appFile3, appType3));
278	SimpleAppLauncher caller3(ref3);
279	team_id team3;
280	CHK(context(caller3, appType3, &team3) == B_OK);
281	// launch app 4
282	entry_ref ref4(create_app(appFile4, appType4));
283	SimpleAppLauncher caller4(ref4);
284	team_id team4;
285	CHK(context(caller4, appType4, &team4) == B_OK);
286	// wait for the apps to run
287	context.WaitForMessage(team1, MSG_READY_TO_RUN);
288	context.WaitForMessage(team2, MSG_READY_TO_RUN);
289	context.WaitForMessage(team3, MSG_READY_TO_RUN);
290	context.WaitForMessage(team4, MSG_READY_TO_RUN);
291	// broadcast a message
292	BMessage message(MSG_1);
293	BMessenger replyTo(dynamic_cast<RosterLaunchApp*>(be_app)->Handler());
294	CHK(roster.Broadcast(&message, replyTo) == B_OK);
295	// wait for the apps to report the receipt of the message
296	context.WaitForMessage(team1, MSG_MESSAGE_RECEIVED);
297	context.WaitForMessage(team2, MSG_MESSAGE_RECEIVED);
298	context.WaitForMessage(team3, MSG_MESSAGE_RECEIVED);
299	context.WaitForMessage(team4, MSG_MESSAGE_RECEIVED);
300	// check the messages
301	context.Terminate();
302	// app 1
303	int32 cookie = 0;
304	CHK(context.CheckNextMessage(caller1, team1, cookie, MSG_STARTED));
305	CHK(context.CheckMainArgsMessage(caller1, team1, cookie, &ref1, false));
306	CHK(context.CheckNextMessage(caller1, team1, cookie, MSG_READY_TO_RUN));
307	CHK(context.CheckMessageMessage(caller1, team1, cookie, &message));
308	CHK(context.CheckNextMessage(caller1, team1, cookie, MSG_REPLY));
309	CHK(context.CheckNextMessage(caller1, team1, cookie, MSG_QUIT_REQUESTED));
310	CHK(context.CheckNextMessage(caller1, team1, cookie, MSG_TERMINATED));
311	// app 2
312	cookie = 0;
313	CHK(context.CheckNextMessage(caller2, team2, cookie, MSG_STARTED));
314	CHK(context.CheckMainArgsMessage(caller2, team2, cookie, &ref2, false));
315	CHK(context.CheckNextMessage(caller2, team2, cookie, MSG_READY_TO_RUN));
316	CHK(context.CheckMessageMessage(caller2, team2, cookie, &message));
317	CHK(context.CheckNextMessage(caller2, team2, cookie, MSG_REPLY));
318	CHK(context.CheckNextMessage(caller2, team2, cookie, MSG_QUIT_REQUESTED));
319	CHK(context.CheckNextMessage(caller2, team2, cookie, MSG_TERMINATED));
320	// app 3
321	cookie = 0;
322	CHK(context.CheckNextMessage(caller3, team3, cookie, MSG_STARTED));
323	CHK(context.CheckMainArgsMessage(caller3, team3, cookie, &ref3, false));
324	CHK(context.CheckNextMessage(caller3, team3, cookie, MSG_READY_TO_RUN));
325	CHK(context.CheckMessageMessage(caller3, team3, cookie, &message));
326	CHK(context.CheckNextMessage(caller3, team3, cookie, MSG_REPLY));
327	CHK(context.CheckNextMessage(caller3, team3, cookie, MSG_QUIT_REQUESTED));
328	CHK(context.CheckNextMessage(caller3, team3, cookie, MSG_TERMINATED));
329	// app 4
330	cookie = 0;
331	CHK(context.CheckNextMessage(caller4, team4, cookie, MSG_STARTED));
332	CHK(context.CheckMainArgsMessage(caller4, team4, cookie, &ref4, false));
333	CHK(context.CheckNextMessage(caller4, team4, cookie, MSG_READY_TO_RUN));
334	CHK(context.CheckMessageMessage(caller4, team4, cookie, &message));
335	CHK(context.CheckNextMessage(caller4, team4, cookie, MSG_REPLY));
336	CHK(context.CheckNextMessage(caller4, team4, cookie, MSG_QUIT_REQUESTED));
337	CHK(context.CheckNextMessage(caller4, team4, cookie, MSG_TERMINATED));
338}
339
340/*
341	status_t Broadcast(BMessage *message, BMessenger replyTo) const
342	@case 3			valid message, several apps, one is B_ARGV_ONLY,
343					invalid replyTo
344	@results		Should return B_OK and send the message to all (including
345					the B_ARGV_ONLY) apps. Replies go to the roster!
346*/
347void BroadcastTester::BroadcastTestB3()
348{
349	LaunchContext context;
350	BRoster roster;
351	// launch app 1
352	entry_ref ref1(create_app(appFile1, appType1));
353	SimpleAppLauncher caller1(ref1);
354	team_id team1;
355	CHK(context(caller1, appType1, &team1) == B_OK);
356	// launch app 2
357	entry_ref ref2(create_app(appFile2, appType2, false, true,
358							  B_SINGLE_LAUNCH | B_ARGV_ONLY));
359	SimpleAppLauncher caller2(ref2);
360	team_id team2;
361	CHK(context(caller2, appType2, &team2) == B_OK);
362	// launch app 3
363	entry_ref ref3(create_app(appFile3, appType3));
364	SimpleAppLauncher caller3(ref3);
365	team_id team3;
366	CHK(context(caller3, appType3, &team3) == B_OK);
367	// launch app 4
368	entry_ref ref4(create_app(appFile4, appType4));
369	SimpleAppLauncher caller4(ref4);
370	team_id team4;
371	CHK(context(caller4, appType4, &team4) == B_OK);
372	// wait for the apps to run
373	context.WaitForMessage(team1, MSG_READY_TO_RUN);
374	context.WaitForMessage(team2, MSG_READY_TO_RUN);
375	context.WaitForMessage(team3, MSG_READY_TO_RUN);
376	context.WaitForMessage(team4, MSG_READY_TO_RUN);
377	// broadcast a message
378	BMessage message(MSG_1);
379	BMessenger replyTo;
380	CHK(roster.Broadcast(&message, replyTo) == B_OK);
381	// wait for the apps to report the receipt of the message
382	context.WaitForMessage(team1, MSG_MESSAGE_RECEIVED);
383	context.WaitForMessage(team2, MSG_MESSAGE_RECEIVED);
384	context.WaitForMessage(team3, MSG_MESSAGE_RECEIVED);
385	context.WaitForMessage(team4, MSG_MESSAGE_RECEIVED);
386	// check the messages
387	context.Terminate();
388	// app 1
389	int32 cookie = 0;
390	CHK(context.CheckNextMessage(caller1, team1, cookie, MSG_STARTED));
391	CHK(context.CheckMainArgsMessage(caller1, team1, cookie, &ref1, false));
392	CHK(context.CheckNextMessage(caller1, team1, cookie, MSG_READY_TO_RUN));
393	CHK(context.CheckMessageMessage(caller1, team1, cookie, &message));
394//	CHK(context.CheckNextMessage(caller1, team1, cookie, MSG_2));
395	CHK(context.CheckNextMessage(caller1, team1, cookie, MSG_QUIT_REQUESTED));
396	CHK(context.CheckNextMessage(caller1, team1, cookie, MSG_TERMINATED));
397	// app 2
398	cookie = 0;
399	CHK(context.CheckNextMessage(caller2, team2, cookie, MSG_STARTED));
400	CHK(context.CheckMainArgsMessage(caller2, team2, cookie, &ref2, false));
401	CHK(context.CheckNextMessage(caller2, team2, cookie, MSG_READY_TO_RUN));
402	CHK(context.CheckMessageMessage(caller2, team2, cookie, &message));
403//	CHK(context.CheckNextMessage(caller2, team2, cookie, MSG_2));
404	CHK(context.CheckNextMessage(caller2, team2, cookie, MSG_QUIT_REQUESTED));
405	CHK(context.CheckNextMessage(caller2, team2, cookie, MSG_TERMINATED));
406	// app 3
407	cookie = 0;
408	CHK(context.CheckNextMessage(caller3, team3, cookie, MSG_STARTED));
409	CHK(context.CheckMainArgsMessage(caller3, team3, cookie, &ref3, false));
410	CHK(context.CheckNextMessage(caller3, team3, cookie, MSG_READY_TO_RUN));
411	CHK(context.CheckMessageMessage(caller3, team3, cookie, &message));
412//	CHK(context.CheckNextMessage(caller3, team3, cookie, MSG_2));
413	CHK(context.CheckNextMessage(caller3, team3, cookie, MSG_QUIT_REQUESTED));
414	CHK(context.CheckNextMessage(caller3, team3, cookie, MSG_TERMINATED));
415	// app 4
416	cookie = 0;
417	CHK(context.CheckNextMessage(caller4, team4, cookie, MSG_STARTED));
418	CHK(context.CheckMainArgsMessage(caller4, team4, cookie, &ref4, false));
419	CHK(context.CheckNextMessage(caller4, team4, cookie, MSG_READY_TO_RUN));
420	CHK(context.CheckMessageMessage(caller4, team4, cookie, &message));
421//	CHK(context.CheckNextMessage(caller4, team4, cookie, MSG_2));
422	CHK(context.CheckNextMessage(caller4, team4, cookie, MSG_QUIT_REQUESTED));
423	CHK(context.CheckNextMessage(caller4, team4, cookie, MSG_TERMINATED));
424}
425
426
427Test* BroadcastTester::Suite()
428{
429	TestSuite* SuiteOfTests = new TestSuite;
430
431	ADD_TEST4(BRoster, SuiteOfTests, BroadcastTester, BroadcastTestA1);
432	ADD_TEST4(BRoster, SuiteOfTests, BroadcastTester, BroadcastTestA2);
433
434	ADD_TEST4(BRoster, SuiteOfTests, BroadcastTester, BroadcastTestB1);
435	ADD_TEST4(BRoster, SuiteOfTests, BroadcastTester, BroadcastTestB2);
436	ADD_TEST4(BRoster, SuiteOfTests, BroadcastTester, BroadcastTestB3);
437
438	return SuiteOfTests;
439}
440
441