chromium/extensions/browser/api/feedback_private/access_rate_limiter_chromeos_unittest.cc

// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "extensions/browser/api/feedback_private/access_rate_limiter.h"

#include <memory>

#include "base/test/simple_test_tick_clock.h"
#include "base/time/time.h"
#include "testing/gtest/include/gtest/gtest.h"

class AccessRateLimiterTest : public ::testing::Test {
 public:
  AccessRateLimiterTest() {
    // |test_clock_| must start out at something other than 0, which is
    // interpreted as an invalid value.
    test_clock_.Advance(base::Milliseconds(100));
  }

  AccessRateLimiterTest(const AccessRateLimiterTest&) = delete;
  AccessRateLimiterTest& operator=(const AccessRateLimiterTest&) = delete;

  ~AccessRateLimiterTest() override = default;

 protected:
  // For manually testing time-sensitive behavior.
  base::SimpleTestTickClock test_clock_;

  // Unit under test.
  std::unique_ptr<extensions::AccessRateLimiter> limiter_;
};

TEST_F(AccessRateLimiterTest, MaxAccessCountOfZero) {
  limiter_ = std::make_unique<extensions::AccessRateLimiter>(
      0, base::Milliseconds(100), &test_clock_);

  EXPECT_FALSE(limiter_->AttemptAccess());
  EXPECT_FALSE(limiter_->AttemptAccess());
  EXPECT_FALSE(limiter_->AttemptAccess());
  EXPECT_FALSE(limiter_->AttemptAccess());
  EXPECT_FALSE(limiter_->AttemptAccess());
}

TEST_F(AccessRateLimiterTest, NormalRepeatedAccess) {
  limiter_ = std::make_unique<extensions::AccessRateLimiter>(
      5, base::Milliseconds(100), &test_clock_);

  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_FALSE(limiter_->AttemptAccess());
  EXPECT_FALSE(limiter_->AttemptAccess());
  EXPECT_FALSE(limiter_->AttemptAccess());
  EXPECT_FALSE(limiter_->AttemptAccess());
  EXPECT_FALSE(limiter_->AttemptAccess());
}

TEST_F(AccessRateLimiterTest, RechargeWhenDry) {
  limiter_ = std::make_unique<extensions::AccessRateLimiter>(
      5, base::Milliseconds(100), &test_clock_);

  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_FALSE(limiter_->AttemptAccess());

  test_clock_.Advance(base::Milliseconds(100));
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_FALSE(limiter_->AttemptAccess());

  test_clock_.Advance(base::Milliseconds(500));
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_FALSE(limiter_->AttemptAccess());
}

TEST_F(AccessRateLimiterTest, RechargeTimeOfZero) {
  limiter_ = std::make_unique<extensions::AccessRateLimiter>(
      5, base::Milliseconds(0), &test_clock_);

  // Unlimited number of accesses.
  for (int i = 0; i < 100; ++i)
    EXPECT_TRUE(limiter_->AttemptAccess()) << i;

  // Advancing should not make a difference.
  test_clock_.Advance(base::Milliseconds(100));
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());

  test_clock_.Advance(base::Milliseconds(500));
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
}

TEST_F(AccessRateLimiterTest, RechargeToMax) {
  limiter_ = std::make_unique<extensions::AccessRateLimiter>(
      5, base::Milliseconds(100), &test_clock_);

  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_FALSE(limiter_->AttemptAccess());

  // Should not exceed the max number of accesses.
  test_clock_.Advance(base::Milliseconds(1000));
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_FALSE(limiter_->AttemptAccess());
}

TEST_F(AccessRateLimiterTest, IncrementalRecharge) {
  limiter_ = std::make_unique<extensions::AccessRateLimiter>(
      5, base::Milliseconds(100), &test_clock_);

  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_FALSE(limiter_->AttemptAccess());

  // Has not yet hit the full recharge period.
  test_clock_.Advance(base::Milliseconds(50));
  EXPECT_FALSE(limiter_->AttemptAccess());

  // Has finally hit the full recharge period.
  test_clock_.Advance(base::Milliseconds(50));
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_FALSE(limiter_->AttemptAccess());

  // This only recharges two full periods.
  test_clock_.Advance(base::Milliseconds(250));
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_FALSE(limiter_->AttemptAccess());

  // This finishes recharging three full periods.
  test_clock_.Advance(base::Milliseconds(250));
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_FALSE(limiter_->AttemptAccess());
}

TEST_F(AccessRateLimiterTest, IncrementalRechargeToMax) {
  limiter_ = std::make_unique<extensions::AccessRateLimiter>(
      5, base::Milliseconds(100), &test_clock_);

  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_FALSE(limiter_->AttemptAccess());

  // This only recharges two full periods.
  test_clock_.Advance(base::Milliseconds(250));
  // This finishes recharging three full periods, but will not recharge over the
  // additional periods.
  test_clock_.Advance(base::Milliseconds(450));
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_TRUE(limiter_->AttemptAccess());
  EXPECT_FALSE(limiter_->AttemptAccess());
  EXPECT_FALSE(limiter_->AttemptAccess());
}