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.
5 #include "chrome/browser/profiles/profile.h"
7 #include "base/command_line.h"
8 #include "base/files/file_util.h"
9 #include "base/files/scoped_temp_dir.h"
10 #include "base/json/json_reader.h"
11 #include "base/logging.h"
12 #include "base/macros.h"
13 #include "base/memory/ref_counted.h"
14 #include "base/memory/scoped_ptr.h"
15 #include "base/prefs/pref_service.h"
16 #include "base/sequenced_task_runner.h"
17 #include "base/synchronization/waitable_event.h"
18 #include "base/values.h"
19 #include "base/version.h"
20 #include "chrome/browser/browser_process.h"
21 #include "chrome/browser/chrome_notification_types.h"
22 #include "chrome/browser/net/url_request_mock_util.h"
23 #include "chrome/browser/profiles/chrome_version_service.h"
24 #include "chrome/browser/profiles/profile_impl.h"
25 #include "chrome/browser/profiles/profile_manager.h"
26 #include "chrome/browser/ui/browser.h"
27 #include "chrome/browser/ui/tabs/tab_strip_model.h"
28 #include "chrome/common/chrome_constants.h"
29 #include "chrome/common/chrome_version_info.h"
30 #include "chrome/common/pref_names.h"
31 #include "chrome/test/base/in_process_browser_test.h"
32 #include "chrome/test/base/ui_test_utils.h"
33 #include "components/bookmarks/browser/startup_task_runner_service.h"
34 #include "content/public/browser/browser_thread.h"
35 #include "content/public/test/test_utils.h"
36 #include "net/base/net_errors.h"
37 #include "net/test/url_request/url_request_failed_job.h"
38 #include "net/url_request/url_fetcher.h"
39 #include "net/url_request/url_fetcher_delegate.h"
40 #include "net/url_request/url_request_context_getter.h"
41 #include "net/url_request/url_request_status.h"
42 #include "testing/gmock/include/gmock/gmock.h"
43 #include "testing/gtest/include/gtest/gtest.h"
46 #if defined(OS_CHROMEOS)
47 #include "chrome/browser/chromeos/profiles/profile_helper.h"
48 #include "chromeos/chromeos_switches.h"
53 // Simple URLFetcherDelegate with an expected final status and the ability to
54 // wait until a request completes. It's not considered a failure for the request
56 class TestURLFetcherDelegate
: public net::URLFetcherDelegate
{
58 // Creating the TestURLFetcherDelegate automatically creates and starts a
60 TestURLFetcherDelegate(
61 scoped_refptr
<net::URLRequestContextGetter
> context_getter
,
63 net::URLRequestStatus expected_request_status
)
64 : expected_request_status_(expected_request_status
),
66 fetcher_(net::URLFetcher::Create(url
, net::URLFetcher::GET
, this)) {
67 fetcher_
->SetRequestContext(context_getter
.get());
71 ~TestURLFetcherDelegate() override
{}
73 void OnURLFetchComplete(const net::URLFetcher
* source
) override
{
74 EXPECT_EQ(expected_request_status_
.status(), source
->GetStatus().status());
75 EXPECT_EQ(expected_request_status_
.error(), source
->GetStatus().error());
80 void WaitForCompletion() {
84 bool is_complete() const { return is_complete_
; }
87 const net::URLRequestStatus expected_request_status_
;
88 base::RunLoop run_loop_
;
91 scoped_ptr
<net::URLFetcher
> fetcher_
;
93 DISALLOW_COPY_AND_ASSIGN(TestURLFetcherDelegate
);
96 class MockProfileDelegate
: public Profile::Delegate
{
98 MOCK_METHOD1(OnPrefsLoaded
, void(Profile
*));
99 MOCK_METHOD3(OnProfileCreated
, void(Profile
*, bool, bool));
102 // Creates a prefs file in the given directory.
103 void CreatePrefsFileInDirectory(const base::FilePath
& directory_path
) {
104 base::FilePath
pref_path(directory_path
.Append(chrome::kPreferencesFilename
));
105 std::string
data("{}");
106 ASSERT_TRUE(base::WriteFile(pref_path
, data
.c_str(), data
.size()));
109 void CheckChromeVersion(Profile
*profile
, bool is_new
) {
110 std::string created_by_version
;
112 chrome::VersionInfo version_info
;
113 created_by_version
= version_info
.Version();
115 created_by_version
= "1.0.0.0";
117 std::string pref_version
=
118 ChromeVersionService::GetVersion(profile
->GetPrefs());
119 // Assert that created_by_version pref gets set to current version.
120 EXPECT_EQ(created_by_version
, pref_version
);
123 void FlushTaskRunner(base::SequencedTaskRunner
* runner
) {
125 base::WaitableEvent
unblock(false, false);
127 runner
->PostTask(FROM_HERE
,
128 base::Bind(&base::WaitableEvent::Signal
, base::Unretained(&unblock
)));
134 // Give threads a chance to do their stuff before shutting down (i.e.
135 // deleting scoped temp dir etc).
136 // Should not be necessary anymore once Profile deletion is fixed
137 // (see crbug.com/88586).
138 content::RunAllPendingInMessageLoop();
139 content::RunAllPendingInMessageLoop(content::BrowserThread::DB
);
140 content::RunAllPendingInMessageLoop(content::BrowserThread::FILE);
145 class ProfileBrowserTest
: public InProcessBrowserTest
{
147 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
148 #if defined(OS_CHROMEOS)
149 command_line
->AppendSwitch(
150 chromeos::switches::kIgnoreUserProfileMappingForTests
);
154 // content::BrowserTestBase implementation:
156 void SetUpOnMainThread() override
{
157 content::BrowserThread::PostTask(
158 content::BrowserThread::IO
, FROM_HERE
,
159 base::Bind(&chrome_browser_net::SetUrlRequestMocksEnabled
, true));
162 void TearDownOnMainThread() override
{
163 content::BrowserThread::PostTask(
164 content::BrowserThread::IO
, FROM_HERE
,
165 base::Bind(&chrome_browser_net::SetUrlRequestMocksEnabled
, false));
168 scoped_ptr
<Profile
> CreateProfile(
169 const base::FilePath
& path
,
170 Profile::Delegate
* delegate
,
171 Profile::CreateMode create_mode
) {
172 scoped_ptr
<Profile
> profile(Profile::CreateProfile(
173 path
, delegate
, create_mode
));
174 EXPECT_TRUE(profile
.get());
176 // Store the Profile's IO task runner so we can wind it down.
177 profile_io_task_runner_
= profile
->GetIOTaskRunner();
179 return profile
.Pass();
182 void FlushIoTaskRunnerAndSpinThreads() {
183 FlushTaskRunner(profile_io_task_runner_
.get());
187 // Starts a test where a URLFetcher is active during profile shutdown. The
188 // test completes during teardown of the test fixture. The request should be
189 // canceled by |context_getter| during profile shutdown, before the
190 // URLRequestContext is destroyed. If that doesn't happen, the Context's
191 // will still have oustanding requests during its destruction, and will
192 // trigger a CHECK failure.
193 void StartActiveFetcherDuringProfileShutdownTest(
194 scoped_refptr
<net::URLRequestContextGetter
> context_getter
) {
195 // This method should only be called once per test.
196 DCHECK(!url_fetcher_delegate_
);
198 // Start a hanging request. This request may or may not completed before
199 // the end of the request.
200 url_fetcher_delegate_
.reset(new TestURLFetcherDelegate(
201 context_getter
.get(),
202 net::URLRequestFailedJob::GetMockHttpUrl(net::ERR_IO_PENDING
),
203 net::URLRequestStatus(net::URLRequestStatus::CANCELED
,
204 net::ERR_CONTEXT_SHUT_DOWN
)));
206 // Start a second mock request that just fails, and wait for it to complete.
207 // This ensures the first request has reached the network stack.
208 TestURLFetcherDelegate
url_fetcher_delegate2(
209 context_getter
.get(),
210 net::URLRequestFailedJob::GetMockHttpUrl(net::ERR_FAILED
),
211 net::URLRequestStatus(net::URLRequestStatus::FAILED
,
213 url_fetcher_delegate2
.WaitForCompletion();
215 // The first request should still be hung.
216 EXPECT_FALSE(url_fetcher_delegate_
->is_complete());
219 // Runs a test where an incognito profile's URLFetcher is active during
220 // teardown of the profile, and makes sure the request fails as expected.
221 // Also tries issuing a request after the incognito profile has been
223 static void RunURLFetcherActiveDuringIncognitoTeardownTest(
224 Browser
* incognito_browser
,
225 scoped_refptr
<net::URLRequestContextGetter
> context_getter
) {
226 // Start a hanging request.
227 TestURLFetcherDelegate
url_fetcher_delegate1(
228 context_getter
.get(),
229 net::URLRequestFailedJob::GetMockHttpUrl(net::ERR_IO_PENDING
),
230 net::URLRequestStatus(net::URLRequestStatus::CANCELED
,
231 net::ERR_CONTEXT_SHUT_DOWN
));
233 // Start a second mock request that just fails, and wait for it to complete.
234 // This ensures the first request has reached the network stack.
235 TestURLFetcherDelegate
url_fetcher_delegate2(
236 context_getter
.get(),
237 net::URLRequestFailedJob::GetMockHttpUrl(net::ERR_FAILED
),
238 net::URLRequestStatus(net::URLRequestStatus::FAILED
,
240 url_fetcher_delegate2
.WaitForCompletion();
242 // The first request should still be hung.
243 EXPECT_FALSE(url_fetcher_delegate1
.is_complete());
245 // Close all incognito tabs, starting profile shutdown.
246 incognito_browser
->tab_strip_model()->CloseAllTabs();
248 // The request should have been canceled when the Profile shut down.
249 url_fetcher_delegate1
.WaitForCompletion();
251 // Requests issued after Profile shutdown should fail in a similar manner.
252 TestURLFetcherDelegate
url_fetcher_delegate3(
253 context_getter
.get(),
254 net::URLRequestFailedJob::GetMockHttpUrl(net::ERR_IO_PENDING
),
255 net::URLRequestStatus(net::URLRequestStatus::CANCELED
,
256 net::ERR_CONTEXT_SHUT_DOWN
));
257 url_fetcher_delegate3
.WaitForCompletion();
260 scoped_refptr
<base::SequencedTaskRunner
> profile_io_task_runner_
;
262 // URLFetcherDelegate that outlives the Profile, to test shutdown.
263 scoped_ptr
<TestURLFetcherDelegate
> url_fetcher_delegate_
;
266 // Test OnProfileCreate is called with is_new_profile set to true when
267 // creating a new profile synchronously.
268 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest
, CreateNewProfileSynchronous
) {
269 base::ScopedTempDir temp_dir
;
270 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
272 MockProfileDelegate delegate
;
273 EXPECT_CALL(delegate
, OnProfileCreated(testing::NotNull(), true, true));
276 scoped_ptr
<Profile
> profile(CreateProfile(
277 temp_dir
.path(), &delegate
, Profile::CREATE_MODE_SYNCHRONOUS
));
278 CheckChromeVersion(profile
.get(), true);
281 FlushIoTaskRunnerAndSpinThreads();
284 // Test OnProfileCreate is called with is_new_profile set to false when
285 // creating a profile synchronously with an existing prefs file.
286 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest
, CreateOldProfileSynchronous
) {
287 base::ScopedTempDir temp_dir
;
288 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
289 CreatePrefsFileInDirectory(temp_dir
.path());
291 MockProfileDelegate delegate
;
292 EXPECT_CALL(delegate
, OnProfileCreated(testing::NotNull(), true, false));
295 scoped_ptr
<Profile
> profile(CreateProfile(
296 temp_dir
.path(), &delegate
, Profile::CREATE_MODE_SYNCHRONOUS
));
297 CheckChromeVersion(profile
.get(), false);
300 FlushIoTaskRunnerAndSpinThreads();
303 // Flaky: http://crbug.com/393177
304 // Test OnProfileCreate is called with is_new_profile set to true when
305 // creating a new profile asynchronously.
306 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest
,
307 DISABLED_CreateNewProfileAsynchronous
) {
308 base::ScopedTempDir temp_dir
;
309 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
311 MockProfileDelegate delegate
;
312 EXPECT_CALL(delegate
, OnProfileCreated(testing::NotNull(), true, true));
315 content::WindowedNotificationObserver
observer(
316 chrome::NOTIFICATION_PROFILE_CREATED
,
317 content::NotificationService::AllSources());
319 scoped_ptr
<Profile
> profile(CreateProfile(
320 temp_dir
.path(), &delegate
, Profile::CREATE_MODE_ASYNCHRONOUS
));
322 // Wait for the profile to be created.
324 CheckChromeVersion(profile
.get(), true);
327 FlushIoTaskRunnerAndSpinThreads();
331 // Flaky: http://crbug.com/393177
332 // Test OnProfileCreate is called with is_new_profile set to false when
333 // creating a profile asynchronously with an existing prefs file.
334 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest
,
335 DISABLED_CreateOldProfileAsynchronous
) {
336 base::ScopedTempDir temp_dir
;
337 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
338 CreatePrefsFileInDirectory(temp_dir
.path());
340 MockProfileDelegate delegate
;
341 EXPECT_CALL(delegate
, OnProfileCreated(testing::NotNull(), true, false));
344 content::WindowedNotificationObserver
observer(
345 chrome::NOTIFICATION_PROFILE_CREATED
,
346 content::NotificationService::AllSources());
348 scoped_ptr
<Profile
> profile(CreateProfile(
349 temp_dir
.path(), &delegate
, Profile::CREATE_MODE_ASYNCHRONOUS
));
351 // Wait for the profile to be created.
353 CheckChromeVersion(profile
.get(), false);
356 FlushIoTaskRunnerAndSpinThreads();
359 // Flaky: http://crbug.com/393177
360 // Test that a README file is created for profiles that didn't have it.
361 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest
, DISABLED_ProfileReadmeCreated
) {
362 base::ScopedTempDir temp_dir
;
363 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
365 MockProfileDelegate delegate
;
366 EXPECT_CALL(delegate
, OnProfileCreated(testing::NotNull(), true, true));
369 content::WindowedNotificationObserver
observer(
370 chrome::NOTIFICATION_PROFILE_CREATED
,
371 content::NotificationService::AllSources());
373 scoped_ptr
<Profile
> profile(CreateProfile(
374 temp_dir
.path(), &delegate
, Profile::CREATE_MODE_ASYNCHRONOUS
));
376 // Wait for the profile to be created.
379 // Verify that README exists.
380 EXPECT_TRUE(base::PathExists(
381 temp_dir
.path().Append(chrome::kReadmeFilename
)));
384 FlushIoTaskRunnerAndSpinThreads();
387 // Test that repeated setting of exit type is handled correctly.
388 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest
, ExitType
) {
389 base::ScopedTempDir temp_dir
;
390 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
392 MockProfileDelegate delegate
;
393 EXPECT_CALL(delegate
, OnProfileCreated(testing::NotNull(), true, true));
395 scoped_ptr
<Profile
> profile(CreateProfile(
396 temp_dir
.path(), &delegate
, Profile::CREATE_MODE_SYNCHRONOUS
));
398 PrefService
* prefs
= profile
->GetPrefs();
399 // The initial state is crashed; store for later reference.
400 std::string
crash_value(prefs
->GetString(prefs::kSessionExitType
));
402 // The first call to a type other than crashed should change the value.
403 profile
->SetExitType(Profile::EXIT_SESSION_ENDED
);
404 std::string
first_call_value(prefs
->GetString(prefs::kSessionExitType
));
405 EXPECT_NE(crash_value
, first_call_value
);
407 // Subsequent calls to a non-crash value should be ignored.
408 profile
->SetExitType(Profile::EXIT_NORMAL
);
409 std::string
second_call_value(prefs
->GetString(prefs::kSessionExitType
));
410 EXPECT_EQ(first_call_value
, second_call_value
);
412 // Setting back to a crashed value should work.
413 profile
->SetExitType(Profile::EXIT_CRASHED
);
414 std::string
final_value(prefs
->GetString(prefs::kSessionExitType
));
415 EXPECT_EQ(crash_value
, final_value
);
418 FlushIoTaskRunnerAndSpinThreads();
421 // The EndSession IO synchronization is only critical on Windows, but also
422 // happens under the USE_X11 define. See BrowserProcessImpl::EndSession.
423 #if defined(USE_X11) || defined(OS_WIN) || defined(USE_OZONE)
427 std::string
GetExitTypePreferenceFromDisk(Profile
* profile
) {
428 base::FilePath prefs_path
=
429 profile
->GetPath().Append(chrome::kPreferencesFilename
);
431 if (!base::ReadFileToString(prefs_path
, &prefs
))
432 return std::string();
434 scoped_ptr
<base::Value
> value
= base::JSONReader::Read(prefs
);
436 return std::string();
438 base::DictionaryValue
* dict
= NULL
;
439 if (!value
->GetAsDictionary(&dict
) || !dict
)
440 return std::string();
442 std::string exit_type
;
443 if (!dict
->GetString("profile.exit_type", &exit_type
))
444 return std::string();
451 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest
,
452 WritesProfilesSynchronouslyOnEndSession
) {
453 base::ScopedTempDir temp_dir
;
454 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
456 ProfileManager
* profile_manager
= g_browser_process
->profile_manager();
457 ASSERT_TRUE(profile_manager
);
458 std::vector
<Profile
*> loaded_profiles
= profile_manager
->GetLoadedProfiles();
460 ASSERT_NE(loaded_profiles
.size(), 0UL);
461 Profile
* profile
= loaded_profiles
[0];
463 #if defined(OS_CHROMEOS)
464 for (const auto& loaded_profile
: loaded_profiles
) {
465 if (!chromeos::ProfileHelper::IsSigninProfile(loaded_profile
)) {
466 profile
= loaded_profile
;
472 // This retry loop reduces flakiness due to the fact that this ultimately
473 // tests whether or not a code path hits a timed wait.
474 bool succeeded
= false;
475 for (size_t retries
= 0; !succeeded
&& retries
< 3; ++retries
) {
476 // Flush the profile data to disk for all loaded profiles.
477 profile
->SetExitType(Profile::EXIT_CRASHED
);
478 profile
->GetPrefs()->CommitPendingWrite();
479 FlushTaskRunner(profile
->GetIOTaskRunner().get());
481 // Make sure that the prefs file was written with the expected key/value.
482 ASSERT_EQ(GetExitTypePreferenceFromDisk(profile
), "Crashed");
484 // The blocking wait in EndSession has a timeout.
485 base::Time start
= base::Time::Now();
487 // This must not return until the profile data has been written to disk.
488 // If this test flakes, then logoff on Windows has broken again.
489 g_browser_process
->EndSession();
491 base::Time end
= base::Time::Now();
493 // The EndSession timeout is 10 seconds. If we take more than half that,
494 // go around again, as we may have timed out on the wait.
495 // This helps against flakes, and also ensures that if the IO thread starts
496 // blocking systemically for that length of time (e.g. deadlocking or such),
497 // we'll get a consistent test failure.
498 if (end
- start
> base::TimeDelta::FromSeconds(5))
501 // Make sure that the prefs file was written with the expected key/value.
502 ASSERT_EQ(GetExitTypePreferenceFromDisk(profile
), "SessionEnded");
508 ASSERT_TRUE(succeeded
) << "profile->EndSession() timed out too often.";
511 #endif // defined(USE_X11) || defined(OS_WIN) || defined(USE_OZONE)
513 // The following tests make sure that it's safe to shut down while one of the
514 // Profile's URLRequestContextGetters is in use by a URLFetcher.
516 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest
,
517 URLFetcherUsingMainContextDuringShutdown
) {
518 StartActiveFetcherDuringProfileShutdownTest(
519 browser()->profile()->GetRequestContext());
522 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest
,
523 URLFetcherUsingMediaContextDuringShutdown
) {
524 StartActiveFetcherDuringProfileShutdownTest(
525 browser()->profile()->GetMediaRequestContext());
528 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest
,
529 URLFetcherUsingExtensionContextDuringShutdown
) {
530 StartActiveFetcherDuringProfileShutdownTest(
531 browser()->profile()->GetRequestContextForExtensions());
534 // The following tests make sure that it's safe to destroy an incognito profile
535 // while one of the its URLRequestContextGetters is in use by a URLFetcher.
537 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest
,
538 URLFetcherUsingMainContextDuringIncognitoTeardown
) {
539 Browser
* incognito_browser
=
540 OpenURLOffTheRecord(browser()->profile(), GURL("about:blank"));
541 RunURLFetcherActiveDuringIncognitoTeardownTest(
542 incognito_browser
, incognito_browser
->profile()->GetRequestContext());
545 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest
,
546 URLFetcherUsingExtensionContextDuringIncognitoTeardown
) {
547 Browser
* incognito_browser
=
548 OpenURLOffTheRecord(browser()->profile(), GURL("about:blank"));
550 RunURLFetcherActiveDuringIncognitoTeardownTest(
552 incognito_browser
->profile()->GetRequestContextForExtensions());