// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. // MediaFileSystemRegistry unit tests. #include #include #include "base/bind_helpers.h" #include "base/command_line.h" #include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/memory/scoped_vector.h" #include "base/message_loop/message_loop.h" #include "base/path_service.h" #include "base/run_loop.h" #include "base/stl_util.h" #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "base/threading/sequenced_worker_pool.h" #include "base/values.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/test_extension_system.h" #include "chrome/browser/media_galleries/media_file_system_context.h" #include "chrome/browser/media_galleries/media_file_system_registry.h" #include "chrome/browser/media_galleries/media_galleries_preferences_factory.h" #include "chrome/browser/media_galleries/media_galleries_test_util.h" #include "chrome/common/chrome_paths.h" #include "chrome/test/base/chrome_render_view_host_test_harness.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/testing_profile.h" #include "components/storage_monitor/removable_device_constants.h" #include "components/storage_monitor/storage_info.h" #include "components/storage_monitor/storage_monitor.h" #include "components/storage_monitor/test_storage_monitor.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_process_host_factory.h" #include "content/public/browser/web_contents.h" #include "content/public/test/mock_render_process_host.h" #include "content/public/test/test_browser_thread.h" #include "content/public/test/web_contents_tester.h" #include "extensions/browser/extension_system.h" #include "extensions/common/extension.h" #include "sync/api/string_ordinal.h" #include "testing/gtest/include/gtest/gtest.h" #if defined(OS_CHROMEOS) #include "chrome/browser/chromeos/login/users/scoped_test_user_manager.h" #include "chrome/browser/chromeos/settings/cros_settings.h" #include "chrome/browser/chromeos/settings/device_settings_service.h" #endif using content::BrowserThread; using storage_monitor::StorageInfo; using storage_monitor::StorageMonitor; using storage_monitor::TestStorageMonitor; // Not anonymous so it can be friends with MediaFileSystemRegistry. class TestMediaFileSystemContext : public MediaFileSystemContext { public: struct FSInfo { FSInfo() {} FSInfo(const std::string& device_id, const base::FilePath& path, const std::string& fs_name); bool operator<(const FSInfo& other) const; std::string device_id; base::FilePath path; std::string fs_name; }; explicit TestMediaFileSystemContext(MediaFileSystemRegistry* registry); ~TestMediaFileSystemContext() override {} // MediaFileSystemContext implementation. bool RegisterFileSystem(const std::string& device_id, const std::string& fs_name, const base::FilePath& path) override; void RevokeFileSystem(const std::string& fs_name) override; base::FilePath GetRegisteredPath(const std::string& fs_name) const override; MediaFileSystemRegistry* registry() { return registry_; } private: void AddFSEntry(const std::string& device_id, const base::FilePath& path, const std::string& fs_name); MediaFileSystemRegistry* registry_; // The currently allocated mock file systems. std::map file_systems_by_name_; }; TestMediaFileSystemContext::FSInfo::FSInfo(const std::string& device_id, const base::FilePath& path, const std::string& fs_name) : device_id(device_id), path(path), fs_name(fs_name) { } bool TestMediaFileSystemContext::FSInfo::operator<(const FSInfo& other) const { if (device_id != other.device_id) return device_id < other.device_id; if (path.value() != other.path.value()) return path.value() < other.path.value(); return fs_name < other.fs_name; } TestMediaFileSystemContext::TestMediaFileSystemContext( MediaFileSystemRegistry* registry) : registry_(registry) { registry_->file_system_context_.reset(this); } bool TestMediaFileSystemContext::RegisterFileSystem( const std::string& device_id, const std::string& fs_name, const base::FilePath& path) { AddFSEntry(device_id, path, fs_name); return true; } void TestMediaFileSystemContext::RevokeFileSystem(const std::string& fs_name) { if (!ContainsKey(file_systems_by_name_, fs_name)) return; EXPECT_EQ(1U, file_systems_by_name_.erase(fs_name)); } base::FilePath TestMediaFileSystemContext::GetRegisteredPath( const std::string& fs_name) const { std::map::const_iterator it = file_systems_by_name_.find(fs_name); if (it == file_systems_by_name_.end()) return base::FilePath(); return it->second.path; } void TestMediaFileSystemContext::AddFSEntry(const std::string& device_id, const base::FilePath& path, const std::string& fs_name) { DCHECK_CURRENTLY_ON(BrowserThread::UI); DCHECK(path.IsAbsolute()); DCHECK(!path.ReferencesParent()); FSInfo info(device_id, path, fs_name); file_systems_by_name_[fs_name] = info; } namespace { typedef std::map FSInfoMap; void GetGalleryInfoCallback( FSInfoMap* results, const std::vector& file_systems) { for (size_t i = 0; i < file_systems.size(); ++i) { ASSERT_FALSE(ContainsKey(*results, file_systems[i].pref_id)); (*results)[file_systems[i].pref_id] = file_systems[i]; } } void CheckGalleryInfo(const MediaFileSystemInfo& info, TestMediaFileSystemContext* fs_context, const base::FilePath& path, bool removable, bool media_device) { EXPECT_EQ(path, info.path); EXPECT_EQ(removable, info.removable); EXPECT_EQ(media_device, info.media_device); EXPECT_NE(0UL, info.pref_id); if (removable) EXPECT_NE(0UL, info.transient_device_id.size()); else EXPECT_EQ(0UL, info.transient_device_id.size()); base::FilePath fsid_path = fs_context->GetRegisteredPath(info.fsid); EXPECT_EQ(path, fsid_path); } class MockProfileSharedRenderProcessHostFactory : public content::RenderProcessHostFactory { public: MockProfileSharedRenderProcessHostFactory() {} ~MockProfileSharedRenderProcessHostFactory() override; // RPH created with this factory are owned by it. If the RPH is destroyed // for testing purposes, it must be removed from the factory first. content::MockRenderProcessHost* ReleaseRPH( content::BrowserContext* browser_context); content::RenderProcessHost* CreateRenderProcessHost( content::BrowserContext* browser_context, content::SiteInstance* site_instance) const override; private: typedef std::map ProfileRPHMap; mutable ProfileRPHMap rph_map_; DISALLOW_COPY_AND_ASSIGN(MockProfileSharedRenderProcessHostFactory); }; class ProfileState { public: explicit ProfileState( MockProfileSharedRenderProcessHostFactory* rph_factory); ~ProfileState(); MediaGalleriesPreferences* GetMediaGalleriesPrefs(); void CheckGalleries( const std::string& test, const std::vector& regular_extension_galleries, const std::vector& all_extension_galleries); FSInfoMap GetGalleriesInfo(extensions::Extension* extension); extensions::Extension* all_permission_extension(); extensions::Extension* regular_permission_extension(); Profile* profile(); void AddNameForReadCompare(const base::string16& name); void AddNameForAllCompare(const base::string16& name); private: void CompareResults(const std::string& test, const std::vector& names, const std::vector& expected, const std::vector& actual); bool ContainsEntry(const MediaFileSystemInfo& info, const std::vector& container); int GetAndClearComparisonCount(); int num_comparisons_; scoped_ptr profile_; scoped_refptr all_permission_extension_; scoped_refptr regular_permission_extension_; scoped_refptr no_permissions_extension_; scoped_ptr single_web_contents_; scoped_ptr shared_web_contents1_; scoped_ptr shared_web_contents2_; // The RenderProcessHosts are freed when their respective WebContents / // RenderViewHosts go away. content::MockRenderProcessHost* single_rph_; content::MockRenderProcessHost* shared_rph_; std::vector compare_names_read_; std::vector compare_names_all_; DISALLOW_COPY_AND_ASSIGN(ProfileState); }; base::string16 GetExpectedFolderName(const base::FilePath& path) { #if defined(OS_CHROMEOS) return path.BaseName().LossyDisplayName(); #else return path.LossyDisplayName(); #endif } } // namespace class MediaFileSystemRegistryTest : public ChromeRenderViewHostTestHarness { public: void CreateProfileState(size_t profile_count); ProfileState* GetProfileState(size_t i); MediaGalleriesPreferences* GetPreferences(Profile* profile); base::FilePath empty_dir() { return empty_dir_; } base::FilePath dcim_dir() { return dcim_dir_; } TestMediaFileSystemContext* test_file_system_context() { return test_file_system_context_; } // Create a user added gallery based on the information passed and add it to // |profiles|. Returns the device id. std::string AddUserGallery(StorageInfo::Type type, const std::string& unique_id, const base::FilePath& path); // Returns the device id. std::string AttachDevice(StorageInfo::Type type, const std::string& unique_id, const base::FilePath& location); void DetachDevice(const std::string& device_id); void SetGalleryPermission(ProfileState* profile_state, extensions::Extension* extension, const std::string& device_id, bool has_access); void AssertAllAutoAddedGalleries(); void InitForGalleriesInfoTest(FSInfoMap* galleries_info); void CheckNewGalleryInfo(ProfileState* profile_state, const FSInfoMap& galleries_info, const base::FilePath& location, bool removable, bool media_device); std::vector GetAutoAddedGalleries( ProfileState* profile_state); void ProcessAttach(const std::string& id, const base::string16& name, const base::FilePath::StringType& location) { StorageInfo info(id, location, name, base::string16(), base::string16(), 0); StorageMonitor::GetInstance()->receiver()->ProcessAttach(info); } void ProcessDetach(const std::string& id) { StorageMonitor::GetInstance()->receiver()->ProcessDetach(id); } MediaFileSystemRegistry* registry() { return test_file_system_context_->registry(); } size_t GetExtensionGalleriesHostCount( const MediaFileSystemRegistry* registry) const; int num_auto_galleries() { return media_directories_.num_galleries(); } protected: void SetUp() override; void TearDown() override; private: // This makes sure that at least one default gallery exists on the file // system. EnsureMediaDirectoriesExists media_directories_; // Some test gallery directories. base::ScopedTempDir galleries_dir_; // An empty directory in |galleries_dir_| base::FilePath empty_dir_; // A directory in |galleries_dir_| with a DCIM directory in it. base::FilePath dcim_dir_; // MediaFileSystemRegistry owns this. TestMediaFileSystemContext* test_file_system_context_; // Needed for extension service & friends to work. #if defined(OS_CHROMEOS) chromeos::ScopedTestDeviceSettingsService test_device_settings_service_; chromeos::ScopedTestCrosSettings test_cros_settings_; scoped_ptr test_user_manager_; #endif MockProfileSharedRenderProcessHostFactory rph_factory_; ScopedVector profile_states_; }; namespace { bool MediaFileSystemInfoComparator(const MediaFileSystemInfo& a, const MediaFileSystemInfo& b) { CHECK_NE(a.name, b.name); // Name must be unique. return a.name < b.name; } /////////////////////////////////////////////// // MockProfileSharedRenderProcessHostFactory // /////////////////////////////////////////////// MockProfileSharedRenderProcessHostFactory:: ~MockProfileSharedRenderProcessHostFactory() { STLDeleteValues(&rph_map_); } content::MockRenderProcessHost* MockProfileSharedRenderProcessHostFactory::ReleaseRPH( content::BrowserContext* browser_context) { ProfileRPHMap::iterator existing = rph_map_.find(browser_context); if (existing == rph_map_.end()) return NULL; content::MockRenderProcessHost* result = existing->second; rph_map_.erase(existing); return result; } content::RenderProcessHost* MockProfileSharedRenderProcessHostFactory::CreateRenderProcessHost( content::BrowserContext* browser_context, content::SiteInstance* site_instance) const { ProfileRPHMap::const_iterator existing = rph_map_.find(browser_context); if (existing != rph_map_.end()) return existing->second; rph_map_[browser_context] = new content::MockRenderProcessHost(browser_context); return rph_map_[browser_context]; } ////////////////// // ProfileState // ////////////////// ProfileState::ProfileState( MockProfileSharedRenderProcessHostFactory* rph_factory) : num_comparisons_(0), profile_(new TestingProfile()) { extensions::TestExtensionSystem* extension_system( static_cast( extensions::ExtensionSystem::Get(profile_.get()))); extension_system->CreateExtensionService( base::CommandLine::ForCurrentProcess(), base::FilePath(), false); std::vector all_permissions; all_permissions.push_back("allAutoDetected"); all_permissions.push_back("read"); std::vector read_permissions; read_permissions.push_back("read"); all_permission_extension_ = AddMediaGalleriesApp("all", all_permissions, profile_.get()); regular_permission_extension_ = AddMediaGalleriesApp("regular", read_permissions, profile_.get()); no_permissions_extension_ = AddMediaGalleriesApp("no", read_permissions, profile_.get()); single_web_contents_.reset( content::WebContentsTester::CreateTestWebContents(profile_.get(), NULL)); single_rph_ = rph_factory->ReleaseRPH(profile_.get()); shared_web_contents1_.reset( content::WebContentsTester::CreateTestWebContents(profile_.get(), NULL)); shared_web_contents2_.reset( content::WebContentsTester::CreateTestWebContents(profile_.get(), NULL)); shared_rph_ = rph_factory->ReleaseRPH(profile_.get()); } ProfileState::~ProfileState() { // TestExtensionSystem uses DeleteSoon, so we need to delete the profiles // and then run the message queue to clean up. But first we have to // delete everything that references the profile. single_web_contents_.reset(); shared_web_contents1_.reset(); shared_web_contents2_.reset(); profile_.reset(); base::MessageLoop::current()->RunUntilIdle(); } MediaGalleriesPreferences* ProfileState::GetMediaGalleriesPrefs() { MediaGalleriesPreferences* prefs = MediaGalleriesPreferencesFactory::GetForProfile(profile_.get()); base::RunLoop loop; prefs->EnsureInitialized(loop.QuitClosure()); loop.Run(); return prefs; } void ProfileState::CheckGalleries( const std::string& test, const std::vector& regular_extension_galleries, const std::vector& all_extension_galleries) { MediaFileSystemRegistry* registry = g_browser_process->media_file_system_registry(); // No Media Galleries permissions. std::vector empty_expectation; std::vector empty_names; registry->GetMediaFileSystemsForExtension( single_web_contents_.get(), no_permissions_extension_.get(), base::Bind(&ProfileState::CompareResults, base::Unretained(this), base::StringPrintf("%s (no permission)", test.c_str()), base::ConstRef(empty_names), base::ConstRef(empty_expectation))); base::MessageLoop::current()->RunUntilIdle(); EXPECT_EQ(1, GetAndClearComparisonCount()); // Read permission only. registry->GetMediaFileSystemsForExtension( single_web_contents_.get(), regular_permission_extension_.get(), base::Bind(&ProfileState::CompareResults, base::Unretained(this), base::StringPrintf("%s (regular permission)", test.c_str()), base::ConstRef(compare_names_read_), base::ConstRef(regular_extension_galleries))); base::MessageLoop::current()->RunUntilIdle(); EXPECT_EQ(1, GetAndClearComparisonCount()); // All galleries permission. registry->GetMediaFileSystemsForExtension( single_web_contents_.get(), all_permission_extension_.get(), base::Bind(&ProfileState::CompareResults, base::Unretained(this), base::StringPrintf("%s (all permission)", test.c_str()), base::ConstRef(compare_names_all_), base::ConstRef(all_extension_galleries))); base::MessageLoop::current()->RunUntilIdle(); EXPECT_EQ(1, GetAndClearComparisonCount()); } FSInfoMap ProfileState::GetGalleriesInfo(extensions::Extension* extension) { FSInfoMap results; MediaFileSystemRegistry* registry = g_browser_process->media_file_system_registry(); registry->GetMediaFileSystemsForExtension( single_web_contents_.get(), extension, base::Bind(&GetGalleryInfoCallback, base::Unretained(&results))); base::MessageLoop::current()->RunUntilIdle(); return results; } extensions::Extension* ProfileState::all_permission_extension() { return all_permission_extension_.get(); } extensions::Extension* ProfileState::regular_permission_extension() { return regular_permission_extension_.get(); } Profile* ProfileState::profile() { return profile_.get(); } void ProfileState::AddNameForReadCompare(const base::string16& name) { compare_names_read_.push_back(name); } void ProfileState::AddNameForAllCompare(const base::string16& name) { compare_names_all_.push_back(name); } bool ProfileState::ContainsEntry( const MediaFileSystemInfo& info, const std::vector& container) { for (size_t i = 0; i < container.size(); ++i) { if (info.path.value() == container[i].path.value()) { EXPECT_FALSE(container[i].fsid.empty()); if (!info.fsid.empty()) EXPECT_EQ(info.fsid, container[i].fsid); return true; } } return false; } void ProfileState::CompareResults( const std::string& test, const std::vector& names, const std::vector& expected, const std::vector& actual) { num_comparisons_++; EXPECT_EQ(expected.size(), actual.size()) << test; // Order isn't important, so sort the results. std::vector sorted(actual); std::sort(sorted.begin(), sorted.end(), MediaFileSystemInfoComparator); std::vector expect(expected); std::sort(expect.begin(), expect.end(), MediaFileSystemInfoComparator); std::vector expect_names(names); std::sort(expect_names.begin(), expect_names.end()); for (size_t i = 0; i < expect.size() && i < sorted.size(); ++i) { if (expect_names.size() > i) EXPECT_EQ(expect_names[i], sorted[i].name) << test; EXPECT_TRUE(ContainsEntry(expect[i], sorted)) << test; } } int ProfileState::GetAndClearComparisonCount() { int result = num_comparisons_; num_comparisons_ = 0; return result; } } // namespace ///////////////////////////////// // MediaFileSystemRegistryTest // ///////////////////////////////// void MediaFileSystemRegistryTest::CreateProfileState(size_t profile_count) { for (size_t i = 0; i < profile_count; ++i) { ProfileState* state = new ProfileState(&rph_factory_); profile_states_.push_back(state); } } ProfileState* MediaFileSystemRegistryTest::GetProfileState(size_t i) { return profile_states_[i]; } MediaGalleriesPreferences* MediaFileSystemRegistryTest::GetPreferences( Profile* profile) { MediaGalleriesPreferences* prefs = registry()->GetPreferences(profile); base::RunLoop loop; prefs->EnsureInitialized(loop.QuitClosure()); loop.Run(); return prefs; } std::string MediaFileSystemRegistryTest::AddUserGallery( StorageInfo::Type type, const std::string& unique_id, const base::FilePath& path) { std::string device_id = StorageInfo::MakeDeviceId(type, unique_id); DCHECK(!StorageInfo::IsMediaDevice(device_id)); for (size_t i = 0; i < profile_states_.size(); ++i) { profile_states_[i]->GetMediaGalleriesPrefs()->AddGallery( device_id, base::FilePath(), MediaGalleryPrefInfo::kUserAdded, base::string16(), base::string16(), base::string16(), 0, base::Time::Now(), 0, 0, 0); } return device_id; } std::string MediaFileSystemRegistryTest::AttachDevice( StorageInfo::Type type, const std::string& unique_id, const base::FilePath& location) { std::string device_id = StorageInfo::MakeDeviceId(type, unique_id); DCHECK(StorageInfo::IsRemovableDevice(device_id)); base::string16 label = location.BaseName().LossyDisplayName(); ProcessAttach(device_id, label, location.value()); base::MessageLoop::current()->RunUntilIdle(); return device_id; } void MediaFileSystemRegistryTest::DetachDevice(const std::string& device_id) { DCHECK(StorageInfo::IsRemovableDevice(device_id)); ProcessDetach(device_id); base::MessageLoop::current()->RunUntilIdle(); } void MediaFileSystemRegistryTest::SetGalleryPermission( ProfileState* profile_state, extensions::Extension* extension, const std::string& device_id, bool has_access) { MediaGalleriesPreferences* preferences = profile_state->GetMediaGalleriesPrefs(); MediaGalleryPrefIdSet pref_id = preferences->LookUpGalleriesByDeviceId(device_id); ASSERT_EQ(1U, pref_id.size()); preferences->SetGalleryPermissionForExtension(*extension, *pref_id.begin(), has_access); } void MediaFileSystemRegistryTest::AssertAllAutoAddedGalleries() { for (size_t i = 0; i < profile_states_.size(); ++i) { MediaGalleriesPreferences* prefs = profile_states_[0]->GetMediaGalleriesPrefs(); // Make sure that we have at least one gallery and that they are all // auto added galleries. const MediaGalleriesPrefInfoMap& galleries = prefs->known_galleries(); #if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) ASSERT_GT(galleries.size(), 0U); #endif for (MediaGalleriesPrefInfoMap::const_iterator it = galleries.begin(); it != galleries.end(); ++it) { ASSERT_EQ(MediaGalleryPrefInfo::kAutoDetected, it->second.type); } } } void MediaFileSystemRegistryTest::InitForGalleriesInfoTest( FSInfoMap* galleries_info) { CreateProfileState(1); AssertAllAutoAddedGalleries(); // Get all existing gallery names. ProfileState* profile_state = GetProfileState(0U); *galleries_info = profile_state->GetGalleriesInfo( profile_state->all_permission_extension()); #if !defined(OS_CHROMEOS) && !defined(OS_ANDROID) ASSERT_EQ(3U, galleries_info->size()); #else ASSERT_EQ(0U, galleries_info->size()); #endif } void MediaFileSystemRegistryTest::CheckNewGalleryInfo( ProfileState* profile_state, const FSInfoMap& galleries_info, const base::FilePath& location, bool removable, bool media_device) { // Get new galleries. FSInfoMap new_galleries_info = profile_state->GetGalleriesInfo( profile_state->all_permission_extension()); ASSERT_EQ(galleries_info.size() + 1U, new_galleries_info.size()); bool found_new = false; for (FSInfoMap::const_iterator it = new_galleries_info.begin(); it != new_galleries_info.end(); ++it) { if (ContainsKey(galleries_info, it->first)) continue; ASSERT_FALSE(found_new); CheckGalleryInfo(it->second, test_file_system_context_, location, removable, media_device); found_new = true; } ASSERT_TRUE(found_new); } std::vector MediaFileSystemRegistryTest::GetAutoAddedGalleries( ProfileState* profile_state) { const MediaGalleriesPrefInfoMap& galleries = profile_state->GetMediaGalleriesPrefs()->known_galleries(); std::vector result; for (MediaGalleriesPrefInfoMap::const_iterator it = galleries.begin(); it != galleries.end(); ++it) { if (it->second.type == MediaGalleryPrefInfo::kAutoDetected) { base::FilePath path = it->second.AbsolutePath(); MediaFileSystemInfo info(path.BaseName().LossyDisplayName(), path, std::string(), 0, std::string(), false, false); result.push_back(info); } } std::sort(result.begin(), result.end(), MediaFileSystemInfoComparator); return result; } size_t MediaFileSystemRegistryTest::GetExtensionGalleriesHostCount( const MediaFileSystemRegistry* registry) const { size_t extension_galleries_host_count = 0; for (MediaFileSystemRegistry::ExtensionGalleriesHostMap::const_iterator it = registry->extension_hosts_map_.begin(); it != registry->extension_hosts_map_.end(); ++it) { extension_galleries_host_count += it->second.size(); } return extension_galleries_host_count; } void MediaFileSystemRegistryTest::SetUp() { ChromeRenderViewHostTestHarness::SetUp(); ASSERT_TRUE(TestStorageMonitor::CreateAndInstall()); DeleteContents(); SetRenderProcessHostFactory(&rph_factory_); test_file_system_context_ = new TestMediaFileSystemContext( g_browser_process->media_file_system_registry()); #if defined(OS_CHROMEOS) test_user_manager_.reset(new chromeos::ScopedTestUserManager()); #endif ASSERT_TRUE(galleries_dir_.CreateUniqueTempDir()); empty_dir_ = galleries_dir_.path().AppendASCII("empty"); ASSERT_TRUE(base::CreateDirectory(empty_dir_)); dcim_dir_ = galleries_dir_.path().AppendASCII("with_dcim"); ASSERT_TRUE(base::CreateDirectory(dcim_dir_)); ASSERT_TRUE(base::CreateDirectory( dcim_dir_.Append(storage_monitor::kDCIMDirectoryName))); } void MediaFileSystemRegistryTest::TearDown() { profile_states_.clear(); MediaFileSystemRegistry* registry = g_browser_process->media_file_system_registry(); EXPECT_EQ(0U, GetExtensionGalleriesHostCount(registry)); TestStorageMonitor::Destroy(); #if defined(OS_CHROMEOS) test_user_manager_.reset(); #endif ChromeRenderViewHostTestHarness::TearDown(); } /////////// // Tests // /////////// TEST_F(MediaFileSystemRegistryTest, Basic) { CreateProfileState(1); AssertAllAutoAddedGalleries(); ProfileState* profile_state = GetProfileState(0); std::vector auto_galleries = GetAutoAddedGalleries(profile_state); std::vector empty_expectation; profile_state->CheckGalleries("basic", empty_expectation, auto_galleries); } TEST_F(MediaFileSystemRegistryTest, UserAddedGallery) { CreateProfileState(1); AssertAllAutoAddedGalleries(); ProfileState* profile_state = GetProfileState(0); std::vector auto_galleries = GetAutoAddedGalleries(profile_state); std::vector added_galleries; profile_state->CheckGalleries("user added init", added_galleries, auto_galleries); // Add a user gallery to the regular permission extension. std::string device_id = AddUserGallery(StorageInfo::FIXED_MASS_STORAGE, empty_dir().AsUTF8Unsafe(), empty_dir()); SetGalleryPermission(profile_state, profile_state->regular_permission_extension(), device_id, true /*has access*/); MediaFileSystemInfo added_info(empty_dir().LossyDisplayName(), empty_dir(), std::string(), 0, std::string(), false, false); added_galleries.push_back(added_info); profile_state->CheckGalleries("user added regular", added_galleries, auto_galleries); // Add it to the all galleries extension. SetGalleryPermission(profile_state, profile_state->all_permission_extension(), device_id, true /*has access*/); auto_galleries.push_back(added_info); profile_state->CheckGalleries("user added all", added_galleries, auto_galleries); } // Regression test to make sure erasing galleries does not result a crash. TEST_F(MediaFileSystemRegistryTest, EraseGalleries) { CreateProfileState(1); AssertAllAutoAddedGalleries(); ProfileState* profile_state = GetProfileState(0); std::vector auto_galleries = GetAutoAddedGalleries(profile_state); std::vector empty_expectation; profile_state->CheckGalleries("erase", empty_expectation, auto_galleries); MediaGalleriesPreferences* prefs = profile_state->GetMediaGalleriesPrefs(); MediaGalleriesPrefInfoMap galleries = prefs->known_galleries(); for (MediaGalleriesPrefInfoMap::const_iterator it = galleries.begin(); it != galleries.end(); ++it) { prefs->ForgetGalleryById(it->first); } } // Regression test to make sure calling GetPreferences() does not re-insert // galleries on auto-detected removable devices that were blacklisted. TEST_F(MediaFileSystemRegistryTest, GetPreferencesDoesNotReinsertBlacklistedGalleries) { CreateProfileState(1); AssertAllAutoAddedGalleries(); ProfileState* profile_state = GetProfileState(0); const size_t gallery_count = GetAutoAddedGalleries(profile_state).size(); // Attach a device. const std::string device_id = AttachDevice( StorageInfo::REMOVABLE_MASS_STORAGE_WITH_DCIM, "removable_dcim_fake_id", dcim_dir()); EXPECT_EQ(gallery_count + 1, GetAutoAddedGalleries(profile_state).size()); // Forget the device. bool forget_gallery = false; MediaGalleriesPreferences* prefs = GetPreferences(profile_state->profile()); const MediaGalleriesPrefInfoMap& galleries = prefs->known_galleries(); for (MediaGalleriesPrefInfoMap::const_iterator it = galleries.begin(); it != galleries.end(); ++it) { if (it->second.device_id == device_id) { prefs->ForgetGalleryById(it->first); forget_gallery = true; break; } } base::MessageLoop::current()->RunUntilIdle(); EXPECT_TRUE(forget_gallery); EXPECT_EQ(gallery_count, GetAutoAddedGalleries(profile_state).size()); // Call GetPreferences() and the gallery count should not change. prefs = GetPreferences(profile_state->profile()); EXPECT_EQ(gallery_count, GetAutoAddedGalleries(profile_state).size()); } TEST_F(MediaFileSystemRegistryTest, GalleryNameDefault) { FSInfoMap galleries_info; InitForGalleriesInfoTest(&galleries_info); for (FSInfoMap::const_iterator it = galleries_info.begin(); it != galleries_info.end(); ++it) { CheckGalleryInfo(it->second, test_file_system_context(), it->second.path, false, false); } } // TODO(gbillock): Move the remaining test into the linux directory. #if !defined(OS_MACOSX) && !defined(OS_WIN) TEST_F(MediaFileSystemRegistryTest, GalleryMTP) { FSInfoMap galleries_info; InitForGalleriesInfoTest(&galleries_info); base::FilePath location(FILE_PATH_LITERAL("/mtp_bogus")); AttachDevice(StorageInfo::MTP_OR_PTP, "mtp_fake_id", location); CheckNewGalleryInfo(GetProfileState(0U), galleries_info, location, true /*removable*/, true /* media device */); } #endif TEST_F(MediaFileSystemRegistryTest, GalleryDCIM) { FSInfoMap galleries_info; InitForGalleriesInfoTest(&galleries_info); AttachDevice(StorageInfo::REMOVABLE_MASS_STORAGE_WITH_DCIM, "removable_dcim_fake_id", dcim_dir()); CheckNewGalleryInfo(GetProfileState(0U), galleries_info, dcim_dir(), true /*removable*/, true /* media device */); } TEST_F(MediaFileSystemRegistryTest, GalleryNoDCIM) { FSInfoMap galleries_info; InitForGalleriesInfoTest(&galleries_info); std::string device_id = AttachDevice(StorageInfo::REMOVABLE_MASS_STORAGE_NO_DCIM, empty_dir().AsUTF8Unsafe(), empty_dir()); std::string device_id2 = AddUserGallery(StorageInfo::REMOVABLE_MASS_STORAGE_NO_DCIM, empty_dir().AsUTF8Unsafe(), empty_dir()); ASSERT_EQ(device_id, device_id2); // Add permission for new non-default gallery. ProfileState* profile_state = GetProfileState(0U); SetGalleryPermission(profile_state, profile_state->all_permission_extension(), device_id, true /*has access*/); CheckNewGalleryInfo(profile_state, galleries_info, empty_dir(), true /*removable*/, false /* media device */); } TEST_F(MediaFileSystemRegistryTest, GalleryUserAddedPath) { FSInfoMap galleries_info; InitForGalleriesInfoTest(&galleries_info); std::string device_id = AddUserGallery(StorageInfo::FIXED_MASS_STORAGE, empty_dir().AsUTF8Unsafe(), empty_dir()); // Add permission for new non-default gallery. ProfileState* profile_state = GetProfileState(0U); SetGalleryPermission(profile_state, profile_state->all_permission_extension(), device_id, true /*has access*/); CheckNewGalleryInfo(profile_state, galleries_info, empty_dir(), false /*removable*/, false /* media device */); } TEST_F(MediaFileSystemRegistryTest, DetachedDeviceGalleryPath) { const std::string device_id = AttachDevice( StorageInfo::REMOVABLE_MASS_STORAGE_WITH_DCIM, "removable_dcim_fake_id", dcim_dir()); MediaGalleryPrefInfo pref_info; pref_info.device_id = device_id; EXPECT_EQ(dcim_dir().value(), pref_info.AbsolutePath().value()); MediaGalleryPrefInfo pref_info_with_relpath; pref_info_with_relpath.path = base::FilePath(FILE_PATH_LITERAL("test_relpath")); pref_info_with_relpath.device_id = device_id; EXPECT_EQ(dcim_dir().Append(pref_info_with_relpath.path).value(), pref_info_with_relpath.AbsolutePath().value()); DetachDevice(device_id); EXPECT_TRUE(pref_info.AbsolutePath().empty()); EXPECT_TRUE(pref_info_with_relpath.AbsolutePath().empty()); } TEST_F(MediaFileSystemRegistryTest, TestNameConstruction) { CreateProfileState(1); AssertAllAutoAddedGalleries(); ProfileState* profile_state = GetProfileState(0); std::string user_gallery = AddUserGallery(StorageInfo::FIXED_MASS_STORAGE, empty_dir().AsUTF8Unsafe(), empty_dir()); SetGalleryPermission(profile_state, profile_state->regular_permission_extension(), user_gallery, true /*has access*/); SetGalleryPermission(profile_state, profile_state->all_permission_extension(), user_gallery, true /*has access*/); std::vector auto_galleries = GetAutoAddedGalleries(profile_state); MediaFileSystemInfo added_info(empty_dir().BaseName().LossyDisplayName(), empty_dir(), std::string(), 0, std::string(), false, false); auto_galleries.push_back(added_info); std::vector one_expectation; one_expectation.push_back(added_info); base::string16 empty_dir_name = GetExpectedFolderName(empty_dir()); profile_state->AddNameForReadCompare(empty_dir_name); profile_state->AddNameForAllCompare(empty_dir_name); // This part of the test is conditional on default directories existing // on the test platform. In ChromeOS, these directories do not exist. base::FilePath path; if (num_auto_galleries() > 0) { ASSERT_TRUE(PathService::Get(chrome::DIR_USER_MUSIC, &path)); profile_state->AddNameForAllCompare(GetExpectedFolderName(path)); ASSERT_TRUE(PathService::Get(chrome::DIR_USER_PICTURES, &path)); profile_state->AddNameForAllCompare(GetExpectedFolderName(path)); ASSERT_TRUE(PathService::Get(chrome::DIR_USER_VIDEOS, &path)); profile_state->AddNameForAllCompare(GetExpectedFolderName(path)); profile_state->CheckGalleries("names-dir", one_expectation, auto_galleries); } else { profile_state->CheckGalleries("names", one_expectation, one_expectation); } } TEST_F(MediaFileSystemRegistryTest, PreferenceListener) { CreateProfileState(1); AssertAllAutoAddedGalleries(); // Add a user gallery to the regular permission extension. std::string device_id = AddUserGallery(StorageInfo::FIXED_MASS_STORAGE, empty_dir().AsUTF8Unsafe(), empty_dir()); ProfileState* profile_state = GetProfileState(0); SetGalleryPermission(profile_state, profile_state->regular_permission_extension(), device_id, true /*has access*/); FSInfoMap fs_info = profile_state->GetGalleriesInfo( profile_state->regular_permission_extension()); ASSERT_EQ(1U, fs_info.size()); EXPECT_FALSE(test_file_system_context()->GetRegisteredPath( fs_info.begin()->second.fsid).empty()); // Revoke permission and ensure that the file system is revoked. SetGalleryPermission(profile_state, profile_state->regular_permission_extension(), device_id, false /*has access*/); EXPECT_TRUE(test_file_system_context()->GetRegisteredPath( fs_info.begin()->second.fsid).empty()); }