import unittest
from unittest.mock import Mock, patch
from requests.exceptions import RequestException, Timeout
from olc.remote.http_client import (
HttpClient,
HttpMethod,
Request,
Response,
HttpException,
LoggingInterceptor,
)
class TestRequest(unittest.TestCase):
def test_request_repr(self):
request = Request(method=HttpMethod.GET, url="http://example.com")
self.assertIn("<request: HttpMethod.GET http://example.com>", repr(request))
def test_request_str(self):
request = Request(method=HttpMethod.POST, url="http://example.com/api")
self.assertEqual(str(request), repr(request))
class TestResponse(unittest.TestCase):
def test_response_ok(self):
response = Response(
status_code=200,
url="http://example.com",
headers={},
content=b'{"key": "value"}',
text='{"key": "value"}',
elapsed=0.1,
)
self.assertTrue(response.ok())
def test_response_not_ok(self):
response = Response(
status_code=404,
url="http://example.com",
headers={},
content=b"Not Found",
text="Not Found",
elapsed=0.1,
)
self.assertFalse(response.ok())
def test_response_json(self):
response = Response(
status_code=200,
url="http://example.com",
headers={},
content=b'{"key": "value"}',
text='{"key": "value"}',
elapsed=0.1,
)
self.assertEqual(response.json(), {"key": "value"})
def test_response_json_invalid(self):
response = Response(
status_code=200,
url="http://example.com",
headers={},
content=b"not json",
text="not json",
elapsed=0.1,
)
with self.assertRaises(ValueError):
response.json()
def test_response_repr(self):
response = Response(
status_code=200,
url="http://example.com",
headers={},
content=b"",
text="",
elapsed=0.5,
)
self.assertIn("<response: 200 http://example.com>", repr(response))
class TestHttpException(unittest.TestCase):
def test_http_exception_with_code(self):
exc = HttpException("test error", code=500)
self.assertEqual(exc.message, "test error")
self.assertEqual(exc.code, 500)
def test_http_exception_repr(self):
exc = HttpException("error", code=404)
self.assertIn("HttpException(code=404, message=error)", repr(exc))
class TestHttpClient(unittest.TestCase):
def test_build_url_with_base_url(self):
client = HttpClient(base_url="http://api.example.com")
self.assertEqual(client._build_url("/users"), "http://api.example.com/users")
self.assertEqual(client._build_url("users"), "http://api.example.com/users")
self.assertEqual(client._build_url("http://other.com/test"), "http://other.com/test")
def test_build_url_without_base_url(self):
client = HttpClient()
self.assertEqual(client._build_url("http://example.com"), "http://example.com")
def test_build_url_trailing_slash(self):
client = HttpClient(base_url="http://api.example.com/")
self.assertEqual(client._build_url("/users"), "http://api.example.com/users")
@patch("olc.remote.http_client.requests.request")
def test_get_request(self, mock_request):
mock_response = Mock()
mock_response.status_code = 200
mock_response.url = "http://example.com/test"
mock_response.headers = {"Content-Type": "application/json"}
mock_response.content = b'{"result": "success"}'
mock_response.text = '{"result": "success"}'
mock_request.return_value = mock_response
client = HttpClient()
response = client.get("http://example.com/test")
self.assertEqual(response.status_code, 200)
self.assertEqual(response.url, "http://example.com/test")
self.assertTrue(response.ok())
mock_request.assert_called_once_with(
method="GET",
url="http://example.com/test",
headers=None,
params=None,
data=None,
json=None,
timeout=(10, 30),
)
@patch("olc.remote.http_client.requests.request")
def test_post_request(self, mock_request):
mock_response = Mock()
mock_response.status_code = 201
mock_response.url = "http://example.com/create"
mock_response.headers = {"Content-Type": "application/json"}
mock_response.content = b'{"id": 1}'
mock_response.text = '{"id": 1}'
mock_request.return_value = mock_response
client = HttpClient()
response = client.post(
"http://example.com/create",
json_data={"name": "test"},
headers={"Authorization": "Bearer token"},
)
self.assertEqual(response.status_code, 201)
mock_request.assert_called_once()
call_kwargs = mock_request.call_args[1]
self.assertEqual(call_kwargs["method"], "POST")
self.assertEqual(call_kwargs["json"], {"name": "test"})
self.assertEqual(call_kwargs["headers"], {"Authorization": "Bearer token"})
@patch("olc.remote.http_client.requests.request")
def test_put_request(self, mock_request):
mock_response = Mock()
mock_response.status_code = 200
mock_response.url = "http://example.com/update/1"
mock_response.headers = {}
mock_response.content = b'{"updated": true}'
mock_response.text = '{"updated": true}'
mock_request.return_value = mock_response
client = HttpClient()
response = client.put(
"http://example.com/update/1",
json_data={"name": "updated"},
)
self.assertEqual(response.status_code, 200)
mock_request.assert_called_once()
call_kwargs = mock_request.call_args[1]
self.assertEqual(call_kwargs["method"], "PUT")
@patch("olc.remote.http_client.requests.request")
def test_delete_request(self, mock_request):
mock_response = Mock()
mock_response.status_code = 204
mock_response.url = "http://example.com/delete/1"
mock_response.headers = {}
mock_response.content = b""
mock_response.text = ""
mock_request.return_value = mock_response
client = HttpClient()
response = client.delete("http://example.com/delete/1")
self.assertEqual(response.status_code, 204)
mock_request.assert_called_once()
call_kwargs = mock_request.call_args[1]
self.assertEqual(call_kwargs["method"], "DELETE")
@patch("olc.remote.http_client.requests.request")
def test_get_json_success(self, mock_request):
mock_response = Mock()
mock_response.status_code = 200
mock_response.url = "http://example.com/data"
mock_response.headers = {"Content-Type": "application/json"}
mock_response.content = b'{"data": "value"}'
mock_response.text = '{"data": "value"}'
mock_request.return_value = mock_response
client = HttpClient()
result = client.get_json("http://example.com/data")
self.assertEqual(result, {"data": "value"})
@patch("olc.remote.http_client.requests.request")
def test_get_json_failure(self, mock_request):
mock_response = Mock()
mock_response.status_code = 404
mock_response.url = "http://example.com/data"
mock_response.headers = {"Content-Type": "application/json"}
mock_response.content = b'{"error": "Not Found"}'
mock_response.text = '{"error": "Not Found"}'
mock_request.return_value = mock_response
client = HttpClient()
with self.assertRaises(HttpException) as context:
client.get_json("http://example.com/data")
self.assertIn("get json failed", str(context.exception))
self.assertEqual(context.exception.code, 404)
@patch("olc.remote.http_client.requests.request")
def test_get_json_invalid_json(self, mock_request):
mock_response = Mock()
mock_response.status_code = 200
mock_response.url = "http://example.com/data"
mock_response.headers = {}
mock_response.content = b"Not a JSON"
mock_response.text = "Not a JSON"
mock_request.return_value = mock_response
client = HttpClient()
with self.assertRaises(HttpException) as context:
client.get_json("http://example.com/data")
self.assertIn("response is not valid json", str(context.exception))
@patch("olc.remote.http_client.requests.request")
def test_post_json_success(self, mock_request):
mock_response = Mock()
mock_response.status_code = 200
mock_response.url = "http://example.com/post"
mock_response.headers = {"Content-Type": "application/json"}
mock_response.content = b'{"result": "success"}'
mock_response.text = '{"result": "success"}'
mock_request.return_value = mock_response
client = HttpClient()
result = client.post_json("http://example.com/post", json_data={"key": "value"})
self.assertEqual(result, {"result": "success"})
@patch("olc.remote.http_client.requests.request")
def test_post_json_failure(self, mock_request):
mock_response = Mock()
mock_response.status_code = 500
mock_response.url = "http://example.com/post"
mock_response.headers = {"Content-Type": "application/json"}
mock_response.content = b'{"error": "Internal Server Error"}'
mock_response.text = '{"error": "Internal Server Error"}'
mock_request.return_value = mock_response
client = HttpClient()
with self.assertRaises(HttpException) as context:
client.post_json("http://example.com/post", json_data={"key": "value"})
self.assertIn("post json failed", str(context.exception))
self.assertEqual(context.exception.code, 500)
@patch("olc.remote.http_client.requests.request")
def test_post_json_invalid_json(self, mock_request):
mock_response = Mock()
mock_response.status_code = 200
mock_response.url = "http://example.com/post"
mock_response.headers = {}
mock_response.content = b"Not a JSON"
mock_response.text = "Not a JSON"
mock_request.return_value = mock_response
client = HttpClient()
with self.assertRaises(HttpException) as context:
client.post_json("http://example.com/post", json_data={"key": "value"})
self.assertIn("response is not valid json", str(context.exception))
@patch("olc.remote.http_client.requests.request")
def test_request_timeout(self, mock_request):
mock_request.side_effect = Timeout("Connection timed out")
client = HttpClient(timeout=(1, 1))
with self.assertRaises(HttpException) as context:
client.get("http://example.com/test")
self.assertIn("request failed", str(context.exception))
@patch("olc.remote.http_client.requests.request")
def test_request_network_error(self, mock_request):
mock_request.side_effect = RequestException("Network error")
client = HttpClient()
with self.assertRaises(HttpException):
client.get("http://example.com/test")
@patch("olc.remote.http_client.requests.request")
def test_retry_on_server_error(self, mock_request):
mock_response_500 = Mock()
mock_response_500.status_code = 500
mock_response_500.url = "http://example.com/test"
mock_response_500.headers = {}
mock_response_500.content = b"Internal Server Error"
mock_response_500.text = "Internal Server Error"
mock_response_200 = Mock()
mock_response_200.status_code = 200
mock_response_200.url = "http://example.com/test"
mock_response_200.headers = {}
mock_response_200.content = b'{"success": true}'
mock_response_200.text = '{"success": true}'
mock_request.side_effect = [mock_response_500, mock_response_200]
client = HttpClient(max_retries=1)
response = client.get("http://example.com/test")
self.assertEqual(response.status_code, 200)
self.assertEqual(mock_request.call_count, 2)
@patch("olc.remote.http_client.requests.request")
def test_retry_for_post(self, mock_request):
mock_response_500 = Mock()
mock_response_500.status_code = 500
mock_response_500.url = "http://example.com/test"
mock_response_500.headers = {}
mock_response_500.content = b"Internal Server Error"
mock_response_500.text = "Internal Server Error"
mock_request.return_value = mock_response_500
client = HttpClient(max_retries=3)
response = client.post("http://example.com/test")
self.assertEqual(response.status_code, 500)
self.assertEqual(mock_request.call_count, 4)
def test_add_interceptor(self):
client = HttpClient(interceptors=[])
interceptor = LoggingInterceptor()
client.add_interceptor(interceptor)
self.assertEqual(len(client.interceptors), 1)
self.assertEqual(client.interceptors[0], interceptor)
def test_add_none_interceptor(self):
client = HttpClient(interceptors=[])
client.add_interceptor(None)
self.assertEqual(len(client.interceptors), 0)
if __name__ == '__main__':
unittest.main()