blob: ad925cfb19844923431b2db02b5dfe6ed84cda08 [file] [log] [blame]
[email protected]e3c1fc92012-11-15 00:56:461// Copyright (c) 2012 The Chromium 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
avi6e1a22d2015-12-21 03:43:205#include <stddef.h>
6#include <stdint.h>
7
[email protected]e3c1fc92012-11-15 00:56:468#include "base/bind.h"
yamaguchi7bec88d82016-09-13 06:10:379#include "base/memory/ptr_util.h"
[email protected]f129d2502013-07-17 22:45:5010#include "base/message_loop/message_loop.h"
yamaguchi7bec88d82016-09-13 06:10:3711#include "base/strings/stringprintf.h"
zelidrag29fe3382014-08-27 01:44:4812#include "chromeos/dbus/dbus_thread_manager.h"
[email protected]cc70f5012013-05-14 04:58:5613#include "chromeos/dbus/fake_cros_disks_client.h"
[email protected]e3c1fc92012-11-15 00:56:4614#include "chromeos/disks/disk_mount_manager.h"
[email protected]e3c1fc92012-11-15 00:56:4615#include "testing/gtest/include/gtest/gtest.h"
16
yamaguchi7bec88d82016-09-13 06:10:3717using base::MakeUnique;
18using base::StringPrintf;
[email protected]e3c1fc92012-11-15 00:56:4619using chromeos::disks::DiskMountManager;
20using chromeos::CrosDisksClient;
21using chromeos::DBusThreadManager;
[email protected]cc70f5012013-05-14 04:58:5622using chromeos::FakeCrosDisksClient;
yamaguchi7bec88d82016-09-13 06:10:3723using chromeos::MountType;
24using chromeos::disks::MountCondition;
[email protected]e3c1fc92012-11-15 00:56:4625
26namespace {
27
yamaguchibffc32eb2016-08-17 06:35:3928const char kReadOnlyMountpath[] = "/device/read_only_mount_path";
29const char kReadOnlyDeviceSource[] = "/device/read_only_source_path";
30
[email protected]e3c1fc92012-11-15 00:56:4631// Holds information needed to create a DiskMountManager::Disk instance.
32struct TestDiskInfo {
33 const char* source_path;
34 const char* mount_path;
35 const char* system_path;
36 const char* file_path;
37 const char* device_label;
38 const char* drive_label;
39 const char* vendor_id;
40 const char* vendor_name;
41 const char* product_id;
42 const char* product_name;
43 const char* fs_uuid;
44 const char* system_path_prefix;
45 chromeos::DeviceType device_type;
avi6e1a22d2015-12-21 03:43:2046 uint64_t size_in_bytes;
[email protected]e3c1fc92012-11-15 00:56:4647 bool is_parent;
48 bool is_read_only;
49 bool has_media;
50 bool on_boot_device;
[email protected]79ed457b2014-07-22 04:07:2651 bool on_removable_device;
[email protected]e3c1fc92012-11-15 00:56:4652 bool is_hidden;
53};
54
55// Holds information to create a DiskMOuntManager::MountPointInfo instance.
56struct TestMountPointInfo {
57 const char* source_path;
58 const char* mount_path;
59 chromeos::MountType mount_type;
60 chromeos::disks::MountCondition mount_condition;
61};
62
63// List of disks held in DiskMountManager at the begining of the test.
64const TestDiskInfo kTestDisks[] = {
65 {
66 "/device/source_path",
67 "/device/mount_path",
68 "/device/prefix/system_path",
69 "/device/file_path",
70 "/device/device_label",
71 "/device/drive_label",
72 "/device/vendor_id",
73 "/device/vendor_name",
74 "/device/product_id",
75 "/device/product_name",
76 "/device/fs_uuid",
77 "/device/prefix",
78 chromeos::DEVICE_TYPE_USB,
79 1073741824, // size in bytes
yamaguchi6594bf7e12016-08-24 22:16:1180 false, // is parent
81 false, // is read only
82 true, // has media
83 false, // is on boot device
84 true, // is on removable device
85 false // is hidden
86 },
87 {
88 "/device/source_path2",
89 "/device/mount_path2",
90 "/device/prefix/system_path2",
91 "/device/file_path2",
92 "/device/device_label2",
93 "/device/drive_label2",
94 "/device/vendor_id2",
95 "/device/vendor_name2",
96 "/device/product_id2",
97 "/device/product_name2",
98 "/device/fs_uuid2",
99 "/device/prefix2",
100 chromeos::DEVICE_TYPE_SD,
101 1073741824, // size in bytes
102 false, // is parent
103 false, // is read only
104 true, // has media
105 false, // is on boot device
106 true, // is on removable device
107 false // is hidden
yamaguchibffc32eb2016-08-17 06:35:39108 },
109 {
110 kReadOnlyDeviceSource,
111 kReadOnlyMountpath,
yamaguchi6594bf7e12016-08-24 22:16:11112 "/device/prefix/system_path_3",
113 "/device/file_path_3",
114 "/device/device_label_3",
115 "/device/drive_label_3",
116 "/device/vendor_id_3",
117 "/device/vendor_name_3",
118 "/device/product_id_3",
119 "/device/product_name_3",
120 "/device/fs_uuid_3",
yamaguchibffc32eb2016-08-17 06:35:39121 "/device/prefix",
122 chromeos::DEVICE_TYPE_USB,
123 1073741824, // size in bytes
yamaguchi6594bf7e12016-08-24 22:16:11124 false, // is parent
125 true, // is read only
126 true, // has media
127 false, // is on boot device
128 true, // is on removable device
129 false // is hidden
[email protected]e3c1fc92012-11-15 00:56:46130 },
131};
132
[email protected]cc70f5012013-05-14 04:58:56133// List of mount points held in DiskMountManager at the begining of the test.
[email protected]e3c1fc92012-11-15 00:56:46134const TestMountPointInfo kTestMountPoints[] = {
135 {
136 "/archive/source_path",
137 "/archive/mount_path",
138 chromeos::MOUNT_TYPE_ARCHIVE,
139 chromeos::disks::MOUNT_CONDITION_NONE
140 },
141 {
142 "/device/source_path",
143 "/device/mount_path",
144 chromeos::MOUNT_TYPE_DEVICE,
145 chromeos::disks::MOUNT_CONDITION_NONE
146 },
yamaguchibffc32eb2016-08-17 06:35:39147 {
148 kReadOnlyDeviceSource,
149 kReadOnlyMountpath,
150 chromeos::MOUNT_TYPE_DEVICE,
151 chromeos::disks::MOUNT_CONDITION_NONE
152 },
[email protected]e3c1fc92012-11-15 00:56:46153};
154
yamaguchi7bec88d82016-09-13 06:10:37155// Represents which function in |DiskMountManager::Observer| was invoked.
156enum ObserverEventType {
157 DEVICE_EVENT, // OnDeviceEvent()
158 DISK_EVENT, // OnDiskEvent()
159 FORMAT_EVENT, // OnFormatEvent()
160 MOUNT_EVENT // OnMountEvent()
[email protected]e3c1fc92012-11-15 00:56:46161};
162
yamaguchi7bec88d82016-09-13 06:10:37163// Represents every event notified to |DiskMountManager::Observer|.
164struct ObserverEvent {
165 public:
166 virtual ObserverEventType type() const = 0;
167};
168
169// Represents an invocation of |DiskMountManager::Observer::OnDeviceEvent()|.
170struct DeviceEvent : public ObserverEvent {
171 DiskMountManager::DeviceEvent event;
172 std::string device_path;
173
174 DeviceEvent() {}
175
176 DeviceEvent(DiskMountManager::DeviceEvent event,
177 const std::string& device_path)
178 : event(event), device_path(device_path) {}
179
180 ObserverEventType type() const override { return DEVICE_EVENT; }
181
182 bool operator==(const DeviceEvent& other) const {
183 return event == other.event && device_path == other.device_path;
184 }
185
186 std::string DebugString() const {
187 return StringPrintf("OnDeviceEvent(%d, %s)", event, device_path.c_str());
188 }
189};
190
191// Represents an invocation of |DiskMountManager::Observer::OnDiskEvent()|.
192struct DiskEvent : public ObserverEvent {
193 DiskMountManager::DiskEvent event;
194 std::unique_ptr<DiskMountManager::Disk> disk;
195
196 DiskEvent(DiskMountManager::DiskEvent event,
197 const DiskMountManager::Disk& disk)
198 : event(event),
199 disk(std::unique_ptr<DiskMountManager::Disk>(
200 new DiskMountManager::Disk(disk))) {}
201
202 DiskEvent(DiskEvent&& other)
203 : event(other.event), disk(std::move(other.disk)) {}
204
205 ObserverEventType type() const override { return DISK_EVENT; }
206
207 bool operator==(const DiskEvent& other) const {
208 return event == other.event && disk == other.disk;
209 }
210
211 std::string DebugString() const {
212 return StringPrintf("OnDiskEvent(event=%d, device_path=%s, mount_path=%s",
213 event, disk->device_path().c_str(),
214 disk->mount_path().c_str());
215 }
216};
217
218// Represents an invocation of |DiskMountManager::Observer::OnFormatEvent()|.
219struct FormatEvent : public ObserverEvent {
220 DiskMountManager::FormatEvent event;
221 chromeos::FormatError error_code;
222 std::string device_path;
223
224 FormatEvent() {}
225 FormatEvent(DiskMountManager::FormatEvent event,
226 chromeos::FormatError error_code,
227 const std::string& device_path)
228 : event(event), error_code(error_code), device_path(device_path) {}
229
230 ObserverEventType type() const override { return FORMAT_EVENT; }
231
232 bool operator==(const FormatEvent& other) const {
233 return event == other.event && error_code == other.error_code &&
234 device_path == other.device_path;
235 }
236
237 std::string DebugString() const {
238 return StringPrintf("OnFormatEvent(%d, %d, %s)", event, error_code,
239 device_path.c_str());
240 }
241};
242
243// Represents an invocation of |DiskMountManager::Observer::OnMountEvent()|.
244struct MountEvent : public ObserverEvent {
245 DiskMountManager::MountEvent event;
246 chromeos::MountError error_code;
247 DiskMountManager::MountPointInfo mount_point;
248
249 // Not passed to callback, but read by handlers. So it's captured upon
250 // callback.
251 std::unique_ptr<DiskMountManager::Disk> disk;
252
253 MountEvent(MountEvent&& other)
254 : event(other.event),
255 error_code(other.error_code),
256 mount_point(other.mount_point),
257 disk(std::move(other.disk)) {}
258 MountEvent(DiskMountManager::MountEvent event,
259 chromeos::MountError error_code,
260 const DiskMountManager::MountPointInfo& mount_point,
261 const DiskMountManager::Disk& disk)
262 : event(event),
263 error_code(error_code),
264 mount_point(mount_point),
265 disk(new DiskMountManager::Disk(disk)) {}
266
267 ObserverEventType type() const override { return MOUNT_EVENT; }
268
269 bool operator==(const MountEvent& other) const;
270
271 std::string DebugString() const {
272 return StringPrintf("OnMountEvent(%d, %d, %s, %s, %d, %d)", event,
273 error_code, mount_point.source_path.c_str(),
274 mount_point.mount_path.c_str(), mount_point.mount_type,
275 mount_point.mount_condition);
276 }
277};
278
279// A mock |Observer| class which records all invocation of the methods invoked
280// from DiskMountManager and all the arguments passed to them.
281class MockDiskMountManagerObserver : public DiskMountManager::Observer {
282 public:
283 MockDiskMountManagerObserver(const DiskMountManager* manager)
284 : manager_(manager) {}
285 ~MockDiskMountManagerObserver() override {}
286
287 // Mock notify methods.
288 void OnDeviceEvent(DiskMountManager::DeviceEvent event,
289 const std::string& device_path) override {
290 events_.push_back(MakeUnique<DeviceEvent>(event, device_path));
291 }
292
293 void OnDiskEvent(DiskMountManager::DiskEvent event,
294 const DiskMountManager::Disk* disk) override {
295 // Take a snapshot (copy) of the Disk object at the time of invocation for
296 // later verification.
297 events_.push_back(MakeUnique<DiskEvent>(event, *disk));
298 }
299
300 void OnFormatEvent(DiskMountManager::FormatEvent event,
301 chromeos::FormatError error_code,
302 const std::string& device_path) override {
303 events_.push_back(MakeUnique<FormatEvent>(event, error_code, device_path));
304 }
305
306 void OnMountEvent(
307 DiskMountManager::MountEvent event,
308 chromeos::MountError error_code,
309 const DiskMountManager::MountPointInfo& mount_point) override {
310 // Take a snapshot (copy) of a Disk object at the time of invocation.
311 // It can be verified later besides the arguments.
312 events_.push_back(MakeUnique<MountEvent>(
313 event, error_code, mount_point,
314 *manager_->disks().find(mount_point.source_path)->second));
315 }
316
317 // Gets invocation history to be verified by testcases.
318 // Verifies if the |index|th invocation is OnDeviceEvent() and returns
319 // details.
320 const DeviceEvent& GetDeviceEvent(size_t index) {
321 DCHECK_GT(events_.size(), index);
322 DCHECK_EQ(DEVICE_EVENT, events_[index]->type());
323 return static_cast<const DeviceEvent&>(*events_[index]);
324 }
325
326 // Verifies if the |index|th invocation is OnDiskEvent() and returns details.
327 const DiskEvent& GetDiskEvent(size_t index) {
328 DCHECK_GT(events_.size(), index);
329 DCHECK_EQ(DISK_EVENT, events_[index]->type());
330 return static_cast<const DiskEvent&>(*events_[index]);
331 }
332
333 // Verifies if the |index|th invocation is OnFormatEvent() and returns
334 // details.
335 const FormatEvent& GetFormatEvent(size_t index) {
336 DCHECK_GT(events_.size(), index);
337 DCHECK_EQ(FORMAT_EVENT, events_[index]->type());
338 return static_cast<const FormatEvent&>(*events_[index]);
339 }
340
341 // Verifies if the |index|th invocation is OnMountEvent() and returns details.
342 const MountEvent& GetMountEvent(size_t index) {
343 DCHECK_GT(events_.size(), index);
344 DCHECK_EQ(MOUNT_EVENT, events_[index]->type());
345 return static_cast<const MountEvent&>(*events_[index]);
346 }
347
348 // Returns number of callback invocations happened so far.
349 size_t GetEventCount() { return events_.size(); }
350
351 // Counts the number of |MountEvent| recorded so far that matches the given
352 // condition.
353 size_t CountMountEvents(DiskMountManager::MountEvent mount_event_type,
354 chromeos::MountError error_code,
355 const std::string& mount_path) {
356 size_t num_matched = 0;
357 for (const auto& it : events_) {
358 if (it->type() != MOUNT_EVENT)
359 continue;
360 const MountEvent& mount_event = static_cast<const MountEvent&>(*it);
361 if (mount_event.event == mount_event_type &&
362 mount_event.error_code == error_code &&
363 mount_event.mount_point.mount_path == mount_path)
364 num_matched++;
365 }
366 return num_matched;
367 }
368
369 // Counts the number of |FormatEvent| recorded so far that matches with
370 // |format_event|.
371 size_t CountFormatEvents(const FormatEvent& exptected_format_event) {
372 size_t num_matched = 0;
373 for (const auto& it : events_) {
374 if (it->type() != FORMAT_EVENT)
375 continue;
376 if (static_cast<const FormatEvent&>(*it) == exptected_format_event)
377 num_matched++;
378 }
379 return num_matched;
380 }
381
382 private:
383 // Pointer to the manager object to which this |Observer| is registered.
384 const DiskMountManager* manager_;
385
386 // Records all invocations.
387 std::vector<std::unique_ptr<ObserverEvent>> events_;
388};
389
390// Shift operators of ostream.
391// Needed to print values in case of EXPECT_* failure in gtest.
392std::ostream& operator<<(std::ostream& stream,
393 const DeviceEvent& device_event) {
394 return stream << device_event.DebugString();
395}
396
397std::ostream& operator<<(std::ostream& stream, const DiskEvent& disk_event) {
398 return stream << disk_event.DebugString();
399}
400
401std::ostream& operator<<(std::ostream& stream,
402 const FormatEvent& format_event) {
403 return stream << format_event.DebugString();
404}
405
406std::ostream& operator<<(std::ostream& stream, const MountEvent& mount_event) {
407 return stream << mount_event.DebugString();
yamaguchi6594bf7e12016-08-24 22:16:11408}
409
[email protected]e3c1fc92012-11-15 00:56:46410class DiskMountManagerTest : public testing::Test {
411 public:
yamaguchi7bec88d82016-09-13 06:10:37412 DiskMountManagerTest() : observer_(NULL) {}
dchengae98daa2015-01-21 20:30:49413 ~DiskMountManagerTest() override {}
[email protected]e3c1fc92012-11-15 00:56:46414
415 // Sets up test dbus tread manager and disks mount manager.
416 // Initializes disk mount manager disks and mount points.
417 // Adds a test observer to the disk mount manager.
dchengae98daa2015-01-21 20:30:49418 void SetUp() override {
[email protected]54652d82013-11-10 16:02:49419 fake_cros_disks_client_ = new FakeCrosDisksClient;
zelidrag29fe3382014-08-27 01:44:48420 DBusThreadManager::GetSetterForTesting()->SetCrosDisksClient(
dcheng0a6e80c2016-04-08 18:37:38421 std::unique_ptr<CrosDisksClient>(fake_cros_disks_client_));
[email protected]e3c1fc92012-11-15 00:56:46422
[email protected]e3c1fc92012-11-15 00:56:46423 DiskMountManager::Initialize();
424
425 InitDisksAndMountPoints();
426
yamaguchi7bec88d82016-09-13 06:10:37427 observer_ =
428 new MockDiskMountManagerObserver(DiskMountManager::GetInstance());
429 DiskMountManager::GetInstance()->AddObserver(observer_);
[email protected]e3c1fc92012-11-15 00:56:46430 }
431
432 // Shuts down dbus thread manager and disk moutn manager used in the test.
dchengae98daa2015-01-21 20:30:49433 void TearDown() override {
yamaguchi7bec88d82016-09-13 06:10:37434 DiskMountManager::GetInstance()->RemoveObserver(observer_);
[email protected]e3c1fc92012-11-15 00:56:46435 DiskMountManager::Shutdown();
436 DBusThreadManager::Shutdown();
437 }
438
439 protected:
440 // Checks if disk mount manager contains a mount point with specified moutn
441 // path.
442 bool HasMountPoint(const std::string& mount_path) {
443 const DiskMountManager::MountPointMap& mount_points =
444 DiskMountManager::GetInstance()->mount_points();
445 return mount_points.find(mount_path) != mount_points.end();
446 }
447
448 private:
449 // Adds a new disk to the disk mount manager.
450 void AddTestDisk(const TestDiskInfo& disk) {
451 EXPECT_TRUE(DiskMountManager::GetInstance()->AddDiskForTest(
452 new DiskMountManager::Disk(disk.source_path,
453 disk.mount_path,
454 disk.system_path,
455 disk.file_path,
456 disk.device_label,
457 disk.drive_label,
458 disk.vendor_id,
459 disk.vendor_name,
460 disk.product_id,
461 disk.product_name,
462 disk.fs_uuid,
463 disk.system_path_prefix,
464 disk.device_type,
465 disk.size_in_bytes,
466 disk.is_parent,
467 disk.is_read_only,
468 disk.has_media,
469 disk.on_boot_device,
[email protected]79ed457b2014-07-22 04:07:26470 disk.on_removable_device,
[email protected]e3c1fc92012-11-15 00:56:46471 disk.is_hidden)));
472 }
473
474 // Adds a new mount point to the disk mount manager.
475 // If the moutn point is a device mount point, disk with its source path
476 // should already be added to the disk mount manager.
477 void AddTestMountPoint(const TestMountPointInfo& mount_point) {
478 EXPECT_TRUE(DiskMountManager::GetInstance()->AddMountPointForTest(
479 DiskMountManager::MountPointInfo(mount_point.source_path,
480 mount_point.mount_path,
481 mount_point.mount_type,
482 mount_point.mount_condition)));
483 }
484
485 // Adds disks and mount points to disk mount manager.
486 void InitDisksAndMountPoints() {
487 // Disks should be added first (when adding device mount points it is
488 // expected that the corresponding disk is already added).
489 for (size_t i = 0; i < arraysize(kTestDisks); i++)
490 AddTestDisk(kTestDisks[i]);
491
492 for (size_t i = 0; i < arraysize(kTestMountPoints); i++)
493 AddTestMountPoint(kTestMountPoints[i]);
494 }
495
496 protected:
[email protected]cc70f5012013-05-14 04:58:56497 chromeos::FakeCrosDisksClient* fake_cros_disks_client_;
yamaguchi7bec88d82016-09-13 06:10:37498 MockDiskMountManagerObserver* observer_;
[email protected]df905632013-05-29 23:04:36499 base::MessageLoopForUI message_loop_;
[email protected]e3c1fc92012-11-15 00:56:46500};
501
502// Tests that the observer gets notified on attempt to format non existent mount
503// point.
504TEST_F(DiskMountManagerTest, Format_NotMounted) {
[email protected]e3c1fc92012-11-15 00:56:46505 DiskMountManager::GetInstance()->FormatMountedDevice("/mount/non_existent");
yamaguchi7bec88d82016-09-13 06:10:37506 ASSERT_EQ(1U, observer_->GetEventCount());
507 EXPECT_EQ(FormatEvent(DiskMountManager::FORMAT_COMPLETED,
508 chromeos::FORMAT_ERROR_UNKNOWN, "/mount/non_existent"),
509 observer_->GetFormatEvent(0));
[email protected]e3c1fc92012-11-15 00:56:46510}
511
yamaguchibffc32eb2016-08-17 06:35:39512// Tests that the observer gets notified on attempt to format read-only mount
513// point.
514TEST_F(DiskMountManagerTest, Format_ReadOnly) {
yamaguchibffc32eb2016-08-17 06:35:39515 DiskMountManager::GetInstance()->FormatMountedDevice(kReadOnlyMountpath);
yamaguchi7bec88d82016-09-13 06:10:37516 ASSERT_EQ(1U, observer_->GetEventCount());
517 EXPECT_EQ(FormatEvent(DiskMountManager::FORMAT_COMPLETED,
518 chromeos::FORMAT_ERROR_DEVICE_NOT_ALLOWED,
519 kReadOnlyMountpath),
520 observer_->GetFormatEvent(0));
yamaguchibffc32eb2016-08-17 06:35:39521}
522
[email protected]e3c1fc92012-11-15 00:56:46523// Tests that it is not possible to format archive mount point.
524TEST_F(DiskMountManagerTest, Format_Archive) {
[email protected]e3c1fc92012-11-15 00:56:46525 DiskMountManager::GetInstance()->FormatMountedDevice("/archive/mount_path");
yamaguchi7bec88d82016-09-13 06:10:37526 ASSERT_EQ(1U, observer_->GetEventCount());
527 EXPECT_EQ(FormatEvent(DiskMountManager::FORMAT_COMPLETED,
528 chromeos::FORMAT_ERROR_UNKNOWN, "/archive/source_path"),
529 observer_->GetFormatEvent(0));
[email protected]e3c1fc92012-11-15 00:56:46530}
531
532// Tests that format fails if the device cannot be unmounted.
533TEST_F(DiskMountManagerTest, Format_FailToUnmount) {
[email protected]e3c1fc92012-11-15 00:56:46534 // Before formatting mounted device, the device should be unmounted.
535 // In this test unmount will fail, and there should be no attempt to
536 // format the device.
[email protected]e3c1fc92012-11-15 00:56:46537
[email protected]cc70f5012013-05-14 04:58:56538 fake_cros_disks_client_->MakeUnmountFail();
[email protected]e3c1fc92012-11-15 00:56:46539 // Start test.
540 DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
541
542 // Cros disks will respond asynchronoulsy, so let's drain the message loop.
543 message_loop_.RunUntilIdle();
544
yamaguchi7bec88d82016-09-13 06:10:37545 // Observer should be notified that unmount attempt fails and format task
546 // failed to start.
547 ASSERT_EQ(2U, observer_->GetEventCount());
548 const MountEvent& mount_event = observer_->GetMountEvent(0);
549 EXPECT_EQ(DiskMountManager::UNMOUNTING, mount_event.event);
550 EXPECT_EQ(chromeos::MOUNT_ERROR_INTERNAL, mount_event.error_code);
551 EXPECT_EQ("/device/mount_path", mount_event.mount_point.mount_path);
552
553 EXPECT_EQ(FormatEvent(DiskMountManager::FORMAT_COMPLETED,
554 chromeos::FORMAT_ERROR_UNKNOWN, "/device/source_path"),
555 observer_->GetFormatEvent(1));
[email protected]cc70f5012013-05-14 04:58:56556 EXPECT_EQ(1, fake_cros_disks_client_->unmount_call_count());
557 EXPECT_EQ("/device/mount_path",
558 fake_cros_disks_client_->last_unmount_device_path());
559 EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE,
560 fake_cros_disks_client_->last_unmount_options());
[email protected]f026c0f2014-05-06 21:52:35561 EXPECT_EQ(0, fake_cros_disks_client_->format_call_count());
[email protected]cc70f5012013-05-14 04:58:56562
[email protected]e3c1fc92012-11-15 00:56:46563 // The device mount should still be here.
564 EXPECT_TRUE(HasMountPoint("/device/mount_path"));
565}
566
567// Tests that observer is notified when cros disks fails to start format
568// process.
569TEST_F(DiskMountManagerTest, Format_FormatFailsToStart) {
[email protected]e3c1fc92012-11-15 00:56:46570 // Before formatting mounted device, the device should be unmounted.
[email protected]f026c0f2014-05-06 21:52:35571 // In this test, unmount will succeed, but call to Format method will
[email protected]e3c1fc92012-11-15 00:56:46572 // fail.
[email protected]e3c1fc92012-11-15 00:56:46573
[email protected]f026c0f2014-05-06 21:52:35574 fake_cros_disks_client_->MakeFormatFail();
[email protected]e3c1fc92012-11-15 00:56:46575 // Start the test.
576 DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
577
578 // Cros disks will respond asynchronoulsy, so let's drain the message loop.
579 message_loop_.RunUntilIdle();
580
yamaguchi7bec88d82016-09-13 06:10:37581 // Observer should be notified that the device was unmounted and format task
582 // failed to start.
583 ASSERT_EQ(2U, observer_->GetEventCount());
584 const MountEvent& mount_event = observer_->GetMountEvent(0);
585 EXPECT_EQ(DiskMountManager::UNMOUNTING, mount_event.event);
586 EXPECT_EQ(chromeos::MOUNT_ERROR_NONE, mount_event.error_code);
587 EXPECT_EQ("/device/mount_path", mount_event.mount_point.mount_path);
588
589 EXPECT_EQ(FormatEvent(DiskMountManager::FORMAT_COMPLETED,
590 chromeos::FORMAT_ERROR_UNKNOWN, "/device/source_path"),
591 observer_->GetFormatEvent(1));
592
[email protected]cc70f5012013-05-14 04:58:56593 EXPECT_EQ(1, fake_cros_disks_client_->unmount_call_count());
594 EXPECT_EQ("/device/mount_path",
595 fake_cros_disks_client_->last_unmount_device_path());
596 EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE,
597 fake_cros_disks_client_->last_unmount_options());
[email protected]f026c0f2014-05-06 21:52:35598 EXPECT_EQ(1, fake_cros_disks_client_->format_call_count());
[email protected]cc70f5012013-05-14 04:58:56599 EXPECT_EQ("/device/source_path",
[email protected]f026c0f2014-05-06 21:52:35600 fake_cros_disks_client_->last_format_device_path());
601 EXPECT_EQ("vfat", fake_cros_disks_client_->last_format_filesystem());
[email protected]cc70f5012013-05-14 04:58:56602
[email protected]e3c1fc92012-11-15 00:56:46603 // The device mount should be gone.
604 EXPECT_FALSE(HasMountPoint("/device/mount_path"));
605}
606
607// Tests the case where there are two format requests for the same device.
608TEST_F(DiskMountManagerTest, Format_ConcurrentFormatCalls) {
[email protected]8f919ee2013-03-14 19:53:29609 // Only the first format request should be processed (the second unmount
610 // request fails because the device is already unmounted at that point).
[email protected]e3c1fc92012-11-15 00:56:46611 // CrosDisksClient will report that the format process for the first request
612 // is successfully started.
[email protected]e3c1fc92012-11-15 00:56:46613
[email protected]cc70f5012013-05-14 04:58:56614 fake_cros_disks_client_->set_unmount_listener(
615 base::Bind(&FakeCrosDisksClient::MakeUnmountFail,
616 base::Unretained(fake_cros_disks_client_)));
[email protected]e3c1fc92012-11-15 00:56:46617 // Start the test.
618 DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
619 DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
620
621 // Cros disks will respond asynchronoulsy, so let's drain the message loop.
622 message_loop_.RunUntilIdle();
623
yamaguchi7bec88d82016-09-13 06:10:37624 // The observer should get a FORMAT_STARTED event for one format request and a
625 // FORMAT_COMPLETED with an error code for the other format request. The
626 // formatting will be started only for the first request.
627 // There should be only one UNMOUNTING event. The result of the second one
628 // should not be reported as the mount point will go away after the first
629 // request.
630 //
631 // Note that in this test the format completion signal will not be simulated,
632 // so the observer should not get FORMAT_COMPLETED signal.
633
634 ASSERT_EQ(3U, observer_->GetEventCount());
635 const MountEvent& mount_event = observer_->GetMountEvent(0);
636 EXPECT_EQ(DiskMountManager::UNMOUNTING, mount_event.event);
637 EXPECT_EQ(chromeos::MOUNT_ERROR_NONE, mount_event.error_code);
638 EXPECT_EQ("/device/mount_path", mount_event.mount_point.mount_path);
639 EXPECT_EQ(FormatEvent(DiskMountManager::FORMAT_COMPLETED,
640 chromeos::FORMAT_ERROR_UNKNOWN, "/device/source_path"),
641 observer_->GetFormatEvent(1));
642 EXPECT_EQ(FormatEvent(DiskMountManager::FORMAT_STARTED,
643 chromeos::FORMAT_ERROR_NONE, "/device/source_path"),
644 observer_->GetFormatEvent(2));
645
[email protected]cc70f5012013-05-14 04:58:56646 EXPECT_EQ(2, fake_cros_disks_client_->unmount_call_count());
647 EXPECT_EQ("/device/mount_path",
648 fake_cros_disks_client_->last_unmount_device_path());
649 EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE,
650 fake_cros_disks_client_->last_unmount_options());
[email protected]f026c0f2014-05-06 21:52:35651 EXPECT_EQ(1, fake_cros_disks_client_->format_call_count());
[email protected]cc70f5012013-05-14 04:58:56652 EXPECT_EQ("/device/source_path",
[email protected]f026c0f2014-05-06 21:52:35653 fake_cros_disks_client_->last_format_device_path());
[email protected]cc70f5012013-05-14 04:58:56654 EXPECT_EQ("vfat",
[email protected]f026c0f2014-05-06 21:52:35655 fake_cros_disks_client_->last_format_filesystem());
[email protected]cc70f5012013-05-14 04:58:56656
[email protected]e3c1fc92012-11-15 00:56:46657 // The device mount should be gone.
658 EXPECT_FALSE(HasMountPoint("/device/mount_path"));
659}
660
yamaguchi7bec88d82016-09-13 06:10:37661// Verifies a |MountEvent| with the given condition. This function only checks
662// the |mount_path| in |MountPointInfo| to make sure to match the event with
663// preceding mount invocations.
664void VerifyMountEvent(const MountEvent& mount_event,
665 DiskMountManager::MountEvent mount_event_type,
666 chromeos::MountError error_code,
667 const std::string& mount_path) {
668 EXPECT_EQ(mount_event_type, mount_event.event);
669 EXPECT_EQ(error_code, mount_event.error_code);
670 EXPECT_EQ(mount_path, mount_event.mount_point.mount_path);
671}
672
[email protected]e3c1fc92012-11-15 00:56:46673// Tests the case when the format process actually starts and fails.
674TEST_F(DiskMountManagerTest, Format_FormatFails) {
[email protected]f026c0f2014-05-06 21:52:35675 // Both unmount and format device cals are successful in this test.
[email protected]e3c1fc92012-11-15 00:56:46676
[email protected]e3c1fc92012-11-15 00:56:46677 // Start the test.
678 DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
679
[email protected]f026c0f2014-05-06 21:52:35680 // Wait for Unmount and Format calls to end.
[email protected]e3c1fc92012-11-15 00:56:46681 message_loop_.RunUntilIdle();
682
[email protected]cc70f5012013-05-14 04:58:56683 EXPECT_EQ(1, fake_cros_disks_client_->unmount_call_count());
684 EXPECT_EQ("/device/mount_path",
685 fake_cros_disks_client_->last_unmount_device_path());
686 EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE,
687 fake_cros_disks_client_->last_unmount_options());
[email protected]f026c0f2014-05-06 21:52:35688 EXPECT_EQ(1, fake_cros_disks_client_->format_call_count());
[email protected]cc70f5012013-05-14 04:58:56689 EXPECT_EQ("/device/source_path",
[email protected]f026c0f2014-05-06 21:52:35690 fake_cros_disks_client_->last_format_device_path());
691 EXPECT_EQ("vfat", fake_cros_disks_client_->last_format_filesystem());
[email protected]cc70f5012013-05-14 04:58:56692
[email protected]e3c1fc92012-11-15 00:56:46693 // The device should be unmounted by now.
694 EXPECT_FALSE(HasMountPoint("/device/mount_path"));
695
[email protected]a0278d52014-05-06 03:36:15696 // Send failing FORMAT_COMPLETED signal.
[email protected]e3c1fc92012-11-15 00:56:46697 // The failure is marked by ! in fromt of the path (but this should change
698 // soon).
[email protected]a0278d52014-05-06 03:36:15699 fake_cros_disks_client_->SendFormatCompletedEvent(
700 chromeos::FORMAT_ERROR_UNKNOWN, "/device/source_path");
yamaguchi7bec88d82016-09-13 06:10:37701
702 // The observer should get notified that the device was unmounted and that
703 // formatting has started.
704 // After the formatting starts, the test will simulate failing
705 // FORMAT_COMPLETED signal, so the observer should also be notified the
706 // formatting has failed (FORMAT_COMPLETED event).
707 ASSERT_EQ(3U, observer_->GetEventCount());
708 VerifyMountEvent(observer_->GetMountEvent(0), DiskMountManager::UNMOUNTING,
709 chromeos::MOUNT_ERROR_NONE, "/device/mount_path");
710 EXPECT_EQ(FormatEvent(DiskMountManager::FORMAT_STARTED,
711 chromeos::FORMAT_ERROR_NONE, "/device/source_path"),
712 observer_->GetFormatEvent(1));
713 EXPECT_EQ(FormatEvent(DiskMountManager::FORMAT_COMPLETED,
714 chromeos::FORMAT_ERROR_UNKNOWN, "/device/source_path"),
715 observer_->GetFormatEvent(2));
[email protected]e3c1fc92012-11-15 00:56:46716}
717
[email protected]e3c1fc92012-11-15 00:56:46718// Tests the case when formatting completes successfully.
719TEST_F(DiskMountManagerTest, Format_FormatSuccess) {
720 // Set up cros disks client mocks.
[email protected]f026c0f2014-05-06 21:52:35721 // Both unmount and format device cals are successful in this test.
[email protected]e3c1fc92012-11-15 00:56:46722
[email protected]e3c1fc92012-11-15 00:56:46723 // Start the test.
724 DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
725
[email protected]f026c0f2014-05-06 21:52:35726 // Wait for Unmount and Format calls to end.
[email protected]e3c1fc92012-11-15 00:56:46727 message_loop_.RunUntilIdle();
728
[email protected]cc70f5012013-05-14 04:58:56729 EXPECT_EQ(1, fake_cros_disks_client_->unmount_call_count());
730 EXPECT_EQ("/device/mount_path",
731 fake_cros_disks_client_->last_unmount_device_path());
732 EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE,
733 fake_cros_disks_client_->last_unmount_options());
[email protected]f026c0f2014-05-06 21:52:35734 EXPECT_EQ(1, fake_cros_disks_client_->format_call_count());
[email protected]cc70f5012013-05-14 04:58:56735 EXPECT_EQ("/device/source_path",
[email protected]f026c0f2014-05-06 21:52:35736 fake_cros_disks_client_->last_format_device_path());
737 EXPECT_EQ("vfat", fake_cros_disks_client_->last_format_filesystem());
[email protected]cc70f5012013-05-14 04:58:56738
[email protected]e3c1fc92012-11-15 00:56:46739 // The device should be unmounted by now.
740 EXPECT_FALSE(HasMountPoint("/device/mount_path"));
741
742 // Simulate cros_disks reporting success.
[email protected]a0278d52014-05-06 03:36:15743 fake_cros_disks_client_->SendFormatCompletedEvent(
744 chromeos::FORMAT_ERROR_NONE, "/device/source_path");
yamaguchi7bec88d82016-09-13 06:10:37745
746 // The observer should receive UNMOUNTING, FORMAT_STARTED and FORMAT_COMPLETED
747 // events (all of them without an error set).
748 ASSERT_EQ(3U, observer_->GetEventCount());
749 VerifyMountEvent(observer_->GetMountEvent(0), DiskMountManager::UNMOUNTING,
750 chromeos::MOUNT_ERROR_NONE, "/device/mount_path");
751 EXPECT_EQ(FormatEvent(DiskMountManager::FORMAT_STARTED,
752 chromeos::FORMAT_ERROR_NONE, "/device/source_path"),
753 observer_->GetFormatEvent(1));
754 EXPECT_EQ(FormatEvent(DiskMountManager::FORMAT_COMPLETED,
755 chromeos::FORMAT_ERROR_NONE, "/device/source_path"),
756 observer_->GetFormatEvent(2));
[email protected]e3c1fc92012-11-15 00:56:46757}
758
759// Tests that it's possible to format the device twice in a row (this may not be
760// true if the list of pending formats is not properly cleared).
761TEST_F(DiskMountManagerTest, Format_ConsecutiveFormatCalls) {
[email protected]f026c0f2014-05-06 21:52:35762 // All unmount and format device cals are successful in this test.
[email protected]e3c1fc92012-11-15 00:56:46763 // Each of the should be made twice (once for each formatting task).
[email protected]e3c1fc92012-11-15 00:56:46764
[email protected]e3c1fc92012-11-15 00:56:46765 // Start the test.
766 DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
767
[email protected]f026c0f2014-05-06 21:52:35768 // Wait for Unmount and Format calls to end.
[email protected]e3c1fc92012-11-15 00:56:46769 message_loop_.RunUntilIdle();
770
[email protected]cc70f5012013-05-14 04:58:56771 EXPECT_EQ(1, fake_cros_disks_client_->unmount_call_count());
772 EXPECT_EQ("/device/mount_path",
773 fake_cros_disks_client_->last_unmount_device_path());
774 EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE,
775 fake_cros_disks_client_->last_unmount_options());
[email protected]f026c0f2014-05-06 21:52:35776 EXPECT_EQ(1, fake_cros_disks_client_->format_call_count());
[email protected]cc70f5012013-05-14 04:58:56777 EXPECT_EQ("/device/source_path",
[email protected]f026c0f2014-05-06 21:52:35778 fake_cros_disks_client_->last_format_device_path());
779 EXPECT_EQ("vfat", fake_cros_disks_client_->last_format_filesystem());
[email protected]cc70f5012013-05-14 04:58:56780
[email protected]e3c1fc92012-11-15 00:56:46781 // The device should be unmounted by now.
782 EXPECT_FALSE(HasMountPoint("/device/mount_path"));
783
784 // Simulate cros_disks reporting success.
[email protected]a0278d52014-05-06 03:36:15785 fake_cros_disks_client_->SendFormatCompletedEvent(
786 chromeos::FORMAT_ERROR_NONE, "/device/source_path");
[email protected]e3c1fc92012-11-15 00:56:46787
788 // Simulate the device remounting.
[email protected]cc70f5012013-05-14 04:58:56789 fake_cros_disks_client_->SendMountCompletedEvent(
[email protected]e3c1fc92012-11-15 00:56:46790 chromeos::MOUNT_ERROR_NONE,
791 "/device/source_path",
792 chromeos::MOUNT_TYPE_DEVICE,
793 "/device/mount_path");
794
795 EXPECT_TRUE(HasMountPoint("/device/mount_path"));
796
797 // Try formatting again.
798 DiskMountManager::GetInstance()->FormatMountedDevice("/device/mount_path");
799
[email protected]f026c0f2014-05-06 21:52:35800 // Wait for Unmount and Format calls to end.
[email protected]e3c1fc92012-11-15 00:56:46801 message_loop_.RunUntilIdle();
802
[email protected]cc70f5012013-05-14 04:58:56803 EXPECT_EQ(2, fake_cros_disks_client_->unmount_call_count());
804 EXPECT_EQ("/device/mount_path",
805 fake_cros_disks_client_->last_unmount_device_path());
806 EXPECT_EQ(chromeos::UNMOUNT_OPTIONS_NONE,
807 fake_cros_disks_client_->last_unmount_options());
[email protected]f026c0f2014-05-06 21:52:35808 EXPECT_EQ(2, fake_cros_disks_client_->format_call_count());
[email protected]cc70f5012013-05-14 04:58:56809 EXPECT_EQ("/device/source_path",
[email protected]f026c0f2014-05-06 21:52:35810 fake_cros_disks_client_->last_format_device_path());
811 EXPECT_EQ("vfat", fake_cros_disks_client_->last_format_filesystem());
[email protected]cc70f5012013-05-14 04:58:56812
[email protected]e3c1fc92012-11-15 00:56:46813 // Simulate cros_disks reporting success.
[email protected]a0278d52014-05-06 03:36:15814 fake_cros_disks_client_->SendFormatCompletedEvent(
815 chromeos::FORMAT_ERROR_NONE, "/device/source_path");
yamaguchi7bec88d82016-09-13 06:10:37816
817 // The observer should receive UNMOUNTING, FORMAT_STARTED and FORMAT_COMPLETED
818 // events (all of them without an error set) twice (once for each formatting
819 // task).
820 // Also, there should be a MOUNTING event when the device remounting is
821 // simulated.
822 EXPECT_EQ(7U, observer_->GetEventCount());
823
824 EXPECT_EQ(2U, observer_->CountFormatEvents(FormatEvent(
825 DiskMountManager::FORMAT_COMPLETED,
826 chromeos::FORMAT_ERROR_NONE, "/device/source_path")));
827
828 EXPECT_EQ(2U, observer_->CountFormatEvents(FormatEvent(
829 DiskMountManager::FORMAT_STARTED,
830 chromeos::FORMAT_ERROR_NONE, "/device/source_path")));
831
832 EXPECT_EQ(2U, observer_->CountMountEvents(DiskMountManager::UNMOUNTING,
833 chromeos::MOUNT_ERROR_NONE,
834 "/device/mount_path"));
835
836 EXPECT_EQ(1U, observer_->CountMountEvents(DiskMountManager::MOUNTING,
837 chromeos::MOUNT_ERROR_NONE,
838 "/device/mount_path"));
[email protected]e3c1fc92012-11-15 00:56:46839}
840
yamaguchi6594bf7e12016-08-24 22:16:11841TEST_F(DiskMountManagerTest, MountPath_RecordAccessMode) {
842 DiskMountManager* manager = DiskMountManager::GetInstance();
843 const std::string kSourcePath1 = "/device/source_path";
844 const std::string kSourcePath2 = "/device/source_path2";
845 const std::string kSourceFormat = std::string();
846 const std::string kMountLabel = std::string(); // N/A for MOUNT_TYPE_DEVICE
847 // For MountCompleted. Must be non-empty strings.
848 const std::string kMountPath1 = "/media/foo";
849 const std::string kMountPath2 = "/media/bar";
850
yamaguchi6594bf7e12016-08-24 22:16:11851 manager->MountPath(kSourcePath1, kSourceFormat, std::string(),
852 chromeos::MOUNT_TYPE_DEVICE,
853 chromeos::MOUNT_ACCESS_MODE_READ_WRITE);
854 manager->MountPath(kSourcePath2, kSourceFormat, std::string(),
855 chromeos::MOUNT_TYPE_DEVICE,
856 chromeos::MOUNT_ACCESS_MODE_READ_ONLY);
857 // Simulate cros_disks reporting mount completed.
858 fake_cros_disks_client_->SendMountCompletedEvent(
859 chromeos::MOUNT_ERROR_NONE, kSourcePath1, chromeos::MOUNT_TYPE_DEVICE,
860 kMountPath1);
861 fake_cros_disks_client_->SendMountCompletedEvent(
862 chromeos::MOUNT_ERROR_NONE, kSourcePath2, chromeos::MOUNT_TYPE_DEVICE,
863 kMountPath2);
864
yamaguchi7bec88d82016-09-13 06:10:37865 // Event handlers of observers should be called.
866 ASSERT_EQ(2U, observer_->GetEventCount());
867 VerifyMountEvent(observer_->GetMountEvent(0), DiskMountManager::MOUNTING,
868 chromeos::MOUNT_ERROR_NONE, kMountPath1);
869 // For the 2nd source, the disk (block device) is not read-only but the
870 // test will mount it in read-only mode.
871 // Observers query |disks_| from |DiskMountManager| in its event handler for
872 // a mount completion event. Therefore |disks_| must be updated with correct
873 // |read_only| value before notifying to observers.
874 const MountEvent& secondMountEvent = observer_->GetMountEvent(1);
875 EXPECT_EQ(DiskMountManager::MOUNTING, secondMountEvent.event);
876 EXPECT_EQ(chromeos::MOUNT_ERROR_NONE, secondMountEvent.error_code);
877 EXPECT_EQ(kMountPath2, secondMountEvent.mount_point.mount_path);
878 // Verify if the disk appears read-only at the time of notification to
879 // observers.
880 EXPECT_TRUE(secondMountEvent.disk->is_read_only());
881
882 // Verify the final state of manager->disks.
yamaguchi6594bf7e12016-08-24 22:16:11883 const DiskMountManager::DiskMap& disks = manager->disks();
884 ASSERT_GT(disks.count(kSourcePath1), 0U);
885 EXPECT_FALSE(disks.find(kSourcePath1)->second->is_read_only());
886 ASSERT_GT(disks.count(kSourcePath2), 0U);
887 EXPECT_TRUE(disks.find(kSourcePath2)->second->is_read_only());
888}
889
yamaguchi21448d5b2016-09-06 02:04:56890TEST_F(DiskMountManagerTest, MountPath_ReadOnlyDevice) {
891 DiskMountManager* manager = DiskMountManager::GetInstance();
892 const std::string kSourceFormat = std::string();
893 const std::string kMountLabel = std::string(); // N/A for MOUNT_TYPE_DEVICE
894
yamaguchi21448d5b2016-09-06 02:04:56895 // Attempt to mount a read-only device in read-write mode.
896 manager->MountPath(kReadOnlyDeviceSource, kSourceFormat, std::string(),
897 chromeos::MOUNT_TYPE_DEVICE,
898 chromeos::MOUNT_ACCESS_MODE_READ_WRITE);
899 // Simulate cros_disks reporting mount completed.
900 fake_cros_disks_client_->SendMountCompletedEvent(
901 chromeos::MOUNT_ERROR_NONE, kReadOnlyDeviceSource,
902 chromeos::MOUNT_TYPE_DEVICE, kReadOnlyMountpath);
903
yamaguchi7bec88d82016-09-13 06:10:37904 // Event handlers of observers should be called.
905 ASSERT_EQ(1U, observer_->GetEventCount());
906 VerifyMountEvent(observer_->GetMountEvent(0), DiskMountManager::MOUNTING,
907 chromeos::MOUNT_ERROR_NONE, kReadOnlyMountpath);
yamaguchi21448d5b2016-09-06 02:04:56908 const DiskMountManager::DiskMap& disks = manager->disks();
909 ASSERT_GT(disks.count(kReadOnlyDeviceSource), 0U);
910 // The mounted disk should preserve the read-only flag of the block device.
911 EXPECT_TRUE(disks.find(kReadOnlyDeviceSource)->second->is_read_only());
912}
913
[email protected]e3c1fc92012-11-15 00:56:46914} // namespace