| 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/session_length_limiter.h" |
| 6 |
| 7 #include <deque> |
| 8 #include <utility> |
| 9 |
| 10 #include "base/basictypes.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 "chrome/browser/chromeos/login/mock_user_manager.h" |
| 21 #include "chrome/browser/chromeos/login/user_manager.h" |
| 22 #include "chrome/browser/chromeos/session_length_limiter_factory.h" |
| 23 #include "chrome/common/pref_names.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::Eq; |
| 30 using ::testing::Invoke; |
| 31 using ::testing::Mock; |
| 32 using ::testing::NiceMock; |
| 33 using ::testing::Pointee; |
| 34 using ::testing::Return; |
| 35 |
| 36 namespace chromeos { |
| 37 |
| 38 namespace { |
| 39 |
| 40 // The interval at which the SessionLengthLimiter fires periodic callbacks. |
| 41 const base::TimeDelta kSessionLengthLimitTimerInterval( |
| 42 base::TimeDelta::FromSeconds(1)); |
| 43 |
| 44 const base::TimeDelta kZeroTimeDelta; |
| 45 const base::TimeDelta kTenSeconds(base::TimeDelta::FromSeconds(10)); |
| 46 |
| 47 class MockSessionLengthLimiterObserver : public SessionLengthLimiter::Observer { |
| 48 public: |
| 49 MOCK_METHOD1(SessionTimeRemainingChanged, void(const base::TimeDelta*)); |
| 50 }; |
| 51 |
| 52 class MockSessionLengthLimiterDelegate : public SessionLengthLimiter::Delegate { |
| 53 public: |
| 54 MOCK_CONST_METHOD0(GetCurrentTime, const base::Time(void)); |
| 55 MOCK_METHOD0(Logout, void(void)); |
| 56 }; |
| 57 |
| 58 // A SingleThreadTaskRunner that allows the task queue to be inspected and |
| 59 // delayed tasks to be run without waiting for the actual delays to expire. |
| 60 class ImmediateSingleThreadTaskRunner : public base::SingleThreadTaskRunner { |
| 61 public: |
| 62 virtual bool RunsTasksOnCurrentThread() const { |
| 63 return true; |
| 64 } |
| 65 |
| 66 virtual bool PostDelayedTask(const tracked_objects::Location& from_here, |
| 67 const base::Closure& task, |
| 68 base::TimeDelta delay) OVERRIDE { |
| 69 tasks_.push_back(std::pair<base::TimeDelta, base::Closure>(delay, task)); |
| 70 return true; |
| 71 } |
| 72 |
| 73 virtual bool PostNonNestableDelayedTask( |
| 74 const tracked_objects::Location& from_here, |
| 75 const base::Closure& task, |
| 76 base::TimeDelta delay) OVERRIDE { |
| 77 NOTREACHED(); |
| 78 return false; |
| 79 } |
| 80 |
| 81 void RunTasks() { |
| 82 std::deque<std::pair<base::TimeDelta, base::Closure> > tasks; |
| 83 tasks.swap(tasks_); |
| 84 for (std::deque<std::pair<base::TimeDelta, base::Closure> >::iterator |
| 85 it = tasks.begin(); it != tasks.end(); ++it) { |
| 86 it->second.Run(); |
| 87 } |
| 88 } |
| 89 |
| 90 const std::deque<std::pair<base::TimeDelta, base::Closure> >& tasks() const { |
| 91 return tasks_; |
| 92 } |
| 93 |
| 94 private: |
| 95 std::deque<std::pair<base::TimeDelta, base::Closure> > tasks_; |
| 96 |
| 97 virtual ~ImmediateSingleThreadTaskRunner() {} |
| 98 }; |
| 99 |
| 100 } // namespace |
| 101 |
| 102 class SessionLengthLimiterTest : public testing::Test { |
| 103 protected: |
| 104 SessionLengthLimiterTest() : delegate_(NULL) { |
| 105 } |
| 106 |
| 107 virtual void SetUp() { |
| 108 old_user_manager_ = UserManager::Set(&mock_user_manager_); |
| 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 SessionLengthLimiterFactory::GetInstance()->RegisterUserPrefs(&prefs_); |
| 117 } |
| 118 |
| 119 virtual void TearDown() { |
| 120 session_length_limiter_->Shutdown(); |
| 121 UserManager::Set(old_user_manager_); |
| 122 } |
| 123 |
| 124 void CreateSessionLengthLimiter() { |
| 125 delegate_ = new NiceMock<MockSessionLengthLimiterDelegate>; |
| 126 ON_CALL(*delegate_, GetCurrentTime()) |
| 127 .WillByDefault(Invoke(this, &SessionLengthLimiterTest::GetCurrentTime)); |
| 128 EXPECT_CALL(*delegate_, Logout()).Times(0); |
| 129 |
| 130 session_length_limiter_.reset(new SessionLengthLimiter(delegate_, &prefs_)); |
| 131 } |
| 132 |
| 133 void SetHasBrowserRestarted(bool has_browser_restarted) { |
| 134 EXPECT_CALL(mock_user_manager_, HasBrowserRestarted()) |
| 135 .WillRepeatedly((Return(has_browser_restarted))); |
| 136 } |
| 137 |
| 138 void SetSessionStartTimePref(int64 session_start_time) { |
| 139 prefs_.SetUserPref(prefs::kSessionStartTime, |
| 140 base::Value::CreateStringValue( |
| 141 base::Int64ToString(session_start_time))); |
| 142 } |
| 143 |
| 144 void VerifySessionStartTimePref() { |
| 145 base::Time session_start_time(base::Time::FromInternalValue( |
| 146 prefs_.GetInt64(prefs::kSessionStartTime))); |
| 147 EXPECT_EQ(session_start_time_, session_start_time); |
| 148 } |
| 149 |
| 150 void SetSessionLengthLimitPref(int64 session_length_limit) { |
| 151 prefs_.SetUserPref(prefs::kSessionLengthLimit, |
| 152 base::Value::CreateIntegerValue(session_length_limit)); |
| 153 } |
| 154 |
| 155 void UpdateRemainingTime(int64 session_length_limit) { |
| 156 if (!session_length_limit) { |
| 157 remaining_.reset(); |
| 158 return; |
| 159 } |
| 160 base::TimeDelta remaining( |
| 161 base::TimeDelta::FromMilliseconds(session_length_limit) - |
| 162 (now_ - session_start_time_)); |
| 163 if (remaining < kZeroTimeDelta) |
| 164 remaining = kZeroTimeDelta; |
| 165 remaining_.reset(new base::TimeDelta(remaining)); |
| 166 } |
| 167 |
| 168 void ExpectSessionTimeRemainingChangedCallback() { |
| 169 EXPECT_CALL(observer_, SessionTimeRemainingChanged(_)).Times(0); |
| 170 if (remaining_) { |
| 171 EXPECT_CALL(observer_, SessionTimeRemainingChanged( |
| 172 Pointee(Eq(*remaining_)))).Times(1); |
| 173 } else { |
| 174 EXPECT_CALL(observer_, SessionTimeRemainingChanged(NULL)).Times(1); |
| 175 } |
| 176 } |
| 177 |
| 178 void ExpectLogout() { |
| 179 Mock::VerifyAndClearExpectations(delegate_); |
| 180 EXPECT_CALL(*delegate_, Logout()).Times(1); |
| 181 } |
| 182 |
| 183 void VerifyTimerTickIsEnqueued() { |
| 184 ASSERT_EQ(1U, runner_->tasks().size()); |
| 185 EXPECT_EQ(kSessionLengthLimitTimerInterval, |
| 186 runner_->tasks().front().first); |
| 187 } |
| 188 |
| 189 void VerifyTimerTick() { |
| 190 ExpectSessionTimeRemainingChangedCallback(); |
| 191 runner_->RunTasks(); |
| 192 Mock::VerifyAndClearExpectations(&observer_); |
| 193 VerifyTimerTickIsEnqueued(); |
| 194 |
| 195 now_ += kSessionLengthLimitTimerInterval; |
| 196 *remaining_ -= kSessionLengthLimitTimerInterval; |
| 197 if (*remaining_ < kZeroTimeDelta) |
| 198 remaining_.reset(new base::TimeDelta(kZeroTimeDelta)); |
| 199 } |
| 200 |
| 201 base::Time GetCurrentTime() const { |
| 202 return now_; |
| 203 } |
| 204 |
| 205 UserManager* old_user_manager_; |
| 206 MockUserManager mock_user_manager_; |
| 207 scoped_refptr<ImmediateSingleThreadTaskRunner> runner_; |
| 208 TestingPrefService prefs_; |
| 209 |
| 210 MockSessionLengthLimiterObserver observer_; |
| 211 MockSessionLengthLimiterDelegate* delegate_; // Owned by |
| 212 // session_length_limiter_. |
| 213 |
| 214 base::Time now_; |
| 215 base::Time session_start_time_; |
| 216 |
| 217 scoped_ptr<SessionLengthLimiter> session_length_limiter_; |
| 218 |
| 219 base::TimeDelta session_length_limit_; |
| 220 scoped_ptr<base::TimeDelta> remaining_; |
| 221 }; |
| 222 |
| 223 // Verifies that during login, the session start time is written to prefs if no |
| 224 // session start time is present in prefs yet. |
| 225 TEST_F(SessionLengthLimiterTest, StartWithSessionStartTimeUnset) { |
| 226 SetHasBrowserRestarted(false); |
| 227 |
| 228 CreateSessionLengthLimiter(); |
| 229 VerifySessionStartTimePref(); |
| 230 } |
| 231 |
| 232 // Verifies that during login, the session start time is written to prefs if an |
| 233 // invalid value is currently present in prefs. |
| 234 TEST_F(SessionLengthLimiterTest, StartWithSessionStartTimeInvalid) { |
| 235 SetHasBrowserRestarted(false); |
| 236 |
| 237 SetSessionStartTimePref(0); |
| 238 CreateSessionLengthLimiter(); |
| 239 VerifySessionStartTimePref(); |
| 240 } |
| 241 |
| 242 // Verifies that during login, the session start time is written to prefs if a |
| 243 // value lying in the future is currently present in prefs. |
| 244 TEST_F(SessionLengthLimiterTest, StartWithSessionStartTimeFuture) { |
| 245 SetHasBrowserRestarted(false); |
| 246 |
| 247 SetSessionStartTimePref( |
| 248 (now_ + base::TimeDelta::FromHours(2)).ToInternalValue()); |
| 249 CreateSessionLengthLimiter(); |
| 250 VerifySessionStartTimePref(); |
| 251 } |
| 252 |
| 253 // Verifies that during login, the session start time is written to prefs if a |
| 254 // previously stored valid value is currently present in prefs. |
| 255 TEST_F(SessionLengthLimiterTest, StartWithSessionStartTimeValid) { |
| 256 SetHasBrowserRestarted(false); |
| 257 |
| 258 const base::Time previous_start_time = now_ - base::TimeDelta::FromHours(2); |
| 259 SetSessionStartTimePref(previous_start_time.ToInternalValue()); |
| 260 CreateSessionLengthLimiter(); |
| 261 VerifySessionStartTimePref(); |
| 262 } |
| 263 |
| 264 // Verifies that during restart after a crash, the current time is written to |
| 265 // prefs as the session start time if no session start time is present in prefs |
| 266 // yet. |
| 267 TEST_F(SessionLengthLimiterTest, RestartWithSessionStartTimeUnset) { |
| 268 SetHasBrowserRestarted(true); |
| 269 |
| 270 CreateSessionLengthLimiter(); |
| 271 VerifySessionStartTimePref(); |
| 272 } |
| 273 |
| 274 // Verifies that during restart after a crash, the current time is written to |
| 275 // prefs as the session start time if an invalid value is currently present in |
| 276 // prefs. |
| 277 TEST_F(SessionLengthLimiterTest, RestartWithSessionStartTimeInvalid) { |
| 278 SetHasBrowserRestarted(true); |
| 279 |
| 280 SetSessionStartTimePref(0); |
| 281 CreateSessionLengthLimiter(); |
| 282 VerifySessionStartTimePref(); |
| 283 } |
| 284 |
| 285 // Verifies that during restart after a crash, the current time is written to |
| 286 // prefs as the session start time if a value lying in the future is currently |
| 287 // present in prefs. |
| 288 TEST_F(SessionLengthLimiterTest, RestartWithSessionStartTimeFuture) { |
| 289 SetHasBrowserRestarted(true); |
| 290 |
| 291 SetSessionStartTimePref( |
| 292 (now_ + base::TimeDelta::FromHours(2)).ToInternalValue()); |
| 293 CreateSessionLengthLimiter(); |
| 294 VerifySessionStartTimePref(); |
| 295 } |
| 296 |
| 297 // Verifies that during restart after a crash, the current time is *not* written |
| 298 // to prefs as the session start time if a previously stored valid value is |
| 299 // currently present in prefs. |
| 300 TEST_F(SessionLengthLimiterTest, RestartWithSessionStartTimeValid) { |
| 301 SetHasBrowserRestarted(true); |
| 302 |
| 303 session_start_time_ -= base::TimeDelta::FromHours(2); |
| 304 SetSessionStartTimePref(session_start_time_.ToInternalValue()); |
| 305 CreateSessionLengthLimiter(); |
| 306 VerifySessionStartTimePref(); |
| 307 } |
| 308 |
| 309 // Creates a SessionLengthLimiter without setting a limit. Verifies that the |
| 310 // limiter does not start a timer and notifies an observer that there is no |
| 311 // limit. |
| 312 TEST_F(SessionLengthLimiterTest, RunWithoutSessionLengthLimit) { |
| 313 SetHasBrowserRestarted(false); |
| 314 |
| 315 base::ThreadTaskRunnerHandle runner_handler(runner_); |
| 316 |
| 317 // Do not set any session time limit. |
| 318 UpdateRemainingTime(0); |
| 319 |
| 320 // Create a SessionLengthLimiter and check that no timer tick has been |
| 321 // enqueued. |
| 322 CreateSessionLengthLimiter(); |
| 323 EXPECT_TRUE(runner_->tasks().empty()); |
| 324 |
| 325 // Add an observer and check that a callback is immediately received. |
| 326 ExpectSessionTimeRemainingChangedCallback(); |
| 327 session_length_limiter_->AddObserver(&observer_); |
| 328 |
| 329 session_length_limiter_->RemoveObserver(&observer_); |
| 330 } |
| 331 |
| 332 // Creates a SessionLengthLimiter after setting a limit. Verifies that the |
| 333 // limiter starts a timer and notifies an observer about the remaining time as |
| 334 // session time passes. Verifies that when the session time reaches the limit, |
| 335 // a logout occurs. |
| 336 TEST_F(SessionLengthLimiterTest, RunWithSessionLengthLimit) { |
| 337 SetHasBrowserRestarted(false); |
| 338 |
| 339 base::ThreadTaskRunnerHandle runner_handler(runner_); |
| 340 |
| 341 // Set a 60 second session time limit. |
| 342 const int session_length_limit = 60 * 1000; // 60 seconds. |
| 343 UpdateRemainingTime(session_length_limit); |
| 344 SetSessionLengthLimitPref(session_length_limit); |
| 345 |
| 346 // Create a SessionLengthLimiter and check that a first timer tick has been |
| 347 // enqueued. |
| 348 CreateSessionLengthLimiter(); |
| 349 VerifyTimerTickIsEnqueued(); |
| 350 |
| 351 // Add an observer and check that a first callback is immediately received. |
| 352 ExpectSessionTimeRemainingChangedCallback(); |
| 353 session_length_limiter_->AddObserver(&observer_); |
| 354 Mock::VerifyAndClearExpectations(&observer_); |
| 355 |
| 356 // Check timer ticks until the remaining session time reaches zero. |
| 357 while (*remaining_ > kZeroTimeDelta) |
| 358 VerifyTimerTick(); |
| 359 |
| 360 // Check that the next timer tick leads to a logout. |
| 361 ExpectLogout(); |
| 362 VerifyTimerTick(); |
| 363 |
| 364 session_length_limiter_->RemoveObserver(&observer_); |
| 365 } |
| 366 |
| 367 // Creates a SessionLengthLimiter after setting a 60 second limit, allows 50 |
| 368 // seconds of session time to pass, then increases the limit to 90 seconds. |
| 369 // Verifies that the limiter starts a timer and notifies an observer about the |
| 370 // remaining time as session time passes and the limit changes. Verifies that |
| 371 // when the session time reaches the 90 second limit, a logout occurs. |
| 372 TEST_F(SessionLengthLimiterTest, RunAndIncreaseSessionLengthLimit) { |
| 373 SetHasBrowserRestarted(false); |
| 374 |
| 375 base::ThreadTaskRunnerHandle runner_handler(runner_); |
| 376 |
| 377 // Set a 60 second session time limit. |
| 378 int session_length_limit = 60 * 1000; // 60 seconds. |
| 379 UpdateRemainingTime(session_length_limit); |
| 380 SetSessionLengthLimitPref(session_length_limit); |
| 381 |
| 382 // Create a SessionLengthLimiter and check that a first timer tick has been |
| 383 // enqueued. |
| 384 CreateSessionLengthLimiter(); |
| 385 VerifyTimerTickIsEnqueued(); |
| 386 |
| 387 // Add an observer and check that a first callback is immediately received. |
| 388 ExpectSessionTimeRemainingChangedCallback(); |
| 389 session_length_limiter_->AddObserver(&observer_); |
| 390 Mock::VerifyAndClearExpectations(&observer_); |
| 391 |
| 392 // Check timer ticks for 50 seconds of session time. |
| 393 while (*remaining_ > kTenSeconds) |
| 394 VerifyTimerTick(); |
| 395 |
| 396 // Check that increasing the session length limit to 90 seconds leads to an |
| 397 // immediate callback. |
| 398 session_length_limit = 90 * 1000; // 90 seconds. |
| 399 UpdateRemainingTime(session_length_limit); |
| 400 ExpectSessionTimeRemainingChangedCallback(); |
| 401 SetSessionLengthLimitPref(session_length_limit); |
| 402 Mock::VerifyAndClearExpectations(&observer_); |
| 403 |
| 404 // Check that a timer tick is still enqueued. |
| 405 VerifyTimerTickIsEnqueued(); |
| 406 |
| 407 // Check timer ticks until the remaining session time reaches zero. |
| 408 while (*remaining_ > kZeroTimeDelta) |
| 409 VerifyTimerTick(); |
| 410 |
| 411 // Check that the next timer tick leads to a logout. |
| 412 ExpectLogout(); |
| 413 VerifyTimerTick(); |
| 414 |
| 415 session_length_limiter_->RemoveObserver(&observer_); |
| 416 } |
| 417 |
| 418 // Creates a SessionLengthLimiter after setting a 60 second limit, allows 50 |
| 419 // seconds of session time to pass, then decreases the limit to 40 seconds. |
| 420 // Verifies that the limiter starts a timer and notifies an observer about the |
| 421 // remaining time as session time passes and the limit changes. Verifies that |
| 422 // when the limit is decreased to 40 seconds after 50 seconds of session time |
| 423 // has passed, an immediate logout occurs. |
| 424 TEST_F(SessionLengthLimiterTest, RunAndDecreaseSessionLengthLimit) { |
| 425 SetHasBrowserRestarted(false); |
| 426 |
| 427 base::ThreadTaskRunnerHandle runner_handler(runner_); |
| 428 |
| 429 // Set a 60 second session time limit. |
| 430 int session_length_limit = 60 * 1000; // 60 seconds. |
| 431 UpdateRemainingTime(session_length_limit); |
| 432 SetSessionLengthLimitPref(session_length_limit); |
| 433 |
| 434 // Create a SessionLengthLimiter and check that a first timer tick has been |
| 435 // enqueued. |
| 436 CreateSessionLengthLimiter(); |
| 437 VerifyTimerTickIsEnqueued(); |
| 438 |
| 439 // Add an observer and check that a first callback is immediately received. |
| 440 ExpectSessionTimeRemainingChangedCallback(); |
| 441 session_length_limiter_->AddObserver(&observer_); |
| 442 Mock::VerifyAndClearExpectations(&observer_); |
| 443 |
| 444 // Check timer ticks for 50 seconds of session time. |
| 445 while (*remaining_ > kTenSeconds) |
| 446 VerifyTimerTick(); |
| 447 |
| 448 // Check that reducing the session length limit below the 50 seconds that |
| 449 // have already elapsed leads to an immediate logout. |
| 450 session_length_limit = 40 * 1000; // 40 seconds. |
| 451 UpdateRemainingTime(session_length_limit); |
| 452 ExpectSessionTimeRemainingChangedCallback(); |
| 453 ExpectLogout(); |
| 454 SetSessionLengthLimitPref(session_length_limit); |
| 455 |
| 456 session_length_limiter_->RemoveObserver(&observer_); |
| 457 } |
| 458 |
| 459 // Creates a SessionLengthLimiter after setting a 60 second limit, allows 50 |
| 460 // seconds of session time to pass, then removes the limit. Verifies that the |
| 461 // limiter starts a timer and notifies an observer about the remaining time as |
| 462 // session time passes and the limit changes. Verifies that when the limit is |
| 463 // removed, no further notifications and no logout occur. |
| 464 TEST_F(SessionLengthLimiterTest, RunAndRemoveSessionLengthLimit) { |
| 465 SetHasBrowserRestarted(false); |
| 466 |
| 467 base::ThreadTaskRunnerHandle runner_handler(runner_); |
| 468 |
| 469 // Set a 60 second session time limit. |
| 470 int session_length_limit = 60 * 1000; // 60 seconds. |
| 471 UpdateRemainingTime(session_length_limit); |
| 472 SetSessionLengthLimitPref(session_length_limit); |
| 473 |
| 474 // Create a SessionLengthLimiter and check that a first timer tick has been |
| 475 // enqueued. |
| 476 CreateSessionLengthLimiter(); |
| 477 VerifyTimerTickIsEnqueued(); |
| 478 |
| 479 // Add an observer and check that a first callback is immediately received. |
| 480 ExpectSessionTimeRemainingChangedCallback(); |
| 481 session_length_limiter_->AddObserver(&observer_); |
| 482 Mock::VerifyAndClearExpectations(&observer_); |
| 483 |
| 484 // Check timer ticks for 50 seconds of session time. |
| 485 while (*remaining_ > kTenSeconds) |
| 486 VerifyTimerTick(); |
| 487 |
| 488 // Check that removing the session length limit leads to an immediate |
| 489 // callback. |
| 490 UpdateRemainingTime(0); |
| 491 ExpectSessionTimeRemainingChangedCallback(); |
| 492 prefs_.RemoveUserPref(prefs::kSessionLengthLimit); |
| 493 Mock::VerifyAndClearExpectations(&observer_); |
| 494 |
| 495 // Check that the next timer tick does not lead to a callback or logout. |
| 496 EXPECT_CALL(observer_, SessionTimeRemainingChanged(_)).Times(0); |
| 497 now_ += kSessionLengthLimitTimerInterval; |
| 498 runner_->RunTasks(); |
| 499 |
| 500 session_length_limiter_->RemoveObserver(&observer_); |
| 501 } |
| 502 |
| 503 } // namespace chromeos |
| OLD | NEW |