"""Unit tests for devx.utils.api.APIClient.""" from __future__ import annotations from unittest.mock import MagicMock, patch import pytest import requests from devx.utils.api import APIClient class TestAPIClient: @patch("devx.utils.api.requests.request") def test_get(self, mock_req): mock_resp = MagicMock() mock_resp.raise_for_status.return_value = None mock_req.return_value = mock_resp client = APIClient("https://api.example.com", {"Authorization": "Bearer token"}) result = client.get("/users") assert result is mock_resp mock_req.assert_called_once_with( "GET", "https://api.example.com/users", headers={"Authorization": "Bearer token"}, timeout=30, verify=True, ) @patch("devx.utils.api.requests.request") def test_post(self, mock_req): mock_resp = MagicMock() mock_resp.raise_for_status.return_value = None mock_req.return_value = mock_resp client = APIClient("https://api.example.com", {}) client.post("/users", json={"name": "alice"}) mock_req.assert_called_once_with( "POST", "https://api.example.com/users", headers={}, timeout=30, verify=True, json={"name": "alice"}, ) @patch("devx.utils.api.requests.request") def test_put(self, mock_req): mock_resp = MagicMock() mock_resp.raise_for_status.return_value = None mock_req.return_value = mock_resp client = APIClient("https://api.example.com", {}) client.put("/users/1", json={"name": "bob"}) mock_req.assert_called_once_with( "PUT", "https://api.example.com/users/1", headers={}, timeout=30, verify=True, json={"name": "bob"}, ) @patch("devx.utils.api.requests.request") def test_delete(self, mock_req): mock_resp = MagicMock() mock_resp.raise_for_status.return_value = None mock_req.return_value = mock_resp client = APIClient("https://api.example.com", {}) client.delete("/users/1") mock_req.assert_called_once_with( "DELETE", "https://api.example.com/users/1", headers={}, timeout=30, verify=True, ) @patch("devx.utils.api.requests.request") def test_patch(self, mock_req): mock_resp = MagicMock() mock_resp.raise_for_status.return_value = None mock_req.return_value = mock_resp client = APIClient("https://api.example.com", {}) client.patch("/users/1", json={"name": "carol"}) mock_req.assert_called_once_with( "PATCH", "https://api.example.com/users/1", headers={}, timeout=30, verify=True, json={"name": "carol"}, ) @patch("devx.utils.api.requests.request") def test_auth_tuple(self, mock_req): mock_resp = MagicMock() mock_resp.raise_for_status.return_value = None mock_req.return_value = mock_resp client = APIClient("https://api.example.com", {}, auth=("admin", "pass")) client.get("/data") mock_req.assert_called_once_with( "GET", "https://api.example.com/data", headers={}, timeout=30, verify=True, auth=("admin", "pass"), ) @patch("devx.utils.api.requests.request") def test_custom_timeout_and_verify(self, mock_req): mock_resp = MagicMock() mock_resp.raise_for_status.return_value = None mock_req.return_value = mock_resp client = APIClient("https://api.example.com", {}, timeout=60, verify=False) client.get("/data") mock_req.assert_called_once_with( "GET", "https://api.example.com/data", headers={}, timeout=60, verify=False, ) @patch("devx.utils.api.requests.request") def test_raises_on_error(self, mock_req): mock_resp = MagicMock() mock_resp.raise_for_status.side_effect = requests.HTTPError("500") mock_req.return_value = mock_resp client = APIClient("https://api.example.com", {}) with pytest.raises(requests.HTTPError): client.get("/fail") @patch("devx.utils.api.requests.request") def test_strips_trailing_slash(self, mock_req): mock_resp = MagicMock() mock_resp.raise_for_status.return_value = None mock_req.return_value = mock_resp client = APIClient("https://api.example.com/", {}) client.get("/users") mock_req.assert_called_once_with( "GET", "https://api.example.com/users", headers={}, timeout=30, verify=True, ) @patch("devx.utils.api.requests.request") def test_kwargs_override_defaults(self, mock_req): mock_resp = MagicMock() mock_resp.raise_for_status.return_value = None mock_req.return_value = mock_resp client = APIClient("https://api.example.com", {}, timeout=30) client.get("/slow", timeout=120) mock_req.assert_called_once_with( "GET", "https://api.example.com/slow", headers={}, timeout=120, verify=True, ) @patch("devx.utils.api.requests.request") def test_no_auth_when_not_set(self, mock_req): mock_resp = MagicMock() mock_resp.raise_for_status.return_value = None mock_req.return_value = mock_resp client = APIClient("https://api.example.com", {}) client.get("/data") call_kwargs = mock_req.call_args.kwargs assert "auth" not in call_kwargs