Skip to content

Commit fc01948

Browse files
committed
anomoly detection fixed fully
1 parent 33e1b5d commit fc01948

File tree

1 file changed

+115
-13
lines changed

1 file changed

+115
-13
lines changed

backend/apps/monitoring/tests/test_anomaly_detection.py

Lines changed: 115 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -19,31 +19,34 @@ def setUp(self):
1919
self.mock_labels.inc = self.mock_inc
2020
self.mock_triggered.labels.return_value = self.mock_labels
2121

22+
# Patch time for consistent latency calculations
23+
self.time_patcher = patch('time.time')
24+
self.mock_time = self.time_patcher.start()
25+
2226
print(">>> SETUP COMPLETED", file=sys.stderr, flush=True)
2327

2428
def tearDown(self):
2529
"""Clean up patches."""
2630
print(">>> TEARDOWN STARTING", file=sys.stderr, flush=True)
2731
self.patcher.stop()
32+
self.time_patcher.stop()
2833
print(">>> TEARDOWN COMPLETED", file=sys.stderr, flush=True)
2934

3035
def test_high_latency_anomaly_detection(self):
3136
"""Test that high latency anomalies are properly detected."""
3237
print(">>> TEST_HIGH_LATENCY STARTING", file=sys.stderr, flush=True)
3338

34-
# Mock time to simulate latency
35-
with patch('time.time') as mock_time:
36-
# First call returns 0, second call returns 1.5 (exceeding threshold)
37-
mock_time.side_effect = [0, 1.5]
38-
39-
# Import module only after patching dependencies
40-
from apps.monitoring.utils import detect_anomalies
41-
42-
# Use the real function with mocked dependencies
43-
with detect_anomalies('test_endpoint', latency_threshold=1.0):
44-
print(">>> INSIDE CONTEXT MANAGER", file=sys.stderr, flush=True)
45-
# Context manager automatically checks latency when exiting
46-
pass
39+
# Configure mock_time to simulate latency
40+
self.mock_time.side_effect = [0, 1.5] # Start time, end time
41+
42+
# Import module only after patching dependencies
43+
from apps.monitoring.utils import detect_anomalies
44+
45+
# Use the real function with mocked dependencies
46+
with detect_anomalies('test_endpoint', latency_threshold=1.0):
47+
print(">>> INSIDE CONTEXT MANAGER", file=sys.stderr, flush=True)
48+
# Context manager automatically checks latency when exiting
49+
pass
4750

4851
# Verify high latency was detected - check that labels was called with correct arguments
4952
self.mock_triggered.labels.assert_called_once_with(
@@ -63,6 +66,9 @@ def test_anomaly_detection_with_exceptions(self):
6366
self.mock_labels.reset_mock()
6467
self.mock_inc.reset_mock()
6568

69+
# Set consistent time values
70+
self.mock_time.side_effect = [0, 0.5] # Start time, end time
71+
6672
# Import module after patching
6773
from apps.monitoring.utils import detect_anomalies
6874

@@ -82,3 +88,99 @@ def test_anomaly_detection_with_exceptions(self):
8288
)
8389
self.mock_inc.assert_called_once()
8490
print(">>> TEST_WITH_EXCEPTIONS COMPLETED", file=sys.stderr, flush=True)
91+
92+
def test_credit_usage_anomaly_detection(self):
93+
"""Test that unusual credit usage patterns are detected."""
94+
print(">>> TEST_CREDIT_USAGE STARTING", file=sys.stderr, flush=True)
95+
96+
# Reset mocks
97+
self.mock_triggered.reset_mock()
98+
self.mock_labels.reset_mock()
99+
self.mock_inc.reset_mock()
100+
101+
# Simulate normal operation (no high latency)
102+
self.mock_time.side_effect = [0, 0.5] # Below threshold
103+
104+
# Import the function
105+
from apps.monitoring.utils import detect_anomalies
106+
107+
# Use it with credit_usage endpoint
108+
with detect_anomalies('credit_usage', latency_threshold=1.0):
109+
print(">>> SIMULATING CREDIT USAGE", file=sys.stderr, flush=True)
110+
# Simulate an operation that would use credits
111+
pass
112+
113+
# Verify that detect_anomalies was called but latency threshold not exceeded
114+
self.mock_triggered.labels.assert_not_called()
115+
self.mock_inc.assert_not_called()
116+
print(">>> TEST_CREDIT_USAGE COMPLETED", file=sys.stderr, flush=True)
117+
118+
def test_error_rate_anomaly_detection(self):
119+
"""Test that error rate anomalies are properly detected and recorded."""
120+
print(">>> TEST_ERROR_RATE STARTING", file=sys.stderr, flush=True)
121+
122+
# Reset mocks
123+
self.mock_triggered.reset_mock()
124+
self.mock_labels.reset_mock()
125+
self.mock_inc.reset_mock()
126+
127+
# Import the function
128+
from apps.monitoring.utils import detect_anomalies
129+
130+
# Since we're just testing the interface, we'll run multiple operations
131+
# and check that metrics are recorded correctly
132+
for i in range(5):
133+
# Set different time values for each call to prevent side_effect list exhaustion
134+
self.mock_time.side_effect = [i, i+0.2] # Below threshold
135+
136+
# For the last iteration, simulate an error
137+
if i == 4:
138+
try:
139+
with detect_anomalies('api_endpoint'):
140+
raise RuntimeError("Simulated error")
141+
except RuntimeError:
142+
pass
143+
else:
144+
with detect_anomalies('api_endpoint'):
145+
pass
146+
147+
# Verify that exception anomaly was detected exactly once
148+
self.mock_triggered.labels.assert_called_once_with(
149+
endpoint='api_endpoint',
150+
reason='exception'
151+
)
152+
self.mock_inc.assert_called_once()
153+
print(">>> TEST_ERROR_RATE COMPLETED", file=sys.stderr, flush=True)
154+
155+
@patch('apps.monitoring.utils.time')
156+
def test_multiple_latency_thresholds(self, mock_time):
157+
"""Test that different latency thresholds trigger anomalies appropriately."""
158+
print(">>> TEST_MULTIPLE_THRESHOLDS STARTING", file=sys.stderr, flush=True)
159+
160+
# Reset mocks
161+
self.mock_triggered.reset_mock()
162+
self.mock_labels.reset_mock()
163+
self.mock_inc.reset_mock()
164+
165+
# Import the function
166+
from apps.monitoring.utils import detect_anomalies
167+
168+
# Test case 1: Just below threshold (should not trigger)
169+
mock_time.time.side_effect = [0, 0.99] # Just below 1.0 threshold
170+
with detect_anomalies('threshold_test', latency_threshold=1.0):
171+
pass
172+
173+
self.mock_triggered.labels.assert_not_called()
174+
175+
# Test case 2: Just above threshold (should trigger)
176+
self.mock_triggered.reset_mock()
177+
mock_time.time.side_effect = [0, 1.01] # Just above 1.0 threshold
178+
with detect_anomalies('threshold_test', latency_threshold=1.0):
179+
pass
180+
181+
self.mock_triggered.labels.assert_called_once_with(
182+
endpoint='threshold_test',
183+
reason='high_latency'
184+
)
185+
self.mock_inc.assert_called_once()
186+
print(">>> TEST_MULTIPLE_THRESHOLDS COMPLETED", file=sys.stderr, flush=True)

0 commit comments

Comments
 (0)