1 // Copyright (c) 2013 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.
5 #include "chrome/browser/chromeos/imageburner/burn_device_handler.h"
11 #include "base/bind.h"
12 #include "base/logging.h"
13 #include "base/memory/scoped_ptr.h"
14 #include "base/observer_list.h"
15 #include "base/stl_util.h"
16 #include "chromeos/dbus/cros_disks_client.h"
17 #include "chromeos/disks/disk_mount_manager.h"
18 #include "testing/gtest/include/gtest/gtest.h"
21 namespace imageburner
{
25 const bool kIsParent
= true;
26 const bool kIsBootDevice
= true;
27 const bool kHasMedia
= true;
29 class FakeDiskMountManager
: public disks::DiskMountManager
{
31 FakeDiskMountManager() {}
33 virtual ~FakeDiskMountManager() {
34 STLDeleteValues(&disks_
);
37 // Emulates to add new disk physically (e.g., connecting a
38 // new USB flash to a Chrome OS).
39 void EmulateAddDisk(scoped_ptr
<Disk
> in_disk
) {
40 DCHECK(in_disk
.get());
41 // Keep the reference for the callback, before passing the ownership to
42 // InsertDisk. It should be safe, because it won't be deleted in
44 Disk
* disk
= in_disk
.get();
45 bool new_disk
= InsertDisk(disk
->device_path(), in_disk
.Pass());
48 OnDiskEvent(new_disk
? DISK_ADDED
: DISK_CHANGED
, disk
));
51 // Emulates to remove a disk phyically (e.g., removing a USB flash from
53 void EmulateRemoveDisk(const std::string
& source_path
) {
54 scoped_ptr
<Disk
> disk(RemoveDisk(source_path
));
57 Observer
, observers_
, OnDiskEvent(DISK_REMOVED
, disk
.get()));
61 // DiskMountManager overrides.
62 virtual void AddObserver(Observer
* observer
) OVERRIDE
{
63 observers_
.AddObserver(observer
);
66 virtual void RemoveObserver(Observer
* observer
) OVERRIDE
{
67 observers_
.RemoveObserver(observer
);
70 virtual const DiskMap
& disks() const OVERRIDE
{
74 // Following methods are not implemented.
75 virtual const Disk
* FindDiskBySourcePath(
76 const std::string
& source_path
) const OVERRIDE
{
79 virtual const MountPointMap
& mount_points() const OVERRIDE
{
80 // Note: mount_points_ will always be empty, now.
83 virtual void RequestMountInfoRefresh() OVERRIDE
{}
84 virtual void MountPath(const std::string
& source_path
,
85 const std::string
& source_format
,
86 const std::string
& mount_label
,
87 MountType type
) OVERRIDE
{}
88 virtual void UnmountPath(const std::string
& mount_path
,
89 UnmountOptions options
,
90 const UnmountPathCallback
& callback
) OVERRIDE
{}
91 virtual void FormatMountedDevice(const std::string
& mount_path
) OVERRIDE
{}
92 virtual void UnmountDeviceRecursively(
93 const std::string
& device_path
,
94 const UnmountDeviceRecursivelyCallbackType
& callback
) OVERRIDE
{}
95 virtual bool AddDiskForTest(Disk
* disk
) OVERRIDE
{ return false; }
96 virtual bool AddMountPointForTest(
97 const MountPointInfo
& mount_point
) OVERRIDE
{
102 bool InsertDisk(const std::string
& path
, scoped_ptr
<Disk
> disk
) {
103 std::pair
<DiskMap::iterator
, bool> insert_result
=
104 disks_
.insert(std::pair
<std::string
, Disk
*>(path
, NULL
));
105 if (!insert_result
.second
) {
106 // There is already an entry. Delete it before replacing.
107 delete insert_result
.first
->second
;
109 insert_result
.first
->second
= disk
.release(); // Moves ownership.
110 return insert_result
.second
;
113 scoped_ptr
<Disk
> RemoveDisk(const std::string
& path
) {
114 DiskMap::iterator iter
= disks_
.find(path
);
115 if (iter
== disks_
.end()) {
117 return scoped_ptr
<Disk
>();
119 scoped_ptr
<Disk
> result(iter
->second
);
121 return result
.Pass();
124 ObserverList
<Observer
> observers_
;
126 MountPointMap mount_points_
;
128 DISALLOW_COPY_AND_ASSIGN(FakeDiskMountManager
);
131 void CopyDevicePathCallback(
132 std::string
* out_path
, const disks::DiskMountManager::Disk
& disk
) {
133 *out_path
= disk
.device_path();
138 class BurnDeviceHandlerTest
: public testing::Test
{
140 virtual void SetUp() OVERRIDE
{
141 disk_mount_manager_
.reset(new FakeDiskMountManager
);
144 virtual void TearDown() OVERRIDE
{
145 disk_mount_manager_
.reset();
148 static scoped_ptr
<disks::DiskMountManager::Disk
> CreateMockDisk(
149 const std::string
& device_path
,
153 DeviceType device_type
) {
154 return scoped_ptr
<disks::DiskMountManager::Disk
>(
155 new disks::DiskMountManager::Disk(
167 "", // system path prefix
169 0, // total size in bytes
171 false, // is read only
174 false)); // is hidden
177 scoped_ptr
<FakeDiskMountManager
> disk_mount_manager_
;
180 TEST_F(BurnDeviceHandlerTest
, GetBurnableDevices
) {
181 // The devices which should be retrieved as burnable.
182 disk_mount_manager_
->EmulateAddDisk(
183 CreateMockDisk("/dev/burnable_usb",
184 kIsParent
, !kIsBootDevice
, kHasMedia
, DEVICE_TYPE_USB
));
185 disk_mount_manager_
->EmulateAddDisk(
186 CreateMockDisk("/dev/burnable_sd",
187 kIsParent
, !kIsBootDevice
, kHasMedia
, DEVICE_TYPE_SD
));
189 // If the device type is neither USB nor SD, it shouldn't be burnable.
190 disk_mount_manager_
->EmulateAddDisk(
192 "/dev/non_burnable_unknown",
193 kIsParent
, !kIsBootDevice
, kHasMedia
, DEVICE_TYPE_UNKNOWN
));
194 disk_mount_manager_
->EmulateAddDisk(
195 CreateMockDisk("/dev/non_burnable_dvd",
196 kIsParent
, !kIsBootDevice
, kHasMedia
, DEVICE_TYPE_DVD
));
198 // If not parent, it shouldn't be burnable.
199 disk_mount_manager_
->EmulateAddDisk(
200 CreateMockDisk("/dev/non_burnable_not_parent",
201 !kIsParent
, !kIsBootDevice
, kHasMedia
, DEVICE_TYPE_USB
));
203 // If on_boot_device, it shouldn't be burnable.
204 disk_mount_manager_
->EmulateAddDisk(
205 CreateMockDisk("/dev/non_burnable_boot_device",
206 kIsParent
, kIsBootDevice
, kHasMedia
, DEVICE_TYPE_USB
));
208 // If no media, it shouldn't be burnable.
209 disk_mount_manager_
->EmulateAddDisk(
210 CreateMockDisk("/dev/non_burnable_no_media",
211 kIsParent
, !kIsBootDevice
, !kHasMedia
, DEVICE_TYPE_USB
));
213 BurnDeviceHandler
handler(disk_mount_manager_
.get());
215 const std::vector
<disks::DiskMountManager::Disk
>& burnable_devices
=
216 handler
.GetBurnableDevices();
217 ASSERT_EQ(2u, burnable_devices
.size());
218 bool burnable_usb_found
= false;
219 bool burnable_sd_found
= false;
220 for (size_t i
= 0; i
< burnable_devices
.size(); ++i
) {
221 const std::string
& device_path
= burnable_devices
[i
].device_path();
222 burnable_usb_found
|= (device_path
== "/dev/burnable_usb");
223 burnable_sd_found
|= (device_path
== "/dev/burnable_sd");
226 EXPECT_TRUE(burnable_usb_found
);
227 EXPECT_TRUE(burnable_sd_found
);
230 TEST_F(BurnDeviceHandlerTest
, Callback
) {
231 std::string added_device
;
232 std::string removed_device
;
234 BurnDeviceHandler
handler(disk_mount_manager_
.get());
235 handler
.SetCallbacks(
236 base::Bind(CopyDevicePathCallback
, &added_device
),
237 base::Bind(CopyDevicePathCallback
, &removed_device
));
239 // Emulate to connect a burnable device.
240 // |add_callback| should be invoked.
241 disk_mount_manager_
->EmulateAddDisk(
242 CreateMockDisk("/dev/burnable",
243 kIsParent
, !kIsBootDevice
, kHasMedia
, DEVICE_TYPE_USB
));
244 EXPECT_EQ("/dev/burnable", added_device
);
245 EXPECT_TRUE(removed_device
.empty());
247 // Emulate to change the currently connected burnable device.
248 // Neither |add_callback| nor |remove_callback| should be called.
249 added_device
.clear();
250 removed_device
.clear();
251 disk_mount_manager_
->EmulateAddDisk(
252 CreateMockDisk("/dev/burnable",
253 kIsParent
, !kIsBootDevice
, kHasMedia
, DEVICE_TYPE_USB
));
254 EXPECT_TRUE(added_device
.empty());
255 EXPECT_TRUE(removed_device
.empty());
257 // Emulate to disconnect the burnable device.
258 // |remove_callback| should be called.
259 added_device
.clear();
260 removed_device
.clear();
261 disk_mount_manager_
->EmulateRemoveDisk("/dev/burnable");
262 EXPECT_TRUE(added_device
.empty());
263 EXPECT_EQ("/dev/burnable", removed_device
);
265 // Emulate to connect and unconnect an unburnable device.
266 // For each case, neither |add_callback| nor |remove_callback| should be
268 added_device
.clear();
269 removed_device
.clear();
270 disk_mount_manager_
->EmulateAddDisk(
271 CreateMockDisk("/dev/unburnable",
272 !kIsParent
, !kIsBootDevice
, kHasMedia
, DEVICE_TYPE_USB
));
273 EXPECT_TRUE(added_device
.empty());
274 EXPECT_TRUE(removed_device
.empty());
276 added_device
.clear();
277 removed_device
.clear();
278 disk_mount_manager_
->EmulateRemoveDisk("/dev/unburnable");
279 EXPECT_TRUE(added_device
.empty());
280 EXPECT_TRUE(removed_device
.empty());
283 } // namespace imageburner
284 } // namespace chromeos