// 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 "base/bind.h" #include "base/command_line.h" #include "base/prefs/pref_service.h" #include "base/strings/utf_string_conversions.h" #include "chrome/browser/profiles/profile_info_cache.h" #include "chrome/browser/profiles/profile_info_cache_observer.h" #include "chrome/browser/profiles/profile_manager.h" #include "chrome/browser/profiles/profile_window.h" #include "chrome/browser/profiles/profiles_state.h" #include "chrome/browser/ui/browser_finder.h" #include "chrome/browser/ui/browser_list.h" #include "chrome/browser/ui/browser_window.h" #include "chrome/browser/ui/host_desktop.h" #include "chrome/common/pref_names.h" #include "chrome/test/base/in_process_browser_test.h" #include "chrome/test/base/test_switches.h" #include "chrome/test/base/testing_browser_process.h" #include "chrome/test/base/ui_test_utils.h" #if defined(OS_CHROMEOS) #include "base/path_service.h" #include "chrome/common/chrome_constants.h" #include "chrome/common/chrome_paths.h" #include "chromeos/chromeos_switches.h" #include "testing/gtest/include/gtest/gtest.h" #endif namespace { const profiles::ProfileSwitchingDoneCallback kOnProfileSwitchDoNothing; // An observer that returns back to test code after a new profile is // initialized. void OnUnblockOnProfileCreation(Profile* profile, Profile::CreateStatus status) { if (status == Profile::CREATE_STATUS_INITIALIZED) base::MessageLoop::current()->Quit(); } void ProfileCreationComplete(Profile* profile, Profile::CreateStatus status) { ASSERT_NE(status, Profile::CREATE_STATUS_LOCAL_FAIL); ASSERT_NE(status, Profile::CREATE_STATUS_REMOTE_FAIL); // No browser should have been created for this profile yet. EXPECT_EQ(chrome::GetTotalBrowserCountForProfile(profile), 0U); EXPECT_EQ(chrome::GetTotalBrowserCount(), 1U); if (status == Profile::CREATE_STATUS_INITIALIZED) base::MessageLoop::current()->Quit(); } void EphemeralProfileCreationComplete(Profile* profile, Profile::CreateStatus status) { if (status == Profile::CREATE_STATUS_INITIALIZED) profile->GetPrefs()->SetBoolean(prefs::kForceEphemeralProfiles, true); ProfileCreationComplete(profile, status); } class ProfileRemovalObserver : public ProfileInfoCacheObserver { public: ProfileRemovalObserver() { g_browser_process->profile_manager()->GetProfileInfoCache().AddObserver( this); } virtual ~ProfileRemovalObserver() { g_browser_process->profile_manager()->GetProfileInfoCache().RemoveObserver( this); } std::string last_used_profile_name() { return last_used_profile_name_; } // ProfileInfoCacheObserver overrides: virtual void OnProfileWillBeRemoved( const base::FilePath& profile_path) OVERRIDE { last_used_profile_name_ = g_browser_process->local_state()->GetString( prefs::kProfileLastUsed); } private: std::string last_used_profile_name_; DISALLOW_COPY_AND_ASSIGN(ProfileRemovalObserver); }; } // namespace // This file contains tests for the ProfileManager that require a heavyweight // InProcessBrowserTest. These include tests involving profile deletion. // TODO(jeremy): crbug.com/103355 - These tests should be enabled on all // platforms. class ProfileManagerBrowserTest : public InProcessBrowserTest { protected: virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { #if defined(OS_CHROMEOS) command_line->AppendSwitch( chromeos::switches::kIgnoreUserProfileMappingForTests); #endif } }; #if defined(OS_MACOSX) // Delete single profile and make sure a new one is created. IN_PROC_BROWSER_TEST_F(ProfileManagerBrowserTest, DeleteSingletonProfile) { ProfileManager* profile_manager = g_browser_process->profile_manager(); ProfileInfoCache& cache = profile_manager->GetProfileInfoCache(); ProfileRemovalObserver observer; // We should start out with 1 profile. ASSERT_EQ(cache.GetNumberOfProfiles(), 1U); // Delete singleton profile. base::FilePath singleton_profile_path = cache.GetPathOfProfileAtIndex(0); EXPECT_FALSE(singleton_profile_path.empty()); profile_manager->ScheduleProfileForDeletion(singleton_profile_path, ProfileManager::CreateCallback()); // Spin things till profile is actually deleted. content::RunAllPendingInMessageLoop(); // Make sure a new profile was created automatically. EXPECT_EQ(cache.GetNumberOfProfiles(), 1U); base::FilePath new_profile_path = cache.GetPathOfProfileAtIndex(0); EXPECT_NE(new_profile_path, singleton_profile_path); // Make sure that last used profile preference is set correctly. Profile* last_used = ProfileManager::GetLastUsedProfile(); EXPECT_EQ(new_profile_path, last_used->GetPath()); // Make sure the last used profile was set correctly before the notification // was sent. std::string last_used_profile_name = last_used->GetPath().BaseName().MaybeAsASCII(); EXPECT_EQ(last_used_profile_name, observer.last_used_profile_name()); } // Delete all profiles in a multi profile setup and make sure a new one is // created. // Crashes/CHECKs. See crbug.com/104851 IN_PROC_BROWSER_TEST_F(ProfileManagerBrowserTest, DISABLED_DeleteAllProfiles) { ProfileManager* profile_manager = g_browser_process->profile_manager(); ProfileInfoCache& cache = profile_manager->GetProfileInfoCache(); // Create an additional profile. base::FilePath new_path = profile_manager->GenerateNextProfileDirectoryPath(); profile_manager->CreateProfileAsync(new_path, base::Bind(&OnUnblockOnProfileCreation), base::string16(), base::string16(), std::string()); // Spin to allow profile creation to take place, loop is terminated // by OnUnblockOnProfileCreation when the profile is created. content::RunMessageLoop(); ASSERT_EQ(cache.GetNumberOfProfiles(), 2U); // Delete all profiles. base::FilePath profile_path1 = cache.GetPathOfProfileAtIndex(0); base::FilePath profile_path2 = cache.GetPathOfProfileAtIndex(1); EXPECT_FALSE(profile_path1.empty()); EXPECT_FALSE(profile_path2.empty()); profile_manager->ScheduleProfileForDeletion(profile_path1, ProfileManager::CreateCallback()); profile_manager->ScheduleProfileForDeletion(profile_path2, ProfileManager::CreateCallback()); // Spin things so deletion can take place. content::RunAllPendingInMessageLoop(); // Make sure a new profile was created automatically. EXPECT_EQ(cache.GetNumberOfProfiles(), 1U); base::FilePath new_profile_path = cache.GetPathOfProfileAtIndex(0); EXPECT_NE(new_profile_path, profile_path1); EXPECT_NE(new_profile_path, profile_path2); // Make sure that last used profile preference is set correctly. Profile* last_used = ProfileManager::GetLastUsedProfile(); EXPECT_EQ(new_profile_path, last_used->GetPath()); } #endif // OS_MACOSX #if defined(OS_CHROMEOS) class ProfileManagerCrOSBrowserTest : public ProfileManagerBrowserTest { protected: virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { // Use a user hash other than the default chrome::kTestUserProfileDir // so that the prefix case is tested. command_line->AppendSwitchASCII(chromeos::switches::kLoginProfile, "test-user-hash"); } }; IN_PROC_BROWSER_TEST_F(ProfileManagerCrOSBrowserTest, GetLastUsedProfile) { // Make sure that last used profile is correct. Profile* last_used_profile = ProfileManager::GetLastUsedProfile(); EXPECT_TRUE(last_used_profile != NULL); base::FilePath profile_path; PathService::Get(chrome::DIR_USER_DATA, &profile_path); profile_path = profile_path.AppendASCII( std::string(chrome::kProfileDirPrefix) + "test-user-hash"); EXPECT_EQ(profile_path.value(), last_used_profile->GetPath().value()); } #endif // OS_CHROMEOS // Times out (http://crbug.com/159002) IN_PROC_BROWSER_TEST_F(ProfileManagerBrowserTest, DISABLED_CreateProfileWithCallback) { ProfileManager* profile_manager = g_browser_process->profile_manager(); ASSERT_EQ(profile_manager->GetNumberOfProfiles(), 1U); EXPECT_EQ(chrome::GetTotalBrowserCount(), 1U); // Create a profile, make sure callback is invoked before any callbacks are // invoked (so they can do things like sign in the profile, etc). ProfileManager::CreateMultiProfileAsync( base::string16(), // name base::string16(), // icon url base::Bind(ProfileCreationComplete), std::string()); // Wait for profile to finish loading. content::RunMessageLoop(); EXPECT_EQ(profile_manager->GetNumberOfProfiles(), 2U); EXPECT_EQ(chrome::GetTotalBrowserCount(), 2U); // Now close all browser windows. std::vector<Profile*> profiles = profile_manager->GetLoadedProfiles(); for (std::vector<Profile*>::const_iterator it = profiles.begin(); it != profiles.end(); ++it) { BrowserList::CloseAllBrowsersWithProfile(*it); } } IN_PROC_BROWSER_TEST_F(ProfileManagerBrowserTest, SwitchToProfile) { #if defined(OS_WIN) && defined(USE_ASH) // Disable this test in Metro+Ash for now (http://crbug.com/262796). if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests)) return; #endif // If multiprofile mode is not enabled, you can't switch between profiles. if (!profiles::IsMultipleProfilesEnabled()) return; ProfileManager* profile_manager = g_browser_process->profile_manager(); ProfileInfoCache& cache = profile_manager->GetProfileInfoCache(); base::FilePath path_profile1 = cache.GetPathOfProfileAtIndex(0); ASSERT_EQ(profile_manager->GetNumberOfProfiles(), 1U); EXPECT_EQ(chrome::GetTotalBrowserCount(), 1U); // Create an additional profile. base::FilePath path_profile2 = profile_manager->GenerateNextProfileDirectoryPath(); profile_manager->CreateProfileAsync(path_profile2, base::Bind(&OnUnblockOnProfileCreation), base::string16(), base::string16(), std::string()); // Spin to allow profile creation to take place, loop is terminated // by OnUnblockOnProfileCreation when the profile is created. content::RunMessageLoop(); chrome::HostDesktopType desktop_type = chrome::GetActiveDesktop(); BrowserList* browser_list = BrowserList::GetInstance(desktop_type); ASSERT_EQ(cache.GetNumberOfProfiles(), 2U); EXPECT_EQ(1U, browser_list->size()); // Open a browser window for the first profile. profiles::SwitchToProfile(path_profile1, desktop_type, false, kOnProfileSwitchDoNothing, ProfileMetrics::SWITCH_PROFILE_ICON); EXPECT_EQ(chrome::GetTotalBrowserCount(), 1U); EXPECT_EQ(1U, browser_list->size()); EXPECT_EQ(path_profile1, browser_list->get(0)->profile()->GetPath()); // Open a browser window for the second profile. profiles::SwitchToProfile(path_profile2, desktop_type, false, kOnProfileSwitchDoNothing, ProfileMetrics::SWITCH_PROFILE_ICON); EXPECT_EQ(chrome::GetTotalBrowserCount(), 2U); EXPECT_EQ(2U, browser_list->size()); EXPECT_EQ(path_profile2, browser_list->get(1)->profile()->GetPath()); // Switch to the first profile without opening a new window. profiles::SwitchToProfile(path_profile1, desktop_type, false, kOnProfileSwitchDoNothing, ProfileMetrics::SWITCH_PROFILE_ICON); EXPECT_EQ(chrome::GetTotalBrowserCount(), 2U); EXPECT_EQ(2U, browser_list->size()); EXPECT_EQ(path_profile1, browser_list->get(0)->profile()->GetPath()); EXPECT_EQ(path_profile2, browser_list->get(1)->profile()->GetPath()); } // This test used to be flakily timing out on Windows: http://crbug.com/314905. // If this happens again please make it a MAYBE_ test and reopen that bug. IN_PROC_BROWSER_TEST_F(ProfileManagerBrowserTest, EphemeralProfile) { #if defined(OS_WIN) && defined(USE_ASH) // Disable this test in Metro+Ash for now (http://crbug.com/262796). if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests)) return; #endif // If multiprofile mode is not enabled, you can't switch between profiles. if (!profiles::IsMultipleProfilesEnabled()) return; ProfileManager* profile_manager = g_browser_process->profile_manager(); ProfileInfoCache& cache = profile_manager->GetProfileInfoCache(); base::FilePath path_profile1 = cache.GetPathOfProfileAtIndex(0); ASSERT_EQ(1U, profile_manager->GetNumberOfProfiles()); EXPECT_EQ(1U, chrome::GetTotalBrowserCount()); // Create an ephemeral profile. base::FilePath path_profile2 = profile_manager->GenerateNextProfileDirectoryPath(); profile_manager->CreateProfileAsync( path_profile2, base::Bind(&EphemeralProfileCreationComplete), base::string16(), base::string16(), std::string()); // Spin to allow profile creation to take place. content::RunMessageLoop(); chrome::HostDesktopType desktop_type = chrome::GetActiveDesktop(); BrowserList* browser_list = BrowserList::GetInstance(desktop_type); ASSERT_EQ(2U, cache.GetNumberOfProfiles()); EXPECT_EQ(1U, browser_list->size()); // Open a browser window for the second profile. profiles::SwitchToProfile(path_profile2, desktop_type, false, kOnProfileSwitchDoNothing, ProfileMetrics::SWITCH_PROFILE_ICON); EXPECT_EQ(2U, chrome::GetTotalBrowserCount()); EXPECT_EQ(2U, browser_list->size()); EXPECT_EQ(path_profile2, browser_list->get(1)->profile()->GetPath()); // Create a second window for the ephemeral profile. profiles::SwitchToProfile(path_profile2, desktop_type, true, kOnProfileSwitchDoNothing, ProfileMetrics::SWITCH_PROFILE_ICON); EXPECT_EQ(3U, chrome::GetTotalBrowserCount()); EXPECT_EQ(3U, browser_list->size()); EXPECT_EQ(path_profile1, browser_list->get(0)->profile()->GetPath()); EXPECT_EQ(path_profile2, browser_list->get(1)->profile()->GetPath()); EXPECT_EQ(path_profile2, browser_list->get(2)->profile()->GetPath()); // Closing the first window of the ephemeral profile should not delete it. browser_list->get(2)->window()->Close(); content::RunAllPendingInMessageLoop(); EXPECT_EQ(2U, browser_list->size()); ASSERT_EQ(2U, cache.GetNumberOfProfiles()); // The second should though. browser_list->get(1)->window()->Close(); content::RunAllPendingInMessageLoop(); EXPECT_EQ(1U, browser_list->size()); ASSERT_EQ(1U, cache.GetNumberOfProfiles()); }