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/chromeos/login/login_utils.h" | 5 #include "chrome/browser/chromeos/login/login_utils.h" |
6 | 6 |
7 #include "base/basictypes.h" | 7 #include "base/basictypes.h" |
8 #include "base/bind.h" | 8 #include "base/bind.h" |
9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
10 #include "base/message_loop.h" | 10 #include "base/message_loop.h" |
11 #include "base/path_service.h" | 11 #include "base/path_service.h" |
12 #include "base/scoped_temp_dir.h" | 12 #include "base/scoped_temp_dir.h" |
13 #include "base/string_util.h" | 13 #include "base/string_util.h" |
14 #include "base/synchronization/waitable_event.h" | |
14 #include "base/threading/sequenced_worker_pool.h" | 15 #include "base/threading/sequenced_worker_pool.h" |
16 #include "base/threading/thread.h" | |
15 #include "chrome/browser/chromeos/cros/cros_library.h" | 17 #include "chrome/browser/chromeos/cros/cros_library.h" |
16 #include "chrome/browser/chromeos/cros/mock_cryptohome_library.h" | 18 #include "chrome/browser/chromeos/cros/mock_cryptohome_library.h" |
17 #include "chrome/browser/chromeos/input_method/mock_input_method_manager.h" | 19 #include "chrome/browser/chromeos/input_method/mock_input_method_manager.h" |
18 #include "chrome/browser/chromeos/login/authenticator.h" | 20 #include "chrome/browser/chromeos/login/authenticator.h" |
19 #include "chrome/browser/chromeos/login/login_status_consumer.h" | 21 #include "chrome/browser/chromeos/login/login_status_consumer.h" |
20 #include "chrome/browser/chromeos/login/user_manager.h" | 22 #include "chrome/browser/chromeos/login/user_manager.h" |
21 #include "chrome/browser/chromeos/settings/device_settings_test_helper.h" | 23 #include "chrome/browser/chromeos/settings/device_settings_test_helper.h" |
22 #include "chrome/browser/io_thread.h" | 24 #include "chrome/browser/io_thread.h" |
23 #include "chrome/browser/net/predictor.h" | 25 #include "chrome/browser/net/predictor.h" |
24 #include "chrome/browser/policy/browser_policy_connector.h" | 26 #include "chrome/browser/policy/browser_policy_connector.h" |
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
87 "http://server/device_management?request=policy"; | 89 "http://server/device_management?request=policy"; |
88 | 90 |
89 const char kDMToken[] = "1234"; | 91 const char kDMToken[] = "1234"; |
90 | 92 |
91 // Used to mark |flag|, indicating that RefreshPolicies() has executed its | 93 // Used to mark |flag|, indicating that RefreshPolicies() has executed its |
92 // callback. | 94 // callback. |
93 void SetFlag(bool* flag) { | 95 void SetFlag(bool* flag) { |
94 *flag = true; | 96 *flag = true; |
95 } | 97 } |
96 | 98 |
99 // Single task of the fake IO loop used in the test, that just waits until | |
100 // it is signaled to quit or perform some work. | |
101 // |completion| is the event to wait for, and |work| is the task to invoke | |
102 // when signaled. If the task returns false then this quits the IO loop. | |
103 void BlockLoop(base::WaitableEvent* completion, base::Callback<bool()> work) { | |
104 do { | |
105 completion->Wait(); | |
Nikita (slow)
2012/11/13 10:11:33
Is this a recommended way to handle fake IO look l
Joao da Silva
2012/11/13 13:11:04
This is not common at all, as you suspected.
Othe
| |
106 } while (work.Run()); | |
107 MessageLoop::current()->QuitNow(); | |
108 } | |
109 | |
97 ACTION_P(MockSessionManagerClientRetrievePolicyCallback, policy) { | 110 ACTION_P(MockSessionManagerClientRetrievePolicyCallback, policy) { |
98 arg0.Run(*policy); | 111 arg0.Run(*policy); |
99 } | 112 } |
100 | 113 |
101 ACTION_P(MockSessionManagerClientStorePolicyCallback, success) { | 114 ACTION_P(MockSessionManagerClientStorePolicyCallback, success) { |
102 arg1.Run(success); | 115 arg1.Run(success); |
103 } | 116 } |
104 | 117 |
105 class LoginUtilsTest : public testing::Test, | 118 class LoginUtilsTest : public testing::Test, |
106 public LoginUtils::Delegate, | 119 public LoginUtils::Delegate, |
107 public LoginStatusConsumer { | 120 public LoginStatusConsumer { |
108 public: | 121 public: |
109 // Initialization here is important. The UI thread gets the test's | 122 // Initialization here is important. The UI thread gets the test's |
110 // message loop, as does the file thread (which never actually gets | 123 // message loop, as does the file thread (which never actually gets |
111 // started - so this is a way to fake multiple threads on a single | 124 // started - so this is a way to fake multiple threads on a single |
112 // test thread). The IO thread does not get the message loop set, | 125 // test thread). The IO thread does not get the message loop set, |
113 // and is never started. This is necessary so that we skip various | 126 // and is never started. This is necessary so that we skip various |
114 // bits of initialization that get posted to the IO thread. We do | 127 // bits of initialization that get posted to the IO thread. We do |
115 // however, at one point in the test, temporarily set the message | 128 // however, at one point in the test, temporarily set the message |
116 // loop for the IO thread. | 129 // loop for the IO thread. |
117 LoginUtilsTest() | 130 LoginUtilsTest() |
118 : loop_(MessageLoop::TYPE_IO), | 131 : fake_io_thread_completion_(false, false), |
132 fake_io_thread_("fake_io_thread"), | |
133 loop_(MessageLoop::TYPE_IO), | |
119 browser_process_( | 134 browser_process_( |
120 static_cast<TestingBrowserProcess*>(g_browser_process)), | 135 static_cast<TestingBrowserProcess*>(g_browser_process)), |
121 local_state_(browser_process_), | 136 local_state_(browser_process_), |
122 ui_thread_(content::BrowserThread::UI, &loop_), | 137 ui_thread_(BrowserThread::UI, &loop_), |
123 db_thread_(content::BrowserThread::DB), | 138 db_thread_(BrowserThread::DB), |
124 file_thread_(content::BrowserThread::FILE, &loop_), | 139 file_thread_(BrowserThread::FILE, &loop_), |
125 io_thread_(content::BrowserThread::IO), | |
126 mock_async_method_caller_(NULL), | 140 mock_async_method_caller_(NULL), |
127 connector_(NULL), | 141 connector_(NULL), |
128 cryptohome_(NULL), | 142 cryptohome_(NULL), |
129 prepared_profile_(NULL) {} | 143 prepared_profile_(NULL) {} |
130 | 144 |
131 virtual void SetUp() OVERRIDE { | 145 virtual void SetUp() OVERRIDE { |
146 // This test is not a full blown InProcessBrowserTest, and doesn't have | |
147 // all the usual threads running. However a lot of subsystems pulled from | |
148 // ProfileImpl post to IO (usually from ProfileIOData), and DCHECK that | |
149 // those tasks were posted. Those tasks in turn depend on a lot of other | |
150 // components that aren't there during this test, so this kludge is used to | |
151 // have a running IO loop that doesn't really execute any tasks. | |
152 // | |
153 // See InvokeOnIO() below for a way to perform specific tasks on IO, when | |
154 // that's necessary. | |
155 | |
156 // A thread is needed to create a new MessageLoop, since there can be only | |
157 // one loop per thread. | |
158 fake_io_thread_.StartWithOptions( | |
159 base::Thread::Options(MessageLoop::TYPE_IO, 0)); | |
160 MessageLoop* fake_io_loop = fake_io_thread_.message_loop(); | |
161 // Make this loop enter the single task, BlockLoop(). Pass in the completion | |
162 // event and the work callback. | |
163 fake_io_loop->PostTask( | |
164 FROM_HERE, | |
165 base::Bind( | |
166 BlockLoop, | |
167 &fake_io_thread_completion_, | |
168 base::Bind(&LoginUtilsTest::DoIOWork, base::Unretained(this)))); | |
169 // Map BrowserThread::IO to this loop. This allows posting to IO but nothing | |
170 // will be executed. | |
171 io_thread_.reset( | |
172 new content::TestBrowserThread(BrowserThread::IO, fake_io_loop)); | |
173 | |
132 ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir()); | 174 ASSERT_TRUE(scoped_temp_dir_.CreateUniqueTempDir()); |
133 | 175 |
134 CommandLine* command_line = CommandLine::ForCurrentProcess(); | 176 CommandLine* command_line = CommandLine::ForCurrentProcess(); |
135 command_line->AppendSwitchASCII(switches::kDeviceManagementUrl, kDMServer); | 177 command_line->AppendSwitchASCII(switches::kDeviceManagementUrl, kDMServer); |
136 command_line->AppendSwitchASCII(switches::kLoginProfile, "user"); | 178 command_line->AppendSwitchASCII(switches::kLoginProfile, "user"); |
137 | 179 |
138 local_state_.Get()->RegisterStringPref(prefs::kApplicationLocale, ""); | 180 local_state_.Get()->RegisterStringPref(prefs::kApplicationLocale, ""); |
139 | 181 |
140 // DBusThreadManager should be initialized before io_thread_state_, as | 182 // DBusThreadManager should be initialized before io_thread_state_, as |
141 // DBusThreadManager is used from chromeos::ProxyConfigServiceImpl, | 183 // DBusThreadManager is used from chromeos::ProxyConfigServiceImpl, |
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
220 connector_ = browser_process_->browser_policy_connector(); | 262 connector_ = browser_process_->browser_policy_connector(); |
221 connector_->Init(); | 263 connector_->Init(); |
222 | 264 |
223 RunUntilIdle(); | 265 RunUntilIdle(); |
224 } | 266 } |
225 | 267 |
226 virtual void TearDown() OVERRIDE { | 268 virtual void TearDown() OVERRIDE { |
227 cryptohome::AsyncMethodCaller::Shutdown(); | 269 cryptohome::AsyncMethodCaller::Shutdown(); |
228 mock_async_method_caller_ = NULL; | 270 mock_async_method_caller_ = NULL; |
229 | 271 |
230 RunUntilIdle(); | 272 InvokeOnIO( |
231 { | 273 base::Bind(&LoginUtilsTest::TearDownOnIO, base::Unretained(this))); |
232 // chrome_browser_net::Predictor usually skips its shutdown routines on | |
233 // unit_tests, but does the full thing when | |
234 // g_browser_process->profile_manager() is valid during initialization. | |
235 // Run a task on a temporary BrowserThread::IO that allows skipping | |
236 // these routines. | |
237 // | |
238 // It is important to not have a fake message loop on the IO | |
239 // thread for the whole test, see comment on LoginUtilsTest | |
240 // constructor for details. | |
241 io_thread_.DeprecatedSetMessageLoop(&loop_); | |
242 loop_.PostTask(FROM_HERE, | |
243 base::Bind(&LoginUtilsTest::TearDownOnIO, | |
244 base::Unretained(this))); | |
245 RunUntilIdle(); | |
246 io_thread_.DeprecatedSetMessageLoop(NULL); | |
247 } | |
248 | 274 |
249 // These trigger some tasks that have to run while BrowserThread::UI | 275 // These trigger some tasks that have to run while BrowserThread::UI |
250 // exists. Delete all the profiles before deleting the connector. | 276 // exists. Delete all the profiles before deleting the connector. |
251 browser_process_->SetProfileManager(NULL); | 277 browser_process_->SetProfileManager(NULL); |
252 connector_ = NULL; | 278 connector_ = NULL; |
253 browser_process_->SetBrowserPolicyConnector(NULL); | 279 browser_process_->SetBrowserPolicyConnector(NULL); |
280 QuitIOLoop(); | |
254 RunUntilIdle(); | 281 RunUntilIdle(); |
255 } | 282 } |
256 | 283 |
257 void TearDownOnIO() { | 284 void TearDownOnIO() { |
285 // chrome_browser_net::Predictor usually skips its shutdown routines on | |
286 // unit_tests, but does the full thing when | |
287 // g_browser_process->profile_manager() is valid during initialization. | |
288 // That includes a WaitableEvent on UI waiting for a task on IO, so that | |
289 // task must execute. Do it directly from here now. | |
258 std::vector<Profile*> profiles = | 290 std::vector<Profile*> profiles = |
259 browser_process_->profile_manager()->GetLoadedProfiles(); | 291 browser_process_->profile_manager()->GetLoadedProfiles(); |
260 for (size_t i = 0; i < profiles.size(); ++i) { | 292 for (size_t i = 0; i < profiles.size(); ++i) { |
261 chrome_browser_net::Predictor* predictor = | 293 chrome_browser_net::Predictor* predictor = |
262 profiles[i]->GetNetworkPredictor(); | 294 profiles[i]->GetNetworkPredictor(); |
263 if (predictor) { | 295 if (predictor) { |
264 predictor->EnablePredictorOnIOThread(false); | 296 predictor->EnablePredictorOnIOThread(false); |
265 predictor->Shutdown(); | 297 predictor->Shutdown(); |
266 } | 298 } |
267 } | 299 } |
268 } | 300 } |
269 | 301 |
270 void RunUntilIdle() { | 302 void RunUntilIdle() { |
271 loop_.RunUntilIdle(); | 303 loop_.RunUntilIdle(); |
272 BrowserThread::GetBlockingPool()->FlushForTesting(); | 304 BrowserThread::GetBlockingPool()->FlushForTesting(); |
273 loop_.RunUntilIdle(); | 305 loop_.RunUntilIdle(); |
274 } | 306 } |
275 | 307 |
308 // Invokes |task| on the IO loop and returns after it has executed. | |
309 void InvokeOnIO(const base::Closure& task) { | |
310 fake_io_thread_work_ = task; | |
311 fake_io_thread_completion_.Signal(); | |
312 content::RunMessageLoop(); | |
313 } | |
314 | |
315 // Makes the fake IO loop return. | |
316 void QuitIOLoop() { | |
317 fake_io_thread_completion_.Signal(); | |
318 content::RunMessageLoop(); | |
319 } | |
320 | |
321 // Helper for BlockLoop, InvokeOnIO and QuitIOLoop. | |
322 bool DoIOWork() { | |
323 bool has_work = !fake_io_thread_work_.is_null(); | |
324 if (has_work) | |
325 fake_io_thread_work_.Run(); | |
326 fake_io_thread_work_.Reset(); | |
327 BrowserThread::PostTask( | |
328 BrowserThread::UI, FROM_HERE, | |
329 MessageLoop::QuitWhenIdleClosure()); | |
330 // If there was work then keep waiting for more work. | |
331 // If there was no work then quit the fake IO loop. | |
332 return has_work; | |
333 } | |
334 | |
276 virtual void OnProfilePrepared(Profile* profile) OVERRIDE { | 335 virtual void OnProfilePrepared(Profile* profile) OVERRIDE { |
277 EXPECT_FALSE(prepared_profile_); | 336 EXPECT_FALSE(prepared_profile_); |
278 prepared_profile_ = profile; | 337 prepared_profile_ = profile; |
279 } | 338 } |
280 | 339 |
281 virtual void OnLoginFailure(const LoginFailure& error) OVERRIDE { | 340 virtual void OnLoginFailure(const LoginFailure& error) OVERRIDE { |
282 FAIL() << "OnLoginFailure not expected"; | 341 FAIL() << "OnLoginFailure not expected"; |
283 } | 342 } |
284 | 343 |
285 virtual void OnLoginSuccess(const std::string& username, | 344 virtual void OnLoginSuccess(const std::string& username, |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
371 | 430 |
372 net::TestURLFetcher* PrepareDMPolicyFetcher() { | 431 net::TestURLFetcher* PrepareDMPolicyFetcher() { |
373 em::DeviceManagementResponse response; | 432 em::DeviceManagementResponse response; |
374 response.mutable_policy_response()->add_response(); | 433 response.mutable_policy_response()->add_response(); |
375 return PrepareDMServiceFetcher(kDMPolicyRequest, response); | 434 return PrepareDMServiceFetcher(kDMPolicyRequest, response); |
376 } | 435 } |
377 | 436 |
378 protected: | 437 protected: |
379 ScopedStubCrosEnabler stub_cros_enabler_; | 438 ScopedStubCrosEnabler stub_cros_enabler_; |
380 | 439 |
440 base::Closure fake_io_thread_work_; | |
441 base::WaitableEvent fake_io_thread_completion_; | |
442 base::Thread fake_io_thread_; | |
443 | |
381 MessageLoop loop_; | 444 MessageLoop loop_; |
382 TestingBrowserProcess* browser_process_; | 445 TestingBrowserProcess* browser_process_; |
383 ScopedTestingLocalState local_state_; | 446 ScopedTestingLocalState local_state_; |
384 | 447 |
385 content::TestBrowserThread ui_thread_; | 448 content::TestBrowserThread ui_thread_; |
386 content::TestBrowserThread db_thread_; | 449 content::TestBrowserThread db_thread_; |
387 content::TestBrowserThread file_thread_; | 450 content::TestBrowserThread file_thread_; |
388 content::TestBrowserThread io_thread_; | 451 scoped_ptr<content::TestBrowserThread> io_thread_; |
389 scoped_ptr<IOThread> io_thread_state_; | 452 scoped_ptr<IOThread> io_thread_state_; |
390 | 453 |
391 MockDBusThreadManager mock_dbus_thread_manager_; | 454 MockDBusThreadManager mock_dbus_thread_manager_; |
392 input_method::MockInputMethodManager mock_input_method_manager_; | 455 input_method::MockInputMethodManager mock_input_method_manager_; |
393 net::TestURLFetcherFactory test_url_fetcher_factory_; | 456 net::TestURLFetcherFactory test_url_fetcher_factory_; |
394 | 457 |
395 cryptohome::MockAsyncMethodCaller* mock_async_method_caller_; | 458 cryptohome::MockAsyncMethodCaller* mock_async_method_caller_; |
396 | 459 |
397 policy::BrowserPolicyConnector* connector_; | 460 policy::BrowserPolicyConnector* connector_; |
398 MockCryptohomeLibrary* cryptohome_; | 461 MockCryptohomeLibrary* cryptohome_; |
(...skipping 192 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
591 } | 654 } |
592 | 655 |
593 INSTANTIATE_TEST_CASE_P( | 656 INSTANTIATE_TEST_CASE_P( |
594 LoginUtilsBlockingLoginTestInstance, | 657 LoginUtilsBlockingLoginTestInstance, |
595 LoginUtilsBlockingLoginTest, | 658 LoginUtilsBlockingLoginTest, |
596 testing::Values(0, 1, 2, 3, 4, 5)); | 659 testing::Values(0, 1, 2, 3, 4, 5)); |
597 | 660 |
598 } // namespace | 661 } // namespace |
599 | 662 |
600 } | 663 } |
OLD | NEW |