| // Copyright 2019 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "filesystem-mounter.h" |
| |
| #include <fidl/fuchsia.io/cpp/wire_test_base.h> |
| #include <fidl/fuchsia.io/cpp/wire_types.h> |
| #include <lib/async-loop/cpp/loop.h> |
| #include <lib/fidl/llcpp/server.h> |
| #include <lib/sync/completion.h> |
| #include <lib/zx/channel.h> |
| #include <zircon/fidl.h> |
| #include <zircon/time.h> |
| |
| #include <mutex> |
| |
| #include <gtest/gtest.h> |
| |
| #include "src/lib/testing/predicates/status.h" |
| #include "src/storage/blobfs/mount.h" |
| #include "src/storage/fshost/block-watcher.h" |
| #include "src/storage/fshost/config.h" |
| #include "src/storage/fshost/constants.h" |
| #include "src/storage/fshost/fs-manager.h" |
| |
| namespace fshost { |
| namespace { |
| class FilesystemMounterHarness : public testing::Test { |
| public: |
| FilesystemMounterHarness() : config_(DefaultConfig()), manager_(FshostBootArgs::Create()) {} |
| |
| protected: |
| FsManager& manager() { |
| if (!watcher_) { |
| watcher_.emplace(manager_, &config_); |
| EXPECT_OK(manager_.Initialize({}, {}, config_, *watcher_)); |
| manager_.ReadyForShutdown(); |
| } |
| return manager_; |
| } |
| |
| fshost_config::Config config_; |
| |
| private: |
| FsManager manager_; |
| std::optional<BlockWatcher> watcher_; |
| }; |
| |
| using MounterTest = FilesystemMounterHarness; |
| |
| TEST_F(MounterTest, CreateFilesystemManager) { manager(); } |
| |
| TEST_F(MounterTest, CreateFilesystemMounter) { FilesystemMounter mounter(manager(), &config_); } |
| |
| enum class FilesystemType { |
| kBlobfs, |
| kMinfs, |
| kDurable, |
| kFactoryfs, |
| }; |
| |
| class TestMounter : public FilesystemMounter { |
| public: |
| class FakeDirectoryImpl : public fidl::testing::WireTestBase<fuchsia_io::Directory> { |
| public: |
| void NotImplemented_(const std::string& name, fidl::CompleterBase& completer) override { |
| ADD_FAILURE() << "Unexpected call to " << name; |
| completer.Close(ZX_ERR_NOT_SUPPORTED); |
| } |
| |
| void Describe(DescribeRequestView request, DescribeCompleter::Sync& completer) override { |
| completer.Reply( |
| fuchsia_io::wire::NodeInfo::WithDirectory(fuchsia_io::wire::DirectoryObject())); |
| } |
| |
| void Open(OpenRequestView request, OpenCompleter::Sync& _completer) override {} |
| }; |
| |
| template <typename... Args> |
| explicit TestMounter(Args&&... args) |
| : FilesystemMounter(std::forward<Args>(args)...), |
| loop_(&kAsyncLoopConfigNoAttachToCurrentThread) { |
| loop_.StartThread("filesystem-mounter-test"); |
| } |
| |
| void ExpectFilesystem(FilesystemType fs) { expected_filesystem_ = fs; } |
| |
| zx::status<> LaunchFsComponent(zx::channel block_device, |
| fuchsia_fs_startup::wire::StartOptions options, |
| const std::string& fs_name) final { |
| switch (expected_filesystem_) { |
| case FilesystemType::kBlobfs: |
| EXPECT_EQ(fs_name, "blobfs"); |
| break; |
| case FilesystemType::kMinfs: |
| EXPECT_EQ(fs_name, "data"); |
| break; |
| default: |
| ADD_FAILURE() << "Unexpected filesystem type"; |
| } |
| |
| return zx::ok(); |
| } |
| |
| zx_status_t LaunchFs(int argc, const char** argv, zx_handle_t* hnd, uint32_t* ids, |
| size_t len) final { |
| if (argc != 2) { |
| return ZX_ERR_INVALID_ARGS; |
| } |
| |
| switch (expected_filesystem_) { |
| case FilesystemType::kDurable: |
| EXPECT_EQ(std::string_view(argv[0]), kMinfsPath); |
| EXPECT_EQ(len, 2ul); |
| break; |
| case FilesystemType::kFactoryfs: |
| EXPECT_EQ(std::string_view(argv[0]), kFactoryfsPath); |
| break; |
| default: |
| ADD_FAILURE() << "Unexpected filesystem type"; |
| } |
| |
| EXPECT_EQ(std::string_view(argv[1]), "mount"); |
| |
| EXPECT_EQ(ids[0], PA_DIRECTORY_REQUEST); |
| EXPECT_EQ(ids[1], FS_HANDLE_BLOCK_DEVICE_ID); |
| |
| fidl::BindServer(loop_.dispatcher(), |
| fidl::ServerEnd<fuchsia_io::Directory>(zx::channel(hnd[0])), |
| std::make_unique<FakeDirectoryImpl>()); |
| |
| // Close all other handles. |
| for (size_t i = 1; i < len; i++) { |
| EXPECT_OK(zx_handle_close(hnd[i])); |
| } |
| |
| return ZX_OK; |
| } |
| |
| private: |
| FilesystemType expected_filesystem_ = FilesystemType::kBlobfs; |
| std::mutex flags_lock_; |
| async::Loop loop_; |
| }; |
| |
| TEST_F(MounterTest, DurableMount) { |
| config_.durable() = true; |
| TestMounter mounter(manager(), &config_); |
| |
| mounter.ExpectFilesystem(FilesystemType::kDurable); |
| ASSERT_EQ(mounter.MountDurable(zx::channel(), fs_management::MountOptions()), ZX_OK); |
| ASSERT_TRUE(mounter.DurableMounted()); |
| } |
| |
| TEST_F(MounterTest, FactoryMount) { |
| config_.factory() = true; |
| TestMounter mounter(manager(), &config_); |
| |
| mounter.ExpectFilesystem(FilesystemType::kFactoryfs); |
| ASSERT_OK(mounter.MountFactoryFs(zx::channel(), fs_management::MountOptions())); |
| |
| ASSERT_TRUE(mounter.FactoryMounted()); |
| } |
| |
| TEST_F(MounterTest, MinfsMount) { |
| TestMounter mounter(manager(), &config_); |
| mounter.ExpectFilesystem(FilesystemType::kMinfs); |
| ASSERT_OK(mounter.MountData(zx::channel(), fs_management::MountOptions(), |
| fs_management::DiskFormat::kDiskFormatMinfs)); |
| ASSERT_TRUE(mounter.DataMounted()); |
| } |
| |
| TEST_F(MounterTest, BlobfsMount) { |
| TestMounter mounter(manager(), &config_); |
| mounter.ExpectFilesystem(FilesystemType::kBlobfs); |
| ASSERT_OK(mounter.MountBlob(zx::channel(), fuchsia_fs_startup::wire::StartOptions())); |
| ASSERT_TRUE(mounter.BlobMounted()); |
| } |
| |
| } // namespace |
| } // namespace fshost |