| // Copyright 2018 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 "components/sessions/core/session_id_generator.h" |
| |
| #include <limits> |
| |
| #include "base/macros.h" |
| #include "base/test/mock_callback.h" |
| #include "components/prefs/testing_pref_service.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| |
| namespace sessions { |
| namespace { |
| |
| using testing::Return; |
| |
| const int kExpectedIdPadding = 50; |
| |
| class SessionIdGeneratorTest : public testing::Test { |
| protected: |
| SessionIdGeneratorTest() { |
| // Call Shutdown() in case other tests outside this file have forgotten to |
| // do so, which would leak undesired state across tests. |
| SessionIdGenerator::GetInstance()->Shutdown(); |
| SessionIdGenerator::RegisterPrefs(prefs_.registry()); |
| } |
| |
| ~SessionIdGeneratorTest() override { |
| SessionIdGenerator::GetInstance()->Shutdown(); |
| } |
| |
| void WriteLastValueToPrefs(int64_t value) { |
| prefs_.SetInt64(SessionIdGenerator::GetLastValuePrefNameForTest(), value); |
| } |
| |
| int64_t ReadLastValueFromPrefs() { |
| return prefs_.GetInt64(SessionIdGenerator::GetLastValuePrefNameForTest()); |
| } |
| |
| TestingPrefServiceSimple prefs_; |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(SessionIdGeneratorTest); |
| }; |
| |
| TEST_F(SessionIdGeneratorTest, ShouldGenerateContiguousIds) { |
| SessionIdGenerator* generator = SessionIdGenerator::GetInstance(); |
| generator->Init(&prefs_); |
| SessionID session_id1 = generator->NewUnique(); |
| SessionID session_id2 = generator->NewUnique(); |
| SessionID session_id3 = generator->NewUnique(); |
| EXPECT_EQ(session_id2.id(), session_id1.id() + 1); |
| EXPECT_EQ(session_id3.id(), session_id2.id() + 1); |
| EXPECT_EQ(session_id3.id(), ReadLastValueFromPrefs()); |
| } |
| |
| TEST_F(SessionIdGeneratorTest, ShouldInitializeWithRandomValue) { |
| base::MockCallback<SessionIdGenerator::RandomGenerator> random_generator; |
| SessionIdGenerator* generator = SessionIdGenerator::GetInstance(); |
| generator->SetRandomGeneratorForTest(random_generator.Get()); |
| |
| EXPECT_CALL(random_generator, Run()).WillOnce(Return(123)); |
| generator->Init(&prefs_); |
| EXPECT_EQ(123 + 1 + kExpectedIdPadding, generator->NewUnique().id()); |
| |
| // Mimic a browser restart with cleared prefs. |
| generator->Shutdown(); |
| WriteLastValueToPrefs(-1); |
| EXPECT_CALL(random_generator, Run()).WillOnce(Return(19)); |
| generator->Init(&prefs_); |
| |
| EXPECT_EQ(19 + 1 + kExpectedIdPadding, generator->NewUnique().id()); |
| } |
| |
| TEST_F(SessionIdGeneratorTest, ShouldCornerCasesInRandomFunc) { |
| base::MockCallback<SessionIdGenerator::RandomGenerator> random_generator; |
| SessionIdGenerator* generator = SessionIdGenerator::GetInstance(); |
| generator->SetRandomGeneratorForTest(random_generator.Get()); |
| |
| // Exercise smallest value in range. |
| EXPECT_CALL(random_generator, Run()).WillOnce(Return(0)); |
| generator->Init(&prefs_); |
| EXPECT_EQ(0 + 1 + kExpectedIdPadding, generator->NewUnique().id()); |
| |
| // Exercise maximum value in range. |
| generator->Shutdown(); |
| WriteLastValueToPrefs(-1); |
| EXPECT_CALL(random_generator, Run()) |
| .WillOnce(Return(std::numeric_limits<SessionID::id_type>::max())); |
| generator->Init(&prefs_); |
| EXPECT_EQ(1 + kExpectedIdPadding, generator->NewUnique().id()); |
| |
| // Exercise maximum value minus one in range. |
| generator->Shutdown(); |
| WriteLastValueToPrefs(-1); |
| EXPECT_CALL(random_generator, Run()) |
| .WillOnce(Return(std::numeric_limits<SessionID::id_type>::max() - 1)); |
| generator->Init(&prefs_); |
| EXPECT_EQ(1 + kExpectedIdPadding, generator->NewUnique().id()); |
| |
| // Exercise a random value which is exactly |kExpectedIdPadding| less than |
| // the maximum value in the range. |
| generator->Shutdown(); |
| WriteLastValueToPrefs(-1); |
| EXPECT_CALL(random_generator, Run()) |
| .WillOnce(Return(std::numeric_limits<SessionID::id_type>::max() - |
| kExpectedIdPadding)); |
| generator->Init(&prefs_); |
| EXPECT_EQ(1, generator->NewUnique().id()); |
| |
| // Exercise a random value which is |kExpectedIdPadding-1| less than the |
| // maximum value in the range (no overflow expected). |
| generator->Shutdown(); |
| WriteLastValueToPrefs(-1); |
| EXPECT_CALL(random_generator, Run()) |
| .WillOnce(Return(std::numeric_limits<SessionID::id_type>::max() - |
| kExpectedIdPadding - 1)); |
| generator->Init(&prefs_); |
| EXPECT_EQ(std::numeric_limits<SessionID::id_type>::max(), |
| generator->NewUnique().id()); |
| } |
| |
| TEST_F(SessionIdGeneratorTest, ShouldRestoreAndPadLastValueFromPrefs) { |
| WriteLastValueToPrefs(7); |
| SessionIdGenerator* generator = SessionIdGenerator::GetInstance(); |
| generator->Init(&prefs_); |
| SessionID session_id = generator->NewUnique(); |
| EXPECT_EQ(8 + kExpectedIdPadding, session_id.id()); |
| EXPECT_EQ(8 + kExpectedIdPadding, ReadLastValueFromPrefs()); |
| } |
| |
| TEST_F(SessionIdGeneratorTest, ShouldHandleOverflowDuringGeneration) { |
| WriteLastValueToPrefs(std::numeric_limits<SessionID::id_type>::max() - |
| kExpectedIdPadding - 3); |
| SessionIdGenerator* generator = SessionIdGenerator::GetInstance(); |
| generator->Init(&prefs_); |
| ASSERT_EQ(std::numeric_limits<SessionID::id_type>::max() - 2, |
| generator->NewUnique().id()); |
| EXPECT_EQ(std::numeric_limits<SessionID::id_type>::max() - 1, |
| generator->NewUnique().id()); |
| EXPECT_EQ(std::numeric_limits<SessionID::id_type>::max(), |
| generator->NewUnique().id()); |
| EXPECT_EQ(1, generator->NewUnique().id()); |
| } |
| |
| TEST_F(SessionIdGeneratorTest, ShouldHandleOverflowDuringPadding) { |
| WriteLastValueToPrefs(std::numeric_limits<SessionID::id_type>::max() - 2); |
| SessionIdGenerator* generator = SessionIdGenerator::GetInstance(); |
| generator->Init(&prefs_); |
| EXPECT_EQ(kExpectedIdPadding + 1, generator->NewUnique().id()); |
| } |
| |
| // Verifies correctness of the test-only codepath. |
| TEST(SessionIdGeneratorWithoutInitTest, ShouldStartFromOneAndIncrement) { |
| SessionIdGenerator* generator = SessionIdGenerator::GetInstance(); |
| EXPECT_EQ(1, generator->NewUnique().id()); |
| EXPECT_EQ(2, generator->NewUnique().id()); |
| generator->Shutdown(); |
| } |
| |
| } // namespace |
| } // namespace sessions |