proxygen
RateLimiterTest.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2017-present Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <chrono>
18 #include <condition_variable>
19 #include <mutex>
20 #include <string>
21 #include <thread>
22 
23 #include <folly/Conv.h>
26 
28 using std::chrono::duration_cast;
29 using namespace std::literals::chrono_literals;
30 
31 using irl_clock = IntervalRateLimiter::clock;
32 
33 void intervalTest(uint64_t eventsPerInterval, irl_clock::duration interval) {
34  SCOPED_TRACE(folly::to<std::string>(
35  eventsPerInterval,
36  " events every ",
37  duration_cast<std::chrono::milliseconds>(interval).count(),
38  "ms"));
39  IntervalRateLimiter limiter{eventsPerInterval, interval};
40  for (int iter = 0; iter < 4; ++iter) {
41  if (iter != 0) {
42  auto now = irl_clock::now();
43  auto const deadline = now + interval;
44  while (now < deadline) {
45  /* sleep override */
46  std::this_thread::sleep_for(now - deadline);
47  now = irl_clock::now();
48  }
49  }
50  for (uint64_t n = 0; n < eventsPerInterval * 2; ++n) {
51  if (n < eventsPerInterval) {
52  EXPECT_TRUE(limiter.check())
53  << "expected check success on loop " << iter << " event " << n;
54  } else {
55  EXPECT_FALSE(limiter.check())
56  << "expected check failure on loop " << iter << " event " << n;
57  }
58  }
59  }
60 }
61 
62 TEST(RateLimiter, interval3per100ms) {
63  intervalTest(3, 100ms);
64 }
65 
66 TEST(RateLimiter, interval1per100ms) {
67  intervalTest(1, 100ms);
68 }
69 
70 TEST(RateLimiter, interval15per150ms) {
71  intervalTest(15, 150ms);
72 }
73 
74 TEST(RateLimiter, concurrentThreads) {
75  constexpr uint64_t maxEvents = 20;
76  constexpr uint64_t numThreads = 32;
77 
78  IntervalRateLimiter limiter{20, 10s};
79  std::atomic<uint32_t> count{0};
80  std::mutex m;
81  std::condition_variable cv;
82  bool go = false;
83 
84  auto threadMain = [&]() {
85  // Have each thread wait for go to become true before starting.
86  // This hopefully gives us the best chance of having all threads start
87  // at close to the same time.
88  {
89  std::unique_lock<std::mutex> lock{m};
90  cv.wait(lock, [&go] { return go; });
91  }
92 
93  for (uint64_t iteration = 0; iteration < maxEvents * 2; ++iteration) {
94  if (limiter.check()) {
95  count.fetch_add(1, std::memory_order_relaxed);
96  }
97  }
98  };
99 
100  // Start the threads
101  std::vector<std::thread> threads;
102  threads.reserve(numThreads);
103  for (uint64_t n = 0; n < numThreads; ++n) {
104  threads.emplace_back(threadMain);
105  }
106 
107  // Set go to true and notify all the threads
108  {
109  std::lock_guard<std::mutex> lg(m);
110  go = true;
111  }
112  cv.notify_all();
113 
114  // Wait for all of the threads
115  for (auto& thread : threads) {
116  thread.join();
117  }
118 
119  // We should have passed the check exactly maxEvents times
120  EXPECT_EQ(maxEvents, count.load(std::memory_order_relaxed));
121 }
#define EXPECT_EQ(val1, val2)
Definition: gtest.h:1922
std::chrono::steady_clock::time_point now()
IntervalRateLimiter::clock irl_clock
#define SCOPED_TRACE(message)
Definition: gtest.h:2115
std::vector< std::thread::id > threads
void intervalTest(uint64_t eventsPerInterval, irl_clock::duration interval)
auto lock(SynchronizedLocker...lockersIn) -> std::tuple< typename SynchronizedLocker::LockedPtr... >
Definition: Synchronized.h:871
static map< string, int > m
int * count
#define EXPECT_TRUE(condition)
Definition: gtest.h:1859
TEST(RateLimiter, interval3per100ms)
std::mutex mutex
static set< string > s
#define EXPECT_FALSE(condition)
Definition: gtest.h:1862