| // Copyright 2019 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "cros-disks/mount_point.h" |
| |
| #include <limits> |
| #include <utility> |
| |
| #include <base/test/bind.h> |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| |
| #include "cros-disks/mock_platform.h" |
| #include "cros-disks/platform.h" |
| |
| namespace cros_disks { |
| namespace { |
| |
| using testing::_; |
| using testing::ElementsAre; |
| using testing::Return; |
| using testing::StrictMock; |
| |
| class MountPointTest : public testing::Test { |
| protected: |
| const std::string kMountPath = "/mount/path"; |
| const std::string kSource = "source"; |
| const std::string kFSType = "fstype"; |
| const std::string kOptions = "foo=bar"; |
| StrictMock<MockPlatform> platform_; |
| const MountPointData data_ = {.mount_path = base::FilePath(kMountPath), |
| .source = kSource, |
| .filesystem_type = kFSType, |
| .flags = MS_DIRSYNC | MS_NODEV, |
| .data = kOptions}; |
| }; |
| |
| } // namespace |
| |
| TEST_F(MountPointTest, Unmount) { |
| auto mount_point = std::make_unique<MountPoint>(data_, &platform_); |
| |
| EXPECT_CALL(platform_, Unmount(base::FilePath(kMountPath), kFSType)) |
| .WillOnce(Return(MountError::kBusy)); |
| EXPECT_EQ(MountError::kBusy, mount_point->Unmount()); |
| |
| EXPECT_CALL(platform_, Unmount(base::FilePath(kMountPath), kFSType)) |
| .WillOnce(Return(MountError::kSuccess)); |
| EXPECT_CALL(platform_, RemoveEmptyDirectory(kMountPath)) |
| .WillOnce(Return(true)); |
| EXPECT_EQ(MountError::kSuccess, mount_point->Unmount()); |
| |
| EXPECT_EQ(MountError::kPathNotMounted, mount_point->Unmount()); |
| } |
| |
| TEST_F(MountPointTest, UnmountOnDestroy) { |
| const std::unique_ptr<MountPoint> mount_point = |
| std::make_unique<MountPoint>(data_, &platform_); |
| EXPECT_TRUE(mount_point->is_mounted()); |
| |
| EXPECT_CALL(platform_, Unmount(base::FilePath(kMountPath), kFSType)) |
| .WillOnce(Return(MountError::kSuccess)); |
| EXPECT_CALL(platform_, RemoveEmptyDirectory(kMountPath)) |
| .WillOnce(Return(false)); |
| } |
| |
| TEST_F(MountPointTest, UnmountError) { |
| const std::unique_ptr<MountPoint> mount_point = |
| std::make_unique<MountPoint>(data_, &platform_); |
| EXPECT_TRUE(mount_point->is_mounted()); |
| |
| EXPECT_CALL(platform_, Unmount(base::FilePath(kMountPath), kFSType)) |
| .WillOnce(Return(MountError::kPathNotMounted)); |
| EXPECT_CALL(platform_, RemoveEmptyDirectory(kMountPath)) |
| .WillOnce(Return(true)); |
| EXPECT_EQ(MountError::kPathNotMounted, mount_point->Unmount()); |
| |
| EXPECT_FALSE(mount_point->is_mounted()); |
| } |
| |
| TEST_F(MountPointTest, Remount) { |
| const std::unique_ptr<MountPoint> mount_point = |
| std::make_unique<MountPoint>(data_, &platform_); |
| EXPECT_TRUE(mount_point->is_mounted()); |
| EXPECT_FALSE(mount_point->is_read_only()); |
| |
| EXPECT_CALL(platform_, |
| Mount(kSource, kMountPath, kFSType, |
| MS_DIRSYNC | MS_NODEV | MS_RDONLY | MS_REMOUNT, kOptions)) |
| .WillOnce(Return(MountError::kSuccess)); |
| EXPECT_EQ(MountError::kSuccess, mount_point->Remount(true)); |
| EXPECT_TRUE(mount_point->is_read_only()); |
| |
| EXPECT_CALL(platform_, Mount(kSource, kMountPath, kFSType, |
| MS_DIRSYNC | MS_NODEV | MS_REMOUNT, kOptions)) |
| .WillOnce(Return(MountError::kInternalError)); |
| EXPECT_EQ(MountError::kInternalError, mount_point->Remount(false)); |
| EXPECT_TRUE(mount_point->is_read_only()); |
| |
| EXPECT_CALL(platform_, Unmount(base::FilePath(kMountPath), kFSType)) |
| .WillOnce(Return(MountError::kSuccess)); |
| EXPECT_CALL(platform_, RemoveEmptyDirectory(kMountPath)) |
| .WillOnce(Return(true)); |
| } |
| |
| TEST_F(MountPointTest, RemountUnmounted) { |
| const std::unique_ptr<MountPoint> mount_point = |
| MountPoint::CreateUnmounted(data_); |
| EXPECT_FALSE(mount_point->is_mounted()); |
| EXPECT_FALSE(mount_point->is_read_only()); |
| |
| EXPECT_EQ(MountError::kPathNotMounted, mount_point->Remount(true)); |
| EXPECT_FALSE(mount_point->is_read_only()); |
| } |
| |
| TEST_F(MountPointTest, MountError) { |
| EXPECT_CALL(platform_, Mount(kSource, kMountPath, kFSType, |
| MS_DIRSYNC | MS_NODEV, kOptions)) |
| .WillOnce(Return(MountError::kInvalidArgument)); |
| |
| MountError error = MountError::kUnknownError; |
| const std::unique_ptr<MountPoint> mount_point = |
| MountPoint::Mount(data_, &platform_, &error); |
| EXPECT_FALSE(mount_point); |
| EXPECT_EQ(MountError::kInvalidArgument, error); |
| } |
| |
| TEST_F(MountPointTest, MountSucceeds) { |
| MountError error = MountError::kUnknownError; |
| EXPECT_CALL(platform_, Mount(kSource, kMountPath, kFSType, |
| MS_DIRSYNC | MS_NODEV, kOptions)) |
| .WillOnce(Return(MountError::kSuccess)); |
| |
| const std::unique_ptr<MountPoint> mount_point = |
| MountPoint::Mount(data_, &platform_, &error); |
| EXPECT_EQ(MountError::kSuccess, error); |
| EXPECT_TRUE(mount_point); |
| EXPECT_TRUE(mount_point->is_mounted()); |
| EXPECT_EQ(data_.mount_path, mount_point->path()); |
| EXPECT_EQ(data_.source, mount_point->source()); |
| EXPECT_EQ(data_.filesystem_type, mount_point->fstype()); |
| EXPECT_EQ(data_.flags, mount_point->flags()); |
| |
| EXPECT_CALL(platform_, Unmount(base::FilePath(kMountPath), kFSType)) |
| .WillOnce(Return(MountError::kSuccess)); |
| EXPECT_CALL(platform_, RemoveEmptyDirectory(kMountPath)) |
| .WillOnce(Return(true)); |
| } |
| |
| TEST_F(MountPointTest, CreateUnmounted) { |
| const std::unique_ptr<MountPoint> mount_point = |
| MountPoint::CreateUnmounted(data_); |
| EXPECT_TRUE(mount_point); |
| EXPECT_FALSE(mount_point->is_mounted()); |
| EXPECT_EQ(data_.mount_path, mount_point->path()); |
| EXPECT_EQ(data_.source, mount_point->source()); |
| EXPECT_EQ(data_.filesystem_type, mount_point->fstype()); |
| EXPECT_EQ(data_.flags, mount_point->flags()); |
| } |
| |
| TEST_F(MountPointTest, ParseProgressMessage) { |
| int percent = -1; |
| EXPECT_FALSE(MountPoint::ParseProgressMessage("", &percent)); |
| EXPECT_FALSE(MountPoint::ParseProgressMessage("x", &percent)); |
| EXPECT_EQ(percent, -1); |
| |
| EXPECT_FALSE(MountPoint::ParseProgressMessage("%", &percent)); |
| EXPECT_FALSE(MountPoint::ParseProgressMessage(" %", &percent)); |
| EXPECT_FALSE(MountPoint::ParseProgressMessage("x%", &percent)); |
| |
| percent = -1; |
| EXPECT_TRUE(MountPoint::ParseProgressMessage("0%", &percent)); |
| EXPECT_EQ(percent, 0); |
| |
| percent = -1; |
| EXPECT_TRUE(MountPoint::ParseProgressMessage("Whatever 1%", &percent)); |
| EXPECT_EQ(percent, 1); |
| |
| percent = -1; |
| EXPECT_TRUE(MountPoint::ParseProgressMessage("Whatever 99%", &percent)); |
| EXPECT_EQ(percent, 99); |
| |
| percent = -1; |
| EXPECT_TRUE(MountPoint::ParseProgressMessage("Whatever 100%", &percent)); |
| EXPECT_EQ(percent, 100); |
| |
| percent = -1; |
| EXPECT_FALSE(MountPoint::ParseProgressMessage("Whatever 101%", &percent)); |
| EXPECT_EQ(percent, 101); |
| |
| percent = -1; |
| EXPECT_FALSE(MountPoint::ParseProgressMessage("Whatever 9999999999999999999%", |
| &percent)); |
| EXPECT_EQ(percent, std::numeric_limits<int>::max()); |
| } |
| |
| TEST_F(MountPointTest, ProgressCallback) { |
| const std::unique_ptr<MountPoint> mount_point = |
| MountPoint::CreateUnmounted(data_); |
| mount_point->OnProgress("Loading 1%"); |
| mount_point->OnProgress("Loading 2%"); |
| std::vector<int> progress_percents; |
| mount_point->SetProgressCallback(base::BindLambdaForTesting( |
| [&progress_percents, want_mount_point = mount_point.get()]( |
| const MountPoint* const got_mount_point) { |
| EXPECT_EQ(want_mount_point, got_mount_point); |
| progress_percents.push_back(got_mount_point->progress_percent()); |
| })); |
| mount_point->OnProgress("Loading 3%"); |
| mount_point->OnProgress("Loading 99%"); |
| mount_point->OnProgress(""); |
| mount_point->OnProgress("%"); |
| mount_point->OnProgress("xx%"); |
| mount_point->OnProgress("Ignored 1"); |
| mount_point->OnProgress("Loading 100%"); |
| EXPECT_THAT(progress_percents, ElementsAre(3, 99, 100)); |
| } |
| |
| } // namespace cros_disks |