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