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
icon_equal(const BBitmap * icon1,const BBitmap * icon2)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*
Suite()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
setUp()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
tearDown()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
CheckVolume(BVolume & volume,dev_t device,status_t error)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
AssertNotBootVolume(const BVolume & volume)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
InitTest1()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
InitTest2()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
AssignmentTest()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
ComparissonTest()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
SetNameTest()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
BadValuesTest()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
GetAllDevices(set<dev_t> & devices)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
IterationTest()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
CheckWatchingMessage(bool mounted,dev_t expectedDevice,BTestHandler & handler,node_ref nodeRef=node_ref ())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
WatchingTest()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