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/command_line.h" 8#include "base/file_util.h" 9#include "base/files/scoped_temp_dir.h" 10#include "base/prefs/pref_service.h" 11#include "base/synchronization/waitable_event.h" 12#include "base/version.h" 13#include "chrome/browser/chrome_notification_types.h" 14#include "chrome/browser/profiles/chrome_version_service.h" 15#include "chrome/browser/profiles/profile_impl.h" 16#include "chrome/browser/profiles/startup_task_runner_service.h" 17#include "chrome/browser/profiles/startup_task_runner_service_factory.h" 18#include "chrome/common/chrome_constants.h" 19#include "chrome/common/chrome_version_info.h" 20#include "chrome/common/pref_names.h" 21#include "chrome/test/base/in_process_browser_test.h" 22#include "chrome/test/base/ui_test_utils.h" 23#include "testing/gmock/include/gmock/gmock.h" 24#include "testing/gtest/include/gtest/gtest.h" 25 26#if defined(OS_CHROMEOS) 27#include "chromeos/chromeos_switches.h" 28#endif 29 30namespace { 31 32class MockProfileDelegate : public Profile::Delegate { 33 public: 34 MOCK_METHOD1(OnPrefsLoaded, void(Profile*)); 35 MOCK_METHOD3(OnProfileCreated, void(Profile*, bool, bool)); 36}; 37 38// Creates a prefs file in the given directory. 39void CreatePrefsFileInDirectory(const base::FilePath& directory_path) { 40 base::FilePath pref_path(directory_path.Append(chrome::kPreferencesFilename)); 41 std::string data("{}"); 42 ASSERT_TRUE(base::WriteFile(pref_path, data.c_str(), data.size())); 43} 44 45scoped_ptr<Profile> CreateProfile( 46 const base::FilePath& path, 47 Profile::Delegate* delegate, 48 Profile::CreateMode create_mode) { 49 scoped_ptr<Profile> profile(Profile::CreateProfile( 50 path, delegate, create_mode)); 51 EXPECT_TRUE(profile.get()); 52 // This is necessary to avoid a memleak from BookmarkModel::Load. 53 // Unfortunately, this also results in warnings during debug runs. 54 StartupTaskRunnerServiceFactory::GetForProfile(profile.get())-> 55 StartDeferredTaskRunners(); 56 return profile.Pass(); 57} 58 59void CheckChromeVersion(Profile *profile, bool is_new) { 60 std::string created_by_version; 61 if (is_new) { 62 chrome::VersionInfo version_info; 63 created_by_version = version_info.Version(); 64 } else { 65 created_by_version = "1.0.0.0"; 66 } 67 std::string pref_version = 68 ChromeVersionService::GetVersion(profile->GetPrefs()); 69 // Assert that created_by_version pref gets set to current version. 70 EXPECT_EQ(created_by_version, pref_version); 71} 72 73void BlockThread( 74 base::WaitableEvent* is_blocked, 75 base::WaitableEvent* unblock) { 76 is_blocked->Signal(); 77 unblock->Wait(); 78} 79 80void SpinThreads() { 81 // Give threads a chance to do their stuff before shutting down (i.e. 82 // deleting scoped temp dir etc). 83 // Should not be necessary anymore once Profile deletion is fixed 84 // (see crbug.com/88586). 85 content::RunAllPendingInMessageLoop(); 86 content::RunAllPendingInMessageLoop(content::BrowserThread::DB); 87 content::RunAllPendingInMessageLoop(content::BrowserThread::FILE); 88} 89 90} // namespace 91 92class ProfileBrowserTest : public InProcessBrowserTest { 93 protected: 94 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 95#if defined(OS_CHROMEOS) 96 command_line->AppendSwitch( 97 chromeos::switches::kIgnoreUserProfileMappingForTests); 98#endif 99 } 100}; 101 102// Test OnProfileCreate is called with is_new_profile set to true when 103// creating a new profile synchronously. 104// 105// Flaky (sometimes timeout): http://crbug.com/141141 106IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, 107 DISABLED_CreateNewProfileSynchronous) { 108 base::ScopedTempDir temp_dir; 109 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 110 111 MockProfileDelegate delegate; 112 EXPECT_CALL(delegate, OnProfileCreated(testing::NotNull(), true, true)); 113 114 { 115 scoped_ptr<Profile> profile(CreateProfile( 116 temp_dir.path(), &delegate, Profile::CREATE_MODE_SYNCHRONOUS)); 117 CheckChromeVersion(profile.get(), true); 118 } 119 120 SpinThreads(); 121} 122 123// Test OnProfileCreate is called with is_new_profile set to false when 124// creating a profile synchronously with an existing prefs file. 125// Flaky: http://crbug.com/141517 126IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, 127 DISABLED_CreateOldProfileSynchronous) { 128 base::ScopedTempDir temp_dir; 129 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 130 CreatePrefsFileInDirectory(temp_dir.path()); 131 132 MockProfileDelegate delegate; 133 EXPECT_CALL(delegate, OnProfileCreated(testing::NotNull(), true, false)); 134 135 { 136 scoped_ptr<Profile> profile(CreateProfile( 137 temp_dir.path(), &delegate, Profile::CREATE_MODE_SYNCHRONOUS)); 138 CheckChromeVersion(profile.get(), false); 139 } 140 141 SpinThreads(); 142} 143 144// Test OnProfileCreate is called with is_new_profile set to true when 145// creating a new profile asynchronously. 146// This test is flaky on Linux, Win and Mac. See crbug.com/142787 147IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, 148 DISABLED_CreateNewProfileAsynchronous) { 149 base::ScopedTempDir temp_dir; 150 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 151 152 MockProfileDelegate delegate; 153 EXPECT_CALL(delegate, OnProfileCreated(testing::NotNull(), true, true)); 154 155 { 156 content::WindowedNotificationObserver observer( 157 chrome::NOTIFICATION_PROFILE_CREATED, 158 content::NotificationService::AllSources()); 159 160 scoped_ptr<Profile> profile(CreateProfile( 161 temp_dir.path(), &delegate, Profile::CREATE_MODE_ASYNCHRONOUS)); 162 163 // Wait for the profile to be created. 164 observer.Wait(); 165 CheckChromeVersion(profile.get(), true); 166 } 167 168 SpinThreads(); 169} 170 171// Test OnProfileCreate is called with is_new_profile set to false when 172// creating a profile asynchronously with an existing prefs file. 173// Flaky: http://crbug.com/141517 174IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, 175 DISABLED_CreateOldProfileAsynchronous) { 176 base::ScopedTempDir temp_dir; 177 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 178 CreatePrefsFileInDirectory(temp_dir.path()); 179 180 MockProfileDelegate delegate; 181 EXPECT_CALL(delegate, OnProfileCreated(testing::NotNull(), true, false)); 182 183 { 184 content::WindowedNotificationObserver observer( 185 chrome::NOTIFICATION_PROFILE_CREATED, 186 content::NotificationService::AllSources()); 187 188 scoped_ptr<Profile> profile(CreateProfile( 189 temp_dir.path(), &delegate, Profile::CREATE_MODE_ASYNCHRONOUS)); 190 191 // Wait for the profile to be created. 192 observer.Wait(); 193 CheckChromeVersion(profile.get(), false); 194 } 195 196 SpinThreads(); 197} 198 199// Test that a README file is created for profiles that didn't have it. 200// Flaky: http://crbug.com/140882 201IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, DISABLED_ProfileReadmeCreated) { 202 base::ScopedTempDir temp_dir; 203 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 204 205 MockProfileDelegate delegate; 206 EXPECT_CALL(delegate, OnProfileCreated(testing::NotNull(), true, true)); 207 208 // No delay before README creation. 209 ProfileImpl::create_readme_delay_ms = 0; 210 211 { 212 content::WindowedNotificationObserver observer( 213 chrome::NOTIFICATION_PROFILE_CREATED, 214 content::NotificationService::AllSources()); 215 216 scoped_ptr<Profile> profile(CreateProfile( 217 temp_dir.path(), &delegate, Profile::CREATE_MODE_ASYNCHRONOUS)); 218 219 // Wait for the profile to be created. 220 observer.Wait(); 221 222 // Wait for file thread to create the README. 223 content::RunAllPendingInMessageLoop(content::BrowserThread::FILE); 224 225 // Verify that README exists. 226 EXPECT_TRUE(base::PathExists( 227 temp_dir.path().Append(chrome::kReadmeFilename))); 228 } 229 230 SpinThreads(); 231} 232 233// Test that Profile can be deleted before README file is created. 234IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, ProfileDeletedBeforeReadmeCreated) { 235 base::ScopedTempDir temp_dir; 236 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 237 238 MockProfileDelegate delegate; 239 EXPECT_CALL(delegate, OnProfileCreated(testing::NotNull(), true, true)); 240 241 // No delay before README creation. 242 ProfileImpl::create_readme_delay_ms = 0; 243 244 base::WaitableEvent is_blocked(false, false); 245 base::WaitableEvent* unblock = new base::WaitableEvent(false, false); 246 247 // Block file thread. 248 content::BrowserThread::PostTask( 249 content::BrowserThread::FILE, FROM_HERE, 250 base::Bind(&BlockThread, &is_blocked, base::Owned(unblock))); 251 // Wait for file thread to actually be blocked. 252 is_blocked.Wait(); 253 254 scoped_ptr<Profile> profile(CreateProfile( 255 temp_dir.path(), &delegate, Profile::CREATE_MODE_SYNCHRONOUS)); 256 257 // Delete the Profile instance before we give the file thread a chance to 258 // create the README. 259 profile.reset(); 260 261 // Now unblock the file thread again and run pending tasks (this includes the 262 // task for README creation). 263 unblock->Signal(); 264 265 SpinThreads(); 266} 267 268// Test that repeated setting of exit type is handled correctly. 269#if defined(OS_WIN) 270// Flaky on Windows: http://crbug.com/163713 271#define MAYBE_ExitType DISABLED_ExitType 272#else 273#define MAYBE_ExitType ExitType 274#endif 275IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, MAYBE_ExitType) { 276 base::ScopedTempDir temp_dir; 277 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); 278 279 MockProfileDelegate delegate; 280 EXPECT_CALL(delegate, OnProfileCreated(testing::NotNull(), true, true)); 281 { 282 scoped_ptr<Profile> profile(CreateProfile( 283 temp_dir.path(), &delegate, Profile::CREATE_MODE_SYNCHRONOUS)); 284 285 PrefService* prefs = profile->GetPrefs(); 286 // The initial state is crashed; store for later reference. 287 std::string crash_value(prefs->GetString(prefs::kSessionExitType)); 288 289 // The first call to a type other than crashed should change the value. 290 profile->SetExitType(Profile::EXIT_SESSION_ENDED); 291 std::string first_call_value(prefs->GetString(prefs::kSessionExitType)); 292 EXPECT_NE(crash_value, first_call_value); 293 294 // Subsequent calls to a non-crash value should be ignored. 295 profile->SetExitType(Profile::EXIT_NORMAL); 296 std::string second_call_value(prefs->GetString(prefs::kSessionExitType)); 297 EXPECT_EQ(first_call_value, second_call_value); 298 299 // Setting back to a crashed value should work. 300 profile->SetExitType(Profile::EXIT_CRASHED); 301 std::string final_value(prefs->GetString(prefs::kSessionExitType)); 302 EXPECT_EQ(crash_value, final_value); 303 } 304 305 SpinThreads(); 306} 307