[go: nahoru, domu]

blob: b51dda5968bddbfc10bc58f97f7201f51abc46d1 [file] [log] [blame]
Avi Drissman4a8573c2022-09-09 19:35:541// Copyright 2018 The Chromium Authors
Joel Hockey5dc76e982018-11-13 22:44:392// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
Henrique Ferreirod67f0472022-11-05 00:40:095#include "chrome/browser/ash/extensions/file_manager/event_router.h"
Ben Reichb0cba5c2022-06-15 10:26:226
7#include <memory>
8
9#include "base/files/file_path.h"
10#include "base/files/file_util.h"
11#include "base/files/scoped_temp_dir.h"
12#include "base/rand_util.h"
13#include "base/run_loop.h"
14#include "base/test/bind.h"
15#include "base/test/gmock_callback_support.h"
Joel Hockey5dc76e982018-11-13 22:44:3916#include "base/values.h"
Henrique Ferreirod67f0472022-11-05 00:40:0917#include "chrome/browser/ash/extensions/file_manager/event_router_factory.h"
Ben Reichb0cba5c2022-06-15 10:26:2218#include "chrome/browser/ash/file_manager/io_task.h"
19#include "chrome/browser/ash/file_manager/path_util.h"
20#include "chrome/browser/ash/file_manager/volume_manager_factory.h"
Joel Hockeyd096e542023-08-07 06:01:2421#include "chrome/browser/ash/fileapi/file_system_backend.h"
Ben Reichb0cba5c2022-06-15 10:26:2222#include "chrome/test/base/testing_profile.h"
Momoko Hattori57ddbd82023-06-30 03:10:2923#include "chromeos/ash/components/disks/fake_disk_mount_manager.h"
Ben Reichb0cba5c2022-06-15 10:26:2224#include "content/public/test/browser_task_environment.h"
25#include "extensions/browser/event_router.h"
26#include "extensions/browser/test_event_router.h"
Bo Majewski3e6cd34f2021-06-03 04:30:0327#include "extensions/common/extension.h"
Ben Reichb0cba5c2022-06-15 10:26:2228#include "storage/browser/file_system/external_mount_points.h"
Hans Wennborg4c71bc62022-12-06 14:05:2329#include "storage/browser/quota/quota_manager_proxy.h"
Ben Reichb0cba5c2022-06-15 10:26:2230#include "storage/browser/test/test_file_system_context.h"
31#include "testing/gmock/include/gmock/gmock.h"
Joel Hockey5dc76e982018-11-13 22:44:3932#include "testing/gtest/include/gtest/gtest.h"
Ben Reichb0cba5c2022-06-15 10:26:2233#include "third_party/blink/public/common/storage_key/storage_key.h"
Eriko Kurimotof95a6af2023-12-11 02:53:1134#include "ui/display/test/test_screen.h"
Bo Majewski3e6cd34f2021-06-03 04:30:0335#include "url/gurl.h"
36#include "url/origin.h"
Joel Hockey5dc76e982018-11-13 22:44:3937
38namespace file_manager {
39
Joel Hockey298eee4b2021-06-01 05:49:5440TEST(EventRouterTest, PopulateCrostiniEvent) {
Bo Majewski3e6cd34f2021-06-03 04:30:0341 extensions::api::file_manager_private::CrostiniEvent ext_event;
42 url::Origin ext_origin = url::Origin::Create(
43 extensions::Extension::GetBaseURLFromExtensionId("extensionid"));
Joel Hockey298eee4b2021-06-01 05:49:5444 EventRouter::PopulateCrostiniEvent(
Bo Majewski3e6cd34f2021-06-03 04:30:0345 ext_event,
Claudio DeSouza8fd15442023-11-06 00:26:5546 extensions::api::file_manager_private::CrostiniEventType::kUnshare,
Bo Majewski3e6cd34f2021-06-03 04:30:0347 "vmname", ext_origin, "mountname", "filesystemname", "/full/path");
Joel Hockey5dc76e982018-11-13 22:44:3948
Bo Majewski3e6cd34f2021-06-03 04:30:0349 EXPECT_EQ(ext_event.event_type,
Claudio DeSouza8fd15442023-11-06 00:26:5550 extensions::api::file_manager_private::CrostiniEventType::kUnshare);
Bo Majewski3e6cd34f2021-06-03 04:30:0351 EXPECT_EQ(ext_event.vm_name, "vmname");
52 EXPECT_EQ(ext_event.entries.size(), 1u);
Allen Bauer76651722022-12-21 17:39:3653 base::Value::Dict ext_props;
54 ext_props.Set(
Joel Hockey5dc76e982018-11-13 22:44:3955 "fileSystemRoot",
56 "filesystem:chrome-extension://extensionid/external/mountname/");
Allen Bauer76651722022-12-21 17:39:3657 ext_props.Set("fileSystemName", "filesystemname");
58 ext_props.Set("fileFullPath", "/full/path");
59 ext_props.Set("fileIsDirectory", true);
Bo Majewski3e6cd34f2021-06-03 04:30:0360 EXPECT_EQ(ext_event.entries[0].additional_properties, ext_props);
61
62 extensions::api::file_manager_private::CrostiniEvent swa_event;
63 url::Origin swa_origin = url::Origin::Create(
64 GURL("chrome://file-manager/this-part-should-not-be-in?the=event"));
65 EventRouter::PopulateCrostiniEvent(
66 swa_event,
Claudio DeSouza8fd15442023-11-06 00:26:5567 extensions::api::file_manager_private::CrostiniEventType::kShare,
Bo Majewski3e6cd34f2021-06-03 04:30:0368 "vmname", swa_origin, "mountname", "filesystemname", "/full/path");
69
70 EXPECT_EQ(swa_event.event_type,
Claudio DeSouza8fd15442023-11-06 00:26:5571 extensions::api::file_manager_private::CrostiniEventType::kShare);
Bo Majewski3e6cd34f2021-06-03 04:30:0372 EXPECT_EQ(swa_event.vm_name, "vmname");
73 EXPECT_EQ(swa_event.entries.size(), 1u);
Allen Bauer76651722022-12-21 17:39:3674 base::Value::Dict swa_props;
75 swa_props.Set("fileSystemRoot",
76 "filesystem:chrome://file-manager/external/mountname/");
77 swa_props.Set("fileSystemName", "filesystemname");
78 swa_props.Set("fileFullPath", "/full/path");
79 swa_props.Set("fileIsDirectory", true);
Bo Majewski3e6cd34f2021-06-03 04:30:0380 EXPECT_EQ(swa_event.entries[0].additional_properties, swa_props);
Joel Hockey5dc76e982018-11-13 22:44:3981}
82
Ben Reichb0cba5c2022-06-15 10:26:2283namespace {
84
85using ::base::test::RunClosure;
86using ::testing::_;
87using ::testing::AllOf;
88using ::testing::Field;
89
90// Observes the `BroadcastEvent` operation that is emitted by the event router.
91// The mock methods are used to assert expectations on the return results.
92class TestEventRouterObserver
93 : public extensions::TestEventRouter::EventObserver {
94 public:
95 explicit TestEventRouterObserver(extensions::TestEventRouter* event_router)
96 : event_router_(event_router) {
97 event_router_->AddEventObserver(this);
98 }
99 ~TestEventRouterObserver() override {
100 event_router_->RemoveEventObserver(this);
101 }
102 TestEventRouterObserver(const TestEventRouterObserver&) = delete;
103 TestEventRouterObserver& operator=(const TestEventRouterObserver&) = delete;
104
105 // TestEventRouter::EventObserver:
106 MOCK_METHOD(void, OnBroadcastEvent, (const extensions::Event&), (override));
107 MOCK_METHOD(void,
108 OnDispatchEventToExtension,
109 (const std::string&, const extensions::Event&),
110 (override));
111
112 private:
113 raw_ptr<extensions::TestEventRouter> event_router_;
114};
115
116class FileManagerEventRouterTest : public testing::Test {
117 public:
118 FileManagerEventRouterTest() = default;
119 FileManagerEventRouterTest(const FileManagerEventRouterTest&) = delete;
120 FileManagerEventRouterTest& operator=(const FileManagerEventRouterTest&) =
121 delete;
122
123 void SetUp() override {
124 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
125
126 profile_ =
127 std::make_unique<TestingProfile>(base::FilePath(temp_dir_.GetPath()));
128 file_system_context_ = storage::CreateFileSystemContextForTesting(
129 nullptr, temp_dir_.GetPath());
130
131 VolumeManagerFactory::GetInstance()->SetTestingFactory(
132 profile_.get(),
133 base::BindLambdaForTesting([this](content::BrowserContext* context) {
134 return std::unique_ptr<KeyedService>(std::make_unique<VolumeManager>(
135 Profile::FromBrowserContext(context), nullptr, nullptr,
136 &disk_mount_manager_, nullptr,
137 VolumeManager::GetMtpStorageInfoCallback()));
138 }));
139
140 storage::ExternalMountPoints::GetSystemInstance()->RegisterFileSystem(
141 file_manager::util::GetDownloadsMountPointName(profile_.get()),
142 storage::kFileSystemTypeLocal, storage::FileSystemMountOption(),
143 temp_dir_.GetPath());
144
Joel Hockeyd096e542023-08-07 06:01:24145 auto* context = file_manager::util::GetFileSystemContextForSourceURL(
146 profile_.get(), GURL("chrome-extension://abc"));
147 ash::FileSystemBackend::Get(*context)->GrantFileAccessToOrigin(
148 url::Origin::Create(GURL("chrome-extension://abc")),
149 base::FilePath(
150 file_manager::util::GetDownloadsMountPointName(profile_.get())));
Ben Reichb0cba5c2022-06-15 10:26:22151 }
152
153 const io_task::EntryStatus CreateSuccessfulEntryStatusForFileName(
154 const std::string& file_name) {
155 const base::FilePath file_path = temp_dir_.GetPath().Append(file_name);
156 EXPECT_TRUE(base::WriteFile(file_path, base::RandBytesAsString(32)));
157
158 storage::FileSystemURL url =
159 file_system_context_->CreateCrackedFileSystemURL(
160 kTestStorageKey, storage::kFileSystemTypeTest, file_path);
161
162 return io_task::EntryStatus(std::move(url), base::File::FILE_OK);
163 }
164
165 content::BrowserTaskEnvironment task_environment_;
Eriko Kurimotof95a6af2023-12-11 02:53:11166 display::test::TestScreen test_screen_{/*create_dispay=*/true,
167 /*register_screen=*/true};
Ben Reichb0cba5c2022-06-15 10:26:22168 base::ScopedTempDir temp_dir_;
169 std::unique_ptr<TestingProfile> profile_;
170 const blink::StorageKey kTestStorageKey =
171 blink::StorageKey::CreateFromStringForTesting("chrome-extension://abc");
172 scoped_refptr<storage::FileSystemContext> file_system_context_;
Momoko Hattori57ddbd82023-06-30 03:10:29173 ash::disks::FakeDiskMountManager disk_mount_manager_;
Ben Reichb0cba5c2022-06-15 10:26:22174};
175
176// A matcher that matches an `extensions::Event::event_args` and attempts to
177// extract the "outputs" key. It then looks at the output at `index` and matches
178// the `field` against the `expected_value`.
179MATCHER_P3(ExpectEventArgString, index, field, expected_value, "") {
Henrique Ferreiro3fce49e2022-09-28 11:37:08180 EXPECT_GE(arg.size(), 1u);
Matt Menke1266cb32023-01-03 22:42:01181 const base::Value::List* outputs = arg[0].GetDict().FindList("outputs");
Ben Reichb0cba5c2022-06-15 10:26:22182 EXPECT_TRUE(outputs) << "The outputs field is not available on the event";
Matt Menke1266cb32023-01-03 22:42:01183 EXPECT_GT(outputs->size(), index)
Ben Reichb0cba5c2022-06-15 10:26:22184 << "The supplied index on outputs is not available, size: "
Matt Menke1266cb32023-01-03 22:42:01185 << outputs->size() << ", index: " << index;
Matt Menkeaf77da792022-06-22 19:10:54186 const std::string* actual_value =
Matt Menke1266cb32023-01-03 22:42:01187 (*outputs)[index].GetDict().FindString(field);
Ben Reichb0cba5c2022-06-15 10:26:22188 EXPECT_TRUE(actual_value) << "Could not find the string with key: " << field;
189 return testing::ExplainMatchResult(expected_value, *actual_value,
190 result_listener);
191}
192
Aya ElAttar49289d92023-06-22 02:06:38193// A matcher that matches an `extensions::Event::event_args` and attempts to
Aida Zoliccf5953f2023-07-07 11:01:24194// extract the "conflictParams" and "pauseParams" keys. It expects
195// "conflictParams" to be empty, and then matches the "policyParams" values
Aida Zolica78b77c2023-07-13 09:58:11196// against the expected ones.
Luca Accorsi0ff12e52023-10-13 08:33:43197MATCHER_P4(ExpectEventArgPauseParams,
Aida Zolica78b77c2023-07-13 09:58:11198 expected_type,
199 expected_count,
200 expected_file_name,
Luca Accorsi0ff12e52023-10-13 08:33:43201 expected_always_show_review,
Aida Zolica78b77c2023-07-13 09:58:11202 "") {
Aya ElAttar49289d92023-06-22 02:06:38203 EXPECT_GE(arg.size(), 1u);
204 const base::Value::Dict* pause_params =
205 arg[0].GetDict().FindDict("pauseParams");
206 EXPECT_TRUE(pause_params)
207 << "The pause_params field is not available on the event";
208
209 const base::Value::Dict* conflict_pause_params =
210 pause_params->FindDict("conflictParams");
211 EXPECT_FALSE(conflict_pause_params)
Aida Zoliccf5953f2023-07-07 11:01:24212 << "The conflictParams field should not be available on the event";
Aya ElAttar49289d92023-06-22 02:06:38213
214 const base::Value::Dict* policy_pause_params =
215 pause_params->FindDict("policyParams");
216 EXPECT_TRUE(policy_pause_params)
217 << "The policyParams field is not available on the event";
Aida Zoliccf5953f2023-07-07 11:01:24218 const std::string* actual_type = policy_pause_params->FindString("type");
219 EXPECT_TRUE(actual_type) << "Could not find the string with key: type";
Mohamed Mansour5cf92142023-12-08 23:12:12220 const std::optional<int> actual_count =
Aida Zoliccf5953f2023-07-07 11:01:24221 policy_pause_params->FindInt("policyFileCount");
222 EXPECT_TRUE(actual_count.has_value())
223 << "Could not find the number with key: type";
Aida Zolica78b77c2023-07-13 09:58:11224 const std::string* actual_file_name =
225 policy_pause_params->FindString("fileName");
226 EXPECT_TRUE(actual_file_name)
227 << "Could not find the string with key: fileName";
Mohamed Mansour5cf92142023-12-08 23:12:12228 const std::optional<bool> actual_always_show_review =
Luca Accorsi0ff12e52023-10-13 08:33:43229 policy_pause_params->FindBool("alwaysShowReview");
230 EXPECT_TRUE(actual_always_show_review.has_value())
231 << "Could not find the string with key: alwaysShowReview";
Aida Zoliccf5953f2023-07-07 11:01:24232 return testing::ExplainMatchResult(expected_type, *actual_type,
233 result_listener) &&
234 testing::ExplainMatchResult(expected_count, actual_count.value(),
Aida Zolica78b77c2023-07-13 09:58:11235 result_listener) &&
236 testing::ExplainMatchResult(expected_file_name, *actual_file_name,
Luca Accorsi0ff12e52023-10-13 08:33:43237 result_listener) &&
238 testing::ExplainMatchResult(expected_always_show_review,
239 actual_always_show_review.value(),
Aya ElAttar49289d92023-06-22 02:06:38240 result_listener);
241}
242
243// A matcher that matches an `extensions::Event::event_args` and attempts to
Aida Zoliccf5953f2023-07-07 11:01:24244// extract the "policyError" key. It then matches the "policyError" values
Aida Zolica78b77c2023-07-13 09:58:11245// against the expected ones.
Luca Accorsi0ff12e52023-10-13 08:33:43246MATCHER_P4(ExpectEventArgPolicyError,
Aida Zolica78b77c2023-07-13 09:58:11247 expected_type,
248 expected_count,
249 expected_file_name,
Luca Accorsi0ff12e52023-10-13 08:33:43250 expected_always_show_review,
Aida Zolica78b77c2023-07-13 09:58:11251 "") {
Aya ElAttar49289d92023-06-22 02:06:38252 EXPECT_GE(arg.size(), 1u);
Aida Zoliccf5953f2023-07-07 11:01:24253 const base::Value::Dict* policy_error =
254 arg[0].GetDict().FindDict("policyError");
Aya ElAttar49289d92023-06-22 02:06:38255 EXPECT_TRUE(policy_error)
256 << "The policyError field is not available on the event";
257
Aida Zoliccf5953f2023-07-07 11:01:24258 const std::string* actual_type = policy_error->FindString("type");
259 EXPECT_TRUE(actual_type) << "Could not find the string with key: type";
Mohamed Mansour5cf92142023-12-08 23:12:12260 const std::optional<int> actual_count =
Aida Zoliccf5953f2023-07-07 11:01:24261 policy_error->FindInt("policyFileCount");
262 EXPECT_TRUE(actual_count.has_value())
263 << "Could not find the string with key: type";
Aida Zolica78b77c2023-07-13 09:58:11264 const std::string* actual_file_name = policy_error->FindString("fileName");
265 EXPECT_TRUE(actual_file_name)
266 << "Could not find the string with key: fileName";
Mohamed Mansour5cf92142023-12-08 23:12:12267 const std::optional<bool> actual_always_show_review =
Luca Accorsi0ff12e52023-10-13 08:33:43268 policy_error->FindBool("alwaysShowReview");
269 EXPECT_TRUE(actual_always_show_review.has_value())
270 << "Could not find the string with key: alwaysShowReview";
Aida Zoliccf5953f2023-07-07 11:01:24271 return testing::ExplainMatchResult(expected_type, *actual_type,
272 result_listener) &&
273 testing::ExplainMatchResult(expected_count, actual_count.value(),
Aida Zolica78b77c2023-07-13 09:58:11274 result_listener) &&
275 testing::ExplainMatchResult(expected_file_name, *actual_file_name,
Luca Accorsi0ff12e52023-10-13 08:33:43276 result_listener) &&
277 testing::ExplainMatchResult(expected_always_show_review,
278 actual_always_show_review.value(),
Aya ElAttar49289d92023-06-22 02:06:38279 result_listener);
280}
281
Ben Reichb0cba5c2022-06-15 10:26:22282TEST_F(FileManagerEventRouterTest, OnIOTaskStatusForTrash) {
283 // Setup event routers.
284 extensions::TestEventRouter* test_event_router =
285 extensions::CreateAndUseTestEventRouter(profile_.get());
286 TestEventRouterObserver observer(test_event_router);
287 auto event_router = std::make_unique<EventRouter>(profile_.get());
288 event_router->ForceBroadcastingForTesting(true);
289
290 io_task::EntryStatus source_entry =
291 CreateSuccessfulEntryStatusForFileName("foo.txt");
292 io_task::EntryStatus output_entry =
293 CreateSuccessfulEntryStatusForFileName("bar.txt");
294
295 std::vector<io_task::EntryStatus> source_entries;
296 source_entries.push_back(std::move(source_entry));
297 std::vector<io_task::EntryStatus> output_entries;
298 output_entries.push_back(std::move(output_entry));
299
300 // Setup the ProgressStatus event that expects
301 file_manager::io_task::ProgressStatus status;
302 status.type = file_manager::io_task::OperationType::kTrash;
303 status.state = file_manager::io_task::State::kSuccess;
304 status.sources = std::move(source_entries);
305 status.outputs = std::move(output_entries);
306
307 base::RunLoop run_loop;
308 EXPECT_CALL(
309 observer,
310 OnBroadcastEvent(Field(
311 &extensions::Event::event_args,
Henrique Ferreiroc7faeda2022-10-07 08:09:46312 AllOf(ExpectEventArgString(0u, "fileFullPath", "/bar.txt"),
313 ExpectEventArgString(0u, "fileSystemName", "Downloads"),
Ben Reichb0cba5c2022-06-15 10:26:22314 ExpectEventArgString(
Henrique Ferreiroc7faeda2022-10-07 08:09:46315 0u, "fileSystemRoot",
Ben Reichb0cba5c2022-06-15 10:26:22316 "filesystem:chrome-extension://abc/external/Downloads/")))))
317 .WillOnce(RunClosure(run_loop.QuitClosure()));
318
319 event_router->OnIOTaskStatus(status);
320 run_loop.Run();
321}
322
Aya ElAttar49289d92023-06-22 02:06:38323TEST_F(FileManagerEventRouterTest, OnIOTaskStatusForCopyPause) {
324 // Setup event routers.
325 extensions::TestEventRouter* test_event_router =
326 extensions::CreateAndUseTestEventRouter(profile_.get());
327 TestEventRouterObserver observer(test_event_router);
328 auto event_router = std::make_unique<EventRouter>(profile_.get());
329 event_router->ForceBroadcastingForTesting(true);
330
331 io_task::EntryStatus source_entry =
332 CreateSuccessfulEntryStatusForFileName("foo.txt");
333
334 std::vector<io_task::EntryStatus> source_entries;
335 source_entries.push_back(std::move(source_entry));
336
337 // Setup the ProgressStatus event.
338 file_manager::io_task::ProgressStatus status;
339 status.type = file_manager::io_task::OperationType::kCopy;
340 status.state = file_manager::io_task::State::kPaused;
341 status.sources = std::move(source_entries);
Aida Zoliccf5953f2023-07-07 11:01:24342 status.pause_params.policy_params = io_task::PolicyPauseParams(
Luca Accorsi0ff12e52023-10-13 08:33:43343 policy::Policy::kDlp, /*warning_files_count*/ 2u, "foo.txt",
344 /*always_show_review=*/false);
Aya ElAttar49289d92023-06-22 02:06:38345
346 // Expect the event to have dlp as policy pause params.
347 base::RunLoop run_loop;
Luca Accorsi0ff12e52023-10-13 08:33:43348 EXPECT_CALL(observer,
349 OnBroadcastEvent(Field(&extensions::Event::event_args,
350 AllOf(ExpectEventArgPauseParams(
351 "dlp", 2, "foo.txt", false)))))
Aya ElAttar49289d92023-06-22 02:06:38352 .WillOnce(RunClosure(run_loop.QuitClosure()));
353
354 event_router->OnIOTaskStatus(status);
355 run_loop.Run();
356}
357
358TEST_F(FileManagerEventRouterTest, OnIOTaskStatusForPolicyError) {
359 // Setup event routers.
360 extensions::TestEventRouter* test_event_router =
361 extensions::CreateAndUseTestEventRouter(profile_.get());
362 TestEventRouterObserver observer(test_event_router);
363 auto event_router = std::make_unique<EventRouter>(profile_.get());
364 event_router->ForceBroadcastingForTesting(true);
365
366 io_task::EntryStatus source_entry =
367 CreateSuccessfulEntryStatusForFileName("foo.txt");
368
369 std::vector<io_task::EntryStatus> source_entries;
370 source_entries.push_back(std::move(source_entry));
371
372 // Setup the ProgressStatus event.
373 file_manager::io_task::ProgressStatus status;
374 status.type = file_manager::io_task::OperationType::kCopy;
375 status.state = file_manager::io_task::State::kError;
376 status.sources = std::move(source_entries);
Aida Zolica8e16bba2023-06-27 22:21:05377 status.policy_error.emplace(io_task::PolicyErrorType::kDlp,
Luca Accorsi0ff12e52023-10-13 08:33:43378 /*blocked_files=*/1, "foo.txt",
379 /*always_show_review=*/true);
Aya ElAttar49289d92023-06-22 02:06:38380
381 // Expect the event to have dlp as policy error.
382 base::RunLoop run_loop;
Luca Accorsi0ff12e52023-10-13 08:33:43383 EXPECT_CALL(observer,
384 OnBroadcastEvent(Field(
385 &extensions::Event::event_args,
386 AllOf(ExpectEventArgPolicyError("dlp", 1, "foo.txt", true)))))
Aya ElAttar49289d92023-06-22 02:06:38387 .WillOnce(RunClosure(run_loop.QuitClosure()));
388
389 event_router->OnIOTaskStatus(status);
390 run_loop.Run();
391}
392
Ben Reichb0cba5c2022-06-15 10:26:22393} // namespace
Joel Hockey5dc76e982018-11-13 22:44:39394} // namespace file_manager