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