OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/system_monitor/removable_device_notifications_window_wi
n.h" | 5 #include "chrome/browser/system_monitor/removable_device_notifications_window_wi
n.h" |
6 | 6 |
7 #include <dbt.h> | 7 #include <dbt.h> |
8 | 8 |
9 #include <string> | 9 #include <string> |
10 #include <vector> | 10 #include <vector> |
11 | 11 |
12 #include "base/file_util.h" | 12 #include "base/file_util.h" |
| 13 #include "base/memory/ref_counted.h" |
13 #include "base/memory/scoped_ptr.h" | 14 #include "base/memory/scoped_ptr.h" |
14 #include "base/message_loop.h" | 15 #include "base/message_loop.h" |
15 #include "base/scoped_temp_dir.h" | 16 #include "base/scoped_temp_dir.h" |
16 #include "base/system_monitor/system_monitor.h" | 17 #include "base/system_monitor/system_monitor.h" |
17 #include "base/test/mock_devices_changed_observer.h" | 18 #include "base/test/mock_devices_changed_observer.h" |
| 19 #include "base/utf_string_conversions.h" |
18 #include "chrome/browser/system_monitor/media_storage_util.h" | 20 #include "chrome/browser/system_monitor/media_storage_util.h" |
| 21 #include "chrome/browser/system_monitor/portable_device_watcher_win.h" |
| 22 #include "chrome/browser/system_monitor/removable_device_constants.h" |
19 #include "chrome/browser/system_monitor/volume_mount_watcher_win.h" | 23 #include "chrome/browser/system_monitor/volume_mount_watcher_win.h" |
20 #include "content/public/test/test_browser_thread.h" | 24 #include "content/public/test/test_browser_thread.h" |
21 #include "testing/gmock/include/gmock/gmock.h" | 25 #include "testing/gmock/include/gmock/gmock.h" |
22 #include "testing/gtest/include/gtest/gtest.h" | 26 #include "testing/gtest/include/gtest/gtest.h" |
23 | 27 |
| 28 namespace chrome { |
| 29 |
24 namespace { | 30 namespace { |
25 | 31 |
26 using content::BrowserThread; | 32 using content::BrowserThread; |
27 using chrome::RemovableDeviceNotificationsWindowWin; | 33 |
| 34 // Mtp device interface path constants. |
| 35 const char16 kMtpDeviceWithInvalidInfo[] = |
| 36 L"\\?\usb#vid_00&pid_00#0&2&1#{0000-0000-0000-0000-0000})"; |
| 37 const char16 kMtpDeviceWithValidInfo[] = |
| 38 L"\\?\usb#vid_ff&pid_000f#32&2&1#{abcd-1234-ffde-1112-9172})"; |
| 39 const char16 kMtpDeviceWithMultipleStorage[] = |
| 40 L"\\?\usb#vid_ff&pid_18#32&2&1#{ab33-1de4-f22e-1882-9724})"; |
| 41 |
| 42 // Sample mtp device storage information. |
| 43 const char16 kMtpDeviceFriendlyName[] = L"Camera V1.1"; |
| 44 const char16 kStorageLabelA[] = L"Camera V1.1 (s10001)"; |
| 45 const char16 kStorageLabelB[] = L"Camera V1.1 (s20001)"; |
| 46 const char16 kStorageObjectIdA[] = L"s10001"; |
| 47 const char16 kStorageObjectIdB[] = L"s20001"; |
| 48 const char kStorageUniqueIdA[] = |
| 49 "mtp:StorageSerial:SID-{s10001, D, 12378}:123123"; |
| 50 const char kStorageUniqueIdB[] = |
| 51 "mtp:StorageSerial:SID-{s20001, S, 2238}:123123"; |
28 | 52 |
29 // Inputs of 'A:\' - 'Z:\' are valid. 'N:\' is not removable. | 53 // Inputs of 'A:\' - 'Z:\' are valid. 'N:\' is not removable. |
30 bool GetDeviceDetails(const FilePath& device_path, string16* device_location, | 54 bool GetMassStorageDeviceDetails(const FilePath& device_path, |
31 std::string* unique_id, string16* name, bool* removable) { | 55 string16* device_location, |
| 56 std::string* unique_id, |
| 57 string16* name, |
| 58 bool* removable) { |
32 if (device_path.value().length() != 3 || device_path.value()[0] < L'A' || | 59 if (device_path.value().length() != 3 || device_path.value()[0] < L'A' || |
33 device_path.value()[0] > L'Z') { | 60 device_path.value()[0] > L'Z') { |
34 return false; | 61 return false; |
35 } | 62 } |
36 | 63 |
37 if (device_location) | 64 if (device_location) |
38 *device_location = device_path.value(); | 65 *device_location = device_path.value(); |
39 if (unique_id) { | 66 if (unique_id) { |
40 *unique_id = "\\\\?\\Volume{00000000-0000-0000-0000-000000000000}\\"; | 67 *unique_id = "\\\\?\\Volume{00000000-0000-0000-0000-000000000000}\\"; |
41 (*unique_id)[11] = device_path.value()[0]; | 68 (*unique_id)[11] = device_path.value()[0]; |
(...skipping 16 matching lines...) Expand all Loading... |
58 result.push_back(DriveNumberToFilePath(0)); | 85 result.push_back(DriveNumberToFilePath(0)); |
59 result.push_back(DriveNumberToFilePath(1)); | 86 result.push_back(DriveNumberToFilePath(1)); |
60 result.push_back(DriveNumberToFilePath(2)); | 87 result.push_back(DriveNumberToFilePath(2)); |
61 result.push_back(DriveNumberToFilePath(3)); | 88 result.push_back(DriveNumberToFilePath(3)); |
62 result.push_back(DriveNumberToFilePath(5)); | 89 result.push_back(DriveNumberToFilePath(5)); |
63 result.push_back(DriveNumberToFilePath(7)); | 90 result.push_back(DriveNumberToFilePath(7)); |
64 result.push_back(DriveNumberToFilePath(25)); | 91 result.push_back(DriveNumberToFilePath(25)); |
65 return result; | 92 return result; |
66 } | 93 } |
67 | 94 |
| 95 // Returns the persistent storage unique id of the device specified by the |
| 96 // |pnp_device_id|. |storage_object_id| specifies the temporary object |
| 97 // identifier that uniquely identifies the object on the device. |
| 98 std::string GetMtpStorageUniqueId(const string16& pnp_device_id, |
| 99 const string16& storage_object_id) { |
| 100 if (storage_object_id == kStorageObjectIdA) |
| 101 return kStorageUniqueIdA; |
| 102 |
| 103 return (storage_object_id == kStorageObjectIdB) ? |
| 104 kStorageUniqueIdB : std::string(); |
| 105 } |
| 106 |
| 107 // Returns the storage name of the device specified by |pnp_device_id|. |
| 108 // |storage_object_id| specifies the temporary object identifier that |
| 109 // uniquely identifies the object on the device. |
| 110 string16 GetMtpStorageName(const string16& pnp_device_id, |
| 111 const string16& storage_object_id) { |
| 112 if (pnp_device_id == kMtpDeviceWithInvalidInfo) |
| 113 return string16(); |
| 114 |
| 115 if (storage_object_id == kStorageObjectIdA) |
| 116 return kStorageLabelA; |
| 117 |
| 118 return (storage_object_id == kStorageObjectIdB) ? |
| 119 kStorageLabelB : string16(); |
| 120 } |
| 121 |
| 122 // Returns a list of storage object identifiers of the device given a |
| 123 // |pnp_device_id|. |
| 124 std::vector<string16> GetMtpStorageObjectIds(const string16& pnp_device_id) { |
| 125 std::vector<string16> storage_object_ids; |
| 126 storage_object_ids.push_back(kStorageObjectIdA); |
| 127 |
| 128 if (pnp_device_id == kMtpDeviceWithMultipleStorage) |
| 129 storage_object_ids.push_back(kStorageObjectIdB); |
| 130 return storage_object_ids; |
| 131 } |
| 132 |
| 133 // Gets the mtp device storage details given a |pnp_device_id| and |
| 134 // |storage_object_id|. On success, returns true and fills in |
| 135 // |device_location|, |unique_id| and |name|. |
| 136 void GetMtpStorageDetails(const string16& pnp_device_id, |
| 137 const string16& storage_object_id, |
| 138 string16* device_location, |
| 139 std::string* unique_id, |
| 140 string16* name) { |
| 141 std::string storage_unique_id = GetMtpStorageUniqueId(pnp_device_id, |
| 142 storage_object_id); |
| 143 |
| 144 if (device_location) { |
| 145 std::string root_path("\\\\"); |
| 146 *device_location = UTF8ToUTF16(root_path + storage_unique_id); |
| 147 } |
| 148 |
| 149 if (unique_id) |
| 150 *unique_id = storage_unique_id; |
| 151 |
| 152 if (name) |
| 153 *name = GetMtpStorageName(pnp_device_id, storage_object_id); |
| 154 } |
| 155 |
| 156 // Returns a list of device storage details for the given device specified by |
| 157 // |pnp_device_id|. |
| 158 std::vector<PortableDeviceWatcherWin::DeviceStorageInfo> |
| 159 GetDeviceStorageInfoList(const string16& pnp_device_id) { |
| 160 std::vector<PortableDeviceWatcherWin::DeviceStorageInfo> storage_info_list; |
| 161 std::vector<string16> storage_object_ids = |
| 162 GetMtpStorageObjectIds(pnp_device_id); |
| 163 for (size_t index = 0; index < storage_object_ids.size(); ++index) { |
| 164 PortableDeviceWatcherWin::DeviceStorageInfo storage; |
| 165 storage.unique_id = GetMtpStorageUniqueId(pnp_device_id, |
| 166 storage_object_ids[index]); |
| 167 storage.storage_object_id = storage_object_ids[index]; |
| 168 storage_info_list.push_back(storage); |
| 169 } |
| 170 return storage_info_list; |
| 171 } |
| 172 |
68 } // namespace | 173 } // namespace |
69 | 174 |
70 namespace chrome { | 175 // Wrapper class for testing PortableDeviceWatcherWin. |
| 176 class TestPortableDeviceWatcherWin : public PortableDeviceWatcherWin { |
| 177 public: |
| 178 TestPortableDeviceWatcherWin(); |
| 179 virtual ~TestPortableDeviceWatcherWin(); |
| 180 |
| 181 private: |
| 182 // Override PortableDeviceWatcherWin:: |
| 183 virtual void EnumerateAttachedDevices() OVERRIDE; |
| 184 virtual void HandleDeviceAttachEvent(const string16& pnp_device_id) OVERRIDE; |
| 185 |
| 186 DISALLOW_COPY_AND_ASSIGN(TestPortableDeviceWatcherWin); |
| 187 }; |
71 | 188 |
72 // Wrapper class for testing VolumeMountWatcherWin. | 189 // Wrapper class for testing VolumeMountWatcherWin. |
73 class TestVolumeMountWatcherWin : public VolumeMountWatcherWin { | 190 class TestVolumeMountWatcherWin : public VolumeMountWatcherWin { |
74 public: | 191 public: |
75 TestVolumeMountWatcherWin() : pre_attach_devices_(false) { | 192 TestVolumeMountWatcherWin(); |
76 } | |
77 | 193 |
78 // Override VolumeMountWatcherWin::GetDeviceInfo(). | 194 void set_pre_attach_devices(bool pre_attach_devices); |
79 virtual bool GetDeviceInfo(const FilePath& device_path, | |
80 string16* device_location, std::string* unique_id, string16* name, | |
81 bool* removable) OVERRIDE { | |
82 return GetDeviceDetails(device_path, device_location, unique_id, name, | |
83 removable); | |
84 } | |
85 | |
86 // Override VolumeMountWatcherWin::GetAttachedDevices(). | |
87 virtual std::vector<FilePath> GetAttachedDevices() OVERRIDE{ | |
88 if (pre_attach_devices_) | |
89 return GetTestAttachedDevices(); | |
90 return std::vector<FilePath>(); | |
91 } | |
92 | |
93 void set_pre_attach_devices(bool pre_attach_devices) { | |
94 pre_attach_devices_ = pre_attach_devices; | |
95 } | |
96 | 195 |
97 private: | 196 private: |
98 // Private, this class is ref-counted. | 197 // Private, this class is ref-counted. |
99 virtual ~TestVolumeMountWatcherWin() { | 198 virtual ~TestVolumeMountWatcherWin(); |
100 } | 199 |
| 200 // Override VolumeMountWatcherWin:: |
| 201 virtual bool GetDeviceInfo(const FilePath& device_path, |
| 202 string16* device_location, |
| 203 std::string* unique_id, |
| 204 string16* name, |
| 205 bool* removable) OVERRIDE; |
| 206 virtual std::vector<FilePath> GetAttachedDevices() OVERRIDE; |
101 | 207 |
102 // Set to true to pre-attach test devices. | 208 // Set to true to pre-attach test devices. |
103 bool pre_attach_devices_; | 209 bool pre_attach_devices_; |
| 210 |
| 211 DISALLOW_COPY_AND_ASSIGN(TestVolumeMountWatcherWin); |
104 }; | 212 }; |
105 | 213 |
106 // Wrapper class for testing RemovableDeviceNotificationsWindowWin. | 214 // Wrapper class for testing RemovableDeviceNotificationsWindowWin. |
107 class TestRemovableDeviceNotificationsWindowWin | 215 class TestRemovableDeviceNotificationsWindowWin |
108 : public RemovableDeviceNotificationsWindowWin { | 216 : public RemovableDeviceNotificationsWindowWin { |
109 public: | 217 public: |
110 explicit TestRemovableDeviceNotificationsWindowWin( | 218 TestRemovableDeviceNotificationsWindowWin( |
111 TestVolumeMountWatcherWin* volume_mount_watcher) | 219 TestVolumeMountWatcherWin* volume_mount_watcher, |
112 : RemovableDeviceNotificationsWindowWin(volume_mount_watcher), | 220 TestPortableDeviceWatcherWin* portable_device_watcher); |
113 volume_mount_watcher_(volume_mount_watcher) { | |
114 DCHECK(volume_mount_watcher_); | |
115 } | |
116 | 221 |
117 virtual ~TestRemovableDeviceNotificationsWindowWin() { | 222 virtual ~TestRemovableDeviceNotificationsWindowWin(); |
118 } | |
119 | 223 |
120 void InitWithTestData() { | 224 void InitWithTestData(); |
121 volume_mount_watcher_->set_pre_attach_devices(false); | 225 void InitWithTestDataAndAttachedDevices(); |
122 Init(); | 226 void InjectDeviceChange(UINT event_type, DWORD data); |
123 } | |
124 | |
125 void InitWithTestDataAndAttachedDevices() { | |
126 volume_mount_watcher_->set_pre_attach_devices(true); | |
127 Init(); | |
128 } | |
129 | |
130 void InjectDeviceChange(UINT event_type, DWORD data) { | |
131 OnDeviceChange(event_type, data); | |
132 } | |
133 | 227 |
134 private: | 228 private: |
135 scoped_refptr<TestVolumeMountWatcherWin> volume_mount_watcher_; | 229 scoped_refptr<TestVolumeMountWatcherWin> volume_mount_watcher_; |
136 }; | 230 }; |
137 | 231 |
138 class RemovableDeviceNotificationsWindowWinTest : public testing::Test { | 232 class RemovableDeviceNotificationsWindowWinTest : public testing::Test { |
139 public: | 233 public: |
140 RemovableDeviceNotificationsWindowWinTest() | 234 RemovableDeviceNotificationsWindowWinTest(); |
141 : ui_thread_(BrowserThread::UI, &message_loop_), | 235 virtual ~RemovableDeviceNotificationsWindowWinTest(); |
142 file_thread_(BrowserThread::FILE, &message_loop_) { } | |
143 virtual ~RemovableDeviceNotificationsWindowWinTest() { } | |
144 | 236 |
145 protected: | 237 protected: |
146 virtual void SetUp() OVERRIDE { | 238 virtual void SetUp() OVERRIDE; |
147 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI)); | 239 virtual void TearDown(); |
148 volume_mount_watcher_ = new TestVolumeMountWatcherWin; | |
149 window_.reset(new TestRemovableDeviceNotificationsWindowWin( | |
150 volume_mount_watcher_.get())); | |
151 window_->InitWithTestData(); | |
152 message_loop_.RunAllPending(); | |
153 system_monitor_.AddDevicesChangedObserver(&observer_); | |
154 } | |
155 | 240 |
156 virtual void TearDown() { | 241 void AddMassStorageDeviceAttachExpectation(FilePath drive); |
157 message_loop_.RunAllPending(); | 242 void PreAttachDevices(); |
158 system_monitor_.RemoveDevicesChangedObserver(&observer_); | |
159 } | |
160 | 243 |
161 void AddAttachExpectation(FilePath drive) { | 244 // Runs all the pending tasks on UI thread, FILE thread and blocking thread. |
162 std::string unique_id; | 245 void RunAllPending(); |
163 string16 device_name; | |
164 bool removable; | |
165 ASSERT_TRUE(GetDeviceDetails(drive, NULL, &unique_id, &device_name, | |
166 &removable)); | |
167 if (removable) { | |
168 MediaStorageUtil::Type type = | |
169 MediaStorageUtil::REMOVABLE_MASS_STORAGE_NO_DCIM; | |
170 std::string device_id = MediaStorageUtil::MakeDeviceId(type, unique_id); | |
171 EXPECT_CALL(observer_, OnRemovableStorageAttached(device_id, device_name, | |
172 drive.value())) | |
173 .Times(1); | |
174 } | |
175 } | |
176 | 246 |
177 void PreAttachDevices() { | 247 void DoMassStorageDeviceAttachedTest(const std::vector<int>& device_indices); |
178 window_.reset(); | 248 void DoMassStorageDevicesDetachedTest(const std::vector<int>& device_indices); |
179 { | 249 void DoMtpDeviceAttachedTest(const string16& pnp_device_id); |
180 testing::InSequence sequence; | 250 void DoMtpDeviceDetachedTest(const string16& pnp_device_id); |
181 std::vector<FilePath> initial_devices = GetTestAttachedDevices(); | |
182 for (size_t i = 0; i < initial_devices.size(); i++) | |
183 AddAttachExpectation(initial_devices[i]); | |
184 } | |
185 window_.reset(new TestRemovableDeviceNotificationsWindowWin( | |
186 volume_mount_watcher_.get())); | |
187 window_->InitWithTestDataAndAttachedDevices(); | |
188 message_loop_.RunAllPending(); | |
189 } | |
190 | |
191 void DoDevicesAttachedTest(const std::vector<int>& device_indices); | |
192 void DoDevicesDetachedTest(const std::vector<int>& device_indices); | |
193 | 251 |
194 MessageLoopForUI message_loop_; | 252 MessageLoopForUI message_loop_; |
195 content::TestBrowserThread ui_thread_; | 253 content::TestBrowserThread ui_thread_; |
196 content::TestBrowserThread file_thread_; | 254 content::TestBrowserThread file_thread_; |
197 | 255 |
198 base::SystemMonitor system_monitor_; | 256 base::SystemMonitor system_monitor_; |
199 base::MockDevicesChangedObserver observer_; | 257 base::MockDevicesChangedObserver observer_; |
200 scoped_ptr<TestRemovableDeviceNotificationsWindowWin> window_; | 258 scoped_ptr<TestRemovableDeviceNotificationsWindowWin> window_; |
201 scoped_refptr<TestVolumeMountWatcherWin> volume_mount_watcher_; | 259 scoped_refptr<TestVolumeMountWatcherWin> volume_mount_watcher_; |
202 }; | 260 }; |
203 | 261 |
204 void RemovableDeviceNotificationsWindowWinTest::DoDevicesAttachedTest( | 262 // TestPortableDeviceWatcherWin implementation. |
205 const std::vector<int>& device_indices) { | 263 TestPortableDeviceWatcherWin::TestPortableDeviceWatcherWin() { |
| 264 } |
| 265 |
| 266 TestPortableDeviceWatcherWin::~TestPortableDeviceWatcherWin() { |
| 267 } |
| 268 |
| 269 void TestPortableDeviceWatcherWin::EnumerateAttachedDevices() { |
| 270 } |
| 271 |
| 272 void TestPortableDeviceWatcherWin::HandleDeviceAttachEvent( |
| 273 const string16& pnp_device_id) { |
| 274 DeviceDetails device_details; |
| 275 std::vector<DeviceStorageInfo> storage_info_list; |
| 276 device_details.storage_info_list = GetDeviceStorageInfoList(pnp_device_id); |
| 277 device_details.name = (pnp_device_id != kMtpDeviceWithInvalidInfo) ? |
| 278 kMtpDeviceFriendlyName : string16(); |
| 279 device_details.location = pnp_device_id; |
| 280 OnHandleDeviceAttachEvent(device_details); |
| 281 } |
| 282 |
| 283 // TestVolumeMountWatcherWin implementation. |
| 284 TestVolumeMountWatcherWin::TestVolumeMountWatcherWin() |
| 285 : pre_attach_devices_(false) { |
| 286 } |
| 287 |
| 288 void TestVolumeMountWatcherWin::set_pre_attach_devices( |
| 289 bool pre_attach_devices) { |
| 290 pre_attach_devices_ = pre_attach_devices; |
| 291 } |
| 292 |
| 293 TestVolumeMountWatcherWin::~TestVolumeMountWatcherWin() { |
| 294 } |
| 295 |
| 296 bool TestVolumeMountWatcherWin::GetDeviceInfo(const FilePath& device_path, |
| 297 string16* device_location, |
| 298 std::string* unique_id, |
| 299 string16* name, |
| 300 bool* removable) { |
| 301 return GetMassStorageDeviceDetails(device_path, device_location, unique_id, |
| 302 name, removable); |
| 303 } |
| 304 |
| 305 std::vector<FilePath> TestVolumeMountWatcherWin::GetAttachedDevices() { |
| 306 return pre_attach_devices_ ? GetTestAttachedDevices() : |
| 307 std::vector<FilePath>(); |
| 308 } |
| 309 |
| 310 // TestRemovableDeviceNotificationsWindowWin implementation. |
| 311 TestRemovableDeviceNotificationsWindowWin:: |
| 312 TestRemovableDeviceNotificationsWindowWin( |
| 313 TestVolumeMountWatcherWin* volume_mount_watcher, |
| 314 TestPortableDeviceWatcherWin* portable_device_watcher) |
| 315 : RemovableDeviceNotificationsWindowWin(volume_mount_watcher, |
| 316 portable_device_watcher), |
| 317 volume_mount_watcher_(volume_mount_watcher) { |
| 318 DCHECK(volume_mount_watcher_); |
| 319 } |
| 320 |
| 321 TestRemovableDeviceNotificationsWindowWin:: |
| 322 ~TestRemovableDeviceNotificationsWindowWin() { |
| 323 } |
| 324 |
| 325 void TestRemovableDeviceNotificationsWindowWin::InitWithTestData() { |
| 326 volume_mount_watcher_->set_pre_attach_devices(false); |
| 327 Init(); |
| 328 } |
| 329 |
| 330 void TestRemovableDeviceNotificationsWindowWin:: |
| 331 InitWithTestDataAndAttachedDevices() { |
| 332 volume_mount_watcher_->set_pre_attach_devices(true); |
| 333 Init(); |
| 334 } |
| 335 |
| 336 void TestRemovableDeviceNotificationsWindowWin::InjectDeviceChange( |
| 337 UINT event_type, DWORD data) { |
| 338 OnDeviceChange(event_type, data); |
| 339 } |
| 340 |
| 341 // RemovableDeviceNotificationsWindowWinTest implementation. |
| 342 RemovableDeviceNotificationsWindowWinTest:: |
| 343 RemovableDeviceNotificationsWindowWinTest() |
| 344 : ui_thread_(BrowserThread::UI, &message_loop_), |
| 345 file_thread_(BrowserThread::FILE, &message_loop_) { |
| 346 } |
| 347 |
| 348 RemovableDeviceNotificationsWindowWinTest:: |
| 349 ~RemovableDeviceNotificationsWindowWinTest() { |
| 350 } |
| 351 |
| 352 void RemovableDeviceNotificationsWindowWinTest::SetUp() { |
| 353 ASSERT_TRUE(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| 354 volume_mount_watcher_ = new TestVolumeMountWatcherWin; |
| 355 window_.reset(new TestRemovableDeviceNotificationsWindowWin( |
| 356 volume_mount_watcher_.get(), new TestPortableDeviceWatcherWin)); |
| 357 window_->InitWithTestData(); |
| 358 RunAllPending(); |
| 359 system_monitor_.AddDevicesChangedObserver(&observer_); |
| 360 } |
| 361 |
| 362 void RemovableDeviceNotificationsWindowWinTest::TearDown() { |
| 363 RunAllPending(); |
| 364 system_monitor_.RemoveDevicesChangedObserver(&observer_); |
| 365 } |
| 366 |
| 367 void RemovableDeviceNotificationsWindowWinTest:: |
| 368 AddMassStorageDeviceAttachExpectation(FilePath drive) { |
| 369 std::string unique_id; |
| 370 string16 device_name; |
| 371 bool removable; |
| 372 ASSERT_TRUE(GetMassStorageDeviceDetails(drive, NULL, &unique_id, |
| 373 &device_name, &removable)); |
| 374 if (removable) { |
| 375 MediaStorageUtil::Type type = |
| 376 MediaStorageUtil::REMOVABLE_MASS_STORAGE_NO_DCIM; |
| 377 std::string device_id = MediaStorageUtil::MakeDeviceId(type, unique_id); |
| 378 EXPECT_CALL(observer_, OnRemovableStorageAttached(device_id, device_name, |
| 379 drive.value())) |
| 380 .Times(1); |
| 381 } |
| 382 } |
| 383 |
| 384 void RemovableDeviceNotificationsWindowWinTest::PreAttachDevices() { |
| 385 window_.reset(); |
| 386 { |
| 387 testing::InSequence sequence; |
| 388 std::vector<FilePath> initial_devices = GetTestAttachedDevices(); |
| 389 for (size_t i = 0; i < initial_devices.size(); i++) |
| 390 AddMassStorageDeviceAttachExpectation(initial_devices[i]); |
| 391 } |
| 392 window_.reset(new TestRemovableDeviceNotificationsWindowWin( |
| 393 volume_mount_watcher_.get(), new TestPortableDeviceWatcherWin)); |
| 394 window_->InitWithTestDataAndAttachedDevices(); |
| 395 RunAllPending(); |
| 396 } |
| 397 |
| 398 void RemovableDeviceNotificationsWindowWinTest::RunAllPending() { |
| 399 message_loop_.RunAllPending(); |
| 400 } |
| 401 |
| 402 void RemovableDeviceNotificationsWindowWinTest:: |
| 403 DoMassStorageDeviceAttachedTest(const std::vector<int>& device_indices) { |
206 DEV_BROADCAST_VOLUME volume_broadcast; | 404 DEV_BROADCAST_VOLUME volume_broadcast; |
207 volume_broadcast.dbcv_size = sizeof(volume_broadcast); | 405 volume_broadcast.dbcv_size = sizeof(volume_broadcast); |
208 volume_broadcast.dbcv_devicetype = DBT_DEVTYP_VOLUME; | 406 volume_broadcast.dbcv_devicetype = DBT_DEVTYP_VOLUME; |
209 volume_broadcast.dbcv_unitmask = 0x0; | 407 volume_broadcast.dbcv_unitmask = 0x0; |
210 volume_broadcast.dbcv_flags = 0x0; | 408 volume_broadcast.dbcv_flags = 0x0; |
211 { | 409 { |
212 testing::InSequence sequence; | 410 testing::InSequence sequence; |
213 for (std::vector<int>::const_iterator it = device_indices.begin(); | 411 for (std::vector<int>::const_iterator it = device_indices.begin(); |
214 it != device_indices.end(); | 412 it != device_indices.end(); |
215 ++it) { | 413 ++it) { |
216 volume_broadcast.dbcv_unitmask |= 0x1 << *it; | 414 volume_broadcast.dbcv_unitmask |= 0x1 << *it; |
217 AddAttachExpectation(DriveNumberToFilePath(*it)); | 415 AddMassStorageDeviceAttachExpectation(DriveNumberToFilePath(*it)); |
218 } | 416 } |
219 } | 417 } |
220 window_->InjectDeviceChange(DBT_DEVICEARRIVAL, | 418 window_->InjectDeviceChange(DBT_DEVICEARRIVAL, |
221 reinterpret_cast<DWORD>(&volume_broadcast)); | 419 reinterpret_cast<DWORD>(&volume_broadcast)); |
222 message_loop_.RunAllPending(); | 420 RunAllPending(); |
223 } | 421 } |
224 | 422 |
225 void RemovableDeviceNotificationsWindowWinTest::DoDevicesDetachedTest( | 423 void RemovableDeviceNotificationsWindowWinTest:: |
226 const std::vector<int>& device_indices) { | 424 DoMassStorageDevicesDetachedTest(const std::vector<int>& device_indices) { |
227 DEV_BROADCAST_VOLUME volume_broadcast; | 425 DEV_BROADCAST_VOLUME volume_broadcast; |
228 volume_broadcast.dbcv_size = sizeof(volume_broadcast); | 426 volume_broadcast.dbcv_size = sizeof(volume_broadcast); |
229 volume_broadcast.dbcv_devicetype = DBT_DEVTYP_VOLUME; | 427 volume_broadcast.dbcv_devicetype = DBT_DEVTYP_VOLUME; |
230 volume_broadcast.dbcv_unitmask = 0x0; | 428 volume_broadcast.dbcv_unitmask = 0x0; |
231 volume_broadcast.dbcv_flags = 0x0; | 429 volume_broadcast.dbcv_flags = 0x0; |
232 { | 430 { |
233 testing::InSequence sequence; | 431 testing::InSequence sequence; |
234 for (std::vector<int>::const_iterator it = device_indices.begin(); | 432 for (std::vector<int>::const_iterator it = device_indices.begin(); |
235 it != device_indices.end(); | 433 it != device_indices.end(); |
236 ++it) { | 434 ++it) { |
237 volume_broadcast.dbcv_unitmask |= 0x1 << *it; | 435 volume_broadcast.dbcv_unitmask |= 0x1 << *it; |
238 std::string unique_id; | 436 std::string unique_id; |
239 bool removable; | 437 bool removable; |
240 ASSERT_TRUE(GetDeviceDetails(DriveNumberToFilePath(*it), NULL, &unique_id, | 438 ASSERT_TRUE(GetMassStorageDeviceDetails(DriveNumberToFilePath(*it), NULL, |
241 NULL, &removable)); | 439 &unique_id, NULL, &removable)); |
242 if (removable) { | 440 if (removable) { |
243 MediaStorageUtil::Type type = | 441 MediaStorageUtil::Type type = |
244 MediaStorageUtil::REMOVABLE_MASS_STORAGE_NO_DCIM; | 442 MediaStorageUtil::REMOVABLE_MASS_STORAGE_NO_DCIM; |
245 std::string device_id = MediaStorageUtil::MakeDeviceId(type, unique_id); | 443 std::string device_id = MediaStorageUtil::MakeDeviceId(type, unique_id); |
246 EXPECT_CALL(observer_, OnRemovableStorageDetached(device_id)).Times(1); | 444 EXPECT_CALL(observer_, OnRemovableStorageDetached(device_id)).Times(1); |
247 } | 445 } |
248 } | 446 } |
249 } | 447 } |
250 window_->InjectDeviceChange(DBT_DEVICEREMOVECOMPLETE, | 448 window_->InjectDeviceChange(DBT_DEVICEREMOVECOMPLETE, |
251 reinterpret_cast<DWORD>(&volume_broadcast)); | 449 reinterpret_cast<DWORD>(&volume_broadcast)); |
252 message_loop_.RunAllPending(); | 450 RunAllPending(); |
| 451 } |
| 452 |
| 453 void RemovableDeviceNotificationsWindowWinTest::DoMtpDeviceAttachedTest( |
| 454 const string16& pnp_device_id) { |
| 455 GUID guidDevInterface = GUID_NULL; |
| 456 HRESULT hr = CLSIDFromString(kWPDDevInterfaceGUID, &guidDevInterface); |
| 457 if (FAILED(hr)) |
| 458 return; |
| 459 |
| 460 size_t device_id_size = pnp_device_id.size() * sizeof(char16); |
| 461 size_t size = sizeof(DEV_BROADCAST_DEVICEINTERFACE) + device_id_size; |
| 462 scoped_ptr_malloc<DEV_BROADCAST_DEVICEINTERFACE> dev_interface_broadcast( |
| 463 static_cast<DEV_BROADCAST_DEVICEINTERFACE*>(malloc(size))); |
| 464 DCHECK(dev_interface_broadcast.get()); |
| 465 ZeroMemory(dev_interface_broadcast.get(), size); |
| 466 dev_interface_broadcast->dbcc_size = size; |
| 467 dev_interface_broadcast->dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; |
| 468 dev_interface_broadcast->dbcc_classguid = guidDevInterface; |
| 469 memcpy(dev_interface_broadcast->dbcc_name, pnp_device_id.data(), |
| 470 device_id_size); |
| 471 { |
| 472 testing::InSequence sequence; |
| 473 std::vector<string16> storage_object_ids = |
| 474 GetMtpStorageObjectIds(pnp_device_id); |
| 475 for (size_t index = 0; index < storage_object_ids.size(); ++index) { |
| 476 std::string unique_id; |
| 477 string16 name; |
| 478 string16 location; |
| 479 GetMtpStorageDetails(pnp_device_id, storage_object_ids[index], |
| 480 &location, &unique_id, &name); |
| 481 int cardinality = 1; |
| 482 if (name.empty() || unique_id.empty()) |
| 483 cardinality = 0; |
| 484 EXPECT_CALL(observer_, OnRemovableStorageAttached(unique_id, name, |
| 485 location)) |
| 486 .Times(cardinality); |
| 487 } |
| 488 } |
| 489 window_->InjectDeviceChange( |
| 490 DBT_DEVICEARRIVAL, |
| 491 reinterpret_cast<DWORD>(dev_interface_broadcast.get())); |
| 492 RunAllPending(); |
| 493 } |
| 494 |
| 495 void RemovableDeviceNotificationsWindowWinTest::DoMtpDeviceDetachedTest( |
| 496 const string16& pnp_device_id) { |
| 497 GUID guidDevInterface = GUID_NULL; |
| 498 HRESULT hr = CLSIDFromString(kWPDDevInterfaceGUID, &guidDevInterface); |
| 499 if (FAILED(hr)) |
| 500 return; |
| 501 |
| 502 size_t device_id_size = pnp_device_id.size() * sizeof(char16); |
| 503 size_t size = sizeof(DEV_BROADCAST_DEVICEINTERFACE) + device_id_size; |
| 504 |
| 505 scoped_ptr_malloc<DEV_BROADCAST_DEVICEINTERFACE> dev_interface_broadcast( |
| 506 static_cast<DEV_BROADCAST_DEVICEINTERFACE*>(malloc(size))); |
| 507 DCHECK(dev_interface_broadcast.get()); |
| 508 ZeroMemory(dev_interface_broadcast.get(), size); |
| 509 dev_interface_broadcast->dbcc_size = size; |
| 510 dev_interface_broadcast->dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE; |
| 511 dev_interface_broadcast->dbcc_classguid = guidDevInterface; |
| 512 memcpy(dev_interface_broadcast->dbcc_name, pnp_device_id.data(), |
| 513 device_id_size); |
| 514 { |
| 515 testing::InSequence sequence; |
| 516 std::vector<string16> storage_object_ids = |
| 517 GetMtpStorageObjectIds(pnp_device_id); |
| 518 for (size_t index = 0; index < storage_object_ids.size(); ++index) { |
| 519 std::string unique_id; |
| 520 string16 name; |
| 521 GetMtpStorageDetails(pnp_device_id, storage_object_ids[index], NULL, |
| 522 &unique_id, &name); |
| 523 int cardinality = 1; |
| 524 if (name.empty() || unique_id.empty()) |
| 525 cardinality = 0; |
| 526 EXPECT_CALL(observer_, OnRemovableStorageDetached(unique_id)) |
| 527 .Times(cardinality); |
| 528 } |
| 529 } |
| 530 window_->InjectDeviceChange( |
| 531 DBT_DEVICEREMOVECOMPLETE, |
| 532 reinterpret_cast<DWORD>(dev_interface_broadcast.get())); |
| 533 RunAllPending(); |
253 } | 534 } |
254 | 535 |
255 TEST_F(RemovableDeviceNotificationsWindowWinTest, RandomMessage) { | 536 TEST_F(RemovableDeviceNotificationsWindowWinTest, RandomMessage) { |
256 window_->InjectDeviceChange(DBT_DEVICEQUERYREMOVE, NULL); | 537 window_->InjectDeviceChange(DBT_DEVICEQUERYREMOVE, NULL); |
257 message_loop_.RunAllPending(); | 538 RunAllPending(); |
258 } | 539 } |
259 | 540 |
260 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesAttached) { | 541 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesAttached) { |
261 std::vector<int> device_indices; | 542 std::vector<int> device_indices; |
262 device_indices.push_back(1); | 543 device_indices.push_back(1); |
263 device_indices.push_back(5); | 544 device_indices.push_back(5); |
264 device_indices.push_back(7); | 545 device_indices.push_back(7); |
265 device_indices.push_back(13); | 546 device_indices.push_back(13); |
266 | 547 |
267 DoDevicesAttachedTest(device_indices); | 548 DoMassStorageDeviceAttachedTest(device_indices); |
268 } | 549 } |
269 | 550 |
270 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesAttachedHighBoundary) { | 551 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesAttachedHighBoundary) { |
271 std::vector<int> device_indices; | 552 std::vector<int> device_indices; |
272 device_indices.push_back(25); | 553 device_indices.push_back(25); |
273 | 554 |
274 DoDevicesAttachedTest(device_indices); | 555 DoMassStorageDeviceAttachedTest(device_indices); |
275 } | 556 } |
276 | 557 |
277 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesAttachedLowBoundary) { | 558 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesAttachedLowBoundary) { |
278 std::vector<int> device_indices; | 559 std::vector<int> device_indices; |
279 device_indices.push_back(0); | 560 device_indices.push_back(0); |
280 | 561 |
281 DoDevicesAttachedTest(device_indices); | 562 DoMassStorageDeviceAttachedTest(device_indices); |
282 } | 563 } |
283 | 564 |
284 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesAttachedAdjacentBits) { | 565 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesAttachedAdjacentBits) { |
285 std::vector<int> device_indices; | 566 std::vector<int> device_indices; |
286 device_indices.push_back(0); | 567 device_indices.push_back(0); |
287 device_indices.push_back(1); | 568 device_indices.push_back(1); |
288 device_indices.push_back(2); | 569 device_indices.push_back(2); |
289 device_indices.push_back(3); | 570 device_indices.push_back(3); |
290 | 571 |
291 DoDevicesAttachedTest(device_indices); | 572 DoMassStorageDeviceAttachedTest(device_indices); |
292 } | 573 } |
293 | 574 |
294 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesDetached) { | 575 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesDetached) { |
295 PreAttachDevices(); | 576 PreAttachDevices(); |
296 | 577 |
297 std::vector<int> device_indices; | 578 std::vector<int> device_indices; |
298 device_indices.push_back(1); | 579 device_indices.push_back(1); |
299 device_indices.push_back(5); | 580 device_indices.push_back(5); |
300 device_indices.push_back(7); | 581 device_indices.push_back(7); |
301 device_indices.push_back(13); | 582 device_indices.push_back(13); |
302 | 583 |
303 DoDevicesDetachedTest(device_indices); | 584 DoMassStorageDevicesDetachedTest(device_indices); |
304 } | 585 } |
305 | 586 |
306 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesDetachedHighBoundary) { | 587 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesDetachedHighBoundary) { |
307 PreAttachDevices(); | 588 PreAttachDevices(); |
308 | 589 |
309 std::vector<int> device_indices; | 590 std::vector<int> device_indices; |
310 device_indices.push_back(25); | 591 device_indices.push_back(25); |
311 | 592 |
312 DoDevicesDetachedTest(device_indices); | 593 DoMassStorageDevicesDetachedTest(device_indices); |
313 } | 594 } |
314 | 595 |
315 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesDetachedLowBoundary) { | 596 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesDetachedLowBoundary) { |
316 PreAttachDevices(); | 597 PreAttachDevices(); |
317 | 598 |
318 std::vector<int> device_indices; | 599 std::vector<int> device_indices; |
319 device_indices.push_back(0); | 600 device_indices.push_back(0); |
320 | 601 |
321 DoDevicesDetachedTest(device_indices); | 602 DoMassStorageDevicesDetachedTest(device_indices); |
322 } | 603 } |
323 | 604 |
324 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesDetachedAdjacentBits) { | 605 TEST_F(RemovableDeviceNotificationsWindowWinTest, DevicesDetachedAdjacentBits) { |
325 PreAttachDevices(); | 606 PreAttachDevices(); |
326 | 607 |
327 std::vector<int> device_indices; | 608 std::vector<int> device_indices; |
328 device_indices.push_back(0); | 609 device_indices.push_back(0); |
329 device_indices.push_back(1); | 610 device_indices.push_back(1); |
330 device_indices.push_back(2); | 611 device_indices.push_back(2); |
331 device_indices.push_back(3); | 612 device_indices.push_back(3); |
332 | 613 |
333 DoDevicesDetachedTest(device_indices); | 614 DoMassStorageDevicesDetachedTest(device_indices); |
334 } | 615 } |
335 | 616 |
336 TEST_F(RemovableDeviceNotificationsWindowWinTest, DeviceInfoFoPath) { | 617 TEST_F(RemovableDeviceNotificationsWindowWinTest, DeviceInfoFoPath) { |
337 PreAttachDevices(); | 618 PreAttachDevices(); |
338 | 619 |
339 // An invalid path. | 620 // An invalid path. |
340 EXPECT_FALSE(window_->GetDeviceInfoForPath(FilePath(L"COM1:\\"), NULL)); | 621 EXPECT_FALSE(window_->GetDeviceInfoForPath(FilePath(L"COM1:\\"), NULL)); |
341 | 622 |
342 // An unconnected removable device. | 623 // An unconnected removable device. |
343 EXPECT_FALSE(window_->GetDeviceInfoForPath(FilePath(L"E:\\"), NULL)); | 624 EXPECT_FALSE(window_->GetDeviceInfoForPath(FilePath(L"E:\\"), NULL)); |
344 | 625 |
345 // A connected removable device. | 626 // A connected removable device. |
346 FilePath removable_device(L"F:\\"); | 627 FilePath removable_device(L"F:\\"); |
347 base::SystemMonitor::RemovableStorageInfo device_info; | 628 base::SystemMonitor::RemovableStorageInfo device_info; |
348 EXPECT_TRUE(window_->GetDeviceInfoForPath(removable_device, &device_info)); | 629 EXPECT_TRUE(window_->GetDeviceInfoForPath(removable_device, &device_info)); |
349 | 630 |
350 std::string unique_id; | 631 std::string unique_id; |
351 string16 device_name; | 632 string16 device_name; |
352 bool removable; | 633 bool removable; |
353 ASSERT_TRUE(GetDeviceDetails(removable_device, NULL, &unique_id, &device_name, | 634 ASSERT_TRUE(GetMassStorageDeviceDetails(removable_device, NULL, &unique_id, |
354 &removable)); | 635 &device_name, &removable)); |
355 EXPECT_TRUE(removable); | 636 EXPECT_TRUE(removable); |
356 std::string device_id = MediaStorageUtil::MakeDeviceId( | 637 std::string device_id = MediaStorageUtil::MakeDeviceId( |
357 MediaStorageUtil::REMOVABLE_MASS_STORAGE_NO_DCIM, unique_id); | 638 MediaStorageUtil::REMOVABLE_MASS_STORAGE_NO_DCIM, unique_id); |
358 EXPECT_EQ(device_id, device_info.device_id); | 639 EXPECT_EQ(device_id, device_info.device_id); |
359 EXPECT_EQ(device_name, device_info.name); | 640 EXPECT_EQ(device_name, device_info.name); |
360 EXPECT_EQ(removable_device.value(), device_info.location); | 641 EXPECT_EQ(removable_device.value(), device_info.location); |
361 | 642 |
362 // A fixed device. | 643 // A fixed device. |
363 FilePath fixed_device(L"N:\\"); | 644 FilePath fixed_device(L"N:\\"); |
364 EXPECT_TRUE(window_->GetDeviceInfoForPath(fixed_device, &device_info)); | 645 EXPECT_TRUE(window_->GetDeviceInfoForPath(fixed_device, &device_info)); |
365 | 646 |
366 ASSERT_TRUE(GetDeviceDetails(fixed_device, NULL, &unique_id, &device_name, | 647 ASSERT_TRUE(GetMassStorageDeviceDetails(fixed_device, NULL, &unique_id, |
367 &removable)); | 648 &device_name, &removable)); |
368 EXPECT_FALSE(removable); | 649 EXPECT_FALSE(removable); |
369 device_id = MediaStorageUtil::MakeDeviceId( | 650 device_id = MediaStorageUtil::MakeDeviceId( |
370 MediaStorageUtil::FIXED_MASS_STORAGE, unique_id); | 651 MediaStorageUtil::FIXED_MASS_STORAGE, unique_id); |
371 EXPECT_EQ(device_id, device_info.device_id); | 652 EXPECT_EQ(device_id, device_info.device_id); |
372 EXPECT_EQ(device_name, device_info.name); | 653 EXPECT_EQ(device_name, device_info.name); |
373 EXPECT_EQ(fixed_device.value(), device_info.location); | 654 EXPECT_EQ(fixed_device.value(), device_info.location); |
374 } | 655 } |
375 | 656 |
| 657 // Test to verify basic mtp storage attach and detach notifications. |
| 658 TEST_F(RemovableDeviceNotificationsWindowWinTest, MtpDeviceBasicAttachDetach) { |
| 659 // Attach a mtp device. |
| 660 DoMtpDeviceAttachedTest(kMtpDeviceWithValidInfo); |
| 661 |
| 662 // Detach the attached device. |
| 663 DoMtpDeviceDetachedTest(kMtpDeviceWithValidInfo); |
| 664 } |
| 665 |
| 666 // When a mtp storage device with invalid storage label and id is |
| 667 // attached/detached, there should not be any device attach/detach |
| 668 // notifications. |
| 669 TEST_F(RemovableDeviceNotificationsWindowWinTest, MtpDeviceWithInvalidInfo) { |
| 670 // Attach the mtp storage with invalid storage info. |
| 671 DoMtpDeviceAttachedTest(kMtpDeviceWithInvalidInfo); |
| 672 |
| 673 // Detach the attached storage. |
| 674 DoMtpDeviceDetachedTest(kMtpDeviceWithInvalidInfo); |
| 675 } |
| 676 |
| 677 // Attach a device with two data partitions. Verify that attach/detach |
| 678 // notifications are sent out for each removable storage. |
| 679 TEST_F(RemovableDeviceNotificationsWindowWinTest, |
| 680 MtpDeviceWithMultipleStorages) { |
| 681 // Attach the mtp device with multiple storage. |
| 682 DoMtpDeviceAttachedTest(kMtpDeviceWithMultipleStorage); |
| 683 |
| 684 // Detach the attached device. |
| 685 DoMtpDeviceDetachedTest(kMtpDeviceWithMultipleStorage); |
| 686 } |
| 687 |
376 } // namespace chrome | 688 } // namespace chrome |
OLD | NEW |