ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / chrome / browser / chromeos / login / signin / oauth2_browsertest.cc
blob48bdb7b6edf34d9362615f1210ab0c57eafce2cd
1 // Copyright 2014 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 <string>
7 #include "base/message_loop/message_loop.h"
8 #include "base/prefs/pref_service.h"
9 #include "base/strings/stringprintf.h"
10 #include "base/synchronization/waitable_event.h"
11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/chrome_notification_types.h"
13 #include "chrome/browser/chromeos/login/signin/oauth2_login_manager.h"
14 #include "chrome/browser/chromeos/login/signin/oauth2_login_manager_factory.h"
15 #include "chrome/browser/chromeos/login/signin_specifics.h"
16 #include "chrome/browser/chromeos/login/test/oobe_base_test.h"
17 #include "chrome/browser/chromeos/login/wizard_controller.h"
18 #include "chrome/browser/profiles/profile_manager.h"
19 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
20 #include "chrome/browser/ui/browser.h"
21 #include "chrome/browser/ui/browser_tabstrip.h"
22 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
23 #include "chrome/browser/ui/tabs/tab_strip_model.h"
24 #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
25 #include "chrome/common/chrome_switches.h"
26 #include "chrome/test/base/ui_test_utils.h"
27 #include "chromeos/login/auth/key.h"
28 #include "chromeos/login/auth/user_context.h"
29 #include "components/app_modal/javascript_app_modal_dialog.h"
30 #include "components/app_modal/native_app_modal_dialog.h"
31 #include "components/signin/core/browser/profile_oauth2_token_service.h"
32 #include "components/user_manager/user.h"
33 #include "components/user_manager/user_manager.h"
34 #include "content/public/browser/notification_service.h"
35 #include "content/public/test/browser_test_utils.h"
36 #include "extensions/browser/process_manager.h"
37 #include "extensions/test/extension_test_message_listener.h"
38 #include "extensions/test/result_catcher.h"
39 #include "google_apis/gaia/gaia_constants.h"
40 #include "google_apis/gaia/gaia_urls.h"
41 #include "net/cookies/canonical_cookie.h"
42 #include "net/cookies/cookie_monster.h"
43 #include "net/cookies/cookie_store.h"
44 #include "net/test/embedded_test_server/http_request.h"
45 #include "net/test/embedded_test_server/http_response.h"
46 #include "net/url_request/url_request_context.h"
47 #include "net/url_request/url_request_context_getter.h"
49 using app_modal::AppModalDialog;
50 using app_modal::JavaScriptAppModalDialog;
51 using net::test_server::BasicHttpResponse;
52 using net::test_server::HttpRequest;
53 using net::test_server::HttpResponse;
55 namespace chromeos {
57 namespace {
59 // Email of owner account for test.
60 const char kTestAccountId[] = "username@gmail.com";
61 const char kTestRawAccountId[] = "User.Name";
62 const char kTestAccountPassword[] = "fake-password";
63 const char kTestAuthCode[] = "fake-auth-code";
64 const char kTestGaiaUberToken[] = "fake-uber-token";
65 const char kTestAuthLoginAccessToken[] = "fake-access-token";
66 const char kTestRefreshToken[] = "fake-refresh-token";
67 const char kTestAuthSIDCookie[] = "fake-auth-SID-cookie";
68 const char kTestAuthLSIDCookie[] = "fake-auth-LSID-cookie";
69 const char kTestSessionSIDCookie[] = "fake-session-SID-cookie";
70 const char kTestSessionLSIDCookie[] = "fake-session-LSID-cookie";
71 const char kTestSession2SIDCookie[] = "fake-session2-SID-cookie";
72 const char kTestSession2LSIDCookie[] = "fake-session2-LSID-cookie";
73 const char kTestUserinfoToken[] = "fake-userinfo-token";
74 const char kTestLoginToken[] = "fake-login-token";
75 const char kTestSyncToken[] = "fake-sync-token";
76 const char kTestAuthLoginToken[] = "fake-oauthlogin-token";
78 class OAuth2LoginManagerStateWaiter : public OAuth2LoginManager::Observer {
79 public:
80 explicit OAuth2LoginManagerStateWaiter(Profile* profile)
81 : profile_(profile),
82 waiting_for_state_(false),
83 final_state_(OAuth2LoginManager::SESSION_RESTORE_NOT_STARTED) {
86 void WaitForStates(
87 const std::set<OAuth2LoginManager::SessionRestoreState>& states) {
88 DCHECK(!waiting_for_state_);
89 OAuth2LoginManager* login_manager =
90 OAuth2LoginManagerFactory::GetInstance()->GetForProfile(profile_);
91 states_ = states;
92 if (states_.find(login_manager->state()) != states_.end()) {
93 final_state_ = login_manager->state();
94 return;
97 waiting_for_state_ = true;
98 login_manager->AddObserver(this);
99 runner_ = new content::MessageLoopRunner;
100 runner_->Run();
101 login_manager->RemoveObserver(this);
104 OAuth2LoginManager::SessionRestoreState final_state() { return final_state_; }
106 private:
107 // OAuth2LoginManager::Observer overrides.
108 void OnSessionRestoreStateChanged(
109 Profile* user_profile,
110 OAuth2LoginManager::SessionRestoreState state) override {
111 if (!waiting_for_state_)
112 return;
114 if (states_.find(state) == states_.end())
115 return;
117 final_state_ = state;
118 waiting_for_state_ = false;
119 runner_->Quit();
122 Profile* profile_;
123 std::set<OAuth2LoginManager::SessionRestoreState> states_;
124 bool waiting_for_state_;
125 OAuth2LoginManager::SessionRestoreState final_state_;
126 scoped_refptr<content::MessageLoopRunner> runner_;
128 DISALLOW_COPY_AND_ASSIGN(OAuth2LoginManagerStateWaiter);
131 } // namespace
133 class OAuth2Test : public OobeBaseTest {
134 protected:
135 OAuth2Test() {}
137 void SetUpCommandLine(base::CommandLine* command_line) override {
138 OobeBaseTest::SetUpCommandLine(command_line);
140 // Disable sync sinc we don't really need this for these tests and it also
141 // makes OAuth2Test.MergeSession test flaky http://crbug.com/408867.
142 command_line->AppendSwitch(switches::kDisableSync);
145 void SetupGaiaServerForNewAccount() {
146 FakeGaia::MergeSessionParams params;
147 params.auth_sid_cookie = kTestAuthSIDCookie;
148 params.auth_lsid_cookie = kTestAuthLSIDCookie;
149 params.auth_code = kTestAuthCode;
150 params.refresh_token = kTestRefreshToken;
151 params.access_token = kTestAuthLoginAccessToken;
152 params.gaia_uber_token = kTestGaiaUberToken;
153 params.session_sid_cookie = kTestSessionSIDCookie;
154 params.session_lsid_cookie = kTestSessionLSIDCookie;
155 fake_gaia_->SetMergeSessionParams(params);
156 SetupGaiaServerWithAccessTokens();
159 void SetupGaiaServerForUnexpiredAccount() {
160 FakeGaia::MergeSessionParams params;
161 params.email = kTestAccountId;
162 fake_gaia_->SetMergeSessionParams(params);
163 SetupGaiaServerWithAccessTokens();
166 void SetupGaiaServerForExpiredAccount() {
167 FakeGaia::MergeSessionParams params;
168 params.gaia_uber_token = kTestGaiaUberToken;
169 params.session_sid_cookie = kTestSession2SIDCookie;
170 params.session_lsid_cookie = kTestSession2LSIDCookie;
171 fake_gaia_->SetMergeSessionParams(params);
172 SetupGaiaServerWithAccessTokens();
175 void LoginAsExistingUser() {
176 content::WindowedNotificationObserver(
177 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
178 content::NotificationService::AllSources()).Wait();
180 JsExpect("!!document.querySelector('#account-picker')");
181 JsExpect("!!document.querySelector('#pod-row')");
183 EXPECT_EQ(GetOAuthStatusFromLocalState(kTestAccountId),
184 user_manager::User::OAUTH2_TOKEN_STATUS_VALID);
186 EXPECT_TRUE(TryToLogin(kTestAccountId, kTestAccountPassword));
187 Profile* profile = ProfileManager::GetPrimaryUserProfile();
189 // Wait for the session merge to finish.
190 WaitForMergeSessionCompletion(OAuth2LoginManager::SESSION_RESTORE_DONE);
192 // Check for existance of refresh token.
193 ProfileOAuth2TokenService* token_service =
194 ProfileOAuth2TokenServiceFactory::GetForProfile(profile);
195 EXPECT_TRUE(token_service->RefreshTokenIsAvailable(kTestAccountId));
197 EXPECT_EQ(GetOAuthStatusFromLocalState(kTestAccountId),
198 user_manager::User::OAUTH2_TOKEN_STATUS_VALID);
201 bool TryToLogin(const std::string& username,
202 const std::string& password) {
203 if (!AddUserToSession(username, password))
204 return false;
206 if (const user_manager::User* active_user =
207 user_manager::UserManager::Get()->GetActiveUser()) {
208 return active_user->email() == username;
211 return false;
214 user_manager::User::OAuthTokenStatus GetOAuthStatusFromLocalState(
215 const std::string& user_id) const {
216 PrefService* local_state = g_browser_process->local_state();
217 const base::DictionaryValue* prefs_oauth_status =
218 local_state->GetDictionary("OAuthTokenStatus");
219 int oauth_token_status = user_manager::User::OAUTH_TOKEN_STATUS_UNKNOWN;
220 if (prefs_oauth_status &&
221 prefs_oauth_status->GetIntegerWithoutPathExpansion(
222 user_id, &oauth_token_status)) {
223 user_manager::User::OAuthTokenStatus result =
224 static_cast<user_manager::User::OAuthTokenStatus>(oauth_token_status);
225 return result;
227 return user_manager::User::OAUTH_TOKEN_STATUS_UNKNOWN;
230 protected:
231 // OobeBaseTest overrides.
232 Profile* profile() override {
233 if (user_manager::UserManager::Get()->GetActiveUser())
234 return ProfileManager::GetPrimaryUserProfile();
236 return OobeBaseTest::profile();
239 bool AddUserToSession(const std::string& username,
240 const std::string& password) {
241 ExistingUserController* controller =
242 ExistingUserController::current_controller();
243 if (!controller) {
244 ADD_FAILURE();
245 return false;
248 UserContext user_context(username);
249 user_context.SetKey(Key(password));
250 controller->Login(user_context, SigninSpecifics());
251 content::WindowedNotificationObserver(
252 chrome::NOTIFICATION_SESSION_STARTED,
253 content::NotificationService::AllSources()).Wait();
254 const user_manager::UserList& logged_users =
255 user_manager::UserManager::Get()->GetLoggedInUsers();
256 for (user_manager::UserList::const_iterator it = logged_users.begin();
257 it != logged_users.end();
258 ++it) {
259 if ((*it)->email() == username)
260 return true;
262 return false;
265 void SetupGaiaServerWithAccessTokens() {
266 // Configure OAuth authentication.
267 GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
269 // This token satisfies the userinfo.email request from
270 // DeviceOAuth2TokenService used in token validation.
271 FakeGaia::AccessTokenInfo userinfo_token_info;
272 userinfo_token_info.token = kTestUserinfoToken;
273 userinfo_token_info.scopes.insert(
274 "https://www.googleapis.com/auth/userinfo.email");
275 userinfo_token_info.audience = gaia_urls->oauth2_chrome_client_id();
276 userinfo_token_info.email = kTestAccountId;
277 fake_gaia_->IssueOAuthToken(kTestRefreshToken, userinfo_token_info);
279 FakeGaia::AccessTokenInfo userinfo_profile_token_info;
280 userinfo_profile_token_info.token = kTestUserinfoToken;
281 userinfo_profile_token_info.scopes.insert(
282 "https://www.googleapis.com/auth/userinfo.profile");
283 userinfo_profile_token_info.audience = gaia_urls->oauth2_chrome_client_id();
284 userinfo_profile_token_info.email = kTestAccountId;
285 fake_gaia_->IssueOAuthToken(kTestRefreshToken, userinfo_profile_token_info);
287 // The any-api access token for accessing the token minting endpoint.
288 FakeGaia::AccessTokenInfo login_token_info;
289 login_token_info.token = kTestLoginToken;
290 login_token_info.scopes.insert(GaiaConstants::kAnyApiOAuth2Scope);
291 login_token_info.audience = gaia_urls->oauth2_chrome_client_id();
292 fake_gaia_->IssueOAuthToken(kTestRefreshToken, login_token_info);
294 // The /auth/chromesync access token for accessing sync endpoint.
295 FakeGaia::AccessTokenInfo sync_token_info;
296 sync_token_info.token = kTestSyncToken;
297 sync_token_info.scopes.insert(GaiaConstants::kChromeSyncOAuth2Scope);
298 sync_token_info.audience = gaia_urls->oauth2_chrome_client_id();
299 fake_gaia_->IssueOAuthToken(kTestRefreshToken, sync_token_info);
301 FakeGaia::AccessTokenInfo auth_login_token_info;
302 auth_login_token_info.token = kTestAuthLoginToken;
303 auth_login_token_info.scopes.insert(GaiaConstants::kOAuth1LoginScope);
304 auth_login_token_info.audience = gaia_urls->oauth2_chrome_client_id();
305 fake_gaia_->IssueOAuthToken(kTestRefreshToken, auth_login_token_info);
308 void CheckSessionState(OAuth2LoginManager::SessionRestoreState state) {
309 OAuth2LoginManager* login_manager =
310 OAuth2LoginManagerFactory::GetInstance()->GetForProfile(
311 profile());
312 ASSERT_EQ(state, login_manager->state());
315 void WaitForMergeSessionCompletion(
316 OAuth2LoginManager::SessionRestoreState final_state) {
317 // Wait for the session merge to finish.
318 std::set<OAuth2LoginManager::SessionRestoreState> states;
319 states.insert(OAuth2LoginManager::SESSION_RESTORE_DONE);
320 states.insert(OAuth2LoginManager::SESSION_RESTORE_FAILED);
321 states.insert(OAuth2LoginManager::SESSION_RESTORE_CONNECTION_FAILED);
322 OAuth2LoginManagerStateWaiter merge_session_waiter(profile());
323 merge_session_waiter.WaitForStates(states);
324 EXPECT_EQ(merge_session_waiter.final_state(), final_state);
327 void StartNewUserSession(bool wait_for_merge) {
328 SetupGaiaServerForNewAccount();
329 SimulateNetworkOnline();
330 chromeos::WizardController::SkipPostLoginScreensForTesting();
331 chromeos::WizardController* wizard_controller =
332 chromeos::WizardController::default_controller();
333 wizard_controller->SkipToLoginForTesting(LoginScreenContext());
335 content::WindowedNotificationObserver(
336 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
337 content::NotificationService::AllSources()).Wait();
339 // Use capitalized and dotted user name on purpose to make sure
340 // our email normalization kicks in.
341 GetLoginDisplay()->ShowSigninScreenForCreds(kTestRawAccountId,
342 kTestAccountPassword);
344 content::WindowedNotificationObserver(
345 chrome::NOTIFICATION_SESSION_STARTED,
346 content::NotificationService::AllSources()).Wait();
348 if (wait_for_merge) {
349 // Wait for the session merge to finish.
350 WaitForMergeSessionCompletion(OAuth2LoginManager::SESSION_RESTORE_DONE);
354 DISALLOW_COPY_AND_ASSIGN(OAuth2Test);
357 class CookieReader : public base::RefCountedThreadSafe<CookieReader> {
358 public:
359 CookieReader() {
362 void ReadCookies(Profile* profile) {
363 context_ = profile->GetRequestContext();
364 content::BrowserThread::PostTask(
365 content::BrowserThread::IO, FROM_HERE,
366 base::Bind(&CookieReader::ReadCookiesOnIOThread,
367 this));
368 runner_ = new content::MessageLoopRunner;
369 runner_->Run();
372 std::string GetCookieValue(const std::string& name) {
373 for (std::vector<net::CanonicalCookie>::const_iterator iter =
374 cookie_list_.begin();
375 iter != cookie_list_.end();
376 ++iter) {
377 if (iter->Name() == name) {
378 return iter->Value();
381 return std::string();
384 private:
385 friend class base::RefCountedThreadSafe<CookieReader>;
387 virtual ~CookieReader() {
390 void ReadCookiesOnIOThread() {
391 context_->GetURLRequestContext()->cookie_store()->GetCookieMonster()->
392 GetAllCookiesAsync(base::Bind(
393 &CookieReader::OnGetAllCookiesOnUIThread,
394 this));
397 void OnGetAllCookiesOnUIThread(const net::CookieList& cookies) {
398 cookie_list_ = cookies;
399 content::BrowserThread::PostTask(
400 content::BrowserThread::UI, FROM_HERE,
401 base::Bind(&CookieReader::OnCookiesReadyOnUIThread,
402 this));
405 void OnCookiesReadyOnUIThread() {
406 runner_->Quit();
409 scoped_refptr<net::URLRequestContextGetter> context_;
410 net::CookieList cookie_list_;
411 scoped_refptr<content::MessageLoopRunner> runner_;
413 DISALLOW_COPY_AND_ASSIGN(CookieReader);
416 // PRE_MergeSession is testing merge session for a new profile.
417 IN_PROC_BROWSER_TEST_F(OAuth2Test, PRE_PRE_PRE_MergeSession) {
418 StartNewUserSession(true);
419 // Check for existance of refresh token.
420 ProfileOAuth2TokenService* token_service =
421 ProfileOAuth2TokenServiceFactory::GetForProfile(
422 profile());
423 EXPECT_TRUE(token_service->RefreshTokenIsAvailable(kTestAccountId));
425 EXPECT_EQ(GetOAuthStatusFromLocalState(kTestAccountId),
426 user_manager::User::OAUTH2_TOKEN_STATUS_VALID);
428 scoped_refptr<CookieReader> cookie_reader(new CookieReader());
429 cookie_reader->ReadCookies(profile());
430 EXPECT_EQ(cookie_reader->GetCookieValue("SID"), kTestSessionSIDCookie);
431 EXPECT_EQ(cookie_reader->GetCookieValue("LSID"), kTestSessionLSIDCookie);
434 // MergeSession test is running merge session process for an existing profile
435 // that was generated in PRE_PRE_PRE_MergeSession test. In this test, we
436 // are not running /MergeSession process since the /ListAccounts call confirms
437 // that the session is not stale.
438 IN_PROC_BROWSER_TEST_F(OAuth2Test, PRE_PRE_MergeSession) {
439 SetupGaiaServerForUnexpiredAccount();
440 SimulateNetworkOnline();
441 LoginAsExistingUser();
442 scoped_refptr<CookieReader> cookie_reader(new CookieReader());
443 cookie_reader->ReadCookies(profile());
444 // These are still cookie values form the initial session since
445 // /ListAccounts
446 EXPECT_EQ(cookie_reader->GetCookieValue("SID"), kTestSessionSIDCookie);
447 EXPECT_EQ(cookie_reader->GetCookieValue("LSID"), kTestSessionLSIDCookie);
450 // MergeSession test is running merge session process for an existing profile
451 // that was generated in PRE_PRE_MergeSession test.
452 IN_PROC_BROWSER_TEST_F(OAuth2Test, PRE_MergeSession) {
453 SetupGaiaServerForExpiredAccount();
454 SimulateNetworkOnline();
455 LoginAsExistingUser();
456 scoped_refptr<CookieReader> cookie_reader(new CookieReader());
457 cookie_reader->ReadCookies(profile());
458 // These should be cookie values that we generated by calling /MergeSession,
459 // since /ListAccounts should have tell us that the initial session cookies
460 // are stale.
461 EXPECT_EQ(cookie_reader->GetCookieValue("SID"), kTestSession2SIDCookie);
462 EXPECT_EQ(cookie_reader->GetCookieValue("LSID"), kTestSession2LSIDCookie);
465 // MergeSession test is attempting to merge session for an existing profile
466 // that was generated in PRE_PRE_MergeSession test. This attempt should fail
467 // since FakeGaia instance isn't configured to return relevant tokens/cookies.
468 IN_PROC_BROWSER_TEST_F(OAuth2Test, MergeSession) {
469 SimulateNetworkOnline();
471 content::WindowedNotificationObserver(
472 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
473 content::NotificationService::AllSources()).Wait();
475 JsExpect("!!document.querySelector('#account-picker')");
476 JsExpect("!!document.querySelector('#pod-row')");
478 EXPECT_EQ(GetOAuthStatusFromLocalState(kTestAccountId),
479 user_manager::User::OAUTH2_TOKEN_STATUS_VALID);
481 EXPECT_TRUE(TryToLogin(kTestAccountId, kTestAccountPassword));
483 // Wait for the session merge to finish.
484 WaitForMergeSessionCompletion(OAuth2LoginManager::SESSION_RESTORE_FAILED);
486 EXPECT_EQ(GetOAuthStatusFromLocalState(kTestAccountId),
487 user_manager::User::OAUTH2_TOKEN_STATUS_INVALID);
491 const char kGooglePageContent[] =
492 "<html><title>Hello!</title><script>alert('hello');</script>"
493 "<body>Hello Google!</body></html>";
494 const char kRandomPageContent[] =
495 "<html><title>SomthingElse</title><body>I am SomethingElse</body></html>";
496 const char kHelloPagePath[] = "/hello_google";
497 const char kRandomPagePath[] = "/non_google_page";
500 // FakeGoogle serves content of http://www.google.com/hello_google page for
501 // merge session tests.
502 class FakeGoogle {
503 public:
504 FakeGoogle() : start_event_(true, false) {
507 ~FakeGoogle() {}
509 scoped_ptr<HttpResponse> HandleRequest(const HttpRequest& request) {
510 // The scheme and host of the URL is actually not important but required to
511 // get a valid GURL in order to parse |request.relative_url|.
512 GURL request_url = GURL("http://localhost").Resolve(request.relative_url);
513 LOG(WARNING) << "Requesting page " << request.relative_url;
514 std::string request_path = request_url.path();
515 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse());
516 if (request_path == kHelloPagePath) { // Serving "google" page.
517 start_event_.Signal();
518 content::BrowserThread::PostTask(
519 content::BrowserThread::UI, FROM_HERE,
520 base::Bind(&FakeGoogle::QuitRunnerOnUIThread,
521 base::Unretained(this)));
523 http_response->set_code(net::HTTP_OK);
524 http_response->set_content_type("text/html");
525 http_response->set_content(kGooglePageContent);
526 } else if (request_path == kRandomPagePath) { // Serving "non-google" page.
527 http_response->set_code(net::HTTP_OK);
528 http_response->set_content_type("text/html");
529 http_response->set_content(kRandomPageContent);
530 } else {
531 return scoped_ptr<HttpResponse>(); // Request not understood.
534 return http_response.Pass();
537 // True if we have already served the test page.
538 bool IsPageRequested () {
539 return start_event_.IsSignaled();
542 // Waits until we receive a request to serve the test page.
543 void WaitForPageRequest() {
544 // If we have already served the request, bail out.
545 if (start_event_.IsSignaled())
546 return;
548 runner_ = new content::MessageLoopRunner;
549 runner_->Run();
552 private:
553 void QuitRunnerOnUIThread() {
554 if (runner_.get())
555 runner_->Quit();
557 // This event will tell us when we actually see HTTP request on the server
558 // side. It should be signalled only after the page/XHR throttle had been
559 // removed (after merge session completes).
560 base::WaitableEvent start_event_;
561 scoped_refptr<content::MessageLoopRunner> runner_;
563 DISALLOW_COPY_AND_ASSIGN(FakeGoogle);
566 // FakeGaia specialization that can delay /MergeSession handler until
567 // we explicitly call DelayedFakeGaia::UnblockMergeSession().
568 class DelayedFakeGaia : public FakeGaia {
569 public:
570 DelayedFakeGaia()
571 : blocking_event_(true, false),
572 start_event_(true, false) {
575 void UnblockMergeSession() {
576 blocking_event_.Signal();
579 void WaitForMergeSessionToStart() {
580 // If we have already served the request, bail out.
581 if (start_event_.IsSignaled())
582 return;
584 runner_ = new content::MessageLoopRunner;
585 runner_->Run();
588 private:
589 // FakeGaia overrides.
590 void HandleMergeSession(const HttpRequest& request,
591 BasicHttpResponse* http_response) override {
592 start_event_.Signal();
593 content::BrowserThread::PostTask(
594 content::BrowserThread::UI, FROM_HERE,
595 base::Bind(&DelayedFakeGaia::QuitRunnerOnUIThread,
596 base::Unretained(this)));
597 blocking_event_.Wait();
598 FakeGaia::HandleMergeSession(request, http_response);
601 void QuitRunnerOnUIThread() {
602 if (runner_.get())
603 runner_->Quit();
606 base::WaitableEvent blocking_event_;
607 base::WaitableEvent start_event_;
608 scoped_refptr<content::MessageLoopRunner> runner_;
610 DISALLOW_COPY_AND_ASSIGN(DelayedFakeGaia);
613 class MergeSessionTest : public OAuth2Test {
614 protected:
615 MergeSessionTest() : delayed_fake_gaia_(new DelayedFakeGaia()) {
616 fake_gaia_.reset(delayed_fake_gaia_);
619 void SetUpCommandLine(base::CommandLine* command_line) override {
620 OAuth2Test::SetUpCommandLine(command_line);
622 // Get fake URL for fake google.com.
623 const GURL& server_url = embedded_test_server()->base_url();
624 GURL::Replacements replace_google_host;
625 replace_google_host.SetHostStr("www.google.com");
626 GURL google_url = server_url.ReplaceComponents(replace_google_host);
627 fake_google_page_url_ = google_url.Resolve(kHelloPagePath);
629 GURL::Replacements replace_non_google_host;
630 replace_non_google_host.SetHostStr("www.somethingelse.org");
631 GURL non_google_url = server_url.ReplaceComponents(replace_non_google_host);
632 non_google_page_url_ = non_google_url.Resolve(kRandomPagePath);
635 void SetUp() override {
636 embedded_test_server()->RegisterRequestHandler(
637 base::Bind(&FakeGoogle::HandleRequest,
638 base::Unretained(&fake_google_)));
639 OAuth2Test::SetUp();
642 protected:
643 void UnblockMergeSession() {
644 delayed_fake_gaia_->UnblockMergeSession();
647 void WaitForMergeSessionToStart() {
648 delayed_fake_gaia_->WaitForMergeSessionToStart();
651 void JsExpect(content::WebContents* contents,
652 const std::string& expression) {
653 bool result;
654 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
655 contents,
656 "window.domAutomationController.send(!!(" + expression + "));",
657 &result));
658 ASSERT_TRUE(result) << expression;
661 const GURL& GetBackGroundPageUrl(const std::string& extension_id) {
662 extensions::ProcessManager* manager =
663 extensions::ProcessManager::Get(profile());
664 extensions::ExtensionHost* host =
665 manager->GetBackgroundHostForExtension(extension_id);
666 return host->host_contents()->GetURL();
669 void JsExpectOnBackgroundPage(const std::string& extension_id,
670 const std::string& expression) {
671 extensions::ProcessManager* manager =
672 extensions::ProcessManager::Get(profile());
673 extensions::ExtensionHost* host =
674 manager->GetBackgroundHostForExtension(extension_id);
675 if (host == NULL) {
676 ADD_FAILURE() << "Extension " << extension_id
677 << " has no background page.";
678 return;
681 JsExpect(host->host_contents(), expression);
684 FakeGoogle fake_google_;
685 DelayedFakeGaia* delayed_fake_gaia_;
686 GURL fake_google_page_url_;
687 GURL non_google_page_url_;
689 private:
690 DISALLOW_COPY_AND_ASSIGN(MergeSessionTest);
693 Browser* FindOrCreateVisibleBrowser(Profile* profile) {
694 chrome::ScopedTabbedBrowserDisplayer displayer(
695 profile, chrome::GetActiveDesktop());
696 Browser* browser = displayer.browser();
697 if (browser->tab_strip_model()->count() == 0)
698 chrome::AddTabAt(browser, GURL(), -1, true);
699 return browser;
702 IN_PROC_BROWSER_TEST_F(MergeSessionTest, PageThrottle) {
703 StartNewUserSession(false);
705 // Try to open a page from google.com.
706 Browser* browser =
707 FindOrCreateVisibleBrowser(profile());
708 ui_test_utils::NavigateToURLWithDisposition(
709 browser,
710 fake_google_page_url_,
711 CURRENT_TAB, ui_test_utils::BROWSER_TEST_NONE);
713 // Wait until we get send merge session request.
714 WaitForMergeSessionToStart();
716 // Make sure the page is blocked by the throttle.
717 EXPECT_FALSE(fake_google_.IsPageRequested());
719 // Check that throttle page is displayed instead.
720 base::string16 title;
721 ui_test_utils::GetCurrentTabTitle(browser, &title);
722 DVLOG(1) << "Loaded page at the start : " << title;
724 // Unblock GAIA request.
725 UnblockMergeSession();
727 // Wait for the session merge to finish.
728 WaitForMergeSessionCompletion(OAuth2LoginManager::SESSION_RESTORE_DONE);
730 // Make sure the test page is served.
731 fake_google_.WaitForPageRequest();
733 // Check that real page is no longer blocked by the throttle and that the
734 // real page pops up JS dialog.
735 AppModalDialog* dialog = ui_test_utils::WaitForAppModalDialog();
736 ASSERT_TRUE(dialog->IsJavaScriptModalDialog());
737 JavaScriptAppModalDialog* js_dialog =
738 static_cast<JavaScriptAppModalDialog*>(dialog);
739 js_dialog->native_dialog()->AcceptAppModalDialog();
741 ui_test_utils::GetCurrentTabTitle(browser, &title);
742 DVLOG(1) << "Loaded page at the end : " << title;
745 IN_PROC_BROWSER_TEST_F(MergeSessionTest, XHRThrottle) {
746 StartNewUserSession(false);
748 // Wait until we get send merge session request.
749 WaitForMergeSessionToStart();
751 // Reset ExtensionBrowserTest::observer_ to the right browser object.
752 Browser* browser = FindOrCreateVisibleBrowser(profile());
753 observer_.reset(new ExtensionTestNotificationObserver(browser));
755 // Run background page tests. The tests will just wait for XHR request
756 // to complete.
757 extensions::ResultCatcher catcher;
759 scoped_ptr<ExtensionTestMessageListener> non_google_xhr_listener(
760 new ExtensionTestMessageListener("non-google-xhr-received", false));
762 // Load extension with a background page. The background page will
763 // attempt to load |fake_google_page_url_| via XHR.
764 const extensions::Extension* ext = LoadExtension(
765 test_data_dir_.AppendASCII("merge_session"));
766 ASSERT_TRUE(ext);
768 // Kick off XHR request from the extension.
769 JsExpectOnBackgroundPage(
770 ext->id(),
771 base::StringPrintf("startThrottledTests('%s', '%s')",
772 fake_google_page_url_.spec().c_str(),
773 non_google_page_url_.spec().c_str()));
775 // Verify that we've sent XHR request form the extension side...
776 JsExpectOnBackgroundPage(ext->id(),
777 "googleRequestSent && !googleResponseReceived");
779 // ...but didn't see it on the server side yet.
780 EXPECT_FALSE(fake_google_.IsPageRequested());
782 // Unblock GAIA request.
783 UnblockMergeSession();
785 // Wait for the session merge to finish.
786 WaitForMergeSessionCompletion(OAuth2LoginManager::SESSION_RESTORE_DONE);
788 // Wait until non-google XHR content to load first.
789 ASSERT_TRUE(non_google_xhr_listener->WaitUntilSatisfied());
791 if (!catcher.GetNextResult()) {
792 std::string message = catcher.message();
793 ADD_FAILURE() << "Tests failed: " << message;
796 EXPECT_TRUE(fake_google_.IsPageRequested());
799 } // namespace chromeos