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