| // 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 <lib/zx/channel.h> |
| #include <zircon/fidl.h> |
| |
| #include <cobalt-client/cpp/in_memory_logger.h> |
| #include <gtest/gtest.h> |
| |
| #include "fs-manager.h" |
| #include "fshost-fs-provider.h" |
| #include "metrics.h" |
| #include "src/storage/blobfs/mount.h" |
| #include "src/storage/fshost/block-watcher.h" |
| |
| namespace devmgr { |
| namespace { |
| |
| std::unique_ptr<FsHostMetrics> MakeMetrics() { |
| return std::make_unique<FsHostMetrics>(std::make_unique<cobalt_client::Collector>( |
| std::make_unique<cobalt_client::InMemoryLogger>())); |
| } |
| |
| class FilesystemMounterHarness : public testing::Test { |
| public: |
| FilesystemMounterHarness() |
| : manager_(FshostBootArgs::Create(), MakeMetrics()), watcher_(manager_, FshostOptions()) {} |
| |
| void SetUp() override { |
| zx::channel dir_request, lifecycle_request; |
| ASSERT_EQ(manager_.Initialize(std::move(dir_request), std::move(lifecycle_request), nullptr, |
| watcher_), |
| ZX_OK); |
| manager_.WatchExit(); |
| } |
| |
| protected: |
| FsManager manager_; |
| |
| private: |
| BlockWatcher watcher_; |
| }; |
| |
| using MounterTest = FilesystemMounterHarness; |
| |
| TEST_F(MounterTest, CreateFilesystemManager) {} |
| |
| TEST_F(MounterTest, CreateFilesystemMounter) { |
| FshostOptions options; |
| FilesystemMounter mounter(manager_, options); |
| } |
| |
| TEST_F(MounterTest, PkgfsWillNotMountBeforeBlobAndData) { |
| FshostOptions options; |
| FilesystemMounter mounter(manager_, options); |
| |
| ASSERT_FALSE(mounter.BlobMounted()); |
| ASSERT_FALSE(mounter.DataMounted()); |
| mounter.TryMountPkgfs(); |
| EXPECT_FALSE(mounter.PkgfsMounted()); |
| } |
| |
| enum class FilesystemType { |
| kBlobfs, |
| kMinfs, |
| kFactoryfs, |
| }; |
| |
| class TestMounter : public FilesystemMounter { |
| public: |
| template <typename... Args> |
| explicit TestMounter(Args&&... args) : FilesystemMounter(std::forward<Args>(args)...) {} |
| |
| void ExpectFilesystem(FilesystemType fs) { expected_filesystem_ = fs; } |
| |
| zx_status_t LaunchFs(int argc, const char** argv, zx_handle_t* hnd, uint32_t* ids, size_t len, |
| uint32_t fs_flags) final { |
| if (argc != 2) { |
| return ZX_ERR_INVALID_ARGS; |
| } |
| |
| switch (expected_filesystem_) { |
| case FilesystemType::kBlobfs: |
| EXPECT_EQ(std::string_view(argv[0]), "/boot/bin/blobfs"); |
| EXPECT_EQ(fs_flags, unsigned{FS_SVC | FS_SVC_BLOBFS}); |
| EXPECT_EQ(len, 3ul); |
| |
| // TODO(fxbug.dev/54521): This check is over-constraining. |
| // BlobFS does not *require* this handle to be |
| // passed in. However, filesystem-mounter will |
| // always pass this handle in. Remove this check |
| // once we migrate away from using this handle. |
| EXPECT_EQ(ids[2], FS_HANDLE_DIAGNOSTICS_DIR); |
| break; |
| case FilesystemType::kMinfs: |
| EXPECT_EQ(std::string_view(argv[0]), "/boot/bin/minfs"); |
| EXPECT_EQ(fs_flags, unsigned{FS_SVC}); |
| EXPECT_EQ(len, 2ul); |
| break; |
| case FilesystemType::kFactoryfs: |
| EXPECT_EQ(std::string_view(argv[0]), "/boot/bin/factoryfs"); |
| EXPECT_EQ(fs_flags, unsigned{FS_SVC}); |
| break; |
| default: |
| ADD_FAILURE() << "Unexpected filesystem type"; |
| } |
| |
| EXPECT_EQ(std::string_view(argv[1]), "mount"); |
| |
| EXPECT_EQ(ids[0], FS_HANDLE_ROOT_ID); |
| EXPECT_EQ(ids[1], FS_HANDLE_BLOCK_DEVICE_ID); |
| |
| zx::channel* server = nullptr; |
| switch (expected_filesystem_) { |
| case FilesystemType::kBlobfs: |
| server = &blobfs_server_; |
| break; |
| case FilesystemType::kMinfs: |
| server = &minfs_server_; |
| break; |
| case FilesystemType::kFactoryfs: |
| server = &factoryfs_server_; |
| break; |
| default: |
| ADD_FAILURE() << "Unexpected filesystem type"; |
| } |
| |
| server->reset(hnd[0]); |
| EXPECT_EQ(server->signal_peer(0, ZX_USER_SIGNAL_0), ZX_OK); |
| EXPECT_EQ(zx_handle_close(hnd[1]), ZX_OK); |
| return ZX_OK; |
| } |
| |
| private: |
| FilesystemType expected_filesystem_ = FilesystemType::kBlobfs; |
| zx::channel blobfs_server_; |
| zx::channel minfs_server_; |
| zx::channel factoryfs_server_; |
| }; |
| |
| TEST_F(MounterTest, DurableMount) { |
| TestMounter mounter(manager_, FshostOptions()); |
| |
| mount_options_t options = default_mount_options; |
| mounter.ExpectFilesystem(FilesystemType::kMinfs); |
| ASSERT_EQ(mounter.MountDurable(zx::channel(), options), ZX_OK); |
| ASSERT_TRUE(mounter.DurableMounted()); |
| } |
| |
| TEST_F(MounterTest, FactoryMount) { |
| TestMounter mounter(manager_, FshostOptions()); |
| |
| mount_options_t options = default_mount_options; |
| mounter.ExpectFilesystem(FilesystemType::kFactoryfs); |
| ASSERT_EQ(mounter.MountFactoryFs(zx::channel(), options), ZX_OK); |
| |
| ASSERT_TRUE(mounter.FactoryMounted()); |
| } |
| |
| TEST_F(MounterTest, PkgfsWillNotMountBeforeData) { |
| FshostOptions fshost_options = {.wait_for_data = true}; |
| TestMounter mounter(manager_, fshost_options); |
| |
| mount_options_t options = default_mount_options; |
| mounter.ExpectFilesystem(FilesystemType::kBlobfs); |
| ASSERT_EQ(mounter.MountBlob(zx::channel(), options), ZX_OK); |
| |
| ASSERT_TRUE(mounter.BlobMounted()); |
| ASSERT_FALSE(mounter.DataMounted()); |
| mounter.TryMountPkgfs(); |
| EXPECT_FALSE(mounter.PkgfsMounted()); |
| } |
| |
| TEST_F(MounterTest, PkgfsWillNotMountBeforeDataUnlessExplicitlyRequested) { |
| FshostOptions fshost_options = {.wait_for_data = false}; |
| TestMounter mounter(manager_, fshost_options); |
| |
| mount_options_t options = default_mount_options; |
| mounter.ExpectFilesystem(FilesystemType::kBlobfs); |
| ASSERT_EQ(mounter.MountBlob(zx::channel(), options), ZX_OK); |
| |
| ASSERT_TRUE(mounter.BlobMounted()); |
| ASSERT_FALSE(mounter.DataMounted()); |
| mounter.TryMountPkgfs(); |
| EXPECT_TRUE(mounter.PkgfsMounted()); |
| } |
| |
| TEST_F(MounterTest, PkgfsWillNotMountBeforeBlob) { |
| FshostOptions fshost_options = {.wait_for_data = true}; |
| TestMounter mounter(manager_, fshost_options); |
| |
| mount_options_t options = default_mount_options; |
| mounter.ExpectFilesystem(FilesystemType::kMinfs); |
| ASSERT_EQ(mounter.MountData(zx::channel(), options), ZX_OK); |
| |
| ASSERT_FALSE(mounter.BlobMounted()); |
| ASSERT_TRUE(mounter.DataMounted()); |
| mounter.TryMountPkgfs(); |
| EXPECT_FALSE(mounter.PkgfsMounted()); |
| } |
| |
| TEST_F(MounterTest, PkgfsMountsWithBlobAndData) { |
| FshostOptions fshost_options = {.wait_for_data = true}; |
| TestMounter mounter(manager_, fshost_options); |
| |
| mount_options_t options = default_mount_options; |
| mounter.ExpectFilesystem(FilesystemType::kBlobfs); |
| ASSERT_EQ(mounter.MountBlob(zx::channel(), options), ZX_OK); |
| mounter.ExpectFilesystem(FilesystemType::kMinfs); |
| ASSERT_EQ(mounter.MountData(zx::channel(), options), ZX_OK); |
| |
| ASSERT_TRUE(mounter.BlobMounted()); |
| ASSERT_TRUE(mounter.DataMounted()); |
| mounter.TryMountPkgfs(); |
| EXPECT_TRUE(mounter.PkgfsMounted()); |
| } |
| |
| } // namespace |
| } // namespace devmgr |