Skip to content

Commit d9e7c89

Browse files
committed
fixed broken test
Signed-off-by: Nikhil Suri <[email protected]>
1 parent 4376b6d commit d9e7c89

File tree

3 files changed

+129
-155
lines changed

3 files changed

+129
-155
lines changed

tests/unit/test_circuit_breaker_http_client.py

Lines changed: 48 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -68,71 +68,54 @@ def test_request_enabled_success(self):
6868
self.mock_delegate.request.assert_called_once()
6969

7070
def test_request_enabled_circuit_breaker_error(self):
71-
"""Test request when circuit breaker is open - should return mock response."""
71+
"""Test request when circuit breaker is open - should raise CircuitBreakerError."""
7272
# Mock circuit breaker to raise CircuitBreakerError
7373
with patch.object(
7474
self.client._circuit_breaker,
7575
"call",
7676
side_effect=CircuitBreakerError("Circuit is open"),
7777
):
78-
# Circuit breaker open should return mock response, not raise
79-
response = self.client.request(HttpMethod.POST, "https://test.com", {})
80-
# Should get a mock success response
81-
assert response is not None
82-
assert response.status == 200
83-
assert b"numProtoSuccess" in response.data
78+
# Circuit breaker open should raise (caller handles it)
79+
with pytest.raises(CircuitBreakerError):
80+
self.client.request(HttpMethod.POST, "https://test.com", {})
8481

8582
def test_request_enabled_other_error(self):
86-
"""Test request when other error occurs - should return mock response."""
83+
"""Test request when other error occurs - should raise original exception."""
8784
# Mock delegate to raise a different error (not rate limiting)
8885
self.mock_delegate.request.side_effect = ValueError("Network error")
8986

90-
# Non-rate-limit errors return mock success response
91-
response = self.client.request(HttpMethod.POST, "https://test.com", {})
92-
assert response is not None
93-
assert response.status == 200
94-
assert b"numProtoSuccess" in response.data
87+
# Non-rate-limit errors are unwrapped and raised
88+
with pytest.raises(ValueError, match="Network error"):
89+
self.client.request(HttpMethod.POST, "https://test.com", {})
9590

9691
def test_is_circuit_breaker_enabled(self):
9792
"""Test checking if circuit breaker is enabled."""
9893
assert self.client._circuit_breaker is not None
9994

10095
def test_circuit_breaker_state_logging(self):
101-
"""Test that circuit breaker state changes are logged."""
102-
with patch(
103-
"databricks.sql.telemetry.telemetry_push_client.logger"
104-
) as mock_logger:
105-
with patch.object(
106-
self.client._circuit_breaker,
107-
"call",
108-
side_effect=CircuitBreakerError("Circuit is open"),
109-
):
110-
# Should return mock response, not raise
111-
response = self.client.request(HttpMethod.POST, "https://test.com", {})
112-
assert response is not None
113-
114-
# Check that debug was logged (not warning - telemetry silently drops)
115-
mock_logger.debug.assert_called()
116-
debug_call = mock_logger.debug.call_args[0]
117-
assert "Circuit breaker is open" in debug_call[0]
118-
assert self.host in debug_call[1]
96+
"""Test that circuit breaker errors are raised (no longer silent)."""
97+
with patch.object(
98+
self.client._circuit_breaker,
99+
"call",
100+
side_effect=CircuitBreakerError("Circuit is open"),
101+
):
102+
# Should raise CircuitBreakerError (caller handles it)
103+
with pytest.raises(CircuitBreakerError):
104+
self.client.request(HttpMethod.POST, "https://test.com", {})
119105

120106
def test_other_error_logging(self):
121-
"""Test that other errors are logged appropriately."""
107+
"""Test that other errors are wrapped, logged, then unwrapped and raised."""
122108
with patch(
123109
"databricks.sql.telemetry.telemetry_push_client.logger"
124110
) as mock_logger:
125111
self.mock_delegate.request.side_effect = ValueError("Network error")
126112

127-
# Should return mock response, not raise
128-
response = self.client.request(HttpMethod.POST, "https://test.com", {})
129-
assert response is not None
113+
# Should raise the original ValueError
114+
with pytest.raises(ValueError, match="Network error"):
115+
self.client.request(HttpMethod.POST, "https://test.com", {})
130116

131-
# Check that debug was logged
132-
mock_logger.debug.assert_called()
133-
debug_call = mock_logger.debug.call_args[0]
134-
assert "failing silently" in debug_call[0]
135-
assert self.host in debug_call[1]
117+
# Check that debug was logged (for wrapping and/or unwrapping)
118+
assert mock_logger.debug.call_count >= 1
136119

137120

138121
class TestCircuitBreakerTelemetryPushClientIntegration:
@@ -161,16 +144,22 @@ def test_circuit_breaker_opens_after_failures(self):
161144
mock_response.status = 429
162145
self.mock_delegate.request.return_value = mock_response
163146

164-
# All calls should return mock success (circuit breaker handles it internally)
165-
mock_response_count = 0
147+
# All calls should raise TelemetryRateLimitError
148+
# After MINIMUM_CALLS failures, circuit breaker opens
149+
rate_limit_error_count = 0
150+
circuit_breaker_error_count = 0
151+
166152
for i in range(MINIMUM_CALLS + 5):
167-
response = client.request(HttpMethod.POST, "https://test.com", {})
168-
# Always get mock response (circuit breaker prevents re-raising)
169-
assert response.status == 200
170-
mock_response_count += 1
153+
try:
154+
client.request(HttpMethod.POST, "https://test.com", {})
155+
except TelemetryRateLimitError:
156+
rate_limit_error_count += 1
157+
except CircuitBreakerError:
158+
circuit_breaker_error_count += 1
171159

172-
# All should return mock responses (telemetry fails silently)
173-
assert mock_response_count == MINIMUM_CALLS + 5
160+
# Should have some rate limit errors before circuit opens, then circuit breaker errors
161+
assert rate_limit_error_count >= MINIMUM_CALLS - 1
162+
assert circuit_breaker_error_count > 0
174163

175164
def test_circuit_breaker_recovers_after_success(self):
176165
"""Test that circuit breaker recovers after successful calls."""
@@ -187,21 +176,23 @@ def test_circuit_breaker_recovers_after_success(self):
187176
client = CircuitBreakerTelemetryPushClient(self.mock_delegate, self.host)
188177

189178
# Simulate rate limit failures first (429)
179+
from databricks.sql.exc import TelemetryRateLimitError
180+
from pybreaker import CircuitBreakerError
181+
190182
mock_rate_limit_response = Mock()
191183
mock_rate_limit_response.status = 429
192184
self.mock_delegate.request.return_value = mock_rate_limit_response
193185

194186
# Trigger enough rate limit failures to open circuit
195187
for i in range(MINIMUM_CALLS + 5):
196-
response = client.request(HttpMethod.POST, "https://test.com", {})
197-
assert response.status == 200 # Returns mock success
198-
assert b"numProtoSuccess" in response.data
199-
200-
# Circuit should be open now - still returns mock response
201-
response = client.request(HttpMethod.POST, "https://test.com", {})
202-
assert response is not None
203-
assert response.status == 200 # Mock success response
204-
assert b"numProtoSuccess" in response.data
188+
try:
189+
client.request(HttpMethod.POST, "https://test.com", {})
190+
except (TelemetryRateLimitError, CircuitBreakerError):
191+
pass # Expected - circuit breaker opens after MINIMUM_CALLS failures
192+
193+
# Circuit should be open now - raises CircuitBreakerError
194+
with pytest.raises(CircuitBreakerError):
195+
client.request(HttpMethod.POST, "https://test.com", {})
205196

206197
# Wait for reset timeout
207198
time.sleep(RESET_TIMEOUT + 1.0)

tests/unit/test_telemetry_circuit_breaker_integration.py

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -238,28 +238,24 @@ def test_circuit_breaker_configuration_from_client_context(self):
238238
# The config is used internally but not exposed as an attribute anymore
239239

240240
def test_circuit_breaker_logging(self):
241-
"""Test that circuit breaker events are properly logged."""
242-
with patch(
243-
"databricks.sql.telemetry.telemetry_push_client.logger"
244-
) as mock_logger:
245-
# Mock circuit breaker error
246-
with patch.object(
247-
self.telemetry_client._telemetry_push_client._circuit_breaker,
248-
"call",
249-
side_effect=CircuitBreakerError("Circuit is open"),
250-
):
251-
# CircuitBreakerError is caught and returns mock response
241+
"""Test that circuit breaker exceptions are raised (callback handles them)."""
242+
from pybreaker import CircuitBreakerError
243+
244+
# Mock circuit breaker error
245+
with patch.object(
246+
self.telemetry_client._telemetry_push_client._circuit_breaker,
247+
"call",
248+
side_effect=CircuitBreakerError("Circuit is open"),
249+
):
250+
# CircuitBreakerError is raised from _send_with_unified_client
251+
# (callback will catch it when called via executor)
252+
with pytest.raises(CircuitBreakerError):
252253
self.telemetry_client._send_with_unified_client(
253254
"https://test.com/telemetry",
254255
'{"test": "data"}',
255256
{"Content-Type": "application/json"},
256257
)
257258

258-
# Check that debug was logged (not warning - telemetry silently drops)
259-
mock_logger.debug.assert_called()
260-
debug_call = mock_logger.debug.call_args[0]
261-
assert "Circuit breaker is open" in debug_call[0]
262-
263259

264260
class TestTelemetryCircuitBreakerThreadSafety:
265261
"""Test thread safety of telemetry circuit breaker functionality."""
@@ -322,11 +318,14 @@ def test_concurrent_telemetry_requests(self):
322318

323319
def make_request():
324320
try:
325-
# Mock the underlying HTTP client to fail, not the telemetry push client
321+
# Mock the underlying HTTP client to return 429 (rate limiting)
322+
# This will trigger circuit breaker after MINIMUM_CALLS failures
323+
mock_response = Mock()
324+
mock_response.status = 429
326325
with patch.object(
327326
telemetry_client._http_client,
328327
"request",
329-
side_effect=Exception("Network error"),
328+
return_value=mock_response,
330329
):
331330
telemetry_client._send_with_unified_client(
332331
"https://test.com/telemetry",
@@ -351,7 +350,8 @@ def make_request():
351350
for thread in threads:
352351
thread.join()
353352

354-
# Should have some results and some errors
355-
assert len(results) + len(errors) == num_threads
356-
# Some should be CircuitBreakerError after circuit opens
357-
assert "CircuitBreakerError" in errors or len(errors) == 0
353+
# All requests should result in errors (no successes)
354+
assert len(results) == 0 # No successes
355+
assert len(errors) == num_threads # All fail
356+
# Should have TelemetryRateLimitError (before circuit opens) and CircuitBreakerError (after)
357+
assert "TelemetryRateLimitError" in errors or "CircuitBreakerError" in errors

0 commit comments

Comments
 (0)