blob: de392c07a824f34db5d03c080fab21f8c393cbc0 [file] [log] [blame]
// Copyright 2016 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 <algorithm>
#include <string>
#include <vector>
#include "base/base_switches.h"
#include "base/bind.h"
#include "base/callback.h"
#include "base/command_line.h"
#include "base/files/file_util.h"
#include "base/path_service.h"
#include "base/run_loop.h"
#include "base/strings/string_util.h"
#include "base/test/test_file_util.h"
#include "base/threading/thread_restrictions.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/profiles/profile_window.h"
#include "chrome/browser/signin/signin_util.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/user_manager.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "chrome/test/base/testing_browser_process.h"
#include "content/public/test/test_launcher.h"
namespace {
void UnblockOnProfileCreation(Profile::CreateStatus expected_final_status,
const base::Closure& quit_closure,
Profile* profile,
Profile::CreateStatus status) {
// If the status is CREATE_STATUS_CREATED, then the function will be called
// again with CREATE_STATUS_INITIALIZED.
if (status == Profile::CREATE_STATUS_CREATED)
return;
EXPECT_EQ(expected_final_status, status);
quit_closure.Run();
}
void UnblockOnProfileInitialized(const base::Closure& quit_closure,
Profile* profile,
Profile::CreateStatus status) {
UnblockOnProfileCreation(Profile::CREATE_STATUS_INITIALIZED, quit_closure,
profile, status);
}
void OnCloseAllBrowsersSucceeded(const base::Closure& quit_closure,
const base::FilePath& path) {
quit_closure.Run();
}
void CreateAndSwitchToProfile(const std::string& basepath) {
ProfileManager* profile_manager = g_browser_process->profile_manager();
ASSERT_TRUE(profile_manager);
base::FilePath path = profile_manager->user_data_dir().AppendASCII(basepath);
base::RunLoop run_loop;
profile_manager->CreateProfileAsync(
path, base::Bind(&UnblockOnProfileInitialized, run_loop.QuitClosure()),
base::string16(), std::string());
// Run the message loop to allow profile creation to take place; the loop is
// terminated by UnblockOnProfileCreation when the profile is created.
run_loop.Run();
profiles::SwitchToProfile(path, false, ProfileManager::CreateCallback(),
ProfileMetrics::SWITCH_PROFILE_ICON);
}
void CheckBrowserWindows(const std::vector<std::string>& expected_basepaths) {
std::vector<std::string> actual_basepaths;
for (const Browser* browser : *BrowserList::GetInstance()) {
actual_basepaths.push_back(
browser->profile()->GetPath().BaseName().AsUTF8Unsafe());
}
if (actual_basepaths.size() != expected_basepaths.size() ||
!std::is_permutation(actual_basepaths.cbegin(), actual_basepaths.cend(),
expected_basepaths.cbegin())) {
ADD_FAILURE()
<< "Expected profile paths are different from actual profile paths."
"\n Actual profile paths: "
<< base::JoinString(actual_basepaths, ", ")
<< "\n Expected profile paths: "
<< base::JoinString(expected_basepaths, ", ");
}
}
void ExpectUserManagerToShow() {
// If the user manager is not shown yet, wait for the user manager to appear.
if (!UserManager::IsShowing()) {
base::RunLoop run_loop;
UserManager::AddOnUserManagerShownCallbackForTesting(
run_loop.QuitClosure());
run_loop.Run();
}
ASSERT_TRUE(UserManager::IsShowing());
// We must hide the user manager before the test ends.
UserManager::Hide();
}
} // namespace
class StartupBrowserCreatorCorruptProfileTest : public InProcessBrowserTest {
public:
StartupBrowserCreatorCorruptProfileTest()
: test_body_has_run_(false), expect_test_body_to_run_(true) {}
void SetExpectTestBodyToRun(bool expected_result) {
expect_test_body_to_run_ = expected_result;
}
bool DeleteProfileData(const std::string& basepath) {
base::FilePath user_data_dir;
if (!base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir))
return false;
base::FilePath dir_to_delete = user_data_dir.AppendASCII(basepath);
return base::DirectoryExists(dir_to_delete) &&
base::DeleteFile(dir_to_delete, true);
}
bool RemoveCreateDirectoryPermissionForUserDataDirectory() {
base::FilePath user_data_dir;
return base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir) &&
base::DenyFilePermission(user_data_dir, FILE_ADD_SUBDIRECTORY);
}
protected:
// For each test, declare a bool SetUpUserDataDirectory[testname] function.
bool SetUpUserDataDirectoryForLastOpenedProfileMissing();
bool SetUpUserDataDirectoryForLastUsedProfileFallbackToLastOpenedProfiles();
bool SetUpUserDataDirectoryForLastUsedProfileFallbackToUserManager();
bool SetUpUserDataDirectoryForCannotCreateSystemProfile();
bool SetUpUserDataDirectoryForLastUsedProfileFallbackToAnyProfile();
bool SetUpUserDataDirectoryForLastUsedProfileFallbackFail();
bool SetUpUserDataDirectoryForDoNotStartLockedProfile();
bool SetUpUserDataDirectoryForNoFallbackForUserSelectedProfile();
bool SetUpUserDataDirectoryForDeletedProfileFallbackToUserManager();
void CloseBrowsersSynchronouslyForProfileBasePath(
const std::string& basepath) {
ProfileManager* profile_manager = g_browser_process->profile_manager();
ASSERT_TRUE(profile_manager);
Profile* profile =
profile_manager->GetProfileByPath(
profile_manager->user_data_dir().AppendASCII(basepath));
ASSERT_TRUE(profile);
base::RunLoop run_loop;
BrowserList::GetInstance()->CloseAllBrowsersWithProfile(
profile,
base::Bind(&OnCloseAllBrowsersSucceeded, run_loop.QuitClosure()),
BrowserList::CloseCallback(), false);
}
void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch(switches::kRestoreLastSession);
command_line->AppendSwitch(switches::kNoErrorDialogs);
}
// In this test fixture, SetUpUserDataDirectory must be handled for all
// non-PRE_ tests.
bool SetUpUserDataDirectory() override {
#define SET_UP_USER_DATA_DIRECTORY_FOR(testname) \
if (testing::UnitTest::GetInstance()->current_test_info()->name() == \
std::string(#testname)) {\
return this->SetUpUserDataDirectoryFor ## testname(); \
}
SET_UP_USER_DATA_DIRECTORY_FOR(LastOpenedProfileMissing);
SET_UP_USER_DATA_DIRECTORY_FOR(LastUsedProfileFallbackToLastOpenedProfiles);
SET_UP_USER_DATA_DIRECTORY_FOR(LastUsedProfileFallbackToUserManager);
SET_UP_USER_DATA_DIRECTORY_FOR(CannotCreateSystemProfile);
SET_UP_USER_DATA_DIRECTORY_FOR(LastUsedProfileFallbackToAnyProfile);
SET_UP_USER_DATA_DIRECTORY_FOR(LastUsedProfileFallbackFail);
SET_UP_USER_DATA_DIRECTORY_FOR(DoNotStartLockedProfile);
SET_UP_USER_DATA_DIRECTORY_FOR(NoFallbackForUserSelectedProfile);
SET_UP_USER_DATA_DIRECTORY_FOR(DeletedProfileFallbackToUserManager);
#undef SET_UP_USER_DATA_DIRECTORY_FOR
// If control goes here, it means SetUpUserDataDirectory is not handled.
// This is okay for PRE_ tests, but not acceptable for main tests.
if (content::IsPreTest())
return true;
ADD_FAILURE() << "SetUpUserDataDirectory is not handled by the test.";
return false;
}
void TearDownOnMainThread() override {
test_body_has_run_ = true;
}
void TearDown() override {
EXPECT_EQ(expect_test_body_to_run_, test_body_has_run_);
InProcessBrowserTest::TearDown();
}
private:
bool test_body_has_run_;
bool expect_test_body_to_run_;
DISALLOW_COPY_AND_ASSIGN(StartupBrowserCreatorCorruptProfileTest);
};
// Most of the tests below have three sections:
// (1) PRE_ test, which is used to create profiles. Most of these profiles are
// meant to be opened in (3) during startup.
// (2) StartupBrowserCreatorCorruptProfileTest::SetUpUserDataDirectoryFor...
// which sets up the user data directory, i.e. to remove profile directories
// and to prevent the profile directories from being created again in (3).
// We cannot remove these directories while the browser process is running,
// so that cannot be done during (1) or (3).
// (3) The test itself. With the |kRestoreLastSession| switch set, profiles
// opened in (1) are reopened. However, since the directories of some
// profiles are removed in (2), these profiles are unable to be initialized.
// We are testing whether the correct fallback action is taken.
// LastOpenedProfileMissing : If any last opened profile is missing, that
// profile is skipped, but other last opened profiles should be opened in the
// browser.
IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
PRE_LastOpenedProfileMissing) {
CreateAndSwitchToProfile("Profile 1");
CreateAndSwitchToProfile("Profile 2");
}
bool StartupBrowserCreatorCorruptProfileTest::
SetUpUserDataDirectoryForLastOpenedProfileMissing() {
return DeleteProfileData("Profile 1") &&
RemoveCreateDirectoryPermissionForUserDataDirectory();
}
IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
LastOpenedProfileMissing) {
CheckBrowserWindows({"Default", "Profile 2"});
}
// LastUsedProfileFallbackToLastOpenedProfiles : If the last used profile is
// missing, it should fall back to any last opened profiles.
IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
PRE_LastUsedProfileFallbackToLastOpenedProfiles) {
CreateAndSwitchToProfile("Profile 1");
CreateAndSwitchToProfile("Profile 2");
}
bool StartupBrowserCreatorCorruptProfileTest::
SetUpUserDataDirectoryForLastUsedProfileFallbackToLastOpenedProfiles() {
return DeleteProfileData("Profile 2") &&
RemoveCreateDirectoryPermissionForUserDataDirectory();
}
IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
LastUsedProfileFallbackToLastOpenedProfiles) {
CheckBrowserWindows({"Default", "Profile 1"});
}
// LastUsedProfileFallbackToUserManager : If all last opened profiles are
// missing, it should fall back to user manager. To open the user manager, both
// the guest profile and the system profile must be creatable.
IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
PRE_LastUsedProfileFallbackToUserManager) {
CreateAndSwitchToProfile("Profile 1");
CloseBrowsersSynchronouslyForProfileBasePath("Profile 1");
CreateAndSwitchToProfile("Profile 2");
base::ScopedAllowBlockingForTesting allow_blocking;
ASSERT_TRUE(base::CreateDirectory(ProfileManager::GetGuestProfilePath()));
ASSERT_TRUE(base::CreateDirectory(ProfileManager::GetSystemProfilePath()));
}
bool StartupBrowserCreatorCorruptProfileTest::
SetUpUserDataDirectoryForLastUsedProfileFallbackToUserManager() {
return DeleteProfileData("Default") &&
DeleteProfileData("Profile 2") &&
RemoveCreateDirectoryPermissionForUserDataDirectory();
}
IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
LastUsedProfileFallbackToUserManager) {
CheckBrowserWindows({});
ExpectUserManagerToShow();
}
// CannotCreateSystemProfile : If the system profile cannot be created, the user
// manager should not be shown. Fallback to any other profile.
IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
PRE_CannotCreateSystemProfile) {
CreateAndSwitchToProfile("Profile 1");
CloseBrowsersSynchronouslyForProfileBasePath("Profile 1");
CreateAndSwitchToProfile("Profile 2");
// Create the guest profile path, but not the system profile one. This will
// make it impossible to create the system profile once the permissions are
// locked down during setup.
base::ScopedAllowBlockingForTesting allow_blocking;
ASSERT_TRUE(base::CreateDirectory(ProfileManager::GetGuestProfilePath()));
}
bool StartupBrowserCreatorCorruptProfileTest::
SetUpUserDataDirectoryForCannotCreateSystemProfile() {
return DeleteProfileData("Default") &&
DeleteProfileData("Profile 2") &&
RemoveCreateDirectoryPermissionForUserDataDirectory();
}
IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
CannotCreateSystemProfile) {
CheckBrowserWindows({"Profile 1"});
}
// LastUsedProfileFallbackToAnyProfile : If all the last opened profiles and the
// guest profile cannot be opened, fall back to any profile that is not locked.
IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
PRE_LastUsedProfileFallbackToAnyProfile) {
CreateAndSwitchToProfile("Profile 1");
CloseBrowsersSynchronouslyForProfileBasePath("Profile 1");
CreateAndSwitchToProfile("Profile 2");
}
bool StartupBrowserCreatorCorruptProfileTest::
SetUpUserDataDirectoryForLastUsedProfileFallbackToAnyProfile() {
return DeleteProfileData("Default") &&
DeleteProfileData("Profile 2") &&
RemoveCreateDirectoryPermissionForUserDataDirectory();
}
IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
LastUsedProfileFallbackToAnyProfile) {
CheckBrowserWindows({"Profile 1"});
}
// LastUsedProfileFallbackFail : If no startup option is feasible, the browser
// should quit cleanly.
bool StartupBrowserCreatorCorruptProfileTest::
SetUpUserDataDirectoryForLastUsedProfileFallbackFail() {
SetExpectTestBodyToRun(false);
return RemoveCreateDirectoryPermissionForUserDataDirectory();
}
IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
LastUsedProfileFallbackFail) {
ADD_FAILURE() << "Test body is not expected to run.";
}
// DoNotStartLockedProfile : Profiles that are locked should never be
// initialized. Since there are no unlocked profiles, the browser should not
// start.
IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
PRE_DoNotStartLockedProfile) {
// Lock the default profile. The user manager is shown after the profile is
// locked.
signin_util::SetForceSigninForTesting(true);
profiles::LockProfile(browser()->profile());
ExpectUserManagerToShow();
}
bool StartupBrowserCreatorCorruptProfileTest::
SetUpUserDataDirectoryForDoNotStartLockedProfile() {
SetExpectTestBodyToRun(false);
signin_util::SetForceSigninForTesting(true);
return RemoveCreateDirectoryPermissionForUserDataDirectory();
}
IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
DoNotStartLockedProfile) {
ADD_FAILURE() << "Test body is not expected to run.";
}
// NoFallbackForUserSelectedProfile : No fallback should be attempted if the
// profile is selected by the --profile-directory switch. The browser should not
// start if the specified profile could not be initialized.
IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
PRE_NoFallbackForUserSelectedProfile) {
CreateAndSwitchToProfile("Profile 1");
CreateAndSwitchToProfile("Profile 2");
}
bool StartupBrowserCreatorCorruptProfileTest::
SetUpUserDataDirectoryForNoFallbackForUserSelectedProfile() {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
command_line->AppendSwitchASCII(switches::kProfileDirectory, "Profile 1");
SetExpectTestBodyToRun(false);
return DeleteProfileData("Profile 1") &&
RemoveCreateDirectoryPermissionForUserDataDirectory();
}
IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
NoFallbackForUserSelectedProfile) {
ADD_FAILURE() << "Test body is not expected to run.";
}
// DeletedProfileFallbackToUserManager : If the profile's entry in
// ProfileAttributesStorage is missing, it means the profile is deleted. The
// browser should not attempt to open the profile, but should show the user
// manager instead.
IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
PRE_DeletedProfileFallbackToUserManager) {
base::ScopedAllowBlockingForTesting allow_blocking;
ASSERT_TRUE(base::CreateDirectory(ProfileManager::GetGuestProfilePath()));
ASSERT_TRUE(base::CreateDirectory(ProfileManager::GetSystemProfilePath()));
}
bool StartupBrowserCreatorCorruptProfileTest::
SetUpUserDataDirectoryForDeletedProfileFallbackToUserManager() {
base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
// Simulate a deleted profile by not creating the profile at the first place.
command_line->AppendSwitchASCII(switches::kProfileDirectory, "Not Found");
return RemoveCreateDirectoryPermissionForUserDataDirectory();
}
IN_PROC_BROWSER_TEST_F(StartupBrowserCreatorCorruptProfileTest,
DeletedProfileFallbackToUserManager) {
CheckBrowserWindows({});
ExpectUserManagerToShow();
}