blob: 11d299c319b4df65c51997a13ee78621d78e77f8 [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.
#include <memory>
#include "ash/constants/ash_switches.h"
#include "base/bind.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/path_service.h"
#include "base/strings/strcat.h"
#include "base/strings/string_util.h"
#include "chrome/browser/ash/drive/drive_integration_service.h"
#include "chrome/browser/ash/drive/drivefs_test_support.h"
#include "chrome/browser/ash/file_manager/file_manager_test_util.h"
#include "chrome/browser/ash/file_manager/mount_test_util.h"
#include "chrome/browser/ash/file_manager/volume_manager.h"
#include "chrome/browser/ash/profiles/profile_helper.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/extension_apitest.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/ash/cast_config_controller_media_router.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/web_applications/system_web_apps/system_web_app_manager.h"
#include "chrome/browser/web_applications/web_app_provider.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/chrome_paths.h"
#include "components/media_router/browser/test/mock_media_router.h"
#include "components/session_manager/core/session_manager.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/navigation_handle.h"
#include "content/public/browser/notification_service.h"
#include "content/public/test/browser_test.h"
#include "content/public/test/test_navigation_observer.h"
#include "content/public/test/test_utils.h"
#include "extensions/browser/notification_types.h"
#include "extensions/test/result_catcher.h"
#include "google_apis/common/test_util.h"
#include "storage/browser/file_system/external_mount_points.h"
#include "ui/shell_dialogs/select_file_dialog_factory.h"
#include "ui/shell_dialogs/select_file_policy.h"
// Tests for access to external file systems (as defined in
// storage/common/file_system/file_system_types.h) from extensions with
// fileManagerPrivate and fileBrowserHandler extension permissions.
// The tests cover following external file system types:
// - local (kFileSystemTypeLocalNative): a local file system on which files are
// accessed using native local path.
// - restricted (kFileSystemTypeRestrictedLocalNative): a *read-only* local file
// system which can only be accessed by extensions that have full access to
// external file systems (i.e. extensions with fileManagerPrivate permission).
//
// The tests cover following scenarios:
// - Performing file system operations on external file systems from an
// app with fileManagerPrivate permission (i.e. The Files app).
// - Performing read/write operations from file handler extensions. These
// extensions need a file browser extension to give them permissions to access
// files. This also includes file handler extensions in filesystem API.
// - Observing directory changes from a file browser extension (using
// fileManagerPrivate API).
// - Doing searches on drive file system from file browser extension (using
// fileManagerPrivate API).
using drive::DriveIntegrationServiceFactory;
using extensions::Extension;
namespace file_manager {
namespace {
// Root dirs for file systems expected by the test extensions.
// NOTE: Root dir for drive file system is set by Chrome's drive implementation,
// but the test will have to make sure the mount point is added before
// starting a test extension using WaitUntilDriveMountPointIsAdded().
constexpr char kLocalMountPointName[] = "local";
constexpr char kRestrictedMountPointName[] = "restricted";
// Default file content for the test files.
constexpr char kTestFileContent[] = "This is some test content.";
// User account email and directory hash for secondary account for multi-profile
// sensitive test cases.
constexpr char kSecondProfileAccount[] = "profile2@test.com";
constexpr char kSecondProfileGiaId[] = "9876543210";
constexpr char kSecondProfileHash[] = "fileBrowserApiTestProfile2";
class FakeSelectFileDialog : public ui::SelectFileDialog {
public:
FakeSelectFileDialog(ui::SelectFileDialog::Listener* listener,
std::unique_ptr<ui::SelectFilePolicy> policy,
const base::FilePath& drivefs_root)
: ui::SelectFileDialog(listener, std::move(policy)),
drivefs_root_(drivefs_root) {}
void SelectFileImpl(Type type,
const std::u16string& title,
const base::FilePath& default_path,
const FileTypeInfo* file_types,
int file_type_index,
const base::FilePath::StringType& default_extension,
gfx::NativeWindow owning_window,
void* params) override {
listener_->FileSelected(drivefs_root_.Append("root/test_dir"), 0, nullptr);
}
bool IsRunning(gfx::NativeWindow owning_window) const override {
return false;
}
void ListenerDestroyed() override {}
bool HasMultipleFileTypeChoicesImpl() override { return false; }
private:
~FakeSelectFileDialog() override = default;
const base::FilePath drivefs_root_;
};
class FakeSelectFileDialogFactory : public ui::SelectFileDialogFactory {
public:
explicit FakeSelectFileDialogFactory(const base::FilePath& drivefs_root)
: drivefs_root_(drivefs_root) {}
private:
ui::SelectFileDialog* Create(
ui::SelectFileDialog::Listener* listener,
std::unique_ptr<ui::SelectFilePolicy> policy) override {
return new FakeSelectFileDialog(listener, std::move(policy), drivefs_root_);
}
const base::FilePath drivefs_root_;
};
// Waits for a WebContents of the background page of the extension under test
// to load, then injects some javascript into it to trigger a particular test.
class JSTestStarter : public content::TestNavigationObserver {
public:
explicit JSTestStarter(const std::string& test_name)
: TestNavigationObserver(GetUrlToWatch()), test_name_(test_name) {
WatchExistingWebContents();
StartWatchingNewWebContents();
}
static GURL GetUrlToWatch() {
// Use the chrome-extension:// ID corresponding to the key used in the app
// manifests for tests in this file. An improvement to this would use the ID
// of the extension from LoadExtensionAsComponentWithManifest(), but that's
// potentially racy.
return GURL(
"chrome-extension://pkplfbidichfdicaijlchgnapepdginl/"
"_generated_background_page.html");
}
// TestNavigationObserver:
void OnDidFinishNavigation(
content::NavigationHandle* navigation_handle) override {
// If the background page scripts have run, the test will exist, so just run
// it. Otherwise, schedule the test to be run at the end of the background
// page script.
constexpr char kScript[] = R"(
if (self.$1) {
chrome.test.runTests([$1])
} else {
self.testNameToRun = '$1';
}
)";
ASSERT_TRUE(content::ExecuteScript(
navigation_handle->GetRenderFrameHost(),
base::ReplaceStringPlaceholders(kScript, {test_name_}, nullptr)));
TestNavigationObserver::OnDidFinishNavigation(navigation_handle);
}
private:
const std::string test_name_;
};
bool TouchFile(const base::FilePath& path,
base::StringPiece mtime_string,
base::StringPiece atime_string) {
base::Time mtime, atime;
auto result = base::Time::FromString(mtime_string.data(), &mtime) &&
base::Time::FromString(atime_string.data(), &atime) &&
base::TouchFile(path, atime, mtime);
return result;
}
// Configuration of a file residing in a "test_dir" of a created volume.
// If contents is null, creates a subdirectory.
struct TestDirConfig {
const char* mtime;
const char* atime;
const char* name;
const char* contents = kTestFileContent;
};
// An arbitrary time, for tests that don't care.
constexpr const char kArbitraryTime[] = "2011-04-03T11:11:10.000Z";
// The default configuration of entries in "test_dir" used in test harnesses.
constexpr const TestDirConfig kDefaultDirConfig[] = {
{"2011-11-02T04:00:00.000Z", "2011-11-02T04:00:00.000Z", "empty_dir",
nullptr},
{"2011-04-01T18:34:08.234Z", "2012-01-02T00:00:01.000Z", "subdir", nullptr},
{"2011-12-14T00:40:47.330Z", "2012-01-02T00:00:00.000Z", "test_file.xul"},
{"2012-01-01T10:00:30.000Z", "2012-01-01T00:00:00.000Z",
"test_file.xul.foo"},
{"2011-04-03T11:11:10.000Z", "2012-01-02T00:00:00.000Z", "test_file.tiff"},
{"2011-12-14T00:40:47.330Z", "2010-01-02T00:00:00.000Z",
"test_file.tiff.foo"},
{"2011-12-14T00:40:47.330Z", "2011-12-14T00:40:47.330Z", "empty_file.foo",
""},
};
// Sets up the initial file system state for native local and restricted native
// local file systems. The hierarchy is the same as for the drive file system.
// The directory is created at unique_temp_dir/|mount_point_name| path.
bool InitializeLocalFileSystem(std::string mount_point_name,
base::ScopedTempDir* tmp_dir,
base::FilePath* mount_point_dir,
const std::vector<TestDirConfig>& dir_contents) {
if (!tmp_dir->CreateUniqueTempDir())
return false;
*mount_point_dir = tmp_dir->GetPath().AppendASCII(mount_point_name);
// Create the mount point.
if (!base::CreateDirectory(*mount_point_dir))
return false;
constexpr TestDirConfig kTestDir = {"2012-01-02T00:00:00.000Z",
"2012-01-02T00:00:01.000Z", "test_dir",
nullptr};
const base::FilePath test_dir = mount_point_dir->AppendASCII(kTestDir.name);
if (!base::CreateDirectory(test_dir))
return false;
for (const auto& file : dir_contents) {
const base::FilePath test_path = test_dir.AppendASCII(file.name);
if (file.contents) {
if (!google_apis::test_util::WriteStringToFile(test_path, file.contents))
return false;
} else {
if (!base::CreateDirectory(test_path))
return false;
}
}
for (const auto& file : dir_contents) {
if (!TouchFile(test_dir.Append(file.name), file.mtime, file.atime))
return false;
}
// Touch the directory holding all the contents last.
return TouchFile(test_dir, kTestDir.mtime, kTestDir.atime);
}
// Helper class to wait for a background page to load or close again.
class BackgroundObserver {
public:
BackgroundObserver()
: page_created_(extensions::NOTIFICATION_EXTENSION_BACKGROUND_PAGE_READY,
content::NotificationService::AllSources()),
page_closed_(extensions::NOTIFICATION_EXTENSION_HOST_DESTROYED,
content::NotificationService::AllSources()) {}
void WaitUntilLoaded() {
page_created_.Wait();
}
void WaitUntilClosed() {
page_closed_.Wait();
}
private:
content::WindowedNotificationObserver page_created_;
content::WindowedNotificationObserver page_closed_;
};
// Base class for FileSystemExtensionApi tests.
class FileSystemExtensionApiTestBase : public extensions::ExtensionApiTest {
public:
enum Flags {
FLAGS_NONE = 0,
FLAGS_USE_FILE_HANDLER = 1 << 1,
FLAGS_LAZY_FILE_HANDLER = 1 << 2
};
FileSystemExtensionApiTestBase() = default;
~FileSystemExtensionApiTestBase() override = default;
virtual std::vector<TestDirConfig> GetTestDirContents() {
return {std::begin(kDefaultDirConfig), std::end(kDefaultDirConfig)};
}
bool SetUpUserDataDirectory() override {
return drive::SetUpUserDataDirectoryForDriveFsTest();
}
void SetUp() override {
InitTestFileSystem();
extensions::ExtensionApiTest::SetUp();
}
void SetUpOnMainThread() override {
AddTestMountPoint();
// Mock the Media Router in extension api tests. Dispatches to the message
// loop now try to handle mojo messages that will call back into Profile
// creation through the media router, which then confuse the drive code.
media_router_ = std::make_unique<media_router::MockMediaRouter>();
ON_CALL(*media_router_, RegisterMediaSinksObserver(testing::_))
.WillByDefault(testing::Return(true));
CastConfigControllerMediaRouter::SetMediaRouterForTest(media_router_.get());
extensions::ExtensionApiTest::SetUpOnMainThread();
}
void TearDownOnMainThread() override {
CastConfigControllerMediaRouter::SetMediaRouterForTest(nullptr);
extensions::ExtensionApiTest::TearDownOnMainThread();
}
// Runs a file system extension API test.
// It loads test component extension at |filebrowser_path| with manifest
// at |filebrowser_manifest|. The |filebrowser_manifest| should be a path
// relative to |filebrowser_path|. The method waits until the test extension
// sends test succeed or fail message. It returns true if the test succeeds.
// If |FLAGS_USE_FILE_HANDLER| flag is set, the file handler extension at path
// |filehandler_path| will be loaded before the file browser extension.
// If the flag FLAGS_LAZY_FILE_HANDLER is set, the file handler extension must
// not have persistent background page. The test will wait until the file
// handler's background page is closed after initial load before the file
// browser extension is loaded.
// If |RunFileSystemExtensionApiTest| fails, |message_| will contain a failure
// message.
bool RunFileSystemExtensionApiTest(
const std::string& filebrowser_path,
const base::FilePath::CharType* filebrowser_manifest,
const std::string& filehandler_path,
int flags) {
if (flags & FLAGS_USE_FILE_HANDLER) {
if (filehandler_path.empty()) {
message_ = "Missing file handler path.";
return false;
}
if (flags & FLAGS_LAZY_FILE_HANDLER) {
// Ensures the file handler extension's background page closes in a
// timely manner to avoid test timeouts.
extensions::ProcessManager::SetEventPageIdleTimeForTesting(1);
}
BackgroundObserver page_complete;
const Extension* file_handler =
LoadExtension(test_data_dir_.AppendASCII(filehandler_path));
if (!file_handler) {
message_ = "Error loading file handler extension";
return false;
}
if (flags & FLAGS_LAZY_FILE_HANDLER) {
page_complete.WaitUntilClosed();
} else {
page_complete.WaitUntilLoaded();
}
}
extensions::ResultCatcher catcher;
const Extension* file_browser = LoadExtensionAsComponentWithManifest(
test_data_dir_.AppendASCII(filebrowser_path),
filebrowser_manifest);
if (!file_browser) {
message_ = "Could not create file browser";
return false;
}
if (!catcher.GetNextResult()) {
message_ = catcher.message();
return false;
}
return true;
}
// Starts the app in |app_folder| then triggers the |test_name| on the
// background page using JSTestStarter. Does not configure a file handler app.
bool RunBackgroundPageTestCase(const std::string& app_folder,
const std::string& test_name) {
JSTestStarter starter(test_name);
return RunFileSystemExtensionApiTest("file_browser/" + app_folder,
FILE_PATH_LITERAL("manifest.json"),
std::string(), FLAGS_NONE);
}
protected:
// Sets up initial test file system hierarchy.
virtual void InitTestFileSystem() = 0;
// Registers mount point used in the test.
virtual void AddTestMountPoint() = 0;
private:
std::unique_ptr<media_router::MockMediaRouter> media_router_;
DISALLOW_COPY_AND_ASSIGN(FileSystemExtensionApiTestBase);
};
// Tests for a native local file system.
class LocalFileSystemExtensionApiTest : public FileSystemExtensionApiTestBase {
public:
LocalFileSystemExtensionApiTest() = default;
~LocalFileSystemExtensionApiTest() override = default;
// FileSystemExtensionApiTestBase override.
void InitTestFileSystem() override {
ASSERT_TRUE(InitializeLocalFileSystem(kLocalMountPointName, &tmp_dir_,
&mount_point_dir_,
GetTestDirContents()))
<< "Failed to initialize file system.";
}
// FileSystemExtensionApiTestBase override.
void AddTestMountPoint() override {
EXPECT_TRUE(profile()->GetMountPoints()->RegisterFileSystem(
kLocalMountPointName, storage::kFileSystemTypeLocal,
storage::FileSystemMountOption(), mount_point_dir_));
VolumeManager::Get(profile())->AddVolumeForTesting(
mount_point_dir_, VOLUME_TYPE_TESTING, chromeos::DEVICE_TYPE_UNKNOWN,
false /* read_only */);
}
private:
base::ScopedTempDir tmp_dir_;
base::FilePath mount_point_dir_;
};
// Tests for restricted native local file systems.
class RestrictedFileSystemExtensionApiTest
: public FileSystemExtensionApiTestBase {
public:
RestrictedFileSystemExtensionApiTest() = default;
~RestrictedFileSystemExtensionApiTest() override = default;
// FileSystemExtensionApiTestBase override.
void InitTestFileSystem() override {
ASSERT_TRUE(InitializeLocalFileSystem(kRestrictedMountPointName, &tmp_dir_,
&mount_point_dir_,
GetTestDirContents()))
<< "Failed to initialize file system.";
}
// FileSystemExtensionApiTestBase override.
void AddTestMountPoint() override {
EXPECT_TRUE(profile()->GetMountPoints()->RegisterFileSystem(
kRestrictedMountPointName, storage::kFileSystemTypeRestrictedLocal,
storage::FileSystemMountOption(), mount_point_dir_));
VolumeManager::Get(profile())->AddVolumeForTesting(
mount_point_dir_, VOLUME_TYPE_TESTING, chromeos::DEVICE_TYPE_UNKNOWN,
true /* read_only */);
}
private:
base::ScopedTempDir tmp_dir_;
base::FilePath mount_point_dir_;
};
// Tests for a drive file system.
class DriveFileSystemExtensionApiTest : public FileSystemExtensionApiTestBase {
public:
DriveFileSystemExtensionApiTest() = default;
~DriveFileSystemExtensionApiTest() override = default;
// FileSystemExtensionApiTestBase override.
void InitTestFileSystem() override {
// Set up cache root to be used by DriveIntegrationService. This has to be
// done before the browser is created because the service instance is
// initialized by EventRouter.
ASSERT_TRUE(test_cache_root_.CreateUniqueTempDir());
// This callback will get called during Profile creation.
create_drive_integration_service_ = base::BindRepeating(
&DriveFileSystemExtensionApiTest::CreateDriveIntegrationService,
base::Unretained(this));
service_factory_for_test_ =
std::make_unique<DriveIntegrationServiceFactory::ScopedFactoryForTest>(
&create_drive_integration_service_);
}
// FileSystemExtensionApiTestBase override.
void AddTestMountPoint() override {
test_util::WaitUntilDriveMountPointIsAdded(profile());
}
// FileSystemExtensionApiTestBase override.
void TearDown() override {
FileSystemExtensionApiTestBase::TearDown();
ui::SelectFileDialog::SetFactory(nullptr);
}
protected:
// DriveIntegrationService factory function for this test.
drive::DriveIntegrationService* CreateDriveIntegrationService(
Profile* profile) {
// Ignore signin and lock screen apps profile.
if (profile->GetPath() == chromeos::ProfileHelper::GetSigninProfileDir() ||
profile->GetPath() ==
chromeos::ProfileHelper::GetLockScreenAppProfilePath()) {
return nullptr;
}
// DriveFileSystemExtensionApiTest doesn't expect that several user profiles
// could exist simultaneously.
base::FilePath drivefs_mount_point;
InitializeLocalFileSystem("drive-user/root", &drivefs_root_,
&drivefs_mount_point, GetTestDirContents());
fake_drivefs_helper_ = std::make_unique<drive::FakeDriveFsHelper>(
profile, drivefs_mount_point.DirName());
return new drive::DriveIntegrationService(
profile, "", test_cache_root_.GetPath(),
fake_drivefs_helper_->CreateFakeDriveFsListenerFactory());
}
base::ScopedTempDir test_cache_root_;
base::ScopedTempDir drivefs_root_;
std::unique_ptr<drive::FakeDriveFsHelper> fake_drivefs_helper_;
DriveIntegrationServiceFactory::FactoryCallback
create_drive_integration_service_;
std::unique_ptr<DriveIntegrationServiceFactory::ScopedFactoryForTest>
service_factory_for_test_;
};
// Tests for Drive file systems in multi-profile setting.
class MultiProfileDriveFileSystemExtensionApiTest :
public FileSystemExtensionApiTestBase {
public:
MultiProfileDriveFileSystemExtensionApiTest() = default;
void SetUpCommandLine(base::CommandLine* command_line) override {
FileSystemExtensionApiTestBase::SetUpCommandLine(command_line);
// Don't require policy for our sessions - this is required because
// this test creates a secondary profile synchronously, so we need to
// let the policy code know not to expect cached policy.
command_line->AppendSwitchASCII(chromeos::switches::kProfileRequiresPolicy,
"false");
}
void SetUpOnMainThread() override {
base::FilePath user_data_directory;
base::PathService::Get(chrome::DIR_USER_DATA, &user_data_directory);
session_manager::SessionManager::Get()->CreateSession(
AccountId::FromUserEmailGaiaId(kSecondProfileAccount,
kSecondProfileGiaId),
kSecondProfileHash, false);
// Set up the secondary profile.
base::FilePath profile_dir =
user_data_directory.Append(
chromeos::ProfileHelper::GetUserProfileDir(
kSecondProfileHash).BaseName());
second_profile_ =
g_browser_process->profile_manager()->GetProfile(profile_dir);
FileSystemExtensionApiTestBase::SetUpOnMainThread();
}
void InitTestFileSystem() override {
ASSERT_TRUE(tmp_dir_.CreateUniqueTempDir());
// This callback will get called during Profile creation.
create_drive_integration_service_ =
base::BindRepeating(&MultiProfileDriveFileSystemExtensionApiTest::
CreateDriveIntegrationService,
base::Unretained(this));
service_factory_for_test_ =
std::make_unique<DriveIntegrationServiceFactory::ScopedFactoryForTest>(
&create_drive_integration_service_);
}
void AddTestMountPoint() override {
test_util::WaitUntilDriveMountPointIsAdded(profile());
test_util::WaitUntilDriveMountPointIsAdded(second_profile_);
}
protected:
// DriveIntegrationService factory function for this test.
drive::DriveIntegrationService* CreateDriveIntegrationService(
Profile* profile) {
// Ignore signin and lock screen apps profile.
if (profile->GetPath() == chromeos::ProfileHelper::GetSigninProfileDir() ||
profile->GetPath() ==
chromeos::ProfileHelper::GetLockScreenAppProfilePath()) {
return nullptr;
}
base::FilePath cache_dir;
base::CreateTemporaryDirInDir(tmp_dir_.GetPath(),
base::FilePath::StringType(), &cache_dir);
base::FilePath drivefs_dir;
base::CreateTemporaryDirInDir(tmp_dir_.GetPath(),
base::FilePath::StringType(), &drivefs_dir);
auto profile_name_storage = profile->GetBaseName().value();
base::StringPiece profile_name = profile_name_storage;
if (base::StartsWith(profile_name, "u-")) {
profile_name = profile_name.substr(2);
}
drivefs_dir = drivefs_dir.Append(base::StrCat({"drive-", profile_name}));
auto test_dir = drivefs_dir.Append("root/test_dir");
CHECK(base::CreateDirectory(test_dir));
CHECK(google_apis::test_util::WriteStringToFile(
test_dir.AppendASCII("test_file.tiff"), kTestFileContent));
CHECK(google_apis::test_util::WriteStringToFile(
test_dir.AppendASCII("hosted_doc.gdoc"), kTestFileContent));
const auto& drivefs_helper = fake_drivefs_helpers_[profile] =
std::make_unique<drive::FakeDriveFsHelper>(profile, drivefs_dir);
return new drive::DriveIntegrationService(
profile, std::string(), cache_dir,
drivefs_helper->CreateFakeDriveFsListenerFactory());
}
base::ScopedTempDir tmp_dir_;
DriveIntegrationServiceFactory::FactoryCallback
create_drive_integration_service_;
std::unique_ptr<DriveIntegrationServiceFactory::ScopedFactoryForTest>
service_factory_for_test_;
Profile* second_profile_ = nullptr;
std::unordered_map<Profile*, std::unique_ptr<drive::FakeDriveFsHelper>>
fake_drivefs_helpers_;
};
class LocalAndDriveFileSystemExtensionApiTest
: public FileSystemExtensionApiTestBase {
public:
LocalAndDriveFileSystemExtensionApiTest() = default;
~LocalAndDriveFileSystemExtensionApiTest() override = default;
// FileSystemExtensionApiTestBase override.
void InitTestFileSystem() override {
ASSERT_TRUE(InitializeLocalFileSystem(kLocalMountPointName, &local_tmp_dir_,
&local_mount_point_dir_,
GetTestDirContents()))
<< "Failed to initialize file system.";
// Set up cache root to be used by DriveIntegrationService. This has to be
// done before the browser is created because the service instance is
// initialized by EventRouter.
ASSERT_TRUE(test_cache_root_.CreateUniqueTempDir());
// This callback will get called during Profile creation.
create_drive_integration_service_ = base::BindRepeating(
&LocalAndDriveFileSystemExtensionApiTest::CreateDriveIntegrationService,
base::Unretained(this));
service_factory_for_test_ =
std::make_unique<DriveIntegrationServiceFactory::ScopedFactoryForTest>(
&create_drive_integration_service_);
}
// FileSystemExtensionApiTestBase override.
void AddTestMountPoint() override {
EXPECT_TRUE(profile()->GetMountPoints()->RegisterFileSystem(
kLocalMountPointName, storage::kFileSystemTypeLocal,
storage::FileSystemMountOption(), local_mount_point_dir_));
VolumeManager::Get(profile())->AddVolumeForTesting(
local_mount_point_dir_, VOLUME_TYPE_TESTING,
chromeos::DEVICE_TYPE_UNKNOWN, false /* read_only */);
test_util::WaitUntilDriveMountPointIsAdded(profile());
}
protected:
// DriveIntegrationService factory function for this test.
drive::DriveIntegrationService* CreateDriveIntegrationService(
Profile* profile) {
// Ignore signin and lock screen apps profile.
if (profile->GetPath() == chromeos::ProfileHelper::GetSigninProfileDir() ||
profile->GetPath() ==
chromeos::ProfileHelper::GetLockScreenAppProfilePath()) {
return nullptr;
}
// LocalAndDriveFileSystemExtensionApiTest doesn't expect that several user
// profiles could exist simultaneously.
base::FilePath drivefs_mount_point;
InitializeLocalFileSystem("drive-user/root", &drivefs_root_,
&drivefs_mount_point, GetTestDirContents());
fake_drivefs_helper_ = std::make_unique<drive::FakeDriveFsHelper>(
profile, drivefs_mount_point.DirName());
return new drive::DriveIntegrationService(
profile, "", test_cache_root_.GetPath(),
fake_drivefs_helper_->CreateFakeDriveFsListenerFactory());
}
private:
// For local volume.
base::ScopedTempDir local_tmp_dir_;
base::FilePath local_mount_point_dir_;
// For drive volume.
base::ScopedTempDir test_cache_root_;
base::ScopedTempDir drivefs_root_;
std::unique_ptr<drive::FakeDriveFsHelper> fake_drivefs_helper_;
DriveIntegrationServiceFactory::FactoryCallback
create_drive_integration_service_;
std::unique_ptr<DriveIntegrationServiceFactory::ScopedFactoryForTest>
service_factory_for_test_;
};
// Mixin for starting one of the FileSystem test fixures with a specific app
// configuration, which may include default-installed apps. Currently set up
// to run with the chrome://media-app.
class FileSystemExtensionApiTestWithApps
: public LocalFileSystemExtensionApiTest {
public:
FileSystemExtensionApiTestWithApps() {}
// FileManagerPrivateApiTest:
void SetUpOnMainThread() override {
Profile* profile = browser()->profile();
file_manager::test::AddDefaultComponentExtensionsOnMainThread(profile);
web_app::WebAppProvider::Get(profile)
->system_web_app_manager()
.InstallSystemAppsForTesting();
LocalFileSystemExtensionApiTest::SetUpOnMainThread();
}
std::vector<TestDirConfig> GetTestDirContents() override {
return {{kArbitraryTime, kArbitraryTime, "test_file.png"},
{kArbitraryTime, kArbitraryTime, "test_file.arw"}};
}
};
namespace {
// Constants from app_service_metrics.cc.
constexpr int kGalleryUmaBucket = 13;
constexpr int kMediaAppUmaBucket = 19;
// Metric recorded as the result of the call to apps::RecordAppLaunch().
constexpr char kAppLaunchMetric[] = "Apps.DefaultAppLaunch.FromFileManager";
} // namespace
// Check the interception of ExecuteTask calls to replace Gallery for PNGs. The
// Media App should always be used in this case.
IN_PROC_BROWSER_TEST_F(FileSystemExtensionApiTestWithApps, OpenGalleryForPng) {
base::HistogramTester histogram_tester;
EXPECT_TRUE(RunBackgroundPageTestCase("open_gallery",
"testPngOpensGalleryReturnsOpened"))
<< message_;
histogram_tester.ExpectBucketCount(kAppLaunchMetric, kGalleryUmaBucket, 0);
histogram_tester.ExpectBucketCount(kAppLaunchMetric, kMediaAppUmaBucket, 1);
}
//
// LocalFileSystemExtensionApiTests.
//
IN_PROC_BROWSER_TEST_F(LocalFileSystemExtensionApiTest,
DISABLED_FileSystemOperations) {
EXPECT_TRUE(RunFileSystemExtensionApiTest(
"file_browser/filesystem_operations_test",
FILE_PATH_LITERAL("manifest.json"),
"",
FLAGS_NONE)) << message_;
}
IN_PROC_BROWSER_TEST_F(LocalFileSystemExtensionApiTest, FileWatch) {
EXPECT_TRUE(RunFileSystemExtensionApiTest(
"file_browser/file_watcher_test",
FILE_PATH_LITERAL("manifest.json"),
"",
FLAGS_NONE)) << message_;
}
IN_PROC_BROWSER_TEST_F(LocalFileSystemExtensionApiTest, FileBrowserHandlers) {
EXPECT_TRUE(RunFileSystemExtensionApiTest(
"file_browser/handler_test_runner",
FILE_PATH_LITERAL("manifest.json"),
"file_browser/file_browser_handler",
FLAGS_USE_FILE_HANDLER)) << message_;
}
IN_PROC_BROWSER_TEST_F(LocalFileSystemExtensionApiTest,
FileBrowserHandlersLazy) {
EXPECT_TRUE(RunFileSystemExtensionApiTest(
"file_browser/handler_test_runner",
FILE_PATH_LITERAL("manifest.json"),
"file_browser/file_browser_handler_lazy",
FLAGS_USE_FILE_HANDLER | FLAGS_LAZY_FILE_HANDLER)) << message_;
}
IN_PROC_BROWSER_TEST_F(LocalFileSystemExtensionApiTest, AppFileHandler) {
EXPECT_TRUE(RunFileSystemExtensionApiTest(
"file_browser/handler_test_runner",
FILE_PATH_LITERAL("manifest.json"),
"file_browser/app_file_handler",
FLAGS_USE_FILE_HANDLER)) << message_;
}
IN_PROC_BROWSER_TEST_F(LocalFileSystemExtensionApiTest, DefaultFileHandler) {
EXPECT_TRUE(RunFileSystemExtensionApiTest("file_browser/default_file_handler",
FILE_PATH_LITERAL("manifest.json"),
"", FLAGS_NONE))
<< message_;
}
//
// RestrictedFileSystemExtensionApiTests.
//
IN_PROC_BROWSER_TEST_F(RestrictedFileSystemExtensionApiTest,
FileSystemOperations) {
EXPECT_TRUE(RunFileSystemExtensionApiTest(
"file_browser/filesystem_operations_test",
FILE_PATH_LITERAL("manifest.json"),
"",
FLAGS_NONE)) << message_;
}
//
// DriveFileSystemExtensionApiTests.
//
// This test is flaky. See https://crbug.com/1008880.
IN_PROC_BROWSER_TEST_F(DriveFileSystemExtensionApiTest,
DISABLED_FileSystemOperations) {
EXPECT_TRUE(RunFileSystemExtensionApiTest(
"file_browser/filesystem_operations_test",
FILE_PATH_LITERAL("manifest.json"),
"",
FLAGS_NONE)) << message_;
}
IN_PROC_BROWSER_TEST_F(DriveFileSystemExtensionApiTest, FileWatch) {
EXPECT_TRUE(RunFileSystemExtensionApiTest(
"file_browser/file_watcher_test",
FILE_PATH_LITERAL("manifest.json"),
"",
FLAGS_NONE)) << message_;
}
IN_PROC_BROWSER_TEST_F(DriveFileSystemExtensionApiTest, FileBrowserHandlers) {
EXPECT_TRUE(RunFileSystemExtensionApiTest(
"file_browser/handler_test_runner",
FILE_PATH_LITERAL("manifest.json"),
"file_browser/file_browser_handler",
FLAGS_USE_FILE_HANDLER)) << message_;
}
IN_PROC_BROWSER_TEST_F(DriveFileSystemExtensionApiTest, Search) {
// Configure the drive service to return only one search result at a time
// to simulate paginated searches.
EXPECT_TRUE(RunFileSystemExtensionApiTest(
"file_browser/drive_search_test",
FILE_PATH_LITERAL("manifest.json"),
"",
FLAGS_NONE)) << message_;
}
IN_PROC_BROWSER_TEST_F(DriveFileSystemExtensionApiTest, AppFileHandler) {
EXPECT_TRUE(RunFileSystemExtensionApiTest(
"file_browser/handler_test_runner",
FILE_PATH_LITERAL("manifest.json"),
"file_browser/app_file_handler",
FLAGS_USE_FILE_HANDLER)) << message_;
}
IN_PROC_BROWSER_TEST_F(DriveFileSystemExtensionApiTest, RetainEntry) {
ui::SelectFileDialog::SetFactory(new FakeSelectFileDialogFactory(
drivefs_root_.GetPath().Append("drive-user")));
EXPECT_TRUE(RunFileSystemExtensionApiTest("file_browser/retain_entry",
FILE_PATH_LITERAL("manifest.json"),
"",
FLAGS_NONE))
<< message_;
}
IN_PROC_BROWSER_TEST_F(MultiProfileDriveFileSystemExtensionApiTest,
CrossProfileCopy) {
EXPECT_TRUE(RunFileSystemExtensionApiTest(
"file_browser/multi_profile_copy",
FILE_PATH_LITERAL("manifest.json"),
"",
FLAGS_NONE)) << message_;
}
//
// LocalAndDriveFileSystemExtensionApiTests.
IN_PROC_BROWSER_TEST_F(LocalAndDriveFileSystemExtensionApiTest,
AppFileHandlerMulti) {
EXPECT_TRUE(
RunFileSystemExtensionApiTest("file_browser/app_file_handler_multi",
FILE_PATH_LITERAL("manifest.json"),
"",
FLAGS_NONE))
<< message_;
}
} // namespace
} // namespace file_manager