@@ -71,42 +71,25 @@ def test_initialization(self):
71
71
assert self .client ._config == self .config
72
72
assert self .client ._circuit_breaker is not None
73
73
74
- def test_initialization_disabled (self ):
75
- """Test client initialization with circuit breaker disabled."""
76
- config = CircuitBreakerConfig (enabled = False )
77
- client = CircuitBreakerHttpClient (self .mock_delegate , self .host , config )
78
-
79
- assert client ._config .enabled is False
80
74
81
- def test_request_context_disabled (self ):
82
- """Test request context when circuit breaker is disabled."""
83
- config = CircuitBreakerConfig (enabled = False )
84
- client = CircuitBreakerHttpClient (self .mock_delegate , self .host , config )
85
-
86
- mock_response = Mock ()
87
- self .mock_delegate .request_context .return_value .__enter__ .return_value = mock_response
88
- self .mock_delegate .request_context .return_value .__exit__ .return_value = None
89
-
90
- with client .request_context (HttpMethod .POST , "https://test.com" , {}) as response :
91
- assert response == mock_response
92
-
93
- self .mock_delegate .request_context .assert_called_once ()
94
75
95
76
def test_request_context_enabled_success (self ):
96
77
"""Test successful request context when circuit breaker is enabled."""
97
78
mock_response = Mock ()
98
- self .mock_delegate .request_context .return_value .__enter__ .return_value = mock_response
99
- self .mock_delegate .request_context .return_value .__exit__ .return_value = None
79
+ mock_context = MagicMock ()
80
+ mock_context .__enter__ .return_value = mock_response
81
+ mock_context .__exit__ .return_value = None
82
+ self .mock_delegate .request_context .return_value = mock_context
100
83
101
- with client .request_context (HttpMethod .POST , "https://test.com" , {}) as response :
84
+ with self . client .request_context (HttpMethod .POST , "https://test.com" , {}) as response :
102
85
assert response == mock_response
103
86
104
87
self .mock_delegate .request_context .assert_called_once ()
105
88
106
89
def test_request_context_enabled_circuit_breaker_error (self ):
107
90
"""Test request context when circuit breaker is open."""
108
91
# Mock circuit breaker to raise CircuitBreakerError
109
- with patch .object (self .client ._circuit_breaker , '__enter__ ' , side_effect = CircuitBreakerError ("Circuit is open" )):
92
+ with patch .object (self .client ._circuit_breaker , 'call ' , side_effect = CircuitBreakerError ("Circuit is open" )):
110
93
with pytest .raises (CircuitBreakerError ):
111
94
with self .client .request_context (HttpMethod .POST , "https://test.com" , {}):
112
95
pass
@@ -120,18 +103,6 @@ def test_request_context_enabled_other_error(self):
120
103
with self .client .request_context (HttpMethod .POST , "https://test.com" , {}):
121
104
pass
122
105
123
- def test_request_disabled (self ):
124
- """Test request method when circuit breaker is disabled."""
125
- config = CircuitBreakerConfig (enabled = False )
126
- client = CircuitBreakerHttpClient (self .mock_delegate , self .host , config )
127
-
128
- mock_response = Mock ()
129
- self .mock_delegate .request .return_value = mock_response
130
-
131
- response = client .request (HttpMethod .POST , "https://test.com" , {})
132
-
133
- assert response == mock_response
134
- self .mock_delegate .request .assert_called_once ()
135
106
136
107
def test_request_enabled_success (self ):
137
108
"""Test successful request when circuit breaker is enabled."""
@@ -146,7 +117,7 @@ def test_request_enabled_success(self):
146
117
def test_request_enabled_circuit_breaker_error (self ):
147
118
"""Test request when circuit breaker is open."""
148
119
# Mock circuit breaker to raise CircuitBreakerError
149
- with patch .object (self .client ._circuit_breaker , '__enter__ ' , side_effect = CircuitBreakerError ("Circuit is open" )):
120
+ with patch .object (self .client ._circuit_breaker , 'call ' , side_effect = CircuitBreakerError ("Circuit is open" )):
150
121
with pytest .raises (CircuitBreakerError ):
151
122
self .client .request (HttpMethod .POST , "https://test.com" , {})
152
123
@@ -160,15 +131,15 @@ def test_request_enabled_other_error(self):
160
131
161
132
def test_get_circuit_breaker_state (self ):
162
133
"""Test getting circuit breaker state."""
163
- with patch . object ( self . client . _circuit_breaker , 'current_state' , 'open' ):
134
+ with patch ( 'databricks.sql.telemetry.telemetry_push_client.CircuitBreakerManager.get_circuit_breaker_state' , return_value = 'open' ):
164
135
state = self .client .get_circuit_breaker_state ()
165
136
assert state == 'open'
166
137
167
138
def test_reset_circuit_breaker (self ):
168
139
"""Test resetting circuit breaker."""
169
- with patch . object ( self . client . _circuit_breaker , 'reset ' ) as mock_reset :
140
+ with patch ( 'databricks.sql.telemetry.telemetry_push_client.CircuitBreakerManager.reset_circuit_breaker ' ) as mock_reset :
170
141
self .client .reset_circuit_breaker ()
171
- mock_reset .assert_called_once ( )
142
+ mock_reset .assert_called_once_with ( self . client . _host )
172
143
173
144
def test_is_circuit_breaker_open (self ):
174
145
"""Test checking if circuit breaker is open."""
@@ -180,42 +151,38 @@ def test_is_circuit_breaker_open(self):
180
151
181
152
def test_is_circuit_breaker_enabled (self ):
182
153
"""Test checking if circuit breaker is enabled."""
183
- assert self .client .is_circuit_breaker_enabled () is True
184
-
185
- config = CircuitBreakerConfig (enabled = False )
186
- client = CircuitBreakerHttpClient (self .mock_delegate , self .host , config )
187
- assert client .is_circuit_breaker_enabled () is False
154
+ assert self .client ._circuit_breaker is not None
188
155
189
156
def test_circuit_breaker_state_logging (self ):
190
157
"""Test that circuit breaker state changes are logged."""
191
- with patch ('databricks.sql.telemetry.circuit_breaker_http_client .logger' ) as mock_logger :
192
- with patch .object (self .client ._circuit_breaker , '__enter__ ' , side_effect = CircuitBreakerError ("Circuit is open" )):
158
+ with patch ('databricks.sql.telemetry.telemetry_push_client .logger' ) as mock_logger :
159
+ with patch .object (self .client ._circuit_breaker , 'call ' , side_effect = CircuitBreakerError ("Circuit is open" )):
193
160
with pytest .raises (CircuitBreakerError ):
194
161
self .client .request (HttpMethod .POST , "https://test.com" , {})
195
-
196
- # Check that warning was logged
197
- mock_logger .warning .assert_called ()
198
- warning_call = mock_logger .warning .call_args [ 0 ] [0 ]
199
- assert "Circuit breaker is open" in warning_call
200
- assert self .host in warning_call
162
+
163
+ # Check that warning was logged
164
+ mock_logger .warning .assert_called ()
165
+ warning_call = mock_logger .warning .call_args [0 ]
166
+ assert "Circuit breaker is open" in warning_call [ 0 ]
167
+ assert self .host in warning_call [ 1 ]
201
168
202
169
def test_other_error_logging (self ):
203
170
"""Test that other errors are logged appropriately."""
204
- with patch ('databricks.sql.telemetry.circuit_breaker_http_client .logger' ) as mock_logger :
171
+ with patch ('databricks.sql.telemetry.telemetry_push_client .logger' ) as mock_logger :
205
172
self .mock_delegate .request .side_effect = ValueError ("Network error" )
206
173
207
174
with pytest .raises (ValueError ):
208
175
self .client .request (HttpMethod .POST , "https://test.com" , {})
209
176
210
177
# Check that debug was logged
211
178
mock_logger .debug .assert_called ()
212
- debug_call = mock_logger .debug .call_args [0 ][ 0 ]
213
- assert "Telemetry request failed" in debug_call
214
- assert self .host in debug_call
179
+ debug_call = mock_logger .debug .call_args [0 ]
180
+ assert "Telemetry request failed" in debug_call [ 0 ]
181
+ assert self .host in debug_call [ 1 ]
215
182
216
183
217
- class TestCircuitBreakerHttpClientIntegration :
218
- """Integration tests for CircuitBreakerHttpClient ."""
184
+ class TestCircuitBreakerTelemetryPushClientIntegration :
185
+ """Integration tests for CircuitBreakerTelemetryPushClient ."""
219
186
220
187
def setup_method (self ):
221
188
"""Set up test fixtures."""
@@ -224,42 +191,59 @@ def setup_method(self):
224
191
225
192
def test_circuit_breaker_opens_after_failures (self ):
226
193
"""Test that circuit breaker opens after repeated failures."""
194
+ from databricks .sql .telemetry .circuit_breaker_manager import CircuitBreakerManager
195
+
196
+ # Clear any existing state
197
+ CircuitBreakerManager .clear_all_circuit_breakers ()
198
+
227
199
config = CircuitBreakerConfig (
228
200
failure_threshold = 0.1 , # 10% failure rate
229
201
minimum_calls = 2 , # Only 2 calls needed
230
202
reset_timeout = 1 # 1 second reset timeout
231
203
)
232
- client = CircuitBreakerHttpClient (self .mock_delegate , self .host , config )
204
+
205
+ # Initialize the manager
206
+ CircuitBreakerManager .initialize (config )
207
+
208
+ client = CircuitBreakerTelemetryPushClient (self .mock_delegate , self .host , config )
233
209
234
210
# Simulate failures
235
211
self .mock_delegate .request .side_effect = Exception ("Network error" )
236
212
237
- # First few calls should fail with the original exception
238
- for _ in range (2 ):
239
- with pytest .raises (Exception , match = "Network error" ):
240
- client .request (HttpMethod .POST , "https://test.com" , {})
213
+ # First call should fail with the original exception
214
+ with pytest .raises (Exception , match = "Network error" ):
215
+ client .request (HttpMethod .POST , "https://test.com" , {})
241
216
242
- # After enough failures, circuit breaker should open
217
+ # Second call should open the circuit breaker and raise CircuitBreakerError
243
218
with pytest .raises (CircuitBreakerError ):
244
219
client .request (HttpMethod .POST , "https://test.com" , {})
245
220
246
221
def test_circuit_breaker_recovers_after_success (self ):
247
222
"""Test that circuit breaker recovers after successful calls."""
223
+ from databricks .sql .telemetry .circuit_breaker_manager import CircuitBreakerManager
224
+
225
+ # Clear any existing state
226
+ CircuitBreakerManager .clear_all_circuit_breakers ()
227
+
248
228
config = CircuitBreakerConfig (
249
229
failure_threshold = 0.1 ,
250
230
minimum_calls = 2 ,
251
231
reset_timeout = 1
252
232
)
253
- client = CircuitBreakerHttpClient (self .mock_delegate , self .host , config )
233
+
234
+ # Initialize the manager
235
+ CircuitBreakerManager .initialize (config )
236
+
237
+ client = CircuitBreakerTelemetryPushClient (self .mock_delegate , self .host , config )
254
238
255
239
# Simulate failures first
256
240
self .mock_delegate .request .side_effect = Exception ("Network error" )
257
241
258
- for _ in range ( 2 ):
259
- with pytest .raises (Exception ):
260
- client .request (HttpMethod .POST , "https://test.com" , {})
242
+ # First call should fail with the original exception
243
+ with pytest .raises (Exception ):
244
+ client .request (HttpMethod .POST , "https://test.com" , {})
261
245
262
- # Circuit breaker should be open now
246
+ # Second call should open the circuit breaker
263
247
with pytest .raises (CircuitBreakerError ):
264
248
client .request (HttpMethod .POST , "https://test.com" , {})
265
249
0 commit comments