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