#include "kernel/filesystem/vfs.hpp" #include "kernel/devices/storage/management.hpp" #include "kernel/filesystem/filesystem.hpp" #include "kernel/test_support/filesystem/storage_boot_module_vfs_fixture.hpp" #include #include SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS with dummy modules", "[filesystem][vfs]") { GIVEN("an initialized boot module registry with multiple modules") { REQUIRE_NOTHROW(setup_modules_and_init_vfs(5)); THEN("vfs initializes and provides /dev mount") { auto & vfs = kernel::filesystem::vfs::get(); auto dev = vfs.open("/dev"); REQUIRE(dev != nullptr); } THEN("vfs initializes root filesystem with boot device if boot module is present") { auto & vfs = kernel::filesystem::vfs::get(); auto root_file = vfs.open("/"); REQUIRE(root_file != nullptr); } } } SCENARIO_METHOD(kernel::tests::filesystem::storage_boot_module_vfs_fixture, "VFS with file backed image", "[filesystem][vfs][img]") { auto const image_path_1 = std::filesystem::path{KERNEL_TEST_ASSETS_DIR} / "ext2_1KB_fs.img"; auto const image_path_2 = std::filesystem::path{KERNEL_TEST_ASSETS_DIR} / "ext2_2KB_fs.img"; auto const image_path_3 = std::filesystem::path{KERNEL_TEST_ASSETS_DIR} / "ext2_4KB_fs.img"; GIVEN("a real image file") { REQUIRE(std::filesystem::exists(image_path_1)); REQUIRE_NOTHROW(setup_modules_from_img_and_init_vfs({"test_img_module"}, {image_path_1})); THEN("vfs initializes and provides expected mount points") { auto & volatilefs = kernel::filesystem::vfs::get(); auto root = volatilefs.open("/"); auto dev = volatilefs.open("/dev"); auto information = volatilefs.open("/information/info_1.txt"); REQUIRE(root != nullptr); REQUIRE(dev != nullptr); REQUIRE(information != nullptr); } } GIVEN("three real image files") { REQUIRE(std::filesystem::exists(image_path_1)); REQUIRE(std::filesystem::exists(image_path_2)); REQUIRE(std::filesystem::exists(image_path_3)); REQUIRE_NOTHROW(setup_modules_from_img_and_init_vfs({"test_img_module_1", "test_img_module_2", "test_img_module_3"}, {image_path_1, image_path_2, image_path_3})); auto & vfs = kernel::filesystem::vfs::get(); auto storage_mgmt = kernel::devices::storage::management::get(); auto device_1 = storage_mgmt.device_by_major_minor(1, 16); auto fs_1 = kernel::filesystem::filesystem::probe_and_mount(device_1); auto device_2 = storage_mgmt.device_by_major_minor(1, 32); auto fs_2 = kernel::filesystem::filesystem::probe_and_mount(device_2); THEN("vfs initializes first module as root") { auto & vfs = kernel::filesystem::vfs::get(); auto info1 = vfs.open("/information/info_1.txt"); auto info2 = vfs.open("/information/info_2.txt"); REQUIRE(info1 != nullptr); REQUIRE(info2 != nullptr); } THEN("second image can be mounted, data retrieved and unmounted again") { REQUIRE(vfs.do_mount("/information", fs_1) == kernel::filesystem::vfs::operation_result::success); auto mounted_monkey_1 = vfs.open("/information/monkey_house/monkey_1.txt"); REQUIRE(mounted_monkey_1 != nullptr); REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::success); auto unmounted_monkey_1 = vfs.open("/information/monkey_house/monkey_1.txt"); REQUIRE(unmounted_monkey_1 == nullptr); auto info_1 = vfs.open("/information/info_1.txt"); REQUIRE(info_1 != nullptr); } THEN("third image can be mounted in a mounted file system, unmount only if no child mount exists") { REQUIRE(vfs.do_mount("/information", fs_1) == kernel::filesystem::vfs::operation_result::success); REQUIRE(vfs.do_mount("/information/monkey_house/infrastructure", fs_2) == kernel::filesystem::vfs::operation_result::success); auto mounted_monkey_1 = vfs.open("/information/monkey_house/monkey_1.txt"); auto mounted_fish1 = vfs.open("/information/monkey_house/infrastructure/enclosures/aquarium/tank_1/fish_1.txt"); REQUIRE(mounted_monkey_1 != nullptr); REQUIRE(mounted_fish1 != nullptr); REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::unmount_failed); REQUIRE(vfs.unmount("/information/monkey_house/infrastructure") == kernel::filesystem::vfs::operation_result::success); REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::success); } THEN("images can be stacked mounted and correct file system is unmounted again") { REQUIRE(vfs.do_mount("/information", fs_1) == kernel::filesystem::vfs::operation_result::success); REQUIRE(vfs.do_mount("/information", fs_2) == kernel::filesystem::vfs::operation_result::success); auto mounted_tickets = vfs.open("/information/entrance/tickets.txt"); REQUIRE(mounted_tickets != nullptr); REQUIRE(vfs.unmount("/information") == kernel::filesystem::vfs::operation_result::success); mounted_tickets = vfs.open("/information/entrance/tickets.txt"); REQUIRE(mounted_tickets == nullptr); auto mounted_monkey = vfs.open("/information/monkey_house/monkey_1.txt"); REQUIRE(mounted_monkey != nullptr); } THEN("mount with null file system fails") { REQUIRE(vfs.do_mount("/information", nullptr) == kernel::filesystem::vfs::operation_result::filesystem_null); } THEN("mount with invalid path fails") { REQUIRE(vfs.do_mount("", fs_1) == kernel::filesystem::vfs::operation_result::invalid_path); REQUIRE(vfs.do_mount("information", fs_1) == kernel::filesystem::vfs::operation_result::invalid_path); REQUIRE(vfs.do_mount("/information/", fs_1) == kernel::filesystem::vfs::operation_result::invalid_path); } THEN("mount with non-existent mount point fails") { REQUIRE(vfs.do_mount("/information/nonexistent", fs_1) == kernel::filesystem::vfs::operation_result::mount_point_not_found); } THEN("unmount with invalid path fails") { REQUIRE(vfs.unmount("") == kernel::filesystem::vfs::operation_result::invalid_path); REQUIRE(vfs.unmount("information") == kernel::filesystem::vfs::operation_result::invalid_path); REQUIRE(vfs.unmount("/information/") == kernel::filesystem::vfs::operation_result::invalid_path); } THEN("unmounting non-existent mount point returns expected error code") { REQUIRE(vfs.unmount("/information/nonexistent") == kernel::filesystem::vfs::operation_result::mount_point_not_found); } } }