Pin Chrome's shortcut to the Win10 Start menu on install and OS upgrade.
[chromium-blink-merge.git] / chrome / browser / profiles / profile_browsertest.cc
blob362107a95029265dd4becfde7682e071b05694a2
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"
44 #include "url/gurl.h"
46 #if defined(OS_CHROMEOS)
47 #include "chrome/browser/chromeos/profiles/profile_helper.h"
48 #include "chromeos/chromeos_switches.h"
49 #endif
51 namespace {
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
55 // to never complete.
56 class TestURLFetcherDelegate : public net::URLFetcherDelegate {
57 public:
58 // Creating the TestURLFetcherDelegate automatically creates and starts a
59 // URLFetcher.
60 TestURLFetcherDelegate(
61 scoped_refptr<net::URLRequestContextGetter> context_getter,
62 const GURL& url,
63 net::URLRequestStatus expected_request_status)
64 : expected_request_status_(expected_request_status),
65 is_complete_(false),
66 fetcher_(net::URLFetcher::Create(url, net::URLFetcher::GET, this)) {
67 fetcher_->SetRequestContext(context_getter.get());
68 fetcher_->Start();
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());
77 run_loop_.Quit();
80 void WaitForCompletion() {
81 run_loop_.Run();
84 bool is_complete() const { return is_complete_; }
86 private:
87 const net::URLRequestStatus expected_request_status_;
88 base::RunLoop run_loop_;
90 bool is_complete_;
91 scoped_ptr<net::URLFetcher> fetcher_;
93 DISALLOW_COPY_AND_ASSIGN(TestURLFetcherDelegate);
96 class MockProfileDelegate : public Profile::Delegate {
97 public:
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;
111 if (is_new) {
112 chrome::VersionInfo version_info;
113 created_by_version = version_info.Version();
114 } else {
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) {
124 ASSERT_TRUE(runner);
125 base::WaitableEvent unblock(false, false);
127 runner->PostTask(FROM_HERE,
128 base::Bind(&base::WaitableEvent::Signal, base::Unretained(&unblock)));
130 unblock.Wait();
133 void SpinThreads() {
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);
143 } // namespace
145 class ProfileBrowserTest : public InProcessBrowserTest {
146 protected:
147 void SetUpCommandLine(base::CommandLine* command_line) override {
148 #if defined(OS_CHROMEOS)
149 command_line->AppendSwitch(
150 chromeos::switches::kIgnoreUserProfileMappingForTests);
151 #endif
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());
184 SpinThreads();
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,
212 net::ERR_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
222 // destroyed.
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,
239 net::ERR_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.
323 observer.Wait();
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.
352 observer.Wait();
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.
377 observer.Wait();
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)
425 namespace {
427 std::string GetExitTypePreferenceFromDisk(Profile* profile) {
428 base::FilePath prefs_path =
429 profile->GetPath().Append(chrome::kPreferencesFilename);
430 std::string prefs;
431 if (!base::ReadFileToString(prefs_path, &prefs))
432 return std::string();
434 scoped_ptr<base::Value> value = base::JSONReader::Read(prefs);
435 if (!value)
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();
446 return exit_type;
449 } // namespace
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;
467 break;
470 #endif
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))
499 continue;
501 // Make sure that the prefs file was written with the expected key/value.
502 ASSERT_EQ(GetExitTypePreferenceFromDisk(profile), "SessionEnded");
504 // Mark the success.
505 succeeded = true;
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(
551 incognito_browser,
552 incognito_browser->profile()->GetRequestContextForExtensions());