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 // InitTest1 195 void 196 VolumeTest::InitTest1() 197 { 198 // 1. BVolume(void) 199 { 200 BVolume volume; 201 CheckVolume(volume, -1, B_NO_INIT); 202 } 203 // 2. BVolume(dev_t dev) 204 // volumes for testing 205 const char *volumes[] = { 206 "/boot", 207 "/", 208 "/dev", 209 "/pipe", 210 "/unknown", 211 testMountPoint 212 }; 213 int32 volumeCount = sizeof(volumes) / sizeof(const char*); 214 for (int32 i = 0; i < volumeCount; i++) { 215 NextSubTest(); 216 const char *volumeRootDir = volumes[i]; 217 dev_t device = dev_for_path(volumeRootDir); 218 BVolume volume(device); 219 CheckVolume(volume, device, (device >= 0 ? B_OK : B_BAD_VALUE)); 220 } 221 // invalid device ID 222 NextSubTest(); 223 { 224 BVolume volume(-2); 225 CHK(volume.InitCheck() == B_BAD_VALUE); 226 } 227 // invalid device ID 228 NextSubTest(); 229 { 230 dev_t device = 213; 231 fs_info info; 232 while (fs_stat_dev(device, &info) == 0) 233 device++; 234 BVolume volume(device); 235 CHK(volume.InitCheck() == B_ENTRY_NOT_FOUND); 236 } 237 } 238 239 // InitTest2 240 void 241 VolumeTest::InitTest2() 242 { 243 // volumes for testing 244 const char *volumes[] = { 245 "/boot", 246 "/", 247 "/dev", 248 "/pipe", 249 "/unknown", 250 testMountPoint 251 }; 252 int32 volumeCount = sizeof(volumes) / sizeof(const char*); 253 BVolume volume1; 254 for (int32 i = 0; i < volumeCount; i++) { 255 NextSubTest(); 256 const char *volumeRootDir = volumes[i]; 257 dev_t device = dev_for_path(volumeRootDir); 258 status_t initError = (device >= 0 ? B_OK : B_BAD_VALUE); 259 // reinit already initialized volume 260 CHK(volume1.SetTo(device) == initError); 261 CheckVolume(volume1, device, initError); 262 // init fresh volume 263 BVolume volume2; 264 CHK(volume2.SetTo(device) == initError); 265 CheckVolume(volume2, device, initError); 266 // uninit volume 267 volume2.Unset(); 268 CheckVolume(volume2, device, B_NO_INIT); 269 } 270 // invalid device ID 271 NextSubTest(); 272 { 273 BVolume volume; 274 CHK(volume.SetTo(-2) == B_BAD_VALUE); 275 CHK(volume.InitCheck() == B_BAD_VALUE); 276 } 277 // invalid device ID 278 NextSubTest(); 279 { 280 dev_t device = 213; 281 fs_info info; 282 while (fs_stat_dev(device, &info) == 0) 283 device++; 284 BVolume volume; 285 CHK(volume.SetTo(device) == B_ENTRY_NOT_FOUND); 286 CHK(volume.InitCheck() == B_ENTRY_NOT_FOUND); 287 } 288 } 289 290 // AssignmentTest 291 void 292 VolumeTest::AssignmentTest() 293 { 294 // volumes for testing 295 const char *volumes[] = { 296 "/boot", 297 "/", 298 "/dev", 299 "/pipe", 300 "/unknown", 301 testMountPoint 302 }; 303 int32 volumeCount = sizeof(volumes) / sizeof(const char*); 304 BVolume volume1; 305 for (int32 i = 0; i < volumeCount; i++) { 306 NextSubTest(); 307 const char *volumeRootDir = volumes[i]; 308 dev_t device = dev_for_path(volumeRootDir); 309 status_t initError = (device >= 0 ? B_OK : B_BAD_VALUE); 310 BVolume volume3(device); 311 CheckVolume(volume3, device, initError); 312 // assignment operation 313 CHK(&(volume1 = volume3) == &volume1); 314 CheckVolume(volume1, device, initError); 315 // copy constructor 316 BVolume volume2(volume3); 317 CheckVolume(volume2, device, initError); 318 } 319 } 320 321 // ComparissonTest 322 void 323 VolumeTest::ComparissonTest() 324 { 325 // volumes for testing 326 const char *volumes[] = { 327 "/boot", 328 "/", 329 "/dev", 330 "/pipe", 331 "/unknown", 332 testMountPoint 333 }; 334 int32 volumeCount = sizeof(volumes) / sizeof(const char*); 335 for (int32 i = 0; i < volumeCount; i++) { 336 NextSubTest(); 337 const char *volumeRootDir = volumes[i]; 338 dev_t device = dev_for_path(volumeRootDir); 339 status_t initError = (device >= 0 ? B_OK : B_BAD_VALUE); 340 BVolume volume(device); 341 CheckVolume(volume, device, initError); 342 for (int32 k = 0; k < volumeCount; k++) { 343 const char *volumeRootDir2 = volumes[k]; 344 dev_t device2 = dev_for_path(volumeRootDir2); 345 status_t initError2 = (device2 >= 0 ? B_OK : B_BAD_VALUE); 346 BVolume volume2(device2); 347 CheckVolume(volume2, device2, initError2); 348 bool equal = (i == k 349 || initError == initError2 && initError2 != B_OK); 350 CHK((volume == volume2) == equal); 351 CHK((volume != volume2) == !equal); 352 } 353 } 354 } 355 356 // SetNameTest 357 void 358 VolumeTest::SetNameTest() 359 { 360 // status_t SetName(const char* name); 361 dev_t device = dev_for_path(testMountPoint); 362 BVolume volume(device); 363 CheckVolume(volume, device, B_OK); 364 // set a new name 365 NextSubTest(); 366 const char *newName = "a new name"; 367 CHK(volume.SetName(newName) == B_OK); 368 char name[B_FILE_NAME_LENGTH]; 369 CHK(volume.GetName(name) == B_OK); 370 CHK(string(newName) == name); 371 CheckVolume(volume, device, B_OK); 372 // set another name 373 NextSubTest(); 374 const char *newName2 = "another name"; 375 CHK(volume.SetName(newName2) == B_OK); 376 CHK(volume.GetName(name) == B_OK); 377 CHK(string(newName2) == name); 378 CheckVolume(volume, device, B_OK); 379 // GetName() with NULL buffer 380 // R5: crashes when passing a NULL pointer 381 #ifndef TEST_R5 382 NextSubTest(); 383 CHK(volume.GetName(NULL) == B_BAD_VALUE); 384 #endif 385 // bad name 386 // R5: crashes when passing a NULL pointer 387 #ifndef TEST_R5 388 NextSubTest(); 389 CHK(volume.SetName(NULL) == B_BAD_VALUE); 390 #endif 391 // uninitialized volume 392 NextSubTest(); 393 volume.Unset(); 394 CHK(volume.SetName(newName) == B_BAD_VALUE); 395 } 396 397 // BadValuesTest 398 void 399 VolumeTest::BadValuesTest() 400 { 401 BVolume volume(dev_for_path("/boot")); 402 CHK(volume.InitCheck() == B_OK); 403 // NULL arguments 404 // R5: crashes, when passing a NULL BDirectory. 405 #ifndef TEST_R5 406 NextSubTest(); 407 CHK(volume.GetRootDirectory(NULL) == B_BAD_VALUE); 408 #endif 409 NextSubTest(); 410 CHK(volume.GetIcon(NULL, B_MINI_ICON) == B_BAD_VALUE); 411 CHK(volume.GetIcon(NULL, B_LARGE_ICON) == B_BAD_VALUE); 412 // incompatible icon formats 413 // R5: returns B_OK 414 #ifndef TEST_R5 415 NextSubTest(); 416 // mini 417 BBitmap largeIcon(BRect(0, 0, 31, 31), B_CMAP8); 418 CHK(volume.GetIcon(&largeIcon, B_MINI_ICON) == B_BAD_VALUE); 419 // large 420 BBitmap miniIcon(BRect(0, 0, 15, 15), B_CMAP8); 421 CHK(volume.GetIcon(&miniIcon, B_LARGE_ICON) == B_BAD_VALUE); 422 #endif 423 } 424 425 426 // BVolumeRoster tests 427 428 // GetAllDevices 429 static 430 void 431 GetAllDevices(set<dev_t> &devices) 432 { 433 //printf("GetAllDevices()\n"); 434 int32 cookie = 0; 435 dev_t device; 436 while ((device = next_dev(&cookie)) >= 0) 437 { 438 //printf(" device: %ld\n", device); 439 //BVolume dVolume(device); 440 //char name[B_FILE_NAME_LENGTH]; 441 //dVolume.GetName(name); 442 //BDirectory rootDir; 443 //dVolume.GetRootDirectory(&rootDir); 444 //BEntry rootEntry; 445 //rootDir.GetEntry(&rootEntry); 446 //BPath rootPath; 447 //rootEntry.GetPath(&rootPath); 448 //printf(" name: `%s', root: `%s'\n", name, rootPath.Path()); 449 devices.insert(device); 450 } 451 //printf("GetAllDevices() done\n"); 452 } 453 454 // IterationTest 455 void 456 VolumeTest::IterationTest() 457 { 458 // status_t GetBootVolume(BVolume *volume) 459 NextSubTest(); 460 BVolumeRoster roster; 461 BVolume volume; 462 CHK(roster.GetBootVolume(&volume) == B_OK); 463 dev_t device = dev_for_path("/boot"); 464 CHK(device >= 0); 465 CheckVolume(volume, device, B_OK); 466 467 // status_t GetNextVolume(BVolume *volume) 468 // void Rewind() 469 set<dev_t> allDevices; 470 GetAllDevices(allDevices); 471 int32 allDevicesCount = allDevices.size(); 472 for (int32 i = 0; i <= allDevicesCount; i++) { 473 NextSubTest(); 474 // iterate through the first i devices 475 set<dev_t> devices(allDevices); 476 volume.Unset(); 477 int32 checkCount = i; 478 while (--checkCount >= 0 && roster.GetNextVolume(&volume) == B_OK) { 479 device = volume.Device(); 480 CHK(device >= 0); 481 CheckVolume(volume, device, B_OK); 482 CHK(devices.find(device) != devices.end()); 483 devices.erase(device); 484 } 485 // rewind and iterate through all devices 486 devices = allDevices; 487 roster.Rewind(); 488 volume.Unset(); 489 status_t error; 490 while ((error = 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 CHK(error == B_BAD_VALUE); 498 CHK(devices.empty()); 499 roster.Rewind(); 500 } 501 502 // bad argument 503 // R5: crashes when passing a NULL BVolume 504 #ifndef TEST_R5 505 NextSubTest(); 506 CHK(roster.GetNextVolume(NULL) == B_BAD_VALUE); 507 #endif 508 } 509 510 // CheckWatchingMessage 511 static 512 void 513 CheckWatchingMessage(bool mounted, dev_t expectedDevice, BTestHandler &handler, 514 node_ref nodeRef = node_ref()) 515 { 516 snooze(100000); 517 // get the message 518 BMessageQueue &queue = handler.Queue(); 519 BMessage *_message = queue.NextMessage(); 520 CHK(_message); 521 BMessage message(*_message); 522 delete _message; 523 // check the message 524 if (mounted) { 525 // volume mounted 526 int32 opcode; 527 dev_t device; 528 dev_t parentDevice; 529 ino_t directory; 530 CHK(message.FindInt32("opcode", &opcode) == B_OK); 531 CHK(message.FindInt32("new device", &device) == B_OK); 532 CHK(message.FindInt32("device", &parentDevice) == B_OK); 533 CHK(message.FindInt64("directory", &directory) == B_OK); 534 CHK(opcode == B_DEVICE_MOUNTED); 535 CHK(device == expectedDevice); 536 CHK(parentDevice == nodeRef.device); 537 CHK(directory == nodeRef.node); 538 } else { 539 // volume unmounted 540 int32 opcode; 541 dev_t device; 542 CHK(message.FindInt32("opcode", &opcode) == B_OK); 543 CHK(message.FindInt32("device", &device) == B_OK); 544 CHK(opcode == B_DEVICE_UNMOUNTED); 545 CHK(device == expectedDevice); 546 } 547 } 548 549 // WatchingTest 550 void 551 VolumeTest::WatchingTest() 552 { 553 // status_t StartWatching(BMessenger msngr=be_app_messenger); 554 // void StopWatching(void); 555 // BMessenger Messenger(void) const; 556 557 // start watching 558 NextSubTest(); 559 BVolumeRoster roster; 560 CHK(!roster.Messenger().IsValid()); 561 BMessenger target(&fApplication->Handler()); 562 CHK(roster.StartWatching(target) == B_OK); 563 CHK(roster.Messenger() == target); 564 dev_t device = dev_for_path(testMountPoint); 565 CHK(device >= 0); 566 // unmount volume 567 NextSubTest(); 568 deleteVolume(testFile1, testMountPoint, false); 569 CHK(roster.Messenger() == target); 570 CheckWatchingMessage(false, device, fApplication->Handler()); 571 // get the node_ref of the mount point 572 node_ref nodeRef; 573 CHK(BDirectory(testMountPoint).GetNodeRef(&nodeRef) == B_OK); 574 // mount volume 575 NextSubTest(); 576 createVolume(testFile1, testMountPoint, 1, false); 577 CHK(roster.Messenger() == target); 578 device = dev_for_path(testMountPoint); 579 CHK(device >= 0); 580 CheckWatchingMessage(true, device, fApplication->Handler(), nodeRef); 581 // start watching with another target 582 BTestHandler *handler2 = fApplication->CreateTestHandler(); 583 BMessenger target2(handler2); 584 CHK(roster.StartWatching(target2) == B_OK); 585 CHK(roster.Messenger() == target2); 586 // unmount volume 587 NextSubTest(); 588 deleteVolume(testFile1, testMountPoint, false); 589 CHK(roster.Messenger() == target2); 590 CheckWatchingMessage(false, device, *handler2); 591 // mount volume 592 NextSubTest(); 593 createVolume(testFile1, testMountPoint, 1, false); 594 CHK(roster.Messenger() == target2); 595 device = dev_for_path(testMountPoint); 596 CHK(device >= 0); 597 CheckWatchingMessage(true, device, *handler2, nodeRef); 598 // stop watching 599 NextSubTest(); 600 roster.StopWatching(); 601 CHK(!roster.Messenger().IsValid()); 602 // unmount, mount volume 603 NextSubTest(); 604 deleteVolume(testFile1, testMountPoint, false); 605 createVolume(testFile1, testMountPoint, 1, false); 606 snooze(100000); 607 CHK(fApplication->Handler().Queue().IsEmpty()); 608 CHK(handler2->Queue().IsEmpty()); 609 610 // try start watching with a bad messenger 611 NextSubTest(); 612 CHK(roster.StartWatching(BMessenger()) == B_ERROR); 613 } 614 615