Chromium Code Reviews
|
| OLD | NEW |
|---|---|
| (Empty) | |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include <mntent.h> | |
| 6 #include <stdio.h> | |
| 7 | |
| 8 #include <string> | |
| 9 | |
| 10 #include "base/file_util.h" | |
| 11 #include "base/logging.h" | |
| 12 #include "base/memory/scoped_ptr.h" | |
| 13 #include "base/message_loop.h" | |
| 14 #include "base/scoped_temp_dir.h" | |
| 15 #include "base/system_monitor/system_monitor.h" | |
| 16 #include "content/browser/browser_thread_impl.h" | |
| 17 #include "content/browser/media_device_notifications_linux.h" | |
| 18 #include "testing/gtest/include/gtest/gtest.h" | |
| 19 | |
| 20 namespace { | |
| 21 | |
| 22 const char* kValidFS = "vfat"; | |
| 23 const char* kInvalidFS = "invalidfs"; | |
| 24 | |
| 25 const char* kInvalidPath = "invalid path does not exist"; | |
| 26 | |
| 27 const char* kDevice1 = "d1"; | |
| 28 const char* kDevice2 = "d2"; | |
| 29 const char* kDevice3 = "d3"; | |
| 30 | |
| 31 const char* kMountPointA = "mnt_a"; | |
| 32 const char* kMountPointB = "mnt_b"; | |
| 33 | |
| 34 } // namespace | |
| 35 | |
| 36 namespace content { | |
| 37 | |
| 38 class MediaDeviceNotificationsLinuxTest : public testing::Test { | |
| 39 public: | |
| 40 struct MtabTestData { | |
| 41 MtabTestData(const char* mount_device, | |
| 42 const char* mount_point, | |
| 43 const char* mount_type) | |
| 44 : mount_device(mount_device), | |
| 45 mount_point(mount_point), | |
| 46 mount_type(mount_type) { | |
| 47 } | |
| 48 | |
| 49 const char* mount_device; | |
| 50 const char* mount_point; | |
| 51 const char* mount_type; | |
| 52 }; | |
| 53 | |
| 54 class DummyDeviceChangeObserver | |
|
vandebo (ex-Chrome)
2012/03/06 00:41:40
You should use MockDevicesChangedObserver
Lei Zhang
2012/03/06 19:00:25
Done.
| |
| 55 : public base::SystemMonitor::DevicesChangedObserver { | |
| 56 public: | |
| 57 DummyDeviceChangeObserver() | |
| 58 : attach_count_(0), | |
| 59 detach_count_(0) { | |
| 60 } | |
| 61 virtual ~DummyDeviceChangeObserver() {} | |
| 62 | |
| 63 void Reset() { | |
| 64 attach_count_ = 0; | |
| 65 detach_count_ = 0; | |
| 66 } | |
| 67 | |
| 68 int attach_count() { return attach_count_; } | |
| 69 int detach_count() { return detach_count_; } | |
| 70 | |
| 71 // base::SystemMonitor::DevicesChangedObserver implementation. | |
| 72 virtual void OnMediaDeviceAttached( | |
| 73 const base::SystemMonitor::DeviceIdType& id, | |
| 74 const std::string& name, | |
| 75 const FilePath& path) OVERRIDE { | |
| 76 ++attach_count_; | |
| 77 } | |
| 78 virtual void OnMediaDeviceDetached( | |
| 79 const base::SystemMonitor::DeviceIdType& id) OVERRIDE { | |
| 80 ++detach_count_; | |
| 81 } | |
| 82 | |
| 83 private: | |
| 84 int attach_count_; | |
| 85 int detach_count_; | |
| 86 | |
| 87 DISALLOW_COPY_AND_ASSIGN(DummyDeviceChangeObserver); | |
| 88 }; | |
| 89 | |
| 90 MediaDeviceNotificationsLinuxTest() | |
| 91 : message_loop_(MessageLoop::TYPE_IO), | |
| 92 file_thread_(BrowserThread::FILE, &message_loop_) { | |
| 93 system_monitor_.reset(new base::SystemMonitor()); | |
| 94 system_monitor_->AddDevicesChangedObserver(&dummy_device_change_observer_); | |
| 95 } | |
| 96 virtual ~MediaDeviceNotificationsLinuxTest() {} | |
| 97 | |
| 98 protected: | |
| 99 virtual void SetUp() { | |
| 100 dummy_device_change_observer_.Reset(); | |
| 101 | |
| 102 // Create and set up a temp dir with files for the test. | |
| 103 ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir()); | |
| 104 FilePath test_dir = scoped_temp_dir_.path().AppendASCII("etc"); | |
| 105 ASSERT_TRUE(file_util::CreateDirectory(test_dir)); | |
| 106 mtab_file_ = test_dir.AppendASCII("foo"); | |
|
vandebo (ex-Chrome)
2012/03/06 00:41:40
why not mtab ?
Lei Zhang
2012/03/06 19:00:25
The name is arbitrary. I changed it to "test_mtab"
| |
| 107 struct MtabTestData initial_test_data[] = { | |
| 108 MtabTestData("dummydevice", "dummydir", kInvalidFS), | |
| 109 }; | |
| 110 WriteToMtab(initial_test_data, arraysize(initial_test_data), true); | |
| 111 | |
| 112 // Initialize the test subject. | |
| 113 notifications_ = new MediaDeviceNotificationsLinux(mtab_file_); | |
| 114 BrowserThread::PostTask( | |
| 115 BrowserThread::FILE, FROM_HERE, | |
| 116 base::Bind(&MediaDeviceNotificationsLinux::InitOnFileThread, | |
| 117 notifications_.get())); | |
| 118 message_loop_.RunAllPending(); | |
| 119 } | |
| 120 | |
| 121 virtual void TearDown() { | |
| 122 message_loop_.RunAllPending(); | |
| 123 notifications_ = NULL; | |
| 124 ASSERT_TRUE(scoped_temp_dir_.Delete()); | |
| 125 } | |
| 126 | |
| 127 // Used to run tests. When the mtab file gets modified, the message loop | |
| 128 // needs to run in order to react to the file modification. | |
| 129 // See WriteToMtab for parameters. | |
| 130 void WriteToMtabAndRunLoop(struct MtabTestData* data, | |
| 131 size_t data_size, | |
| 132 bool overwrite) { | |
| 133 WriteToMtab(data, data_size, overwrite); | |
| 134 message_loop_.RunAllPending(); | |
| 135 } | |
| 136 | |
| 137 // Create a directory named |dir| relative to the test directory. | |
| 138 // Set |with_dcim_dir| to true if the created directory will have a "DCIM" | |
| 139 // subdirectory. | |
| 140 // Returns the full path to the created directory on success, or an empty | |
| 141 // path on failure. | |
| 142 FilePath CreateMountPoint(const char* dir, bool with_dcim_dir) { | |
| 143 FilePath return_path(scoped_temp_dir_.path()); | |
| 144 return_path = return_path.AppendASCII(dir); | |
| 145 FilePath path(return_path); | |
| 146 if (with_dcim_dir) | |
| 147 path = path.AppendASCII("DCIM"); | |
| 148 if (!file_util::CreateDirectory(path)) | |
| 149 return FilePath(); | |
| 150 return return_path; | |
| 151 } | |
| 152 | |
| 153 int attach_count() { return dummy_device_change_observer_.attach_count(); } | |
| 154 int detach_count() { return dummy_device_change_observer_.detach_count(); } | |
| 155 | |
| 156 private: | |
| 157 // Write the test mtab data to |mtab_file_|. | |
| 158 // |data| is an array of mtab entries. | |
| 159 // |data_size| is the array size of |data|. | |
| 160 // |overwrite| specifies whether to overwrite |mtab_file_|. | |
| 161 void WriteToMtab(struct MtabTestData* data, | |
| 162 size_t data_size, | |
| 163 bool overwrite) { | |
| 164 FILE* fd = setmntent(mtab_file_.value().c_str(), overwrite ? "w" : "a"); | |
| 165 ASSERT_TRUE(fd); | |
| 166 | |
| 167 scoped_ptr<char> mnt_opts(strdup("rw")); | |
| 168 struct mntent entry; | |
| 169 entry.mnt_opts = mnt_opts.get(); | |
| 170 entry.mnt_freq = 0; | |
| 171 entry.mnt_passno = 0; | |
| 172 for (size_t i = 0; i < data_size; ++i) { | |
| 173 scoped_ptr<char> mnt_fsname(strdup(data[i].mount_device)); | |
| 174 scoped_ptr<char> mnt_dir(strdup(data[i].mount_point)); | |
| 175 scoped_ptr<char> mnt_type(strdup(data[i].mount_type)); | |
| 176 entry.mnt_fsname = mnt_fsname.get(); | |
| 177 entry.mnt_dir = mnt_dir.get(); | |
| 178 entry.mnt_type = mnt_type.get(); | |
| 179 int add_result = addmntent(fd, &entry); | |
| 180 ASSERT_EQ(0, add_result); | |
| 181 } | |
| 182 int end_result = endmntent(fd); | |
| 183 ASSERT_EQ(1, end_result); | |
| 184 } | |
| 185 | |
| 186 // The message loop and file thread to run tests on. | |
| 187 MessageLoop message_loop_; | |
| 188 BrowserThreadImpl file_thread_; | |
| 189 | |
| 190 // SystemMonitor and DevicesChangedObserver to hook together to test. | |
| 191 scoped_ptr<base::SystemMonitor> system_monitor_; | |
| 192 DummyDeviceChangeObserver dummy_device_change_observer_; | |
| 193 | |
| 194 // Temporary directory for created test data. | |
| 195 ScopedTempDir scoped_temp_dir_; | |
| 196 // Path to the test mtab file. | |
| 197 FilePath mtab_file_; | |
| 198 | |
| 199 scoped_refptr<MediaDeviceNotificationsLinux> notifications_; | |
| 200 | |
| 201 DISALLOW_COPY_AND_ASSIGN(MediaDeviceNotificationsLinuxTest); | |
| 202 }; | |
| 203 | |
| 204 TEST_F(MediaDeviceNotificationsLinuxTest, BasicAttachDetach) { | |
| 205 FilePath test_path = CreateMountPoint(kMountPointA, true); | |
| 206 ASSERT_FALSE(test_path.empty()); | |
| 207 struct MtabTestData test_data[] = { | |
| 208 MtabTestData(kDevice1, kInvalidPath, kValidFS), | |
| 209 MtabTestData(kDevice2, test_path.value().c_str(), kValidFS), | |
| 210 }; | |
| 211 WriteToMtabAndRunLoop(test_data, arraysize(test_data), false); | |
| 212 EXPECT_EQ(1, attach_count()); | |
| 213 EXPECT_EQ(0, detach_count()); | |
| 214 | |
| 215 WriteToMtabAndRunLoop(NULL, 0, true); | |
| 216 EXPECT_EQ(1, attach_count()); | |
| 217 EXPECT_EQ(1, detach_count()); | |
| 218 } | |
| 219 | |
| 220 // Only mount points with DCIM directories are recognized. | |
| 221 TEST_F(MediaDeviceNotificationsLinuxTest, DCIM) { | |
| 222 FilePath test_path1 = CreateMountPoint(kMountPointA, true); | |
| 223 ASSERT_FALSE(test_path1.empty()); | |
| 224 struct MtabTestData test_data1[] = { | |
| 225 MtabTestData(kDevice1, test_path1.value().c_str(), kValidFS), | |
| 226 }; | |
| 227 WriteToMtabAndRunLoop(test_data1, arraysize(test_data1), false); | |
| 228 EXPECT_EQ(1, attach_count()); | |
| 229 EXPECT_EQ(0, detach_count()); | |
| 230 | |
| 231 FilePath test_path2 = CreateMountPoint(kMountPointB, false); | |
| 232 ASSERT_FALSE(test_path2.empty()); | |
| 233 struct MtabTestData test_data2[] = { | |
| 234 MtabTestData(kDevice2, test_path2.value().c_str(), kValidFS), | |
| 235 }; | |
| 236 WriteToMtabAndRunLoop(test_data2, arraysize(test_data2), false); | |
| 237 EXPECT_EQ(1, attach_count()); | |
| 238 EXPECT_EQ(0, detach_count()); | |
| 239 | |
| 240 WriteToMtabAndRunLoop(NULL, 0, true); | |
| 241 EXPECT_EQ(1, attach_count()); | |
| 242 EXPECT_EQ(1, detach_count()); | |
| 243 } | |
| 244 | |
| 245 TEST_F(MediaDeviceNotificationsLinuxTest, MultiDeviceMultiMount) { | |
| 246 FilePath test_path1 = CreateMountPoint(kMountPointA, true); | |
| 247 FilePath test_path2 = CreateMountPoint(kMountPointB, true); | |
| 248 ASSERT_FALSE(test_path1.empty()); | |
| 249 ASSERT_FALSE(test_path2.empty()); | |
| 250 | |
| 251 // Attach two devices. | |
| 252 // kDevice1 -> kMountPointA | |
| 253 // kDevice2 -> kMountPointB | |
| 254 struct MtabTestData test_data1[] = { | |
| 255 MtabTestData(kDevice1, test_path1.value().c_str(), kValidFS), | |
| 256 MtabTestData(kDevice2, test_path2.value().c_str(), kValidFS), | |
| 257 }; | |
| 258 WriteToMtabAndRunLoop(test_data1, arraysize(test_data1), false); | |
| 259 EXPECT_EQ(2, attach_count()); | |
| 260 EXPECT_EQ(0, detach_count()); | |
| 261 | |
| 262 // Attach |kDevice1| to |kMountPointB|. | |
| 263 // |kDevice2| is inaccessible, so it is detached. |kDevice1| has been | |
| 264 // re-attached at |kMountPointB|, so it is 'detached' from kMountPointA. | |
| 265 // kDevice1 -> kMountPointA | |
| 266 // kDevice2 -> kMountPointB | |
| 267 // kDevice1 -> kMountPointB | |
| 268 struct MtabTestData test_data2[] = { | |
| 269 MtabTestData(kDevice1, test_path2.value().c_str(), kValidFS), | |
| 270 }; | |
| 271 WriteToMtabAndRunLoop(test_data2, arraysize(test_data2), false); | |
| 272 EXPECT_EQ(3, attach_count()); | |
| 273 EXPECT_EQ(2, detach_count()); | |
| 274 | |
| 275 // Attach |kDevice2| to |kMountPointA|. | |
| 276 // kDevice1 -> kMountPointA | |
| 277 // kDevice2 -> kMountPointB | |
| 278 // kDevice1 -> kMountPointB | |
| 279 // kDevice2 -> kMountPointA | |
| 280 struct MtabTestData test_data3[] = { | |
| 281 MtabTestData(kDevice2, test_path1.value().c_str(), kValidFS), | |
| 282 }; | |
| 283 WriteToMtabAndRunLoop(test_data3, arraysize(test_data3), false); | |
| 284 EXPECT_EQ(4, attach_count()); | |
| 285 EXPECT_EQ(2, detach_count()); | |
| 286 | |
| 287 // Detach |kDevice2| from |kMountPointA|. | |
| 288 // kDevice1 -> kMountPointA | |
| 289 // kDevice2 -> kMountPointB | |
| 290 // kDevice1 -> kMountPointB | |
| 291 struct MtabTestData test_data4[] = { | |
| 292 MtabTestData(kDevice1, test_path1.value().c_str(), kValidFS), | |
| 293 MtabTestData(kDevice2, test_path2.value().c_str(), kValidFS), | |
| 294 MtabTestData(kDevice1, test_path2.value().c_str(), kValidFS), | |
| 295 }; | |
| 296 WriteToMtabAndRunLoop(test_data4, arraysize(test_data4), true); | |
| 297 EXPECT_EQ(4, attach_count()); | |
| 298 EXPECT_EQ(3, detach_count()); | |
| 299 | |
| 300 // Detach |kDevice1| from |kMountPointB|. | |
| 301 // kDevice1 -> kMountPointA | |
| 302 // kDevice2 -> kMountPointB | |
| 303 WriteToMtabAndRunLoop(test_data1, arraysize(test_data1), true); | |
| 304 EXPECT_EQ(6, attach_count()); | |
| 305 EXPECT_EQ(4, detach_count()); | |
| 306 | |
| 307 // Detach all devices. | |
| 308 WriteToMtabAndRunLoop(NULL, 0, true); | |
| 309 EXPECT_EQ(6, attach_count()); | |
| 310 EXPECT_EQ(6, detach_count()); | |
| 311 } | |
| 312 | |
| 313 TEST_F(MediaDeviceNotificationsLinuxTest, MultiDeviceMount2) { | |
| 314 FilePath test_path1 = CreateMountPoint(kMountPointA, true); | |
| 315 FilePath test_path2 = CreateMountPoint(kMountPointB, true); | |
| 316 ASSERT_FALSE(test_path1.empty()); | |
| 317 ASSERT_FALSE(test_path2.empty()); | |
| 318 | |
| 319 // |kDevice1| is most recently mounted at |kMountPointB|. | |
| 320 // kDevice1 -> kMountPointA | |
| 321 // kDevice2 -> kMountPointB | |
| 322 // kDevice1 -> kMountPointB | |
| 323 struct MtabTestData test_data2[] = { | |
| 324 MtabTestData(kDevice1, test_path2.value().c_str(), kValidFS), | |
| 325 }; | |
| 326 WriteToMtabAndRunLoop(test_data2, arraysize(test_data2), false); | |
| 327 EXPECT_EQ(1, attach_count()); | |
| 328 EXPECT_EQ(0, detach_count()); | |
| 329 | |
| 330 // Attach |kDevice3| to |kMountPointB|. | |
| 331 // |kDevice1| is inaccessible at its most recent mount point, so it is | |
| 332 // detached and unavailable, even though it is still accessible via | |
| 333 // |kMountPointA|. | |
| 334 // kDevice1 -> kMountPointA | |
| 335 // kDevice2 -> kMountPointB | |
| 336 // kDevice1 -> kMountPointB | |
| 337 // kDevice3 -> kMountPointB | |
| 338 struct MtabTestData test_data3[] = { | |
| 339 MtabTestData(kDevice3, test_path2.value().c_str(), kValidFS), | |
| 340 }; | |
| 341 WriteToMtabAndRunLoop(test_data3, arraysize(test_data3), false); | |
| 342 EXPECT_EQ(2, attach_count()); | |
| 343 EXPECT_EQ(1, detach_count()); | |
| 344 | |
| 345 // Detach all devices. | |
| 346 WriteToMtabAndRunLoop(NULL, 0, true); | |
| 347 EXPECT_EQ(2, attach_count()); | |
| 348 EXPECT_EQ(2, detach_count()); | |
| 349 } | |
| 350 | |
| 351 } // namespace content | |
| OLD | NEW |