xref: /haiku/src/tests/kits/app/broster/RosterWatchingTester.cpp (revision 268f99dd7dc4bd7474a8bd2742d3f1ec1de6752a)
1 //------------------------------------------------------------------------------
2 //	RosterWatchingTester.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 "RosterWatchingTester.h"
34 #include "LaunchTesterHelper.h"
35 #include "RosterTestAppDefs.h"
36 
37 // Local Defines ---------------------------------------------------------------
38 
39 // Globals ---------------------------------------------------------------------
40 
41 //------------------------------------------------------------------------------
42 
43 static const char *testerSignature
44 	= "application/x-vnd.obos-roster-watching-test";
45 static const char *appType1	= "application/x-vnd.obos-roster-watching-app1";
46 static const char *appType2	= "application/x-vnd.obos-roster-watching-app2";
47 static const char *appType3	= "application/x-vnd.obos-roster-watching-app3";
48 static const char *appType4	= "application/x-vnd.obos-roster-watching-app4";
49 //static const char *appType5	= "application/x-vnd.obos-roster-watching-app5";
50 
51 static const char *testDir		= "/tmp/testdir";
52 static const char *appFile1		= "/tmp/testdir/app1";
53 static const char *appFile2		= "/tmp/testdir/app2";
54 static const char *appFile3		= "/tmp/testdir/app3";
55 static const char *appFile4		= "/tmp/testdir/app4";
56 //static const char *appFile5		= "/tmp/testdir/app5";
57 
58 
59 // ref_for_path
60 static
61 entry_ref
ref_for_path(const char * filename,bool traverse=true)62 ref_for_path(const char *filename, bool traverse = true)
63 {
64 	entry_ref ref;
65 	BEntry entry;
66 	CHK(entry.SetTo(filename, traverse) == B_OK);
67 	CHK(entry.GetRef(&ref) == B_OK);
68 	return ref;
69 }
70 
71 // create_app
72 static
73 entry_ref
create_app(const char * filename,const char * signature,bool install=false,bool makeExecutable=true,uint32 appFlags=B_SINGLE_LAUNCH)74 create_app(const char *filename, const char *signature,
75 		   bool install = false, bool makeExecutable = true,
76 		   uint32 appFlags = B_SINGLE_LAUNCH)
77 {
78 	BString testApp;
79 	CHK(find_test_app("RosterWatchingTestApp1", &testApp) == B_OK);
80 	system((string("cp ") + testApp.String() + " " + filename).c_str());
81 	if (makeExecutable)
82 		system((string("chmod a+x ") + filename).c_str());
83 	BFile file;
84 	CHK(file.SetTo(filename, B_READ_WRITE) == B_OK);
85 	BAppFileInfo appFileInfo;
86 	CHK(appFileInfo.SetTo(&file) == B_OK);
87 	if (signature)
88 		CHK(appFileInfo.SetSignature(signature) == B_OK);
89 	CHK(appFileInfo.SetAppFlags(appFlags) == B_OK);
90 	if (install && signature)
91 		CHK(BMimeType(signature).Install() == B_OK);
92 	// We write the signature into a separate attribute, just in case we
93 	// decide to also test files without BEOS:APP_SIG attribute.
94 	BString signatureString(signature);
95 	file.WriteAttrString("signature", &signatureString);
96 	return ref_for_path(filename);
97 }
98 
99 // app_info_for_team
100 static
101 app_info
app_info_for_team(team_id team)102 app_info_for_team(team_id team)
103 {
104 	app_info info;
105 	CHK(be_roster->GetRunningAppInfo(team, &info) == B_OK);
106 	return info;
107 }
108 
109 // check_watching_message
110 void
check_watching_message(LaunchContext & context,team_id team,int32 & cookie,const app_info & info,uint32 messageCode)111 check_watching_message(LaunchContext &context, team_id team, int32 &cookie,
112 					   const app_info &info, uint32 messageCode)
113 {
114 	// wait for and get the message
115 	CHK(context.WaitForMessage(team, MSG_MESSAGE_RECEIVED, false,
116 							   B_INFINITE_TIMEOUT, cookie));
117 	BMessage *container = context.NextMessageFrom(team, cookie);
118 	CHK(container != NULL);
119 	CHK(container->what == MSG_MESSAGE_RECEIVED);
120 	BMessage message;
121 	CHK(container->FindMessage("message", &message) == B_OK);
122 	// check the message
123 if (message.what != messageCode)
124 printf("message.what: %.4s vs messageCode: %.4s\n", (char*)&message.what,
125 (char*)&messageCode);
126 	CHK(message.what == messageCode);
127 	// team
128 	team_id foundTeam;
129 	CHK(message.FindInt32("be:team", &foundTeam) == B_OK);
130 	CHK(foundTeam == info.team);
131 	// thread
132 	thread_id thread;
133 	CHK(message.FindInt32("be:thread", &thread) == B_OK);
134 	CHK(thread == info.thread);
135 	// signature
136 	const char *signature = NULL;
137 	CHK(message.FindString("be:signature", &signature) == B_OK);
138 	CHK(!strcmp(signature, info.signature));
139 	// ref
140 	entry_ref ref;
141 	CHK(message.FindRef("be:ref", &ref) == B_OK);
142 	CHK(ref == info.ref);
143 	// flags
144 	uint32 flags;
145 	CHK(message.FindInt32("be:flags", (int32*)&flags) == B_OK);
146 	CHK(flags == info.flags);
147 }
148 
149 
150 // setUp
151 void
setUp()152 RosterWatchingTester::setUp()
153 {
154 	RosterLaunchApp *app = new RosterLaunchApp(testerSignature);
155 	fApplication = app;
156 	app->SetHandler(new RosterBroadcastHandler);
157 	system((string("mkdir ") + testDir).c_str());
158 }
159 
160 // tearDown
161 void
tearDown()162 RosterWatchingTester::tearDown()
163 {
164 	BMimeType(appType1).Delete();
165 	BMimeType(appType2).Delete();
166 	BMimeType(appType3).Delete();
167 	BMimeType(appType4).Delete();
168 //	BMimeType(appType5).Delete();
169 	delete fApplication;
170 	system((string("rm -rf ") + testDir).c_str());
171 }
172 
173 // SimpleAppLauncher
174 class SimpleAppLauncher : public LaunchCaller {
175 public:
SimpleAppLauncher()176 	SimpleAppLauncher() : fRef() {}
SimpleAppLauncher(const entry_ref & ref)177 	SimpleAppLauncher(const entry_ref &ref) : fRef(ref) {}
~SimpleAppLauncher()178 	virtual ~SimpleAppLauncher() {}
operator ()(const char * type,BList * messages,int32 argc,const char ** argv,team_id * team)179 	virtual status_t operator()(const char *type, BList *messages, int32 argc,
180 								const char **argv, team_id *team)
181 	{
182 		return be_roster->Launch(&fRef, (BMessage*)NULL, team);
183 	}
SupportsRefs() const184 	virtual bool SupportsRefs() const { return true; }
Ref() const185 	virtual const entry_ref *Ref() const { return &fRef; }
186 
CloneInternal()187 	virtual LaunchCaller *CloneInternal()
188 	{
189 		return new SimpleAppLauncher;
190 	}
191 
192 protected:
193 	entry_ref fRef;
194 };
195 
196 
197 /*
198 	status_t StartWatching(BMessenger target, uint32 eventMask) const
199 	status_t StopWatching(BMessenger target) const
200 	@case 1			{Start,Stop}Watching() with invalid messenger or invalid
201 					flags; StopWatching() non-watching messenger =>
202 	@results		Should return B_OK; B_BAD_VALUE.
203 */
WatchingTest1()204 void RosterWatchingTester::WatchingTest1()
205 {
206 	BRoster roster;
207 	BMessenger target;
208 	// not valid, not watching
209 	CHK(roster.StopWatching(target) == B_BAD_VALUE);
210 	// not valid
211 	CHK(roster.StartWatching(target, B_REQUEST_LAUNCHED | B_REQUEST_QUIT
212 							 | B_REQUEST_ACTIVATED) == B_OK);
213 	CHK(roster.StopWatching(target) == B_OK);
214 	// invalid flags
215 	CHK(roster.StartWatching(target, 0) == B_OK);
216 	CHK(roster.StopWatching(target) == B_OK);
217 	// valid, but not watching
218 	CHK(roster.StopWatching(be_app_messenger) == B_BAD_VALUE);
219 }
220 
221 /*
222 	status_t StartWatching(BMessenger target, uint32 eventMask) const
223 	status_t StopWatching(BMessenger target) const
224 	@case 2			several apps, several watchers, different eventMasks
225 	@results		Should return B_OK...
226 					Watching ends, when target has become invalid and the next watching
227 					message is tried to be sent.
228 */
WatchingTest2()229 void RosterWatchingTester::WatchingTest2()
230 {
231 	LaunchContext context;
232 	BRoster roster;
233 	// launch app 1
234 	entry_ref ref1(create_app(appFile1, appType1));
235 	SimpleAppLauncher caller1(ref1);
236 	team_id team1;
237 	CHK(context(caller1, appType1, &team1) == B_OK);
238 	context.WaitForMessage(team1, MSG_READY_TO_RUN);
239 	BMessenger target1(NULL, team1);
240 	app_info appInfo1(app_info_for_team(team1));
241 	CHK(roster.StartWatching(target1, B_REQUEST_LAUNCHED | B_REQUEST_QUIT
242 							 | B_REQUEST_ACTIVATED) == B_OK);
243 	//   messages: app 1
244 	int32 cookie1 = 0;
245 	CHK(context.CheckNextMessage(caller1, team1, cookie1, MSG_STARTED));
246 	CHK(context.CheckMainArgsMessage(caller1, team1, cookie1, &ref1, false));
247 	CHK(context.CheckNextMessage(caller1, team1, cookie1, MSG_READY_TO_RUN));
248 	// launch app 2
249 	entry_ref ref2(create_app(appFile2, appType2, false, true,
250 							  B_SINGLE_LAUNCH | B_ARGV_ONLY));
251 	SimpleAppLauncher caller2(ref2);
252 	team_id team2;
253 	CHK(context(caller2, appType2, &team2) == B_OK);
254 	context.WaitForMessage(team2, MSG_READY_TO_RUN);
255 	BMessenger target2(context.AppMessengerFor(team2));
256 	CHK(target2.IsValid());
257 	app_info appInfo2(app_info_for_team(team2));
258 	CHK(roster.StartWatching(target2, B_REQUEST_LAUNCHED) == B_OK);
259 	//   messages: app 2
260 	int32 cookie2 = 0;
261 	CHK(context.CheckNextMessage(caller2, team2, cookie2, MSG_STARTED));
262 	CHK(context.CheckMainArgsMessage(caller2, team2, cookie2, &ref2, false));
263 	CHK(context.CheckNextMessage(caller2, team2, cookie2, MSG_READY_TO_RUN));
264 	//   messages: app 1
265 	check_watching_message(context, team1, cookie1, appInfo2,
266 						   B_SOME_APP_LAUNCHED);
267 	// launch app 3
268 	entry_ref ref3(create_app(appFile3, appType3));
269 	SimpleAppLauncher caller3(ref3);
270 	team_id team3;
271 	CHK(context(caller3, appType3, &team3) == B_OK);
272 	context.WaitForMessage(team3, MSG_READY_TO_RUN);
273 	BMessenger target3(NULL, team3);
274 	app_info appInfo3(app_info_for_team(team3));
275 	CHK(roster.StartWatching(target3, B_REQUEST_QUIT) == B_OK);
276 	//   messages: app 3
277 	int32 cookie3 = 0;
278 	CHK(context.CheckNextMessage(caller3, team3, cookie3, MSG_STARTED));
279 	CHK(context.CheckMainArgsMessage(caller3, team3, cookie3, &ref3, false));
280 	CHK(context.CheckNextMessage(caller3, team3, cookie3, MSG_READY_TO_RUN));
281 	//   messages: app 2
282 	check_watching_message(context, team2, cookie2, appInfo3,
283 						   B_SOME_APP_LAUNCHED);
284 	//   messages: app 1
285 	check_watching_message(context, team1, cookie1, appInfo3,
286 						   B_SOME_APP_LAUNCHED);
287 	// launch app 4
288 	entry_ref ref4(create_app(appFile4, appType4));
289 	SimpleAppLauncher caller4(ref4);
290 	team_id team4;
291 	CHK(context(caller4, appType4, &team4) == B_OK);
292 	context.WaitForMessage(team4, MSG_READY_TO_RUN);
293 	BMessenger target4(NULL, team4);
294 	app_info appInfo4(app_info_for_team(team4));
295 	//   messages: app 4
296 	int32 cookie4 = 0;
297 	CHK(context.CheckNextMessage(caller4, team4, cookie4, MSG_STARTED));
298 	CHK(context.CheckMainArgsMessage(caller4, team4, cookie4, &ref4, false));
299 	CHK(context.CheckNextMessage(caller4, team4, cookie4, MSG_READY_TO_RUN));
300 	//   messages: app 3
301 	//   none
302 	//   messages: app 2
303 	check_watching_message(context, team2, cookie2, appInfo4,
304 						   B_SOME_APP_LAUNCHED);
305 	//   messages: app 1
306 	check_watching_message(context, team1, cookie1, appInfo4,
307 						   B_SOME_APP_LAUNCHED);
308 	// terminate app 4
309 	context.TerminateApp(team4);
310 	//   messages: app 3
311 	check_watching_message(context, team3, cookie3, appInfo4,
312 						   B_SOME_APP_QUIT);
313 	//   messages: app 2
314 	//   none
315 	//   messages: app 1
316 	check_watching_message(context, team1, cookie1, appInfo4,
317 						   B_SOME_APP_QUIT);
318 	// stop watching app 1
319 	CHK(roster.StopWatching(target1) == B_OK);
320 	// terminate app 2
321 	context.TerminateApp(team2);
322 	CHK(roster.StopWatching(target2) == B_OK);
323 	//   messages: app 3
324 	check_watching_message(context, team3, cookie3, appInfo2,
325 						   B_SOME_APP_QUIT);
326 	//   messages: app 1
327 	//   none
328 	// terminate app 3
329 	context.TerminateApp(team3);
330 // Haiku handles app termination a bit different. At the point, when the
331 // application unregisters itself from the registrar, its port is still
332 // valid.
333 #ifdef TEST_R5
334 	CHK(roster.StopWatching(target3) == B_BAD_VALUE);
335 #else
336 	CHK(roster.StopWatching(target3) == B_OK);
337 #endif
338 	//   messages: app 1
339 	//   none
340 	// remaining messages
341 	context.Terminate();
342 	// app 1
343 	CHK(context.CheckNextMessage(caller1, team1, cookie1, MSG_QUIT_REQUESTED));
344 	CHK(context.CheckNextMessage(caller1, team1, cookie1, MSG_TERMINATED));
345 	// app 2
346 	CHK(context.CheckNextMessage(caller2, team2, cookie2, MSG_QUIT_REQUESTED));
347 	CHK(context.CheckNextMessage(caller2, team2, cookie2, MSG_TERMINATED));
348 	// app 3
349 	CHK(context.CheckNextMessage(caller3, team3, cookie3, MSG_QUIT_REQUESTED));
350 	CHK(context.CheckNextMessage(caller3, team3, cookie3, MSG_TERMINATED));
351 	// app 4
352 	CHK(context.CheckNextMessage(caller4, team4, cookie4, MSG_QUIT_REQUESTED));
353 	CHK(context.CheckNextMessage(caller4, team4, cookie4, MSG_TERMINATED));
354 }
355 
356 /*
357 	status_t StartWatching(BMessenger target, uint32 eventMask) const
358 	status_t StopWatching(BMessenger target) const
359 	@case 3			call StartWatching() twice, second time with different
360 					masks
361 	@results		Should return B_OK. The second call simply overrides the
362 					first one.
363 */
WatchingTest3()364 void RosterWatchingTester::WatchingTest3()
365 {
366 	LaunchContext context;
367 	BRoster roster;
368 	// launch app 1
369 	entry_ref ref1(create_app(appFile1, appType1));
370 	SimpleAppLauncher caller1(ref1);
371 	team_id team1;
372 	CHK(context(caller1, appType1, &team1) == B_OK);
373 	context.WaitForMessage(team1, MSG_READY_TO_RUN);
374 	BMessenger target1(NULL, team1);
375 	app_info appInfo1(app_info_for_team(team1));
376 	CHK(roster.StartWatching(target1, B_REQUEST_LAUNCHED | B_REQUEST_QUIT
377 							 | B_REQUEST_ACTIVATED) == B_OK);
378 	//   messages: app 1
379 	int32 cookie1 = 0;
380 	CHK(context.CheckNextMessage(caller1, team1, cookie1, MSG_STARTED));
381 	CHK(context.CheckMainArgsMessage(caller1, team1, cookie1, &ref1, false));
382 	CHK(context.CheckNextMessage(caller1, team1, cookie1, MSG_READY_TO_RUN));
383 	// app 1: another StartWatching() with different event mask
384 	CHK(roster.StartWatching(target1, B_REQUEST_QUIT) == B_OK);
385 	// launch app 2
386 	entry_ref ref2(create_app(appFile2, appType2, false, true,
387 							  B_SINGLE_LAUNCH | B_ARGV_ONLY));
388 	SimpleAppLauncher caller2(ref2);
389 	team_id team2;
390 	CHK(context(caller2, appType2, &team2) == B_OK);
391 	context.WaitForMessage(team2, MSG_READY_TO_RUN);
392 	BMessenger target2(context.AppMessengerFor(team2));
393 	CHK(target2.IsValid());
394 	app_info appInfo2(app_info_for_team(team2));
395 	CHK(roster.StartWatching(target2, B_REQUEST_QUIT) == B_OK);
396 	//   messages: app 2
397 	int32 cookie2 = 0;
398 	CHK(context.CheckNextMessage(caller2, team2, cookie2, MSG_STARTED));
399 	CHK(context.CheckMainArgsMessage(caller2, team2, cookie2, &ref2, false));
400 	CHK(context.CheckNextMessage(caller2, team2, cookie2, MSG_READY_TO_RUN));
401 	//   messages: app 1
402 	// none
403 	// app 2: another StartWatching() with different event mask
404 	CHK(roster.StartWatching(target2, B_REQUEST_LAUNCHED) == B_OK);
405 	// launch app 3
406 	entry_ref ref3(create_app(appFile3, appType3));
407 	SimpleAppLauncher caller3(ref3);
408 	team_id team3;
409 	CHK(context(caller3, appType3, &team3) == B_OK);
410 	context.WaitForMessage(team3, MSG_READY_TO_RUN);
411 	BMessenger target3(NULL, team3);
412 	app_info appInfo3(app_info_for_team(team3));
413 	//   messages: app 3
414 	int32 cookie3 = 0;
415 	CHK(context.CheckNextMessage(caller3, team3, cookie3, MSG_STARTED));
416 	CHK(context.CheckMainArgsMessage(caller3, team3, cookie3, &ref3, false));
417 	CHK(context.CheckNextMessage(caller3, team3, cookie3, MSG_READY_TO_RUN));
418 	//   messages: app 2
419 	check_watching_message(context, team2, cookie2, appInfo3,
420 						   B_SOME_APP_LAUNCHED);
421 	//   messages: app 1
422 	//   none
423 	// terminate app 3
424 	context.TerminateApp(team3);
425 	//   messages: app 3
426 	//   none
427 	//   messages: app 2
428 	//   none
429 	//   messages: app 1
430 	check_watching_message(context, team1, cookie1, appInfo3,
431 						   B_SOME_APP_QUIT);
432 	// terminate app 2
433 	context.TerminateApp(team2);
434 	CHK(roster.StopWatching(target2) == B_OK);
435 	//   messages: app 1
436 	check_watching_message(context, team1, cookie1, appInfo2,
437 						   B_SOME_APP_QUIT);
438 	// remaining messages
439 	context.Terminate();
440 	// app 1
441 	CHK(context.CheckNextMessage(caller1, team1, cookie1, MSG_QUIT_REQUESTED));
442 	CHK(context.CheckNextMessage(caller1, team1, cookie1, MSG_TERMINATED));
443 	// app 2
444 	CHK(context.CheckNextMessage(caller2, team2, cookie2, MSG_QUIT_REQUESTED));
445 	CHK(context.CheckNextMessage(caller2, team2, cookie2, MSG_TERMINATED));
446 	// app 3
447 	CHK(context.CheckNextMessage(caller3, team3, cookie3, MSG_QUIT_REQUESTED));
448 	CHK(context.CheckNextMessage(caller3, team3, cookie3, MSG_TERMINATED));
449 }
450 
451 
Suite()452 Test* RosterWatchingTester::Suite()
453 {
454 	TestSuite* SuiteOfTests = new TestSuite;
455 
456 	ADD_TEST4(BRoster, SuiteOfTests, RosterWatchingTester, WatchingTest1);
457 	ADD_TEST4(BRoster, SuiteOfTests, RosterWatchingTester, WatchingTest2);
458 	ADD_TEST4(BRoster, SuiteOfTests, RosterWatchingTester, WatchingTest3);
459 
460 	return SuiteOfTests;
461 }
462 
463