blob: 2740c81e686b4fa687fc2a3ffe4dfee28083b9ed [file] [log] [blame]
// Copyright (c) 2012 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Unit tests for cros_disks::MountManager. See mount-manager.h for details
// on MountManager.
#include "cros-disks/mount_manager.h"
#include <sys/mount.h>
#include <sys/unistd.h>
#include <algorithm>
#include <string>
#include <unordered_set>
#include <utility>
#include <vector>
#include <base/callback.h>
#include <base/check.h>
#include <base/strings/strcat.h>
#include <brillo/process/process_reaper.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "cros-disks/metrics.h"
#include "cros-disks/mock_platform.h"
#include "cros-disks/mount_options.h"
#include "cros-disks/mount_point.h"
#include "cros-disks/mounter.h"
#include "cros-disks/platform.h"
using testing::_;
using testing::ByMove;
using testing::DoAll;
using testing::ElementsAre;
using testing::Invoke;
using testing::IsEmpty;
using testing::Return;
using testing::SetArgPointee;
using testing::SizeIs;
using testing::StrictMock;
using testing::WithArgs;
namespace cros_disks {
namespace {
const char kMountRootDirectory[] = "/media/removable";
const char kSourcePath[] = "source";
const char kMountPath[] = "/media/removable/test";
} // namespace
// A mock mount manager class for testing the mount manager base class.
class MountManagerUnderTest : public MountManager {
public:
MountManagerUnderTest(Platform* platform,
Metrics* metrics,
brillo::ProcessReaper* process_reaper)
: MountManager(kMountRootDirectory, platform, metrics, process_reaper) {}
~MountManagerUnderTest() override { UnmountAll(); }
MOCK_METHOD(bool, CanMount, (const std::string&), (const, override));
MOCK_METHOD(MountSourceType, GetMountSourceType, (), (const, override));
MOCK_METHOD(std::unique_ptr<MountPoint>,
DoMount,
(const std::string&,
const std::string&,
const std::vector<std::string>&,
const base::FilePath&,
MountErrorType*),
(override));
MOCK_METHOD(bool,
ShouldReserveMountPathOnError,
(MountErrorType),
(const, override));
MOCK_METHOD(std::string,
SuggestMountPath,
(const std::string&),
(const, override));
// Adds a mount point to the collection of mount points.
void AddMount(std::unique_ptr<MountPoint> mount_point) {
DCHECK(mount_point);
DCHECK(!FindMountBySource(mount_point->source()));
DCHECK(!FindMountByMountPath(mount_point->path()));
mount_points_.push_back(std::move(mount_point));
}
bool IsMountPathInCache(const std::string& path) {
return FindMountByMountPath(base::FilePath(path));
}
bool RemoveMountPathFromCache(const std::string& path) {
MountPoint* mp = FindMountByMountPath(base::FilePath(path));
if (!mp)
return false;
return RemoveMount(mp);
}
using MountManager::FindMountBySource;
};
class MountManagerTest : public ::testing::Test {
public:
MountManagerTest() : manager_(&platform_, &metrics_, &process_reaper_) {
EXPECT_CALL(manager_, GetMountSourceType())
.WillRepeatedly(Return(MOUNT_SOURCE_REMOVABLE_DEVICE));
EXPECT_CALL(platform_, GetRealPath(_, _)).WillRepeatedly(Return(false));
}
std::unique_ptr<MountPoint> MakeMountPoint(const std::string& mount_path) {
return MountPoint::CreateUnmounted(
{.mount_path = base::FilePath(mount_path),
.source = kSourcePath,
.source_type = MOUNT_SOURCE_REMOVABLE_DEVICE},
&platform_);
}
void OnMountCompleted(const std::string& path, MountErrorType error) {
EXPECT_FALSE(mount_completed_);
mount_path_ = path;
mount_error_ = error;
mount_completed_ = true;
}
MountManager::MountCallback GetMountCallback() {
mount_path_.clear();
mount_error_ = MOUNT_ERROR_NONE;
mount_completed_ = false;
return base::BindOnce(&MountManagerTest::OnMountCompleted,
base::Unretained(this));
}
protected:
Metrics metrics_;
StrictMock<MockPlatform> platform_;
brillo::ProcessReaper process_reaper_;
StrictMock<MountManagerUnderTest> manager_;
std::string filesystem_type_;
std::string mount_path_;
MountErrorType mount_error_;
bool mount_completed_;
std::vector<std::string> options_;
};
// Verifies that MountManager::Initialize() returns false when it fails to
// create the mount root directory.
TEST_F(MountManagerTest, InitializeFailedInCreateDirectory) {
EXPECT_CALL(platform_, CreateDirectory(kMountRootDirectory))
.WillOnce(Return(false));
EXPECT_CALL(platform_, SetOwnership(kMountRootDirectory, getuid(), getgid()))
.Times(0);
EXPECT_CALL(platform_, SetPermissions(kMountRootDirectory, _)).Times(0);
EXPECT_CALL(platform_, CleanUpStaleMountPoints(_)).Times(0);
EXPECT_FALSE(manager_.Initialize());
}
// Verifies that MountManager::Initialize() returns false when it fails to
// set the ownership of the created mount root directory.
TEST_F(MountManagerTest, InitializeFailedInSetOwnership) {
EXPECT_CALL(platform_, CreateDirectory(kMountRootDirectory))
.WillOnce(Return(true));
EXPECT_CALL(platform_, SetOwnership(kMountRootDirectory, getuid(), getgid()))
.WillOnce(Return(false));
EXPECT_CALL(platform_, SetPermissions(kMountRootDirectory, _)).Times(0);
EXPECT_CALL(platform_, CleanUpStaleMountPoints(_)).Times(0);
EXPECT_FALSE(manager_.Initialize());
}
// Verifies that MountManager::Initialize() returns false when it fails to
// set the permissions of the created mount root directory.
TEST_F(MountManagerTest, InitializeFailedInSetPermissions) {
EXPECT_CALL(platform_, CreateDirectory(kMountRootDirectory))
.WillOnce(Return(true));
EXPECT_CALL(platform_, SetOwnership(kMountRootDirectory, getuid(), getgid()))
.WillOnce(Return(true));
EXPECT_CALL(platform_, SetPermissions(kMountRootDirectory, _))
.WillOnce(Return(false));
EXPECT_CALL(platform_, CleanUpStaleMountPoints(_)).Times(0);
EXPECT_FALSE(manager_.Initialize());
}
// Verifies that MountManager::Initialize() returns false when it fails to
// clean up stale mount points.
TEST_F(MountManagerTest, InitializeFailedInCleanUp) {
EXPECT_CALL(platform_, CreateDirectory(kMountRootDirectory))
.WillOnce(Return(true));
EXPECT_CALL(platform_, SetOwnership(kMountRootDirectory, getuid(), getgid()))
.WillOnce(Return(true));
EXPECT_CALL(platform_, SetPermissions(kMountRootDirectory, _))
.WillOnce(Return(true));
EXPECT_CALL(platform_, CleanUpStaleMountPoints(kMountRootDirectory))
.WillOnce(Return(false));
EXPECT_FALSE(manager_.Initialize());
}
// Verifies that MountManager::Initialize() returns true when it creates
// the mount root directory with the specified ownership and permissions.
TEST_F(MountManagerTest, InitializeSucceeded) {
EXPECT_CALL(platform_, CreateDirectory(kMountRootDirectory))
.WillOnce(Return(true));
EXPECT_CALL(platform_, SetOwnership(kMountRootDirectory, getuid(), getgid()))
.WillOnce(Return(true));
EXPECT_CALL(platform_, SetPermissions(kMountRootDirectory, _))
.WillOnce(Return(true));
EXPECT_CALL(platform_, CleanUpStaleMountPoints(kMountRootDirectory))
.WillOnce(Return(true));
EXPECT_TRUE(manager_.Initialize());
}
// Verifies that MountManager::Mount() returns an error when it is invoked
// to mount an empty source path.
TEST_F(MountManagerTest, MountFailedWithEmptySourcePath) {
EXPECT_CALL(manager_, SuggestMountPath(_)).Times(0);
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectory(_)).Times(0);
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
.Times(0);
EXPECT_CALL(platform_, RemoveEmptyDirectory(_)).Times(0);
EXPECT_CALL(manager_, DoMount(_, _, _, _, _)).Times(0);
manager_.Mount("", filesystem_type_, options_, GetMountCallback());
EXPECT_TRUE(mount_completed_);
EXPECT_EQ(MOUNT_ERROR_INVALID_ARGUMENT, mount_error_);
}
// Verifies that MountManager::Mount() returns an error when it is invoked
// without a given mount path and the suggested mount path is invalid.
TEST_F(MountManagerTest, MountFailedWithInvalidSuggestedMountPath) {
EXPECT_CALL(manager_, SuggestMountPath(_))
.WillRepeatedly(Return("/media/removable/../test/doc"));
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectory(_)).Times(0);
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
.Times(0);
EXPECT_CALL(platform_, RemoveEmptyDirectory(_)).Times(0);
EXPECT_CALL(manager_, DoMount(_, _, _, _, _)).Times(0);
manager_.Mount(kSourcePath, filesystem_type_, options_, GetMountCallback());
EXPECT_TRUE(mount_completed_);
EXPECT_EQ(MOUNT_ERROR_INVALID_PATH, mount_error_);
options_.push_back("mountlabel=custom_label");
manager_.Mount(kSourcePath, filesystem_type_, options_, GetMountCallback());
EXPECT_TRUE(mount_completed_);
EXPECT_EQ(MOUNT_ERROR_INVALID_PATH, mount_error_);
}
// Verifies that MountManager::Mount() returns an error when it is invoked
// with an mount label that yields an invalid mount path.
TEST_F(MountManagerTest, MountFailedWithInvalidMountLabel) {
options_.push_back("mountlabel=../custom_label");
EXPECT_CALL(manager_, SuggestMountPath(kSourcePath))
.WillOnce(Return(kSourcePath));
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectory(_)).Times(0);
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
.Times(0);
EXPECT_CALL(platform_, RemoveEmptyDirectory(_)).Times(0);
EXPECT_CALL(manager_, DoMount(_, _, _, _, _)).Times(0);
manager_.Mount(kSourcePath, filesystem_type_, options_, GetMountCallback());
EXPECT_TRUE(mount_completed_);
EXPECT_EQ(MOUNT_ERROR_INVALID_PATH, mount_error_);
}
// Verifies that MountManager::Mount() returns an error when it fails to
// create the specified mount directory.
TEST_F(MountManagerTest, MountFailedInCreateOrReuseEmptyDirectory) {
EXPECT_CALL(manager_, SuggestMountPath(kSourcePath))
.WillOnce(Return(kMountPath));
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
.WillOnce(Return(false));
EXPECT_CALL(platform_, RemoveEmptyDirectory(_)).Times(0);
EXPECT_CALL(manager_, DoMount(_, _, _, _, _)).Times(0);
manager_.Mount(kSourcePath, filesystem_type_, options_, GetMountCallback());
EXPECT_TRUE(mount_completed_);
EXPECT_EQ(MOUNT_ERROR_DIRECTORY_CREATION_FAILED, mount_error_);
EXPECT_EQ("", mount_path_);
}
// Verifies that MountManager::Mount() returns an error when it fails to
// create a mount directory after a number of trials.
TEST_F(MountManagerTest, MountFailedInCreateOrReuseEmptyDirectoryWithFallback) {
EXPECT_CALL(manager_, SuggestMountPath(kSourcePath))
.WillOnce(Return(kMountPath));
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
.WillOnce(Return(false));
EXPECT_CALL(platform_, RemoveEmptyDirectory(_)).Times(0);
EXPECT_CALL(manager_, DoMount(_, _, _, _, _)).Times(0);
manager_.Mount(kSourcePath, filesystem_type_, options_, GetMountCallback());
EXPECT_TRUE(mount_completed_);
EXPECT_EQ(MOUNT_ERROR_DIRECTORY_CREATION_FAILED, mount_error_);
EXPECT_EQ("", mount_path_);
EXPECT_FALSE(manager_.IsMountPathInCache(kMountPath));
}
// Verifies that MountManager::Mount() fails when DoMount returns no MountPoint
// and no error (crbug.com/1317877 and crbug.com/1317878).
TEST_F(MountManagerTest, MountFailsWithNoMountPointAndNoError) {
EXPECT_CALL(manager_, SuggestMountPath(kSourcePath))
.WillOnce(Return(kMountPath));
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
.WillOnce(Return(true));
EXPECT_CALL(manager_, DoMount(kSourcePath, filesystem_type_, options_,
base::FilePath(kMountPath), _))
.WillOnce(
DoAll(SetArgPointee<4>(MOUNT_ERROR_NONE), Return(ByMove(nullptr))));
EXPECT_CALL(manager_, ShouldReserveMountPathOnError(MOUNT_ERROR_UNKNOWN))
.WillOnce(Return(false));
EXPECT_CALL(platform_, RemoveEmptyDirectory(kMountPath))
.WillOnce(Return(true));
manager_.Mount(kSourcePath, filesystem_type_, options_, GetMountCallback());
EXPECT_TRUE(mount_completed_);
EXPECT_EQ(MOUNT_ERROR_UNKNOWN, mount_error_);
EXPECT_EQ("", mount_path_);
EXPECT_FALSE(manager_.IsMountPathInCache(kMountPath));
}
// Verifies that MountManager::Mount() fails when DoMount returns both a
// MountPoint and an error.
TEST_F(MountManagerTest, MountFailsWithMountPointAndError) {
EXPECT_CALL(manager_, SuggestMountPath(kSourcePath))
.WillOnce(Return(kMountPath));
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
.WillOnce(Return(true));
const base::FilePath mount_path(kMountPath);
auto ptr = std::make_unique<MountPoint>(
MountPointData{.mount_path = mount_path,
.flags = IsReadOnlyMount(options_) ? MS_RDONLY : 0},
&platform_);
EXPECT_CALL(manager_,
DoMount(kSourcePath, filesystem_type_, options_, mount_path, _))
.WillOnce(DoAll(SetArgPointee<4>(MOUNT_ERROR_INVALID_PATH),
Return(ByMove(std::move(ptr)))));
EXPECT_CALL(manager_, ShouldReserveMountPathOnError(MOUNT_ERROR_INVALID_PATH))
.WillOnce(Return(false));
EXPECT_CALL(platform_, Unmount(kMountPath, _))
.WillOnce(Return(MOUNT_ERROR_NONE));
EXPECT_CALL(platform_, RemoveEmptyDirectory(kMountPath))
.WillOnce(Return(true))
.WillOnce(Return(false));
manager_.Mount(kSourcePath, filesystem_type_, options_, GetMountCallback());
EXPECT_TRUE(mount_completed_);
EXPECT_EQ(MOUNT_ERROR_INVALID_PATH, mount_error_);
EXPECT_EQ("", mount_path_);
EXPECT_FALSE(manager_.IsMountPathInCache(kMountPath));
}
// Verifies that MountManager::Mount() returns no error when it successfully
// mounts a source path in read-write mode.
TEST_F(MountManagerTest, MountSucceededWithGivenMountPath) {
options_.push_back("rw");
EXPECT_CALL(manager_, SuggestMountPath(kSourcePath))
.WillOnce(Return(kMountPath));
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
.WillOnce(Return(true));
const base::FilePath mount_path(kMountPath);
auto ptr = std::make_unique<MountPoint>(
MountPointData{.mount_path = mount_path,
.flags = IsReadOnlyMount(options_) ? MS_RDONLY : 0},
&platform_);
EXPECT_CALL(manager_,
DoMount(kSourcePath, filesystem_type_, options_, mount_path, _))
.WillOnce(DoAll(SetArgPointee<4>(MOUNT_ERROR_NONE),
Return(ByMove(std::move(ptr)))));
manager_.Mount(kSourcePath, filesystem_type_, options_, GetMountCallback());
EXPECT_TRUE(mount_completed_);
EXPECT_EQ(MOUNT_ERROR_NONE, mount_error_);
EXPECT_EQ(kMountPath, mount_path_);
EXPECT_TRUE(manager_.IsMountPathInCache(mount_path_));
{
const MountPoint* const mount_point =
manager_.FindMountBySource(kSourcePath);
ASSERT_TRUE(mount_point);
EXPECT_FALSE(mount_point->is_read_only());
}
EXPECT_CALL(platform_, Unmount(mount_path_, _))
.WillOnce(Return(MOUNT_ERROR_NONE));
EXPECT_CALL(platform_, RemoveEmptyDirectory(kMountPath))
.WillOnce(Return(true));
manager_.UnmountAll();
EXPECT_FALSE(manager_.IsMountPathInCache(mount_path_));
}
// Verifies that MountManager::Mount() stores correct mount status in cache when
// read-only option is specified.
TEST_F(MountManagerTest, MountCachesStatusWithReadOnlyOption) {
EXPECT_CALL(manager_, SuggestMountPath(kSourcePath))
.WillOnce(Return(kMountPath));
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
.WillOnce(Return(true));
// Add read-only mount option.
options_.push_back("ro");
base::FilePath mount_path(kMountPath);
auto ptr = std::make_unique<MountPoint>(
MountPointData{.mount_path = mount_path,
.flags = IsReadOnlyMount(options_) ? MS_RDONLY : 0},
&platform_);
EXPECT_CALL(manager_,
DoMount(kSourcePath, filesystem_type_, options_, mount_path, _))
.WillOnce(DoAll(SetArgPointee<4>(MOUNT_ERROR_NONE),
Return(ByMove(std::move(ptr)))));
manager_.Mount(kSourcePath, filesystem_type_, options_, GetMountCallback());
EXPECT_TRUE(mount_completed_);
EXPECT_EQ(MOUNT_ERROR_NONE, mount_error_);
EXPECT_EQ(kMountPath, mount_path_);
EXPECT_TRUE(manager_.IsMountPathInCache(mount_path_));
{
const MountPoint* const mount_point =
manager_.FindMountBySource(kSourcePath);
ASSERT_TRUE(mount_point);
EXPECT_TRUE(mount_point->is_read_only());
}
EXPECT_CALL(platform_, Unmount(mount_path_, _))
.WillOnce(Return(MOUNT_ERROR_NONE));
EXPECT_CALL(platform_, RemoveEmptyDirectory(mount_path_))
.WillOnce(Return(true));
}
// Verifies that MountManager::Mount() stores correct mount status in cache when
// the mounter requested to mount in read-write mode but fell back to read-only
// mode.
TEST_F(MountManagerTest, MountSuccededWithReadOnlyFallback) {
EXPECT_CALL(manager_, SuggestMountPath(kSourcePath))
.WillOnce(Return(kMountPath));
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
.WillOnce(Return(true));
options_.push_back("rw");
// Emulate Mounter added read-only option as a fallback.
const base::FilePath mount_path(kMountPath);
auto ptr = std::make_unique<MountPoint>(
MountPointData{.mount_path = mount_path, .flags = MS_RDONLY}, &platform_);
EXPECT_CALL(manager_,
DoMount(kSourcePath, filesystem_type_, options_, mount_path, _))
.WillOnce(DoAll(SetArgPointee<4>(MOUNT_ERROR_NONE),
Return(ByMove(std::move(ptr)))));
manager_.Mount(kSourcePath, filesystem_type_, options_, GetMountCallback());
EXPECT_TRUE(mount_completed_);
EXPECT_EQ(MOUNT_ERROR_NONE, mount_error_);
EXPECT_EQ(kMountPath, mount_path_);
EXPECT_TRUE(manager_.IsMountPathInCache(mount_path_));
{
const MountPoint* const mount_point =
manager_.FindMountBySource(kSourcePath);
ASSERT_TRUE(mount_point);
EXPECT_TRUE(mount_point->is_read_only());
}
EXPECT_CALL(platform_, Unmount(mount_path_, _))
.WillOnce(Return(MOUNT_ERROR_NONE));
EXPECT_CALL(platform_, RemoveEmptyDirectory(mount_path_))
.WillOnce(Return(true));
}
// Verifies that MountManager::Mount() returns no error when it successfully
// mounts a source path with no mount path specified.
TEST_F(MountManagerTest, MountSucceededWithEmptyMountPath) {
EXPECT_CALL(manager_, SuggestMountPath(kSourcePath))
.WillOnce(Return(kMountPath));
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
.WillOnce(Return(true));
const base::FilePath mount_path(kMountPath);
auto ptr = std::make_unique<MountPoint>(
MountPointData{.mount_path = mount_path,
.flags = IsReadOnlyMount(options_) ? MS_RDONLY : 0},
&platform_);
EXPECT_CALL(manager_,
DoMount(kSourcePath, filesystem_type_, options_, mount_path, _))
.WillOnce(DoAll(SetArgPointee<4>(MOUNT_ERROR_NONE),
Return(ByMove(std::move(ptr)))));
manager_.Mount(kSourcePath, filesystem_type_, options_, GetMountCallback());
EXPECT_TRUE(mount_completed_);
EXPECT_EQ(MOUNT_ERROR_NONE, mount_error_);
EXPECT_EQ(kMountPath, mount_path_);
EXPECT_TRUE(manager_.IsMountPathInCache(mount_path_));
EXPECT_CALL(platform_, Unmount(mount_path_, _))
.WillOnce(Return(MOUNT_ERROR_NONE));
EXPECT_CALL(platform_, RemoveEmptyDirectory(mount_path_))
.WillOnce(Return(true));
manager_.UnmountAll();
EXPECT_FALSE(manager_.IsMountPathInCache(mount_path_));
}
// Verifies that MountManager::Mount() returns no error when it successfully
// mounts a source path with a given mount label in options.
TEST_F(MountManagerTest, MountSucceededWithGivenMountLabel) {
const std::string final_mount_path =
base::StrCat({kMountRootDirectory, "/custom_label"});
options_.push_back("mountlabel=custom_label");
std::vector<std::string> updated_options;
EXPECT_CALL(manager_, SuggestMountPath(kSourcePath))
.WillOnce(Return(kMountPath));
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
.WillOnce(Return(true));
const base::FilePath mount_path(final_mount_path);
auto ptr = std::make_unique<MountPoint>(
MountPointData{.mount_path = mount_path,
.flags = IsReadOnlyMount(options_) ? MS_RDONLY : 0},
&platform_);
EXPECT_CALL(manager_,
DoMount(kSourcePath, filesystem_type_, _, mount_path, _))
.WillOnce(DoAll(SetArgPointee<4>(MOUNT_ERROR_NONE),
Return(ByMove(std::move(ptr)))));
manager_.Mount(kSourcePath, filesystem_type_, options_, GetMountCallback());
EXPECT_TRUE(mount_completed_);
EXPECT_EQ(MOUNT_ERROR_NONE, mount_error_);
EXPECT_EQ(final_mount_path, mount_path_);
EXPECT_TRUE(manager_.IsMountPathInCache(mount_path_));
EXPECT_CALL(platform_, Unmount(final_mount_path, _))
.WillOnce(Return(MOUNT_ERROR_NONE));
EXPECT_CALL(platform_, RemoveEmptyDirectory(final_mount_path))
.WillOnce(Return(true));
manager_.UnmountAll();
EXPECT_FALSE(manager_.IsMountPathInCache(mount_path_));
}
// Verifies that MountManager::Mount() handles the mounting of an already
// mounted source path properly.
TEST_F(MountManagerTest, MountWithAlreadyMountedSourcePath) {
EXPECT_CALL(manager_, SuggestMountPath(kSourcePath))
.WillOnce(Return(kMountPath));
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
.WillOnce(Return(true));
const base::FilePath mount_path(kMountPath);
auto ptr = std::make_unique<MountPoint>(
MountPointData{.mount_path = mount_path,
.flags = IsReadOnlyMount(options_) ? MS_RDONLY : 0},
&platform_);
EXPECT_CALL(manager_,
DoMount(kSourcePath, filesystem_type_, options_, mount_path, _))
.WillOnce(DoAll(SetArgPointee<4>(MOUNT_ERROR_NONE),
Return(ByMove(std::move(ptr)))));
manager_.Mount(kSourcePath, filesystem_type_, options_, GetMountCallback());
EXPECT_TRUE(mount_completed_);
EXPECT_EQ(MOUNT_ERROR_NONE, mount_error_);
EXPECT_EQ(kMountPath, mount_path_);
EXPECT_TRUE(manager_.IsMountPathInCache(mount_path_));
// Mount an already-mounted source path
manager_.Mount(kSourcePath, filesystem_type_, options_, GetMountCallback());
EXPECT_TRUE(mount_completed_);
EXPECT_EQ(MOUNT_ERROR_NONE, mount_error_);
EXPECT_EQ(kMountPath, mount_path_);
EXPECT_TRUE(manager_.IsMountPathInCache(mount_path_));
// Mount an already-mounted source path
manager_.Mount(kSourcePath, filesystem_type_, options_, GetMountCallback());
EXPECT_TRUE(mount_completed_);
EXPECT_EQ(MOUNT_ERROR_NONE, mount_error_);
EXPECT_EQ(kMountPath, mount_path_);
EXPECT_TRUE(manager_.IsMountPathInCache(mount_path_));
// Unmount
EXPECT_CALL(platform_, Unmount(kMountPath, _))
.WillOnce(Return(MOUNT_ERROR_NONE));
EXPECT_CALL(platform_, RemoveEmptyDirectory(kMountPath))
.WillOnce(Return(true));
manager_.UnmountAll();
EXPECT_FALSE(manager_.IsMountPathInCache(kMountPath));
}
// Verifies that MountManager::Mount() successfully reserves a path for a given
// type of error. A specific mount path is given in this case.
TEST_F(MountManagerTest, MountSucceededWithGivenMountPathInReservedCase) {
EXPECT_CALL(manager_, SuggestMountPath(kSourcePath))
.WillOnce(Return(kMountPath));
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
.WillOnce(Return(true));
EXPECT_CALL(manager_, DoMount(kSourcePath, filesystem_type_, options_,
base::FilePath(kMountPath), _))
.WillOnce(DoAll(SetArgPointee<4>(MOUNT_ERROR_UNKNOWN_FILESYSTEM),
Return(ByMove(nullptr))));
EXPECT_CALL(manager_,
ShouldReserveMountPathOnError(MOUNT_ERROR_UNKNOWN_FILESYSTEM))
.WillOnce(Return(true));
manager_.Mount(kSourcePath, filesystem_type_, options_, GetMountCallback());
EXPECT_TRUE(mount_completed_);
EXPECT_EQ(MOUNT_ERROR_UNKNOWN_FILESYSTEM, mount_error_);
EXPECT_EQ(kMountPath, mount_path_);
EXPECT_TRUE(manager_.IsMountPathInCache(mount_path_));
EXPECT_CALL(platform_, RemoveEmptyDirectory(kMountPath))
.WillOnce(Return(true));
manager_.UnmountAll();
EXPECT_FALSE(manager_.IsMountPathInCache(mount_path_));
}
// Verifies that MountManager::Mount() successfully reserves a path for a given
// type of error. No specific mount path is given in this case.
TEST_F(MountManagerTest, MountSucceededWithEmptyMountPathInReservedCase) {
EXPECT_CALL(manager_, SuggestMountPath(kSourcePath))
.WillOnce(Return(kMountPath));
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectory(_)).Times(0);
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
.WillOnce(Return(true));
EXPECT_CALL(platform_, RemoveEmptyDirectory(kMountPath))
.WillOnce(Return(true));
EXPECT_CALL(manager_, DoMount(kSourcePath, filesystem_type_, options_,
base::FilePath(kMountPath), _))
.WillOnce(DoAll(SetArgPointee<4>(MOUNT_ERROR_UNKNOWN_FILESYSTEM),
Return(ByMove(nullptr))));
EXPECT_CALL(manager_,
ShouldReserveMountPathOnError(MOUNT_ERROR_UNKNOWN_FILESYSTEM))
.WillOnce(Return(true));
manager_.Mount(kSourcePath, filesystem_type_, options_, GetMountCallback());
EXPECT_TRUE(mount_completed_);
EXPECT_EQ(MOUNT_ERROR_UNKNOWN_FILESYSTEM, mount_error_);
EXPECT_EQ(kMountPath, mount_path_);
EXPECT_TRUE(manager_.IsMountPathInCache(mount_path_));
manager_.UnmountAll();
EXPECT_FALSE(manager_.IsMountPathInCache(mount_path_));
}
// Verifies that MountManager::Mount() successfully reserves a path for a given
// type of error and returns the same error when it tries to mount the same path
// again.
TEST_F(MountManagerTest, MountSucceededWithAlreadyReservedMountPath) {
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectory(_)).Times(0);
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
.WillOnce(Return(true));
EXPECT_CALL(platform_, RemoveEmptyDirectory(kMountPath))
.WillOnce(Return(true));
EXPECT_CALL(manager_, DoMount(kSourcePath, filesystem_type_, options_,
base::FilePath(kMountPath), _))
.WillOnce(DoAll(SetArgPointee<4>(MOUNT_ERROR_UNKNOWN_FILESYSTEM),
Return(ByMove(nullptr))));
EXPECT_CALL(manager_,
ShouldReserveMountPathOnError(MOUNT_ERROR_UNKNOWN_FILESYSTEM))
.WillOnce(Return(true));
EXPECT_CALL(manager_, SuggestMountPath(kSourcePath))
.WillOnce(Return(kMountPath));
manager_.Mount(kSourcePath, filesystem_type_, options_, GetMountCallback());
EXPECT_TRUE(mount_completed_);
EXPECT_EQ(MOUNT_ERROR_UNKNOWN_FILESYSTEM, mount_error_);
EXPECT_EQ(kMountPath, mount_path_);
EXPECT_TRUE(manager_.IsMountPathInCache(mount_path_));
manager_.Mount(kSourcePath, filesystem_type_, options_, GetMountCallback());
EXPECT_TRUE(mount_completed_);
EXPECT_EQ(MOUNT_ERROR_UNKNOWN_FILESYSTEM, mount_error_);
EXPECT_EQ(kMountPath, mount_path_);
EXPECT_TRUE(manager_.IsMountPathInCache(mount_path_));
manager_.UnmountAll();
EXPECT_FALSE(manager_.IsMountPathInCache(mount_path_));
}
// Verifies that MountManager::Mount() successfully reserves a path for a given
// type of error and returns the same error when it tries to mount the same path
// again.
TEST_F(MountManagerTest, MountFailedWithGivenMountPathInReservedCase) {
EXPECT_CALL(manager_, SuggestMountPath(kSourcePath))
.WillOnce(Return(kMountPath));
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
.WillOnce(Return(true));
EXPECT_CALL(platform_, RemoveEmptyDirectory(kMountPath))
.WillOnce(Return(true));
EXPECT_CALL(manager_, DoMount(kSourcePath, filesystem_type_, options_,
base::FilePath(kMountPath), _))
.WillOnce(DoAll(SetArgPointee<4>(MOUNT_ERROR_UNKNOWN_FILESYSTEM),
Return(ByMove(nullptr))));
EXPECT_CALL(manager_,
ShouldReserveMountPathOnError(MOUNT_ERROR_UNKNOWN_FILESYSTEM))
.WillOnce(Return(true));
manager_.Mount(kSourcePath, filesystem_type_, options_, GetMountCallback());
EXPECT_TRUE(mount_completed_);
EXPECT_EQ(MOUNT_ERROR_UNKNOWN_FILESYSTEM, mount_error_);
EXPECT_EQ(kMountPath, mount_path_);
EXPECT_TRUE(manager_.IsMountPathInCache(mount_path_));
}
// Verifies that MountManager::Mount() fails to mount or reserve a path for
// a type of error that is not enabled for reservation.
TEST_F(MountManagerTest, MountFailedWithEmptyMountPathInReservedCase) {
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectory(_)).Times(0);
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
.WillOnce(Return(true));
EXPECT_CALL(platform_, RemoveEmptyDirectory(kMountPath))
.WillOnce(Return(true));
EXPECT_CALL(manager_, DoMount(kSourcePath, filesystem_type_, options_,
base::FilePath(kMountPath), _))
.WillOnce(DoAll(SetArgPointee<4>(MOUNT_ERROR_UNKNOWN_FILESYSTEM),
Return(ByMove(nullptr))));
EXPECT_CALL(manager_,
ShouldReserveMountPathOnError(MOUNT_ERROR_UNKNOWN_FILESYSTEM))
.WillOnce(Return(false));
EXPECT_CALL(manager_, SuggestMountPath(kSourcePath))
.WillOnce(Return(kMountPath));
manager_.Mount(kSourcePath, filesystem_type_, options_, GetMountCallback());
EXPECT_TRUE(mount_completed_);
EXPECT_EQ(MOUNT_ERROR_UNKNOWN_FILESYSTEM, mount_error_);
EXPECT_EQ("", mount_path_);
EXPECT_FALSE(manager_.IsMountPathInCache(mount_path_));
}
// Verifies that MountManager::Unmount() returns an error when it is invoked
// to unmount an empty path.
TEST_F(MountManagerTest, UnmountFailedWithEmptyPath) {
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectory(_)).Times(0);
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
.Times(0);
EXPECT_CALL(platform_, RemoveEmptyDirectory(_)).Times(0);
EXPECT_CALL(manager_, DoMount(_, _, _, _, _)).Times(0);
EXPECT_CALL(manager_, SuggestMountPath(_)).Times(0);
EXPECT_EQ(MOUNT_ERROR_PATH_NOT_MOUNTED, manager_.Unmount(mount_path_));
}
// Verifies that MountManager::Unmount() returns an error when it fails to
// unmount a path that is not mounted.
TEST_F(MountManagerTest, UnmountFailedWithPathNotMounted) {
mount_path_ = "nonexistent-path";
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectory(_)).Times(0);
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
.Times(0);
EXPECT_CALL(platform_, RemoveEmptyDirectory(_)).Times(0);
EXPECT_CALL(manager_, DoMount(_, _, _, _, _)).Times(0);
EXPECT_CALL(manager_, SuggestMountPath(_)).Times(0);
EXPECT_EQ(MOUNT_ERROR_PATH_NOT_MOUNTED, manager_.Unmount(mount_path_));
}
// Verifies that MountManager::Unmount() returns no error when it successfully
// unmounts a source path.
TEST_F(MountManagerTest, UnmountSucceededWithGivenSourcePath) {
EXPECT_CALL(manager_, SuggestMountPath(kSourcePath))
.WillOnce(Return(kMountPath));
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
.WillOnce(Return(true));
const base::FilePath mount_path(kMountPath);
auto ptr = std::make_unique<MountPoint>(
MountPointData{.mount_path = mount_path,
.flags = IsReadOnlyMount(options_) ? MS_RDONLY : 0},
&platform_);
EXPECT_CALL(manager_,
DoMount(kSourcePath, filesystem_type_, options_, mount_path, _))
.WillOnce(DoAll(SetArgPointee<4>(MOUNT_ERROR_NONE),
Return(ByMove(std::move(ptr)))));
manager_.Mount(kSourcePath, filesystem_type_, options_, GetMountCallback());
EXPECT_TRUE(mount_completed_);
EXPECT_EQ(MOUNT_ERROR_NONE, mount_error_);
EXPECT_EQ(kMountPath, mount_path_);
EXPECT_TRUE(manager_.IsMountPathInCache(mount_path_));
EXPECT_CALL(platform_, Unmount(mount_path_, _))
.WillOnce(Return(MOUNT_ERROR_NONE));
EXPECT_CALL(platform_, RemoveEmptyDirectory(mount_path_))
.WillOnce(Return(true));
EXPECT_EQ(MOUNT_ERROR_NONE, manager_.Unmount(kSourcePath));
EXPECT_FALSE(manager_.IsMountPathInCache(mount_path_));
}
// Verifies that MountManager::Unmount() returns no error when it successfully
// unmounts a mount path.
TEST_F(MountManagerTest, UnmountSucceededWithGivenMountPath) {
EXPECT_CALL(manager_, SuggestMountPath(kSourcePath))
.WillOnce(Return(kMountPath));
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
.WillOnce(Return(true));
const base::FilePath mount_path(kMountPath);
auto ptr = std::make_unique<MountPoint>(
MountPointData{.mount_path = mount_path,
.flags = IsReadOnlyMount(options_) ? MS_RDONLY : 0},
&platform_);
EXPECT_CALL(manager_,
DoMount(kSourcePath, filesystem_type_, options_, mount_path, _))
.WillOnce(DoAll(SetArgPointee<4>(MOUNT_ERROR_NONE),
Return(ByMove(std::move(ptr)))));
manager_.Mount(kSourcePath, filesystem_type_, options_, GetMountCallback());
EXPECT_TRUE(mount_completed_);
EXPECT_EQ(MOUNT_ERROR_NONE, mount_error_);
EXPECT_EQ(kMountPath, mount_path_);
EXPECT_TRUE(manager_.IsMountPathInCache(mount_path_));
EXPECT_CALL(platform_, Unmount(mount_path_, _))
.WillOnce(Return(MOUNT_ERROR_NONE));
EXPECT_CALL(platform_, RemoveEmptyDirectory(mount_path_))
.WillOnce(Return(true));
EXPECT_EQ(MOUNT_ERROR_NONE, manager_.Unmount(mount_path_));
EXPECT_FALSE(manager_.IsMountPathInCache(mount_path_));
}
// Verifies that MountManager::Unmount() removes mount path from cache if
// it appears to be not mounted.
TEST_F(MountManagerTest, UnmountRemovesFromCacheIfNotMounted) {
EXPECT_CALL(manager_, SuggestMountPath(kSourcePath))
.WillOnce(Return(kMountPath));
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
.WillOnce(Return(true));
const base::FilePath mount_path(kMountPath);
auto ptr = std::make_unique<MountPoint>(
MountPointData{.mount_path = mount_path,
.flags = IsReadOnlyMount(options_) ? MS_RDONLY : 0},
&platform_);
EXPECT_CALL(manager_,
DoMount(kSourcePath, filesystem_type_, options_, mount_path, _))
.WillOnce(DoAll(SetArgPointee<4>(MOUNT_ERROR_NONE),
Return(ByMove(std::move(ptr)))));
manager_.Mount(kSourcePath, filesystem_type_, options_, GetMountCallback());
EXPECT_TRUE(mount_completed_);
EXPECT_EQ(MOUNT_ERROR_NONE, mount_error_);
EXPECT_EQ(kMountPath, mount_path_);
EXPECT_TRUE(manager_.IsMountPathInCache(mount_path_));
EXPECT_CALL(platform_, Unmount(mount_path_, _))
.WillOnce(Return(MOUNT_ERROR_PATH_NOT_MOUNTED));
EXPECT_CALL(platform_, RemoveEmptyDirectory(mount_path_))
.WillOnce(Return(true));
EXPECT_EQ(MOUNT_ERROR_NONE, manager_.Unmount(mount_path_));
EXPECT_FALSE(manager_.IsMountPathInCache(mount_path_));
}
// Verifies that MountManager::Unmount() returns no error when it is invoked
// to unmount the source path of a reserved mount path.
TEST_F(MountManagerTest, UnmountSucceededWithGivenSourcePathInReservedCase) {
EXPECT_CALL(manager_, SuggestMountPath(kSourcePath))
.WillOnce(Return(kMountPath));
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
.WillOnce(Return(true));
const base::FilePath mount_path(kMountPath);
EXPECT_CALL(manager_,
DoMount(kSourcePath, filesystem_type_, options_, mount_path, _))
.WillOnce(DoAll(SetArgPointee<4>(MOUNT_ERROR_UNKNOWN_FILESYSTEM),
Return(ByMove(nullptr))));
EXPECT_CALL(manager_,
ShouldReserveMountPathOnError(MOUNT_ERROR_UNKNOWN_FILESYSTEM))
.WillOnce(Return(true));
manager_.Mount(kSourcePath, filesystem_type_, options_, GetMountCallback());
EXPECT_TRUE(mount_completed_);
EXPECT_EQ(MOUNT_ERROR_UNKNOWN_FILESYSTEM, mount_error_);
EXPECT_EQ(kMountPath, mount_path_);
EXPECT_TRUE(manager_.IsMountPathInCache(mount_path_));
EXPECT_CALL(platform_, Unmount).Times(0);
EXPECT_CALL(platform_, RemoveEmptyDirectory(mount_path_))
.WillOnce(Return(true));
EXPECT_EQ(MOUNT_ERROR_NONE, manager_.Unmount(kSourcePath));
EXPECT_FALSE(manager_.IsMountPathInCache(mount_path_));
}
// Verifies that MountManager::Unmount() returns no error when it is invoked
// to unmount a reserved mount path.
TEST_F(MountManagerTest, UnmountSucceededWithGivenMountPathInReservedCase) {
EXPECT_CALL(manager_, SuggestMountPath(kSourcePath))
.WillOnce(Return(kMountPath));
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
.WillOnce(Return(true));
const base::FilePath mount_path(kMountPath);
EXPECT_CALL(manager_,
DoMount(kSourcePath, filesystem_type_, options_, mount_path, _))
.WillOnce(DoAll(SetArgPointee<4>(MOUNT_ERROR_UNKNOWN_FILESYSTEM),
Return(ByMove(nullptr))));
EXPECT_CALL(manager_,
ShouldReserveMountPathOnError(MOUNT_ERROR_UNKNOWN_FILESYSTEM))
.WillOnce(Return(true));
manager_.Mount(kSourcePath, filesystem_type_, options_, GetMountCallback());
EXPECT_TRUE(mount_completed_);
EXPECT_EQ(MOUNT_ERROR_UNKNOWN_FILESYSTEM, mount_error_);
EXPECT_EQ(kMountPath, mount_path_);
EXPECT_TRUE(manager_.IsMountPathInCache(mount_path_));
EXPECT_CALL(platform_, Unmount).Times(0);
EXPECT_CALL(platform_, RemoveEmptyDirectory(mount_path_))
.WillOnce(Return(true));
EXPECT_EQ(MOUNT_ERROR_NONE, manager_.Unmount(mount_path_));
EXPECT_FALSE(manager_.IsMountPathInCache(mount_path_));
}
// Verifies that MountManager::IsMountPathInCache() works as expected.
TEST_F(MountManagerTest, IsMountPathInCache) {
mount_path_ = kMountPath;
EXPECT_FALSE(manager_.IsMountPathInCache(mount_path_));
manager_.AddMount(MakeMountPoint(mount_path_));
EXPECT_TRUE(manager_.IsMountPathInCache(mount_path_));
EXPECT_CALL(platform_, RemoveEmptyDirectory(mount_path_))
.WillOnce(Return(true));
EXPECT_TRUE(manager_.RemoveMountPathFromCache(mount_path_));
EXPECT_FALSE(manager_.IsMountPathInCache(mount_path_));
}
// Verifies that MountManager::RemoveMountPathFromCache() works as expected.
TEST_F(MountManagerTest, RemoveMountPathFromCache) {
mount_path_ = kMountPath;
EXPECT_FALSE(manager_.RemoveMountPathFromCache(mount_path_));
manager_.AddMount(MakeMountPoint(mount_path_));
EXPECT_CALL(platform_, RemoveEmptyDirectory(mount_path_))
.WillOnce(Return(true));
EXPECT_TRUE(manager_.RemoveMountPathFromCache(mount_path_));
EXPECT_FALSE(manager_.RemoveMountPathFromCache(mount_path_));
}
// Verifies that MountManager::GetMountPoints() returns the expected list of
// mount entries under different scenarios.
TEST_F(MountManagerTest, GetMountPoints) {
// No mount entry is returned.
EXPECT_THAT(manager_.GetMountPoints(), IsEmpty());
// A normal mount entry is returned.
manager_.AddMount(MakeMountPoint(kMountPath));
const std::vector<const MountPoint*> mount_points = manager_.GetMountPoints();
ASSERT_THAT(mount_points, SizeIs(1));
EXPECT_EQ(MOUNT_ERROR_NONE, mount_points[0]->error());
EXPECT_EQ(kSourcePath, mount_points[0]->source());
EXPECT_EQ(MOUNT_SOURCE_REMOVABLE_DEVICE, mount_points[0]->source_type());
EXPECT_EQ(base::FilePath(kMountPath), mount_points[0]->path());
EXPECT_CALL(platform_, RemoveEmptyDirectory(kMountPath))
.WillOnce(Return(true));
}
// Verifies that MountManager::IsPathImmediateChildOfParent() correctly
// determines if a path is an immediate child of another path.
TEST_F(MountManagerTest, IsPathImmediateChildOfParent) {
EXPECT_TRUE(manager_.IsPathImmediateChildOfParent(
base::FilePath("/media/archive/test.zip"),
base::FilePath("/media/archive")));
EXPECT_TRUE(manager_.IsPathImmediateChildOfParent(
base::FilePath("/media/archive/test.zip/"),
base::FilePath("/media/archive")));
EXPECT_TRUE(manager_.IsPathImmediateChildOfParent(
base::FilePath("/media/archive/test.zip"),
base::FilePath("/media/archive/")));
EXPECT_TRUE(manager_.IsPathImmediateChildOfParent(
base::FilePath("/media/archive/test.zip/"),
base::FilePath("/media/archive/")));
EXPECT_FALSE(manager_.IsPathImmediateChildOfParent(
base::FilePath("/media/archive/test.zip/doc.zip"),
base::FilePath("/media/archive/")));
EXPECT_FALSE(manager_.IsPathImmediateChildOfParent(
base::FilePath("/media/archive/test.zip"),
base::FilePath("/media/removable")));
EXPECT_FALSE(manager_.IsPathImmediateChildOfParent(
base::FilePath("/tmp/archive/test.zip"),
base::FilePath("/media/removable")));
EXPECT_FALSE(manager_.IsPathImmediateChildOfParent(
base::FilePath("/media"), base::FilePath("/media/removable")));
EXPECT_FALSE(manager_.IsPathImmediateChildOfParent(
base::FilePath("/media/removable"), base::FilePath("/media/removable")));
EXPECT_FALSE(manager_.IsPathImmediateChildOfParent(
base::FilePath("/media/removable/"), base::FilePath("/media/removable")));
EXPECT_FALSE(manager_.IsPathImmediateChildOfParent(
base::FilePath("/media/removable/."),
base::FilePath("/media/removable")));
EXPECT_FALSE(manager_.IsPathImmediateChildOfParent(
base::FilePath("/media/removable/.."),
base::FilePath("/media/removable")));
}
// Verifies that MountManager::IsValidMountPath() correctly determines if a
// mount path is an immediate child of the mount root.
TEST_F(MountManagerTest, IsValidMountPath) {
EXPECT_TRUE(
manager_.IsValidMountPath(base::FilePath("/media/removable/test")));
EXPECT_TRUE(
manager_.IsValidMountPath(base::FilePath("/media/removable/test/")));
EXPECT_TRUE(
manager_.IsValidMountPath(base::FilePath("/media/removable/test/")));
EXPECT_TRUE(
manager_.IsValidMountPath(base::FilePath("/media/removable//test")));
EXPECT_FALSE(
manager_.IsValidMountPath(base::FilePath("/media/archive/test")));
EXPECT_FALSE(manager_.IsValidMountPath(base::FilePath("/media/removable")));
EXPECT_FALSE(manager_.IsValidMountPath(base::FilePath("/media/removable/")));
EXPECT_FALSE(manager_.IsValidMountPath(base::FilePath("/media/removable/.")));
EXPECT_FALSE(
manager_.IsValidMountPath(base::FilePath("/media/removable/..")));
EXPECT_FALSE(
manager_.IsValidMountPath(base::FilePath("/media/removable/test/doc")));
EXPECT_FALSE(
manager_.IsValidMountPath(base::FilePath("/media/removable/../test")));
EXPECT_FALSE(
manager_.IsValidMountPath(base::FilePath("/media/removable/../test/")));
EXPECT_FALSE(
manager_.IsValidMountPath(base::FilePath("/media/removable/test/..")));
EXPECT_FALSE(
manager_.IsValidMountPath(base::FilePath("/media/removable/test/../")));
}
// Verifies that MountManager::Mount() returns an error when the source is
// not mounted yet but attempted to remount it.
TEST_F(MountManagerTest, RemountFailedNotMounted) {
options_.push_back("remount");
EXPECT_CALL(manager_, DoMount(_, _, _, _, _)).Times(0);
// source = kSourcePath has not been mounted yet.
manager_.Mount(kSourcePath, filesystem_type_, options_, GetMountCallback());
EXPECT_TRUE(mount_completed_);
EXPECT_EQ(MOUNT_ERROR_PATH_NOT_MOUNTED, mount_error_);
}
// Verifies that MountManager::Mount() returns no error when it successfully
// remounts a source path on a specified mount path.
TEST_F(MountManagerTest, RemountSucceededWithGivenSourcePath) {
// Mount a device in read-write mode.
base::FilePath mount_path(kMountPath);
EXPECT_CALL(manager_, SuggestMountPath(_)).WillOnce(Return(kMountPath));
EXPECT_CALL(platform_, CreateOrReuseEmptyDirectoryWithFallback(_, _, _))
.WillOnce(Return(true));
auto ptr = std::make_unique<MountPoint>(
MountPointData{.mount_path = mount_path, .flags = 0}, &platform_);
EXPECT_CALL(manager_,
DoMount(kSourcePath, filesystem_type_, _, mount_path, _))
.WillOnce(DoAll(SetArgPointee<4>(MOUNT_ERROR_NONE),
Return(ByMove(std::move(ptr)))));
manager_.Mount(kSourcePath, filesystem_type_, {"rw"}, GetMountCallback());
EXPECT_TRUE(mount_completed_);
EXPECT_EQ(MOUNT_ERROR_NONE, mount_error_);
EXPECT_EQ(kMountPath, mount_path_);
{
const MountPoint* const mount_point =
manager_.FindMountBySource(kSourcePath);
ASSERT_TRUE(mount_point);
EXPECT_FALSE(mount_point->is_read_only());
EXPECT_EQ(base::FilePath(kMountPath), mount_point->path());
}
// Remount with read-only mount option.
EXPECT_CALL(platform_, Mount(kSourcePath, kMountPath, filesystem_type_,
MS_RDONLY | MS_REMOUNT, _))
.WillOnce(Return(MOUNT_ERROR_NONE));
manager_.Mount(kSourcePath, filesystem_type_, {"remount", "ro"},
GetMountCallback());
EXPECT_TRUE(mount_completed_);
EXPECT_EQ(MOUNT_ERROR_NONE, mount_error_);
EXPECT_EQ(kMountPath, mount_path_);
EXPECT_TRUE(manager_.IsMountPathInCache(mount_path_));
{
const MountPoint* const mount_point =
manager_.FindMountBySource(kSourcePath);
ASSERT_TRUE(mount_point);
EXPECT_TRUE(mount_point->is_read_only());
}
// Should be unmounted correctly even after remount.
EXPECT_CALL(platform_, Unmount(kMountPath, _))
.WillOnce(Return(MOUNT_ERROR_NONE));
EXPECT_CALL(platform_, RemoveEmptyDirectory(kMountPath))
.WillOnce(Return(true));
manager_.UnmountAll();
EXPECT_FALSE(manager_.IsMountPathInCache(kMountPath));
}
} // namespace cros_disks