markitect-main/tests/unit/llm/test_http.py

76 lines
2.9 KiB
Python
Raw Normal View History

"""Tests for markitect.llm._http."""
import json
import urllib.error
from unittest import mock
import pytest
from markitect.llm._http import post_json
from markitect.llm.exceptions import LLMAPIError, LLMRateLimitError, LLMTimeoutError
class TestPostJson:
def _mock_urlopen(self, response_body: dict, status: int = 200):
"""Return a context-manager mock for urllib.request.urlopen."""
body_bytes = json.dumps(response_body).encode()
resp = mock.MagicMock()
resp.read.return_value = body_bytes
resp.__enter__ = mock.MagicMock(return_value=resp)
resp.__exit__ = mock.MagicMock(return_value=False)
return resp
@mock.patch("markitect.llm._http.urllib.request.urlopen")
def test_success(self, mock_urlopen):
expected = {"choices": [{"message": {"content": "hi"}}]}
mock_urlopen.return_value = self._mock_urlopen(expected)
result = post_json("https://api.test/v1", {"prompt": "hello"})
assert result == expected
@mock.patch("markitect.llm._http.urllib.request.urlopen")
def test_429_raises_rate_limit(self, mock_urlopen):
exc = urllib.error.HTTPError(
"https://api.test/v1", 429, "Too Many Requests", {}, None
)
exc.read = mock.MagicMock(return_value=b"rate limited")
mock_urlopen.side_effect = exc
with pytest.raises(LLMRateLimitError) as exc_info:
post_json("https://api.test/v1", {})
assert exc_info.value.status_code == 429
@mock.patch("markitect.llm._http.urllib.request.urlopen")
def test_500_raises_api_error(self, mock_urlopen):
exc = urllib.error.HTTPError(
"https://api.test/v1", 500, "Internal Server Error", {}, None
)
exc.read = mock.MagicMock(return_value=b"server error")
mock_urlopen.side_effect = exc
with pytest.raises(LLMAPIError) as exc_info:
post_json("https://api.test/v1", {})
assert exc_info.value.status_code == 500
@mock.patch("markitect.llm._http.urllib.request.urlopen")
def test_timeout_raises_timeout_error(self, mock_urlopen):
exc = urllib.error.URLError("timed out")
mock_urlopen.side_effect = exc
with pytest.raises(LLMTimeoutError):
post_json("https://api.test/v1", {})
@mock.patch("markitect.llm._http.urllib.request.urlopen")
def test_generic_url_error_raises_api_error(self, mock_urlopen):
exc = urllib.error.URLError("connection refused")
mock_urlopen.side_effect = exc
with pytest.raises(LLMAPIError):
post_json("https://api.test/v1", {})
@mock.patch("markitect.llm._http.urllib.request.urlopen")
def test_python_timeout_error(self, mock_urlopen):
mock_urlopen.side_effect = TimeoutError("timed out")
with pytest.raises(LLMTimeoutError):
post_json("https://api.test/v1", {})