Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / chromeos / login / oauth2_browsertest.cc
blob8bf6438421a3e22861046b2871e26243088bc431
1 // Copyright (c) 2013 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 "base/message_loop/message_loop.h"
6 #include "base/prefs/pref_service.h"
7 #include "base/strings/stringprintf.h"
8 #include "base/synchronization/waitable_event.h"
9 #include "chrome/browser/browser_process.h"
10 #include "chrome/browser/chrome_notification_types.h"
11 #include "chrome/browser/chromeos/login/oauth2_login_manager.h"
12 #include "chrome/browser/chromeos/login/oauth2_login_manager_factory.h"
13 #include "chrome/browser/chromeos/login/oobe_base_test.h"
14 #include "chrome/browser/chromeos/login/user_manager.h"
15 #include "chrome/browser/chromeos/login/wizard_controller.h"
16 #include "chrome/browser/extensions/extension_test_message_listener.h"
17 #include "chrome/browser/profiles/profile_manager.h"
18 #include "chrome/browser/signin/profile_oauth2_token_service.h"
19 #include "chrome/browser/signin/profile_oauth2_token_service_factory.h"
20 #include "chrome/browser/ui/app_modal_dialogs/javascript_app_modal_dialog.h"
21 #include "chrome/browser/ui/app_modal_dialogs/native_app_modal_dialog.h"
22 #include "chrome/browser/ui/browser.h"
23 #include "chrome/browser/ui/browser_tabstrip.h"
24 #include "chrome/browser/ui/scoped_tabbed_browser_displayer.h"
25 #include "chrome/browser/ui/tabs/tab_strip_model.h"
26 #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
27 #include "chrome/test/base/ui_test_utils.h"
28 #include "content/public/browser/notification_service.h"
29 #include "content/public/test/browser_test_utils.h"
30 #include "extensions/browser/process_manager.h"
31 #include "google_apis/gaia/gaia_constants.h"
32 #include "google_apis/gaia/gaia_urls.h"
33 #include "net/cookies/canonical_cookie.h"
34 #include "net/cookies/cookie_monster.h"
35 #include "net/cookies/cookie_store.h"
36 #include "net/test/embedded_test_server/http_request.h"
37 #include "net/test/embedded_test_server/http_response.h"
38 #include "net/url_request/url_request_context.h"
39 #include "net/url_request/url_request_context_getter.h"
41 using net::test_server::BasicHttpResponse;
42 using net::test_server::HttpRequest;
43 using net::test_server::HttpResponse;
45 namespace chromeos {
47 namespace {
49 // Email of owner account for test.
50 const char kTestAccountId[] = "username@gmail.com";
51 const char kTestRawAccountId[] = "User.Name";
52 const char kTestAccountPassword[] = "fake-password";
53 const char kTestAuthCode[] = "fake-auth-code";
54 const char kTestGaiaUberToken[] = "fake-uber-token";
55 const char kTestAuthLoginAccessToken[] = "fake-access-token";
56 const char kTestRefreshToken[] = "fake-refresh-token";
57 const char kTestAuthSIDCookie[] = "fake-auth-SID-cookie";
58 const char kTestAuthLSIDCookie[] = "fake-auth-LSID-cookie";
59 const char kTestSessionSIDCookie[] = "fake-session-SID-cookie";
60 const char kTestSessionLSIDCookie[] = "fake-session-LSID-cookie";
61 const char kTestSession2SIDCookie[] = "fake-session2-SID-cookie";
62 const char kTestSession2LSIDCookie[] = "fake-session2-LSID-cookie";
63 const char kTestUserinfoToken[] = "fake-userinfo-token";
64 const char kTestLoginToken[] = "fake-login-token";
65 const char kTestSyncToken[] = "fake-sync-token";
66 const char kTestAuthLoginToken[] = "fake-oauthlogin-token";
68 class OAuth2LoginManagerStateWaiter : public OAuth2LoginManager::Observer {
69 public:
70 explicit OAuth2LoginManagerStateWaiter(Profile* profile)
71 : profile_(profile),
72 waiting_for_state_(false),
73 final_state_(OAuth2LoginManager::SESSION_RESTORE_NOT_STARTED) {
76 void WaitForStates(
77 const std::set<OAuth2LoginManager::SessionRestoreState>& states) {
78 DCHECK(!waiting_for_state_);
79 OAuth2LoginManager* login_manager =
80 OAuth2LoginManagerFactory::GetInstance()->GetForProfile(profile_);
81 states_ = states;
82 if (states_.find(login_manager->state()) != states_.end()) {
83 final_state_ = login_manager->state();
84 return;
87 waiting_for_state_ = true;
88 login_manager->AddObserver(this);
89 runner_ = new content::MessageLoopRunner;
90 runner_->Run();
91 login_manager->RemoveObserver(this);
94 OAuth2LoginManager::SessionRestoreState final_state() { return final_state_; }
96 private:
97 // OAuth2LoginManager::Observer overrides.
98 virtual void OnSessionRestoreStateChanged(
99 Profile* user_profile,
100 OAuth2LoginManager::SessionRestoreState state) OVERRIDE {
101 if (!waiting_for_state_)
102 return;
104 if (states_.find(state) == states_.end())
105 return;
107 final_state_ = state;
108 waiting_for_state_ = false;
109 runner_->Quit();
112 Profile* profile_;
113 std::set<OAuth2LoginManager::SessionRestoreState> states_;
114 bool waiting_for_state_;
115 OAuth2LoginManager::SessionRestoreState final_state_;
116 scoped_refptr<content::MessageLoopRunner> runner_;
118 DISALLOW_COPY_AND_ASSIGN(OAuth2LoginManagerStateWaiter);
121 } // namespace
123 class OAuth2Test : public OobeBaseTest {
124 protected:
125 OAuth2Test() {}
127 void SetupGaiaServerForNewAccount() {
128 FakeGaia::MergeSessionParams params;
129 params.auth_sid_cookie = kTestAuthSIDCookie;
130 params.auth_lsid_cookie = kTestAuthLSIDCookie;
131 params.auth_code = kTestAuthCode;
132 params.refresh_token = kTestRefreshToken;
133 params.access_token = kTestAuthLoginAccessToken;
134 params.gaia_uber_token = kTestGaiaUberToken;
135 params.session_sid_cookie = kTestSessionSIDCookie;
136 params.session_lsid_cookie = kTestSessionLSIDCookie;
137 fake_gaia_->SetMergeSessionParams(params);
138 SetupGaiaServerWithAccessTokens();
141 void SetupGaiaServerForExistingAccount() {
142 FakeGaia::MergeSessionParams params;
143 params.gaia_uber_token = kTestGaiaUberToken;
144 params.session_sid_cookie = kTestSession2SIDCookie;
145 params.session_lsid_cookie = kTestSession2LSIDCookie;
146 fake_gaia_->SetMergeSessionParams(params);
147 SetupGaiaServerWithAccessTokens();
150 bool TryToLogin(const std::string& username,
151 const std::string& password) {
152 if (!AddUserTosession(username, password))
153 return false;
155 if (const User* active_user = UserManager::Get()->GetActiveUser())
156 return active_user->email() == username;
158 return false;
161 User::OAuthTokenStatus GetOAuthStatusFromLocalState(
162 const std::string& user_id) const {
163 PrefService* local_state = g_browser_process->local_state();
164 const base::DictionaryValue* prefs_oauth_status =
165 local_state->GetDictionary("OAuthTokenStatus");
166 int oauth_token_status = User::OAUTH_TOKEN_STATUS_UNKNOWN;
167 if (prefs_oauth_status &&
168 prefs_oauth_status->GetIntegerWithoutPathExpansion(
169 user_id, &oauth_token_status)) {
170 User::OAuthTokenStatus result =
171 static_cast<User::OAuthTokenStatus>(oauth_token_status);
172 return result;
174 return User::OAUTH_TOKEN_STATUS_UNKNOWN;
177 protected:
178 // OobeBaseTest overrides.
179 virtual Profile* profile() OVERRIDE {
180 if (UserManager::Get()->GetActiveUser())
181 return ProfileManager::GetPrimaryUserProfile();
183 return OobeBaseTest::profile();
186 bool AddUserTosession(const std::string& username,
187 const std::string& password) {
188 ExistingUserController* controller =
189 ExistingUserController::current_controller();
190 if (!controller) {
191 ADD_FAILURE();
192 return false;
195 controller->Login(UserContext(username, password, std::string()));
196 content::WindowedNotificationObserver(
197 chrome::NOTIFICATION_SESSION_STARTED,
198 content::NotificationService::AllSources()).Wait();
199 const UserList& logged_users = UserManager::Get()->GetLoggedInUsers();
200 for (UserList::const_iterator it = logged_users.begin();
201 it != logged_users.end(); ++it) {
202 if ((*it)->email() == username)
203 return true;
205 return false;
208 void SetupGaiaServerWithAccessTokens() {
209 // Configure OAuth authentication.
210 GaiaUrls* gaia_urls = GaiaUrls::GetInstance();
212 // This token satisfies the userinfo.email request from
213 // DeviceOAuth2TokenService used in token validation.
214 FakeGaia::AccessTokenInfo userinfo_token_info;
215 userinfo_token_info.token = kTestUserinfoToken;
216 userinfo_token_info.scopes.insert(
217 "https://www.googleapis.com/auth/userinfo.email");
218 userinfo_token_info.audience = gaia_urls->oauth2_chrome_client_id();
219 userinfo_token_info.email = kTestAccountId;
220 fake_gaia_->IssueOAuthToken(kTestRefreshToken, userinfo_token_info);
222 FakeGaia::AccessTokenInfo userinfo_profile_token_info;
223 userinfo_profile_token_info.token = kTestUserinfoToken;
224 userinfo_profile_token_info.scopes.insert(
225 "https://www.googleapis.com/auth/userinfo.profile");
226 userinfo_profile_token_info.audience = gaia_urls->oauth2_chrome_client_id();
227 userinfo_profile_token_info.email = kTestAccountId;
228 fake_gaia_->IssueOAuthToken(kTestRefreshToken, userinfo_profile_token_info);
230 // The any-api access token for accessing the token minting endpoint.
231 FakeGaia::AccessTokenInfo login_token_info;
232 login_token_info.token = kTestLoginToken;
233 login_token_info.scopes.insert(GaiaConstants::kAnyApiOAuth2Scope);
234 login_token_info.audience = gaia_urls->oauth2_chrome_client_id();
235 fake_gaia_->IssueOAuthToken(kTestRefreshToken, login_token_info);
237 // The /auth/chromesync access token for accessing sync endpoint.
238 FakeGaia::AccessTokenInfo sync_token_info;
239 sync_token_info.token = kTestSyncToken;
240 sync_token_info.scopes.insert(GaiaConstants::kChromeSyncOAuth2Scope);
241 sync_token_info.audience = gaia_urls->oauth2_chrome_client_id();
242 fake_gaia_->IssueOAuthToken(kTestRefreshToken, sync_token_info);
244 FakeGaia::AccessTokenInfo auth_login_token_info;
245 auth_login_token_info.token = kTestAuthLoginToken;
246 auth_login_token_info.scopes.insert(gaia_urls->oauth1_login_scope());
247 auth_login_token_info.audience = gaia_urls->oauth2_chrome_client_id();
248 fake_gaia_->IssueOAuthToken(kTestRefreshToken, auth_login_token_info);
251 void CheckSessionState(OAuth2LoginManager::SessionRestoreState state) {
252 OAuth2LoginManager* login_manager =
253 OAuth2LoginManagerFactory::GetInstance()->GetForProfile(
254 profile());
255 ASSERT_EQ(state, login_manager->state());
258 void WaitForMergeSessionCompletion(
259 OAuth2LoginManager::SessionRestoreState final_state) {
260 // Wait for the session merge to finish.
261 std::set<OAuth2LoginManager::SessionRestoreState> states;
262 states.insert(OAuth2LoginManager::SESSION_RESTORE_DONE);
263 states.insert(OAuth2LoginManager::SESSION_RESTORE_FAILED);
264 states.insert(OAuth2LoginManager::SESSION_RESTORE_CONNECTION_FAILED);
265 OAuth2LoginManagerStateWaiter merge_session_waiter(profile());
266 merge_session_waiter.WaitForStates(states);
267 EXPECT_EQ(merge_session_waiter.final_state(), final_state);
270 void StartNewUserSession() {
271 SetupGaiaServerForNewAccount();
272 SimulateNetworkOnline();
273 chromeos::WizardController::SkipPostLoginScreensForTesting();
274 chromeos::WizardController* wizard_controller =
275 chromeos::WizardController::default_controller();
276 wizard_controller->SkipToLoginForTesting(LoginScreenContext());
278 content::WindowedNotificationObserver(
279 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
280 content::NotificationService::AllSources()).Wait();
282 // Use capitalized and dotted user name on purpose to make sure
283 // our email normalization kicks in.
284 GetLoginDisplay()->ShowSigninScreenForCreds(kTestRawAccountId,
285 kTestAccountPassword);
287 content::WindowedNotificationObserver(
288 chrome::NOTIFICATION_SESSION_STARTED,
289 content::NotificationService::AllSources()).Wait();
292 DISALLOW_COPY_AND_ASSIGN(OAuth2Test);
295 class CookieReader : public base::RefCountedThreadSafe<CookieReader> {
296 public:
297 CookieReader() {
300 void ReadCookies(Profile* profile) {
301 context_ = profile->GetRequestContext();
302 content::BrowserThread::PostTask(
303 content::BrowserThread::IO, FROM_HERE,
304 base::Bind(&CookieReader::ReadCookiesOnIOThread,
305 this));
306 runner_ = new content::MessageLoopRunner;
307 runner_->Run();
310 std::string GetCookieValue(const std::string& name) {
311 for (std::vector<net::CanonicalCookie>::const_iterator iter =
312 cookie_list_.begin();
313 iter != cookie_list_.end();
314 ++iter) {
315 if (iter->Name() == name) {
316 return iter->Value();
319 return std::string();
322 private:
323 friend class base::RefCountedThreadSafe<CookieReader>;
325 virtual ~CookieReader() {
328 void ReadCookiesOnIOThread() {
329 context_->GetURLRequestContext()->cookie_store()->GetCookieMonster()->
330 GetAllCookiesAsync(base::Bind(
331 &CookieReader::OnGetAllCookiesOnUIThread,
332 this));
335 void OnGetAllCookiesOnUIThread(const net::CookieList& cookies) {
336 cookie_list_ = cookies;
337 content::BrowserThread::PostTask(
338 content::BrowserThread::UI, FROM_HERE,
339 base::Bind(&CookieReader::OnCookiesReadyOnUIThread,
340 this));
343 void OnCookiesReadyOnUIThread() {
344 runner_->Quit();
347 scoped_refptr<net::URLRequestContextGetter> context_;
348 net::CookieList cookie_list_;
349 scoped_refptr<content::MessageLoopRunner> runner_;
351 DISALLOW_COPY_AND_ASSIGN(CookieReader);
354 // PRE_MergeSession is testing merge session for a new profile.
355 IN_PROC_BROWSER_TEST_F(OAuth2Test, PRE_PRE_MergeSession) {
356 StartNewUserSession();
358 // Wait for the session merge to finish.
359 WaitForMergeSessionCompletion(OAuth2LoginManager::SESSION_RESTORE_DONE);
361 // Check for existance of refresh token.
362 ProfileOAuth2TokenService* token_service =
363 ProfileOAuth2TokenServiceFactory::GetForProfile(
364 profile());
365 EXPECT_TRUE(token_service->RefreshTokenIsAvailable(kTestAccountId));
367 EXPECT_EQ(GetOAuthStatusFromLocalState(kTestAccountId),
368 User::OAUTH2_TOKEN_STATUS_VALID);
370 scoped_refptr<CookieReader> cookie_reader(new CookieReader());
371 cookie_reader->ReadCookies(profile());
372 EXPECT_EQ(cookie_reader->GetCookieValue("SID"), kTestSessionSIDCookie);
373 EXPECT_EQ(cookie_reader->GetCookieValue("LSID"), kTestSessionLSIDCookie);
376 // MergeSession test is running merge session process for an existing profile
377 // that was generated in PRE_PRE_MergeSession test.
378 IN_PROC_BROWSER_TEST_F(OAuth2Test, PRE_MergeSession) {
379 SetupGaiaServerForExistingAccount();
380 SimulateNetworkOnline();
382 content::WindowedNotificationObserver(
383 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
384 content::NotificationService::AllSources()).Wait();
386 JsExpect("!!document.querySelector('#account-picker')");
387 JsExpect("!!document.querySelector('#pod-row')");
389 EXPECT_EQ(GetOAuthStatusFromLocalState(kTestAccountId),
390 User::OAUTH2_TOKEN_STATUS_VALID);
392 EXPECT_TRUE(TryToLogin(kTestAccountId, kTestAccountPassword));
394 // Wait for the session merge to finish.
395 WaitForMergeSessionCompletion(OAuth2LoginManager::SESSION_RESTORE_DONE);
397 // Check for existance of refresh token.
398 ProfileOAuth2TokenService* token_service =
399 ProfileOAuth2TokenServiceFactory::GetForProfile(profile());
400 EXPECT_TRUE(token_service->RefreshTokenIsAvailable(kTestAccountId));
402 EXPECT_EQ(GetOAuthStatusFromLocalState(kTestAccountId),
403 User::OAUTH2_TOKEN_STATUS_VALID);
405 scoped_refptr<CookieReader> cookie_reader(new CookieReader());
406 cookie_reader->ReadCookies(profile());
407 EXPECT_EQ(cookie_reader->GetCookieValue("SID"), kTestSession2SIDCookie);
408 EXPECT_EQ(cookie_reader->GetCookieValue("LSID"), kTestSession2LSIDCookie);
411 // MergeSession test is attempting to merge session for an existing profile
412 // that was generated in PRE_PRE_MergeSession test. This attempt should fail
413 // since FakeGaia instance isn't configured to return relevant tokens/cookies.
414 IN_PROC_BROWSER_TEST_F(OAuth2Test, MergeSession) {
415 SimulateNetworkOnline();
417 content::WindowedNotificationObserver(
418 chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
419 content::NotificationService::AllSources()).Wait();
421 JsExpect("!!document.querySelector('#account-picker')");
422 JsExpect("!!document.querySelector('#pod-row')");
424 EXPECT_EQ(GetOAuthStatusFromLocalState(kTestAccountId),
425 User::OAUTH2_TOKEN_STATUS_VALID);
427 EXPECT_TRUE(TryToLogin(kTestAccountId, kTestAccountPassword));
429 // Wait for the session merge to finish.
430 WaitForMergeSessionCompletion(OAuth2LoginManager::SESSION_RESTORE_FAILED);
432 EXPECT_EQ(GetOAuthStatusFromLocalState(kTestAccountId),
433 User::OAUTH2_TOKEN_STATUS_INVALID);
437 const char kGooglePageContent[] =
438 "<html><title>Hello!</title><script>alert('hello');</script>"
439 "<body>Hello Google!</body></html>";
440 const char kRandomPageContent[] =
441 "<html><title>SomthingElse</title><body>I am SomethingElse</body></html>";
442 const char kHelloPagePath[] = "/hello_google";
443 const char kRandomPagePath[] = "/non_google_page";
446 // FakeGoogle serves content of http://www.google.com/hello_google page for
447 // merge session tests.
448 class FakeGoogle {
449 public:
450 FakeGoogle() : start_event_(true, false) {
453 ~FakeGoogle() {}
455 scoped_ptr<HttpResponse> HandleRequest(const HttpRequest& request) {
456 // The scheme and host of the URL is actually not important but required to
457 // get a valid GURL in order to parse |request.relative_url|.
458 GURL request_url = GURL("http://localhost").Resolve(request.relative_url);
459 LOG(WARNING) << "Requesting page " << request.relative_url;
460 std::string request_path = request_url.path();
461 scoped_ptr<BasicHttpResponse> http_response(new BasicHttpResponse());
462 if (request_path == kHelloPagePath) { // Serving "google" page.
463 start_event_.Signal();
464 content::BrowserThread::PostTask(
465 content::BrowserThread::UI, FROM_HERE,
466 base::Bind(&FakeGoogle::QuitRunnerOnUIThread,
467 base::Unretained(this)));
469 http_response->set_code(net::HTTP_OK);
470 http_response->set_content_type("text/html");
471 http_response->set_content(kGooglePageContent);
472 } else if (request_path == kRandomPagePath) { // Serving "non-google" page.
473 http_response->set_code(net::HTTP_OK);
474 http_response->set_content_type("text/html");
475 http_response->set_content(kRandomPageContent);
476 } else {
477 return scoped_ptr<HttpResponse>(); // Request not understood.
480 return http_response.PassAs<HttpResponse>();
483 // True if we have already served the test page.
484 bool IsPageRequested () {
485 return start_event_.IsSignaled();
488 // Waits until we receive a request to serve the test page.
489 void WaitForPageRequest() {
490 // If we have already served the request, bail out.
491 if (start_event_.IsSignaled())
492 return;
494 runner_ = new content::MessageLoopRunner;
495 runner_->Run();
498 private:
499 void QuitRunnerOnUIThread() {
500 if (runner_.get())
501 runner_->Quit();
503 // This event will tell us when we actually see HTTP request on the server
504 // side. It should be signalled only after the page/XHR throttle had been
505 // removed (after merge session completes).
506 base::WaitableEvent start_event_;
507 scoped_refptr<content::MessageLoopRunner> runner_;
509 DISALLOW_COPY_AND_ASSIGN(FakeGoogle);
512 // FakeGaia specialization that can delay /MergeSession handler until
513 // we explicitly call DelayedFakeGaia::UnblockMergeSession().
514 class DelayedFakeGaia : public FakeGaia {
515 public:
516 DelayedFakeGaia()
517 : blocking_event_(true, false),
518 start_event_(true, false) {
521 void UnblockMergeSession() {
522 blocking_event_.Signal();
525 void WaitForMergeSessionToStart() {
526 // If we have already served the request, bail out.
527 if (start_event_.IsSignaled())
528 return;
530 runner_ = new content::MessageLoopRunner;
531 runner_->Run();
534 private:
535 // FakeGaia overrides.
536 virtual void HandleMergeSession(const HttpRequest& request,
537 BasicHttpResponse* http_response) OVERRIDE {
538 start_event_.Signal();
539 content::BrowserThread::PostTask(
540 content::BrowserThread::UI, FROM_HERE,
541 base::Bind(&DelayedFakeGaia::QuitRunnerOnUIThread,
542 base::Unretained(this)));
543 blocking_event_.Wait();
544 FakeGaia::HandleMergeSession(request, http_response);
547 void QuitRunnerOnUIThread() {
548 if (runner_.get())
549 runner_->Quit();
552 base::WaitableEvent blocking_event_;
553 base::WaitableEvent start_event_;
554 scoped_refptr<content::MessageLoopRunner> runner_;
556 DISALLOW_COPY_AND_ASSIGN(DelayedFakeGaia);
559 class MergeSessionTest : public OAuth2Test {
560 protected:
561 MergeSessionTest() : delayed_fake_gaia_(new DelayedFakeGaia()) {
562 fake_gaia_.reset(delayed_fake_gaia_);
565 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
566 OAuth2Test::SetUpCommandLine(command_line);
568 // Get fake URL for fake google.com.
569 const GURL& server_url = embedded_test_server()->base_url();
570 std::string google_host("www.google.com");
571 GURL::Replacements replace_google_host;
572 replace_google_host.SetHostStr(google_host);
573 GURL google_url = server_url.ReplaceComponents(replace_google_host);
574 fake_google_page_url_ = google_url.Resolve(kHelloPagePath);
576 std::string non_google_host("www.somethingelse.org");
577 GURL::Replacements replace_non_google_host;
578 replace_non_google_host.SetHostStr(non_google_host);
579 GURL non_google_url = server_url.ReplaceComponents(replace_non_google_host);
580 non_google_page_url_ = non_google_url.Resolve(kRandomPagePath);
583 virtual void SetUp() OVERRIDE {
584 embedded_test_server()->RegisterRequestHandler(
585 base::Bind(&FakeGoogle::HandleRequest,
586 base::Unretained(&fake_google_)));
587 OAuth2Test::SetUp();
590 protected:
591 void UnblockMergeSession() {
592 delayed_fake_gaia_->UnblockMergeSession();
595 void WaitForMergeSessionToStart() {
596 delayed_fake_gaia_->WaitForMergeSessionToStart();
599 void JsExpect(content::WebContents* contents,
600 const std::string& expression) {
601 bool result;
602 ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
603 contents,
604 "window.domAutomationController.send(!!(" + expression + "));",
605 &result));
606 ASSERT_TRUE(result) << expression;
609 const GURL& GetBackGroundPageUrl(const std::string& extension_id) {
610 extensions::ProcessManager* manager =
611 extensions::ExtensionSystem::Get(profile())->process_manager();
612 extensions::ExtensionHost* host =
613 manager->GetBackgroundHostForExtension(extension_id);
614 return host->host_contents()->GetURL();
617 void JsExpectOnBackgroundPage(const std::string& extension_id,
618 const std::string& expression) {
619 extensions::ProcessManager* manager =
620 extensions::ExtensionSystem::Get(profile())->process_manager();
621 extensions::ExtensionHost* host =
622 manager->GetBackgroundHostForExtension(extension_id);
623 if (host == NULL) {
624 ADD_FAILURE() << "Extension " << extension_id
625 << " has no background page.";
626 return;
629 JsExpect(host->host_contents(), expression);
632 FakeGoogle fake_google_;
633 DelayedFakeGaia* delayed_fake_gaia_;
634 GURL fake_google_page_url_;
635 GURL non_google_page_url_;
637 private:
638 DISALLOW_COPY_AND_ASSIGN(MergeSessionTest);
641 Browser* FindOrCreateVisibleBrowser(Profile* profile) {
642 chrome::ScopedTabbedBrowserDisplayer displayer(
643 profile, chrome::GetActiveDesktop());
644 Browser* browser = displayer.browser();
645 if (browser->tab_strip_model()->count() == 0)
646 chrome::AddTabAt(browser, GURL(), -1, true);
647 return browser;
650 IN_PROC_BROWSER_TEST_F(MergeSessionTest, PageThrottle) {
651 StartNewUserSession();
653 // Try to open a page from google.com.
654 Browser* browser =
655 FindOrCreateVisibleBrowser(profile());
656 ui_test_utils::NavigateToURLWithDisposition(
657 browser,
658 fake_google_page_url_,
659 CURRENT_TAB, ui_test_utils::BROWSER_TEST_NONE);
661 // Wait until we get send merge session request.
662 WaitForMergeSessionToStart();
664 // Make sure the page is blocked by the throttle.
665 EXPECT_FALSE(fake_google_.IsPageRequested());
667 // Check that throttle page is displayed instead.
668 base::string16 title;
669 ui_test_utils::GetCurrentTabTitle(browser, &title);
670 DVLOG(1) << "Loaded page at the start : " << title;
672 // Unblock GAIA request.
673 UnblockMergeSession();
675 // Wait for the session merge to finish.
676 WaitForMergeSessionCompletion(OAuth2LoginManager::SESSION_RESTORE_DONE);
678 // Make sure the test page is served.
679 fake_google_.WaitForPageRequest();
681 // Check that real page is no longer blocked by the throttle and that the
682 // real page pops up JS dialog.
683 AppModalDialog* dialog = ui_test_utils::WaitForAppModalDialog();
684 ASSERT_TRUE(dialog->IsJavaScriptModalDialog());
685 JavaScriptAppModalDialog* js_dialog =
686 static_cast<JavaScriptAppModalDialog*>(dialog);
687 js_dialog->native_dialog()->AcceptAppModalDialog();
689 ui_test_utils::GetCurrentTabTitle(browser, &title);
690 DVLOG(1) << "Loaded page at the end : " << title;
693 IN_PROC_BROWSER_TEST_F(MergeSessionTest, XHRThrottle) {
694 StartNewUserSession();
696 // Wait until we get send merge session request.
697 WaitForMergeSessionToStart();
699 // Reset ExtensionBrowserTest::observer_ to the right browser object.
700 Browser* browser = FindOrCreateVisibleBrowser(profile());
701 observer_.reset(new ExtensionTestNotificationObserver(browser));
703 // Run background page tests. The tests will just wait for XHR request
704 // to complete.
705 ResultCatcher catcher;
707 scoped_ptr<ExtensionTestMessageListener> non_google_xhr_listener(
708 new ExtensionTestMessageListener("non-google-xhr-received", false));
710 // Load extension with a background page. The background page will
711 // attempt to load |fake_google_page_url_| via XHR.
712 const extensions::Extension* ext = LoadExtension(
713 test_data_dir_.AppendASCII("merge_session"));
714 ASSERT_TRUE(ext);
716 // Kick off XHR request from the extension.
717 JsExpectOnBackgroundPage(
718 ext->id(),
719 base::StringPrintf("startThrottledTests('%s', '%s')",
720 fake_google_page_url_.spec().c_str(),
721 non_google_page_url_.spec().c_str()));
723 // Verify that we've sent XHR request form the extension side...
724 JsExpectOnBackgroundPage(ext->id(),
725 "googleRequestSent && !googleResponseReceived");
727 // ...but didn't see it on the server side yet.
728 EXPECT_FALSE(fake_google_.IsPageRequested());
730 // Unblock GAIA request.
731 UnblockMergeSession();
733 // Wait for the session merge to finish.
734 WaitForMergeSessionCompletion(OAuth2LoginManager::SESSION_RESTORE_DONE);
736 // Wait until non-google XHR content to load first.
737 ASSERT_TRUE(non_google_xhr_listener->WaitUntilSatisfied());
739 if (!catcher.GetNextResult()) {
740 std::string message = catcher.message();
741 ADD_FAILURE() << "Tests failed: " << message;
744 EXPECT_TRUE(fake_google_.IsPageRequested());
747 } // namespace chromeos