| Index: chrome/browser/ui/startup/startup_browser_creator_corrupt_profiles_browsertest_win.cc
|
| diff --git a/chrome/browser/ui/startup/startup_browser_creator_corrupt_profiles_browsertest_win.cc b/chrome/browser/ui/startup/startup_browser_creator_corrupt_profiles_browsertest_win.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..3c4fe5e46f24aed46d685fb875ec644063999fdc
|
| --- /dev/null
|
| +++ b/chrome/browser/ui/startup/startup_browser_creator_corrupt_profiles_browsertest_win.cc
|
| @@ -0,0 +1,420 @@
|
| +// 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 "chrome/browser/profiles/profile.h"
|
| +#include "chrome/browser/profiles/profile_manager.h"
|
| +#include "chrome/browser/profiles/profile_window.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"
|
| +
|
| +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(), 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 (!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 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()));
|
| + }
|
| +
|
| + 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 (base::StartsWith(
|
| + testing::UnitTest::GetInstance()->current_test_info()->name(),
|
| + "PRE_", base::CompareCase::SENSITIVE)) {
|
| + return true;
|
| + }
|
| +
|
| + ADD_FAILURE() << "SetUpUserDataDirectory is not handled by the test.";
|
| + return false;
|
| + }
|
| +
|
| + void TearDownOnMainThread() override {
|
| + test_body_has_run_ = true;
|
| + InProcessBrowserTest::TearDownOnMainThread();
|
| + }
|
| +
|
| + 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");
|
| +
|
| + 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.
|
| + 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.
|
| + profiles::LockProfile(browser()->profile());
|
| + ExpectUserManagerToShow();
|
| +}
|
| +
|
| +bool StartupBrowserCreatorCorruptProfileTest::
|
| + SetUpUserDataDirectoryForDoNotStartLockedProfile() {
|
| + SetExpectTestBodyToRun(false);
|
| + 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) {
|
| + 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();
|
| +}
|
|
|