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 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 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 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 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 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 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: 176 SimpleAppLauncher() : fRef() {} 177 SimpleAppLauncher(const entry_ref &ref) : fRef(ref) {} 178 virtual ~SimpleAppLauncher() {} 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 } 184 virtual bool SupportsRefs() const { return true; } 185 virtual const entry_ref *Ref() const { return &fRef; } 186 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 */ 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 */ 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 */ 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 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