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/pref_names.h"
30 #include "chrome/test/base/in_process_browser_test.h"
31 #include "chrome/test/base/ui_test_utils.h"
32 #include "components/bookmarks/browser/startup_task_runner_service.h"
33 #include "components/version_info/version_info.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 created_by_version
= version_info::GetVersionNumber();
114 created_by_version
= "1.0.0.0";
116 std::string pref_version
=
117 ChromeVersionService::GetVersion(profile
->GetPrefs());
118 // Assert that created_by_version pref gets set to current version.
119 EXPECT_EQ(created_by_version
, pref_version
);
122 void FlushTaskRunner(base::SequencedTaskRunner
* runner
) {
124 base::WaitableEvent
unblock(false, false);
126 runner
->PostTask(FROM_HERE
,
127 base::Bind(&base::WaitableEvent::Signal
, base::Unretained(&unblock
)));
133 // Give threads a chance to do their stuff before shutting down (i.e.
134 // deleting scoped temp dir etc).
135 // Should not be necessary anymore once Profile deletion is fixed
136 // (see crbug.com/88586).
137 content::RunAllPendingInMessageLoop();
138 content::RunAllPendingInMessageLoop(content::BrowserThread::DB
);
139 content::RunAllPendingInMessageLoop(content::BrowserThread::FILE);
144 class ProfileBrowserTest
: public InProcessBrowserTest
{
146 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
147 #if defined(OS_CHROMEOS)
148 command_line
->AppendSwitch(
149 chromeos::switches::kIgnoreUserProfileMappingForTests
);
153 // content::BrowserTestBase implementation:
155 void SetUpOnMainThread() override
{
156 content::BrowserThread::PostTask(
157 content::BrowserThread::IO
, FROM_HERE
,
158 base::Bind(&chrome_browser_net::SetUrlRequestMocksEnabled
, true));
161 void TearDownOnMainThread() override
{
162 content::BrowserThread::PostTask(
163 content::BrowserThread::IO
, FROM_HERE
,
164 base::Bind(&chrome_browser_net::SetUrlRequestMocksEnabled
, false));
167 scoped_ptr
<Profile
> CreateProfile(
168 const base::FilePath
& path
,
169 Profile::Delegate
* delegate
,
170 Profile::CreateMode create_mode
) {
171 scoped_ptr
<Profile
> profile(Profile::CreateProfile(
172 path
, delegate
, create_mode
));
173 EXPECT_TRUE(profile
.get());
175 // Store the Profile's IO task runner so we can wind it down.
176 profile_io_task_runner_
= profile
->GetIOTaskRunner();
178 return profile
.Pass();
181 void FlushIoTaskRunnerAndSpinThreads() {
182 FlushTaskRunner(profile_io_task_runner_
.get());
186 // Starts a test where a URLFetcher is active during profile shutdown. The
187 // test completes during teardown of the test fixture. The request should be
188 // canceled by |context_getter| during profile shutdown, before the
189 // URLRequestContext is destroyed. If that doesn't happen, the Context's
190 // will still have oustanding requests during its destruction, and will
191 // trigger a CHECK failure.
192 void StartActiveFetcherDuringProfileShutdownTest(
193 scoped_refptr
<net::URLRequestContextGetter
> context_getter
) {
194 // This method should only be called once per test.
195 DCHECK(!url_fetcher_delegate_
);
197 // Start a hanging request. This request may or may not completed before
198 // the end of the request.
199 url_fetcher_delegate_
.reset(new TestURLFetcherDelegate(
200 context_getter
.get(),
201 net::URLRequestFailedJob::GetMockHttpUrl(net::ERR_IO_PENDING
),
202 net::URLRequestStatus(net::URLRequestStatus::CANCELED
,
203 net::ERR_CONTEXT_SHUT_DOWN
)));
205 // Start a second mock request that just fails, and wait for it to complete.
206 // This ensures the first request has reached the network stack.
207 TestURLFetcherDelegate
url_fetcher_delegate2(
208 context_getter
.get(),
209 net::URLRequestFailedJob::GetMockHttpUrl(net::ERR_FAILED
),
210 net::URLRequestStatus(net::URLRequestStatus::FAILED
,
212 url_fetcher_delegate2
.WaitForCompletion();
214 // The first request should still be hung.
215 EXPECT_FALSE(url_fetcher_delegate_
->is_complete());
218 // Runs a test where an incognito profile's URLFetcher is active during
219 // teardown of the profile, and makes sure the request fails as expected.
220 // Also tries issuing a request after the incognito profile has been
222 static void RunURLFetcherActiveDuringIncognitoTeardownTest(
223 Browser
* incognito_browser
,
224 scoped_refptr
<net::URLRequestContextGetter
> context_getter
) {
225 // Start a hanging request.
226 TestURLFetcherDelegate
url_fetcher_delegate1(
227 context_getter
.get(),
228 net::URLRequestFailedJob::GetMockHttpUrl(net::ERR_IO_PENDING
),
229 net::URLRequestStatus(net::URLRequestStatus::CANCELED
,
230 net::ERR_CONTEXT_SHUT_DOWN
));
232 // Start a second mock request that just fails, and wait for it to complete.
233 // This ensures the first request has reached the network stack.
234 TestURLFetcherDelegate
url_fetcher_delegate2(
235 context_getter
.get(),
236 net::URLRequestFailedJob::GetMockHttpUrl(net::ERR_FAILED
),
237 net::URLRequestStatus(net::URLRequestStatus::FAILED
,
239 url_fetcher_delegate2
.WaitForCompletion();
241 // The first request should still be hung.
242 EXPECT_FALSE(url_fetcher_delegate1
.is_complete());
244 // Close all incognito tabs, starting profile shutdown.
245 incognito_browser
->tab_strip_model()->CloseAllTabs();
247 // The request should have been canceled when the Profile shut down.
248 url_fetcher_delegate1
.WaitForCompletion();
250 // Requests issued after Profile shutdown should fail in a similar manner.
251 TestURLFetcherDelegate
url_fetcher_delegate3(
252 context_getter
.get(),
253 net::URLRequestFailedJob::GetMockHttpUrl(net::ERR_IO_PENDING
),
254 net::URLRequestStatus(net::URLRequestStatus::CANCELED
,
255 net::ERR_CONTEXT_SHUT_DOWN
));
256 url_fetcher_delegate3
.WaitForCompletion();
259 scoped_refptr
<base::SequencedTaskRunner
> profile_io_task_runner_
;
261 // URLFetcherDelegate that outlives the Profile, to test shutdown.
262 scoped_ptr
<TestURLFetcherDelegate
> url_fetcher_delegate_
;
265 // Test OnProfileCreate is called with is_new_profile set to true when
266 // creating a new profile synchronously.
267 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest
, CreateNewProfileSynchronous
) {
268 base::ScopedTempDir temp_dir
;
269 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
271 MockProfileDelegate delegate
;
272 EXPECT_CALL(delegate
, OnProfileCreated(testing::NotNull(), true, true));
275 scoped_ptr
<Profile
> profile(CreateProfile(
276 temp_dir
.path(), &delegate
, Profile::CREATE_MODE_SYNCHRONOUS
));
277 CheckChromeVersion(profile
.get(), true);
280 FlushIoTaskRunnerAndSpinThreads();
283 // Test OnProfileCreate is called with is_new_profile set to false when
284 // creating a profile synchronously with an existing prefs file.
285 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest
, CreateOldProfileSynchronous
) {
286 base::ScopedTempDir temp_dir
;
287 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
288 CreatePrefsFileInDirectory(temp_dir
.path());
290 MockProfileDelegate delegate
;
291 EXPECT_CALL(delegate
, OnProfileCreated(testing::NotNull(), true, false));
294 scoped_ptr
<Profile
> profile(CreateProfile(
295 temp_dir
.path(), &delegate
, Profile::CREATE_MODE_SYNCHRONOUS
));
296 CheckChromeVersion(profile
.get(), false);
299 FlushIoTaskRunnerAndSpinThreads();
302 // Flaky: http://crbug.com/393177
303 // Test OnProfileCreate is called with is_new_profile set to true when
304 // creating a new profile asynchronously.
305 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest
,
306 DISABLED_CreateNewProfileAsynchronous
) {
307 base::ScopedTempDir temp_dir
;
308 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
310 MockProfileDelegate delegate
;
311 EXPECT_CALL(delegate
, OnProfileCreated(testing::NotNull(), true, true));
314 content::WindowedNotificationObserver
observer(
315 chrome::NOTIFICATION_PROFILE_CREATED
,
316 content::NotificationService::AllSources());
318 scoped_ptr
<Profile
> profile(CreateProfile(
319 temp_dir
.path(), &delegate
, Profile::CREATE_MODE_ASYNCHRONOUS
));
321 // Wait for the profile to be created.
323 CheckChromeVersion(profile
.get(), true);
326 FlushIoTaskRunnerAndSpinThreads();
330 // Flaky: http://crbug.com/393177
331 // Test OnProfileCreate is called with is_new_profile set to false when
332 // creating a profile asynchronously with an existing prefs file.
333 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest
,
334 DISABLED_CreateOldProfileAsynchronous
) {
335 base::ScopedTempDir temp_dir
;
336 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
337 CreatePrefsFileInDirectory(temp_dir
.path());
339 MockProfileDelegate delegate
;
340 EXPECT_CALL(delegate
, OnProfileCreated(testing::NotNull(), true, false));
343 content::WindowedNotificationObserver
observer(
344 chrome::NOTIFICATION_PROFILE_CREATED
,
345 content::NotificationService::AllSources());
347 scoped_ptr
<Profile
> profile(CreateProfile(
348 temp_dir
.path(), &delegate
, Profile::CREATE_MODE_ASYNCHRONOUS
));
350 // Wait for the profile to be created.
352 CheckChromeVersion(profile
.get(), false);
355 FlushIoTaskRunnerAndSpinThreads();
358 // Flaky: http://crbug.com/393177
359 // Test that a README file is created for profiles that didn't have it.
360 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest
, DISABLED_ProfileReadmeCreated
) {
361 base::ScopedTempDir temp_dir
;
362 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
364 MockProfileDelegate delegate
;
365 EXPECT_CALL(delegate
, OnProfileCreated(testing::NotNull(), true, true));
368 content::WindowedNotificationObserver
observer(
369 chrome::NOTIFICATION_PROFILE_CREATED
,
370 content::NotificationService::AllSources());
372 scoped_ptr
<Profile
> profile(CreateProfile(
373 temp_dir
.path(), &delegate
, Profile::CREATE_MODE_ASYNCHRONOUS
));
375 // Wait for the profile to be created.
378 // Verify that README exists.
379 EXPECT_TRUE(base::PathExists(
380 temp_dir
.path().Append(chrome::kReadmeFilename
)));
383 FlushIoTaskRunnerAndSpinThreads();
386 // Test that repeated setting of exit type is handled correctly.
387 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest
, ExitType
) {
388 base::ScopedTempDir temp_dir
;
389 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
391 MockProfileDelegate delegate
;
392 EXPECT_CALL(delegate
, OnProfileCreated(testing::NotNull(), true, true));
394 scoped_ptr
<Profile
> profile(CreateProfile(
395 temp_dir
.path(), &delegate
, Profile::CREATE_MODE_SYNCHRONOUS
));
397 PrefService
* prefs
= profile
->GetPrefs();
398 // The initial state is crashed; store for later reference.
399 std::string
crash_value(prefs
->GetString(prefs::kSessionExitType
));
401 // The first call to a type other than crashed should change the value.
402 profile
->SetExitType(Profile::EXIT_SESSION_ENDED
);
403 std::string
first_call_value(prefs
->GetString(prefs::kSessionExitType
));
404 EXPECT_NE(crash_value
, first_call_value
);
406 // Subsequent calls to a non-crash value should be ignored.
407 profile
->SetExitType(Profile::EXIT_NORMAL
);
408 std::string
second_call_value(prefs
->GetString(prefs::kSessionExitType
));
409 EXPECT_EQ(first_call_value
, second_call_value
);
411 // Setting back to a crashed value should work.
412 profile
->SetExitType(Profile::EXIT_CRASHED
);
413 std::string
final_value(prefs
->GetString(prefs::kSessionExitType
));
414 EXPECT_EQ(crash_value
, final_value
);
417 FlushIoTaskRunnerAndSpinThreads();
420 // The EndSession IO synchronization is only critical on Windows, but also
421 // happens under the USE_X11 define. See BrowserProcessImpl::EndSession.
422 #if defined(USE_X11) || defined(OS_WIN) || defined(USE_OZONE)
426 std::string
GetExitTypePreferenceFromDisk(Profile
* profile
) {
427 base::FilePath prefs_path
=
428 profile
->GetPath().Append(chrome::kPreferencesFilename
);
430 if (!base::ReadFileToString(prefs_path
, &prefs
))
431 return std::string();
433 scoped_ptr
<base::Value
> value
= base::JSONReader::Read(prefs
);
435 return std::string();
437 base::DictionaryValue
* dict
= NULL
;
438 if (!value
->GetAsDictionary(&dict
) || !dict
)
439 return std::string();
441 std::string exit_type
;
442 if (!dict
->GetString("profile.exit_type", &exit_type
))
443 return std::string();
450 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest
,
451 WritesProfilesSynchronouslyOnEndSession
) {
452 base::ScopedTempDir temp_dir
;
453 ASSERT_TRUE(temp_dir
.CreateUniqueTempDir());
455 ProfileManager
* profile_manager
= g_browser_process
->profile_manager();
456 ASSERT_TRUE(profile_manager
);
457 std::vector
<Profile
*> loaded_profiles
= profile_manager
->GetLoadedProfiles();
459 ASSERT_NE(loaded_profiles
.size(), 0UL);
460 Profile
* profile
= loaded_profiles
[0];
462 #if defined(OS_CHROMEOS)
463 for (const auto& loaded_profile
: loaded_profiles
) {
464 if (!chromeos::ProfileHelper::IsSigninProfile(loaded_profile
)) {
465 profile
= loaded_profile
;
471 // This retry loop reduces flakiness due to the fact that this ultimately
472 // tests whether or not a code path hits a timed wait.
473 bool succeeded
= false;
474 for (size_t retries
= 0; !succeeded
&& retries
< 3; ++retries
) {
475 // Flush the profile data to disk for all loaded profiles.
476 profile
->SetExitType(Profile::EXIT_CRASHED
);
477 profile
->GetPrefs()->CommitPendingWrite();
478 FlushTaskRunner(profile
->GetIOTaskRunner().get());
480 // Make sure that the prefs file was written with the expected key/value.
481 ASSERT_EQ(GetExitTypePreferenceFromDisk(profile
), "Crashed");
483 // The blocking wait in EndSession has a timeout.
484 base::Time start
= base::Time::Now();
486 // This must not return until the profile data has been written to disk.
487 // If this test flakes, then logoff on Windows has broken again.
488 g_browser_process
->EndSession();
490 base::Time end
= base::Time::Now();
492 // The EndSession timeout is 10 seconds. If we take more than half that,
493 // go around again, as we may have timed out on the wait.
494 // This helps against flakes, and also ensures that if the IO thread starts
495 // blocking systemically for that length of time (e.g. deadlocking or such),
496 // we'll get a consistent test failure.
497 if (end
- start
> base::TimeDelta::FromSeconds(5))
500 // Make sure that the prefs file was written with the expected key/value.
501 ASSERT_EQ(GetExitTypePreferenceFromDisk(profile
), "SessionEnded");
507 ASSERT_TRUE(succeeded
) << "profile->EndSession() timed out too often.";
510 #endif // defined(USE_X11) || defined(OS_WIN) || defined(USE_OZONE)
512 // The following tests make sure that it's safe to shut down while one of the
513 // Profile's URLRequestContextGetters is in use by a URLFetcher.
515 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest
,
516 URLFetcherUsingMainContextDuringShutdown
) {
517 StartActiveFetcherDuringProfileShutdownTest(
518 browser()->profile()->GetRequestContext());
521 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest
,
522 URLFetcherUsingMediaContextDuringShutdown
) {
523 StartActiveFetcherDuringProfileShutdownTest(
524 browser()->profile()->GetMediaRequestContext());
527 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest
,
528 URLFetcherUsingExtensionContextDuringShutdown
) {
529 StartActiveFetcherDuringProfileShutdownTest(
530 browser()->profile()->GetRequestContextForExtensions());
533 // The following tests make sure that it's safe to destroy an incognito profile
534 // while one of the its URLRequestContextGetters is in use by a URLFetcher.
536 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest
,
537 URLFetcherUsingMainContextDuringIncognitoTeardown
) {
538 Browser
* incognito_browser
=
539 OpenURLOffTheRecord(browser()->profile(), GURL("about:blank"));
540 RunURLFetcherActiveDuringIncognitoTeardownTest(
541 incognito_browser
, incognito_browser
->profile()->GetRequestContext());
544 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest
,
545 URLFetcherUsingExtensionContextDuringIncognitoTeardown
) {
546 Browser
* incognito_browser
=
547 OpenURLOffTheRecord(browser()->profile(), GURL("about:blank"));
549 RunURLFetcherActiveDuringIncognitoTeardownTest(
551 incognito_browser
->profile()->GetRequestContextForExtensions());