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.
7 #include "base/command_line.h"
8 #include "base/json/json_file_value_serializer.h"
9 #include "base/path_service.h"
10 #include "base/prefs/pref_service.h"
11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/chromeos/login/login_manager_test.h"
13 #include "chrome/browser/chromeos/login/startup_utils.h"
14 #include "chrome/browser/chromeos/login/test/oobe_screen_waiter.h"
15 #include "chrome/browser/chromeos/login/ui/login_display_host_impl.h"
16 #include "chrome/browser/chromeos/login/ui/oobe_display.h"
17 #include "chrome/browser/chromeos/login/ui/webui_login_view.h"
18 #include "chrome/common/chrome_constants.h"
19 #include "chrome/common/chrome_paths.h"
20 #include "chrome/common/chrome_switches.h"
21 #include "chrome/common/pref_names.h"
22 #include "chromeos/chromeos_switches.h"
23 #include "chromeos/dbus/dbus_thread_manager.h"
24 #include "chromeos/dbus/fake_debug_daemon_client.h"
25 #include "chromeos/dbus/fake_power_manager_client.h"
26 #include "chromeos/dbus/fake_update_engine_client.h"
27 #include "content/public/test/browser_test_utils.h"
28 #include "content/public/test/test_utils.h"
29 #include "third_party/cros_system_api/dbus/service_constants.h"
33 class TestDebugDaemonClient
: public FakeDebugDaemonClient
{
35 TestDebugDaemonClient()
37 num_query_debugging_features_(0),
38 num_enable_debugging_features_(0),
39 num_remove_protection_(0) {
42 ~TestDebugDaemonClient() override
{
45 // FakeDebugDaemonClient overrides:
46 void SetDebuggingFeaturesStatus(int featues_mask
) override
{
48 FakeDebugDaemonClient::SetDebuggingFeaturesStatus(featues_mask
);
51 void EnableDebuggingFeatures(
52 const std::string
& password
,
53 const EnableDebuggingCallback
& callback
) override
{
54 FakeDebugDaemonClient::EnableDebuggingFeatures(
56 base::Bind(&TestDebugDaemonClient::OnEnableDebuggingFeatures
,
57 base::Unretained(this),
61 void RemoveRootfsVerification(
62 const DebugDaemonClient::EnableDebuggingCallback
& callback
) override
{
63 FakeDebugDaemonClient::RemoveRootfsVerification(
64 base::Bind(&TestDebugDaemonClient::OnRemoveRootfsVerification
,
65 base::Unretained(this),
69 void QueryDebuggingFeatures(
70 const DebugDaemonClient::QueryDevFeaturesCallback
& callback
) override
{
71 LOG(WARNING
) << "QueryDebuggingFeatures";
72 FakeDebugDaemonClient::QueryDebuggingFeatures(
73 base::Bind(&TestDebugDaemonClient::OnQueryDebuggingFeatures
,
74 base::Unretained(this),
78 void OnRemoveRootfsVerification(
79 const DebugDaemonClient::EnableDebuggingCallback
& original_callback
,
81 LOG(WARNING
) << "OnRemoveRootfsVerification: succeeded = " << succeeded
;
82 base::MessageLoop::current()->PostTask(
84 base::Bind(original_callback
, succeeded
));
90 num_remove_protection_
++;
93 void OnQueryDebuggingFeatures(
94 const DebugDaemonClient::QueryDevFeaturesCallback
& original_callback
,
97 LOG(WARNING
) << "OnQueryDebuggingFeatures: succeeded = " << succeeded
98 << ", feature_mask = " << feature_mask
;
99 base::MessageLoop::current()->PostTask(
101 base::Bind(original_callback
, succeeded
, feature_mask
));
107 num_query_debugging_features_
++;
110 void OnEnableDebuggingFeatures(
111 const DebugDaemonClient::EnableDebuggingCallback
& original_callback
,
113 LOG(WARNING
) << "OnEnableDebuggingFeatures: succeeded = " << succeeded
114 << ", feature_mask = ";
115 base::MessageLoop::current()->PostTask(
117 base::Bind(original_callback
, succeeded
));
123 num_enable_debugging_features_
++;
128 num_query_debugging_features_
= 0;
129 num_enable_debugging_features_
= 0;
130 num_remove_protection_
= 0;
133 int num_query_debugging_features() const {
134 return num_query_debugging_features_
;
137 int num_enable_debugging_features() const {
138 return num_enable_debugging_features_
;
141 int num_remove_protection() const {
142 return num_remove_protection_
;
145 void WaitUntilCalled() {
149 runner_
= new content::MessageLoopRunner
;
154 scoped_refptr
<content::MessageLoopRunner
> runner_
;
156 int num_query_debugging_features_
;
157 int num_enable_debugging_features_
;
158 int num_remove_protection_
;
161 class EnableDebuggingTest
: public LoginManagerTest
{
163 EnableDebuggingTest() : LoginManagerTest(false),
164 debug_daemon_client_(NULL
),
165 power_manager_client_(NULL
) {
167 ~EnableDebuggingTest() override
{}
169 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
170 LoginManagerTest::SetUpCommandLine(command_line
);
171 command_line
->AppendSwitch(chromeos::switches::kSystemDevMode
);
172 // Disable HID detection because it takes precedence and could block
173 // enable-debugging UI.
174 command_line
->AppendSwitch(chromeos::switches::kDisableHIDDetectionOnOOBE
);
177 // LoginManagerTest overrides:
178 void SetUpInProcessBrowserTestFixture() override
{
179 scoped_ptr
<DBusThreadManagerSetter
> dbus_setter
=
180 chromeos::DBusThreadManager::GetSetterForTesting();
181 power_manager_client_
= new FakePowerManagerClient
;
182 dbus_setter
->SetPowerManagerClient(
183 scoped_ptr
<PowerManagerClient
>(power_manager_client_
));
184 debug_daemon_client_
= new TestDebugDaemonClient
;
185 dbus_setter
->SetDebugDaemonClient(
186 scoped_ptr
<DebugDaemonClient
>(debug_daemon_client_
));
188 LoginManagerTest::SetUpInProcessBrowserTestFixture();
191 bool JSExecuted(const std::string
& script
) {
192 return content::ExecuteScript(web_contents(), script
);
195 void WaitUntilJSIsReady() {
196 LoginDisplayHostImpl
* host
= static_cast<LoginDisplayHostImpl
*>(
197 LoginDisplayHostImpl::default_host());
200 chromeos::OobeUI
* oobe_ui
= host
->GetOobeUI();
203 base::RunLoop run_loop
;
204 const bool oobe_ui_ready
= oobe_ui
->IsJSReady(run_loop
.QuitClosure());
209 void InvokeEnableDebuggingScreen() {
210 ASSERT_TRUE(JSExecuted("cr.ui.Oobe.handleAccelerator('debugging');"));
211 OobeScreenWaiter(OobeDisplay::SCREEN_OOBE_ENABLE_DEBUGGING
).Wait();
214 void CloseEnableDebuggingScreen() {
215 ASSERT_TRUE(JSExecuted("$('debugging-cancel-button').click();"));
218 void ClickRemoveProtectionButton() {
219 ASSERT_TRUE(JSExecuted("$('debugging-remove-protection-button').click();"));
222 void ClickEnableButton() {
223 ASSERT_TRUE(JSExecuted("$('debugging-enable-button').click();"));
226 void ClickOKButton() {
227 ASSERT_TRUE(JSExecuted("$('debugging-ok-button').click();"));
230 void ShowRemoveProtectionScreen() {
231 debug_daemon_client_
->SetDebuggingFeaturesStatus(
232 DebugDaemonClient::DEV_FEATURE_NONE
);
233 WaitUntilJSIsReady();
234 JSExpect("!!document.querySelector('#debugging.hidden')");
235 InvokeEnableDebuggingScreen();
236 JSExpect("!document.querySelector('#debugging.hidden')");
237 debug_daemon_client_
->WaitUntilCalled();
238 base::MessageLoop::current()->RunUntilIdle();
239 VerifyRemoveProtectionScreen();
242 void VerifyRemoveProtectionScreen() {
243 JSExpect("!!document.querySelector('#debugging.remove-protection-view')");
244 JSExpect("!document.querySelector('#debugging.setup-view')");
245 JSExpect("!document.querySelector('#debugging.done-view')");
246 JSExpect("!document.querySelector('#debugging.wait-view')");
249 void ShowSetupScreen() {
250 debug_daemon_client_
->SetDebuggingFeaturesStatus(
251 debugd::DevFeatureFlag::DEV_FEATURE_ROOTFS_VERIFICATION_REMOVED
);
252 WaitUntilJSIsReady();
253 JSExpect("!!document.querySelector('#debugging.hidden')");
254 InvokeEnableDebuggingScreen();
255 JSExpect("!document.querySelector('#debugging.hidden')");
256 debug_daemon_client_
->WaitUntilCalled();
257 base::MessageLoop::current()->RunUntilIdle();
258 JSExpect("!document.querySelector('#debugging.remove-protection-view')");
259 JSExpect("!!document.querySelector('#debugging.setup-view')");
260 JSExpect("!document.querySelector('#debugging.done-view')");
261 JSExpect("!document.querySelector('#debugging.wait-view')");
264 TestDebugDaemonClient
* debug_daemon_client_
;
265 FakePowerManagerClient
* power_manager_client_
;
268 // Show remove protection screen, click on [Cancel] button.
269 IN_PROC_BROWSER_TEST_F(EnableDebuggingTest
, ShowAndCancelRemoveProtection
) {
270 ShowRemoveProtectionScreen();
271 CloseEnableDebuggingScreen();
272 JSExpect("!!document.querySelector('#debugging.hidden')");
274 EXPECT_EQ(debug_daemon_client_
->num_query_debugging_features(), 1);
275 EXPECT_EQ(debug_daemon_client_
->num_enable_debugging_features(), 0);
276 EXPECT_EQ(debug_daemon_client_
->num_remove_protection(), 0);
279 // Show remove protection, click on [Remove protection] button and wait for
281 IN_PROC_BROWSER_TEST_F(EnableDebuggingTest
, ShowAndRemoveProtection
) {
282 ShowRemoveProtectionScreen();
283 debug_daemon_client_
->ResetWait();
284 ClickRemoveProtectionButton();
285 debug_daemon_client_
->WaitUntilCalled();
286 JSExpect("!!document.querySelector('#debugging.wait-view')");
287 // Check if we have rebooted after enabling.
288 base::MessageLoop::current()->RunUntilIdle();
289 EXPECT_EQ(debug_daemon_client_
->num_remove_protection(), 1);
290 EXPECT_EQ(debug_daemon_client_
->num_enable_debugging_features(), 0);
291 EXPECT_EQ(power_manager_client_
->num_request_restart_calls(), 1);
295 // Show setup screen. Click on [Enable] button. Wait until done screen is shown.
296 IN_PROC_BROWSER_TEST_F(EnableDebuggingTest
, ShowSetup
) {
298 debug_daemon_client_
->ResetWait();
300 debug_daemon_client_
->WaitUntilCalled();
301 base::MessageLoop::current()->RunUntilIdle();
302 JSExpect("!!document.querySelector('#debugging.done-view')");
303 EXPECT_EQ(debug_daemon_client_
->num_enable_debugging_features(), 1);
304 EXPECT_EQ(debug_daemon_client_
->num_remove_protection(), 0);
307 // Test images come with some features enabled but still has rootfs protection.
308 // Invoking debug screen should show remove protection screen.
309 IN_PROC_BROWSER_TEST_F(EnableDebuggingTest
, ShowOnTestImages
) {
310 debug_daemon_client_
->SetDebuggingFeaturesStatus(
311 debugd::DevFeatureFlag::DEV_FEATURE_SSH_SERVER_CONFIGURED
|
312 debugd::DevFeatureFlag::DEV_FEATURE_SYSTEM_ROOT_PASSWORD_SET
);
313 WaitUntilJSIsReady();
314 JSExpect("!!document.querySelector('#debugging.hidden')");
315 InvokeEnableDebuggingScreen();
316 JSExpect("!document.querySelector('#debugging.hidden')");
317 debug_daemon_client_
->WaitUntilCalled();
318 base::MessageLoop::current()->RunUntilIdle();
319 VerifyRemoveProtectionScreen();
321 EXPECT_EQ(debug_daemon_client_
->num_query_debugging_features(), 1);
322 EXPECT_EQ(debug_daemon_client_
->num_enable_debugging_features(), 0);
323 EXPECT_EQ(debug_daemon_client_
->num_remove_protection(), 0);
326 IN_PROC_BROWSER_TEST_F(EnableDebuggingTest
, WaitForDebugDaemon
) {
327 // Stat with service not ready.
328 debug_daemon_client_
->SetServiceIsAvailable(false);
329 debug_daemon_client_
->SetDebuggingFeaturesStatus(
330 DebugDaemonClient::DEV_FEATURE_NONE
);
331 WaitUntilJSIsReady();
333 // Invoking UI and it should land on wait-view.
334 JSExpect("!!document.querySelector('#debugging.hidden')");
335 InvokeEnableDebuggingScreen();
336 JSExpect("!document.querySelector('#debugging.hidden')");
337 JSExpect("!!document.querySelector('#debugging.wait-view')");
339 // Mark service ready and it should proceed to remove protection view.
340 debug_daemon_client_
->SetServiceIsAvailable(true);
341 debug_daemon_client_
->WaitUntilCalled();
342 base::MessageLoop::current()->RunUntilIdle();
343 VerifyRemoveProtectionScreen();
346 class EnableDebuggingNonDevTest
: public EnableDebuggingTest
{
348 EnableDebuggingNonDevTest() {
351 void SetUpCommandLine(base::CommandLine
* command_line
) override
{
352 // Skip EnableDebuggingTest::SetUpCommandLine().
353 LoginManagerTest::SetUpCommandLine(command_line
);
356 // LoginManagerTest overrides:
357 void SetUpInProcessBrowserTestFixture() override
{
358 scoped_ptr
<DBusThreadManagerSetter
> dbus_setter
=
359 chromeos::DBusThreadManager::GetSetterForTesting();
360 dbus_setter
->SetDebugDaemonClient(
361 scoped_ptr
<DebugDaemonClient
>(new FakeDebugDaemonClient
));
362 LoginManagerTest::SetUpInProcessBrowserTestFixture();
366 // Try to show enable debugging dialog, we should see error screen here.
367 IN_PROC_BROWSER_TEST_F(EnableDebuggingNonDevTest
, NoShowInNonDevMode
) {
368 JSExpect("!!document.querySelector('#debugging.hidden')");
369 InvokeEnableDebuggingScreen();
370 JSExpect("!document.querySelector('#debugging.hidden')");
371 base::MessageLoop::current()->RunUntilIdle();
372 JSExpect("!!document.querySelector('#debugging.error-view')");
373 JSExpect("!document.querySelector('#debugging.remove-protection-view')");
374 JSExpect("!document.querySelector('#debugging.setup-view')");
375 JSExpect("!document.querySelector('#debugging.done-view')");
376 JSExpect("!document.querySelector('#debugging.wait-view')");
379 class EnableDebuggingRequestedTest
: public EnableDebuggingTest
{
381 EnableDebuggingRequestedTest() {
384 // EnableDebuggingTest overrides:
385 bool SetUpUserDataDirectory() override
{
386 base::DictionaryValue local_state_dict
;
387 local_state_dict
.SetBoolean(prefs::kDebuggingFeaturesRequested
, true);
389 base::FilePath user_data_dir
;
390 CHECK(PathService::Get(chrome::DIR_USER_DATA
, &user_data_dir
));
391 base::FilePath local_state_path
=
392 user_data_dir
.Append(chrome::kLocalStateFilename
);
394 JSONFileValueSerializer(local_state_path
).Serialize(local_state_dict
));
396 return EnableDebuggingTest::SetUpUserDataDirectory();
398 void SetUpInProcessBrowserTestFixture() override
{
399 EnableDebuggingTest::SetUpInProcessBrowserTestFixture();
401 debug_daemon_client_
->SetDebuggingFeaturesStatus(
402 debugd::DevFeatureFlag::DEV_FEATURE_ROOTFS_VERIFICATION_REMOVED
);
406 // Setup screen is automatically shown when the feature is requested.
407 IN_PROC_BROWSER_TEST_F(EnableDebuggingRequestedTest
, AutoShowSetup
) {
408 OobeScreenWaiter(OobeDisplay::SCREEN_OOBE_ENABLE_DEBUGGING
).Wait();
411 // Canceling auto shown setup screen should close it.
412 IN_PROC_BROWSER_TEST_F(EnableDebuggingRequestedTest
, CancelAutoShowSetup
) {
413 OobeScreenWaiter(OobeDisplay::SCREEN_OOBE_ENABLE_DEBUGGING
).Wait();
414 CloseEnableDebuggingScreen();
415 JSExpect("!!document.querySelector('#debugging.hidden')");
418 } // namespace chromeos