1// Copyright 2014 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 "base/bind.h" 6#include "base/command_line.h" 7#include "base/files/file_path.h" 8#include "base/files/file_util.h" 9#include "base/files/scoped_temp_dir.h" 10#include "base/memory/scoped_ptr.h" 11#include "base/run_loop.h" 12#include "base/test/scoped_path_override.h" 13#include "chrome/browser/extensions/test_extension_system.h" 14#include "chrome/browser/media_galleries/gallery_watch_manager.h" 15#include "chrome/browser/media_galleries/gallery_watch_manager_observer.h" 16#include "chrome/browser/media_galleries/media_galleries_preferences.h" 17#include "chrome/browser/media_galleries/media_galleries_preferences_factory.h" 18#include "chrome/browser/media_galleries/media_galleries_test_util.h" 19#include "chrome/test/base/testing_profile.h" 20#include "components/storage_monitor/test_storage_monitor.h" 21#include "content/public/test/test_browser_thread_bundle.h" 22#include "extensions/browser/extension_system.h" 23#include "extensions/common/extension.h" 24#include "extensions/common/permissions/media_galleries_permission.h" 25#include "testing/gtest/include/gtest/gtest.h" 26 27#if defined(OS_CHROMEOS) 28#include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h" 29#include "chrome/browser/chromeos/settings/cros_settings.h" 30#include "chrome/browser/chromeos/settings/device_settings_service.h" 31#endif 32 33namespace component_updater { 34 35namespace { 36 37void ConfirmWatch(base::RunLoop* loop, const std::string& error) { 38 EXPECT_TRUE(error.empty()); 39 loop->Quit(); 40} 41 42void ExpectWatchError(base::RunLoop* loop, 43 const std::string& expected_error, 44 const std::string& error) { 45 EXPECT_EQ(expected_error, error); 46 loop->Quit(); 47} 48 49} // namespace 50 51class GalleryWatchManagerTest : public GalleryWatchManagerObserver, 52 public testing::Test { 53 public: 54 GalleryWatchManagerTest() 55 : thread_bundle_(content::TestBrowserThreadBundle::IO_MAINLOOP), 56 profile_(new TestingProfile()), 57 gallery_prefs_(NULL), 58 expect_gallery_changed_(false), 59 expect_gallery_watch_dropped_(false), 60 pending_loop_(NULL) {} 61 62 virtual ~GalleryWatchManagerTest() {} 63 64 virtual void SetUp() OVERRIDE { 65 ASSERT_TRUE(storage_monitor::TestStorageMonitor::CreateAndInstall()); 66 67 extensions::TestExtensionSystem* extension_system( 68 static_cast<extensions::TestExtensionSystem*>( 69 extensions::ExtensionSystem::Get(profile_.get()))); 70 extension_system->CreateExtensionService( 71 base::CommandLine::ForCurrentProcess(), base::FilePath(), false); 72 73 gallery_prefs_ = 74 MediaGalleriesPreferencesFactory::GetForProfile(profile_.get()); 75 base::RunLoop loop; 76 gallery_prefs_->EnsureInitialized(loop.QuitClosure()); 77 loop.Run(); 78 79 std::vector<std::string> read_permissions; 80 read_permissions.push_back( 81 extensions::MediaGalleriesPermission::kReadPermission); 82 extension_ = AddMediaGalleriesApp("read", read_permissions, profile_.get()); 83 84 manager_.reset(new GalleryWatchManager); 85 manager_->AddObserver(profile_.get(), this); 86 } 87 88 virtual void TearDown() OVERRIDE { 89 manager_->RemoveObserver(profile_.get()); 90 manager_.reset(); 91 storage_monitor::TestStorageMonitor::Destroy(); 92 } 93 94 protected: 95 // Create the specified path, and add it to preferences as a gallery. 96 MediaGalleryPrefId AddGallery(const base::FilePath& path) { 97 MediaGalleryPrefInfo gallery_info; 98 EXPECT_FALSE(gallery_prefs_->LookUpGalleryByPath(path, &gallery_info)); 99 MediaGalleryPrefId id = 100 gallery_prefs_->AddGallery(gallery_info.device_id, 101 gallery_info.path, 102 MediaGalleryPrefInfo::kUserAdded, 103 gallery_info.volume_label, 104 gallery_info.vendor_name, 105 gallery_info.model_name, 106 gallery_info.total_size_in_bytes, 107 gallery_info.last_attach_time, 108 0, 109 0, 110 0); 111 EXPECT_NE(kInvalidMediaGalleryPrefId, id); 112 113 EXPECT_TRUE(gallery_prefs_->SetGalleryPermissionForExtension( 114 *extension_, id, true)); 115 return id; 116 } 117 118 TestingProfile* profile() { return profile_.get(); } 119 120 GalleryWatchManager* manager() { return manager_.get(); } 121 122 extensions::Extension* extension() { return extension_.get(); } 123 124 MediaGalleriesPreferences* gallery_prefs() { return gallery_prefs_; } 125 126 bool GalleryWatchesSupported() { 127 return base::FilePathWatcher::RecursiveWatchAvailable(); 128 } 129 130 void AddAndConfirmWatch(MediaGalleryPrefId gallery_id) { 131 base::RunLoop loop; 132 manager()->AddWatch(profile(), 133 extension(), 134 gallery_id, 135 base::Bind(&ConfirmWatch, base::Unretained(&loop))); 136 loop.Run(); 137 } 138 139 void ExpectGalleryChanged(base::RunLoop* loop) { 140 expect_gallery_changed_ = true; 141 pending_loop_ = loop; 142 } 143 144 void ExpectGalleryWatchDropped(base::RunLoop* loop) { 145 expect_gallery_watch_dropped_ = true; 146 pending_loop_ = loop; 147 } 148 149 private: 150 // GalleryWatchManagerObserver implementation. 151 virtual void OnGalleryChanged(const std::string& extension_id, 152 MediaGalleryPrefId gallery_id) OVERRIDE { 153 EXPECT_TRUE(expect_gallery_changed_); 154 pending_loop_->Quit(); 155 } 156 157 virtual void OnGalleryWatchDropped(const std::string& extension_id, 158 MediaGalleryPrefId gallery_id) OVERRIDE { 159 EXPECT_TRUE(expect_gallery_watch_dropped_); 160 pending_loop_->Quit(); 161 } 162 163 scoped_ptr<GalleryWatchManager> manager_; 164 165 // Needed for extension service & friends to work. 166 content::TestBrowserThreadBundle thread_bundle_; 167 168 scoped_refptr<extensions::Extension> extension_; 169 170 EnsureMediaDirectoriesExists mock_gallery_locations_; 171 172#if defined(OS_CHROMEOS) 173 chromeos::ScopedTestDeviceSettingsService test_device_settings_service_; 174 chromeos::ScopedTestCrosSettings test_cros_settings_; 175 chromeos::ScopedTestUserManager test_user_manager_; 176#endif 177 178 storage_monitor::TestStorageMonitor monitor_; 179 scoped_ptr<TestingProfile> profile_; 180 MediaGalleriesPreferences* gallery_prefs_; 181 182 bool expect_gallery_changed_; 183 bool expect_gallery_watch_dropped_; 184 base::RunLoop* pending_loop_; 185 186 DISALLOW_COPY_AND_ASSIGN(GalleryWatchManagerTest); 187}; 188 189TEST_F(GalleryWatchManagerTest, Basic) { 190 base::ScopedTempDir temp_dir; 191 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 192 MediaGalleryPrefId id = AddGallery(temp_dir.path()); 193 194 base::RunLoop loop; 195 if (GalleryWatchesSupported()) { 196 manager()->AddWatch(profile(), 197 extension(), 198 id, 199 base::Bind(&ConfirmWatch, base::Unretained(&loop))); 200 } else { 201 manager()->AddWatch( 202 profile(), 203 extension(), 204 id, 205 base::Bind(&ExpectWatchError, 206 base::Unretained(&loop), 207 GalleryWatchManager::kCouldNotWatchGalleryError)); 208 } 209 loop.Run(); 210} 211 212TEST_F(GalleryWatchManagerTest, AddAndRemoveTwoWatches) { 213 if (!GalleryWatchesSupported()) 214 return; 215 216 EXPECT_TRUE(manager()->GetWatchSet(profile(), extension()->id()).empty()); 217 218 base::ScopedTempDir temp1; 219 ASSERT_TRUE(temp1.CreateUniqueTempDir()); 220 MediaGalleryPrefId id1 = AddGallery(temp1.path()); 221 222 base::ScopedTempDir temp2; 223 ASSERT_TRUE(temp2.CreateUniqueTempDir()); 224 MediaGalleryPrefId id2 = AddGallery(temp2.path()); 225 226 // Add first watch and test it was added correctly. 227 AddAndConfirmWatch(id1); 228 MediaGalleryPrefIdSet set1 = 229 manager()->GetWatchSet(profile(), extension()->id()); 230 EXPECT_EQ(1u, set1.size()); 231 EXPECT_TRUE(ContainsKey(set1, id1)); 232 233 // Test that the second watch was added correctly too. 234 AddAndConfirmWatch(id2); 235 MediaGalleryPrefIdSet set2 = 236 manager()->GetWatchSet(profile(), extension()->id()); 237 EXPECT_EQ(2u, set2.size()); 238 EXPECT_TRUE(ContainsKey(set2, id1)); 239 EXPECT_TRUE(ContainsKey(set2, id2)); 240 241 // Remove first watch and test that the second is still in there. 242 manager()->RemoveWatch(profile(), extension()->id(), id1); 243 MediaGalleryPrefIdSet set3 = 244 manager()->GetWatchSet(profile(), extension()->id()); 245 EXPECT_EQ(1u, set3.size()); 246 EXPECT_TRUE(ContainsKey(set3, id2)); 247 248 // Try removing the first watch again and test that it has no effect. 249 manager()->RemoveWatch(profile(), extension()->id(), id1); 250 EXPECT_EQ(1u, manager()->GetWatchSet(profile(), extension()->id()).size()); 251 252 // Remove the second watch and test that the new watch set is empty. 253 manager()->RemoveWatch(profile(), extension()->id(), id2); 254 EXPECT_TRUE(manager()->GetWatchSet(profile(), extension()->id()).empty()); 255} 256 257TEST_F(GalleryWatchManagerTest, RemoveAllWatches) { 258 if (!GalleryWatchesSupported()) 259 return; 260 261 base::ScopedTempDir temp1; 262 ASSERT_TRUE(temp1.CreateUniqueTempDir()); 263 MediaGalleryPrefId id1 = AddGallery(temp1.path()); 264 265 base::ScopedTempDir temp2; 266 ASSERT_TRUE(temp2.CreateUniqueTempDir()); 267 MediaGalleryPrefId id2 = AddGallery(temp2.path()); 268 269 // Add watches. 270 AddAndConfirmWatch(id1); 271 AddAndConfirmWatch(id2); 272 273 EXPECT_EQ(2u, manager()->GetWatchSet(profile(), extension()->id()).size()); 274 275 // RemoveAllWatches using a different extension ID and verify watches remain. 276 manager()->RemoveAllWatches(profile(), "OtherExtensionId"); 277 EXPECT_EQ(2u, manager()->GetWatchSet(profile(), extension()->id()).size()); 278 279 // RemoveAllWatches using the correct extension ID and verify watches gone. 280 281 manager()->RemoveAllWatches(profile(), extension()->id()); 282 EXPECT_TRUE(manager()->GetWatchSet(profile(), extension()->id()).empty()); 283} 284 285TEST_F(GalleryWatchManagerTest, DropWatchOnGalleryRemoved) { 286 if (!GalleryWatchesSupported()) 287 return; 288 289 base::ScopedTempDir temp_dir; 290 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 291 MediaGalleryPrefId id = AddGallery(temp_dir.path()); 292 AddAndConfirmWatch(id); 293 294 base::RunLoop success_loop; 295 ExpectGalleryWatchDropped(&success_loop); 296 gallery_prefs()->EraseGalleryById(id); 297 success_loop.Run(); 298} 299 300TEST_F(GalleryWatchManagerTest, DropWatchOnGalleryPermissionRevoked) { 301 if (!GalleryWatchesSupported()) 302 return; 303 304 base::ScopedTempDir temp_dir; 305 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 306 MediaGalleryPrefId id = AddGallery(temp_dir.path()); 307 AddAndConfirmWatch(id); 308 309 base::RunLoop success_loop; 310 ExpectGalleryWatchDropped(&success_loop); 311 gallery_prefs()->SetGalleryPermissionForExtension(*extension(), id, false); 312 success_loop.Run(); 313} 314 315TEST_F(GalleryWatchManagerTest, TestWatchOperation) { 316 if (!GalleryWatchesSupported()) 317 return; 318 319 base::ScopedTempDir temp_dir; 320 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 321 MediaGalleryPrefId id = AddGallery(temp_dir.path()); 322 AddAndConfirmWatch(id); 323 324 base::RunLoop success_loop; 325 ExpectGalleryChanged(&success_loop); 326 ASSERT_EQ( 327 4, base::WriteFile(temp_dir.path().AppendASCII("fake file"), "blah", 4)); 328 success_loop.Run(); 329} 330 331} // namespace component_updater 332