Skip to content

Commit 4e98595

Browse files
committed
Add on_rate_limit() to statistics object
1 parent 700042a commit 4e98595

2 files changed

Lines changed: 54 additions & 0 deletions

File tree

aikido_zen/storage/statistics/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,15 @@ def __init__(self):
1212
self.total_hits = 0
1313
self.attacks_detected = 0
1414
self.attacks_blocked = 0
15+
self.rate_limited_hits = 0
1516
self.started_at = t.get_unixtime_ms()
1617
self.operations = Operations()
1718

1819
def clear(self):
1920
self.total_hits = 0
2021
self.attacks_detected = 0
2122
self.attacks_blocked = 0
23+
self.rate_limited_hits = 0
2224
self.started_at = t.get_unixtime_ms()
2325
self.operations.clear()
2426

@@ -31,13 +33,17 @@ def on_detected_attack(self, blocked, operation):
3133
self.attacks_blocked += 1
3234
self.operations.on_detected_attack(blocked, operation)
3335

36+
def on_rate_limit(self):
37+
self.rate_limited_hits += 1
38+
3439
def get_record(self):
3540
current_time = t.get_unixtime_ms()
3641
return {
3742
"startedAt": self.started_at,
3843
"endedAt": current_time,
3944
"requests": {
4045
"total": self.total_hits,
46+
"rate_limited": self.rate_limited_hits,
4147
"aborted": 0, # statistic currently not in use
4248
"attacksDetected": {
4349
"total": self.attacks_detected,
@@ -50,6 +56,7 @@ def get_record(self):
5056
def import_from_record(self, record):
5157
attacks_detected = record.get("requests", {}).get("attacksDetected", {})
5258
self.total_hits += record.get("requests", {}).get("total", 0)
59+
self.rate_limited_hits += record.get("requests", {}).get("rate_limited", 0)
5360
self.attacks_detected += attacks_detected.get("total", 0)
5461
self.attacks_blocked += attacks_detected.get("blocked", 0)
5562
self.operations.update(record.get("operations", {}))

aikido_zen/storage/statistics/init_test.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ def test_get_record(monkeypatch):
6868

6969
stats = Statistics()
7070
stats.total_hits = 10
71+
stats.on_rate_limit()
72+
stats.on_rate_limit()
7173
stats.operations.register_call("test.test", "nosql_op")
7274
stats.on_detected_attack(blocked=True, operation="test.test")
7375
stats.attacks_detected = 5
@@ -77,6 +79,7 @@ def test_get_record(monkeypatch):
7779
assert record["startedAt"] == stats.started_at
7880
assert record["endedAt"] == mock_time
7981
assert record["requests"]["total"] == 10
82+
assert record["requests"]["rate_limited"] == 2
8083
assert record["requests"]["aborted"] == 0
8184
assert record["requests"]["attacksDetected"]["total"] == 5
8285
assert record["requests"]["attacksDetected"]["blocked"] == 3
@@ -97,6 +100,7 @@ def test_import_from_record():
97100
record = {
98101
"requests": {
99102
"total": 10,
103+
"rate_limited": 5,
100104
"attacksDetected": {
101105
"total": 5,
102106
"blocked": 3,
@@ -117,6 +121,7 @@ def test_import_from_record():
117121
}
118122
stats.import_from_record(record)
119123
assert stats.total_hits == 10
124+
assert stats.rate_limited_hits == 5
120125
assert stats.attacks_detected == 5
121126
assert stats.attacks_blocked == 3
122127
assert stats.operations == {
@@ -152,6 +157,7 @@ def test_multiple_imports(stats):
152157
record1 = {
153158
"requests": {
154159
"total": 10,
160+
"rate_limited": 20,
155161
"attacksDetected": {
156162
"total": 5,
157163
"blocked": 3,
@@ -168,6 +174,7 @@ def test_multiple_imports(stats):
168174
record2 = {
169175
"requests": {
170176
"total": 20,
177+
"rate_limited": 5,
171178
"attacksDetected": {
172179
"total": 10,
173180
"blocked": 7,
@@ -184,6 +191,7 @@ def test_multiple_imports(stats):
184191
stats.import_from_record(record1)
185192
stats.import_from_record(record2)
186193
assert stats.total_hits == 30
194+
assert stats.rate_limited_hits == 25
187195
assert stats.attacks_detected == 15
188196
assert stats.attacks_blocked == 10
189197
assert stats.operations == {
@@ -204,6 +212,7 @@ def test_import_empty_record(stats):
204212
record = {"requests": {}}
205213
stats.import_from_record(record)
206214
assert stats.total_hits == 0
215+
assert stats.rate_limited_hits == 0
207216
assert stats.attacks_detected == 0
208217
assert stats.attacks_blocked == 0
209218
assert stats.operations == {}
@@ -213,6 +222,7 @@ def test_import_partial_record(stats):
213222
record = {"requests": {"total": 10}}
214223
stats.import_from_record(record)
215224
assert stats.total_hits == 10
225+
assert stats.rate_limited_hits == 0
216226
assert stats.attacks_detected == 0
217227
assert stats.attacks_blocked == 0
218228
assert stats.operations == {}
@@ -242,3 +252,40 @@ def test_multiple_increments_and_detects(stats):
242252
"kind": "sql_op",
243253
"total": 1,
244254
}
255+
256+
stats.on_rate_limit()
257+
assert stats.rate_limited_hits == 1
258+
259+
stats.on_rate_limit()
260+
assert stats.rate_limited_hits == 2
261+
262+
263+
def test_multiple_rate_limits(stats):
264+
"""Test multiple rate limit calls"""
265+
for _ in range(5):
266+
stats.on_rate_limit()
267+
assert stats.rate_limited_hits == 5
268+
269+
270+
def test_rate_limit_in_get_record():
271+
"""Test that rate_limited_hits is included in get_record output"""
272+
stats = Statistics()
273+
stats.total_hits = 10
274+
stats.on_rate_limit()
275+
stats.on_rate_limit()
276+
stats.on_rate_limit()
277+
278+
record = stats.get_record()
279+
assert record["requests"]["rate_limited"] == 3
280+
assert record["requests"]["total"] == 10
281+
282+
283+
def test_rate_limit_clear():
284+
"""Test that clear() resets rate_limited_hits"""
285+
stats = Statistics()
286+
stats.on_rate_limit()
287+
stats.on_rate_limit()
288+
assert stats.rate_limited_hits == 2
289+
290+
stats.clear()
291+
assert stats.rate_limited_hits == 0

0 commit comments

Comments
 (0)