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.
6 #include "ash/system/tray/system_tray.h"
7 #include "base/command_line.h"
8 #include "base/json/json_file_value_serializer.h"
9 #include "base/path_service.h"
10 #include "base/strings/string_util.h"
11 #include "chrome/browser/chrome_notification_types.h"
12 #include "chrome/browser/chromeos/login/login_manager_test.h"
13 #include "chrome/browser/chromeos/login/login_wizard.h"
14 #include "chrome/browser/chromeos/login/startup_utils.h"
15 #include "chrome/browser/chromeos/login/ui/login_display_host_impl.h"
16 #include "chrome/browser/chromeos/login/wizard_controller.h"
17 #include "chrome/browser/chromeos/settings/cros_settings.h"
18 #include "chrome/browser/profiles/profile_manager.h"
19 #include "chrome/browser/profiles/profiles_state.h"
20 #include "chrome/browser/ui/browser.h"
21 #include "chrome/common/chrome_constants.h"
22 #include "chrome/common/chrome_paths.h"
23 #include "chrome/common/chrome_switches.h"
24 #include "chrome/common/pref_names.h"
25 #include "chrome/test/base/in_process_browser_test.h"
26 #include "chrome/test/base/interactive_test_utils.h"
27 #include "chrome/test/base/tracing.h"
28 #include "chrome/test/base/ui_test_utils.h"
29 #include "chromeos/chromeos_switches.h"
30 #include "chromeos/login/user_names.h"
31 #include "chromeos/settings/cros_settings_names.h"
32 #include "content/public/browser/render_frame_host.h"
33 #include "content/public/test/browser_test_utils.h"
34 #include "content/public/test/test_utils.h"
35 #include "extensions/browser/extension_system.h"
36 #include "testing/gmock/include/gmock/gmock.h"
37 #include "testing/gtest/include/gtest/gtest.h"
40 using ::testing::AnyNumber
;
41 using ::testing::Return
;
45 const char kGaiaId
[] = "12345";
46 const char kTestUser
[] = "test-user@gmail.com";
47 const char kPassword
[] = "password";
49 void FilterFrameByName(std::set
<content::RenderFrameHost
*>* frame_set
,
50 const std::string
& frame_name
,
51 content::RenderFrameHost
* frame
) {
52 if (frame
->GetFrameName() == frame_name
)
53 frame_set
->insert(frame
);
56 class LoginUserTest
: public InProcessBrowserTest
{
58 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
59 command_line
->AppendSwitchASCII(
60 chromeos::switches::kLoginUser
, "TestUser@gmail.com");
61 command_line
->AppendSwitchASCII(chromeos::switches::kLoginProfile
,
66 class LoginGuestTest
: public InProcessBrowserTest
{
68 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
69 command_line
->AppendSwitch(chromeos::switches::kGuestSession
);
70 command_line
->AppendSwitch(::switches::kIncognito
);
71 command_line
->AppendSwitchASCII(chromeos::switches::kLoginProfile
,
73 command_line
->AppendSwitchASCII(chromeos::switches::kLoginUser
,
74 chromeos::login::kGuestUserName
);
78 class LoginCursorTest
: public InProcessBrowserTest
{
80 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
81 command_line
->AppendSwitch(chromeos::switches::kLoginManager
);
85 class LoginSigninTest
: public InProcessBrowserTest
{
87 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
88 command_line
->AppendSwitch(chromeos::switches::kLoginManager
);
89 command_line
->AppendSwitch(chromeos::switches::kForceLoginManagerInTests
);
92 void SetUpOnMainThread() override
{
93 ASSERT_TRUE(tracing::BeginTracingWithWatch(
94 "ui", "ui", "ShowLoginWebUI", 1));
98 class LoginTest
: public chromeos::LoginManagerTest
{
100 LoginTest() : LoginManagerTest(true) {}
101 ~LoginTest() override
{}
103 content::RenderFrameHost
* GetNamedFrame(const std::string
& frame_name
) {
104 std::set
<content::RenderFrameHost
*> frame_set
;
105 web_contents()->ForEachFrame(
106 base::Bind(&FilterFrameByName
, &frame_set
, frame_name
));
107 return frame_set
.empty() ? NULL
: *frame_set
.begin();
110 void ExecuteJsInGaiaAuthFrame(const std::string
& js
) {
111 content::RenderFrameHost
* frame
= GetNamedFrame("signin-frame");
113 ASSERT_TRUE(content::ExecuteScript(frame
, js
));
116 void StartGaiaAuthOffline() {
117 content::DOMMessageQueue message_queue
;
118 const std::string js
= "(function() {"
119 "var authenticator = $('gaia-signin').gaiaAuthHost_;"
120 "authenticator.addEventListener('ready',"
122 "authenticator.removeEventListener('ready', f);"
123 "window.domAutomationController.setAutomationId(0);"
124 "window.domAutomationController.send('offlineLoaded');"
126 "$('error-offline-login-link').onclick();"
128 ASSERT_TRUE(content::ExecuteScript(web_contents(), js
));
132 ASSERT_TRUE(message_queue
.WaitForMessage(&message
));
133 } while (message
!= "\"offlineLoaded\"");
136 void SubmitOldGaiaAuthOfflineForm(const std::string
& user_email
,
137 const std::string
& password
) {
138 // Note the input elements must match gaia_auth/offline.html.
139 JSExpect("document.querySelector('#offline-gaia').hidden");
140 JSExpect("!document.querySelector('#signin-frame').hidden");
143 "document.getElementsByName('email')[0].value = '$Email';"
144 "document.getElementsByName('password')[0].value = '$Password';"
145 "document.getElementById('submit-button').click();"
147 base::ReplaceSubstringsAfterOffset(&js
, 0, "$Email", user_email
);
148 base::ReplaceSubstringsAfterOffset(&js
, 0, "$Password", password
);
149 ExecuteJsInGaiaAuthFrame(js
);
152 void SubmitGaiaAuthOfflineForm(const std::string
& user_email
,
153 const std::string
& password
) {
154 const std::string animated_pages
=
155 "document.querySelector('#offline-gaia /deep/ "
157 const std::string email_input
=
158 "document.querySelector('#offline-gaia /deep/ #emailInput')";
159 const std::string email_next_button
=
160 "document.querySelector('#offline-gaia /deep/ #emailSection "
162 const std::string password_input
=
163 "document.querySelector('#offline-gaia /deep/ "
165 const std::string password_next_button
=
166 "document.querySelector('#offline-gaia /deep/ #passwordSection"
169 content::DOMMessageQueue message_queue
;
170 JSExpect("!document.querySelector('#offline-gaia').hidden");
171 JSExpect("document.querySelector('#signin-frame').hidden");
172 const std::string js
=
174 ".addEventListener('neon-animation-finish',"
176 "window.domAutomationController.setAutomationId(0);"
177 "window.domAutomationController.send('switchToPassword');"
179 ASSERT_TRUE(content::ExecuteScript(web_contents(), js
));
180 std::string set_email
= email_input
+ ".value = '$Email'";
181 base::ReplaceSubstringsAfterOffset(&set_email
, 0, "$Email", user_email
);
182 ASSERT_TRUE(content::ExecuteScript(web_contents(), set_email
));
183 ASSERT_TRUE(content::ExecuteScript(web_contents(),
184 email_next_button
+ ".fire('tap')"));
187 ASSERT_TRUE(message_queue
.WaitForMessage(&message
));
188 } while (message
!= "\"switchToPassword\"");
190 std::string set_password
= password_input
+ ".value = '$Password'";
191 base::ReplaceSubstringsAfterOffset(&set_password
, 0, "$Password", password
);
192 ASSERT_TRUE(content::ExecuteScript(web_contents(), set_password
));
193 ASSERT_TRUE(content::ExecuteScript(web_contents(),
194 password_next_button
+ ".fire('tap')"));
197 void PrepareOfflineLogin() {
199 ASSERT_TRUE(chromeos::CrosSettings::Get()->GetBoolean(
200 chromeos::kAccountsPrefShowUserNamesOnSignIn
, &show_user
));
201 ASSERT_FALSE(show_user
);
203 StartGaiaAuthOffline();
205 chromeos::UserContext
user_context(kTestUser
);
206 user_context
.SetGaiaID(kGaiaId
);
207 user_context
.SetKey(chromeos::Key(kPassword
));
208 SetExpectedCredentials(user_context
);
212 class LoginOfflineTest
: public LoginTest
{
214 LoginOfflineTest() {}
215 ~LoginOfflineTest() override
{}
217 bool SetUpUserDataDirectory() override
{
218 base::FilePath user_data_dir
;
219 CHECK(PathService::Get(chrome::DIR_USER_DATA
, &user_data_dir
));
220 base::FilePath local_state_path
=
221 user_data_dir
.Append(chrome::kLocalStateFilename
);
222 base::DictionaryValue local_state_dict
;
224 // Set webview disabled flag only when local state file does not exist.
225 // Otherwise, we break PRE tests that leave state in it.
226 if (!base::PathExists(local_state_path
)) {
227 // TODO(rsorokin): Fix offline test for webview signin.
228 // http://crbug.com/475569
229 local_state_dict
.SetBoolean(prefs::kWebviewSigninDisabled
, true);
231 CHECK(JSONFileValueSerializer(local_state_path
)
232 .Serialize(local_state_dict
));
235 return LoginTest::SetUpUserDataDirectory();
239 // Used to make sure that the system tray is visible and within the screen
240 // bounds after login.
241 void TestSystemTrayIsVisible() {
242 ash::SystemTray
* tray
= ash::Shell::GetInstance()->GetPrimarySystemTray();
243 aura::Window
* primary_win
= ash::Shell::GetPrimaryRootWindow();
244 EXPECT_TRUE(tray
->visible());
245 EXPECT_TRUE(primary_win
->bounds().Contains(tray
->GetBoundsInScreen()));
248 // After a chrome crash, the session manager will restart chrome with
249 // the -login-user flag indicating that the user is already logged in.
250 // This profile should NOT be an OTR profile.
251 IN_PROC_BROWSER_TEST_F(LoginUserTest
, UserPassed
) {
252 Profile
* profile
= browser()->profile();
253 std::string
profile_base_path("hash");
254 profile_base_path
.insert(0, chrome::kProfileDirPrefix
);
255 EXPECT_EQ(profile_base_path
, profile
->GetPath().BaseName().value());
256 EXPECT_FALSE(profile
->IsOffTheRecord());
258 TestSystemTrayIsVisible();
261 // Verifies the cursor is not hidden at startup when user is logged in.
262 IN_PROC_BROWSER_TEST_F(LoginUserTest
, CursorShown
) {
263 EXPECT_TRUE(ash::Shell::GetInstance()->cursor_manager()->IsCursorVisible());
265 TestSystemTrayIsVisible();
268 // After a guest login, we should get the OTR default profile.
269 IN_PROC_BROWSER_TEST_F(LoginGuestTest
, GuestIsOTR
) {
270 Profile
* profile
= browser()->profile();
271 EXPECT_TRUE(profile
->IsOffTheRecord());
272 // Ensure there's extension service for this profile.
273 EXPECT_TRUE(extensions::ExtensionSystem::Get(profile
)->extension_service());
275 TestSystemTrayIsVisible();
278 // Verifies the cursor is not hidden at startup when running guest session.
279 IN_PROC_BROWSER_TEST_F(LoginGuestTest
, CursorShown
) {
280 EXPECT_TRUE(ash::Shell::GetInstance()->cursor_manager()->IsCursorVisible());
282 TestSystemTrayIsVisible();
285 // Verifies the cursor is hidden at startup on login screen.
286 IN_PROC_BROWSER_TEST_F(LoginCursorTest
, CursorHidden
) {
287 // Login screen needs to be shown explicitly when running test.
288 chromeos::ShowLoginWizard(chromeos::WizardController::kLoginScreenName
);
290 // Cursor should be hidden at startup
291 EXPECT_FALSE(ash::Shell::GetInstance()->cursor_manager()->IsCursorVisible());
293 // Cursor should be shown after cursor is moved.
294 EXPECT_TRUE(ui_test_utils::SendMouseMoveSync(gfx::Point()));
295 EXPECT_TRUE(ash::Shell::GetInstance()->cursor_manager()->IsCursorVisible());
297 base::MessageLoop::current()->DeleteSoon(
298 FROM_HERE
, chromeos::LoginDisplayHostImpl::default_host());
300 TestSystemTrayIsVisible();
303 // Verifies that the webui for login comes up successfully.
304 IN_PROC_BROWSER_TEST_F(LoginSigninTest
, WebUIVisible
) {
305 base::TimeDelta no_timeout
;
306 EXPECT_TRUE(tracing::WaitForWatchEvent(no_timeout
));
307 std::string json_events
;
308 ASSERT_TRUE(tracing::EndTracing(&json_events
));
311 IN_PROC_BROWSER_TEST_F(LoginOfflineTest
, PRE_OldGaiaAuthOffline
) {
312 RegisterUser(kTestUser
);
313 chromeos::StartupUtils::MarkOobeCompleted();
314 chromeos::CrosSettings::Get()->SetBoolean(
315 chromeos::kAccountsPrefShowUserNamesOnSignIn
, false);
318 IN_PROC_BROWSER_TEST_F(LoginOfflineTest
, OldGaiaAuthOffline
) {
319 PrepareOfflineLogin();
320 content::WindowedNotificationObserver
session_start_waiter(
321 chrome::NOTIFICATION_SESSION_STARTED
,
322 content::NotificationService::AllSources());
323 SubmitOldGaiaAuthOfflineForm(kTestUser
, kPassword
);
324 session_start_waiter
.Wait();
326 TestSystemTrayIsVisible();
329 IN_PROC_BROWSER_TEST_F(LoginTest
, PRE_GaiaAuthOffline
) {
330 RegisterUser(kTestUser
);
331 chromeos::StartupUtils::MarkOobeCompleted();
332 chromeos::CrosSettings::Get()->SetBoolean(
333 chromeos::kAccountsPrefShowUserNamesOnSignIn
, false);
336 IN_PROC_BROWSER_TEST_F(LoginTest
, GaiaAuthOffline
) {
337 PrepareOfflineLogin();
338 content::WindowedNotificationObserver
session_start_waiter(
339 chrome::NOTIFICATION_SESSION_STARTED
,
340 content::NotificationService::AllSources());
341 SubmitGaiaAuthOfflineForm(kTestUser
, kPassword
);
342 session_start_waiter
.Wait();
344 TestSystemTrayIsVisible();