1// Copyright 2014 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 "chrome/browser/chromeos/login/lock/screen_locker_tester.h"
6
7#include <string>
8
9#include "base/strings/string_util.h"
10#include "base/strings/stringprintf.h"
11#include "base/strings/utf_string_conversions.h"
12#include "base/values.h"
13#include "chrome/browser/chromeos/login/lock/screen_locker.h"
14#include "chrome/browser/chromeos/login/lock/webui_screen_locker.h"
15#include "chrome/test/base/ui_test_utils.h"
16#include "chromeos/login/auth/auth_status_consumer.h"
17#include "chromeos/login/auth/fake_extended_authenticator.h"
18#include "chromeos/login/auth/mock_authenticator.h"
19#include "content/public/browser/render_frame_host.h"
20#include "content/public/browser/render_view_host.h"
21#include "content/public/browser/web_contents.h"
22#include "content/public/browser/web_ui.h"
23#include "content/public/test/test_utils.h"
24#include "ui/views/controls/button/button.h"
25#include "ui/views/controls/label.h"
26#include "ui/views/controls/textfield/textfield.h"
27#include "ui/views/widget/root_view.h"
28
29using content::WebContents;
30
31namespace {
32
33// This class is used to observe state of the global ScreenLocker instance,
34// which can go away as a result of a successful authentication. As such,
35// it needs to directly reference the global ScreenLocker.
36class LoginAttemptObserver : public chromeos::AuthStatusConsumer {
37 public:
38  LoginAttemptObserver();
39  virtual ~LoginAttemptObserver();
40
41  void WaitForAttempt();
42
43  // Overridden from AuthStatusConsumer:
44  virtual void OnAuthFailure(const chromeos::AuthFailure& error) OVERRIDE {
45    LoginAttempted();
46  }
47
48  virtual void OnAuthSuccess(
49      const chromeos::UserContext& credentials) OVERRIDE {
50    LoginAttempted();
51  }
52
53 private:
54  void LoginAttempted();
55
56  bool login_attempted_;
57  bool waiting_;
58
59  DISALLOW_COPY_AND_ASSIGN(LoginAttemptObserver);
60};
61
62LoginAttemptObserver::LoginAttemptObserver()
63    : chromeos::AuthStatusConsumer(), login_attempted_(false), waiting_(false) {
64  chromeos::ScreenLocker::default_screen_locker()->SetLoginStatusConsumer(this);
65}
66
67LoginAttemptObserver::~LoginAttemptObserver() {
68  chromeos::ScreenLocker* global_locker =
69      chromeos::ScreenLocker::default_screen_locker();
70  if (global_locker)
71    global_locker->SetLoginStatusConsumer(NULL);
72}
73
74void LoginAttemptObserver::WaitForAttempt() {
75  if (!login_attempted_) {
76    waiting_ = true;
77    content::RunMessageLoop();
78    waiting_ = false;
79  }
80  ASSERT_TRUE(login_attempted_);
81}
82
83void LoginAttemptObserver::LoginAttempted() {
84  login_attempted_ = true;
85  if (waiting_)
86    base::MessageLoopForUI::current()->Quit();
87}
88
89}  // anyonymous namespace
90
91namespace chromeos {
92
93namespace test {
94
95class WebUIScreenLockerTester : public ScreenLockerTester {
96 public:
97  // ScreenLockerTester overrides:
98  virtual void SetPassword(const std::string& password) OVERRIDE;
99  virtual std::string GetPassword() OVERRIDE;
100  virtual void EnterPassword(const std::string& password) OVERRIDE;
101  virtual void EmulateWindowManagerReady() OVERRIDE;
102  virtual views::Widget* GetWidget() const OVERRIDE;
103  virtual views::Widget* GetChildWidget() const OVERRIDE;
104
105 private:
106  friend class chromeos::ScreenLocker;
107
108  WebUIScreenLockerTester() {}
109
110  content::RenderViewHost* RenderViewHost() const;
111
112  // Returns the ScreenLockerWebUI object.
113  WebUIScreenLocker* webui_screen_locker() const;
114
115  // Returns the WebUI object from the screen locker.
116  content::WebUI* webui() const;
117
118  DISALLOW_COPY_AND_ASSIGN(WebUIScreenLockerTester);
119};
120
121void WebUIScreenLockerTester::SetPassword(const std::string& password) {
122  webui()->GetWebContents()->GetMainFrame()->ExecuteJavaScript(
123      base::ASCIIToUTF16(base::StringPrintf(
124          "$('pod-row').pods[0].passwordElement.value = '%s';",
125          password.c_str())));
126}
127
128std::string WebUIScreenLockerTester::GetPassword() {
129  std::string result;
130  scoped_ptr<base::Value> v = content::ExecuteScriptAndGetValue(
131      RenderViewHost()->GetMainFrame(),
132      "$('pod-row').pods[0].passwordElement.value;");
133  CHECK(v->GetAsString(&result));
134  return result;
135}
136
137void WebUIScreenLockerTester::EnterPassword(const std::string& password) {
138  bool result;
139  SetPassword(password);
140
141  // Verify password is set.
142  ASSERT_EQ(password, GetPassword());
143
144  // Verify that "signin" button is hidden.
145  scoped_ptr<base::Value> v = content::ExecuteScriptAndGetValue(
146      RenderViewHost()->GetMainFrame(),
147      "window.getComputedStyle("
148      "    $('pod-row').pods[0].querySelector('.signin-button-container'))"
149      "        .display == 'none'");
150  ASSERT_TRUE(v->GetAsBoolean(&result));
151  ASSERT_TRUE(result);
152
153  // Attempt to sign in.
154  LoginAttemptObserver login;
155  v = content::ExecuteScriptAndGetValue(
156      RenderViewHost()->GetMainFrame(),
157      "$('pod-row').pods[0].activate();");
158  ASSERT_TRUE(v->GetAsBoolean(&result));
159  ASSERT_TRUE(result);
160
161  // Wait for login attempt.
162  login.WaitForAttempt();
163}
164
165void WebUIScreenLockerTester::EmulateWindowManagerReady() {
166}
167
168views::Widget* WebUIScreenLockerTester::GetWidget() const {
169  return webui_screen_locker()->lock_window_;
170}
171
172views::Widget* WebUIScreenLockerTester::GetChildWidget() const {
173  return webui_screen_locker()->lock_window_;
174}
175
176content::RenderViewHost* WebUIScreenLockerTester::RenderViewHost() const {
177  return webui()->GetWebContents()->GetRenderViewHost();
178}
179
180WebUIScreenLocker* WebUIScreenLockerTester::webui_screen_locker() const {
181  DCHECK(ScreenLocker::screen_locker_);
182  return static_cast<WebUIScreenLocker*>(
183      ScreenLocker::screen_locker_->delegate_.get());
184}
185
186content::WebUI* WebUIScreenLockerTester::webui() const {
187  DCHECK(webui_screen_locker()->webui_ready_);
188  content::WebUI* webui = webui_screen_locker()->GetWebUI();
189  DCHECK(webui);
190  return webui;
191}
192
193ScreenLockerTester::ScreenLockerTester() {
194}
195
196ScreenLockerTester::~ScreenLockerTester() {
197}
198
199bool ScreenLockerTester::IsLocked() {
200  return ScreenLocker::screen_locker_ &&
201      ScreenLocker::screen_locker_->locked_;
202}
203
204void ScreenLockerTester::InjectMockAuthenticator(
205    const UserContext& user_context) {
206  DCHECK(ScreenLocker::screen_locker_);
207  ScreenLocker::screen_locker_->SetAuthenticator(
208      new MockAuthenticator(ScreenLocker::screen_locker_, user_context));
209  ScreenLocker::screen_locker_->extended_authenticator_ =
210      new FakeExtendedAuthenticator(ScreenLocker::screen_locker_, user_context);
211}
212
213}  // namespace test
214
215test::ScreenLockerTester* ScreenLocker::GetTester() {
216  return new test::WebUIScreenLockerTester();
217}
218
219}  // namespace chromeos
220