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