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. 4 5 #include "base/command_line.h" 6 #include "base/memory/scoped_ptr.h" 7 #include "base/message_loop/message_loop.h" 8 #include "chrome/browser/chrome_notification_types.h" 9 #include "chrome/browser/chromeos/cros/cros_in_process_browser_test.h" 10 #include "chrome/browser/chromeos/login/mock_authenticator.h" 11 #include "chrome/browser/chromeos/login/screen_locker.h" 12 #include "chrome/browser/chromeos/login/screen_locker_tester.h" 13 #include "chrome/browser/chromeos/login/user_manager.h" 14 #include "chrome/browser/profiles/profile_manager.h" 15 #include "chrome/browser/ui/browser.h" 16 #include "chrome/browser/ui/browser_window.h" 17 #include "chrome/browser/ui/fullscreen/fullscreen_controller.h" 18 #include "chrome/common/chrome_switches.h" 19 #include "chrome/test/base/ui_test_utils.h" 20 #include "chromeos/chromeos_switches.h" 21 #include "chromeos/dbus/fake_session_manager_client.h" 22 #include "chromeos/dbus/mock_dbus_thread_manager_without_gmock.h" 23 #include "content/public/browser/notification_service.h" 24 #include "testing/gmock/include/gmock/gmock.h" 25 #include "testing/gtest/include/gtest/gtest.h" 26 #include "ui/base/test/ui_controls.h" 27 #include "ui/compositor/layer_animator.h" 28 #include "ui/compositor/scoped_animation_duration_scale_mode.h" 29 #include "ui/views/widget/widget.h" 30 31 using testing::_; 32 using testing::AnyNumber; 33 using testing::Return; 34 35 namespace { 36 37 // An object that wait for lock state and fullscreen state. 38 class Waiter : public content::NotificationObserver { 39 public: 40 explicit Waiter(Browser* browser) 41 : browser_(browser), 42 running_(false) { 43 registrar_.Add(this, 44 chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED, 45 content::NotificationService::AllSources()); 46 registrar_.Add(this, 47 chrome::NOTIFICATION_FULLSCREEN_CHANGED, 48 content::NotificationService::AllSources()); 49 } 50 51 virtual ~Waiter() { 52 } 53 54 virtual void Observe(int type, 55 const content::NotificationSource& source, 56 const content::NotificationDetails& details) OVERRIDE { 57 DCHECK(type == chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED || 58 type == chrome::NOTIFICATION_FULLSCREEN_CHANGED); 59 if (running_) 60 base::MessageLoop::current()->Quit(); 61 } 62 63 // Wait until the two conditions are met. 64 void Wait(bool locker_state, bool fullscreen) { 65 running_ = true; 66 scoped_ptr<chromeos::test::ScreenLockerTester> 67 tester(chromeos::ScreenLocker::GetTester()); 68 while (tester->IsLocked() != locker_state || 69 browser_->window()->IsFullscreen() != fullscreen) { 70 content::RunMessageLoop(); 71 } 72 // Make sure all pending tasks are executed. 73 content::RunAllPendingInMessageLoop(); 74 running_ = false; 75 } 76 77 private: 78 Browser* browser_; 79 content::NotificationRegistrar registrar_; 80 81 // Are we currently running the message loop? 82 bool running_; 83 84 DISALLOW_COPY_AND_ASSIGN(Waiter); 85 }; 86 87 } // namespace 88 89 namespace chromeos { 90 91 class ScreenLockerTest : public CrosInProcessBrowserTest { 92 public: 93 ScreenLockerTest() : fake_session_manager_client_(NULL) { 94 } 95 96 protected: 97 FakeSessionManagerClient* fake_session_manager_client_; 98 99 void LockScreen(test::ScreenLockerTester* tester) { 100 ScreenLocker::Show(); 101 tester->EmulateWindowManagerReady(); 102 content::WindowedNotificationObserver lock_state_observer( 103 chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED, 104 content::NotificationService::AllSources()); 105 if (!tester->IsLocked()) 106 lock_state_observer.Wait(); 107 EXPECT_TRUE(tester->IsLocked()); 108 } 109 110 // Verifies if LockScreenDismissed() was called once. 111 bool VerifyLockScreenDismissed() { 112 return 1 == fake_session_manager_client_-> 113 notify_lock_screen_dismissed_call_count(); 114 } 115 116 private: 117 virtual void SetUpInProcessBrowserTestFixture() OVERRIDE { 118 MockDBusThreadManagerWithoutGMock* mock_dbus_thread_manager = 119 new MockDBusThreadManagerWithoutGMock; 120 DBusThreadManager::InitializeForTesting(mock_dbus_thread_manager); 121 CrosInProcessBrowserTest::SetUpInProcessBrowserTestFixture(); 122 fake_session_manager_client_ = 123 mock_dbus_thread_manager->fake_session_manager_client(); 124 zero_duration_mode_.reset(new ui::ScopedAnimationDurationScaleMode( 125 ui::ScopedAnimationDurationScaleMode::ZERO_DURATION)); 126 } 127 128 virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { 129 command_line->AppendSwitchASCII(switches::kLoginProfile, "user"); 130 } 131 132 scoped_ptr<ui::ScopedAnimationDurationScaleMode> zero_duration_mode_; 133 134 DISALLOW_COPY_AND_ASSIGN(ScreenLockerTest); 135 }; 136 137 IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestBasic) { 138 ScreenLocker::Show(); 139 scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester()); 140 tester->EmulateWindowManagerReady(); 141 content::WindowedNotificationObserver lock_state_observer( 142 chrome::NOTIFICATION_SCREEN_LOCK_STATE_CHANGED, 143 content::NotificationService::AllSources()); 144 if (!chromeos::ScreenLocker::GetTester()->IsLocked()) 145 lock_state_observer.Wait(); 146 147 // Test to make sure that the widget is actually appearing and is of 148 // reasonable size, preventing a regression of 149 // http://code.google.com/p/chromium-os/issues/detail?id=5987 150 gfx::Rect lock_bounds = tester->GetChildWidget()->GetWindowBoundsInScreen(); 151 EXPECT_GT(lock_bounds.width(), 10); 152 EXPECT_GT(lock_bounds.height(), 10); 153 154 tester->InjectMockAuthenticator(UserManager::kStubUser, "pass"); 155 EXPECT_TRUE(tester->IsLocked()); 156 tester->EnterPassword("fail"); 157 content::RunAllPendingInMessageLoop(); 158 EXPECT_TRUE(tester->IsLocked()); 159 tester->EnterPassword("pass"); 160 content::RunAllPendingInMessageLoop(); 161 // Successful authentication simply send a unlock request to PowerManager. 162 EXPECT_TRUE(tester->IsLocked()); 163 EXPECT_EQ( 164 1, 165 fake_session_manager_client_->notify_lock_screen_shown_call_count()); 166 167 // Emulate LockScreen request from SessionManager. 168 // TODO(oshima): Find out better way to handle this in mock. 169 ScreenLocker::Hide(); 170 content::RunAllPendingInMessageLoop(); 171 EXPECT_FALSE(tester->IsLocked()); 172 EXPECT_TRUE(VerifyLockScreenDismissed()); 173 } 174 175 IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestFullscreenExit) { 176 scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester()); 177 { 178 Waiter waiter(browser()); 179 browser()->fullscreen_controller()->ToggleFullscreenMode(); 180 waiter.Wait(false /* not locked */, true /* full screen */); 181 EXPECT_TRUE(browser()->window()->IsFullscreen()); 182 EXPECT_FALSE(tester->IsLocked()); 183 } 184 { 185 Waiter waiter(browser()); 186 ScreenLocker::Show(); 187 tester->EmulateWindowManagerReady(); 188 waiter.Wait(true /* locked */, false /* full screen */); 189 EXPECT_FALSE(browser()->window()->IsFullscreen()); 190 EXPECT_TRUE(tester->IsLocked()); 191 } 192 EXPECT_EQ( 193 1, 194 fake_session_manager_client_->notify_lock_screen_shown_call_count()); 195 196 tester->InjectMockAuthenticator(UserManager::kStubUser, "pass"); 197 tester->EnterPassword("pass"); 198 content::RunAllPendingInMessageLoop(); 199 ScreenLocker::Hide(); 200 content::RunAllPendingInMessageLoop(); 201 EXPECT_FALSE(tester->IsLocked()); 202 EXPECT_TRUE(VerifyLockScreenDismissed()); 203 } 204 205 void SimulateKeyPress(views::Widget* widget, ui::KeyboardCode key_code) { 206 ui_controls::SendKeyPress(widget->GetNativeWindow(), 207 key_code, false, false, false, false); 208 } 209 210 void UnlockKeyPress(views::Widget* widget) { 211 SimulateKeyPress(widget, ui::VKEY_SPACE); 212 } 213 214 IN_PROC_BROWSER_TEST_F(ScreenLockerTest, TestShowTwice) { 215 scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester()); 216 LockScreen(tester.get()); 217 218 // Ensure there's a profile or this test crashes. 219 ProfileManager::GetDefaultProfile(); 220 221 // Calling Show again simply send LockCompleted signal. 222 ScreenLocker::Show(); 223 EXPECT_TRUE(tester->IsLocked()); 224 EXPECT_EQ( 225 2, 226 fake_session_manager_client_->notify_lock_screen_shown_call_count()); 227 228 229 // Close the locker to match expectations. 230 ScreenLocker::Hide(); 231 content::RunAllPendingInMessageLoop(); 232 EXPECT_FALSE(tester->IsLocked()); 233 EXPECT_TRUE(VerifyLockScreenDismissed()); 234 } 235 236 // TODO(flackr): Find out why the RenderView isn't getting the escape press 237 // and re-enable this test (currently this test is flaky). 238 IN_PROC_BROWSER_TEST_F(ScreenLockerTest, DISABLED_TestEscape) { 239 scoped_ptr<test::ScreenLockerTester> tester(ScreenLocker::GetTester()); 240 LockScreen(tester.get()); 241 242 // Ensure there's a profile or this test crashes. 243 ProfileManager::GetDefaultProfile(); 244 245 EXPECT_EQ( 246 1, 247 fake_session_manager_client_->notify_lock_screen_shown_call_count()); 248 249 tester->SetPassword("password"); 250 EXPECT_EQ("password", tester->GetPassword()); 251 // Escape clears the password. 252 SimulateKeyPress(tester->GetWidget(), ui::VKEY_ESCAPE); 253 content::RunAllPendingInMessageLoop(); 254 EXPECT_EQ("", tester->GetPassword()); 255 256 // Close the locker to match expectations. 257 ScreenLocker::Hide(); 258 content::RunAllPendingInMessageLoop(); 259 EXPECT_FALSE(tester->IsLocked()); 260 EXPECT_TRUE(VerifyLockScreenDismissed()); 261 } 262 263 } // namespace chromeos 264