blob: af685905453882bb7f6a75b6f22f1e6758592a86 [file] [log] [blame]
Sergei Datsenko0f014d22018-04-04 16:37:22 +10001// Copyright 2018 The Chromium OS Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "cros-disks/fuse_mount_manager.h"
6
Anand K Mistry68418e62018-08-22 11:37:04 +10007#include <sys/mount.h>
8
Sergei Datsenko0f014d22018-04-04 16:37:22 +10009#include <string>
10#include <utility>
11#include <vector>
12
13#include <base/strings/string_util.h>
Simon Glass2b1da092020-05-21 12:24:16 -060014#include <brillo/process/process_reaper.h>
Sergei Datsenko0f014d22018-04-04 16:37:22 +100015#include <gmock/gmock.h>
16#include <gtest/gtest.h>
17
Sergei Datsenkobcd8e462018-04-20 15:44:56 +100018#include "cros-disks/fuse_mounter.h"
Sergei Datsenko0f014d22018-04-04 16:37:22 +100019#include "cros-disks/metrics.h"
20#include "cros-disks/mount_options.h"
Anand K Mistry25a5f852020-01-14 17:08:39 +110021#include "cros-disks/mount_point.h"
Sergei Datsenko0f014d22018-04-04 16:37:22 +100022#include "cros-disks/platform.h"
Sergei Datsenko88035aa2020-11-15 00:24:01 +110023#include "cros-disks/sandboxed_process.h"
Sergei Datsenkobcd8e462018-04-20 15:44:56 +100024#include "cros-disks/uri.h"
Sergei Datsenko0f014d22018-04-04 16:37:22 +100025
Anand K Mistry9f4611e2019-12-19 16:06:39 +110026using testing::_;
Sergei Datsenkobcd8e462018-04-20 15:44:56 +100027using testing::ByMove;
Sergei Datsenko0f014d22018-04-04 16:37:22 +100028using testing::DoAll;
Sergei Datsenko0f014d22018-04-04 16:37:22 +100029using testing::Return;
30using testing::SetArgPointee;
Anand K Mistry9f4611e2019-12-19 16:06:39 +110031using testing::WithArg;
Sergei Datsenko0f014d22018-04-04 16:37:22 +100032
33namespace cros_disks {
34
35namespace {
36
37const char kMountRoot[] = "/mntroot";
Sergei Datsenkobcd8e462018-04-20 15:44:56 +100038const char kWorkingDirRoot[] = "/wkdir";
Sergei Datsenko0f014d22018-04-04 16:37:22 +100039const char kNoType[] = "";
Sergei Datsenko0f014d22018-04-04 16:37:22 +100040const char kSomeMountpoint[] = "/mnt";
Sergei Datsenkobcd8e462018-04-20 15:44:56 +100041const Uri kSomeSource("fuse", "something");
Sergei Datsenko0f014d22018-04-04 16:37:22 +100042
43// Mock Platform implementation for testing.
44class MockPlatform : public Platform {
45 public:
46 MockPlatform() = default;
47
Ben Chanef8e6032019-09-27 08:24:56 -070048 MOCK_METHOD(MountErrorType,
Sergei Datsenko199f4f42020-10-08 10:47:12 +110049 Mount,
50 (const std::string& source,
51 const std::string& target,
52 const std::string& filesystem_type,
53 uint64_t flags,
54 const std::string& options),
55 (const, override));
56 MOCK_METHOD(MountErrorType,
Ben Chanef8e6032019-09-27 08:24:56 -070057 Unmount,
58 (const std::string&, int),
59 (const, override));
60 MOCK_METHOD(bool, DirectoryExists, (const std::string&), (const, override));
61 MOCK_METHOD(bool, CreateDirectory, (const std::string&), (const, override));
62 MOCK_METHOD(bool,
63 SetPermissions,
64 (const std::string&, mode_t),
65 (const, override));
66 MOCK_METHOD(bool,
67 CreateTemporaryDirInDir,
68 (const std::string&, const std::string&, std::string*),
69 (const, override));
Sergei Datsenko0f014d22018-04-04 16:37:22 +100070};
71
Sergei Datsenkof3ebcc32020-12-07 23:47:56 +110072// Mock implementation of a Mounter.
73class MockMounter : public Mounter {
Sergei Datsenko0f014d22018-04-04 16:37:22 +100074 public:
Sergei Datsenkof3ebcc32020-12-07 23:47:56 +110075 MOCK_METHOD(std::unique_ptr<MountPoint>,
76 Mount,
77 (const std::string& source,
78 const base::FilePath& target_path,
79 std::vector<std::string> params,
80 MountErrorType* error),
81 (const, override));
82 MOCK_METHOD(bool,
83 CanMount,
84 (const std::string& source,
85 const std::vector<std::string>& params,
86 base::FilePath* suggested_dir_name),
Ben Chanef8e6032019-09-27 08:24:56 -070087 (const, override));
Sergei Datsenkobcd8e462018-04-20 15:44:56 +100088};
89
Sergei Datsenko88035aa2020-11-15 00:24:01 +110090class MockSandboxedProcess : public SandboxedProcess {
91 public:
92 MockSandboxedProcess() = default;
93 pid_t StartImpl(base::ScopedFD, base::ScopedFD, base::ScopedFD) override {
94 return 123;
95 }
96 MOCK_METHOD(int, WaitImpl, (), (override));
97 MOCK_METHOD(int, WaitNonBlockingImpl, (), (override));
98};
99
Sergei Datsenko0f014d22018-04-04 16:37:22 +1000100} // namespace
101
102class FUSEMountManagerTest : public ::testing::Test {
103 public:
104 FUSEMountManagerTest()
Sergei Datsenkoa910bba2019-06-18 13:31:59 +1000105 : manager_(kMountRoot,
106 kWorkingDirRoot,
107 &platform_,
108 &metrics_,
109 &process_reaper_),
Sergei Datsenkof3ebcc32020-12-07 23:47:56 +1100110 foo_(new MockMounter()),
111 bar_(new MockMounter()),
112 baz_(new MockMounter()) {
Sergei Datsenko85a18332019-04-08 14:25:03 +1000113 ON_CALL(platform_, Unmount(_, _))
Sergei Datsenkob362e4a2019-04-03 17:23:24 +1100114 .WillByDefault(Return(MOUNT_ERROR_INVALID_ARGUMENT));
Sergei Datsenkobcd8e462018-04-20 15:44:56 +1000115 ON_CALL(platform_, DirectoryExists(_)).WillByDefault(Return(true));
Sergei Datsenko0f014d22018-04-04 16:37:22 +1000116 }
117
118 protected:
Sergei Datsenkof3ebcc32020-12-07 23:47:56 +1100119 void RegisterHelper(std::unique_ptr<Mounter> helper) {
Sergei Datsenko0f014d22018-04-04 16:37:22 +1000120 manager_.RegisterHelper(std::move(helper));
121 }
122
Anand K Mistry25a5f852020-01-14 17:08:39 +1100123 std::unique_ptr<MountPoint> DoMount(const std::string& type,
124 const std::string& src,
125 MountErrorType* error) {
Sergei Datsenko3928f782020-12-31 09:14:04 +1100126 std::unique_ptr<MountPoint> mount_point =
Nigel Taoca7a4ef2021-05-14 11:44:25 +1000127 manager_.DoMount(src, type, {}, base::FilePath(kSomeMountpoint), error);
Anand K Mistry25a5f852020-01-14 17:08:39 +1100128 if (*error == MOUNT_ERROR_NONE) {
129 EXPECT_TRUE(mount_point);
130 } else {
131 EXPECT_FALSE(mount_point);
132 }
133 return mount_point;
Sergei Datsenko0f014d22018-04-04 16:37:22 +1000134 }
135
136 Metrics metrics_;
137 MockPlatform platform_;
Sergei Datsenkoa910bba2019-06-18 13:31:59 +1000138 brillo::ProcessReaper process_reaper_;
Sergei Datsenko0f014d22018-04-04 16:37:22 +1000139 FUSEMountManager manager_;
Sergei Datsenkof3ebcc32020-12-07 23:47:56 +1100140 std::unique_ptr<MockMounter> foo_;
141 std::unique_ptr<MockMounter> bar_;
142 std::unique_ptr<MockMounter> baz_;
Sergei Datsenko0f014d22018-04-04 16:37:22 +1000143};
144
145// Verifies that CanMount returns false when there are no handlers registered.
146TEST_F(FUSEMountManagerTest, CanMount_NoHandlers) {
Sergei Datsenkobcd8e462018-04-20 15:44:56 +1000147 EXPECT_FALSE(manager_.CanMount(kSomeSource.value()));
Sergei Datsenko0f014d22018-04-04 16:37:22 +1000148}
149
150// Verifies that CanMount returns false when known helpers can't handle that.
151TEST_F(FUSEMountManagerTest, CanMount_NotHandled) {
Sergei Datsenkof3ebcc32020-12-07 23:47:56 +1100152 EXPECT_CALL(*foo_, CanMount).WillOnce(Return(false));
153 EXPECT_CALL(*bar_, CanMount).WillOnce(Return(false));
154 EXPECT_CALL(*baz_, CanMount).WillOnce(Return(false));
Sergei Datsenko0f014d22018-04-04 16:37:22 +1000155 RegisterHelper(std::move(foo_));
156 RegisterHelper(std::move(bar_));
157 RegisterHelper(std::move(baz_));
Sergei Datsenkobcd8e462018-04-20 15:44:56 +1000158 EXPECT_FALSE(manager_.CanMount(kSomeSource.value()));
Sergei Datsenko0f014d22018-04-04 16:37:22 +1000159}
160
161// Verify that CanMount returns true when there is a helper that can handle
162// this source.
163TEST_F(FUSEMountManagerTest, CanMount) {
Sergei Datsenkof3ebcc32020-12-07 23:47:56 +1100164 EXPECT_CALL(*foo_, CanMount).WillOnce(Return(false));
165 EXPECT_CALL(*bar_, CanMount).WillOnce(Return(true));
166 EXPECT_CALL(*baz_, CanMount).Times(0);
Sergei Datsenko0f014d22018-04-04 16:37:22 +1000167 RegisterHelper(std::move(foo_));
168 RegisterHelper(std::move(bar_));
169 RegisterHelper(std::move(baz_));
Sergei Datsenkobcd8e462018-04-20 15:44:56 +1000170 EXPECT_TRUE(manager_.CanMount(kSomeSource.value()));
Sergei Datsenko0f014d22018-04-04 16:37:22 +1000171}
172
173// Verify that SuggestMountPath dispatches query for name to the correct helper.
174TEST_F(FUSEMountManagerTest, SuggestMountPath) {
Sergei Datsenkof3ebcc32020-12-07 23:47:56 +1100175 EXPECT_CALL(*foo_, CanMount).WillOnce(Return(false));
176 EXPECT_CALL(*bar_, CanMount)
177 .WillOnce(
178 DoAll(SetArgPointee<2>(base::FilePath("suffix")), Return(true)));
179 EXPECT_CALL(*baz_, CanMount).Times(0);
Sergei Datsenko0f014d22018-04-04 16:37:22 +1000180 RegisterHelper(std::move(foo_));
181 RegisterHelper(std::move(bar_));
182 RegisterHelper(std::move(baz_));
Sergei Datsenkobcd8e462018-04-20 15:44:56 +1000183 EXPECT_EQ("/mntroot/suffix", manager_.SuggestMountPath(kSomeSource.value()));
Sergei Datsenko0f014d22018-04-04 16:37:22 +1000184}
185
Sergei Datsenkof3ebcc32020-12-07 23:47:56 +1100186// Verify that DoMount fails when there are no helpers.
Sergei Datsenko0f014d22018-04-04 16:37:22 +1000187TEST_F(FUSEMountManagerTest, DoMount_NoHandlers) {
Anand K Mistry25a5f852020-01-14 17:08:39 +1100188 MountErrorType mount_error;
189 std::unique_ptr<MountPoint> mount_point =
190 DoMount(kNoType, kSomeSource.value(), &mount_error);
191 EXPECT_EQ(MOUNT_ERROR_UNKNOWN_FILESYSTEM, mount_error);
Sergei Datsenko0f014d22018-04-04 16:37:22 +1000192}
193
194// Verify that DoMount fails when helpers don't handle this source.
195TEST_F(FUSEMountManagerTest, DoMount_NotHandled) {
Sergei Datsenkof3ebcc32020-12-07 23:47:56 +1100196 EXPECT_CALL(*foo_, CanMount).WillOnce(Return(false));
197 EXPECT_CALL(*bar_, CanMount).WillOnce(Return(false));
198 EXPECT_CALL(*baz_, CanMount).WillOnce(Return(false));
Sergei Datsenko0f014d22018-04-04 16:37:22 +1000199 RegisterHelper(std::move(foo_));
200 RegisterHelper(std::move(bar_));
201 RegisterHelper(std::move(baz_));
Anand K Mistry25a5f852020-01-14 17:08:39 +1100202 MountErrorType mount_error;
203 std::unique_ptr<MountPoint> mount_point =
204 DoMount(kNoType, kSomeSource.value(), &mount_error);
205 EXPECT_EQ(MOUNT_ERROR_UNKNOWN_FILESYSTEM, mount_error);
Sergei Datsenko0f014d22018-04-04 16:37:22 +1000206}
207
208// Verify that DoMount delegates mounting to the correct helpers when
209// dispatching by source description.
210TEST_F(FUSEMountManagerTest, DoMount_BySource) {
Sergei Datsenkof3ebcc32020-12-07 23:47:56 +1100211 EXPECT_CALL(*foo_, CanMount).WillOnce(Return(false));
212 EXPECT_CALL(*bar_, CanMount)
Sergei Datsenko88035aa2020-11-15 00:24:01 +1100213 .WillOnce(
Sergei Datsenkof3ebcc32020-12-07 23:47:56 +1100214 DoAll(SetArgPointee<2>(base::FilePath("suffix")), Return(true)));
215 EXPECT_CALL(*baz_, CanMount).Times(0);
216
217 EXPECT_CALL(*foo_, Mount).Times(0);
218 EXPECT_CALL(*baz_, Mount).Times(0);
219
220 EXPECT_CALL(*bar_, Mount(kSomeSource.value(), _, _, _))
221 .WillOnce(DoAll(SetArgPointee<3>(MOUNT_ERROR_NONE),
222 Return(ByMove(MountPoint::CreateLeaking(
223 base::FilePath(kSomeMountpoint))))));
224
Sergei Datsenko0f014d22018-04-04 16:37:22 +1000225 RegisterHelper(std::move(foo_));
226 RegisterHelper(std::move(bar_));
227 RegisterHelper(std::move(baz_));
Anand K Mistry25a5f852020-01-14 17:08:39 +1100228 MountErrorType mount_error;
229 std::unique_ptr<MountPoint> mount_point =
230 DoMount(kNoType, kSomeSource.value(), &mount_error);
231 EXPECT_EQ(MOUNT_ERROR_NONE, mount_error);
232 EXPECT_EQ(base::FilePath(kSomeMountpoint), mount_point->path());
Sergei Datsenko0f014d22018-04-04 16:37:22 +1000233}
234
235} // namespace cros_disks