Home | History | Annotate | Download | only in login
      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