blob: 6cecb16d18733eb4b01f2076bd0968644b2410c8 [file] [log] [blame]
// 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 "chrome/browser/media_galleries/media_file_system_registry.h"
#include <stddef.h>
#include <algorithm>
#include <memory>
#include <set>
#include <vector>
#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/macros.h"
#include "base/memory/ptr_util.h"
#include "base/memory/ref_counted.h"
#include "base/path_service.h"
#include "base/run_loop.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 "build/build_config.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_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 "components/sync/model/string_ordinal.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/test_utils.h"
#include "content/public/test/web_contents_tester.h"
#include "extensions/browser/extension_system.h"
#include "extensions/common/extension.h"
#include "testing/gtest/include/gtest/gtest.h"
#if defined(OS_CHROMEOS)
#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<std::string /*fs_name*/, FSInfo> 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 (!base::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<std::string /*fs_name*/, FSInfo>::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<MediaGalleryPrefId, MediaFileSystemInfo> FSInfoMap;
void GetGalleryInfoCallback(
FSInfoMap* results,
const std::vector<MediaFileSystemInfo>& file_systems) {
for (size_t i = 0; i < file_systems.size(); ++i) {
ASSERT_FALSE(base::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) const override;
private:
mutable std::map<content::BrowserContext*,
std::unique_ptr<content::MockRenderProcessHost>>
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<MediaFileSystemInfo>& regular_extension_galleries,
const std::vector<MediaFileSystemInfo>& 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<base::string16>& names,
const std::vector<MediaFileSystemInfo>& expected,
const std::vector<MediaFileSystemInfo>& actual);
bool ContainsEntry(const MediaFileSystemInfo& info,
const std::vector<MediaFileSystemInfo>& container);
int GetAndClearComparisonCount();
int num_comparisons_;
std::unique_ptr<TestingProfile> profile_;
scoped_refptr<extensions::Extension> all_permission_extension_;
scoped_refptr<extensions::Extension> regular_permission_extension_;
scoped_refptr<extensions::Extension> no_permissions_extension_;
std::unique_ptr<content::WebContents> single_web_contents_;
std::unique_ptr<content::WebContents> shared_web_contents1_;
std::unique_ptr<content::WebContents> shared_web_contents2_;
// The RenderProcessHosts are freed when their respective WebContents /
// RenderViewHosts go away.
content::MockRenderProcessHost* single_rph_;
content::MockRenderProcessHost* shared_rph_;
std::vector<base::string16> compare_names_read_;
std::vector<base::string16> 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:
MediaFileSystemRegistryTest() = default;
~MediaFileSystemRegistryTest() override = default;
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<MediaFileSystemInfo> 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_;
#endif
MockProfileSharedRenderProcessHostFactory rph_factory_;
std::vector<std::unique_ptr<ProfileState>> profile_states_;
DISALLOW_COPY_AND_ASSIGN(MediaFileSystemRegistryTest);
};
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() {
}
content::MockRenderProcessHost*
MockProfileSharedRenderProcessHostFactory::ReleaseRPH(
content::BrowserContext* browser_context) {
auto existing = rph_map_.find(browser_context);
if (existing == rph_map_.end())
return NULL;
std::unique_ptr<content::MockRenderProcessHost> result =
std::move(existing->second);
rph_map_.erase(existing);
return result.release();
}
content::RenderProcessHost*
MockProfileSharedRenderProcessHostFactory::CreateRenderProcessHost(
content::BrowserContext* browser_context) const {
auto existing = rph_map_.find(browser_context);
if (existing != rph_map_.end())
return existing->second.get();
rph_map_[browser_context] =
base::MakeUnique<content::MockRenderProcessHost>(browser_context);
return rph_map_[browser_context].get();
}
//////////////////
// ProfileState //
//////////////////
ProfileState::ProfileState(
MockProfileSharedRenderProcessHostFactory* rph_factory)
: num_comparisons_(0), profile_(new TestingProfile()) {
extensions::TestExtensionSystem* extension_system(
static_cast<extensions::TestExtensionSystem*>(
extensions::ExtensionSystem::Get(profile_.get())));
extension_system->CreateExtensionService(
base::CommandLine::ForCurrentProcess(), base::FilePath(), false);
std::vector<std::string> all_permissions;
all_permissions.push_back("allAutoDetected");
all_permissions.push_back("read");
std::vector<std::string> 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();
content::RunAllTasksUntilIdle();
}
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<MediaFileSystemInfo>& regular_extension_galleries,
const std::vector<MediaFileSystemInfo>& all_extension_galleries) {
MediaFileSystemRegistry* registry =
g_browser_process->media_file_system_registry();
// No Media Galleries permissions.
std::vector<MediaFileSystemInfo> empty_expectation;
std::vector<base::string16> 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)));
content::RunAllTasksUntilIdle();
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)));
content::RunAllTasksUntilIdle();
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)));
content::RunAllTasksUntilIdle();
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)));
content::RunAllTasksUntilIdle();
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<MediaFileSystemInfo>& 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<base::string16>& names,
const std::vector<MediaFileSystemInfo>& expected,
const std::vector<MediaFileSystemInfo>& actual) {
num_comparisons_++;
EXPECT_EQ(expected.size(), actual.size()) << test;
// Order isn't important, so sort the results.
std::vector<MediaFileSystemInfo> sorted(actual);
std::sort(sorted.begin(), sorted.end(), MediaFileSystemInfoComparator);
std::vector<MediaFileSystemInfo> expect(expected);
std::sort(expect.begin(), expect.end(), MediaFileSystemInfoComparator);
std::vector<base::string16> 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) {
profile_states_.push_back(base::MakeUnique<ProfileState>(&rph_factory_));
}
}
ProfileState* MediaFileSystemRegistryTest::GetProfileState(size_t i) {
return profile_states_[i].get();
}
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());
content::RunAllTasksUntilIdle();
return device_id;
}
void MediaFileSystemRegistryTest::DetachDevice(const std::string& device_id) {
DCHECK(StorageInfo::IsRemovableDevice(device_id));
ProcessDetach(device_id);
content::RunAllTasksUntilIdle();
}
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 (base::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<MediaFileSystemInfo>
MediaFileSystemRegistryTest::GetAutoAddedGalleries(
ProfileState* profile_state) {
const MediaGalleriesPrefInfoMap& galleries =
profile_state->GetMediaGalleriesPrefs()->known_galleries();
std::vector<MediaFileSystemInfo> 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());
ASSERT_TRUE(galleries_dir_.CreateUniqueTempDir());
empty_dir_ = galleries_dir_.GetPath().AppendASCII("empty");
ASSERT_TRUE(base::CreateDirectory(empty_dir_));
dcim_dir_ = galleries_dir_.GetPath().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));
// The TestingProfile must be destroyed before the TestingBrowserProcess
// because it uses it in its destructor.
ChromeRenderViewHostTestHarness::TearDown();
// The MediaFileSystemRegistry owned by the TestingBrowserProcess must be
// destroyed before the StorageMonitor because it calls
// StorageMonitor::RemoveObserver() in its destructor.
TestingBrowserProcess::DeleteInstance();
TestStorageMonitor::Destroy();
}
///////////
// Tests //
///////////
TEST_F(MediaFileSystemRegistryTest, Basic) {
CreateProfileState(1);
AssertAllAutoAddedGalleries();
ProfileState* profile_state = GetProfileState(0);
std::vector<MediaFileSystemInfo> auto_galleries =
GetAutoAddedGalleries(profile_state);
std::vector<MediaFileSystemInfo> empty_expectation;
profile_state->CheckGalleries("basic", empty_expectation, auto_galleries);
}
TEST_F(MediaFileSystemRegistryTest, UserAddedGallery) {
CreateProfileState(1);
AssertAllAutoAddedGalleries();
ProfileState* profile_state = GetProfileState(0);
std::vector<MediaFileSystemInfo> auto_galleries =
GetAutoAddedGalleries(profile_state);
std::vector<MediaFileSystemInfo> 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<MediaFileSystemInfo> auto_galleries =
GetAutoAddedGalleries(profile_state);
std::vector<MediaFileSystemInfo> 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;
}
}
content::RunAllTasksUntilIdle();
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<MediaFileSystemInfo> 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<MediaFileSystemInfo> 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());
}