1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "base/bind.h"
6#include "base/command_line.h"
7#include "base/prefs/pref_service.h"
8#include "base/strings/utf_string_conversions.h"
9#include "chrome/browser/profiles/profile_info_cache.h"
10#include "chrome/browser/profiles/profile_info_cache_observer.h"
11#include "chrome/browser/profiles/profile_manager.h"
12#include "chrome/browser/profiles/profile_window.h"
13#include "chrome/browser/profiles/profiles_state.h"
14#include "chrome/browser/ui/browser_finder.h"
15#include "chrome/browser/ui/browser_list.h"
16#include "chrome/browser/ui/browser_window.h"
17#include "chrome/browser/ui/host_desktop.h"
18#include "chrome/common/chrome_switches.h"
19#include "chrome/common/pref_names.h"
20#include "chrome/test/base/in_process_browser_test.h"
21#include "chrome/test/base/test_switches.h"
22#include "chrome/test/base/testing_browser_process.h"
23#include "chrome/test/base/ui_test_utils.h"
24
25#if defined(OS_CHROMEOS)
26#include "base/path_service.h"
27#include "chrome/common/chrome_constants.h"
28#include "chrome/common/chrome_paths.h"
29#include "testing/gtest/include/gtest/gtest.h"
30#endif
31
32namespace {
33
34const profiles::ProfileSwitchingDoneCallback kOnProfileSwitchDoNothing;
35
36// An observer that returns back to test code after a new profile is
37// initialized.
38void OnUnblockOnProfileCreation(Profile* profile,
39                                Profile::CreateStatus status) {
40  if (status == Profile::CREATE_STATUS_INITIALIZED)
41    base::MessageLoop::current()->Quit();
42}
43
44void ProfileCreationComplete(Profile* profile, Profile::CreateStatus status) {
45  ASSERT_NE(status, Profile::CREATE_STATUS_LOCAL_FAIL);
46  ASSERT_NE(status, Profile::CREATE_STATUS_REMOTE_FAIL);
47  // No browser should have been created for this profile yet.
48  EXPECT_EQ(chrome::GetTotalBrowserCountForProfile(profile), 0U);
49  EXPECT_EQ(chrome::GetTotalBrowserCount(), 1U);
50  if (status == Profile::CREATE_STATUS_INITIALIZED)
51    base::MessageLoop::current()->Quit();
52}
53
54void EphemeralProfileCreationComplete(Profile* profile,
55                                      Profile::CreateStatus status) {
56  if (status == Profile::CREATE_STATUS_INITIALIZED)
57    profile->GetPrefs()->SetBoolean(prefs::kForceEphemeralProfiles, true);
58  ProfileCreationComplete(profile, status);
59}
60
61class ProfileRemovalObserver : public ProfileInfoCacheObserver {
62 public:
63  ProfileRemovalObserver() {
64    g_browser_process->profile_manager()->GetProfileInfoCache().AddObserver(
65        this);
66  }
67
68  virtual ~ProfileRemovalObserver() {
69    g_browser_process->profile_manager()->GetProfileInfoCache().RemoveObserver(
70        this);
71  }
72
73  std::string last_used_profile_name() { return last_used_profile_name_; }
74
75  // ProfileInfoCacheObserver overrides:
76  virtual void OnProfileWillBeRemoved(
77      const base::FilePath& profile_path) OVERRIDE {
78    last_used_profile_name_ = g_browser_process->local_state()->GetString(
79        prefs::kProfileLastUsed);
80  }
81
82 private:
83  std::string last_used_profile_name_;
84
85  DISALLOW_COPY_AND_ASSIGN(ProfileRemovalObserver);
86};
87
88} // namespace
89
90// This file contains tests for the ProfileManager that require a heavyweight
91// InProcessBrowserTest.  These include tests involving profile deletion.
92
93// TODO(jeremy): crbug.com/103355 - These tests should be enabled on all
94// platforms.
95class ProfileManagerBrowserTest : public InProcessBrowserTest {
96};
97
98#if defined(OS_MACOSX)
99
100// Delete single profile and make sure a new one is created.
101IN_PROC_BROWSER_TEST_F(ProfileManagerBrowserTest, DeleteSingletonProfile) {
102  ProfileManager* profile_manager = g_browser_process->profile_manager();
103  ProfileInfoCache& cache = profile_manager->GetProfileInfoCache();
104  ProfileRemovalObserver observer;
105
106  // We should start out with 1 profile.
107  ASSERT_EQ(cache.GetNumberOfProfiles(), 1U);
108
109  // Delete singleton profile.
110  base::FilePath singleton_profile_path = cache.GetPathOfProfileAtIndex(0);
111  EXPECT_FALSE(singleton_profile_path.empty());
112  profile_manager->ScheduleProfileForDeletion(singleton_profile_path,
113                                              ProfileManager::CreateCallback());
114
115  // Spin things till profile is actually deleted.
116  content::RunAllPendingInMessageLoop();
117
118  // Make sure a new profile was created automatically.
119  EXPECT_EQ(cache.GetNumberOfProfiles(), 1U);
120  base::FilePath new_profile_path = cache.GetPathOfProfileAtIndex(0);
121  EXPECT_NE(new_profile_path, singleton_profile_path);
122
123  // Make sure that last used profile preference is set correctly.
124  Profile* last_used = ProfileManager::GetLastUsedProfile();
125  EXPECT_EQ(new_profile_path, last_used->GetPath());
126
127  // Make sure the last used profile was set correctly before the notification
128  // was sent.
129  std::string last_used_profile_name =
130      last_used->GetPath().BaseName().MaybeAsASCII();
131  EXPECT_EQ(last_used_profile_name, observer.last_used_profile_name());
132}
133
134// Delete all profiles in a multi profile setup and make sure a new one is
135// created.
136// Crashes/CHECKs. See crbug.com/104851
137IN_PROC_BROWSER_TEST_F(ProfileManagerBrowserTest, DISABLED_DeleteAllProfiles) {
138  ProfileManager* profile_manager = g_browser_process->profile_manager();
139  ProfileInfoCache& cache = profile_manager->GetProfileInfoCache();
140
141  // Create an additional profile.
142  base::FilePath new_path = profile_manager->GenerateNextProfileDirectoryPath();
143  profile_manager->CreateProfileAsync(new_path,
144                                      base::Bind(&OnUnblockOnProfileCreation),
145                                      base::string16(), base::string16(),
146                                      std::string());
147
148  // Spin to allow profile creation to take place, loop is terminated
149  // by OnUnblockOnProfileCreation when the profile is created.
150  content::RunMessageLoop();
151
152  ASSERT_EQ(cache.GetNumberOfProfiles(), 2U);
153
154  // Delete all profiles.
155  base::FilePath profile_path1 = cache.GetPathOfProfileAtIndex(0);
156  base::FilePath profile_path2 = cache.GetPathOfProfileAtIndex(1);
157  EXPECT_FALSE(profile_path1.empty());
158  EXPECT_FALSE(profile_path2.empty());
159  profile_manager->ScheduleProfileForDeletion(profile_path1,
160                                              ProfileManager::CreateCallback());
161  profile_manager->ScheduleProfileForDeletion(profile_path2,
162                                              ProfileManager::CreateCallback());
163
164  // Spin things so deletion can take place.
165  content::RunAllPendingInMessageLoop();
166
167  // Make sure a new profile was created automatically.
168  EXPECT_EQ(cache.GetNumberOfProfiles(), 1U);
169  base::FilePath new_profile_path = cache.GetPathOfProfileAtIndex(0);
170  EXPECT_NE(new_profile_path, profile_path1);
171  EXPECT_NE(new_profile_path, profile_path2);
172
173  // Make sure that last used profile preference is set correctly.
174  Profile* last_used = ProfileManager::GetLastUsedProfile();
175  EXPECT_EQ(new_profile_path, last_used->GetPath());
176}
177#endif  // OS_MACOSX
178
179#if defined(OS_CHROMEOS)
180
181class ProfileManagerCrOSBrowserTest : public ProfileManagerBrowserTest,
182                                      public testing::WithParamInterface<bool> {
183 protected:
184  virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
185    if (GetParam())
186      command_line->AppendSwitch(::switches::kMultiProfiles);
187  }
188};
189
190IN_PROC_BROWSER_TEST_P(ProfileManagerCrOSBrowserTest, GetLastUsedProfile) {
191  // Make sure that last used profile is correct.
192  Profile* last_used_profile = ProfileManager::GetLastUsedProfile();
193  EXPECT_TRUE(last_used_profile != NULL);
194
195  base::FilePath profile_path;
196  PathService::Get(chrome::DIR_USER_DATA, &profile_path);
197
198  const CommandLine& command_line = *CommandLine::ForCurrentProcess();
199  if (command_line.HasSwitch(switches::kMultiProfiles)) {
200    profile_path = profile_path.Append(base::FilePath(
201        std::string(chrome::kProfileDirPrefix) + chrome::kTestUserProfileDir));
202  } else {
203    profile_path = profile_path.Append(
204        base::FilePath(chrome::kTestUserProfileDir));
205  }
206  EXPECT_EQ(profile_path.value(), last_used_profile->GetPath().value());
207}
208
209INSTANTIATE_TEST_CASE_P(ProfileManagerCrOSBrowserTestInstantiation,
210                        ProfileManagerCrOSBrowserTest,
211                        testing::Bool());
212
213#endif  // OS_CHROMEOS
214
215// Times out (http://crbug.com/159002)
216IN_PROC_BROWSER_TEST_F(ProfileManagerBrowserTest,
217                       DISABLED_CreateProfileWithCallback) {
218  ProfileManager* profile_manager = g_browser_process->profile_manager();
219
220  ASSERT_EQ(profile_manager->GetNumberOfProfiles(), 1U);
221  EXPECT_EQ(chrome::GetTotalBrowserCount(), 1U);
222
223  // Create a profile, make sure callback is invoked before any callbacks are
224  // invoked (so they can do things like sign in the profile, etc).
225  ProfileManager::CreateMultiProfileAsync(
226      base::string16(), // name
227      base::string16(), // icon url
228      base::Bind(ProfileCreationComplete),
229      std::string());
230  // Wait for profile to finish loading.
231  content::RunMessageLoop();
232  EXPECT_EQ(profile_manager->GetNumberOfProfiles(), 2U);
233  EXPECT_EQ(chrome::GetTotalBrowserCount(), 2U);
234
235  // Now close all browser windows.
236  std::vector<Profile*> profiles = profile_manager->GetLoadedProfiles();
237  for (std::vector<Profile*>::const_iterator it = profiles.begin();
238       it != profiles.end(); ++it) {
239    BrowserList::CloseAllBrowsersWithProfile(*it);
240  }
241}
242
243IN_PROC_BROWSER_TEST_F(ProfileManagerBrowserTest,
244                       SwitchToProfile) {
245#if defined(OS_WIN) && defined(USE_ASH)
246  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
247  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
248    return;
249#endif
250
251  // If multiprofile mode is not enabled, you can't switch between profiles.
252  if (!profiles::IsMultipleProfilesEnabled())
253    return;
254
255  ProfileManager* profile_manager = g_browser_process->profile_manager();
256  ProfileInfoCache& cache = profile_manager->GetProfileInfoCache();
257  base::FilePath path_profile1 = cache.GetPathOfProfileAtIndex(0);
258
259  ASSERT_EQ(profile_manager->GetNumberOfProfiles(), 1U);
260  EXPECT_EQ(chrome::GetTotalBrowserCount(), 1U);
261
262  // Create an additional profile.
263  base::FilePath path_profile2 =
264      profile_manager->GenerateNextProfileDirectoryPath();
265  profile_manager->CreateProfileAsync(path_profile2,
266                                      base::Bind(&OnUnblockOnProfileCreation),
267                                      base::string16(), base::string16(),
268                                      std::string());
269
270  // Spin to allow profile creation to take place, loop is terminated
271  // by OnUnblockOnProfileCreation when the profile is created.
272  content::RunMessageLoop();
273
274  chrome::HostDesktopType desktop_type = chrome::GetActiveDesktop();
275  BrowserList* browser_list = BrowserList::GetInstance(desktop_type);
276  ASSERT_EQ(cache.GetNumberOfProfiles(), 2U);
277  EXPECT_EQ(1U, browser_list->size());
278
279  // Open a browser window for the first profile.
280  profiles::SwitchToProfile(path_profile1, desktop_type, false,
281                            kOnProfileSwitchDoNothing);
282  EXPECT_EQ(chrome::GetTotalBrowserCount(), 1U);
283  EXPECT_EQ(1U, browser_list->size());
284  EXPECT_EQ(path_profile1, browser_list->get(0)->profile()->GetPath());
285
286  // Open a browser window for the second profile.
287  profiles::SwitchToProfile(path_profile2, desktop_type, false,
288                            kOnProfileSwitchDoNothing);
289  EXPECT_EQ(chrome::GetTotalBrowserCount(), 2U);
290  EXPECT_EQ(2U, browser_list->size());
291  EXPECT_EQ(path_profile2, browser_list->get(1)->profile()->GetPath());
292
293  // Switch to the first profile without opening a new window.
294  profiles::SwitchToProfile(path_profile1, desktop_type, false,
295                            kOnProfileSwitchDoNothing);
296  EXPECT_EQ(chrome::GetTotalBrowserCount(), 2U);
297  EXPECT_EQ(2U, browser_list->size());
298
299  EXPECT_EQ(path_profile1, browser_list->get(0)->profile()->GetPath());
300  EXPECT_EQ(path_profile2, browser_list->get(1)->profile()->GetPath());
301}
302
303// This test used to be flakily timing out on Windows: http://crbug.com/314905.
304// If this happens again please make it a MAYBE_ test and reopen that bug.
305IN_PROC_BROWSER_TEST_F(ProfileManagerBrowserTest, EphemeralProfile) {
306#if defined(OS_WIN) && defined(USE_ASH)
307  // Disable this test in Metro+Ash for now (http://crbug.com/262796).
308  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kAshBrowserTests))
309    return;
310#endif
311
312  // If multiprofile mode is not enabled, you can't switch between profiles.
313  if (!profiles::IsMultipleProfilesEnabled())
314    return;
315
316  ProfileManager* profile_manager = g_browser_process->profile_manager();
317  ProfileInfoCache& cache = profile_manager->GetProfileInfoCache();
318  base::FilePath path_profile1 = cache.GetPathOfProfileAtIndex(0);
319
320  ASSERT_EQ(1U, profile_manager->GetNumberOfProfiles());
321  EXPECT_EQ(1U, chrome::GetTotalBrowserCount());
322
323  // Create an ephemeral profile.
324  base::FilePath path_profile2 =
325      profile_manager->GenerateNextProfileDirectoryPath();
326  profile_manager->CreateProfileAsync(
327      path_profile2,
328      base::Bind(&EphemeralProfileCreationComplete),
329      base::string16(), base::string16(), std::string());
330
331  // Spin to allow profile creation to take place.
332  content::RunMessageLoop();
333
334  chrome::HostDesktopType desktop_type = chrome::GetActiveDesktop();
335  BrowserList* browser_list = BrowserList::GetInstance(desktop_type);
336  ASSERT_EQ(2U, cache.GetNumberOfProfiles());
337  EXPECT_EQ(1U, browser_list->size());
338
339  // Open a browser window for the second profile.
340  profiles::SwitchToProfile(path_profile2, desktop_type, false,
341                            kOnProfileSwitchDoNothing);
342  EXPECT_EQ(2U, chrome::GetTotalBrowserCount());
343  EXPECT_EQ(2U, browser_list->size());
344  EXPECT_EQ(path_profile2, browser_list->get(1)->profile()->GetPath());
345
346  // Create a second window for the ephemeral profile.
347  profiles::SwitchToProfile(path_profile2, desktop_type, true,
348                            kOnProfileSwitchDoNothing);
349  EXPECT_EQ(3U, chrome::GetTotalBrowserCount());
350  EXPECT_EQ(3U, browser_list->size());
351
352  EXPECT_EQ(path_profile1, browser_list->get(0)->profile()->GetPath());
353  EXPECT_EQ(path_profile2, browser_list->get(1)->profile()->GetPath());
354  EXPECT_EQ(path_profile2, browser_list->get(2)->profile()->GetPath());
355
356  // Closing the first window of the ephemeral profile should not delete it.
357  browser_list->get(2)->window()->Close();
358  content::RunAllPendingInMessageLoop();
359  EXPECT_EQ(2U, browser_list->size());
360  ASSERT_EQ(2U, cache.GetNumberOfProfiles());
361
362  // The second should though.
363  browser_list->get(1)->window()->Close();
364  content::RunAllPendingInMessageLoop();
365  EXPECT_EQ(1U, browser_list->size());
366  ASSERT_EQ(1U, cache.GetNumberOfProfiles());
367}
368