media_file_system_registry_unittest.cc revision f2477e01787aa58f445919b809d89e252beef54f
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// MediaFileSystemRegistry unit tests. 6 7#include <algorithm> 8#include <set> 9 10#include "base/bind_helpers.h" 11#include "base/command_line.h" 12#include "base/file_util.h" 13#include "base/files/scoped_temp_dir.h" 14#include "base/memory/ref_counted.h" 15#include "base/memory/scoped_ptr.h" 16#include "base/memory/scoped_vector.h" 17#include "base/message_loop/message_loop.h" 18#include "base/path_service.h" 19#include "base/run_loop.h" 20#include "base/stl_util.h" 21#include "base/strings/stringprintf.h" 22#include "base/strings/utf_string_conversions.h" 23#include "base/threading/sequenced_worker_pool.h" 24#include "base/values.h" 25#include "chrome/browser/extensions/extension_service.h" 26#include "chrome/browser/extensions/extension_system.h" 27#include "chrome/browser/extensions/test_extension_system.h" 28#include "chrome/browser/media_galleries/media_file_system_context.h" 29#include "chrome/browser/media_galleries/media_file_system_registry.h" 30#include "chrome/browser/media_galleries/media_galleries_preferences_factory.h" 31#include "chrome/browser/media_galleries/media_galleries_test_util.h" 32#include "chrome/browser/storage_monitor/removable_device_constants.h" 33#include "chrome/browser/storage_monitor/storage_info.h" 34#include "chrome/browser/storage_monitor/storage_monitor.h" 35#include "chrome/browser/storage_monitor/test_storage_monitor.h" 36#include "chrome/common/chrome_paths.h" 37#include "chrome/test/base/chrome_render_view_host_test_harness.h" 38#include "chrome/test/base/testing_browser_process.h" 39#include "chrome/test/base/testing_profile.h" 40#include "content/public/browser/render_process_host.h" 41#include "content/public/browser/render_process_host_factory.h" 42#include "content/public/browser/render_view_host.h" 43#include "content/public/browser/web_contents.h" 44#include "content/public/test/mock_render_process_host.h" 45#include "content/public/test/test_browser_thread.h" 46#include "content/public/test/web_contents_tester.h" 47#include "extensions/common/extension.h" 48#include "sync/api/string_ordinal.h" 49#include "testing/gtest/include/gtest/gtest.h" 50 51#if defined(OS_CHROMEOS) 52#include "chrome/browser/chromeos/login/user_manager.h" 53#include "chrome/browser/chromeos/settings/cros_settings.h" 54#include "chrome/browser/chromeos/settings/device_settings_service.h" 55#endif 56 57using content::BrowserThread; 58 59// Not anonymous so it can be friends with MediaFileSystemRegistry. 60class TestMediaFileSystemContext : public MediaFileSystemContext { 61 public: 62 struct FSInfo { 63 FSInfo() {} 64 FSInfo(const std::string& device_id, const base::FilePath& path, 65 const std::string& fsid); 66 67 bool operator<(const FSInfo& other) const; 68 69 std::string device_id; 70 base::FilePath path; 71 std::string fsid; 72 }; 73 74 explicit TestMediaFileSystemContext(MediaFileSystemRegistry* registry); 75 virtual ~TestMediaFileSystemContext() {} 76 77 // MediaFileSystemContext implementation. 78 virtual std::string RegisterFileSystem( 79 const std::string& device_id, const base::FilePath& path) OVERRIDE; 80 81 virtual void RevokeFileSystem(const std::string& fsid) OVERRIDE; 82 83 base::FilePath GetPathForId(const std::string& fsid) const; 84 85 MediaFileSystemRegistry* registry() { return registry_; } 86 87 private: 88 std::string AddFSEntry(const std::string& device_id, 89 const base::FilePath& path); 90 91 MediaFileSystemRegistry* registry_; 92 93 // A counter used to construct mock FSIDs. 94 int fsid_; 95 96 // The currently allocated mock file systems. 97 std::map<std::string /*fsid*/, FSInfo> file_systems_by_id_; 98}; 99 100TestMediaFileSystemContext::FSInfo::FSInfo(const std::string& device_id, 101 const base::FilePath& path, 102 const std::string& fsid) 103 : device_id(device_id), 104 path(path), 105 fsid(fsid) { 106} 107 108bool TestMediaFileSystemContext::FSInfo::operator<(const FSInfo& other) const { 109 if (device_id != other.device_id) 110 return device_id < other.device_id; 111 if (path.value() != other.path.value()) 112 return path.value() < other.path.value(); 113 return fsid < other.fsid; 114} 115 116TestMediaFileSystemContext::TestMediaFileSystemContext( 117 MediaFileSystemRegistry* registry) 118 : registry_(registry), 119 fsid_(0) { 120 registry_->file_system_context_.reset(this); 121} 122 123std::string TestMediaFileSystemContext::RegisterFileSystem( 124 const std::string& device_id, const base::FilePath& path) { 125 std::string fsid = AddFSEntry(device_id, path); 126 return fsid; 127} 128 129void TestMediaFileSystemContext::RevokeFileSystem(const std::string& fsid) { 130 if (!ContainsKey(file_systems_by_id_, fsid)) 131 return; 132 EXPECT_EQ(1U, file_systems_by_id_.erase(fsid)); 133} 134 135base::FilePath TestMediaFileSystemContext::GetPathForId( 136 const std::string& fsid) const { 137 std::map<std::string /*fsid*/, FSInfo>::const_iterator it = 138 file_systems_by_id_.find(fsid); 139 if (it == file_systems_by_id_.end()) 140 return base::FilePath(); 141 return it->second.path; 142} 143 144std::string TestMediaFileSystemContext::AddFSEntry(const std::string& device_id, 145 const base::FilePath& path) { 146 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 147 DCHECK(path.IsAbsolute()); 148 DCHECK(!path.ReferencesParent()); 149 150 std::string fsid = base::StringPrintf("FSID:%d", ++fsid_); 151 FSInfo info(device_id, path, fsid); 152 file_systems_by_id_[fsid] = info; 153 return fsid; 154} 155 156namespace { 157 158typedef std::map<MediaGalleryPrefId, MediaFileSystemInfo> FSInfoMap; 159 160void GetGalleryInfoCallback( 161 FSInfoMap* results, 162 const std::vector<MediaFileSystemInfo>& file_systems) { 163 for (size_t i = 0; i < file_systems.size(); ++i) { 164 ASSERT_FALSE(ContainsKey(*results, file_systems[i].pref_id)); 165 (*results)[file_systems[i].pref_id] = file_systems[i]; 166 } 167} 168 169void CheckGalleryInfo(const MediaFileSystemInfo& info, 170 TestMediaFileSystemContext* fs_context, 171 const base::FilePath& path, 172 bool removable, 173 bool media_device) { 174 EXPECT_EQ(path, info.path); 175 EXPECT_EQ(removable, info.removable); 176 EXPECT_EQ(media_device, info.media_device); 177 EXPECT_NE(0UL, info.pref_id); 178 179 if (removable) 180 EXPECT_NE(0UL, info.transient_device_id.size()); 181 else 182 EXPECT_EQ(0UL, info.transient_device_id.size()); 183 184 base::FilePath fsid_path = fs_context->GetPathForId(info.fsid); 185 EXPECT_EQ(path, fsid_path); 186} 187 188class MockProfileSharedRenderProcessHostFactory 189 : public content::RenderProcessHostFactory { 190 public: 191 MockProfileSharedRenderProcessHostFactory() {} 192 virtual ~MockProfileSharedRenderProcessHostFactory(); 193 194 // RPH created with this factory are owned by it. If the RPH is destroyed 195 // for testing purposes, it must be removed from the factory first. 196 content::MockRenderProcessHost* ReleaseRPH( 197 content::BrowserContext* browser_context); 198 199 virtual content::RenderProcessHost* CreateRenderProcessHost( 200 content::BrowserContext* browser_context, 201 content::SiteInstance* site_instance) const OVERRIDE; 202 203 private: 204 typedef std::map<content::BrowserContext*, content::MockRenderProcessHost*> 205 ProfileRPHMap; 206 mutable ProfileRPHMap rph_map_; 207 208 DISALLOW_COPY_AND_ASSIGN(MockProfileSharedRenderProcessHostFactory); 209}; 210 211class ProfileState { 212 public: 213 explicit ProfileState( 214 MockProfileSharedRenderProcessHostFactory* rph_factory); 215 ~ProfileState(); 216 217 MediaGalleriesPreferences* GetMediaGalleriesPrefs(); 218 219 void CheckGalleries( 220 const std::string& test, 221 const std::vector<MediaFileSystemInfo>& regular_extension_galleries, 222 const std::vector<MediaFileSystemInfo>& all_extension_galleries); 223 224 FSInfoMap GetGalleriesInfo(extensions::Extension* extension); 225 226 extensions::Extension* all_permission_extension(); 227 extensions::Extension* regular_permission_extension(); 228 Profile* profile(); 229 230 void AddNameForReadCompare(const string16& name); 231 void AddNameForAllCompare(const string16& name); 232 233 private: 234 void CompareResults(const std::string& test, 235 const std::vector<string16>& names, 236 const std::vector<MediaFileSystemInfo>& expected, 237 const std::vector<MediaFileSystemInfo>& actual); 238 bool ContainsEntry(const MediaFileSystemInfo& info, 239 const std::vector<MediaFileSystemInfo>& container); 240 241 int GetAndClearComparisonCount(); 242 243 int num_comparisons_; 244 245 scoped_ptr<TestingProfile> profile_; 246 247 scoped_refptr<extensions::Extension> all_permission_extension_; 248 scoped_refptr<extensions::Extension> regular_permission_extension_; 249 scoped_refptr<extensions::Extension> no_permissions_extension_; 250 251 scoped_ptr<content::WebContents> single_web_contents_; 252 scoped_ptr<content::WebContents> shared_web_contents1_; 253 scoped_ptr<content::WebContents> shared_web_contents2_; 254 255 // The RenderProcessHosts are freed when their respective WebContents / 256 // RenderViewHosts go away. 257 content::MockRenderProcessHost* single_rph_; 258 content::MockRenderProcessHost* shared_rph_; 259 260 std::vector<string16> compare_names_read_; 261 std::vector<string16> compare_names_all_; 262 263 DISALLOW_COPY_AND_ASSIGN(ProfileState); 264}; 265 266} // namespace 267 268class MediaFileSystemRegistryTest : public ChromeRenderViewHostTestHarness { 269 public: 270 void CreateProfileState(size_t profile_count); 271 272 ProfileState* GetProfileState(size_t i); 273 274 MediaGalleriesPreferences* GetPreferences(Profile* profile); 275 276 base::FilePath empty_dir() { 277 return empty_dir_; 278 } 279 280 base::FilePath dcim_dir() { 281 return dcim_dir_; 282 } 283 284 TestMediaFileSystemContext* test_file_system_context() { 285 return test_file_system_context_; 286 } 287 288 // Create a user added gallery based on the information passed and add it to 289 // |profiles|. Returns the device id. 290 std::string AddUserGallery(StorageInfo::Type type, 291 const std::string& unique_id, 292 const base::FilePath& path); 293 294 // Returns the device id. 295 std::string AttachDevice(StorageInfo::Type type, 296 const std::string& unique_id, 297 const base::FilePath& location); 298 299 void DetachDevice(const std::string& device_id); 300 301 void SetGalleryPermission(ProfileState* profile_state, 302 extensions::Extension* extension, 303 const std::string& device_id, 304 bool has_access); 305 306 void AssertAllAutoAddedGalleries(); 307 308 void InitForGalleriesInfoTest(FSInfoMap* galleries_info); 309 310 void CheckNewGalleryInfo(ProfileState* profile_state, 311 const FSInfoMap& galleries_info, 312 const base::FilePath& location, 313 bool removable, 314 bool media_device); 315 316 std::vector<MediaFileSystemInfo> GetAutoAddedGalleries( 317 ProfileState* profile_state); 318 319 void ProcessAttach(const std::string& id, 320 const string16& name, 321 const base::FilePath::StringType& location) { 322 StorageInfo info(id, string16(), location, name, string16(), string16(), 0); 323 StorageMonitor::GetInstance()->receiver()->ProcessAttach(info); 324 } 325 326 void ProcessDetach(const std::string& id) { 327 StorageMonitor::GetInstance()->receiver()->ProcessDetach(id); 328 } 329 330 MediaFileSystemRegistry* registry() { 331 return test_file_system_context_->registry(); 332 } 333 334 size_t GetExtensionGalleriesHostCount( 335 const MediaFileSystemRegistry* registry) const; 336 337 int num_auto_galleries() { 338 return media_directories_.num_galleries(); 339 } 340 341 protected: 342 virtual void SetUp() OVERRIDE; 343 virtual void TearDown() OVERRIDE; 344 345 private: 346 // This makes sure that at least one default gallery exists on the file 347 // system. 348 EnsureMediaDirectoriesExists media_directories_; 349 350 // Some test gallery directories. 351 base::ScopedTempDir galleries_dir_; 352 // An empty directory in |galleries_dir_| 353 base::FilePath empty_dir_; 354 // A directory in |galleries_dir_| with a DCIM directory in it. 355 base::FilePath dcim_dir_; 356 357 // MediaFileSystemRegistry owns this. 358 TestMediaFileSystemContext* test_file_system_context_; 359 360 // Needed for extension service & friends to work. 361 362#if defined OS_CHROMEOS 363 chromeos::ScopedTestDeviceSettingsService test_device_settings_service_; 364 chromeos::ScopedTestCrosSettings test_cros_settings_; 365 scoped_ptr<chromeos::ScopedTestUserManager> test_user_manager_; 366#endif 367 368 MockProfileSharedRenderProcessHostFactory rph_factory_; 369 370 ScopedVector<ProfileState> profile_states_; 371}; 372 373namespace { 374 375bool MediaFileSystemInfoComparator(const MediaFileSystemInfo& a, 376 const MediaFileSystemInfo& b) { 377 CHECK_NE(a.name, b.name); // Name must be unique. 378 return a.name < b.name; 379} 380 381/////////////////////////////////////////////// 382// MockProfileSharedRenderProcessHostFactory // 383/////////////////////////////////////////////// 384 385MockProfileSharedRenderProcessHostFactory:: 386 ~MockProfileSharedRenderProcessHostFactory() { 387 STLDeleteValues(&rph_map_); 388} 389 390content::MockRenderProcessHost* 391MockProfileSharedRenderProcessHostFactory::ReleaseRPH( 392 content::BrowserContext* browser_context) { 393 ProfileRPHMap::iterator existing = rph_map_.find(browser_context); 394 if (existing == rph_map_.end()) 395 return NULL; 396 content::MockRenderProcessHost* result = existing->second; 397 rph_map_.erase(existing); 398 return result; 399} 400 401content::RenderProcessHost* 402MockProfileSharedRenderProcessHostFactory::CreateRenderProcessHost( 403 content::BrowserContext* browser_context, 404 content::SiteInstance* site_instance) const { 405 ProfileRPHMap::const_iterator existing = rph_map_.find(browser_context); 406 if (existing != rph_map_.end()) 407 return existing->second; 408 rph_map_[browser_context] = 409 new content::MockRenderProcessHost(browser_context); 410 return rph_map_[browser_context]; 411} 412 413////////////////// 414// ProfileState // 415////////////////// 416 417ProfileState::ProfileState( 418 MockProfileSharedRenderProcessHostFactory* rph_factory) 419 : num_comparisons_(0), 420 profile_(new TestingProfile()) { 421 extensions::TestExtensionSystem* extension_system( 422 static_cast<extensions::TestExtensionSystem*>( 423 extensions::ExtensionSystem::Get(profile_.get()))); 424 extension_system->CreateExtensionService( 425 CommandLine::ForCurrentProcess(), base::FilePath(), false); 426 427 std::vector<std::string> all_permissions; 428 all_permissions.push_back("allAutoDetected"); 429 all_permissions.push_back("read"); 430 std::vector<std::string> read_permissions; 431 read_permissions.push_back("read"); 432 433 all_permission_extension_ = 434 AddMediaGalleriesApp("all", all_permissions, profile_.get()); 435 regular_permission_extension_ = 436 AddMediaGalleriesApp("regular", read_permissions, profile_.get()); 437 no_permissions_extension_ = 438 AddMediaGalleriesApp("no", read_permissions, profile_.get()); 439 440 single_web_contents_.reset( 441 content::WebContentsTester::CreateTestWebContents(profile_.get(), NULL)); 442 single_rph_ = rph_factory->ReleaseRPH(profile_.get()); 443 444 shared_web_contents1_.reset( 445 content::WebContentsTester::CreateTestWebContents(profile_.get(), NULL)); 446 shared_web_contents2_.reset( 447 content::WebContentsTester::CreateTestWebContents(profile_.get(), NULL)); 448 shared_rph_ = rph_factory->ReleaseRPH(profile_.get()); 449} 450 451ProfileState::~ProfileState() { 452 // TestExtensionSystem uses DeleteSoon, so we need to delete the profiles 453 // and then run the message queue to clean up. But first we have to 454 // delete everything that references the profile. 455 single_web_contents_.reset(); 456 shared_web_contents1_.reset(); 457 shared_web_contents2_.reset(); 458 profile_.reset(); 459 460 base::MessageLoop::current()->RunUntilIdle(); 461} 462 463MediaGalleriesPreferences* ProfileState::GetMediaGalleriesPrefs() { 464 MediaGalleriesPreferences* prefs = 465 MediaGalleriesPreferencesFactory::GetForProfile(profile_.get()); 466 base::RunLoop loop; 467 prefs->EnsureInitialized(loop.QuitClosure()); 468 loop.Run(); 469 return prefs; 470} 471 472void ProfileState::CheckGalleries( 473 const std::string& test, 474 const std::vector<MediaFileSystemInfo>& regular_extension_galleries, 475 const std::vector<MediaFileSystemInfo>& all_extension_galleries) { 476 content::RenderViewHost* rvh = single_web_contents_->GetRenderViewHost(); 477 MediaFileSystemRegistry* registry = 478 g_browser_process->media_file_system_registry(); 479 480 // No Media Galleries permissions. 481 std::vector<MediaFileSystemInfo> empty_expectation; 482 std::vector<string16> empty_names; 483 registry->GetMediaFileSystemsForExtension( 484 rvh, no_permissions_extension_.get(), 485 base::Bind(&ProfileState::CompareResults, base::Unretained(this), 486 base::StringPrintf("%s (no permission)", test.c_str()), 487 base::ConstRef(empty_names), 488 base::ConstRef(empty_expectation))); 489 base::MessageLoop::current()->RunUntilIdle(); 490 EXPECT_EQ(1, GetAndClearComparisonCount()); 491 492 // Read permission only. 493 registry->GetMediaFileSystemsForExtension( 494 rvh, regular_permission_extension_.get(), 495 base::Bind(&ProfileState::CompareResults, base::Unretained(this), 496 base::StringPrintf("%s (regular permission)", test.c_str()), 497 base::ConstRef(compare_names_read_), 498 base::ConstRef(regular_extension_galleries))); 499 base::MessageLoop::current()->RunUntilIdle(); 500 EXPECT_EQ(1, GetAndClearComparisonCount()); 501 502 // All galleries permission. 503 registry->GetMediaFileSystemsForExtension( 504 rvh, all_permission_extension_.get(), 505 base::Bind(&ProfileState::CompareResults, base::Unretained(this), 506 base::StringPrintf("%s (all permission)", test.c_str()), 507 base::ConstRef(compare_names_all_), 508 base::ConstRef(all_extension_galleries))); 509 base::MessageLoop::current()->RunUntilIdle(); 510 EXPECT_EQ(1, GetAndClearComparisonCount()); 511} 512 513FSInfoMap ProfileState::GetGalleriesInfo(extensions::Extension* extension) { 514 content::RenderViewHost* rvh = single_web_contents_->GetRenderViewHost(); 515 FSInfoMap results; 516 MediaFileSystemRegistry* registry = 517 g_browser_process->media_file_system_registry(); 518 registry->GetMediaFileSystemsForExtension( 519 rvh, extension, 520 base::Bind(&GetGalleryInfoCallback, base::Unretained(&results))); 521 base::MessageLoop::current()->RunUntilIdle(); 522 return results; 523} 524 525extensions::Extension* ProfileState::all_permission_extension() { 526 return all_permission_extension_.get(); 527} 528 529extensions::Extension* ProfileState::regular_permission_extension() { 530 return regular_permission_extension_.get(); 531} 532 533Profile* ProfileState::profile() { 534 return profile_.get(); 535} 536 537void ProfileState::AddNameForReadCompare(const string16& name) { 538 compare_names_read_.push_back(name); 539} 540 541void ProfileState::AddNameForAllCompare(const string16& name) { 542 compare_names_all_.push_back(name); 543} 544 545bool ProfileState::ContainsEntry( 546 const MediaFileSystemInfo& info, 547 const std::vector<MediaFileSystemInfo>& container) { 548 for (size_t i = 0; i < container.size(); ++i) { 549 if (info.path.value() == container[i].path.value()) { 550 EXPECT_FALSE(container[i].fsid.empty()); 551 if (!info.fsid.empty()) 552 EXPECT_EQ(info.fsid, container[i].fsid); 553 return true; 554 } 555 } 556 return false; 557} 558 559void ProfileState::CompareResults( 560 const std::string& test, 561 const std::vector<string16>& names, 562 const std::vector<MediaFileSystemInfo>& expected, 563 const std::vector<MediaFileSystemInfo>& actual) { 564 num_comparisons_++; 565 EXPECT_EQ(expected.size(), actual.size()) << test; 566 567 // Order isn't important, so sort the results. 568 std::vector<MediaFileSystemInfo> sorted(actual); 569 std::sort(sorted.begin(), sorted.end(), MediaFileSystemInfoComparator); 570 std::vector<MediaFileSystemInfo> expect(expected); 571 std::sort(expect.begin(), expect.end(), MediaFileSystemInfoComparator); 572 std::vector<string16> expect_names(names); 573 std::sort(expect_names.begin(), expect_names.end()); 574 575 for (size_t i = 0; i < expect.size() && i < sorted.size(); ++i) { 576 if (expect_names.size() > i) 577 EXPECT_EQ(expect_names[i], sorted[i].name) << test; 578 EXPECT_TRUE(ContainsEntry(expect[i], sorted)) << test; 579 } 580} 581 582int ProfileState::GetAndClearComparisonCount() { 583 int result = num_comparisons_; 584 num_comparisons_ = 0; 585 return result; 586} 587 588} // namespace 589 590///////////////////////////////// 591// MediaFileSystemRegistryTest // 592///////////////////////////////// 593 594void MediaFileSystemRegistryTest::CreateProfileState(size_t profile_count) { 595 for (size_t i = 0; i < profile_count; ++i) { 596 ProfileState* state = new ProfileState(&rph_factory_); 597 profile_states_.push_back(state); 598 } 599} 600 601ProfileState* MediaFileSystemRegistryTest::GetProfileState(size_t i) { 602 return profile_states_[i]; 603} 604 605MediaGalleriesPreferences* MediaFileSystemRegistryTest::GetPreferences( 606 Profile* profile) { 607 MediaGalleriesPreferences* prefs = registry()->GetPreferences(profile); 608 base::RunLoop loop; 609 prefs->EnsureInitialized(loop.QuitClosure()); 610 loop.Run(); 611 return prefs; 612} 613 614std::string MediaFileSystemRegistryTest::AddUserGallery( 615 StorageInfo::Type type, 616 const std::string& unique_id, 617 const base::FilePath& path) { 618 std::string device_id = StorageInfo::MakeDeviceId(type, unique_id); 619 DCHECK(!StorageInfo::IsMediaDevice(device_id)); 620 621 for (size_t i = 0; i < profile_states_.size(); ++i) { 622 profile_states_[i]->GetMediaGalleriesPrefs()->AddGallery( 623 device_id, base::FilePath(), true /*user_added*/, 624 string16(), string16(), string16(), 0, base::Time::Now()); 625 } 626 return device_id; 627} 628 629std::string MediaFileSystemRegistryTest::AttachDevice( 630 StorageInfo::Type type, 631 const std::string& unique_id, 632 const base::FilePath& location) { 633 std::string device_id = StorageInfo::MakeDeviceId(type, unique_id); 634 DCHECK(StorageInfo::IsRemovableDevice(device_id)); 635 string16 label = location.BaseName().LossyDisplayName(); 636 ProcessAttach(device_id, label, location.value()); 637 base::MessageLoop::current()->RunUntilIdle(); 638 return device_id; 639} 640 641void MediaFileSystemRegistryTest::DetachDevice(const std::string& device_id) { 642 DCHECK(StorageInfo::IsRemovableDevice(device_id)); 643 ProcessDetach(device_id); 644 base::MessageLoop::current()->RunUntilIdle(); 645} 646 647void MediaFileSystemRegistryTest::SetGalleryPermission( 648 ProfileState* profile_state, extensions::Extension* extension, 649 const std::string& device_id, bool has_access) { 650 MediaGalleriesPreferences* preferences = 651 profile_state->GetMediaGalleriesPrefs(); 652 MediaGalleryPrefIdSet pref_id = 653 preferences->LookUpGalleriesByDeviceId(device_id); 654 ASSERT_EQ(1U, pref_id.size()); 655 preferences->SetGalleryPermissionForExtension(*extension, *pref_id.begin(), 656 has_access); 657} 658 659void MediaFileSystemRegistryTest::AssertAllAutoAddedGalleries() { 660 for (size_t i = 0; i < profile_states_.size(); ++i) { 661 MediaGalleriesPreferences* prefs = 662 profile_states_[0]->GetMediaGalleriesPrefs(); 663 664 // Make sure that we have at least one gallery and that they are all 665 // auto added galleries. 666 const MediaGalleriesPrefInfoMap& galleries = prefs->known_galleries(); 667#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) 668 ASSERT_GT(galleries.size(), 0U); 669#endif 670 for (MediaGalleriesPrefInfoMap::const_iterator it = galleries.begin(); 671 it != galleries.end(); 672 ++it) { 673 ASSERT_EQ(MediaGalleryPrefInfo::kAutoDetected, it->second.type); 674 } 675 } 676} 677 678void MediaFileSystemRegistryTest::InitForGalleriesInfoTest( 679 FSInfoMap* galleries_info) { 680 CreateProfileState(1); 681 AssertAllAutoAddedGalleries(); 682 683 // Get all existing gallery names. 684 ProfileState* profile_state = GetProfileState(0U); 685 *galleries_info = profile_state->GetGalleriesInfo( 686 profile_state->all_permission_extension()); 687#if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) 688 ASSERT_EQ(3U, galleries_info->size()); 689#else 690 ASSERT_EQ(0U, galleries_info->size()); 691#endif 692} 693 694void MediaFileSystemRegistryTest::CheckNewGalleryInfo( 695 ProfileState* profile_state, 696 const FSInfoMap& galleries_info, 697 const base::FilePath& location, 698 bool removable, 699 bool media_device) { 700 // Get new galleries. 701 FSInfoMap new_galleries_info = profile_state->GetGalleriesInfo( 702 profile_state->all_permission_extension()); 703 ASSERT_EQ(galleries_info.size() + 1U, new_galleries_info.size()); 704 705 bool found_new = false; 706 for (FSInfoMap::const_iterator it = new_galleries_info.begin(); 707 it != new_galleries_info.end(); 708 ++it) { 709 if (ContainsKey(galleries_info, it->first)) 710 continue; 711 712 ASSERT_FALSE(found_new); 713 CheckGalleryInfo(it->second, test_file_system_context_, location, 714 removable, media_device); 715 found_new = true; 716 } 717 ASSERT_TRUE(found_new); 718} 719 720std::vector<MediaFileSystemInfo> 721MediaFileSystemRegistryTest::GetAutoAddedGalleries( 722 ProfileState* profile_state) { 723 const MediaGalleriesPrefInfoMap& galleries = 724 profile_state->GetMediaGalleriesPrefs()->known_galleries(); 725 std::vector<MediaFileSystemInfo> result; 726 for (MediaGalleriesPrefInfoMap::const_iterator it = galleries.begin(); 727 it != galleries.end(); 728 ++it) { 729 if (it->second.type == MediaGalleryPrefInfo::kAutoDetected) { 730 base::FilePath path = it->second.AbsolutePath(); 731 MediaFileSystemInfo info(path.BaseName().LossyDisplayName(), path, 732 std::string(), 0, std::string(), false, false); 733 result.push_back(info); 734 } 735 } 736 std::sort(result.begin(), result.end(), MediaFileSystemInfoComparator); 737 return result; 738} 739 740size_t MediaFileSystemRegistryTest::GetExtensionGalleriesHostCount( 741 const MediaFileSystemRegistry* registry) const { 742 size_t extension_galleries_host_count = 0; 743 for (MediaFileSystemRegistry::ExtensionGalleriesHostMap::const_iterator it = 744 registry->extension_hosts_map_.begin(); 745 it != registry->extension_hosts_map_.end(); 746 ++it) { 747 extension_galleries_host_count += it->second.size(); 748 } 749 return extension_galleries_host_count; 750} 751 752 753void MediaFileSystemRegistryTest::SetUp() { 754 ChromeRenderViewHostTestHarness::SetUp(); 755 ASSERT_TRUE(TestStorageMonitor::CreateAndInstall()); 756 757 DeleteContents(); 758 SetRenderProcessHostFactory(&rph_factory_); 759 760 test_file_system_context_ = new TestMediaFileSystemContext( 761 g_browser_process->media_file_system_registry()); 762 763#if defined(OS_CHROMEOS) 764 test_user_manager_.reset(new chromeos::ScopedTestUserManager()); 765#endif 766 767 ASSERT_TRUE(galleries_dir_.CreateUniqueTempDir()); 768 empty_dir_ = galleries_dir_.path().AppendASCII("empty"); 769 ASSERT_TRUE(file_util::CreateDirectory(empty_dir_)); 770 dcim_dir_ = galleries_dir_.path().AppendASCII("with_dcim"); 771 ASSERT_TRUE(file_util::CreateDirectory(dcim_dir_)); 772 ASSERT_TRUE(file_util::CreateDirectory(dcim_dir_.Append(kDCIMDirectoryName))); 773} 774 775void MediaFileSystemRegistryTest::TearDown() { 776 profile_states_.clear(); 777 MediaFileSystemRegistry* registry = 778 g_browser_process->media_file_system_registry(); 779 EXPECT_EQ(0U, GetExtensionGalleriesHostCount(registry)); 780 TestStorageMonitor::RemoveSingleton(); 781#if defined(OS_CHROMEOS) 782 test_user_manager_.reset(); 783#endif 784 785 ChromeRenderViewHostTestHarness::TearDown(); 786} 787 788/////////// 789// Tests // 790/////////// 791 792TEST_F(MediaFileSystemRegistryTest, Basic) { 793 CreateProfileState(1); 794 AssertAllAutoAddedGalleries(); 795 796 ProfileState* profile_state = GetProfileState(0); 797 std::vector<MediaFileSystemInfo> auto_galleries = 798 GetAutoAddedGalleries(profile_state); 799 std::vector<MediaFileSystemInfo> empty_expectation; 800 profile_state->CheckGalleries("basic", empty_expectation, auto_galleries); 801} 802 803TEST_F(MediaFileSystemRegistryTest, UserAddedGallery) { 804 CreateProfileState(1); 805 AssertAllAutoAddedGalleries(); 806 ProfileState* profile_state = GetProfileState(0); 807 std::vector<MediaFileSystemInfo> auto_galleries = 808 GetAutoAddedGalleries(profile_state); 809 std::vector<MediaFileSystemInfo> added_galleries; 810 profile_state->CheckGalleries("user added init", added_galleries, 811 auto_galleries); 812 813 // Add a user gallery to the regular permission extension. 814 std::string device_id = AddUserGallery(StorageInfo::FIXED_MASS_STORAGE, 815 empty_dir().AsUTF8Unsafe(), 816 empty_dir()); 817 SetGalleryPermission(profile_state, 818 profile_state->regular_permission_extension(), 819 device_id, 820 true /*has access*/); 821 MediaFileSystemInfo added_info(empty_dir().LossyDisplayName(), empty_dir(), 822 std::string(), 0, std::string(), false, false); 823 added_galleries.push_back(added_info); 824 profile_state->CheckGalleries("user added regular", added_galleries, 825 auto_galleries); 826 827 // Add it to the all galleries extension. 828 SetGalleryPermission(profile_state, 829 profile_state->all_permission_extension(), 830 device_id, 831 true /*has access*/); 832 auto_galleries.push_back(added_info); 833 profile_state->CheckGalleries("user added all", added_galleries, 834 auto_galleries); 835} 836 837// Regression test to make sure erasing galleries does not result a crash. 838TEST_F(MediaFileSystemRegistryTest, EraseGalleries) { 839 CreateProfileState(1); 840 AssertAllAutoAddedGalleries(); 841 842 ProfileState* profile_state = GetProfileState(0); 843 std::vector<MediaFileSystemInfo> auto_galleries = 844 GetAutoAddedGalleries(profile_state); 845 std::vector<MediaFileSystemInfo> empty_expectation; 846 profile_state->CheckGalleries("erase", empty_expectation, auto_galleries); 847 848 MediaGalleriesPreferences* prefs = profile_state->GetMediaGalleriesPrefs(); 849 MediaGalleriesPrefInfoMap galleries = prefs->known_galleries(); 850 for (MediaGalleriesPrefInfoMap::const_iterator it = galleries.begin(); 851 it != galleries.end(); ++it) { 852 prefs->ForgetGalleryById(it->first); 853 } 854} 855 856// Regression test to make sure calling GetPreferences() does not re-insert 857// galleries on auto-detected removable devices that were blacklisted. 858TEST_F(MediaFileSystemRegistryTest, 859 GetPreferencesDoesNotReinsertBlacklistedGalleries) { 860 CreateProfileState(1); 861 AssertAllAutoAddedGalleries(); 862 863 ProfileState* profile_state = GetProfileState(0); 864 const size_t gallery_count = GetAutoAddedGalleries(profile_state).size(); 865 866 // Attach a device. 867 const std::string device_id = AttachDevice( 868 StorageInfo::REMOVABLE_MASS_STORAGE_WITH_DCIM, 869 "removable_dcim_fake_id", 870 dcim_dir()); 871 EXPECT_EQ(gallery_count + 1, GetAutoAddedGalleries(profile_state).size()); 872 873 // Forget the device. 874 bool forget_gallery = false; 875 MediaGalleriesPreferences* prefs = GetPreferences(profile_state->profile()); 876 const MediaGalleriesPrefInfoMap& galleries = prefs->known_galleries(); 877 for (MediaGalleriesPrefInfoMap::const_iterator it = galleries.begin(); 878 it != galleries.end(); ++it) { 879 if (it->second.device_id == device_id) { 880 prefs->ForgetGalleryById(it->first); 881 forget_gallery = true; 882 break; 883 } 884 } 885 base::MessageLoop::current()->RunUntilIdle(); 886 EXPECT_TRUE(forget_gallery); 887 EXPECT_EQ(gallery_count, GetAutoAddedGalleries(profile_state).size()); 888 889 // Call GetPreferences() and the gallery count should not change. 890 prefs = GetPreferences(profile_state->profile()); 891 EXPECT_EQ(gallery_count, GetAutoAddedGalleries(profile_state).size()); 892} 893 894TEST_F(MediaFileSystemRegistryTest, GalleryNameDefault) { 895 FSInfoMap galleries_info; 896 InitForGalleriesInfoTest(&galleries_info); 897 898 for (FSInfoMap::const_iterator it = galleries_info.begin(); 899 it != galleries_info.end(); 900 ++it) { 901 CheckGalleryInfo(it->second, test_file_system_context(), 902 it->second.path, false, false); 903 } 904} 905 906// TODO(gbillock): Move the remaining test into the linux directory. 907#if !defined(OS_MACOSX) && !defined(OS_WIN) 908TEST_F(MediaFileSystemRegistryTest, GalleryMTP) { 909 FSInfoMap galleries_info; 910 InitForGalleriesInfoTest(&galleries_info); 911 912 base::FilePath location(FILE_PATH_LITERAL("/mtp_bogus")); 913 AttachDevice(StorageInfo::MTP_OR_PTP, "mtp_fake_id", location); 914 CheckNewGalleryInfo(GetProfileState(0U), galleries_info, location, 915 true /*removable*/, true /* media device */); 916} 917#endif 918 919TEST_F(MediaFileSystemRegistryTest, GalleryDCIM) { 920 FSInfoMap galleries_info; 921 InitForGalleriesInfoTest(&galleries_info); 922 923 AttachDevice(StorageInfo::REMOVABLE_MASS_STORAGE_WITH_DCIM, 924 "removable_dcim_fake_id", 925 dcim_dir()); 926 CheckNewGalleryInfo(GetProfileState(0U), galleries_info, dcim_dir(), 927 true /*removable*/, true /* media device */); 928} 929 930TEST_F(MediaFileSystemRegistryTest, GalleryNoDCIM) { 931 FSInfoMap galleries_info; 932 InitForGalleriesInfoTest(&galleries_info); 933 934 std::string device_id = 935 AttachDevice(StorageInfo::REMOVABLE_MASS_STORAGE_NO_DCIM, 936 empty_dir().AsUTF8Unsafe(), 937 empty_dir()); 938 std::string device_id2 = 939 AddUserGallery(StorageInfo::REMOVABLE_MASS_STORAGE_NO_DCIM, 940 empty_dir().AsUTF8Unsafe(), 941 empty_dir()); 942 ASSERT_EQ(device_id, device_id2); 943 // Add permission for new non-default gallery. 944 ProfileState* profile_state = GetProfileState(0U); 945 SetGalleryPermission(profile_state, 946 profile_state->all_permission_extension(), 947 device_id, 948 true /*has access*/); 949 CheckNewGalleryInfo(profile_state, galleries_info, empty_dir(), 950 true /*removable*/, false /* media device */); 951} 952 953TEST_F(MediaFileSystemRegistryTest, GalleryUserAddedPath) { 954 FSInfoMap galleries_info; 955 InitForGalleriesInfoTest(&galleries_info); 956 957 std::string device_id = AddUserGallery(StorageInfo::FIXED_MASS_STORAGE, 958 empty_dir().AsUTF8Unsafe(), 959 empty_dir()); 960 // Add permission for new non-default gallery. 961 ProfileState* profile_state = GetProfileState(0U); 962 SetGalleryPermission(profile_state, 963 profile_state->all_permission_extension(), 964 device_id, 965 true /*has access*/); 966 CheckNewGalleryInfo(profile_state, galleries_info, empty_dir(), 967 false /*removable*/, false /* media device */); 968} 969 970TEST_F(MediaFileSystemRegistryTest, DetachedDeviceGalleryPath) { 971 const std::string device_id = AttachDevice( 972 StorageInfo::REMOVABLE_MASS_STORAGE_WITH_DCIM, 973 "removable_dcim_fake_id", 974 dcim_dir()); 975 976 MediaGalleryPrefInfo pref_info; 977 pref_info.device_id = device_id; 978 EXPECT_EQ(dcim_dir().value(), pref_info.AbsolutePath().value()); 979 980 MediaGalleryPrefInfo pref_info_with_relpath; 981 pref_info_with_relpath.path = 982 base::FilePath(FILE_PATH_LITERAL("test_relpath")); 983 pref_info_with_relpath.device_id = device_id; 984 EXPECT_EQ(dcim_dir().Append(pref_info_with_relpath.path).value(), 985 pref_info_with_relpath.AbsolutePath().value()); 986 987 DetachDevice(device_id); 988 EXPECT_TRUE(pref_info.AbsolutePath().empty()); 989 EXPECT_TRUE(pref_info_with_relpath.AbsolutePath().empty()); 990} 991 992TEST_F(MediaFileSystemRegistryTest, TestNameConstruction) { 993 CreateProfileState(1); 994 AssertAllAutoAddedGalleries(); 995 996 ProfileState* profile_state = GetProfileState(0); 997 998 std::string user_gallery = AddUserGallery(StorageInfo::FIXED_MASS_STORAGE, 999 empty_dir().AsUTF8Unsafe(), 1000 empty_dir()); 1001 SetGalleryPermission(profile_state, 1002 profile_state->regular_permission_extension(), 1003 user_gallery, 1004 true /*has access*/); 1005 SetGalleryPermission(profile_state, 1006 profile_state->all_permission_extension(), 1007 user_gallery, 1008 true /*has access*/); 1009 1010 std::vector<MediaFileSystemInfo> auto_galleries = 1011 GetAutoAddedGalleries(profile_state); 1012 MediaFileSystemInfo added_info(empty_dir().BaseName().LossyDisplayName(), 1013 empty_dir(), std::string(), 0, std::string(), 1014 false, false); 1015 auto_galleries.push_back(added_info); 1016 std::vector<MediaFileSystemInfo> one_expectation; 1017 one_expectation.push_back(added_info); 1018 1019 profile_state->AddNameForReadCompare( 1020#if defined(OS_CHROMEOS) 1021 empty_dir().BaseName().LossyDisplayName()); 1022#else 1023 empty_dir().LossyDisplayName()); 1024#endif 1025 profile_state->AddNameForAllCompare( 1026#if defined(OS_CHROMEOS) 1027 empty_dir().BaseName().LossyDisplayName()); 1028#else 1029 empty_dir().LossyDisplayName()); 1030#endif 1031 1032 // This part of the test is conditional on default directories existing 1033 // on the test platform. In ChromeOS, these directories do not exist. 1034 base::FilePath path; 1035 if (num_auto_galleries() > 0) { 1036 ASSERT_TRUE(PathService::Get(chrome::DIR_USER_MUSIC, &path)); 1037#if defined(OS_CHROMEOS) 1038 profile_state->AddNameForAllCompare(path.BaseName().LossyDisplayName()); 1039#else 1040 profile_state->AddNameForAllCompare(path.LossyDisplayName()); 1041#endif 1042 ASSERT_TRUE(PathService::Get(chrome::DIR_USER_PICTURES, &path)); 1043#if defined(OS_CHROMEOS) 1044 profile_state->AddNameForAllCompare(path.BaseName().LossyDisplayName()); 1045#else 1046 profile_state->AddNameForAllCompare(path.LossyDisplayName()); 1047#endif 1048 ASSERT_TRUE(PathService::Get(chrome::DIR_USER_VIDEOS, &path)); 1049#if defined(OS_CHROMEOS) 1050 profile_state->AddNameForAllCompare(path.BaseName().LossyDisplayName()); 1051#else 1052 profile_state->AddNameForAllCompare(path.LossyDisplayName()); 1053#endif 1054 1055 profile_state->CheckGalleries("names-dir", one_expectation, auto_galleries); 1056 } else { 1057 profile_state->CheckGalleries("names", one_expectation, one_expectation); 1058 } 1059} 1060