1 // VolumeTest.cpp 2 3 #include <stdio.h> 4 #include <string> 5 #include <unistd.h> 6 7 #include <Application.h> 8 #include <Bitmap.h> 9 #include <Directory.h> 10 #include <Entry.h> 11 #include <File.h> 12 #include <fs_attr.h> 13 #include <fs_info.h> 14 #include <Node.h> 15 #include <NodeMonitor.h> 16 #include <Path.h> 17 #include <Resources.h> 18 #include <Roster.h> 19 #include <String.h> 20 #include <TypeConstants.h> 21 #include <Volume.h> 22 #include <VolumeRoster.h> 23 24 #include <cppunit/Test.h> 25 #include <cppunit/TestCaller.h> 26 #include <cppunit/TestSuite.h> 27 #include <TestApp.h> 28 #include <TestShell.h> 29 #include <TestUtils.h> 30 #include <cppunit/TestAssert.h> 31 32 #include "VolumeTest.h" 33 #include "../app/bmessenger/Helpers.h" 34 35 // test dirs/files/types 36 static const char *testDir = "/tmp/testDir"; 37 static const char *testFile1 = "/tmp/testDir/file1"; 38 static const char *testMountPoint = "/tmp/testDir/mount_point"; 39 40 // icon_equal 41 static 42 bool 43 icon_equal(const BBitmap *icon1, const BBitmap *icon2) 44 { 45 return (icon1->Bounds() == icon2->Bounds() 46 && icon1->BitsLength() == icon2->BitsLength() 47 && memcmp(icon1->Bits(), icon2->Bits(), icon1->BitsLength()) == 0); 48 } 49 50 // Suite 51 CppUnit::Test* 52 VolumeTest::Suite() { 53 CppUnit::TestSuite *suite = new CppUnit::TestSuite(); 54 typedef CppUnit::TestCaller<VolumeTest> TC; 55 56 suite->addTest( new TC("BVolume::Init Test1", 57 &VolumeTest::InitTest1) ); 58 suite->addTest( new TC("BVolume::Init Test2", 59 &VolumeTest::InitTest2) ); 60 suite->addTest( new TC("BVolume::Assignment Test", 61 &VolumeTest::AssignmentTest) ); 62 suite->addTest( new TC("BVolume::Comparisson Test", 63 &VolumeTest::ComparissonTest) ); 64 suite->addTest( new TC("BVolume::SetName Test", 65 &VolumeTest::SetNameTest) ); 66 suite->addTest( new TC("BVolume::BadValues Test", 67 &VolumeTest::BadValuesTest) ); 68 suite->addTest( new TC("BVolumeRoster::Iteration Test", 69 &VolumeTest::IterationTest) ); 70 suite->addTest( new TC("BVolumeRoster::Watching Test", 71 &VolumeTest::WatchingTest) ); 72 73 return suite; 74 } 75 76 // setUp 77 void 78 VolumeTest::setUp() 79 { 80 BasicTest::setUp(); 81 // create test dir and files 82 execCommand( 83 string("mkdir ") + testDir 84 ); 85 // create and mount image 86 createVolume(testFile1, testMountPoint, 1); 87 // create app 88 fApplication = new BTestApp("application/x-vnd.obos.volume-test"); 89 if (fApplication->Init() != B_OK) { 90 fprintf(stderr, "Failed to initialize application.\n"); 91 delete fApplication; 92 fApplication = NULL; 93 } 94 } 95 96 // tearDown 97 void 98 VolumeTest::tearDown() 99 { 100 // delete the application 101 if (fApplication) { 102 fApplication->Terminate(); 103 delete fApplication; 104 fApplication = NULL; 105 } 106 // unmount and delete image 107 deleteVolume(testFile1, testMountPoint); 108 // delete the test dir 109 execCommand(string("rm -rf ") + testDir); 110 111 BasicTest::tearDown(); 112 } 113 114 // CheckVolume 115 static 116 void 117 CheckVolume(BVolume &volume, dev_t device, status_t error) 118 { 119 CHK(volume.InitCheck() == error); 120 if (error == B_OK) { 121 fs_info info; 122 CHK(fs_stat_dev(device, &info) == 0); 123 // device 124 CHK(volume.Device() == device); 125 // root dir 126 BDirectory rootDir; 127 CHK(volume.GetRootDirectory(&rootDir) == B_OK); 128 node_ref rootNode; 129 rootNode.device = device; 130 rootNode.node = info.root; 131 BDirectory actualRootDir(&rootNode); 132 CHK(rootDir == actualRootDir); 133 // capacity, free bytes 134 CHK(volume.Capacity() == info.total_blocks * info.block_size); 135 CHK(volume.FreeBytes() == info.free_blocks * info.block_size); 136 // name 137 char name[B_FILE_NAME_LENGTH]; 138 CHK(volume.GetName(name) == B_OK); 139 CHK(BString(name) == info.volume_name); 140 // icons 141 // mini 142 BBitmap miniIcon(BRect(0, 0, 15, 15), B_CMAP8); 143 BBitmap miniIcon2(BRect(0, 0, 15, 15), B_CMAP8); 144 status_t iconError = get_device_icon(info.device_name, 145 miniIcon2.Bits(), B_MINI_ICON); 146 CHK(volume.GetIcon(&miniIcon, B_MINI_ICON) == iconError); 147 if (iconError == B_OK) 148 CHK(icon_equal(&miniIcon, &miniIcon2)); 149 // large 150 BBitmap largeIcon(BRect(0, 0, 31, 31), B_CMAP8); 151 BBitmap largeIcon2(BRect(0, 0, 31, 31), B_CMAP8); 152 iconError = get_device_icon(info.device_name, largeIcon2.Bits(), 153 B_LARGE_ICON); 154 CHK(volume.GetIcon(&largeIcon, B_LARGE_ICON) == iconError); 155 if (iconError == B_OK) 156 CHK(icon_equal(&largeIcon, &largeIcon2)); 157 // flags 158 CHK(volume.IsRemovable() == bool(info.flags & B_FS_IS_REMOVABLE)); 159 CHK(volume.IsReadOnly() == bool(info.flags & B_FS_IS_READONLY)); 160 CHK(volume.IsPersistent() == bool(info.flags & B_FS_IS_PERSISTENT)); 161 CHK(volume.IsShared() == bool(info.flags & B_FS_IS_SHARED)); 162 CHK(volume.KnowsMime() == bool(info.flags & B_FS_HAS_MIME)); 163 CHK(volume.KnowsAttr() == bool(info.flags & B_FS_HAS_ATTR)); 164 CHK(volume.KnowsQuery() == bool(info.flags & B_FS_HAS_QUERY)); 165 } else { 166 CHK(volume.Device() == -1); 167 // root dir 168 BDirectory rootDir; 169 CHK(volume.GetRootDirectory(&rootDir) == B_BAD_VALUE); 170 // capacity, free bytes 171 CHK(volume.Capacity() == B_BAD_VALUE); 172 CHK(volume.FreeBytes() == B_BAD_VALUE); 173 // name 174 char name[B_FILE_NAME_LENGTH]; 175 CHK(volume.GetName(name) == B_BAD_VALUE); 176 // icons 177 // mini 178 BBitmap miniIcon(BRect(0, 0, 15, 15), B_CMAP8); 179 CHK(volume.GetIcon(&miniIcon, B_MINI_ICON) == B_BAD_VALUE); 180 // large 181 BBitmap largeIcon(BRect(0, 0, 31, 31), B_CMAP8); 182 CHK(volume.GetIcon(&largeIcon, B_LARGE_ICON) == B_BAD_VALUE); 183 // flags 184 CHK(volume.IsRemovable() == false); 185 CHK(volume.IsReadOnly() == false); 186 CHK(volume.IsPersistent() == false); 187 CHK(volume.IsShared() == false); 188 CHK(volume.KnowsMime() == false); 189 CHK(volume.KnowsAttr() == false); 190 CHK(volume.KnowsQuery() == false); 191 } 192 } 193 194 // AssertNotBootVolume 195 static 196 void 197 AssertNotBootVolume(const BVolume &volume) 198 { 199 CHK(volume.InitCheck() == B_OK); 200 dev_t bootDevice = dev_for_path("/boot"); 201 CHK(bootDevice >= 0); 202 CHK(volume.Device() != bootDevice); 203 } 204 205 // InitTest1 206 void 207 VolumeTest::InitTest1() 208 { 209 // 1. BVolume(void) 210 { 211 BVolume volume; 212 CheckVolume(volume, -1, B_NO_INIT); 213 } 214 // 2. BVolume(dev_t dev) 215 // volumes for testing 216 const char *volumes[] = { 217 "/boot", 218 "/", 219 "/dev", 220 "/pipe", 221 "/unknown", 222 testMountPoint 223 }; 224 int32 volumeCount = sizeof(volumes) / sizeof(const char*); 225 for (int32 i = 0; i < volumeCount; i++) { 226 NextSubTest(); 227 const char *volumeRootDir = volumes[i]; 228 dev_t device = dev_for_path(volumeRootDir); 229 BVolume volume(device); 230 CheckVolume(volume, device, (device >= 0 ? B_OK : B_BAD_VALUE)); 231 } 232 // invalid device ID 233 NextSubTest(); 234 { 235 BVolume volume(-2); 236 CHK(volume.InitCheck() == B_BAD_VALUE); 237 } 238 // invalid device ID 239 NextSubTest(); 240 { 241 dev_t device = 213; 242 fs_info info; 243 while (fs_stat_dev(device, &info) == 0) 244 device++; 245 BVolume volume(device); 246 CHK(volume.InitCheck() == B_ENTRY_NOT_FOUND); 247 } 248 } 249 250 // InitTest2 251 void 252 VolumeTest::InitTest2() 253 { 254 // volumes for testing 255 const char *volumes[] = { 256 "/boot", 257 "/", 258 "/dev", 259 "/pipe", 260 "/unknown", 261 testMountPoint 262 }; 263 int32 volumeCount = sizeof(volumes) / sizeof(const char*); 264 BVolume volume1; 265 for (int32 i = 0; i < volumeCount; i++) { 266 NextSubTest(); 267 const char *volumeRootDir = volumes[i]; 268 dev_t device = dev_for_path(volumeRootDir); 269 status_t initError = (device >= 0 ? B_OK : B_BAD_VALUE); 270 // reinit already initialized volume 271 CHK(volume1.SetTo(device) == initError); 272 CheckVolume(volume1, device, initError); 273 // init fresh volume 274 BVolume volume2; 275 CHK(volume2.SetTo(device) == initError); 276 CheckVolume(volume2, device, initError); 277 // uninit volume 278 volume2.Unset(); 279 CheckVolume(volume2, device, B_NO_INIT); 280 } 281 // invalid device ID 282 NextSubTest(); 283 { 284 BVolume volume; 285 CHK(volume.SetTo(-2) == B_BAD_VALUE); 286 CHK(volume.InitCheck() == B_BAD_VALUE); 287 } 288 // invalid device ID 289 NextSubTest(); 290 { 291 dev_t device = 213; 292 fs_info info; 293 while (fs_stat_dev(device, &info) == 0) 294 device++; 295 BVolume volume; 296 CHK(volume.SetTo(device) == B_ENTRY_NOT_FOUND); 297 CHK(volume.InitCheck() == B_ENTRY_NOT_FOUND); 298 } 299 } 300 301 // AssignmentTest 302 void 303 VolumeTest::AssignmentTest() 304 { 305 // volumes for testing 306 const char *volumes[] = { 307 "/boot", 308 "/", 309 "/dev", 310 "/pipe", 311 "/unknown", 312 testMountPoint 313 }; 314 int32 volumeCount = sizeof(volumes) / sizeof(const char*); 315 BVolume volume1; 316 for (int32 i = 0; i < volumeCount; i++) { 317 NextSubTest(); 318 const char *volumeRootDir = volumes[i]; 319 dev_t device = dev_for_path(volumeRootDir); 320 status_t initError = (device >= 0 ? B_OK : B_BAD_VALUE); 321 BVolume volume3(device); 322 CheckVolume(volume3, device, initError); 323 // assignment operation 324 CHK(&(volume1 = volume3) == &volume1); 325 CheckVolume(volume1, device, initError); 326 // copy constructor 327 BVolume volume2(volume3); 328 CheckVolume(volume2, device, initError); 329 } 330 } 331 332 // ComparissonTest 333 void 334 VolumeTest::ComparissonTest() 335 { 336 // volumes for testing 337 const char *volumes[] = { 338 "/boot", 339 "/", 340 "/dev", 341 "/pipe", 342 "/unknown", 343 testMountPoint 344 }; 345 int32 volumeCount = sizeof(volumes) / sizeof(const char*); 346 for (int32 i = 0; i < volumeCount; i++) { 347 NextSubTest(); 348 const char *volumeRootDir = volumes[i]; 349 dev_t device = dev_for_path(volumeRootDir); 350 status_t initError = (device >= 0 ? B_OK : B_BAD_VALUE); 351 BVolume volume(device); 352 CheckVolume(volume, device, initError); 353 for (int32 k = 0; k < volumeCount; k++) { 354 const char *volumeRootDir2 = volumes[k]; 355 dev_t device2 = dev_for_path(volumeRootDir2); 356 status_t initError2 = (device2 >= 0 ? B_OK : B_BAD_VALUE); 357 BVolume volume2(device2); 358 CheckVolume(volume2, device2, initError2); 359 bool equal = (i == k 360 || initError == initError2 && initError2 != B_OK); 361 CHK((volume == volume2) == equal); 362 CHK((volume != volume2) == !equal); 363 } 364 } 365 } 366 367 // SetNameTest 368 void 369 VolumeTest::SetNameTest() 370 { 371 // status_t SetName(const char* name); 372 dev_t device = dev_for_path(testMountPoint); 373 BVolume volume(device); 374 CheckVolume(volume, device, B_OK); 375 AssertNotBootVolume(volume); 376 // set a new name 377 NextSubTest(); 378 const char *newName = "a new name"; 379 CHK(volume.SetName(newName) == B_OK); 380 char name[B_FILE_NAME_LENGTH]; 381 CHK(volume.GetName(name) == B_OK); 382 CHK(string(newName) == name); 383 CheckVolume(volume, device, B_OK); 384 // set another name 385 NextSubTest(); 386 const char *newName2 = "another name"; 387 CHK(volume.SetName(newName2) == B_OK); 388 CHK(volume.GetName(name) == B_OK); 389 CHK(string(newName2) == name); 390 CheckVolume(volume, device, B_OK); 391 // GetName() with NULL buffer 392 // R5: crashes when passing a NULL pointer 393 #ifndef TEST_R5 394 NextSubTest(); 395 CHK(volume.GetName(NULL) == B_BAD_VALUE); 396 #endif 397 // bad name 398 // R5: crashes when passing a NULL pointer 399 #ifndef TEST_R5 400 NextSubTest(); 401 CHK(volume.SetName(NULL) == B_BAD_VALUE); 402 #endif 403 // uninitialized volume 404 NextSubTest(); 405 volume.Unset(); 406 CHK(volume.SetName(newName) == B_BAD_VALUE); 407 } 408 409 // BadValuesTest 410 void 411 VolumeTest::BadValuesTest() 412 { 413 BVolume volume(dev_for_path("/boot")); 414 CHK(volume.InitCheck() == B_OK); 415 // NULL arguments 416 // R5: crashes, when passing a NULL BDirectory. 417 #ifndef TEST_R5 418 NextSubTest(); 419 CHK(volume.GetRootDirectory(NULL) == B_BAD_VALUE); 420 #endif 421 NextSubTest(); 422 CHK(volume.GetIcon(NULL, B_MINI_ICON) == B_BAD_VALUE); 423 CHK(volume.GetIcon(NULL, B_LARGE_ICON) == B_BAD_VALUE); 424 // incompatible icon formats 425 // R5: returns B_OK 426 #ifndef TEST_R5 427 NextSubTest(); 428 // mini 429 BBitmap largeIcon(BRect(0, 0, 31, 31), B_CMAP8); 430 CHK(volume.GetIcon(&largeIcon, B_MINI_ICON) == B_BAD_VALUE); 431 // large 432 BBitmap miniIcon(BRect(0, 0, 15, 15), B_CMAP8); 433 CHK(volume.GetIcon(&miniIcon, B_LARGE_ICON) == B_BAD_VALUE); 434 #endif 435 } 436 437 438 // BVolumeRoster tests 439 440 // GetAllDevices 441 static 442 void 443 GetAllDevices(set<dev_t> &devices) 444 { 445 //printf("GetAllDevices()\n"); 446 int32 cookie = 0; 447 dev_t device; 448 while ((device = next_dev(&cookie)) >= 0) 449 { 450 //printf(" device: %ld\n", device); 451 //BVolume dVolume(device); 452 //char name[B_FILE_NAME_LENGTH]; 453 //dVolume.GetName(name); 454 //BDirectory rootDir; 455 //dVolume.GetRootDirectory(&rootDir); 456 //BEntry rootEntry; 457 //rootDir.GetEntry(&rootEntry); 458 //BPath rootPath; 459 //rootEntry.GetPath(&rootPath); 460 //printf(" name: `%s', root: `%s'\n", name, rootPath.Path()); 461 devices.insert(device); 462 } 463 //printf("GetAllDevices() done\n"); 464 } 465 466 // IterationTest 467 void 468 VolumeTest::IterationTest() 469 { 470 // status_t GetBootVolume(BVolume *volume) 471 NextSubTest(); 472 BVolumeRoster roster; 473 BVolume volume; 474 CHK(roster.GetBootVolume(&volume) == B_OK); 475 dev_t device = dev_for_path("/boot"); 476 CHK(device >= 0); 477 CheckVolume(volume, device, B_OK); 478 479 // status_t GetNextVolume(BVolume *volume) 480 // void Rewind() 481 set<dev_t> allDevices; 482 GetAllDevices(allDevices); 483 int32 allDevicesCount = allDevices.size(); 484 for (int32 i = 0; i <= allDevicesCount; i++) { 485 NextSubTest(); 486 // iterate through the first i devices 487 set<dev_t> devices(allDevices); 488 volume.Unset(); 489 int32 checkCount = i; 490 while (--checkCount >= 0 && roster.GetNextVolume(&volume) == B_OK) { 491 device = volume.Device(); 492 CHK(device >= 0); 493 CheckVolume(volume, device, B_OK); 494 CHK(devices.find(device) != devices.end()); 495 devices.erase(device); 496 } 497 // rewind and iterate through all devices 498 devices = allDevices; 499 roster.Rewind(); 500 volume.Unset(); 501 status_t error; 502 while ((error = roster.GetNextVolume(&volume)) == B_OK) { 503 device = volume.Device(); 504 CHK(device >= 0); 505 CheckVolume(volume, device, B_OK); 506 CHK(devices.find(device) != devices.end()); 507 devices.erase(device); 508 } 509 CHK(error == B_BAD_VALUE); 510 CHK(devices.empty()); 511 roster.Rewind(); 512 } 513 514 // bad argument 515 // R5: crashes when passing a NULL BVolume 516 #ifndef TEST_R5 517 NextSubTest(); 518 CHK(roster.GetNextVolume(NULL) == B_BAD_VALUE); 519 #endif 520 } 521 522 // CheckWatchingMessage 523 static 524 void 525 CheckWatchingMessage(bool mounted, dev_t expectedDevice, BTestHandler &handler, 526 node_ref nodeRef = node_ref()) 527 { 528 snooze(100000); 529 // get the message 530 BMessageQueue &queue = handler.Queue(); 531 BMessage *_message = queue.NextMessage(); 532 CHK(_message); 533 BMessage message(*_message); 534 delete _message; 535 // check the message 536 if (mounted) { 537 // volume mounted 538 int32 opcode; 539 dev_t device; 540 dev_t parentDevice; 541 ino_t directory; 542 CHK(message.FindInt32("opcode", &opcode) == B_OK); 543 CHK(message.FindInt32("new device", &device) == B_OK); 544 CHK(message.FindInt32("device", &parentDevice) == B_OK); 545 CHK(message.FindInt64("directory", &directory) == B_OK); 546 CHK(opcode == B_DEVICE_MOUNTED); 547 CHK(device == expectedDevice); 548 CHK(parentDevice == nodeRef.device); 549 CHK(directory == nodeRef.node); 550 } else { 551 // volume unmounted 552 int32 opcode; 553 dev_t device; 554 CHK(message.FindInt32("opcode", &opcode) == B_OK); 555 CHK(message.FindInt32("device", &device) == B_OK); 556 CHK(opcode == B_DEVICE_UNMOUNTED); 557 CHK(device == expectedDevice); 558 } 559 } 560 561 // WatchingTest 562 void 563 VolumeTest::WatchingTest() 564 { 565 // status_t StartWatching(BMessenger msngr=be_app_messenger); 566 // void StopWatching(void); 567 // BMessenger Messenger(void) const; 568 569 // start watching 570 NextSubTest(); 571 BVolumeRoster roster; 572 CHK(!roster.Messenger().IsValid()); 573 BMessenger target(&fApplication->Handler()); 574 CHK(roster.StartWatching(target) == B_OK); 575 CHK(roster.Messenger() == target); 576 dev_t device = dev_for_path(testMountPoint); 577 CHK(device >= 0); 578 // unmount volume 579 NextSubTest(); 580 deleteVolume(testFile1, testMountPoint, false); 581 CHK(roster.Messenger() == target); 582 CheckWatchingMessage(false, device, fApplication->Handler()); 583 // get the node_ref of the mount point 584 node_ref nodeRef; 585 CHK(BDirectory(testMountPoint).GetNodeRef(&nodeRef) == B_OK); 586 // mount volume 587 NextSubTest(); 588 createVolume(testFile1, testMountPoint, 1, false); 589 CHK(roster.Messenger() == target); 590 device = dev_for_path(testMountPoint); 591 CHK(device >= 0); 592 CheckWatchingMessage(true, device, fApplication->Handler(), nodeRef); 593 // start watching with another target 594 BTestHandler *handler2 = fApplication->CreateTestHandler(); 595 BMessenger target2(handler2); 596 CHK(roster.StartWatching(target2) == B_OK); 597 CHK(roster.Messenger() == target2); 598 // unmount volume 599 NextSubTest(); 600 deleteVolume(testFile1, testMountPoint, false); 601 CHK(roster.Messenger() == target2); 602 CheckWatchingMessage(false, device, *handler2); 603 // mount volume 604 NextSubTest(); 605 createVolume(testFile1, testMountPoint, 1, false); 606 CHK(roster.Messenger() == target2); 607 device = dev_for_path(testMountPoint); 608 CHK(device >= 0); 609 CheckWatchingMessage(true, device, *handler2, nodeRef); 610 // stop watching 611 NextSubTest(); 612 roster.StopWatching(); 613 CHK(!roster.Messenger().IsValid()); 614 // unmount, mount volume 615 NextSubTest(); 616 deleteVolume(testFile1, testMountPoint, false); 617 createVolume(testFile1, testMountPoint, 1, false); 618 snooze(100000); 619 CHK(fApplication->Handler().Queue().IsEmpty()); 620 CHK(handler2->Queue().IsEmpty()); 621 622 // try start watching with a bad messenger 623 NextSubTest(); 624 CHK(roster.StartWatching(BMessenger()) == B_ERROR); 625 } 626 627