1 // Copyright (c) 2011 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. 4 5 #include "base/command_line.h" 6 #include "base/memory/scoped_ptr.h" 7 #include "base/message_loop.h" 8 #include "chrome/browser/automation/ui_controls.h" 9 #include "chrome/browser/chromeos/cros/cros_in_process_browser_test.h" 10 #include "chrome/browser/chromeos/cros/mock_input_method_library.h" 11 #include "chrome/browser/chromeos/cros/mock_screen_lock_library.h" 12 #include "chrome/browser/chromeos/login/mock_authenticator.h" 13 #include "chrome/browser/chromeos/login/screen_locker.h" 14 #include "chrome/browser/chromeos/login/screen_locker_tester.h" 15 #include "chrome/browser/chromeos/login/user_manager.h" 16 #include "chrome/browser/profiles/profile_manager.h" 17 #include "chrome/browser/ui/browser.h" 18 #include "chrome/browser/ui/browser_window.h" 19 #include "chrome/browser/ui/views/browser_dialogs.h" 20 #include "chrome/common/chrome_switches.h" 21 #include "chrome/test/ui_test_utils.h" 22 #include "content/common/notification_service.h" 23 #include "content/common/notification_type.h" 24 #include "testing/gmock/include/gmock/gmock.h" 25 #include "testing/gtest/include/gtest/gtest.h" 26 #include "views/controls/textfield/textfield.h" 27 #include "views/window/window_gtk.h" 28 29 namespace { 30 31 // An object that wait for lock state and fullscreen state. 32 class Waiter : public NotificationObserver { 33 public: 34 explicit Waiter(Browser* browser) 35 : browser_(browser), 36 running_(false) { 37 registrar_.Add(this, 38 NotificationType::SCREEN_LOCK_STATE_CHANGED, 39 NotificationService::AllSources()); 40 handler_id_ = g_signal_connect( 41 G_OBJECT(browser_->window()->GetNativeHandle()), 42 "window-state-event", 43 G_CALLBACK(OnWindowStateEventThunk), 44 this); 45 } 46 47 ~Waiter() { 48 g_signal_handler_disconnect( 49 G_OBJECT(browser_->window()->GetNativeHandle()), 50 handler_id_); 51 } 52 53 virtual void Observe(NotificationType type, 54 const NotificationSource& source, 55 const NotificationDetails& details) { 56 DCHECK(type == NotificationType::SCREEN_LOCK_STATE_CHANGED); 57 if (running_) 58 MessageLoop::current()->Quit(); 59 } 60 61 // Wait until the two conditions are met. 62 void Wait(bool locker_state, bool fullscreen) { 63 running_ = true; 64 scoped_ptr<chromeos::test::ScreenLockerTester> 65 tester(chromeos::ScreenLocker::GetTester()); 66 while (tester->IsLocked() != locker_state || 67 browser_->window()->IsFullscreen() != fullscreen) { 68 ui_test_utils::RunMessageLoop(); 69 } 70 // Make sure all pending tasks are executed. 71 ui_test_utils::RunAllPendingInMessageLoop(); 72 running_ = false; 73 } 74 75 CHROMEGTK_CALLBACK_1(Waiter, gboolean, OnWindowStateEvent, 76 GdkEventWindowState*); 77 78 private: 79 Browser* browser_; 80 gulong handler_id_; 81 NotificationRegistrar registrar_; 82 83 // Are we currently running the message loop? 84 bool running_; 85 86 DISALLOW_COPY_AND_ASSIGN(Waiter); 87 }; 88 89 gboolean Waiter::OnWindowStateEvent(GtkWidget* widget, 90 GdkEventWindowState* event) { 91 MessageLoop::current()->Quit(); 92 return false; 93 } 94 95 } // namespace 96 97 namespace chromeos { 98 99 class ScreenLockerTest : public CrosInProcessBrowserTest { 100 public: 101 ScreenLockerTest() : mock_screen_lock_library_(NULL), 102 mock_input_method_library_(NULL) { 103 } 104 105 protected: 106 MockScreenLockLibrary *mock_screen_lock_library_; 107 MockInputMethodLibrary *mock_input_method_library_; 108 109 // Test the no password mode with different unlock scheme given by 110 // |unlock| function. 111 void TestNoPassword(void (unlock)(views::Widget*)) { 112 EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenUnlockRequested()) 113 .Times(1) 114 .RetiresOnSaturation(); 115 EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenLockCompleted()) 116 .Times(1) 117 .RetiresOnSaturation(); 118 UserManager::Get()->OffTheRecordUserLoggedIn(); 119 ScreenLocker::Show(); 120 scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester()); 121 tester->EmulateWindowManagerReady(); 122 if (!chromeos::ScreenLocker::GetTester()->IsLocked()) 123 ui_test_utils::WaitForNotification( 124 NotificationType::SCREEN_LOCK_STATE_CHANGED); 125 EXPECT_TRUE(tester->IsLocked()); 126 tester->InjectMockAuthenticator("", ""); 127 128 unlock(tester->GetWidget()); 129 130 ui_test_utils::RunAllPendingInMessageLoop(); 131 EXPECT_TRUE(tester->IsLocked()); 132 133 // Emulate LockScreen request from PowerManager (via SessionManager). 134 ScreenLocker::Hide(); 135 ui_test_utils::RunAllPendingInMessageLoop(); 136 EXPECT_FALSE(tester->IsLocked()); 137 } 138 139 void LockScreenWithUser(test::ScreenLockerTester* tester, 140 const std::string& user) { 141 UserManager::Get()->UserLoggedIn(user); 142 ScreenLocker::Show(); 143 tester->EmulateWindowManagerReady(); 144 if (!tester->IsLocked()) { 145 ui_test_utils::WaitForNotification( 146 NotificationType::SCREEN_LOCK_STATE_CHANGED); 147 } 148 EXPECT_TRUE(tester->IsLocked()); 149 } 150 151 private: 152 virtual void SetUpInProcessBrowserTestFixture() { 153 cros_mock_->InitStatusAreaMocks(); 154 cros_mock_->InitMockScreenLockLibrary(); 155 mock_screen_lock_library_ = cros_mock_->mock_screen_lock_library(); 156 mock_input_method_library_ = cros_mock_->mock_input_method_library(); 157 EXPECT_CALL(*mock_screen_lock_library_, AddObserver(testing::_)) 158 .Times(1) 159 .RetiresOnSaturation(); 160 EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenUnlockCompleted()) 161 .Times(1) 162 .RetiresOnSaturation(); 163 // Expectations for the status are on the screen lock window. 164 cros_mock_->SetStatusAreaMocksExpectations(); 165 // Expectations for the status area on the browser window. 166 cros_mock_->SetStatusAreaMocksExpectations(); 167 } 168 169 virtual void SetUpCommandLine(CommandLine* command_line) { 170 command_line->AppendSwitchASCII(switches::kLoginProfile, "user"); 171 command_line->AppendSwitch(switches::kNoFirstRun); 172 } 173 174 DISALLOW_COPY_AND_ASSIGN(ScreenLockerTest); 175 }; 176 177 // Temporarily disabling all screen locker tests while investigating the 178 // issue crbug.com/78764. 179 IN_PROC_BROWSER_TEST_F(ScreenLockerTest, DISABLED_TestBasic) { 180 EXPECT_CALL(*mock_input_method_library_, GetNumActiveInputMethods()) 181 .Times(1) 182 .WillRepeatedly((testing::Return(0))) 183 .RetiresOnSaturation(); 184 EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenUnlockRequested()) 185 .Times(1) 186 .RetiresOnSaturation(); 187 EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenLockCompleted()) 188 .Times(1) 189 .RetiresOnSaturation(); 190 UserManager::Get()->UserLoggedIn("user"); 191 ScreenLocker::Show(); 192 scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester()); 193 tester->EmulateWindowManagerReady(); 194 if (!chromeos::ScreenLocker::GetTester()->IsLocked()) 195 ui_test_utils::WaitForNotification( 196 NotificationType::SCREEN_LOCK_STATE_CHANGED); 197 198 // Test to make sure that the widget is actually appearing and is of 199 // reasonable size, preventing a regression of 200 // http://code.google.com/p/chromium-os/issues/detail?id=5987 201 gfx::Rect lock_bounds = tester->GetChildWidget()->GetWindowScreenBounds(); 202 EXPECT_GT(lock_bounds.width(), 10); 203 EXPECT_GT(lock_bounds.height(), 10); 204 205 tester->InjectMockAuthenticator("user", "pass"); 206 EXPECT_TRUE(tester->IsLocked()); 207 tester->EnterPassword("fail"); 208 ui_test_utils::RunAllPendingInMessageLoop(); 209 EXPECT_TRUE(tester->IsLocked()); 210 tester->EnterPassword("pass"); 211 ui_test_utils::RunAllPendingInMessageLoop(); 212 // Successful authentication simply send a unlock request to PowerManager. 213 EXPECT_TRUE(tester->IsLocked()); 214 215 // Emulate LockScreen request from PowerManager (via SessionManager). 216 // TODO(oshima): Find out better way to handle this in mock. 217 ScreenLocker::Hide(); 218 ui_test_utils::RunAllPendingInMessageLoop(); 219 EXPECT_FALSE(tester->IsLocked()); 220 } 221 222 IN_PROC_BROWSER_TEST_F(ScreenLockerTest, DISABLED_TestFullscreenExit) { 223 EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenUnlockRequested()) 224 .Times(1) 225 .RetiresOnSaturation(); 226 EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenLockCompleted()) 227 .Times(1) 228 .RetiresOnSaturation(); 229 scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester()); 230 { 231 Waiter waiter(browser()); 232 browser()->ToggleFullscreenMode(); 233 waiter.Wait(false /* not locked */, true /* full screen */); 234 EXPECT_TRUE(browser()->window()->IsFullscreen()); 235 EXPECT_FALSE(tester->IsLocked()); 236 } 237 { 238 Waiter waiter(browser()); 239 UserManager::Get()->UserLoggedIn("user"); 240 ScreenLocker::Show(); 241 tester->EmulateWindowManagerReady(); 242 waiter.Wait(true /* locked */, false /* full screen */); 243 EXPECT_FALSE(browser()->window()->IsFullscreen()); 244 EXPECT_TRUE(tester->IsLocked()); 245 } 246 tester->InjectMockAuthenticator("user", "pass"); 247 tester->EnterPassword("pass"); 248 ui_test_utils::RunAllPendingInMessageLoop(); 249 ScreenLocker::Hide(); 250 ui_test_utils::RunAllPendingInMessageLoop(); 251 EXPECT_FALSE(tester->IsLocked()); 252 } 253 254 void MouseMove(views::Widget* widget) { 255 ui_controls::SendMouseMove(10, 10); 256 } 257 258 IN_PROC_BROWSER_TEST_F(ScreenLockerTest, 259 DISABLED_TestNoPasswordWithMouseMove) { 260 TestNoPassword(MouseMove); 261 } 262 263 void MouseClick(views::Widget* widget) { 264 ui_controls::SendMouseClick(ui_controls::RIGHT); 265 } 266 267 IN_PROC_BROWSER_TEST_F(ScreenLockerTest, 268 DISABLED_TestNoPasswordWithMouseClick) { 269 TestNoPassword(MouseClick); 270 } 271 272 void KeyPress(views::Widget* widget) { 273 ui_controls::SendKeyPress(GTK_WINDOW(widget->GetNativeView()), 274 ui::VKEY_SPACE, false, false, false, false); 275 } 276 277 IN_PROC_BROWSER_TEST_F(ScreenLockerTest, DISABLED_TestNoPasswordWithKeyPress) { 278 TestNoPassword(KeyPress); 279 } 280 281 IN_PROC_BROWSER_TEST_F(ScreenLockerTest, DISABLED_TestShowTwice) { 282 EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenLockCompleted()) 283 .Times(2) 284 .RetiresOnSaturation(); 285 scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester()); 286 LockScreenWithUser(tester.get(), "user"); 287 288 // Ensure there's a profile or this test crashes. 289 ProfileManager::GetDefaultProfile(); 290 291 // Calling Show again simply send LockCompleted signal. 292 ScreenLocker::Show(); 293 EXPECT_TRUE(tester->IsLocked()); 294 295 // Close the locker to match expectations. 296 ScreenLocker::Hide(); 297 ui_test_utils::RunAllPendingInMessageLoop(); 298 EXPECT_FALSE(tester->IsLocked()); 299 } 300 301 IN_PROC_BROWSER_TEST_F(ScreenLockerTest, DISABLED_TestEscape) { 302 EXPECT_CALL(*mock_screen_lock_library_, NotifyScreenLockCompleted()) 303 .Times(1) 304 .RetiresOnSaturation(); 305 scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester()); 306 LockScreenWithUser(tester.get(), "user"); 307 308 // Ensure there's a profile or this test crashes. 309 ProfileManager::GetDefaultProfile(); 310 311 tester->SetPassword("password"); 312 EXPECT_EQ("password", tester->GetPassword()); 313 // Escape clears the password. 314 ui_controls::SendKeyPress(GTK_WINDOW(tester->GetWidget()->GetNativeView()), 315 ui::VKEY_ESCAPE, false, false, false, false); 316 ui_test_utils::RunAllPendingInMessageLoop(); 317 EXPECT_EQ("", tester->GetPassword()); 318 319 // Close the locker to match expectations. 320 ScreenLocker::Hide(); 321 ui_test_utils::RunAllPendingInMessageLoop(); 322 EXPECT_FALSE(tester->IsLocked()); 323 } 324 325 } // namespace chromeos 326