| OLD | NEW |
| (Empty) | |
| 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 "chrome/browser/chromeos/power/session_length_limiter.h" |
| 6 |
| 7 #include <deque> |
| 8 #include <utility> |
| 9 |
| 10 #include "base/callback.h" |
| 11 #include "base/compiler_specific.h" |
| 12 #include "base/location.h" |
| 13 #include "base/logging.h" |
| 14 #include "base/memory/ref_counted.h" |
| 15 #include "base/memory/scoped_ptr.h" |
| 16 #include "base/single_thread_task_runner.h" |
| 17 #include "base/string_number_conversions.h" |
| 18 #include "base/thread_task_runner_handle.h" |
| 19 #include "base/time.h" |
| 20 #include "base/values.h" |
| 21 #include "chrome/browser/browser_process.h" |
| 22 #include "chrome/common/pref_names.h" |
| 23 #include "chrome/test/base/testing_browser_process.h" |
| 24 #include "chrome/test/base/testing_pref_service.h" |
| 25 #include "testing/gmock/include/gmock/gmock.h" |
| 26 #include "testing/gtest/include/gtest/gtest.h" |
| 27 |
| 28 using ::testing::_; |
| 29 using ::testing::Invoke; |
| 30 using ::testing::Mock; |
| 31 using ::testing::NiceMock; |
| 32 |
| 33 namespace chromeos { |
| 34 |
| 35 namespace { |
| 36 |
| 37 // The interval at which the SessionLengthLimiter checks whether the remaining |
| 38 // session time has reachzed zero. |
| 39 const base::TimeDelta kSessionLengthLimitTimerInterval( |
| 40 base::TimeDelta::FromSeconds(1)); |
| 41 |
| 42 const base::TimeDelta kZeroTimeDelta; |
| 43 const base::TimeDelta kTenSeconds(base::TimeDelta::FromSeconds(10)); |
| 44 |
| 45 class MockSessionLengthLimiterDelegate : public SessionLengthLimiter::Delegate { |
| 46 public: |
| 47 MOCK_CONST_METHOD0(GetCurrentTime, const base::Time(void)); |
| 48 MOCK_METHOD0(StopSession, void(void)); |
| 49 }; |
| 50 |
| 51 // A SingleThreadTaskRunner that allows the task queue to be inspected and |
| 52 // delayed tasks to be run without waiting for the actual delays to expire. |
| 53 class ImmediateSingleThreadTaskRunner : public base::SingleThreadTaskRunner { |
| 54 public: |
| 55 virtual bool RunsTasksOnCurrentThread() const OVERRIDE { |
| 56 return true; |
| 57 } |
| 58 |
| 59 virtual bool PostDelayedTask(const tracked_objects::Location& from_here, |
| 60 const base::Closure& task, |
| 61 base::TimeDelta delay) OVERRIDE { |
| 62 tasks_.push_back(std::pair<base::TimeDelta, base::Closure>(delay, task)); |
| 63 return true; |
| 64 } |
| 65 |
| 66 virtual bool PostNonNestableDelayedTask( |
| 67 const tracked_objects::Location& from_here, |
| 68 const base::Closure& task, |
| 69 base::TimeDelta delay) OVERRIDE { |
| 70 NOTREACHED(); |
| 71 return false; |
| 72 } |
| 73 |
| 74 void RunTasks() { |
| 75 std::deque<std::pair<base::TimeDelta, base::Closure> > tasks; |
| 76 tasks.swap(tasks_); |
| 77 for (std::deque<std::pair<base::TimeDelta, base::Closure> >::iterator |
| 78 it = tasks.begin(); it != tasks.end(); ++it) { |
| 79 it->second.Run(); |
| 80 } |
| 81 } |
| 82 |
| 83 const std::deque<std::pair<base::TimeDelta, base::Closure> >& tasks() const { |
| 84 return tasks_; |
| 85 } |
| 86 |
| 87 private: |
| 88 std::deque<std::pair<base::TimeDelta, base::Closure> > tasks_; |
| 89 |
| 90 virtual ~ImmediateSingleThreadTaskRunner() {} |
| 91 }; |
| 92 |
| 93 } // namespace |
| 94 |
| 95 class SessionLengthLimiterTest : public testing::Test { |
| 96 protected: |
| 97 SessionLengthLimiterTest() : delegate_(NULL) { |
| 98 } |
| 99 |
| 100 virtual void SetUp() { |
| 101 static_cast<TestingBrowserProcess*>(g_browser_process)-> |
| 102 SetLocalState(&local_state_); |
| 103 SessionLengthLimiter::RegisterPrefs(&local_state_); |
| 104 |
| 105 delegate_ = new NiceMock<MockSessionLengthLimiterDelegate>; |
| 106 ON_CALL(*delegate_, GetCurrentTime()) |
| 107 .WillByDefault(Invoke(this, &SessionLengthLimiterTest::GetCurrentTime)); |
| 108 EXPECT_CALL(*delegate_, StopSession()).Times(0); |
| 109 runner_ = new ImmediateSingleThreadTaskRunner; |
| 110 |
| 111 // Initialize the mock clock to a fixed value, ensuring that timezone |
| 112 // differences or DST changes do not affect the test. |
| 113 now_ = base::Time::UnixEpoch() + base::TimeDelta::FromDays(40 * 365); |
| 114 session_start_time_ = now_; |
| 115 } |
| 116 |
| 117 virtual void TearDown() { |
| 118 static_cast<TestingBrowserProcess*>(g_browser_process)->SetLocalState(NULL); |
| 119 } |
| 120 |
| 121 void SetSessionStartTimePref(int64 session_start_time) { |
| 122 local_state_.SetUserPref(prefs::kSessionStartTime, |
| 123 base::Value::CreateStringValue( |
| 124 base::Int64ToString(session_start_time))); |
| 125 } |
| 126 |
| 127 void VerifySessionStartTimePref() { |
| 128 base::Time session_start_time(base::Time::FromInternalValue( |
| 129 local_state_.GetInt64(prefs::kSessionStartTime))); |
| 130 EXPECT_EQ(session_start_time_, session_start_time); |
| 131 } |
| 132 |
| 133 void SetSessionLengthLimitPref(int64 session_length_limit) { |
| 134 local_state_.SetUserPref(prefs::kSessionLengthLimit, |
| 135 base::Value::CreateIntegerValue( |
| 136 session_length_limit)); |
| 137 base::TimeDelta remaining( |
| 138 base::TimeDelta::FromMilliseconds(session_length_limit) - |
| 139 (now_ - session_start_time_)); |
| 140 if (remaining < kZeroTimeDelta) |
| 141 remaining = kZeroTimeDelta; |
| 142 remaining_.reset(new base::TimeDelta(remaining)); |
| 143 } |
| 144 |
| 145 void ExpectStopSession() { |
| 146 Mock::VerifyAndClearExpectations(delegate_); |
| 147 EXPECT_CALL(*delegate_, StopSession()).Times(1); |
| 148 } |
| 149 |
| 150 void CreateSessionLengthLimiter(bool browser_restarted) { |
| 151 session_length_limiter_.reset( |
| 152 new SessionLengthLimiter(delegate_, browser_restarted)); |
| 153 } |
| 154 |
| 155 void VerifyNoTimerTickIsEnqueued() { |
| 156 EXPECT_TRUE(runner_->tasks().empty()); |
| 157 } |
| 158 |
| 159 void VerifyTimerTickIsEnqueued() { |
| 160 ASSERT_EQ(1U, runner_->tasks().size()); |
| 161 EXPECT_EQ(kSessionLengthLimitTimerInterval, |
| 162 runner_->tasks().front().first); |
| 163 } |
| 164 |
| 165 void VerifyTimerTick() { |
| 166 VerifyTimerTickIsEnqueued(); |
| 167 runner_->RunTasks(); |
| 168 |
| 169 now_ += kSessionLengthLimitTimerInterval; |
| 170 *remaining_ -= kSessionLengthLimitTimerInterval; |
| 171 if (*remaining_ < kZeroTimeDelta) |
| 172 remaining_.reset(new base::TimeDelta(kZeroTimeDelta)); |
| 173 } |
| 174 |
| 175 base::Time GetCurrentTime() const { |
| 176 return now_; |
| 177 } |
| 178 |
| 179 TestingPrefService local_state_; |
| 180 MockSessionLengthLimiterDelegate* delegate_; // Owned by |
| 181 // session_length_limiter_. |
| 182 scoped_refptr<ImmediateSingleThreadTaskRunner> runner_; |
| 183 |
| 184 base::Time session_start_time_; |
| 185 base::Time now_; |
| 186 scoped_ptr<base::TimeDelta> remaining_; |
| 187 |
| 188 scoped_ptr<SessionLengthLimiter> session_length_limiter_; |
| 189 }; |
| 190 |
| 191 // Verifies that the session start time in local state is updated during login |
| 192 // if no session start time has been stored before. |
| 193 TEST_F(SessionLengthLimiterTest, StartWithSessionStartTimeUnset) { |
| 194 CreateSessionLengthLimiter(false); |
| 195 VerifySessionStartTimePref(); |
| 196 } |
| 197 |
| 198 // Verifies that the session start time in local state is updated during login |
| 199 // if an invalid session start time has been stored before. |
| 200 TEST_F(SessionLengthLimiterTest, StartWithSessionStartTimeInvalid) { |
| 201 SetSessionStartTimePref(0); |
| 202 CreateSessionLengthLimiter(false); |
| 203 VerifySessionStartTimePref(); |
| 204 } |
| 205 |
| 206 // Verifies that the session start time in local state is updated during login |
| 207 // if a session start time lying in the future has been stored before. |
| 208 TEST_F(SessionLengthLimiterTest, StartWithSessionStartTimeFuture) { |
| 209 SetSessionStartTimePref( |
| 210 (now_ + base::TimeDelta::FromHours(2)).ToInternalValue()); |
| 211 CreateSessionLengthLimiter(false); |
| 212 VerifySessionStartTimePref(); |
| 213 } |
| 214 |
| 215 // Verifies that the session start time in local state is updated during login |
| 216 // if a valid session start time has been stored before. |
| 217 TEST_F(SessionLengthLimiterTest, StartWithSessionStartTimeValid) { |
| 218 const base::Time previous_start_time = now_ - base::TimeDelta::FromHours(2); |
| 219 SetSessionStartTimePref(previous_start_time.ToInternalValue()); |
| 220 CreateSessionLengthLimiter(false); |
| 221 VerifySessionStartTimePref(); |
| 222 } |
| 223 |
| 224 // Verifies that the session start time in local state is updated during restart |
| 225 // after a crash if no session start time has been stored before. |
| 226 TEST_F(SessionLengthLimiterTest, RestartWithSessionStartTimeUnset) { |
| 227 CreateSessionLengthLimiter(true); |
| 228 VerifySessionStartTimePref(); |
| 229 } |
| 230 |
| 231 // Verifies that the session start time in local state is updated during restart |
| 232 // after a crash if an invalid session start time has been stored before. |
| 233 TEST_F(SessionLengthLimiterTest, RestartWithSessionStartTimeInvalid) { |
| 234 SetSessionStartTimePref(0); |
| 235 CreateSessionLengthLimiter(true); |
| 236 VerifySessionStartTimePref(); |
| 237 } |
| 238 |
| 239 // Verifies that the session start time in local state is updated during restart |
| 240 // after a crash if a session start time lying in the future has been stored |
| 241 // before. |
| 242 TEST_F(SessionLengthLimiterTest, RestartWithSessionStartTimeFuture) { |
| 243 SetSessionStartTimePref( |
| 244 (now_ + base::TimeDelta::FromHours(2)).ToInternalValue()); |
| 245 CreateSessionLengthLimiter(true); |
| 246 VerifySessionStartTimePref(); |
| 247 } |
| 248 |
| 249 // Verifies that the session start time in local state is *not* updated during |
| 250 // restart after a crash if a valid session start time has been stored before. |
| 251 TEST_F(SessionLengthLimiterTest, RestartWithSessionStartTimeValid) { |
| 252 session_start_time_ -= base::TimeDelta::FromHours(2); |
| 253 SetSessionStartTimePref(session_start_time_.ToInternalValue()); |
| 254 CreateSessionLengthLimiter(true); |
| 255 VerifySessionStartTimePref(); |
| 256 } |
| 257 |
| 258 // Creates a SessionLengthLimiter without setting a limit. Verifies that the |
| 259 // limiter does not start a timer. |
| 260 TEST_F(SessionLengthLimiterTest, RunWithoutSessionLengthLimit) { |
| 261 base::ThreadTaskRunnerHandle runner_handler(runner_); |
| 262 |
| 263 // Create a SessionLengthLimiter. |
| 264 CreateSessionLengthLimiter(false); |
| 265 |
| 266 // Verify that no timer tick has been enqueued. |
| 267 VerifyNoTimerTickIsEnqueued(); |
| 268 } |
| 269 |
| 270 // Creates a SessionLengthLimiter after setting a limit. Verifies that the |
| 271 // limiter starts a timer and that when the session length reaches the limit, |
| 272 // the session is terminated. |
| 273 TEST_F(SessionLengthLimiterTest, RunWithSessionLengthLimit) { |
| 274 base::ThreadTaskRunnerHandle runner_handler(runner_); |
| 275 |
| 276 // Set a 60 second session time limit. |
| 277 SetSessionLengthLimitPref(60 * 1000); // 60 seconds. |
| 278 |
| 279 // Create a SessionLengthLimiter. |
| 280 CreateSessionLengthLimiter(false); |
| 281 |
| 282 // Check timer ticks until the remaining session time reaches zero. |
| 283 while (*remaining_ > kZeroTimeDelta) |
| 284 VerifyTimerTick(); |
| 285 |
| 286 // Check that the next timer tick leads to the session being terminated. |
| 287 ExpectStopSession(); |
| 288 VerifyTimerTick(); |
| 289 } |
| 290 |
| 291 // Creates a SessionLengthLimiter after setting a 60 second limit, allows 50 |
| 292 // seconds of session time to pass, then increases the limit to 90 seconds. |
| 293 // Verifies that when the session time reaches the new 90 second limit, the |
| 294 // session is terminated. |
| 295 TEST_F(SessionLengthLimiterTest, RunAndIncreaseSessionLengthLimit) { |
| 296 base::ThreadTaskRunnerHandle runner_handler(runner_); |
| 297 |
| 298 // Set a 60 second session time limit. |
| 299 SetSessionLengthLimitPref(60 * 1000); // 60 seconds. |
| 300 |
| 301 // Create a SessionLengthLimiter. |
| 302 CreateSessionLengthLimiter(false); |
| 303 |
| 304 // Check timer ticks for 50 seconds of session time. |
| 305 while (*remaining_ > kTenSeconds) |
| 306 VerifyTimerTick(); |
| 307 |
| 308 // Increase the session length limit to 90 seconds. |
| 309 SetSessionLengthLimitPref(90 * 1000); // 90 seconds. |
| 310 |
| 311 // Check timer ticks until the remaining session time reaches zero. |
| 312 while (*remaining_ > kZeroTimeDelta) |
| 313 VerifyTimerTick(); |
| 314 |
| 315 // Check that the next timer tick leads to the session being terminated. |
| 316 ExpectStopSession(); |
| 317 VerifyTimerTick(); |
| 318 } |
| 319 |
| 320 // Creates a SessionLengthLimiter after setting a 60 second limit, allows 50 |
| 321 // seconds of session time to pass, then decreases the limit to 40 seconds. |
| 322 // Verifies that when the limit is decreased to 40 seconds after 50 seconds of |
| 323 // session time have passed, the next timer tick causes the session to be |
| 324 // terminated. |
| 325 TEST_F(SessionLengthLimiterTest, RunAndDecreaseSessionLengthLimit) { |
| 326 base::ThreadTaskRunnerHandle runner_handler(runner_); |
| 327 |
| 328 // Set a 60 second session time limit. |
| 329 SetSessionLengthLimitPref(60 * 1000); // 60 seconds. |
| 330 |
| 331 // Create a SessionLengthLimiter. |
| 332 CreateSessionLengthLimiter(false); |
| 333 |
| 334 // Check timer ticks for 50 seconds of session time. |
| 335 while (*remaining_ > kTenSeconds) |
| 336 VerifyTimerTick(); |
| 337 |
| 338 // Reduce the session length limit below the 50 seconds that have already |
| 339 // elapsed. |
| 340 SetSessionLengthLimitPref(40 * 1000); // 40 seconds. |
| 341 |
| 342 // Check that the next timer tick causes the session to be terminated. |
| 343 ExpectStopSession(); |
| 344 VerifyTimerTick(); |
| 345 } |
| 346 |
| 347 // Creates a SessionLengthLimiter after setting a 60 second limit, allows 50 |
| 348 // seconds of session time to pass, then removes the limit. Verifies that after |
| 349 // the limit is removed, the session is not terminated when the session time |
| 350 // reaches the original 60 second limit. |
| 351 TEST_F(SessionLengthLimiterTest, RunAndRemoveSessionLengthLimit) { |
| 352 base::ThreadTaskRunnerHandle runner_handler(runner_); |
| 353 |
| 354 // Set a 60 second session time limit. |
| 355 SetSessionLengthLimitPref(60 * 1000); // 60 seconds. |
| 356 |
| 357 // Create a SessionLengthLimiter. |
| 358 CreateSessionLengthLimiter(false); |
| 359 |
| 360 // Check timer ticks for 50 seconds of session time. |
| 361 while (*remaining_ > kTenSeconds) |
| 362 VerifyTimerTick(); |
| 363 |
| 364 // Remove the session length limit. |
| 365 local_state_.RemoveUserPref(prefs::kSessionLengthLimit); |
| 366 |
| 367 // Continue advancing the session time until it reaches the original 60 second |
| 368 // limit. |
| 369 while (*remaining_ > kZeroTimeDelta) { |
| 370 runner_->RunTasks(); |
| 371 |
| 372 now_ += kSessionLengthLimitTimerInterval; |
| 373 *remaining_ -= kSessionLengthLimitTimerInterval; |
| 374 if (*remaining_ < kZeroTimeDelta) |
| 375 remaining_.reset(new base::TimeDelta(kZeroTimeDelta)); |
| 376 } |
| 377 |
| 378 // Check that the next timer tick does not lead to the session being |
| 379 // terminated. |
| 380 now_ += kSessionLengthLimitTimerInterval; |
| 381 runner_->RunTasks(); |
| 382 } |
| 383 |
| 384 } // namespace chromeos |
| OLD | NEW |