OLD | NEW |
---|---|
(Empty) | |
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 "ash/system/session/logout_confirmation_controller.h" | |
6 | |
7 #include <queue> | |
8 #include <utility> | |
9 #include <vector> | |
10 | |
11 #include "base/bind.h" | |
12 #include "base/bind_helpers.h" | |
13 #include "base/compiler_specific.h" | |
14 #include "base/location.h" | |
15 #include "base/memory/ref_counted.h" | |
16 #include "base/single_thread_task_runner.h" | |
17 #include "base/thread_task_runner_handle.h" | |
18 #include "base/time/tick_clock.h" | |
19 #include "testing/gtest/include/gtest/gtest.h" | |
20 | |
21 namespace ash { | |
22 namespace internal { | |
23 | |
24 namespace { | |
25 | |
26 // A SingleThreadTaskRunner that mocks the current time and allows it to be | |
27 // fast-forwarded. TODO(bartfab): Copies of this class exist in several tests. | |
28 // Consolidate them (crbug.com/329911). | |
29 class MockTimeSingleThreadTaskRunner : public base::SingleThreadTaskRunner { | |
30 public: | |
31 MockTimeSingleThreadTaskRunner(); | |
32 | |
33 // base::SingleThreadTaskRunner: | |
34 virtual bool RunsTasksOnCurrentThread() const OVERRIDE; | |
35 virtual bool PostDelayedTask(const tracked_objects::Location& from_here, | |
36 const base::Closure& task, | |
37 base::TimeDelta delay) OVERRIDE; | |
38 virtual bool PostNonNestableDelayedTask( | |
39 const tracked_objects::Location& from_here, | |
40 const base::Closure& task, | |
41 base::TimeDelta delay) OVERRIDE; | |
42 | |
43 const base::TimeTicks& GetCurrentTime() const; | |
44 | |
45 void FastForwardBy(base::TimeDelta delta); | |
46 void FastForwardUntilNoTasksRemain(); | |
47 | |
48 private: | |
49 // Strict weak temporal ordering of tasks. | |
50 class TemporalOrder { | |
51 public: | |
52 bool operator()( | |
53 const std::pair<base::TimeTicks, base::Closure>& first_task, | |
54 const std::pair<base::TimeTicks, base::Closure>& second_task) const; | |
55 }; | |
56 | |
57 virtual ~MockTimeSingleThreadTaskRunner(); | |
58 | |
59 base::TimeTicks now_; | |
60 std::priority_queue<std::pair<base::TimeTicks, base::Closure>, | |
61 std::vector<std::pair<base::TimeTicks, base::Closure> >, | |
62 TemporalOrder> tasks_; | |
63 | |
64 DISALLOW_COPY_AND_ASSIGN(MockTimeSingleThreadTaskRunner); | |
65 }; | |
66 | |
67 // A base::TickClock that uses a MockTimeSingleThreadTaskRunner as the source of | |
68 // the current time. | |
69 class MockClock : public base::TickClock { | |
70 public: | |
71 explicit MockClock(scoped_refptr<MockTimeSingleThreadTaskRunner> task_runner); | |
72 virtual ~MockClock(); | |
73 | |
74 // base::TickClock: | |
75 virtual base::TimeTicks NowTicks() OVERRIDE; | |
76 | |
77 private: | |
78 scoped_refptr<MockTimeSingleThreadTaskRunner> task_runner_; | |
79 | |
80 DISALLOW_COPY_AND_ASSIGN(MockClock); | |
81 }; | |
82 | |
83 | |
84 MockTimeSingleThreadTaskRunner::MockTimeSingleThreadTaskRunner() { | |
85 } | |
86 | |
87 bool MockTimeSingleThreadTaskRunner::RunsTasksOnCurrentThread() const { | |
88 return true; | |
89 } | |
90 | |
91 bool MockTimeSingleThreadTaskRunner::PostDelayedTask( | |
92 const tracked_objects::Location& from_here, | |
93 const base::Closure& task, | |
94 base::TimeDelta delay) { | |
95 tasks_.push(std::make_pair(now_ + delay, task)); | |
96 return true; | |
97 } | |
98 | |
99 bool MockTimeSingleThreadTaskRunner::PostNonNestableDelayedTask( | |
100 const tracked_objects::Location& from_here, | |
101 const base::Closure& task, | |
102 base::TimeDelta delay) { | |
103 NOTREACHED(); | |
104 return false; | |
105 } | |
106 | |
107 const base::TimeTicks& MockTimeSingleThreadTaskRunner::GetCurrentTime() const { | |
108 return now_; | |
109 } | |
110 | |
111 void MockTimeSingleThreadTaskRunner::FastForwardBy(base::TimeDelta delta) { | |
112 const base::TimeTicks latest = now_ + delta; | |
113 while (!tasks_.empty() && tasks_.top().first <= latest) { | |
114 now_ = tasks_.top().first; | |
115 base::Closure task = tasks_.top().second; | |
116 tasks_.pop(); | |
117 task.Run(); | |
118 } | |
119 now_ = latest; | |
120 } | |
121 | |
122 void MockTimeSingleThreadTaskRunner::FastForwardUntilNoTasksRemain() { | |
123 while (!tasks_.empty()) { | |
124 now_ = tasks_.top().first; | |
125 base::Closure task = tasks_.top().second; | |
126 tasks_.pop(); | |
127 task.Run(); | |
128 } | |
129 } | |
130 | |
131 bool MockTimeSingleThreadTaskRunner::TemporalOrder::operator()( | |
132 const std::pair<base::TimeTicks, base::Closure>& first_task, | |
133 const std::pair<base::TimeTicks, base::Closure>& second_task) const { | |
134 return first_task.first > second_task.first; | |
135 } | |
136 | |
137 MockTimeSingleThreadTaskRunner::~MockTimeSingleThreadTaskRunner() { | |
138 } | |
139 | |
140 MockClock::MockClock(scoped_refptr<MockTimeSingleThreadTaskRunner> task_runner) | |
141 : task_runner_(task_runner) { | |
142 } | |
143 | |
144 MockClock::~MockClock() { | |
145 } | |
146 | |
147 base::TimeTicks MockClock::NowTicks() { | |
148 return task_runner_->GetCurrentTime(); | |
149 } | |
150 | |
151 } // namespace | |
152 | |
153 class LogoutConfirmationControllerTest : public testing::Test { | |
154 protected: | |
155 LogoutConfirmationControllerTest(); | |
156 virtual ~LogoutConfirmationControllerTest(); | |
157 | |
158 void LogOut(); | |
159 | |
160 bool log_out_called_; | |
161 | |
162 scoped_refptr<MockTimeSingleThreadTaskRunner> runner_; | |
163 base::ThreadTaskRunnerHandle runner_handle_; | |
164 | |
165 LogoutConfirmationController controller_; | |
166 | |
167 private: | |
168 DISALLOW_COPY_AND_ASSIGN(LogoutConfirmationControllerTest); | |
169 }; | |
170 | |
171 LogoutConfirmationControllerTest::LogoutConfirmationControllerTest() | |
172 : log_out_called_(false), | |
173 runner_(new MockTimeSingleThreadTaskRunner), | |
174 runner_handle_(runner_), | |
175 controller_(base::Bind(&LogoutConfirmationControllerTest::LogOut, | |
176 base::Unretained(this))) { | |
177 controller_.SetClockForTesting( | |
178 scoped_ptr<base::TickClock>(new MockClock(runner_))); | |
179 } | |
180 | |
181 LogoutConfirmationControllerTest::~LogoutConfirmationControllerTest() { | |
182 } | |
183 | |
184 void LogoutConfirmationControllerTest::LogOut() { | |
185 log_out_called_ = true; | |
186 } | |
187 | |
188 // Verifies that the user is logged out immediately if logout confirmation with | |
189 // a zero-length countdown is requested. | |
190 TEST_F(LogoutConfirmationControllerTest, ZeroDuration) { | |
191 controller_.ConfirmLogout(runner_->GetCurrentTime()); | |
192 EXPECT_FALSE(log_out_called_); | |
193 runner_->FastForwardBy(base::TimeDelta()); | |
194 EXPECT_TRUE(log_out_called_); | |
195 } | |
196 | |
197 // Verifies that the user is logged out when the countdown expires. | |
198 TEST_F(LogoutConfirmationControllerTest, DurationExpired) { | |
199 controller_.ConfirmLogout( | |
200 runner_->GetCurrentTime() + base::TimeDelta::FromSeconds(10)); | |
201 EXPECT_FALSE(log_out_called_); | |
202 runner_->FastForwardBy(base::TimeDelta::FromSeconds(9)); | |
203 EXPECT_FALSE(log_out_called_); | |
204 runner_->FastForwardBy(base::TimeDelta::FromSeconds(2)); | |
205 EXPECT_TRUE(log_out_called_); | |
206 } | |
207 | |
208 // Verifies that when a second request to confirm logout is made and the second | |
209 // request's countdown ends before the original request's, the user is logged | |
210 // out when the new countdown expires. | |
211 TEST_F(LogoutConfirmationControllerTest, DurationShortened) { | |
212 controller_.ConfirmLogout( | |
213 runner_->GetCurrentTime() + base::TimeDelta::FromSeconds(30)); | |
214 EXPECT_FALSE(log_out_called_); | |
215 runner_->FastForwardBy(base::TimeDelta::FromSeconds(9)); | |
216 EXPECT_FALSE(log_out_called_); | |
217 controller_.ConfirmLogout( | |
218 runner_->GetCurrentTime() + base::TimeDelta::FromSeconds(10)); | |
219 runner_->FastForwardBy(base::TimeDelta::FromSeconds(9)); | |
220 EXPECT_FALSE(log_out_called_); | |
221 runner_->FastForwardBy(base::TimeDelta::FromSeconds(2)); | |
222 EXPECT_TRUE(log_out_called_); | |
223 } | |
224 | |
225 // Verifies that when a second request to confirm logout is made and the second | |
226 // request's countdown ends after the original request's, the user is logged | |
227 // out when the original countdown expires. | |
228 TEST_F(LogoutConfirmationControllerTest, DurationExtended) { | |
229 controller_.ConfirmLogout( | |
230 runner_->GetCurrentTime() + base::TimeDelta::FromSeconds(10)); | |
231 EXPECT_FALSE(log_out_called_); | |
232 runner_->FastForwardBy(base::TimeDelta::FromSeconds(9)); | |
233 EXPECT_FALSE(log_out_called_); | |
234 controller_.ConfirmLogout( | |
235 runner_->GetCurrentTime() + base::TimeDelta::FromSeconds(10)); | |
236 runner_->FastForwardBy(base::TimeDelta::FromSeconds(2)); | |
237 EXPECT_TRUE(log_out_called_); | |
238 } | |
239 | |
240 // Verifies that when the screen is locked while the countdown is running, the | |
241 // user is not logged out, even when the original countdown expires. | |
242 TEST_F(LogoutConfirmationControllerTest, Lock) { | |
243 controller_.ConfirmLogout( | |
244 runner_->GetCurrentTime() + base::TimeDelta::FromSeconds(10)); | |
245 EXPECT_FALSE(log_out_called_); | |
246 controller_.OnLockStateChanged(true); | |
247 runner_->FastForwardUntilNoTasksRemain(); | |
248 EXPECT_FALSE(log_out_called_); | |
249 } | |
250 | |
251 // Verifies that when the user confirms the logout request, the user is logged | |
252 // out immediately. | |
253 TEST_F(LogoutConfirmationControllerTest, UserAccepted) { | |
254 controller_.ConfirmLogout( | |
255 runner_->GetCurrentTime() + base::TimeDelta::FromSeconds(10)); | |
256 EXPECT_FALSE(log_out_called_); | |
257 controller_.OnLogoutConfirmed(); | |
258 EXPECT_TRUE(log_out_called_); | |
259 } | |
260 | |
261 // Verifies that when the user denies the logout request, the user is not logged | |
262 // out, even when the original countdown expires. | |
263 TEST_F(LogoutConfirmationControllerTest, UserDeclineed) { | |
264 controller_.ConfirmLogout( | |
265 runner_->GetCurrentTime() + base::TimeDelta::FromSeconds(10)); | |
266 EXPECT_FALSE(log_out_called_); | |
267 controller_.OnDialogClosed(); | |
268 runner_->FastForwardUntilNoTasksRemain(); | |
269 EXPECT_FALSE(log_out_called_); | |
270 } | |
stevenjb
2014/03/05 18:57:20
Can we add a test to ensure that if a user decline
bartfab (slow)
2014/03/05 22:24:56
Done.
| |
271 | |
272 } // namespace internal | |
273 } // namespace ash | |
OLD | NEW |