"""Tests for the Cisco API client."""
import pytest
from cisco_catalog_mcp.client import CiscoCatalogClient, CiscoAPIError
from cisco_catalog_mcp.config import Settings
class TestCiscoCatalogClient:
"""Tests for CiscoCatalogClient."""
def test_client_initialization(self, mock_settings: Settings) -> None:
"""Test client initializes correctly."""
client = CiscoCatalogClient(mock_settings)
assert client.settings == mock_settings
assert client._token is None
assert client._token_expires_at is None
def test_build_get_item_info_xml(self, mock_settings: Settings) -> None:
"""Test XML request building."""
client = CiscoCatalogClient(mock_settings)
xml = client._build_get_item_info_xml(
skus=["C9300-24T-E"],
price_list="GLUS",
attributes=["ListPrice", "ProductType"],
)
assert '<?xml version="1.0" encoding="UTF-8"?>' in xml
assert "<GetCatalog" in xml
assert "<ID>C9300-24T-E</ID>" in xml
assert 'typeCode="PriceListShortName">GLUS</ID>' in xml
assert 'typeCode="ListPrice"/>' in xml
assert 'typeCode="ProductType"/>' in xml
def test_build_get_item_info_xml_multiple_skus(self, mock_settings: Settings) -> None:
"""Test XML building with multiple SKUs."""
client = CiscoCatalogClient(mock_settings)
xml = client._build_get_item_info_xml(
skus=["C9300-24T-E", "C9300-48T-E", "WS-C3850-24T-S"],
price_list="GLUS",
attributes=["ListPrice"],
)
assert "<ID>C9300-24T-E</ID>" in xml
assert "<ID>C9300-48T-E</ID>" in xml
assert "<ID>WS-C3850-24T-S</ID>" in xml
def test_parse_item_response(
self, mock_settings: Settings, sample_item_response: dict
) -> None:
"""Test parsing of item information response."""
client = CiscoCatalogClient(mock_settings)
results = client._parse_item_response(sample_item_response)
assert len(results) == 1
result = results[0]
assert result["sku"] == "C9300-24T-E"
assert "Catalyst 9300" in result["description"]
assert result["list_price"] == "4500.00"
assert result["currency"] == "USD"
assert result["product_type"] == "Hardware"
assert result["erp_family"] == "SWITCHES"
assert result["width"] == "17.5"
assert result["weight"] == "12.5"
def test_parse_item_response_error(
self, mock_settings: Settings, sample_error_response: dict
) -> None:
"""Test parsing handles error responses."""
client = CiscoCatalogClient(mock_settings)
with pytest.raises(CiscoAPIError) as exc_info:
client._parse_item_response(sample_error_response)
assert exc_info.value.code == "CC003H"
def test_parse_mapped_service_response(
self, mock_settings: Settings, sample_mapped_service_response: dict
) -> None:
"""Test parsing of mapped service response."""
client = CiscoCatalogClient(mock_settings)
results = client._parse_mapped_service_response(sample_mapped_service_response)
assert len(results) == 1
result = results[0]
assert result["sku"] == "C9300-24T-E"
assert len(result["services"]) == 2
# Check first service
svc1 = result["services"][0]
assert svc1["service_program"] == "SNTC"
assert svc1["service_level"] == "8X5XNBD"
assert svc1["service_sku"] == "CON-SNT-C93002TE"
assert svc1["price"] == "450.00"
def test_to_snake_case(self, mock_settings: Settings) -> None:
"""Test CamelCase to snake_case conversion."""
client = CiscoCatalogClient(mock_settings)
assert client._to_snake_case("ProductType") == "product_type"
assert client._to_snake_case("ERPFamily") == "erp_family"
assert client._to_snake_case("ListPrice") == "list_price"
assert client._to_snake_case("UNSPSCCode") == "unspsc_code"
assert client._to_snake_case("EndOfSaleDate") == "end_of_sale_date"
def test_get_text_various_formats(self, mock_settings: Settings) -> None:
"""Test text extraction from various response formats."""
client = CiscoCatalogClient(mock_settings)
# String
assert client._get_text("simple") == "simple"
# Dict with #text
assert client._get_text({"#text": "value1"}) == "value1"
# Dict with $
assert client._get_text({"$": "value2"}) == "value2"
# Dict with value
assert client._get_text({"value": "value3"}) == "value3"
# None
assert client._get_text(None) is None
# Number
assert client._get_text(123) == "123"
def test_clear_token(self, mock_settings: Settings) -> None:
"""Test token clearing."""
client = CiscoCatalogClient(mock_settings)
client._token = "test_token"
client._token_expires_at = "2024-01-15T10:00:00"
client._clear_token()
assert client._token is None
assert client._token_expires_at is None
class TestCiscoAPIError:
"""Tests for CiscoAPIError exception."""
def test_error_creation(self) -> None:
"""Test error creation and message formatting."""
error = CiscoAPIError("CC003H", "Service cannot provide any requested data")
assert error.code == "CC003H"
assert error.message == "Service cannot provide any requested data"
assert str(error) == "CC003H: Service cannot provide any requested data"