| Index: chrome/browser/chromeos/session_length_limiter_unittest.cc
|
| diff --git a/chrome/browser/chromeos/session_length_limiter_unittest.cc b/chrome/browser/chromeos/session_length_limiter_unittest.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..20a28b643c2151e78654a7c07a4709f7eb0d1547
|
| --- /dev/null
|
| +++ b/chrome/browser/chromeos/session_length_limiter_unittest.cc
|
| @@ -0,0 +1,503 @@
|
| +// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "chrome/browser/chromeos/session_length_limiter.h"
|
| +
|
| +#include <deque>
|
| +#include <utility>
|
| +
|
| +#include "base/basictypes.h"
|
| +#include "base/compiler_specific.h"
|
| +#include "base/location.h"
|
| +#include "base/logging.h"
|
| +#include "base/memory/ref_counted.h"
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "base/single_thread_task_runner.h"
|
| +#include "base/string_number_conversions.h"
|
| +#include "base/thread_task_runner_handle.h"
|
| +#include "base/time.h"
|
| +#include "chrome/browser/chromeos/login/mock_user_manager.h"
|
| +#include "chrome/browser/chromeos/login/user_manager.h"
|
| +#include "chrome/browser/chromeos/session_length_limiter_factory.h"
|
| +#include "chrome/common/pref_names.h"
|
| +#include "chrome/test/base/testing_pref_service.h"
|
| +#include "testing/gmock/include/gmock/gmock.h"
|
| +#include "testing/gtest/include/gtest/gtest.h"
|
| +
|
| +using ::testing::_;
|
| +using ::testing::Eq;
|
| +using ::testing::Invoke;
|
| +using ::testing::Mock;
|
| +using ::testing::NiceMock;
|
| +using ::testing::Pointee;
|
| +using ::testing::Return;
|
| +
|
| +namespace chromeos {
|
| +
|
| +namespace {
|
| +
|
| +// The interval at which the SessionLengthLimiter fires periodic callbacks.
|
| +const base::TimeDelta kSessionLengthLimitTimerInterval(
|
| + base::TimeDelta::FromSeconds(1));
|
| +
|
| +const base::TimeDelta kZeroTimeDelta;
|
| +const base::TimeDelta kTenSeconds(base::TimeDelta::FromSeconds(10));
|
| +
|
| +class MockSessionLengthLimiterObserver : public SessionLengthLimiter::Observer {
|
| + public:
|
| + MOCK_METHOD1(SessionTimeRemainingChanged, void(const base::TimeDelta*));
|
| +};
|
| +
|
| +class MockSessionLengthLimiterDelegate : public SessionLengthLimiter::Delegate {
|
| + public:
|
| + MOCK_CONST_METHOD0(GetCurrentTime, const base::Time(void));
|
| + MOCK_METHOD0(Logout, void(void));
|
| +};
|
| +
|
| +// A SingleThreadTaskRunner that allows the task queue to be inspected and
|
| +// delayed tasks to be run without waiting for the actual delays to expire.
|
| +class ImmediateSingleThreadTaskRunner : public base::SingleThreadTaskRunner {
|
| + public:
|
| + virtual bool RunsTasksOnCurrentThread() const {
|
| + return true;
|
| + }
|
| +
|
| + virtual bool PostDelayedTask(const tracked_objects::Location& from_here,
|
| + const base::Closure& task,
|
| + base::TimeDelta delay) OVERRIDE {
|
| + tasks_.push_back(std::pair<base::TimeDelta, base::Closure>(delay, task));
|
| + return true;
|
| + }
|
| +
|
| + virtual bool PostNonNestableDelayedTask(
|
| + const tracked_objects::Location& from_here,
|
| + const base::Closure& task,
|
| + base::TimeDelta delay) OVERRIDE {
|
| + NOTREACHED();
|
| + return false;
|
| + }
|
| +
|
| + void RunTasks() {
|
| + std::deque<std::pair<base::TimeDelta, base::Closure> > tasks;
|
| + tasks.swap(tasks_);
|
| + for (std::deque<std::pair<base::TimeDelta, base::Closure> >::iterator
|
| + it = tasks.begin(); it != tasks.end(); ++it) {
|
| + it->second.Run();
|
| + }
|
| + }
|
| +
|
| + const std::deque<std::pair<base::TimeDelta, base::Closure> >& tasks() const {
|
| + return tasks_;
|
| + }
|
| +
|
| + private:
|
| + std::deque<std::pair<base::TimeDelta, base::Closure> > tasks_;
|
| +
|
| + virtual ~ImmediateSingleThreadTaskRunner() {}
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +class SessionLengthLimiterTest : public testing::Test {
|
| + protected:
|
| + SessionLengthLimiterTest() : delegate_(NULL) {
|
| + }
|
| +
|
| + virtual void SetUp() {
|
| + old_user_manager_ = UserManager::Set(&mock_user_manager_);
|
| + runner_ = new ImmediateSingleThreadTaskRunner;
|
| +
|
| + // Initialize the mock clock to a fixed value, ensuring that timezone
|
| + // differences or DST changes do not affect the test.
|
| + now_ = base::Time::UnixEpoch() + base::TimeDelta::FromDays(40 * 365);
|
| + session_start_time_ = now_;
|
| +
|
| + SessionLengthLimiterFactory::GetInstance()->RegisterUserPrefs(&prefs_);
|
| + }
|
| +
|
| + virtual void TearDown() {
|
| + session_length_limiter_->Shutdown();
|
| + UserManager::Set(old_user_manager_);
|
| + }
|
| +
|
| + void CreateSessionLengthLimiter() {
|
| + delegate_ = new NiceMock<MockSessionLengthLimiterDelegate>;
|
| + ON_CALL(*delegate_, GetCurrentTime())
|
| + .WillByDefault(Invoke(this, &SessionLengthLimiterTest::GetCurrentTime));
|
| + EXPECT_CALL(*delegate_, Logout()).Times(0);
|
| +
|
| + session_length_limiter_.reset(new SessionLengthLimiter(delegate_, &prefs_));
|
| + }
|
| +
|
| + void SetHasBrowserRestarted(bool has_browser_restarted) {
|
| + EXPECT_CALL(mock_user_manager_, HasBrowserRestarted())
|
| + .WillRepeatedly((Return(has_browser_restarted)));
|
| + }
|
| +
|
| + void SetSessionStartTimePref(int64 session_start_time) {
|
| + prefs_.SetUserPref(prefs::kSessionStartTime,
|
| + base::Value::CreateStringValue(
|
| + base::Int64ToString(session_start_time)));
|
| + }
|
| +
|
| + void VerifySessionStartTimePref() {
|
| + base::Time session_start_time(base::Time::FromInternalValue(
|
| + prefs_.GetInt64(prefs::kSessionStartTime)));
|
| + EXPECT_EQ(session_start_time_, session_start_time);
|
| + }
|
| +
|
| + void SetSessionLengthLimitPref(int64 session_length_limit) {
|
| + prefs_.SetUserPref(prefs::kSessionLengthLimit,
|
| + base::Value::CreateIntegerValue(session_length_limit));
|
| + }
|
| +
|
| + void UpdateRemainingTime(int64 session_length_limit) {
|
| + if (!session_length_limit) {
|
| + remaining_.reset();
|
| + return;
|
| + }
|
| + base::TimeDelta remaining(
|
| + base::TimeDelta::FromMilliseconds(session_length_limit) -
|
| + (now_ - session_start_time_));
|
| + if (remaining < kZeroTimeDelta)
|
| + remaining = kZeroTimeDelta;
|
| + remaining_.reset(new base::TimeDelta(remaining));
|
| + }
|
| +
|
| + void ExpectSessionTimeRemainingChangedCallback() {
|
| + EXPECT_CALL(observer_, SessionTimeRemainingChanged(_)).Times(0);
|
| + if (remaining_) {
|
| + EXPECT_CALL(observer_, SessionTimeRemainingChanged(
|
| + Pointee(Eq(*remaining_)))).Times(1);
|
| + } else {
|
| + EXPECT_CALL(observer_, SessionTimeRemainingChanged(NULL)).Times(1);
|
| + }
|
| + }
|
| +
|
| + void ExpectLogout() {
|
| + Mock::VerifyAndClearExpectations(delegate_);
|
| + EXPECT_CALL(*delegate_, Logout()).Times(1);
|
| + }
|
| +
|
| + void VerifyTimerTickIsEnqueued() {
|
| + ASSERT_EQ(1U, runner_->tasks().size());
|
| + EXPECT_EQ(kSessionLengthLimitTimerInterval,
|
| + runner_->tasks().front().first);
|
| + }
|
| +
|
| + void VerifyTimerTick() {
|
| + ExpectSessionTimeRemainingChangedCallback();
|
| + runner_->RunTasks();
|
| + Mock::VerifyAndClearExpectations(&observer_);
|
| + VerifyTimerTickIsEnqueued();
|
| +
|
| + now_ += kSessionLengthLimitTimerInterval;
|
| + *remaining_ -= kSessionLengthLimitTimerInterval;
|
| + if (*remaining_ < kZeroTimeDelta)
|
| + remaining_.reset(new base::TimeDelta(kZeroTimeDelta));
|
| + }
|
| +
|
| + base::Time GetCurrentTime() const {
|
| + return now_;
|
| + }
|
| +
|
| + UserManager* old_user_manager_;
|
| + MockUserManager mock_user_manager_;
|
| + scoped_refptr<ImmediateSingleThreadTaskRunner> runner_;
|
| + TestingPrefService prefs_;
|
| +
|
| + MockSessionLengthLimiterObserver observer_;
|
| + MockSessionLengthLimiterDelegate* delegate_; // Owned by
|
| + // session_length_limiter_.
|
| +
|
| + base::Time now_;
|
| + base::Time session_start_time_;
|
| +
|
| + scoped_ptr<SessionLengthLimiter> session_length_limiter_;
|
| +
|
| + base::TimeDelta session_length_limit_;
|
| + scoped_ptr<base::TimeDelta> remaining_;
|
| +};
|
| +
|
| +// Verifies that during login, the session start time is written to prefs if no
|
| +// session start time is present in prefs yet.
|
| +TEST_F(SessionLengthLimiterTest, StartWithSessionStartTimeUnset) {
|
| + SetHasBrowserRestarted(false);
|
| +
|
| + CreateSessionLengthLimiter();
|
| + VerifySessionStartTimePref();
|
| +}
|
| +
|
| +// Verifies that during login, the session start time is written to prefs if an
|
| +// invalid value is currently present in prefs.
|
| +TEST_F(SessionLengthLimiterTest, StartWithSessionStartTimeInvalid) {
|
| + SetHasBrowserRestarted(false);
|
| +
|
| + SetSessionStartTimePref(0);
|
| + CreateSessionLengthLimiter();
|
| + VerifySessionStartTimePref();
|
| +}
|
| +
|
| +// Verifies that during login, the session start time is written to prefs if a
|
| +// value lying in the future is currently present in prefs.
|
| +TEST_F(SessionLengthLimiterTest, StartWithSessionStartTimeFuture) {
|
| + SetHasBrowserRestarted(false);
|
| +
|
| + SetSessionStartTimePref(
|
| + (now_ + base::TimeDelta::FromHours(2)).ToInternalValue());
|
| + CreateSessionLengthLimiter();
|
| + VerifySessionStartTimePref();
|
| +}
|
| +
|
| +// Verifies that during login, the session start time is written to prefs if a
|
| +// previously stored valid value is currently present in prefs.
|
| +TEST_F(SessionLengthLimiterTest, StartWithSessionStartTimeValid) {
|
| + SetHasBrowserRestarted(false);
|
| +
|
| + const base::Time previous_start_time = now_ - base::TimeDelta::FromHours(2);
|
| + SetSessionStartTimePref(previous_start_time.ToInternalValue());
|
| + CreateSessionLengthLimiter();
|
| + VerifySessionStartTimePref();
|
| +}
|
| +
|
| +// Verifies that during restart after a crash, the current time is written to
|
| +// prefs as the session start time if no session start time is present in prefs
|
| +// yet.
|
| +TEST_F(SessionLengthLimiterTest, RestartWithSessionStartTimeUnset) {
|
| + SetHasBrowserRestarted(true);
|
| +
|
| + CreateSessionLengthLimiter();
|
| + VerifySessionStartTimePref();
|
| +}
|
| +
|
| +// Verifies that during restart after a crash, the current time is written to
|
| +// prefs as the session start time if an invalid value is currently present in
|
| +// prefs.
|
| +TEST_F(SessionLengthLimiterTest, RestartWithSessionStartTimeInvalid) {
|
| + SetHasBrowserRestarted(true);
|
| +
|
| + SetSessionStartTimePref(0);
|
| + CreateSessionLengthLimiter();
|
| + VerifySessionStartTimePref();
|
| +}
|
| +
|
| +// Verifies that during restart after a crash, the current time is written to
|
| +// prefs as the session start time if a value lying in the future is currently
|
| +// present in prefs.
|
| +TEST_F(SessionLengthLimiterTest, RestartWithSessionStartTimeFuture) {
|
| + SetHasBrowserRestarted(true);
|
| +
|
| + SetSessionStartTimePref(
|
| + (now_ + base::TimeDelta::FromHours(2)).ToInternalValue());
|
| + CreateSessionLengthLimiter();
|
| + VerifySessionStartTimePref();
|
| +}
|
| +
|
| +// Verifies that during restart after a crash, the current time is *not* written
|
| +// to prefs as the session start time if a previously stored valid value is
|
| +// currently present in prefs.
|
| +TEST_F(SessionLengthLimiterTest, RestartWithSessionStartTimeValid) {
|
| + SetHasBrowserRestarted(true);
|
| +
|
| + session_start_time_ -= base::TimeDelta::FromHours(2);
|
| + SetSessionStartTimePref(session_start_time_.ToInternalValue());
|
| + CreateSessionLengthLimiter();
|
| + VerifySessionStartTimePref();
|
| +}
|
| +
|
| +// Creates a SessionLengthLimiter without setting a limit. Verifies that the
|
| +// limiter does not start a timer and notifies an observer that there is no
|
| +// limit.
|
| +TEST_F(SessionLengthLimiterTest, RunWithoutSessionLengthLimit) {
|
| + SetHasBrowserRestarted(false);
|
| +
|
| + base::ThreadTaskRunnerHandle runner_handler(runner_);
|
| +
|
| + // Do not set any session time limit.
|
| + UpdateRemainingTime(0);
|
| +
|
| + // Create a SessionLengthLimiter and check that no timer tick has been
|
| + // enqueued.
|
| + CreateSessionLengthLimiter();
|
| + EXPECT_TRUE(runner_->tasks().empty());
|
| +
|
| + // Add an observer and check that a callback is immediately received.
|
| + ExpectSessionTimeRemainingChangedCallback();
|
| + session_length_limiter_->AddObserver(&observer_);
|
| +
|
| + session_length_limiter_->RemoveObserver(&observer_);
|
| +}
|
| +
|
| +// Creates a SessionLengthLimiter after setting a limit. Verifies that the
|
| +// limiter starts a timer and notifies an observer about the remaining time as
|
| +// session time passes. Verifies that when the session time reaches the limit,
|
| +// a logout occurs.
|
| +TEST_F(SessionLengthLimiterTest, RunWithSessionLengthLimit) {
|
| + SetHasBrowserRestarted(false);
|
| +
|
| + base::ThreadTaskRunnerHandle runner_handler(runner_);
|
| +
|
| + // Set a 60 second session time limit.
|
| + const int session_length_limit = 60 * 1000; // 60 seconds.
|
| + UpdateRemainingTime(session_length_limit);
|
| + SetSessionLengthLimitPref(session_length_limit);
|
| +
|
| + // Create a SessionLengthLimiter and check that a first timer tick has been
|
| + // enqueued.
|
| + CreateSessionLengthLimiter();
|
| + VerifyTimerTickIsEnqueued();
|
| +
|
| + // Add an observer and check that a first callback is immediately received.
|
| + ExpectSessionTimeRemainingChangedCallback();
|
| + session_length_limiter_->AddObserver(&observer_);
|
| + Mock::VerifyAndClearExpectations(&observer_);
|
| +
|
| + // Check timer ticks until the remaining session time reaches zero.
|
| + while (*remaining_ > kZeroTimeDelta)
|
| + VerifyTimerTick();
|
| +
|
| + // Check that the next timer tick leads to a logout.
|
| + ExpectLogout();
|
| + VerifyTimerTick();
|
| +
|
| + session_length_limiter_->RemoveObserver(&observer_);
|
| +}
|
| +
|
| +// Creates a SessionLengthLimiter after setting a 60 second limit, allows 50
|
| +// seconds of session time to pass, then increases the limit to 90 seconds.
|
| +// Verifies that the limiter starts a timer and notifies an observer about the
|
| +// remaining time as session time passes and the limit changes. Verifies that
|
| +// when the session time reaches the 90 second limit, a logout occurs.
|
| +TEST_F(SessionLengthLimiterTest, RunAndIncreaseSessionLengthLimit) {
|
| + SetHasBrowserRestarted(false);
|
| +
|
| + base::ThreadTaskRunnerHandle runner_handler(runner_);
|
| +
|
| + // Set a 60 second session time limit.
|
| + int session_length_limit = 60 * 1000; // 60 seconds.
|
| + UpdateRemainingTime(session_length_limit);
|
| + SetSessionLengthLimitPref(session_length_limit);
|
| +
|
| + // Create a SessionLengthLimiter and check that a first timer tick has been
|
| + // enqueued.
|
| + CreateSessionLengthLimiter();
|
| + VerifyTimerTickIsEnqueued();
|
| +
|
| + // Add an observer and check that a first callback is immediately received.
|
| + ExpectSessionTimeRemainingChangedCallback();
|
| + session_length_limiter_->AddObserver(&observer_);
|
| + Mock::VerifyAndClearExpectations(&observer_);
|
| +
|
| + // Check timer ticks for 50 seconds of session time.
|
| + while (*remaining_ > kTenSeconds)
|
| + VerifyTimerTick();
|
| +
|
| + // Check that increasing the session length limit to 90 seconds leads to an
|
| + // immediate callback.
|
| + session_length_limit = 90 * 1000; // 90 seconds.
|
| + UpdateRemainingTime(session_length_limit);
|
| + ExpectSessionTimeRemainingChangedCallback();
|
| + SetSessionLengthLimitPref(session_length_limit);
|
| + Mock::VerifyAndClearExpectations(&observer_);
|
| +
|
| + // Check that a timer tick is still enqueued.
|
| + VerifyTimerTickIsEnqueued();
|
| +
|
| + // Check timer ticks until the remaining session time reaches zero.
|
| + while (*remaining_ > kZeroTimeDelta)
|
| + VerifyTimerTick();
|
| +
|
| + // Check that the next timer tick leads to a logout.
|
| + ExpectLogout();
|
| + VerifyTimerTick();
|
| +
|
| + session_length_limiter_->RemoveObserver(&observer_);
|
| +}
|
| +
|
| +// Creates a SessionLengthLimiter after setting a 60 second limit, allows 50
|
| +// seconds of session time to pass, then decreases the limit to 40 seconds.
|
| +// Verifies that the limiter starts a timer and notifies an observer about the
|
| +// remaining time as session time passes and the limit changes. Verifies that
|
| +// when the limit is decreased to 40 seconds after 50 seconds of session time
|
| +// has passed, an immediate logout occurs.
|
| +TEST_F(SessionLengthLimiterTest, RunAndDecreaseSessionLengthLimit) {
|
| + SetHasBrowserRestarted(false);
|
| +
|
| + base::ThreadTaskRunnerHandle runner_handler(runner_);
|
| +
|
| + // Set a 60 second session time limit.
|
| + int session_length_limit = 60 * 1000; // 60 seconds.
|
| + UpdateRemainingTime(session_length_limit);
|
| + SetSessionLengthLimitPref(session_length_limit);
|
| +
|
| + // Create a SessionLengthLimiter and check that a first timer tick has been
|
| + // enqueued.
|
| + CreateSessionLengthLimiter();
|
| + VerifyTimerTickIsEnqueued();
|
| +
|
| + // Add an observer and check that a first callback is immediately received.
|
| + ExpectSessionTimeRemainingChangedCallback();
|
| + session_length_limiter_->AddObserver(&observer_);
|
| + Mock::VerifyAndClearExpectations(&observer_);
|
| +
|
| + // Check timer ticks for 50 seconds of session time.
|
| + while (*remaining_ > kTenSeconds)
|
| + VerifyTimerTick();
|
| +
|
| + // Check that reducing the session length limit below the 50 seconds that
|
| + // have already elapsed leads to an immediate logout.
|
| + session_length_limit = 40 * 1000; // 40 seconds.
|
| + UpdateRemainingTime(session_length_limit);
|
| + ExpectSessionTimeRemainingChangedCallback();
|
| + ExpectLogout();
|
| + SetSessionLengthLimitPref(session_length_limit);
|
| +
|
| + session_length_limiter_->RemoveObserver(&observer_);
|
| +}
|
| +
|
| +// Creates a SessionLengthLimiter after setting a 60 second limit, allows 50
|
| +// seconds of session time to pass, then removes the limit. Verifies that the
|
| +// limiter starts a timer and notifies an observer about the remaining time as
|
| +// session time passes and the limit changes. Verifies that when the limit is
|
| +// removed, no further notifications and no logout occur.
|
| +TEST_F(SessionLengthLimiterTest, RunAndRemoveSessionLengthLimit) {
|
| + SetHasBrowserRestarted(false);
|
| +
|
| + base::ThreadTaskRunnerHandle runner_handler(runner_);
|
| +
|
| + // Set a 60 second session time limit.
|
| + int session_length_limit = 60 * 1000; // 60 seconds.
|
| + UpdateRemainingTime(session_length_limit);
|
| + SetSessionLengthLimitPref(session_length_limit);
|
| +
|
| + // Create a SessionLengthLimiter and check that a first timer tick has been
|
| + // enqueued.
|
| + CreateSessionLengthLimiter();
|
| + VerifyTimerTickIsEnqueued();
|
| +
|
| + // Add an observer and check that a first callback is immediately received.
|
| + ExpectSessionTimeRemainingChangedCallback();
|
| + session_length_limiter_->AddObserver(&observer_);
|
| + Mock::VerifyAndClearExpectations(&observer_);
|
| +
|
| + // Check timer ticks for 50 seconds of session time.
|
| + while (*remaining_ > kTenSeconds)
|
| + VerifyTimerTick();
|
| +
|
| + // Check that removing the session length limit leads to an immediate
|
| + // callback.
|
| + UpdateRemainingTime(0);
|
| + ExpectSessionTimeRemainingChangedCallback();
|
| + prefs_.RemoveUserPref(prefs::kSessionLengthLimit);
|
| + Mock::VerifyAndClearExpectations(&observer_);
|
| +
|
| + // Check that the next timer tick does not lead to a callback or logout.
|
| + EXPECT_CALL(observer_, SessionTimeRemainingChanged(_)).Times(0);
|
| + now_ += kSessionLengthLimitTimerInterval;
|
| + runner_->RunTasks();
|
| +
|
| + session_length_limiter_->RemoveObserver(&observer_);
|
| +}
|
| +
|
| +} // namespace chromeos
|
|
|