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