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