Skip to content

Commit f3abdb0

Browse files
add more unit tests
Signed-off-by: varun-edachali-dbx <varun.edachali@databricks.com>
1 parent 2d10cb4 commit f3abdb0

File tree

1 file changed

+276
-22
lines changed

1 file changed

+276
-22
lines changed

tests/unit/test_thrift_http_client.py

Lines changed: 276 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import unittest
22
import json
33
import urllib
4-
from unittest.mock import patch, Mock, MagicMock
4+
from unittest.mock import patch, Mock, MagicMock, PropertyMock, call
55
import urllib3
66
from http.client import HTTPResponse
77
from io import BytesIO
@@ -43,6 +43,9 @@ def setUp(self, mock_proxy_bypass, mock_getproxies):
4343
self.http_client._headers = {"User-Agent": "test-agent"}
4444
self.http_client.__custom_headers = {"User-Agent": "test-agent"}
4545

46+
# Set timeout
47+
self.http_client._THttpClient__timeout = None
48+
4649
def test_check_rest_response_for_error_success(self):
4750
"""Test _check_rest_response_for_error with success status."""
4851
# No exception should be raised for status codes < 400
@@ -106,34 +109,285 @@ def test_check_rest_response_for_error_invalid_json(self):
106109
"REST HTTP request failed with status 500", str(context.exception)
107110
)
108111

109-
@patch("databricks.sql.auth.thrift_http_client.THttpClient.make_rest_request")
110-
def test_make_rest_request_integration(self, mock_make_rest_request):
111-
"""Test that make_rest_request can be called with the expected parameters."""
112-
# Setup mock return value
113-
expected_result = {"result": "success"}
114-
mock_make_rest_request.return_value = expected_result
112+
@patch("databricks.sql.auth.thrift_http_client.THttpClient.isOpen")
113+
@patch("databricks.sql.auth.thrift_http_client.THttpClient.open")
114+
@patch(
115+
"databricks.sql.auth.thrift_http_client.THttpClient._check_rest_response_for_error"
116+
)
117+
def test_make_rest_request_success(self, mock_check_error, mock_open, mock_is_open):
118+
"""Test the make_rest_request method with a successful response."""
119+
# Setup mocks
120+
mock_is_open.return_value = False # To trigger open() call
121+
122+
# Create a mock response
123+
mock_response = Mock()
124+
mock_response.status = 200
125+
mock_response.reason = "OK"
126+
mock_response.headers = {"Content-Type": "application/json"}
127+
mock_response.data = json.dumps({"result": "success"}).encode("utf-8")
128+
129+
# Configure the mock pool to return our mock response
130+
self.mock_pool.request.return_value = mock_response
115131

116-
# Call the original method to verify it works
132+
# Call the method under test
117133
result = self.http_client.make_rest_request(
118-
method="GET",
119-
endpoint_path="test/endpoint",
120-
params={"param": "value"},
121-
data={"key": "value"},
122-
headers={"X-Custom-Header": "custom-value"},
134+
method="GET", endpoint_path="test/endpoint", params={"param": "value"}
123135
)
124136

125137
# Verify the result
126-
self.assertEqual(result, expected_result)
127-
128-
# Verify the method was called with correct parameters
129-
mock_make_rest_request.assert_called_once_with(
130-
method="GET",
131-
endpoint_path="test/endpoint",
132-
params={"param": "value"},
133-
data={"key": "value"},
134-
headers={"X-Custom-Header": "custom-value"},
138+
self.assertEqual(result, {"result": "success"})
139+
140+
# Verify open was called
141+
mock_open.assert_called_once()
142+
143+
# Verify the request was made with correct parameters
144+
self.mock_pool.request.assert_called_once()
145+
146+
# Check URL contains the parameters
147+
args, kwargs = self.mock_pool.request.call_args
148+
self.assertIn("test/endpoint?param=value", kwargs["url"])
149+
150+
# Verify error check was called
151+
mock_check_error.assert_called_once_with(200, mock_response.data)
152+
153+
# Verify auth headers were added
154+
self.mock_auth_provider.add_headers.assert_called_once()
155+
156+
@patch("databricks.sql.auth.thrift_http_client.THttpClient.isOpen")
157+
@patch("databricks.sql.auth.thrift_http_client.THttpClient.open")
158+
@patch(
159+
"databricks.sql.auth.thrift_http_client.THttpClient._check_rest_response_for_error"
160+
)
161+
def test_make_rest_request_with_data(
162+
self, mock_check_error, mock_open, mock_is_open
163+
):
164+
"""Test the make_rest_request method with data payload."""
165+
# Setup mocks
166+
mock_is_open.return_value = True # Connection is already open
167+
168+
# Create a mock response
169+
mock_response = Mock()
170+
mock_response.status = 200
171+
mock_response.reason = "OK"
172+
mock_response.headers = {"Content-Type": "application/json"}
173+
mock_response.data = json.dumps({"result": "success"}).encode("utf-8")
174+
175+
# Configure the mock pool to return our mock response
176+
self.mock_pool.request.return_value = mock_response
177+
178+
# Call the method under test with data
179+
data = {"key": "value"}
180+
result = self.http_client.make_rest_request(
181+
method="POST", endpoint_path="test/endpoint", data=data
182+
)
183+
184+
# Verify the result
185+
self.assertEqual(result, {"result": "success"})
186+
187+
# Verify open was not called (connection already open)
188+
mock_open.assert_not_called()
189+
190+
# Verify the request was made with correct parameters
191+
self.mock_pool.request.assert_called_once()
192+
193+
# Check body contains the JSON data
194+
args, kwargs = self.mock_pool.request.call_args
195+
self.assertEqual(kwargs["body"], json.dumps(data).encode("utf-8"))
196+
197+
# Verify error check was called
198+
mock_check_error.assert_called_once_with(200, mock_response.data)
199+
200+
@patch("databricks.sql.auth.thrift_http_client.THttpClient.isOpen")
201+
@patch("databricks.sql.auth.thrift_http_client.THttpClient.open")
202+
@patch(
203+
"databricks.sql.auth.thrift_http_client.THttpClient._check_rest_response_for_error"
204+
)
205+
def test_make_rest_request_with_custom_headers(
206+
self, mock_check_error, mock_open, mock_is_open
207+
):
208+
"""Test the make_rest_request method with custom headers."""
209+
# Setup mocks
210+
mock_is_open.return_value = True # Connection is already open
211+
212+
# Create a mock response
213+
mock_response = Mock()
214+
mock_response.status = 200
215+
mock_response.reason = "OK"
216+
mock_response.headers = {"Content-Type": "application/json"}
217+
mock_response.data = json.dumps({"result": "success"}).encode("utf-8")
218+
219+
# Configure the mock pool to return our mock response
220+
self.mock_pool.request.return_value = mock_response
221+
222+
# Call the method under test with custom headers
223+
custom_headers = {"X-Custom-Header": "custom-value"}
224+
result = self.http_client.make_rest_request(
225+
method="GET", endpoint_path="test/endpoint", headers=custom_headers
226+
)
227+
228+
# Verify the result
229+
self.assertEqual(result, {"result": "success"})
230+
231+
# Verify the request was made with correct headers
232+
self.mock_pool.request.assert_called_once()
233+
234+
# Check headers contain the custom header
235+
args, kwargs = self.mock_pool.request.call_args
236+
headers = kwargs["headers"]
237+
self.assertIn("X-Custom-Header", headers)
238+
self.assertEqual(headers["X-Custom-Header"], "custom-value")
239+
self.assertEqual(headers["Content-Type"], "application/json")
240+
241+
# Verify error check was called
242+
mock_check_error.assert_called_once_with(200, mock_response.data)
243+
244+
@patch("databricks.sql.auth.thrift_http_client.THttpClient.isOpen")
245+
@patch("databricks.sql.auth.thrift_http_client.THttpClient.open")
246+
def test_make_rest_request_http_error(self, mock_open, mock_is_open):
247+
"""Test the make_rest_request method with an HTTP error."""
248+
# Setup mocks
249+
mock_is_open.return_value = True # Connection is already open
250+
251+
# Configure the mock pool to raise an HTTP error
252+
http_error = urllib3.exceptions.HTTPError("HTTP Error")
253+
self.mock_pool.request.side_effect = http_error
254+
255+
# Call the method under test and expect an exception
256+
with self.assertRaises(RequestError) as context:
257+
self.http_client.make_rest_request(
258+
method="GET", endpoint_path="test/endpoint"
259+
)
260+
261+
# Verify the exception message
262+
self.assertIn("REST HTTP request failed", str(context.exception))
263+
self.assertIn("HTTP Error", str(context.exception))
264+
265+
@patch("databricks.sql.auth.thrift_http_client.THttpClient.isOpen")
266+
@patch("databricks.sql.auth.thrift_http_client.THttpClient.open")
267+
@patch(
268+
"databricks.sql.auth.thrift_http_client.THttpClient._check_rest_response_for_error"
269+
)
270+
def test_make_rest_request_empty_response(
271+
self, mock_check_error, mock_open, mock_is_open
272+
):
273+
"""Test the make_rest_request method with an empty response."""
274+
# Setup mocks
275+
mock_is_open.return_value = True # Connection is already open
276+
277+
# Create a mock response with empty data
278+
mock_response = Mock()
279+
mock_response.status = 204 # No Content
280+
mock_response.reason = "No Content"
281+
mock_response.headers = {"Content-Type": "application/json"}
282+
mock_response.data = None # Empty response
283+
284+
# Configure the mock pool to return our mock response
285+
self.mock_pool.request.return_value = mock_response
286+
287+
# Call the method under test
288+
result = self.http_client.make_rest_request(
289+
method="DELETE", endpoint_path="test/endpoint/123"
135290
)
136291

292+
# Verify the result is an empty dict
293+
self.assertEqual(result, {})
294+
295+
# Verify error check was called with None data
296+
mock_check_error.assert_called_once_with(204, None)
297+
298+
@patch("databricks.sql.auth.thrift_http_client.THttpClient.isOpen")
299+
@patch("databricks.sql.auth.thrift_http_client.THttpClient.open")
300+
def test_make_rest_request_no_response(self, mock_open, mock_is_open):
301+
"""Test the make_rest_request method with no response."""
302+
# Setup mocks
303+
mock_is_open.return_value = True # Connection is already open
304+
305+
# Configure the mock pool to return None
306+
self.mock_pool.request.return_value = None
307+
308+
# Call the method under test and expect an exception
309+
with self.assertRaises(ValueError) as context:
310+
self.http_client.make_rest_request(
311+
method="GET", endpoint_path="test/endpoint"
312+
)
313+
314+
# Verify the exception message
315+
self.assertEqual(str(context.exception), "No response received from server")
316+
317+
@patch("databricks.sql.auth.thrift_http_client.THttpClient.isOpen")
318+
@patch("databricks.sql.auth.thrift_http_client.THttpClient.open")
319+
@patch(
320+
"databricks.sql.auth.thrift_http_client.THttpClient._check_rest_response_for_error"
321+
)
322+
def test_make_rest_request_with_retry_policy(
323+
self, mock_check_error, mock_open, mock_is_open
324+
):
325+
"""Test the make_rest_request method with a retry policy."""
326+
# Setup mocks
327+
mock_is_open.return_value = True # Connection is already open
328+
329+
# Create a mock response
330+
mock_response = Mock()
331+
mock_response.status = 200
332+
mock_response.reason = "OK"
333+
mock_response.headers = {"Content-Type": "application/json"}
334+
mock_response.data = json.dumps({"result": "success"}).encode("utf-8")
335+
336+
# Configure the mock pool to return our mock response
337+
self.mock_pool.request.return_value = mock_response
338+
339+
# Create a retry policy mock
340+
mock_retry_policy = Mock(spec=DatabricksRetryPolicy)
341+
342+
# Set the retry policy on the client
343+
self.http_client.retry_policy = mock_retry_policy
344+
345+
# Call the method under test
346+
result = self.http_client.make_rest_request(
347+
method="GET", endpoint_path="test/endpoint"
348+
)
349+
350+
# Verify the result
351+
self.assertEqual(result, {"result": "success"})
352+
353+
# Verify the request was made with the retry policy
354+
self.mock_pool.request.assert_called_once()
355+
356+
# Check retries parameter
357+
args, kwargs = self.mock_pool.request.call_args
358+
self.assertEqual(kwargs["retries"], mock_retry_policy)
359+
360+
@patch("databricks.sql.auth.thrift_http_client.THttpClient.isOpen")
361+
@patch("databricks.sql.auth.thrift_http_client.THttpClient.open")
362+
@patch(
363+
"databricks.sql.auth.thrift_http_client.THttpClient._check_rest_response_for_error"
364+
)
365+
def test_make_rest_request_invalid_json_response(
366+
self, mock_check_error, mock_open, mock_is_open
367+
):
368+
"""Test the make_rest_request method with invalid JSON response."""
369+
# Setup mocks
370+
mock_is_open.return_value = True # Connection is already open
371+
372+
# Create a mock response with invalid JSON
373+
mock_response = Mock()
374+
mock_response.status = 200
375+
mock_response.reason = "OK"
376+
mock_response.headers = {"Content-Type": "application/json"}
377+
mock_response.data = "Not a valid JSON".encode("utf-8")
378+
379+
# Configure the mock pool to return our mock response
380+
self.mock_pool.request.return_value = mock_response
381+
382+
# Call the method under test and expect a JSON decode error
383+
with self.assertRaises(json.JSONDecodeError):
384+
self.http_client.make_rest_request(
385+
method="GET", endpoint_path="test/endpoint"
386+
)
387+
388+
# Verify error check was called before the JSON parsing
389+
mock_check_error.assert_called_once_with(200, mock_response.data)
390+
137391

138392
if __name__ == "__main__":
139393
unittest.main()

0 commit comments

Comments
 (0)