Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(8610)

Unified Diff: chrome/browser/ui/startup/startup_browser_creator_corrupt_profiles_browsertest_win.cc

Issue 2047483003: Add fallback behavior if the last used profile cannot initialize (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@bug-614753-fix
Patch Set: Fix a mistake in a comment. (Didn't check Atom reflow output, sorry :-( ) Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/browser/ui/startup/startup_browser_creator.cc ('k') | chrome/chrome_tests.gypi » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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();
+}
« no previous file with comments | « chrome/browser/ui/startup/startup_browser_creator.cc ('k') | chrome/chrome_tests.gypi » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698