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