Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/profiles/profile.h" | 5 #include "chrome/browser/profiles/profile.h" |
| 6 | 6 |
| 7 #include "base/command_line.h" | 7 #include "base/command_line.h" |
| 8 #include "base/files/file_util.h" | 8 #include "base/files/file_util.h" |
| 9 #include "base/files/scoped_temp_dir.h" | 9 #include "base/files/scoped_temp_dir.h" |
| 10 #include "base/json/json_reader.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" | |
| 11 #include "base/prefs/pref_service.h" | 15 #include "base/prefs/pref_service.h" |
| 12 #include "base/sequenced_task_runner.h" | 16 #include "base/sequenced_task_runner.h" |
| 13 #include "base/synchronization/waitable_event.h" | 17 #include "base/synchronization/waitable_event.h" |
| 14 #include "base/values.h" | 18 #include "base/values.h" |
| 15 #include "base/version.h" | 19 #include "base/version.h" |
| 16 #include "chrome/browser/browser_process.h" | 20 #include "chrome/browser/browser_process.h" |
| 17 #include "chrome/browser/chrome_notification_types.h" | 21 #include "chrome/browser/chrome_notification_types.h" |
| 22 #include "chrome/browser/net/url_request_mock_util.h" | |
| 18 #include "chrome/browser/profiles/chrome_version_service.h" | 23 #include "chrome/browser/profiles/chrome_version_service.h" |
| 19 #include "chrome/browser/profiles/profile_impl.h" | 24 #include "chrome/browser/profiles/profile_impl.h" |
| 20 #include "chrome/browser/profiles/profile_manager.h" | 25 #include "chrome/browser/profiles/profile_manager.h" |
| 21 #include "chrome/browser/profiles/startup_task_runner_service.h" | 26 #include "chrome/browser/profiles/startup_task_runner_service.h" |
| 22 #include "chrome/browser/profiles/startup_task_runner_service_factory.h" | 27 #include "chrome/browser/profiles/startup_task_runner_service_factory.h" |
| 28 #include "chrome/browser/ui/browser.h" | |
| 29 #include "chrome/browser/ui/tabs/tab_strip_model.h" | |
| 23 #include "chrome/common/chrome_constants.h" | 30 #include "chrome/common/chrome_constants.h" |
| 24 #include "chrome/common/chrome_version_info.h" | 31 #include "chrome/common/chrome_version_info.h" |
| 25 #include "chrome/common/pref_names.h" | 32 #include "chrome/common/pref_names.h" |
| 26 #include "chrome/test/base/in_process_browser_test.h" | 33 #include "chrome/test/base/in_process_browser_test.h" |
| 34 #include "chrome/test/base/ui_test_utils.h" | |
| 35 #include "content/public/browser/browser_thread.h" | |
| 27 #include "content/public/test/test_utils.h" | 36 #include "content/public/test/test_utils.h" |
| 37 #include "net/base/net_errors.h" | |
| 38 #include "net/test/url_request/url_request_failed_job.h" | |
| 39 #include "net/url_request/url_fetcher.h" | |
| 40 #include "net/url_request/url_fetcher_delegate.h" | |
| 41 #include "net/url_request/url_request_context_getter.h" | |
| 42 #include "net/url_request/url_request_status.h" | |
| 28 #include "testing/gmock/include/gmock/gmock.h" | 43 #include "testing/gmock/include/gmock/gmock.h" |
| 29 #include "testing/gtest/include/gtest/gtest.h" | 44 #include "testing/gtest/include/gtest/gtest.h" |
| 45 #include "url/gurl.h" | |
| 30 | 46 |
| 31 #if defined(OS_CHROMEOS) | 47 #if defined(OS_CHROMEOS) |
| 32 #include "chrome/browser/chromeos/profiles/profile_helper.h" | 48 #include "chrome/browser/chromeos/profiles/profile_helper.h" |
| 33 #include "chromeos/chromeos_switches.h" | 49 #include "chromeos/chromeos_switches.h" |
| 34 #endif | 50 #endif |
| 35 | 51 |
| 36 namespace { | 52 namespace { |
| 37 | 53 |
| 54 // Simple URLFetcherDelegate with an expected final status and the ability to | |
| 55 // wait until a request completes. It's not considered a failure for the request | |
| 56 // to never complete. | |
|
davidben
2015/05/14 17:09:27
This comment is a little confusing since the metho
mmenke
2015/05/14 19:23:52
Done - I think the last sentence is a bit unexpect
| |
| 57 class TestURLFetcherDelegate : public net::URLFetcherDelegate { | |
| 58 public: | |
| 59 // Creating the TestURLFetcherDelegate automatically creates and starts a | |
| 60 // URLFetcher. | |
| 61 TestURLFetcherDelegate( | |
| 62 scoped_refptr<net::URLRequestContextGetter> context_getter, | |
| 63 const GURL& url, | |
| 64 net::URLRequestStatus expected_request_status) | |
| 65 : expected_request_status_(expected_request_status), | |
| 66 is_complete_(false), | |
| 67 fetcher_(net::URLFetcher::Create(url, net::URLFetcher::GET, this)) { | |
| 68 fetcher_->SetRequestContext(context_getter.get()); | |
| 69 fetcher_->Start(); | |
| 70 } | |
| 71 | |
| 72 ~TestURLFetcherDelegate() override {} | |
| 73 | |
| 74 void OnURLFetchComplete(const net::URLFetcher* source) override { | |
| 75 EXPECT_EQ(expected_request_status_.status(), source->GetStatus().status()); | |
| 76 EXPECT_EQ(expected_request_status_.error(), source->GetStatus().error()); | |
| 77 | |
| 78 run_loop_.Quit(); | |
| 79 } | |
| 80 | |
| 81 void WaitForCompletion() { | |
| 82 run_loop_.Run(); | |
| 83 } | |
| 84 | |
| 85 bool is_complete() const { return is_complete_; } | |
| 86 | |
| 87 private: | |
| 88 const net::URLRequestStatus expected_request_status_; | |
| 89 base::RunLoop run_loop_; | |
| 90 | |
| 91 bool is_complete_; | |
| 92 scoped_ptr<net::URLFetcher> fetcher_; | |
| 93 | |
| 94 DISALLOW_COPY_AND_ASSIGN(TestURLFetcherDelegate); | |
| 95 }; | |
| 96 | |
| 38 class MockProfileDelegate : public Profile::Delegate { | 97 class MockProfileDelegate : public Profile::Delegate { |
| 39 public: | 98 public: |
| 40 MOCK_METHOD1(OnPrefsLoaded, void(Profile*)); | 99 MOCK_METHOD1(OnPrefsLoaded, void(Profile*)); |
| 41 MOCK_METHOD3(OnProfileCreated, void(Profile*, bool, bool)); | 100 MOCK_METHOD3(OnProfileCreated, void(Profile*, bool, bool)); |
| 42 }; | 101 }; |
| 43 | 102 |
| 44 // Creates a prefs file in the given directory. | 103 // Creates a prefs file in the given directory. |
| 45 void CreatePrefsFileInDirectory(const base::FilePath& directory_path) { | 104 void CreatePrefsFileInDirectory(const base::FilePath& directory_path) { |
| 46 base::FilePath pref_path(directory_path.Append(chrome::kPreferencesFilename)); | 105 base::FilePath pref_path(directory_path.Append(chrome::kPreferencesFilename)); |
| 47 std::string data("{}"); | 106 std::string data("{}"); |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 93 | 152 |
| 94 class ProfileBrowserTest : public InProcessBrowserTest { | 153 class ProfileBrowserTest : public InProcessBrowserTest { |
| 95 protected: | 154 protected: |
| 96 void SetUpCommandLine(base::CommandLine* command_line) override { | 155 void SetUpCommandLine(base::CommandLine* command_line) override { |
| 97 #if defined(OS_CHROMEOS) | 156 #if defined(OS_CHROMEOS) |
| 98 command_line->AppendSwitch( | 157 command_line->AppendSwitch( |
| 99 chromeos::switches::kIgnoreUserProfileMappingForTests); | 158 chromeos::switches::kIgnoreUserProfileMappingForTests); |
| 100 #endif | 159 #endif |
| 101 } | 160 } |
| 102 | 161 |
| 162 // content::BrowserTestBase implementation: | |
| 163 | |
| 164 void SetUpOnMainThread() override { | |
| 165 content::BrowserThread::PostTask( | |
| 166 content::BrowserThread::IO, FROM_HERE, | |
| 167 base::Bind(&chrome_browser_net::SetUrlRequestMocksEnabled, true)); | |
| 168 } | |
| 169 | |
| 170 void TearDownOnMainThread() override { | |
| 171 content::BrowserThread::PostTask( | |
| 172 content::BrowserThread::IO, FROM_HERE, | |
| 173 base::Bind(&chrome_browser_net::SetUrlRequestMocksEnabled, false)); | |
| 174 } | |
| 175 | |
| 103 scoped_ptr<Profile> CreateProfile( | 176 scoped_ptr<Profile> CreateProfile( |
| 104 const base::FilePath& path, | 177 const base::FilePath& path, |
| 105 Profile::Delegate* delegate, | 178 Profile::Delegate* delegate, |
| 106 Profile::CreateMode create_mode) { | 179 Profile::CreateMode create_mode) { |
| 107 scoped_ptr<Profile> profile(Profile::CreateProfile( | 180 scoped_ptr<Profile> profile(Profile::CreateProfile( |
| 108 path, delegate, create_mode)); | 181 path, delegate, create_mode)); |
| 109 EXPECT_TRUE(profile.get()); | 182 EXPECT_TRUE(profile.get()); |
| 110 | 183 |
| 111 // Store the Profile's IO task runner so we can wind it down. | 184 // Store the Profile's IO task runner so we can wind it down. |
| 112 profile_io_task_runner_ = profile->GetIOTaskRunner(); | 185 profile_io_task_runner_ = profile->GetIOTaskRunner(); |
| 113 | 186 |
| 114 return profile.Pass(); | 187 return profile.Pass(); |
| 115 } | 188 } |
| 116 | 189 |
| 117 void FlushIoTaskRunnerAndSpinThreads() { | 190 void FlushIoTaskRunnerAndSpinThreads() { |
| 118 FlushTaskRunner(profile_io_task_runner_.get()); | 191 FlushTaskRunner(profile_io_task_runner_.get()); |
| 119 SpinThreads(); | 192 SpinThreads(); |
| 120 } | 193 } |
| 121 | 194 |
| 195 // Starts a test where a URLFetcher is active during profile shutdown. The | |
| 196 // test completes during teardown of the test fixture. The request should be | |
| 197 // canceled by |context_getter| during profile shutdown, before the | |
| 198 // URLRequestContext is destroyed. If that doesn't happen, the Context's | |
| 199 // will still have oustanding requests during its destruction, and will | |
| 200 // trigger a CHECK failure. | |
| 201 void StartActiveFetcherDuringProfileShutdownTest( | |
| 202 scoped_refptr<net::URLRequestContextGetter> context_getter) { | |
| 203 // This method should only be called once per test. | |
| 204 DCHECK(!url_fetcher_delegate_); | |
| 205 | |
| 206 // Start a hanging request. This request may or may not completed before | |
| 207 // the end of the request. | |
| 208 url_fetcher_delegate_.reset(new TestURLFetcherDelegate( | |
| 209 context_getter.get(), | |
| 210 net::URLRequestFailedJob::GetMockHttpUrl(net::ERR_IO_PENDING), | |
| 211 net::URLRequestStatus(net::URLRequestStatus::CANCELED, | |
| 212 net::ERR_CONTEXT_SHUT_DOWN))); | |
| 213 | |
| 214 // Start a second mock request that just fails, and wait for it to complete. | |
| 215 // This ensures the first request has reached the network stack. | |
| 216 TestURLFetcherDelegate url_fetcher_delegate2( | |
| 217 context_getter.get(), | |
| 218 net::URLRequestFailedJob::GetMockHttpUrl(net::ERR_FAILED), | |
| 219 net::URLRequestStatus(net::URLRequestStatus::FAILED, | |
| 220 net::ERR_FAILED)); | |
| 221 url_fetcher_delegate2.WaitForCompletion(); | |
|
davidben
2015/05/14 17:09:27
[Just to confirm, without this line, the test stil
mmenke
2015/05/14 19:23:52
Discussed this offline, clarified comment.
| |
| 222 | |
| 223 // The first request should still be hung. | |
| 224 EXPECT_FALSE(url_fetcher_delegate_->is_complete()); | |
| 225 } | |
| 226 | |
| 227 // Runs a test where an incognito profile's URLFetcher is active during | |
| 228 // teardown of the profile, and makes sure the request fails as expected. | |
| 229 // Also tries issuing a request after the incognito profile has been | |
| 230 // destroyed. | |
| 231 static void RunURLFetcherActiveDuringIncognitoTeardownTest( | |
| 232 Browser* incognito_browser, | |
| 233 scoped_refptr<net::URLRequestContextGetter> context_getter) { | |
| 234 // Start a hanging request. | |
| 235 TestURLFetcherDelegate url_fetcher_delegate1( | |
| 236 context_getter.get(), | |
| 237 net::URLRequestFailedJob::GetMockHttpUrl(net::ERR_IO_PENDING), | |
| 238 net::URLRequestStatus(net::URLRequestStatus::CANCELED, | |
| 239 net::ERR_CONTEXT_SHUT_DOWN)); | |
| 240 | |
| 241 // Start a second mock request that just fails, and wait for it to complete. | |
| 242 // This ensures the first request has reached the network stack. | |
| 243 TestURLFetcherDelegate url_fetcher_delegate2( | |
| 244 context_getter.get(), | |
| 245 net::URLRequestFailedJob::GetMockHttpUrl(net::ERR_FAILED), | |
| 246 net::URLRequestStatus(net::URLRequestStatus::FAILED, | |
| 247 net::ERR_FAILED)); | |
| 248 url_fetcher_delegate2.WaitForCompletion(); | |
| 249 | |
| 250 // The first request should still be hung. | |
| 251 EXPECT_FALSE(url_fetcher_delegate1.is_complete()); | |
| 252 | |
| 253 // Close all incognito tabs, starting profile shutdown. | |
| 254 incognito_browser->tab_strip_model()->CloseAllTabs(); | |
| 255 | |
| 256 // The request should have been canceled when the Profile shut down. | |
| 257 url_fetcher_delegate1.WaitForCompletion(); | |
| 258 | |
| 259 // Requests issued after Profile shutdown should fail in a similar manner. | |
| 260 TestURLFetcherDelegate url_fetcher_delegate3( | |
| 261 context_getter.get(), | |
| 262 net::URLRequestFailedJob::GetMockHttpUrl(net::ERR_IO_PENDING), | |
| 263 net::URLRequestStatus(net::URLRequestStatus::CANCELED, | |
| 264 net::ERR_CONTEXT_SHUT_DOWN)); | |
| 265 url_fetcher_delegate3.WaitForCompletion(); | |
| 266 } | |
| 267 | |
| 122 scoped_refptr<base::SequencedTaskRunner> profile_io_task_runner_; | 268 scoped_refptr<base::SequencedTaskRunner> profile_io_task_runner_; |
| 269 | |
| 270 // URLFetcherDelegate that outlives the Profile, to test shutdown. | |
| 271 scoped_ptr<TestURLFetcherDelegate> url_fetcher_delegate_; | |
| 123 }; | 272 }; |
| 124 | 273 |
| 125 // Test OnProfileCreate is called with is_new_profile set to true when | 274 // Test OnProfileCreate is called with is_new_profile set to true when |
| 126 // creating a new profile synchronously. | 275 // creating a new profile synchronously. |
| 127 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, CreateNewProfileSynchronous) { | 276 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, CreateNewProfileSynchronous) { |
| 128 base::ScopedTempDir temp_dir; | 277 base::ScopedTempDir temp_dir; |
| 129 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); | 278 ASSERT_TRUE(temp_dir.CreateUniqueTempDir()); |
| 130 | 279 |
| 131 MockProfileDelegate delegate; | 280 MockProfileDelegate delegate; |
| 132 EXPECT_CALL(delegate, OnProfileCreated(testing::NotNull(), true, true)); | 281 EXPECT_CALL(delegate, OnProfileCreated(testing::NotNull(), true, true)); |
| (...skipping 269 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 402 ASSERT_EQ(GetExitTypePreferenceFromDisk(profile), "SessionEnded"); | 551 ASSERT_EQ(GetExitTypePreferenceFromDisk(profile), "SessionEnded"); |
| 403 | 552 |
| 404 // Mark the success. | 553 // Mark the success. |
| 405 succeeded = true; | 554 succeeded = true; |
| 406 } | 555 } |
| 407 | 556 |
| 408 ASSERT_TRUE(succeeded) << "profile->EndSession() timed out too often."; | 557 ASSERT_TRUE(succeeded) << "profile->EndSession() timed out too often."; |
| 409 } | 558 } |
| 410 | 559 |
| 411 #endif // defined(USE_X11) || defined(OS_WIN) || defined(USE_OZONE) | 560 #endif // defined(USE_X11) || defined(OS_WIN) || defined(USE_OZONE) |
| 561 | |
| 562 // The following tests make sure that it's safe to shut down while one of the | |
| 563 // Profile's URLRequestContextGetters is in use by a URLFetcher. | |
| 564 | |
| 565 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, | |
| 566 URLFetcherUsingMainContextDuringShutdown) { | |
| 567 StartActiveFetcherDuringProfileShutdownTest( | |
| 568 browser()->profile()->GetRequestContext()); | |
| 569 } | |
| 570 | |
| 571 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, | |
| 572 URLFetcherUsingMediaContextDuringShutdown) { | |
| 573 StartActiveFetcherDuringProfileShutdownTest( | |
| 574 browser()->profile()->GetMediaRequestContext()); | |
| 575 } | |
| 576 | |
| 577 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, | |
| 578 URLFetcherUsingExtensionContextDuringShutdown) { | |
| 579 StartActiveFetcherDuringProfileShutdownTest( | |
| 580 browser()->profile()->GetRequestContextForExtensions()); | |
| 581 } | |
| 582 | |
| 583 // The following tests make sure that it's safe to destroy an incognito profile | |
| 584 // while one of the its URLRequestContextGetters is in use by a URLFetcher. | |
| 585 | |
| 586 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, | |
| 587 URLFetcherUsingMainContextDuringIncognitoTeardown) { | |
| 588 Browser* incognito_browser = | |
| 589 ui_test_utils::OpenURLOffTheRecord(browser()->profile(), | |
| 590 GURL("about:blank")); | |
| 591 RunURLFetcherActiveDuringIncognitoTeardownTest( | |
| 592 incognito_browser, incognito_browser->profile()->GetRequestContext()); | |
| 593 } | |
| 594 | |
| 595 IN_PROC_BROWSER_TEST_F(ProfileBrowserTest, | |
| 596 URLFetcherUsingExtensionContextDuringIncognitoTeardown) { | |
| 597 Browser* incognito_browser = | |
| 598 ui_test_utils::OpenURLOffTheRecord(browser()->profile(), | |
| 599 GURL("about:blank")); | |
| 600 RunURLFetcherActiveDuringIncognitoTeardownTest( | |
| 601 incognito_browser, | |
| 602 incognito_browser->profile()->GetRequestContextForExtensions()); | |
| 603 } | |
| OLD | NEW |