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 "chrome/browser/profiles/profile.h"
6
7#include "base/file_util.h"
8#include "base/files/scoped_temp_dir.h"
9#include "base/platform_file.h"
10#include "base/prefs/pref_service.h"
11#include "base/version.h"
12#include "chrome/browser/chrome_notification_types.h"
13#include "chrome/browser/profiles/chrome_version_service.h"
14#include "chrome/browser/profiles/profile_impl.h"
15#include "chrome/browser/profiles/startup_task_runner_service.h"
16#include "chrome/browser/profiles/startup_task_runner_service_factory.h"
17#include "chrome/common/chrome_constants.h"
18#include "chrome/common/chrome_version_info.h"
19#include "chrome/common/pref_names.h"
20#include "chrome/test/base/in_process_browser_test.h"
21#include "chrome/test/base/ui_test_utils.h"
22#include "testing/gmock/include/gmock/gmock.h"
23#include "testing/gtest/include/gtest/gtest.h"
24
25namespace {
26
27class MockProfileDelegate : public Profile::Delegate {
28 public:
29  MOCK_METHOD1(OnPrefsLoaded, void(Profile*));
30  MOCK_METHOD3(OnProfileCreated, void(Profile*, bool, bool));
31};
32
33// Creates a prefs file in the given directory.
34void CreatePrefsFileInDirectory(const base::FilePath& directory_path) {
35  base::FilePath pref_path(directory_path.Append(chrome::kPreferencesFilename));
36  base::PlatformFile file = base::CreatePlatformFile(pref_path,
37      base::PLATFORM_FILE_CREATE | base::PLATFORM_FILE_WRITE, NULL, NULL);
38  ASSERT_TRUE(file != base::kInvalidPlatformFileValue);
39  ASSERT_TRUE(base::ClosePlatformFile(file));
40  std::string data("{}");
41  ASSERT_TRUE(file_util::WriteFile(pref_path, data.c_str(), data.size()));
42}
43
44void CheckChromeVersion(Profile *profile, bool is_new) {
45  std::string created_by_version;
46  if (is_new) {
47    chrome::VersionInfo version_info;
48    created_by_version = version_info.Version();
49  } else {
50    created_by_version = "1.0.0.0";
51  }
52  std::string pref_version =
53      ChromeVersionService::GetVersion(profile->GetPrefs());
54  // Assert that created_by_version pref gets set to current version.
55  EXPECT_EQ(created_by_version, pref_version);
56}
57
58}  // namespace
59
60typedef InProcessBrowserTest ProfileBrowserTest;
61
62// Test OnProfileCreate is called with is_new_profile set to true when
63// creating a new profile synchronously.
64//
65// Flaky (sometimes timeout): http://crbug.com/141141
66IN_PROC_BROWSER_TEST_F(ProfileBrowserTest,
67                       DISABLED_CreateNewProfileSynchronous) {
68  base::ScopedTempDir temp_dir;
69  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
70
71  MockProfileDelegate delegate;
72  EXPECT_CALL(delegate, OnProfileCreated(testing::NotNull(), true, true));
73
74  scoped_ptr<Profile> profile(Profile::CreateProfile(
75      temp_dir.path(), &delegate, Profile::CREATE_MODE_SYNCHRONOUS));
76  ASSERT_TRUE(profile.get());
77  CheckChromeVersion(profile.get(), true);
78  StartupTaskRunnerServiceFactory::GetForProfile(profile.get())->
79              StartDeferredTaskRunners();
80}
81
82// Test OnProfileCreate is called with is_new_profile set to false when
83// creating a profile synchronously with an existing prefs file.
84// Flaky: http://crbug.com/141517
85IN_PROC_BROWSER_TEST_F(ProfileBrowserTest,
86                       DISABLED_CreateOldProfileSynchronous) {
87  base::ScopedTempDir temp_dir;
88  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
89  CreatePrefsFileInDirectory(temp_dir.path());
90
91  MockProfileDelegate delegate;
92  EXPECT_CALL(delegate, OnProfileCreated(testing::NotNull(), true, false));
93
94  scoped_ptr<Profile> profile(Profile::CreateProfile(
95      temp_dir.path(), &delegate, Profile::CREATE_MODE_SYNCHRONOUS));
96  ASSERT_TRUE(profile.get());
97  CheckChromeVersion(profile.get(), false);
98  StartupTaskRunnerServiceFactory::GetForProfile(profile.get())->
99              StartDeferredTaskRunners();
100}
101
102// Test OnProfileCreate is called with is_new_profile set to true when
103// creating a new profile asynchronously.
104// This test is flaky on Linux, Win and Mac.  See crbug.com/142787
105IN_PROC_BROWSER_TEST_F(ProfileBrowserTest,
106                       DISABLED_CreateNewProfileAsynchronous) {
107  base::ScopedTempDir temp_dir;
108  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
109
110  MockProfileDelegate delegate;
111  EXPECT_CALL(delegate, OnProfileCreated(testing::NotNull(), true, true));
112
113  scoped_ptr<Profile> profile(Profile::CreateProfile(
114      temp_dir.path(), &delegate, Profile::CREATE_MODE_ASYNCHRONOUS));
115  ASSERT_TRUE(profile.get());
116  StartupTaskRunnerServiceFactory::GetForProfile(profile.get())->
117              StartDeferredTaskRunners();
118
119  // Wait for the profile to be created.
120  content::WindowedNotificationObserver observer(
121      chrome::NOTIFICATION_PROFILE_CREATED,
122      content::Source<Profile>(profile.get()));
123  observer.Wait();
124  CheckChromeVersion(profile.get(), true);
125}
126
127// Test OnProfileCreate is called with is_new_profile set to false when
128// creating a profile asynchronously with an existing prefs file.
129// Flaky: http://crbug.com/141517
130IN_PROC_BROWSER_TEST_F(ProfileBrowserTest,
131                       DISABLED_CreateOldProfileAsynchronous) {
132  base::ScopedTempDir temp_dir;
133  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
134  CreatePrefsFileInDirectory(temp_dir.path());
135
136  MockProfileDelegate delegate;
137  EXPECT_CALL(delegate, OnProfileCreated(testing::NotNull(), true, false));
138  scoped_ptr<Profile> profile(Profile::CreateProfile(
139      temp_dir.path(), &delegate, Profile::CREATE_MODE_ASYNCHRONOUS));
140  ASSERT_TRUE(profile.get());
141  StartupTaskRunnerServiceFactory::GetForProfile(profile.get())->
142              StartDeferredTaskRunners();
143
144  // Wait for the profile to be created.
145  content::WindowedNotificationObserver observer(
146      chrome::NOTIFICATION_PROFILE_CREATED,
147      content::Source<Profile>(profile.get()));
148  observer.Wait();
149  CheckChromeVersion(profile.get(), false);
150}
151
152// Test that a README file is created for profiles that didn't have it.
153// Flaky: http://crbug.com/140882
154IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, DISABLED_ProfileReadmeCreated) {
155  base::ScopedTempDir temp_dir;
156  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
157
158  MockProfileDelegate delegate;
159  EXPECT_CALL(delegate, OnProfileCreated(testing::NotNull(), true, true));
160
161  // No delay before README creation.
162  ProfileImpl::create_readme_delay_ms = 0;
163
164  scoped_ptr<Profile> profile(Profile::CreateProfile(
165      temp_dir.path(), &delegate, Profile::CREATE_MODE_ASYNCHRONOUS));
166  ASSERT_TRUE(profile.get());
167  StartupTaskRunnerServiceFactory::GetForProfile(profile.get())->
168              StartDeferredTaskRunners();
169
170  // Wait for the profile to be created.
171  content::WindowedNotificationObserver observer(
172      chrome::NOTIFICATION_PROFILE_CREATED,
173      content::Source<Profile>(profile.get()));
174  observer.Wait();
175
176  content::RunAllPendingInMessageLoop(content::BrowserThread::FILE);
177
178  // Verify that README exists.
179  EXPECT_TRUE(base::PathExists(
180      temp_dir.path().Append(chrome::kReadmeFilename)));
181}
182
183// Test that Profile can be deleted before README file is created.
184IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, ProfileDeletedBeforeReadmeCreated) {
185  base::ScopedTempDir temp_dir;
186  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
187
188  MockProfileDelegate delegate;
189  EXPECT_CALL(delegate, OnProfileCreated(testing::NotNull(), true, true));
190
191  // No delay before README creation.
192  ProfileImpl::create_readme_delay_ms = 0;
193
194  scoped_ptr<Profile> profile(Profile::CreateProfile(
195      temp_dir.path(), &delegate, Profile::CREATE_MODE_SYNCHRONOUS));
196  ASSERT_TRUE(profile.get());
197  StartupTaskRunnerServiceFactory::GetForProfile(profile.get())->
198              StartDeferredTaskRunners();
199
200  // Delete the Profile instance and run pending tasks (this includes the task
201  // for README creation).
202  profile.reset();
203  content::RunAllPendingInMessageLoop();
204  content::RunAllPendingInMessageLoop(content::BrowserThread::DB);
205  content::RunAllPendingInMessageLoop(content::BrowserThread::FILE);
206}
207
208// Test that repeated setting of exit type is handled correctly.
209#if defined(OS_WIN)
210// Flaky on Windows: http://crbug.com/163713
211#define MAYBE_ExitType DISABLED_ExitType
212#else
213#define MAYBE_ExitType ExitType
214#endif
215IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, MAYBE_ExitType) {
216  base::ScopedTempDir temp_dir;
217  ASSERT_TRUE(temp_dir.CreateUniqueTempDir());
218
219  MockProfileDelegate delegate;
220  EXPECT_CALL(delegate, OnProfileCreated(testing::NotNull(), true, true));
221
222  scoped_ptr<Profile> profile(Profile::CreateProfile(
223      temp_dir.path(), &delegate, Profile::CREATE_MODE_SYNCHRONOUS));
224  ASSERT_TRUE(profile.get());
225  StartupTaskRunnerServiceFactory::GetForProfile(profile.get())->
226              StartDeferredTaskRunners();
227
228  PrefService* prefs = profile->GetPrefs();
229  // The initial state is crashed; store for later reference.
230  std::string crash_value(prefs->GetString(prefs::kSessionExitType));
231
232  // The first call to a type other than crashed should change the value.
233  profile->SetExitType(Profile::EXIT_SESSION_ENDED);
234  std::string first_call_value(prefs->GetString(prefs::kSessionExitType));
235  EXPECT_NE(crash_value, first_call_value);
236
237  // Subsequent calls to a non-crash value should be ignored.
238  profile->SetExitType(Profile::EXIT_NORMAL);
239  std::string second_call_value(prefs->GetString(prefs::kSessionExitType));
240  EXPECT_EQ(first_call_value, second_call_value);
241
242  // Setting back to a crashed value should work.
243  profile->SetExitType(Profile::EXIT_CRASHED);
244  std::string final_value(prefs->GetString(prefs::kSessionExitType));
245  EXPECT_EQ(crash_value, final_value);
246
247  // This test runs fast enough that the WebDataService may still be
248  // initializing (which uses the temp directory) when the test
249  // ends. Give it a chance to complete.
250  profile.reset();
251  content::RunAllPendingInMessageLoop();
252  content::RunAllPendingInMessageLoop(content::BrowserThread::DB);
253}
254