]>
Commit | Line | Data |
---|---|---|
20effc67 TL |
1 | // -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- |
2 | // vim: ts=8 sw=2 smarttab ft=cpp | |
3 | ||
4 | #include <gtest/gtest.h> | |
1e59de90 | 5 | #include "rgw_ratelimit.h" |
20effc67 TL |
6 | |
7 | ||
8 | using namespace std::chrono_literals; | |
9 | ||
10 | TEST(RGWRateLimit, op_limit_not_enabled) | |
11 | { | |
12 | // info.enabled = false, so no limit | |
13 | std::atomic_bool replacing; | |
14 | std::condition_variable cv; | |
15 | RateLimiter ratelimit(replacing, cv); | |
16 | RGWRateLimitInfo info; | |
17 | auto time = ceph::coarse_real_clock::now(); | |
18 | std::string key = "uuser123"; | |
19 | bool success = ratelimit.should_rate_limit("PUT", key, time, &info); | |
20 | EXPECT_EQ(false, success); | |
21 | } | |
22 | TEST(RGWRateLimit, reject_op_over_limit) | |
23 | { | |
24 | // check that request is being rejected because there are not enough tokens | |
25 | std::atomic_bool replacing; | |
26 | std::condition_variable cv; | |
27 | RateLimiter ratelimit(replacing, cv); | |
28 | RGWRateLimitInfo info; | |
29 | info.enabled = true; | |
30 | info.max_read_ops = 1; | |
31 | auto time = ceph::coarse_real_clock::now(); | |
32 | std::string key = "uuser123"; | |
33 | bool success = ratelimit.should_rate_limit("GET", key, time, &info); | |
34 | time = ceph::coarse_real_clock::now(); | |
35 | success = ratelimit.should_rate_limit("GET", key, time, &info); | |
36 | EXPECT_EQ(true, success); | |
37 | } | |
38 | TEST(RGWRateLimit, accept_op_after_giveback) | |
39 | { | |
40 | // check that giveback is working fine | |
41 | std::atomic_bool replacing; | |
42 | std::condition_variable cv; | |
43 | RateLimiter ratelimit(replacing, cv); | |
44 | RGWRateLimitInfo info; | |
45 | info.enabled = true; | |
46 | info.max_read_ops = 1; | |
47 | auto time = ceph::coarse_real_clock::now(); | |
48 | std::string key = "uuser123"; | |
49 | bool success = ratelimit.should_rate_limit("GET", key, time, &info); | |
50 | ratelimit.giveback_tokens("GET", key); | |
51 | time = ceph::coarse_real_clock::now(); | |
52 | success = ratelimit.should_rate_limit("GET", key, time, &info); | |
53 | EXPECT_EQ(false, success); | |
54 | } | |
55 | TEST(RGWRateLimit, accept_op_after_refill) | |
56 | { | |
57 | // check that tokens are being filled properly | |
58 | std::atomic_bool replacing; | |
59 | std::condition_variable cv; | |
60 | RateLimiter ratelimit(replacing, cv); | |
61 | RGWRateLimitInfo info; | |
62 | info.enabled = true; | |
63 | info.max_read_ops = 1; | |
64 | auto time = ceph::coarse_real_clock::now(); | |
65 | std::string key = "uuser123"; | |
66 | bool success = ratelimit.should_rate_limit("GET", key, time, &info); | |
67 | time += 61s; | |
68 | success = ratelimit.should_rate_limit("GET", key, time, &info); | |
69 | EXPECT_EQ(false, success); | |
70 | } | |
71 | TEST(RGWRateLimit, reject_bw_over_limit) | |
72 | { | |
73 | // check that a newer request is rejected if there is no enough tokens (bw) | |
74 | std::atomic_bool replacing; | |
75 | std::condition_variable cv; | |
76 | RateLimiter ratelimit(replacing, cv); | |
77 | RGWRateLimitInfo info; | |
78 | info.enabled = true; | |
79 | info.max_read_bytes = 1; | |
80 | auto time = ceph::coarse_real_clock::now(); | |
81 | std::string key = "uuser123"; | |
82 | bool success = ratelimit.should_rate_limit("GET", key, time, &info); | |
83 | ratelimit.decrease_bytes("GET",key, 2, &info); | |
84 | time = ceph::coarse_real_clock::now(); | |
85 | success = ratelimit.should_rate_limit("GET", key, time, &info); | |
86 | EXPECT_EQ(true, success); | |
87 | } | |
88 | TEST(RGWRateLimit, accept_bw) | |
89 | { | |
90 | // check that when there are enough tokens (bw) the request is still being served | |
91 | std::atomic_bool replacing; | |
92 | std::condition_variable cv; | |
93 | RateLimiter ratelimit(replacing, cv); | |
94 | RGWRateLimitInfo info; | |
95 | info.enabled = true; | |
96 | info.max_read_bytes = 2; | |
97 | auto time = ceph::coarse_real_clock::now(); | |
98 | std::string key = "uuser123"; | |
99 | bool success = ratelimit.should_rate_limit("GET", key, time, &info); | |
100 | ratelimit.decrease_bytes("GET",key, 1, &info); | |
101 | time = ceph::coarse_real_clock::now(); | |
102 | success = ratelimit.should_rate_limit("GET", key, time, &info); | |
103 | EXPECT_EQ(false, success); | |
104 | } | |
105 | TEST(RGWRateLimit, check_bw_debt_at_max_120secs) | |
106 | { | |
107 | // check that the bandwidth debt is not larger than 120 seconds | |
108 | std::atomic_bool replacing; | |
109 | std::condition_variable cv; | |
110 | RateLimiter ratelimit(replacing, cv); | |
111 | RGWRateLimitInfo info; | |
112 | info.enabled = true; | |
113 | info.max_read_bytes = 2; | |
114 | auto time = ceph::coarse_real_clock::now(); | |
115 | std::string key = "uuser123"; | |
116 | bool success = ratelimit.should_rate_limit("GET", key, time, &info); | |
117 | ratelimit.decrease_bytes("GET",key, 100, &info); | |
118 | time += 121s; | |
119 | success = ratelimit.should_rate_limit("GET", key, time, &info); | |
120 | EXPECT_EQ(false, success); | |
121 | } | |
122 | TEST(RGWRateLimit, check_that_bw_limit_not_affect_ops) | |
123 | { | |
124 | // check that high read bytes limit, does not affect ops limit | |
125 | std::atomic_bool replacing; | |
126 | std::condition_variable cv; | |
127 | RateLimiter ratelimit(replacing, cv); | |
128 | RGWRateLimitInfo info; | |
129 | info.enabled = true; | |
130 | info.max_read_ops = 1; | |
131 | info.max_read_bytes = 100000000; | |
132 | auto time = ceph::coarse_real_clock::now(); | |
133 | std::string key = "uuser123"; | |
134 | bool success = ratelimit.should_rate_limit("GET", key, time, &info); | |
135 | ratelimit.decrease_bytes("GET",key, 10000, &info); | |
136 | time = ceph::coarse_real_clock::now(); | |
137 | success = ratelimit.should_rate_limit("GET", key, time, &info); | |
138 | EXPECT_EQ(true, success); | |
139 | } | |
140 | TEST(RGWRateLimit, read_limit_does_not_affect_writes) | |
141 | { | |
142 | // read limit does not affect writes | |
143 | std::atomic_bool replacing; | |
144 | std::condition_variable cv; | |
145 | RateLimiter ratelimit(replacing, cv); | |
146 | RGWRateLimitInfo info; | |
147 | info.enabled = true; | |
148 | info.max_read_ops = 1; | |
149 | info.max_read_bytes = 100000000; | |
150 | auto time = ceph::coarse_real_clock::now(); | |
151 | std::string key = "uuser123"; | |
152 | bool success = ratelimit.should_rate_limit("PUT", key, time, &info); | |
153 | ratelimit.decrease_bytes("PUT",key, 10000, &info); | |
154 | time = ceph::coarse_real_clock::now(); | |
155 | success = ratelimit.should_rate_limit("PUT", key, time, &info); | |
156 | EXPECT_EQ(false, success); | |
157 | } | |
158 | TEST(RGWRateLimit, write_limit_does_not_affect_reads) | |
159 | { | |
160 | // write limit does not affect reads | |
161 | std::atomic_bool replacing; | |
162 | std::condition_variable cv; | |
163 | RateLimiter ratelimit(replacing, cv); | |
164 | RGWRateLimitInfo info; | |
165 | info.enabled = true; | |
166 | info.max_write_ops = 1; | |
167 | info.max_write_bytes = 100000000; | |
168 | auto time = ceph::coarse_real_clock::now(); | |
169 | std::string key = "uuser123"; | |
170 | bool success = ratelimit.should_rate_limit("GET", key, time, &info); | |
171 | ratelimit.decrease_bytes("GET",key, 10000, &info); | |
172 | time = ceph::coarse_real_clock::now(); | |
173 | success = ratelimit.should_rate_limit("GET", key, time, &info); | |
174 | EXPECT_EQ(false, success); | |
175 | } | |
176 | ||
177 | TEST(RGWRateLimit, allow_unlimited_access) | |
178 | { | |
179 | // 0 values in RGWRateLimitInfo should allow unlimited access | |
180 | std::atomic_bool replacing; | |
181 | std::condition_variable cv; | |
182 | RateLimiter ratelimit(replacing, cv); | |
183 | RGWRateLimitInfo info; | |
184 | info.enabled = true; | |
185 | auto time = ceph::coarse_real_clock::now(); | |
186 | std::string key = "uuser123"; | |
187 | bool success = ratelimit.should_rate_limit("GET", key, time, &info); | |
188 | EXPECT_EQ(false, success); | |
189 | } | |
190 | ||
191 | TEST(RGWRateLimitGC, NO_GC_AHEAD_OF_TIME) | |
192 | { | |
193 | // Test if GC is not starting the replace before getting to map_size * 0.9 | |
194 | // Please make sure to change those values when you change the map_size in the code | |
195 | ||
196 | std::shared_ptr<ActiveRateLimiter> ratelimit(new ActiveRateLimiter(g_ceph_context)); | |
197 | ratelimit->start(); | |
198 | auto active = ratelimit->get_active(); | |
199 | RGWRateLimitInfo info; | |
200 | auto time = ceph::coarse_real_clock::now(); | |
201 | std::string key = "uuser123"; | |
202 | active->should_rate_limit("GET", key, time, &info); | |
203 | auto activegc = ratelimit->get_active(); | |
204 | EXPECT_EQ(activegc, active); | |
205 | } | |
206 | TEST(RGWRateLimiterGC, GC_IS_WORKING) | |
207 | { | |
208 | // Test if GC is replacing the active RateLimiter | |
209 | // Please make sure to change those values when you change the map_size in the code | |
210 | ||
211 | std::shared_ptr<ActiveRateLimiter> ratelimit(new ActiveRateLimiter(g_ceph_context)); | |
212 | ratelimit->start(); | |
213 | auto active = ratelimit->get_active(); | |
214 | RGWRateLimitInfo info; | |
215 | info.enabled = true; | |
216 | auto time = ceph::coarse_real_clock::now(); | |
217 | std::string key = "-1"; | |
218 | for(int i = 0; i < 2000000; i++) | |
219 | { | |
220 | active->should_rate_limit("GET", key, time, &info); | |
221 | key = std::to_string(i); | |
222 | } | |
223 | auto activegc = ratelimit->get_active(); | |
224 | EXPECT_NE(activegc, active); | |
225 | } | |
226 | ||
227 | ||
228 | TEST(RGWRateLimitEntry, op_limit_not_enabled) | |
229 | { | |
230 | // info.enabled = false, so no limit | |
231 | RateLimiterEntry entry; | |
232 | RGWRateLimitInfo info; | |
233 | auto time = ceph::coarse_real_clock::now().time_since_epoch(); | |
234 | bool success = entry.should_rate_limit(false, &info, time); | |
235 | EXPECT_EQ(false, success); | |
236 | } | |
237 | TEST(RGWRateLimitEntry, reject_op_over_limit) | |
238 | { | |
239 | // check that request is being rejected because there are not enough tokens | |
240 | ||
241 | RGWRateLimitInfo info; | |
242 | RateLimiterEntry entry; | |
243 | info.enabled = true; | |
244 | info.max_read_ops = 1; | |
245 | auto time = ceph::coarse_real_clock::now().time_since_epoch(); | |
246 | bool success = entry.should_rate_limit(true, &info, time); | |
247 | time = ceph::coarse_real_clock::now().time_since_epoch(); | |
248 | success = entry.should_rate_limit(true, &info, time); | |
249 | EXPECT_EQ(true, success); | |
250 | } | |
251 | TEST(RGWRateLimitEntry, accept_op_after_giveback) | |
252 | { | |
253 | // check that giveback is working fine | |
254 | RGWRateLimitInfo info; | |
255 | RateLimiterEntry entry; | |
256 | info.enabled = true; | |
257 | info.max_read_ops = 1; | |
258 | auto time = ceph::coarse_real_clock::now().time_since_epoch(); | |
259 | bool success = entry.should_rate_limit(true, &info, time); | |
260 | entry.giveback_tokens(true); | |
261 | time = ceph::coarse_real_clock::now().time_since_epoch(); | |
262 | success = entry.should_rate_limit(true, &info, time); | |
263 | EXPECT_EQ(false, success); | |
264 | } | |
265 | TEST(RGWRateLimitEntry, accept_op_after_refill) | |
266 | { | |
267 | // check that tokens are being filled properly | |
268 | RateLimiterEntry entry; | |
269 | RGWRateLimitInfo info; | |
270 | info.enabled = true; | |
271 | info.max_read_ops = 1; | |
272 | auto time = ceph::coarse_real_clock::now().time_since_epoch(); | |
273 | bool success = entry.should_rate_limit(true, &info, time); | |
274 | time += 61s; | |
275 | success = entry.should_rate_limit(true, &info, time); | |
276 | EXPECT_EQ(false, success); | |
277 | } | |
278 | TEST(RGWRateLimitEntry, reject_bw_over_limit) | |
279 | { | |
280 | // check that a newer request is rejected if there is no enough tokens (bw) | |
281 | RateLimiterEntry entry; | |
282 | RGWRateLimitInfo info; | |
283 | info.enabled = true; | |
284 | info.max_read_bytes = 1; | |
285 | auto time = ceph::coarse_real_clock::now().time_since_epoch(); | |
286 | bool success = entry.should_rate_limit(true, &info, time); | |
287 | entry.decrease_bytes(true, 2, &info); | |
288 | time = ceph::coarse_real_clock::now().time_since_epoch(); | |
289 | success = entry.should_rate_limit(true, &info, time); | |
290 | EXPECT_EQ(true, success); | |
291 | } | |
292 | TEST(RGWRateLimitEntry, accept_bw) | |
293 | { | |
294 | // check that when there are enough tokens (bw) the request is still being served | |
295 | RateLimiterEntry entry; | |
296 | RGWRateLimitInfo info; | |
297 | info.enabled = true; | |
298 | info.max_read_bytes = 2; | |
299 | auto time = ceph::coarse_real_clock::now().time_since_epoch(); | |
300 | bool success = entry.should_rate_limit(true, &info, time); | |
301 | entry.decrease_bytes(true, 1, &info); | |
302 | time = ceph::coarse_real_clock::now().time_since_epoch(); | |
303 | success = entry.should_rate_limit(true, &info, time); | |
304 | EXPECT_EQ(false, success); | |
305 | } | |
306 | TEST(RGWRateLimitEntry, check_bw_debt_at_max_120secs) | |
307 | { | |
308 | // check that the bandwidth debt is not larger than 120 seconds | |
309 | RateLimiterEntry entry; | |
310 | RGWRateLimitInfo info; | |
311 | info.enabled = true; | |
312 | info.max_read_bytes = 2; | |
313 | auto time = ceph::coarse_real_clock::now().time_since_epoch(); | |
314 | bool success = entry.should_rate_limit(true, &info, time); | |
315 | entry.decrease_bytes(true, 100, &info); | |
316 | time += 121s; | |
317 | success = entry.should_rate_limit(true, &info, time); | |
318 | EXPECT_EQ(false, success); | |
319 | } | |
320 | TEST(RGWRateLimitEntry, check_that_bw_limit_not_affect_ops) | |
321 | { | |
322 | // check that high read bytes limit, does not affect ops limit | |
323 | RateLimiterEntry entry; | |
324 | RGWRateLimitInfo info; | |
325 | info.enabled = true; | |
326 | info.max_read_ops = 1; | |
327 | info.max_read_bytes = 100000000; | |
328 | auto time = ceph::coarse_real_clock::now().time_since_epoch(); | |
329 | bool success = entry.should_rate_limit(true, &info, time); | |
330 | entry.decrease_bytes(true, 10000, &info); | |
331 | time = ceph::coarse_real_clock::now().time_since_epoch(); | |
332 | success = entry.should_rate_limit(true, &info, time); | |
333 | EXPECT_EQ(true, success); | |
334 | } | |
335 | TEST(RGWRateLimitEntry, read_limit_does_not_affect_writes) | |
336 | { | |
337 | // read limit does not affect writes | |
338 | RateLimiterEntry entry; | |
339 | RGWRateLimitInfo info; | |
340 | info.enabled = true; | |
341 | info.max_read_ops = 1; | |
342 | info.max_read_bytes = 100000000; | |
343 | auto time = ceph::coarse_real_clock::now().time_since_epoch(); | |
344 | bool success = entry.should_rate_limit(false, &info, time); | |
345 | entry.decrease_bytes(false, 10000, &info); | |
346 | time = ceph::coarse_real_clock::now().time_since_epoch(); | |
347 | success = entry.should_rate_limit(false, &info, time); | |
348 | EXPECT_EQ(false, success); | |
349 | } | |
350 | TEST(RGWRateLimitEntry, write_limit_does_not_affect_reads) | |
351 | { | |
352 | // write limit does not affect reads | |
353 | RateLimiterEntry entry; | |
354 | RGWRateLimitInfo info; | |
355 | info.enabled = true; | |
356 | info.max_write_ops = 1; | |
357 | info.max_write_bytes = 100000000; | |
358 | auto time = ceph::coarse_real_clock::now().time_since_epoch(); | |
359 | std::string key = "uuser123"; | |
360 | bool success = entry.should_rate_limit(true, &info, time); | |
361 | entry.decrease_bytes(true, 10000, &info); | |
362 | time = ceph::coarse_real_clock::now().time_since_epoch(); | |
363 | success = entry.should_rate_limit(true, &info, time); | |
364 | EXPECT_EQ(false, success); | |
365 | } | |
366 | ||
367 | TEST(RGWRateLimitEntry, allow_unlimited_access) | |
368 | { | |
369 | // 0 values in RGWRateLimitInfo should allow unlimited access (default value) | |
370 | RateLimiterEntry entry; | |
371 | RGWRateLimitInfo info; | |
372 | info.enabled = true; | |
373 | auto time = ceph::coarse_real_clock::now().time_since_epoch(); | |
374 | bool success = entry.should_rate_limit(true, &info, time); | |
375 | EXPECT_EQ(false, success); | |
376 | } |