blob: e01252b67a963ed6ab3241d39158ddff1a3958de [file] [log] [blame]
// Copyright 2018 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.
#include "cros-disks/fuse_mount_manager.h"
#include <string>
#include <utility>
#include <vector>
#include <base/strings/string_util.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include "cros-disks/fuse_helper.h"
#include "cros-disks/metrics.h"
#include "cros-disks/mount_options.h"
#include "cros-disks/platform.h"
using std::set;
using std::string;
using std::vector;
using testing::DoAll;
using testing::Eq;
using testing::Invoke;
using testing::Return;
using testing::SetArgPointee;
using testing::UnorderedElementsAre;
using testing::_;
namespace cros_disks {
namespace {
const char kMountRoot[] = "/mntroot";
const char kNoType[] = "";
const char kSomeSource[] = "/dev/sdz";
const char kSomeMountpoint[] = "/mnt";
// Mock Platform implementation for testing.
class MockPlatform : public Platform {
public:
MockPlatform() = default;
MOCK_CONST_METHOD1(Unmount, bool(const string& path));
};
// Mock implementation of FUSEHelper.
class MockHelper : public FUSEHelper {
public:
MockHelper(const string& tag, const Platform* platform)
: FUSEHelper(tag, platform, "/sbin/" + tag, "fuse-" + tag) {}
MOCK_CONST_METHOD1(CanMount, bool(const string& src));
MOCK_CONST_METHOD1(GetTargetSuffix, string(const string& src));
MOCK_CONST_METHOD3(Mount,
MountErrorType(const string& src,
const string& dst,
const vector<string>& opts));
};
} // namespace
class FUSEMountManagerTest : public ::testing::Test {
public:
FUSEMountManagerTest()
: manager_(kMountRoot, &platform_, &metrics_),
foo_(new MockHelper("foo", &platform_)),
bar_(new MockHelper("bar", &platform_)),
baz_(new MockHelper("baz", &platform_)) {
ON_CALL(platform_, Unmount(_)).WillByDefault(Return(false));
}
protected:
void RegisterHelper(std::unique_ptr<FUSEHelper> helper) {
manager_.RegisterHelper(std::move(helper));
}
MountErrorType DoMount(const string& type, const string& src) {
MountOptions mount_options;
return manager_.DoMount(src, type, {}, kSomeMountpoint, &mount_options);
}
Metrics metrics_;
MockPlatform platform_;
FUSEMountManager manager_;
std::unique_ptr<MockHelper> foo_;
std::unique_ptr<MockHelper> bar_;
std::unique_ptr<MockHelper> baz_;
};
// Verifies that CanMount returns false when there are no handlers registered.
TEST_F(FUSEMountManagerTest, CanMount_NoHandlers) {
EXPECT_FALSE(manager_.CanMount(kSomeSource));
}
// Verifies that CanMount returns false when known helpers can't handle that.
TEST_F(FUSEMountManagerTest, CanMount_NotHandled) {
EXPECT_CALL(*foo_, CanMount(_)).WillOnce(Return(false));
EXPECT_CALL(*bar_, CanMount(_)).WillOnce(Return(false));
EXPECT_CALL(*baz_, CanMount(_)).WillOnce(Return(false));
RegisterHelper(std::move(foo_));
RegisterHelper(std::move(bar_));
RegisterHelper(std::move(baz_));
EXPECT_FALSE(manager_.CanMount(kSomeSource));
}
// Verify that CanMount returns true when there is a helper that can handle
// this source.
TEST_F(FUSEMountManagerTest, CanMount) {
EXPECT_CALL(*foo_, CanMount(_)).WillOnce(Return(false));
EXPECT_CALL(*bar_, CanMount(_)).WillOnce(Return(true));
EXPECT_CALL(*baz_, CanMount(_)).Times(0);
RegisterHelper(std::move(foo_));
RegisterHelper(std::move(bar_));
RegisterHelper(std::move(baz_));
EXPECT_TRUE(manager_.CanMount(kSomeSource));
}
// Verify that SuggestMountPath dispatches query for name to the correct helper.
TEST_F(FUSEMountManagerTest, SuggestMountPath) {
EXPECT_CALL(*foo_, CanMount(_)).WillOnce(Return(false));
EXPECT_CALL(*foo_, GetTargetSuffix(_)).Times(0);
EXPECT_CALL(*bar_, CanMount(_)).WillOnce(Return(true));
EXPECT_CALL(*bar_, GetTargetSuffix(kSomeSource)).WillOnce(Return("suffix"));
EXPECT_CALL(*baz_, CanMount(_)).Times(0);
EXPECT_CALL(*baz_, GetTargetSuffix(_)).Times(0);
RegisterHelper(std::move(foo_));
RegisterHelper(std::move(bar_));
RegisterHelper(std::move(baz_));
EXPECT_EQ("/mntroot/suffix", manager_.SuggestMountPath(kSomeSource));
}
// Verify that DoUnmount delegates unmount directly to platform.
TEST_F(FUSEMountManagerTest, DoUnmount) {
EXPECT_CALL(platform_, Unmount(kSomeSource)).WillOnce(Return(true));
EXPECT_CALL(platform_, Unmount("foobar")).WillOnce(Return(false));
EXPECT_EQ(MOUNT_ERROR_NONE, manager_.DoUnmount(kSomeSource, {}));
EXPECT_NE(MOUNT_ERROR_NONE, manager_.DoUnmount("foobar", {}));
}
// Verify that DoMount fails when there are not helpers.
TEST_F(FUSEMountManagerTest, DoMount_NoHandlers) {
EXPECT_EQ(MOUNT_ERROR_UNKNOWN_FILESYSTEM, DoMount(kNoType, kSomeSource));
}
// Verify that DoMount fails when helpers don't handle this source.
TEST_F(FUSEMountManagerTest, DoMount_NotHandled) {
EXPECT_CALL(*foo_, CanMount(_)).WillOnce(Return(false));
EXPECT_CALL(*bar_, CanMount(_)).WillOnce(Return(false));
EXPECT_CALL(*baz_, CanMount(_)).WillOnce(Return(false));
RegisterHelper(std::move(foo_));
RegisterHelper(std::move(bar_));
RegisterHelper(std::move(baz_));
EXPECT_EQ(MOUNT_ERROR_UNKNOWN_FILESYSTEM, DoMount(kNoType, kSomeSource));
}
// Verify that DoMount delegates mounting to the correct helpers when
// dispatching by source description.
TEST_F(FUSEMountManagerTest, DoMount_BySource) {
EXPECT_CALL(*foo_, CanMount(_)).WillOnce(Return(false));
EXPECT_CALL(*bar_, CanMount(_)).WillRepeatedly(Return(true));
EXPECT_CALL(*baz_, CanMount(_)).Times(0);
EXPECT_CALL(*foo_, Mount(_, _, _)).Times(0);
EXPECT_CALL(*bar_, Mount(kSomeSource, kSomeMountpoint, _))
.WillOnce(Return(MOUNT_ERROR_NONE));
EXPECT_CALL(*baz_, Mount(_, _, _)).Times(0);
RegisterHelper(std::move(foo_));
RegisterHelper(std::move(bar_));
RegisterHelper(std::move(baz_));
EXPECT_EQ(MOUNT_ERROR_NONE, DoMount(kNoType, kSomeSource));
}
} // namespace cros_disks