Model/backend/magic_plan/tests/test_magic_plan_client.py
2026-05-08 14:08:56 +00:00

226 lines
6.1 KiB
Python

import json
from pathlib import Path
from typing import Any
from unittest.mock import MagicMock, patch
import pytest
import requests
from backend.magic_plan.magic_plan_client import MagicPlanClient
from datatypes.magicplan.api.response import MagicPlanPlan, PlansListResponse
FIXTURE_DIR = Path(__file__).parents[2] / "magic_plan"
BASE_URL = "https://cloud.magicplan.app/api/v2"
CUSTOMER_ID = "test-customer"
API_KEY = "test-key"
def _load_fixture(name: str) -> dict[str, Any]:
return json.loads((FIXTURE_DIR / name).read_text())
def _make_client(mock_session: MagicMock) -> MagicPlanClient:
with patch(
"backend.magic_plan.magic_plan_client.requests.Session",
return_value=mock_session,
):
return MagicPlanClient(customer_id=CUSTOMER_ID, api_key=API_KEY)
@pytest.fixture()
def mock_session() -> MagicMock:
return MagicMock()
@pytest.fixture()
def client(mock_session: MagicMock) -> MagicPlanClient:
return _make_client(mock_session)
# --- constructor ---
def test_customer_header_set_on_session(mock_session: MagicMock) -> None:
# Act
_make_client(mock_session)
# Assert
mock_session.headers.update.assert_called_once_with({"customer": CUSTOMER_ID})
# --- get_plans ---
def test_get_plans_calls_correct_url(
client: MagicPlanClient, mock_session: MagicMock
) -> None:
# Arrange
plans_data = _load_fixture("magicplan_api_plans_response_example.json")["data"]
mock_session.get.return_value.json.return_value = {
"message": "OK",
"data": plans_data,
}
# Act
client.get_plans()
# Assert
mock_session.get.assert_called_once_with(
f"{BASE_URL}/plans", params={"key": API_KEY}
)
def test_get_plans_calls_raise_for_status(
client: MagicPlanClient, mock_session: MagicMock
) -> None:
# Arrange
plans_data = _load_fixture("magicplan_api_plans_response_example.json")["data"]
mock_session.get.return_value.json.return_value = {
"message": "OK",
"data": plans_data,
}
# Act
client.get_plans()
# Assert
mock_session.get.return_value.raise_for_status.assert_called_once()
def test_get_plans_returns_plans_list_response(
client: MagicPlanClient, mock_session: MagicMock
) -> None:
# Arrange
plans_data = _load_fixture("magicplan_api_plans_response_example.json")["data"]
mock_session.get.return_value.json.return_value = {
"message": "OK",
"data": plans_data,
}
# Act
result = client.get_plans()
# Assert
assert isinstance(result, PlansListResponse)
assert len(result.plans) == 1
def test_get_plans_propagates_http_error(
client: MagicPlanClient, mock_session: MagicMock
) -> None:
# Arrange
mock_session.get.return_value.raise_for_status.side_effect = requests.HTTPError(
"404"
)
# Act / Assert
with pytest.raises(requests.HTTPError):
client.get_plans()
# --- get_plan ---
def test_get_plan_calls_correct_url(
client: MagicPlanClient, mock_session: MagicMock
) -> None:
# Arrange
plan_data = _load_fixture("magicplan_api_plan_response_example.json")["data"]
mock_session.get.return_value.json.return_value = {
"message": "OK",
"data": plan_data,
}
plan_id = "a7285ed1-878d-47eb-8aa6-85ef9e187516"
# Act
client.get_plan(plan_id)
# Assert
mock_session.get.assert_called_once_with(
f"{BASE_URL}/plans/{plan_id}", params={"key": API_KEY}
)
def test_get_plan_calls_raise_for_status(
client: MagicPlanClient, mock_session: MagicMock
) -> None:
# Arrange
plan_data = _load_fixture("magicplan_api_plan_response_example.json")["data"]
mock_session.get.return_value.json.return_value = {
"message": "OK",
"data": plan_data,
}
# Act
client.get_plan("a7285ed1-878d-47eb-8aa6-85ef9e187516")
# Assert
mock_session.get.return_value.raise_for_status.assert_called_once()
def test_get_plan_returns_magic_plan(
client: MagicPlanClient, mock_session: MagicMock
) -> None:
# Arrange
plan_data = _load_fixture("magicplan_api_plan_response_example.json")["data"]
mock_session.get.return_value.json.return_value = {
"message": "OK",
"data": plan_data,
}
# Act
result = client.get_plan("a7285ed1-878d-47eb-8aa6-85ef9e187516")
# Assert
assert isinstance(result, MagicPlanPlan)
assert result.plan.id == "a7285ed1-878d-47eb-8aa6-85ef9e187516"
def test_get_plan_propagates_http_error(
client: MagicPlanClient, mock_session: MagicMock
) -> None:
# Arrange
mock_session.get.return_value.raise_for_status.side_effect = requests.HTTPError(
"500"
)
# Act / Assert
with pytest.raises(requests.HTTPError):
client.get_plan("some-id")
# --- get_plan_raw ---
def test_get_plan_raw_returns_bytes(
client: MagicPlanClient, mock_session: MagicMock
) -> None:
# Arrange
mock_session.get.return_value.content = b'{"data": "raw"}'
plan_id = "a7285ed1-878d-47eb-8aa6-85ef9e187516"
# Act
result = client.get_plan_raw(plan_id)
# Assert
assert isinstance(result, bytes)
def test_get_plan_raw_calls_correct_url(
client: MagicPlanClient, mock_session: MagicMock
) -> None:
# Arrange
mock_session.get.return_value.content = b"{}"
plan_id = "a7285ed1-878d-47eb-8aa6-85ef9e187516"
# Act
client.get_plan_raw(plan_id)
# Assert
mock_session.get.assert_called_once_with(
f"{BASE_URL}/plans/{plan_id}", params={"key": API_KEY}
)
def test_get_plan_raw_calls_raise_for_status(
client: MagicPlanClient, mock_session: MagicMock
) -> None:
# Arrange
mock_session.get.return_value.content = b"{}"
# Act
client.get_plan_raw("a7285ed1-878d-47eb-8aa6-85ef9e187516")
# Assert
mock_session.get.return_value.raise_for_status.assert_called_once()
def test_get_plan_raw_propagates_http_error(
client: MagicPlanClient, mock_session: MagicMock
) -> None:
# Arrange
mock_session.get.return_value.raise_for_status.side_effect = requests.HTTPError(
"500"
)
# Act / Assert
with pytest.raises(requests.HTTPError):
client.get_plan_raw("some-id")