logout_confirmation_controller_unittest.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377
  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. #include "ash/system/session/logout_confirmation_controller.h"
  5. #include "ash/constants/ash_pref_names.h"
  6. #include "ash/session/session_controller_impl.h"
  7. #include "ash/session/test_session_controller_client.h"
  8. #include "ash/shell.h"
  9. #include "ash/test/ash_test_base.h"
  10. #include "ash/test/test_window_builder.h"
  11. #include "ash/wm/desks/desks_util.h"
  12. #include "base/bind.h"
  13. #include "base/callback_helpers.h"
  14. #include "base/memory/ref_counted.h"
  15. #include "base/test/test_mock_time_task_runner.h"
  16. #include "base/threading/thread_task_runner_handle.h"
  17. #include "base/time/tick_clock.h"
  18. #include "components/prefs/pref_service.h"
  19. #include "components/session_manager/session_manager_types.h"
  20. #include "components/user_manager/user_type.h"
  21. #include "testing/gtest/include/gtest/gtest.h"
  22. #include "ui/aura/window.h"
  23. #include "ui/views/widget/widget.h"
  24. namespace ash {
  25. constexpr char kUserEmail[] = "user1@test.com";
  26. class LogoutConfirmationControllerTest : public testing::Test {
  27. public:
  28. LogoutConfirmationControllerTest(const LogoutConfirmationControllerTest&) =
  29. delete;
  30. LogoutConfirmationControllerTest& operator=(
  31. const LogoutConfirmationControllerTest&) = delete;
  32. protected:
  33. LogoutConfirmationControllerTest();
  34. ~LogoutConfirmationControllerTest() override;
  35. void LogOut(LogoutConfirmationController::Source source);
  36. bool log_out_called_;
  37. scoped_refptr<base::TestMockTimeTaskRunner> runner_;
  38. base::ThreadTaskRunnerHandle runner_handle_;
  39. LogoutConfirmationController controller_;
  40. };
  41. LogoutConfirmationControllerTest::LogoutConfirmationControllerTest()
  42. : log_out_called_(false),
  43. runner_(new base::TestMockTimeTaskRunner),
  44. runner_handle_(runner_) {
  45. controller_.SetClockForTesting(runner_->GetMockTickClock());
  46. controller_.SetLogoutCallbackForTesting(base::BindRepeating(
  47. &LogoutConfirmationControllerTest::LogOut, base::Unretained(this)));
  48. }
  49. LogoutConfirmationControllerTest::~LogoutConfirmationControllerTest() = default;
  50. void LogoutConfirmationControllerTest::LogOut(
  51. LogoutConfirmationController::Source source) {
  52. log_out_called_ = true;
  53. }
  54. // Verifies that the user is logged out immediately if logout confirmation with
  55. // a zero-length countdown is requested.
  56. TEST_F(LogoutConfirmationControllerTest, ZeroDuration) {
  57. controller_.ConfirmLogout(
  58. runner_->NowTicks(),
  59. LogoutConfirmationController::Source::kShelfExitButton);
  60. EXPECT_FALSE(log_out_called_);
  61. runner_->FastForwardBy(base::TimeDelta());
  62. EXPECT_TRUE(log_out_called_);
  63. }
  64. // Verifies that the user is logged out when the countdown expires.
  65. TEST_F(LogoutConfirmationControllerTest, DurationExpired) {
  66. controller_.ConfirmLogout(
  67. runner_->NowTicks() + base::Seconds(10),
  68. LogoutConfirmationController::Source::kShelfExitButton);
  69. EXPECT_FALSE(log_out_called_);
  70. runner_->FastForwardBy(base::Seconds(9));
  71. EXPECT_FALSE(log_out_called_);
  72. runner_->FastForwardBy(base::Seconds(2));
  73. EXPECT_TRUE(log_out_called_);
  74. }
  75. // Verifies that when a second request to confirm logout is made and the second
  76. // request's countdown ends before the original request's, the user is logged
  77. // out when the new countdown expires.
  78. TEST_F(LogoutConfirmationControllerTest, DurationShortened) {
  79. controller_.ConfirmLogout(
  80. runner_->NowTicks() + base::Seconds(30),
  81. LogoutConfirmationController::Source::kShelfExitButton);
  82. EXPECT_FALSE(log_out_called_);
  83. runner_->FastForwardBy(base::Seconds(9));
  84. EXPECT_FALSE(log_out_called_);
  85. controller_.ConfirmLogout(
  86. runner_->NowTicks() + base::Seconds(10),
  87. LogoutConfirmationController::Source::kShelfExitButton);
  88. runner_->FastForwardBy(base::Seconds(9));
  89. EXPECT_FALSE(log_out_called_);
  90. runner_->FastForwardBy(base::Seconds(2));
  91. EXPECT_TRUE(log_out_called_);
  92. }
  93. // Verifies that when a second request to confirm logout is made and the second
  94. // request's countdown ends after the original request's, the user is logged
  95. // out when the original countdown expires.
  96. TEST_F(LogoutConfirmationControllerTest, DurationExtended) {
  97. controller_.ConfirmLogout(
  98. runner_->NowTicks() + base::Seconds(10),
  99. LogoutConfirmationController::Source::kShelfExitButton);
  100. EXPECT_FALSE(log_out_called_);
  101. runner_->FastForwardBy(base::Seconds(9));
  102. EXPECT_FALSE(log_out_called_);
  103. controller_.ConfirmLogout(
  104. runner_->NowTicks() + base::Seconds(10),
  105. LogoutConfirmationController::Source::kShelfExitButton);
  106. runner_->FastForwardBy(base::Seconds(2));
  107. EXPECT_TRUE(log_out_called_);
  108. }
  109. // Verifies that when the screen is locked while the countdown is running, the
  110. // user is not logged out, even when the original countdown expires.
  111. TEST_F(LogoutConfirmationControllerTest, Lock) {
  112. controller_.ConfirmLogout(
  113. runner_->NowTicks() + base::Seconds(10),
  114. LogoutConfirmationController::Source::kShelfExitButton);
  115. EXPECT_FALSE(log_out_called_);
  116. controller_.OnLockStateChanged(true);
  117. runner_->FastForwardUntilNoTasksRemain();
  118. EXPECT_FALSE(log_out_called_);
  119. }
  120. // Verifies that when the user confirms the logout request, the user is logged
  121. // out immediately.
  122. TEST_F(LogoutConfirmationControllerTest, UserAccepted) {
  123. controller_.ConfirmLogout(
  124. runner_->NowTicks() + base::Seconds(10),
  125. LogoutConfirmationController::Source::kShelfExitButton);
  126. EXPECT_FALSE(log_out_called_);
  127. controller_.OnLogoutConfirmed();
  128. EXPECT_TRUE(log_out_called_);
  129. }
  130. // Verifies that when the user denies the logout request, the user is not logged
  131. // out, even when the original countdown expires.
  132. TEST_F(LogoutConfirmationControllerTest, UserDenied) {
  133. controller_.ConfirmLogout(
  134. runner_->NowTicks() + base::Seconds(10),
  135. LogoutConfirmationController::Source::kShelfExitButton);
  136. EXPECT_FALSE(log_out_called_);
  137. controller_.OnDialogClosed();
  138. runner_->FastForwardUntilNoTasksRemain();
  139. EXPECT_FALSE(log_out_called_);
  140. }
  141. // Verifies that after the user has denied a logout request, a subsequent logout
  142. // request is handled correctly and the user is logged out when the countdown
  143. // expires.
  144. TEST_F(LogoutConfirmationControllerTest, DurationExpiredAfterDeniedRequest) {
  145. controller_.ConfirmLogout(
  146. runner_->NowTicks() + base::Seconds(10),
  147. LogoutConfirmationController::Source::kShelfExitButton);
  148. EXPECT_FALSE(log_out_called_);
  149. controller_.OnDialogClosed();
  150. runner_->FastForwardUntilNoTasksRemain();
  151. EXPECT_FALSE(log_out_called_);
  152. controller_.ConfirmLogout(
  153. runner_->NowTicks() + base::Seconds(10),
  154. LogoutConfirmationController::Source::kShelfExitButton);
  155. EXPECT_FALSE(log_out_called_);
  156. runner_->FastForwardBy(base::Seconds(9));
  157. EXPECT_FALSE(log_out_called_);
  158. runner_->FastForwardBy(base::Seconds(2));
  159. EXPECT_TRUE(log_out_called_);
  160. }
  161. class LastWindowClosedTest : public NoSessionAshTestBase {
  162. public:
  163. LastWindowClosedTest() = default;
  164. LastWindowClosedTest(const LastWindowClosedTest&) = delete;
  165. LastWindowClosedTest& operator=(const LastWindowClosedTest&) = delete;
  166. ~LastWindowClosedTest() override = default;
  167. // Simulate a managed guest session (non-demo session) login.
  168. void StartManagedGuestSession() {
  169. TestSessionControllerClient* session = GetSessionControllerClient();
  170. session->Reset();
  171. session->AddUserSession(kUserEmail, user_manager::USER_TYPE_PUBLIC_ACCOUNT);
  172. session->SetSessionState(session_manager::SessionState::ACTIVE);
  173. }
  174. // Simulate a demo session signing in.
  175. void StartDemoSession() {
  176. GetSessionControllerClient()->SetIsDemoSession();
  177. // Demo session is implemented as a managed guest session.
  178. StartManagedGuestSession();
  179. }
  180. // PrefService for the managed guest session started by
  181. // StartManagedGuestSession().
  182. PrefService* pref_service() {
  183. return Shell::Get()->session_controller()->GetUserPrefServiceForUser(
  184. AccountId::FromUserEmail(kUserEmail));
  185. }
  186. };
  187. TEST_F(LastWindowClosedTest, RegularSession) {
  188. // Dialog is not visible at startup.
  189. LogoutConfirmationController* controller =
  190. Shell::Get()->logout_confirmation_controller();
  191. EXPECT_FALSE(controller->dialog_for_testing());
  192. // Dialog is not visible after login.
  193. CreateUserSessions(1);
  194. EXPECT_FALSE(controller->dialog_for_testing());
  195. // Creating and closing a window does not show the dialog because this is not
  196. // a managed guest session.
  197. std::unique_ptr<aura::Window> window = CreateToplevelTestWindow();
  198. EXPECT_FALSE(controller->dialog_for_testing());
  199. window.reset();
  200. EXPECT_FALSE(controller->dialog_for_testing());
  201. }
  202. TEST_F(LastWindowClosedTest, DemoSession) {
  203. // Dialog is not visible at startup.
  204. LogoutConfirmationController* controller =
  205. Shell::Get()->logout_confirmation_controller();
  206. EXPECT_FALSE(controller->dialog_for_testing());
  207. // Dialog is not visible after demo session starts.
  208. StartDemoSession();
  209. EXPECT_FALSE(controller->dialog_for_testing());
  210. // Creating and closing a window does not show the dialog.
  211. std::unique_ptr<aura::Window> window = CreateToplevelTestWindow();
  212. EXPECT_FALSE(controller->dialog_for_testing());
  213. window.reset();
  214. EXPECT_FALSE(controller->dialog_for_testing());
  215. }
  216. TEST_F(LastWindowClosedTest, ManagedGuestSession) {
  217. LogoutConfirmationController* controller =
  218. Shell::Get()->logout_confirmation_controller();
  219. // Dialog is not visible after managed guest session login.
  220. StartManagedGuestSession();
  221. EXPECT_FALSE(controller->dialog_for_testing());
  222. // Opening windows does not show the dialog.
  223. std::unique_ptr<views::Widget> widget1 = CreateTestWidget();
  224. std::unique_ptr<views::Widget> widget2 = CreateTestWidget();
  225. EXPECT_FALSE(controller->dialog_for_testing());
  226. // Closing the last window shows the dialog.
  227. widget1.reset();
  228. EXPECT_FALSE(controller->dialog_for_testing());
  229. widget2.reset();
  230. EXPECT_TRUE(controller->dialog_for_testing());
  231. }
  232. TEST_F(LastWindowClosedTest, SuggestLogoutAfterClosingLastWindowPolicy) {
  233. LogoutConfirmationController* controller =
  234. Shell::Get()->logout_confirmation_controller();
  235. // Dialog is not visible after managed guest session login.
  236. StartManagedGuestSession();
  237. pref_service()->SetBoolean(prefs::kSuggestLogoutAfterClosingLastWindow,
  238. false);
  239. EXPECT_FALSE(controller->dialog_for_testing());
  240. // Opening windows does not show the dialog.
  241. std::unique_ptr<views::Widget> widget1 = CreateTestWidget();
  242. std::unique_ptr<views::Widget> widget2 = CreateTestWidget();
  243. EXPECT_FALSE(controller->dialog_for_testing());
  244. // Closing the last window does not show the dialog because the
  245. // kSuggestLogoutAfterClosingLastWindow is set to false.
  246. widget1.reset();
  247. EXPECT_FALSE(controller->dialog_for_testing());
  248. widget2.reset();
  249. EXPECT_FALSE(controller->dialog_for_testing());
  250. }
  251. // Test ARC++ window hierarchy where window minimize, restore and go in/out full
  252. // screen causes a window removing deep inside the top window hierarchy. Actions
  253. // above should no cause logout timer and only closing the last top window
  254. // triggers the logout timer.
  255. TEST_F(LastWindowClosedTest, ManagedGuestSessionComplexHierarchy) {
  256. LogoutConfirmationController* controller =
  257. Shell::Get()->logout_confirmation_controller();
  258. StartManagedGuestSession();
  259. EXPECT_FALSE(controller->dialog_for_testing());
  260. std::unique_ptr<aura::Window> window = CreateToplevelTestWindow();
  261. EXPECT_FALSE(controller->dialog_for_testing());
  262. std::unique_ptr<aura::Window> window_child =
  263. ChildTestWindowBuilder(window.get()).Build();
  264. EXPECT_FALSE(controller->dialog_for_testing());
  265. window_child.reset();
  266. EXPECT_FALSE(controller->dialog_for_testing());
  267. window.reset();
  268. EXPECT_TRUE(controller->dialog_for_testing());
  269. }
  270. TEST_F(LastWindowClosedTest, AlwaysOnTop) {
  271. LogoutConfirmationController* controller =
  272. Shell::Get()->logout_confirmation_controller();
  273. StartManagedGuestSession();
  274. // The new widget starts in the default window container.
  275. std::unique_ptr<views::Widget> widget = CreateTestWidget();
  276. // Moving the widget to the always-on-top container does not trigger the
  277. // dialog because the window didn't close.
  278. widget->SetZOrderLevel(ui::ZOrderLevel::kFloatingWindow);
  279. EXPECT_FALSE(controller->dialog_for_testing());
  280. // Closing the window triggers the dialog.
  281. widget.reset();
  282. EXPECT_TRUE(controller->dialog_for_testing());
  283. }
  284. TEST_F(LastWindowClosedTest, MultipleContainers) {
  285. LogoutConfirmationController* controller =
  286. Shell::Get()->logout_confirmation_controller();
  287. StartManagedGuestSession();
  288. // Create two windows in different containers.
  289. std::unique_ptr<views::Widget> normal_widget = CreateTestWidget();
  290. std::unique_ptr<views::Widget> always_on_top_widget = CreateTestWidget();
  291. always_on_top_widget->SetZOrderLevel(ui::ZOrderLevel::kFloatingWindow);
  292. // Closing the last window shows the dialog.
  293. always_on_top_widget.reset();
  294. EXPECT_FALSE(controller->dialog_for_testing());
  295. normal_widget.reset();
  296. EXPECT_TRUE(controller->dialog_for_testing());
  297. }
  298. TEST_F(LastWindowClosedTest, MultipleDisplays) {
  299. LogoutConfirmationController* controller =
  300. Shell::Get()->logout_confirmation_controller();
  301. StartManagedGuestSession();
  302. // Create two displays, each with a window.
  303. UpdateDisplay("1024x768,800x600");
  304. std::unique_ptr<aura::Window> window1 =
  305. ChildTestWindowBuilder(Shell::GetAllRootWindows()[0]->GetChildById(
  306. desks_util::GetActiveDeskContainerId()))
  307. .Build();
  308. std::unique_ptr<aura::Window> window2 =
  309. ChildTestWindowBuilder(Shell::GetAllRootWindows()[1]->GetChildById(
  310. desks_util::GetActiveDeskContainerId()))
  311. .Build();
  312. // Closing the last window shows the dialog.
  313. window1.reset();
  314. EXPECT_FALSE(controller->dialog_for_testing());
  315. window2.reset();
  316. EXPECT_TRUE(controller->dialog_for_testing());
  317. }
  318. } // namespace ash