import pytest import pytest_asyncio from unittest.mock import MagicMock, patch import json from contextlib import asynccontextmanager import sys from pathlib import Path sys.path.insert(0, str(Path(__file__).parent / "src")) @pytest.fixture def mock_client(): return MagicMock() @pytest.fixture def mock_service_provider(mock_client): provider_mock = MagicMock() mock_response = MagicMock() mock_response.is_error = False mock_response.data = [] provider_mock.party.find_by_identifier.return_value = mock_response provider_mock.party.create.return_value = mock_response provider_mock.schedule.create.return_value = mock_response provider_mock.service_center.find_all.return_value = mock_response provider_mock.product.find_salable.return_value = mock_response return provider_mock @pytest.fixture def server_with_mocks(mock_service_provider): with patch("tryton_mcp.server._service_provider", mock_service_provider): yield mock_service_provider @pytest.mark.asyncio class TestFindCustomerByIdentifier: async def test_find_customer_success(self, server_with_mocks): from tryton_mcp.server import find_customer_by_identifier server_with_mocks.party.find_by_identifier.return_value.data = [ {"id": 1, "party": {"name": "Test Customer"}} ] result = find_customer_by_identifier("12345") assert result == [{"id": 1, "party": {"name": "Test Customer"}}] server_with_mocks.party.find_by_identifier.assert_called_once_with("12345") async def test_find_customer_not_found(self, server_with_mocks): from tryton_mcp.server import find_customer_by_identifier server_with_mocks.party.find_by_identifier.return_value.is_error = True with pytest.raises(Exception, match="Customer with identifier"): find_customer_by_identifier("invalid") @pytest.mark.asyncio class TestCreateCustomer: async def test_create_customer_success(self, server_with_mocks): from tryton_mcp.server import create_customer server_with_mocks.party.create.return_value.data = [1] result = create_customer("New Customer", []) assert result == [1] async def test_create_customer_invalid_name(self, server_with_mocks): from tryton_mcp.server import create_customer from pydantic import ValidationError with pytest.raises(ValidationError): create_customer("", []) @pytest.mark.asyncio class TestCreateSchedule: async def test_create_schedule_success(self, server_with_mocks): from tryton_mcp.server import create_schedule server_with_mocks.schedule.create.return_value.data = [1] result = create_schedule( professional=6, description="Test appointment", customer=4, date="2026-03-15T10:00:00", service_center=11, ) assert result == [1] async def test_create_schedule_failure(self, server_with_mocks): from tryton_mcp.server import create_schedule server_with_mocks.schedule.create.return_value.is_error = True server_with_mocks.schedule.create.return_value.error = "Create failed" with pytest.raises(Exception, match="Failed to create schedule"): create_schedule( professional=6, description="Test appointment", customer=4, date="2026-03-15T10:00:00", service_center=11, ) async def test_create_schedule_invalid_date_format(self, server_with_mocks): from tryton_mcp.server import create_schedule from pydantic import ValidationError with pytest.raises(ValidationError): create_schedule( professional=6, description="Test appointment", customer=4, date="invalid-date", service_center=11, ) async def test_create_schedule_invalid_professional(self, server_with_mocks): from tryton_mcp.server import create_schedule from pydantic import ValidationError with pytest.raises(ValidationError): create_schedule( professional=0, description="Test appointment", customer=4, date="2026-03-15T10:00:00", service_center=11, ) @pytest.mark.asyncio class TestFindServiceCenters: async def test_find_service_centers_success(self, server_with_mocks): from tryton_mcp.server import find_service_centers server_with_mocks.service_center.find_all.return_value.data = [ {"id": 11, "name": "Center 1", "address.street": "Street 1"} ] result = find_service_centers() assert result == [{"id": 11, "name": "Center 1", "address.street": "Street 1"}] server_with_mocks.service_center.find_all.assert_called_once_with( offset=0, limit=None ) async def test_find_service_centers_with_pagination(self, server_with_mocks): from tryton_mcp.server import find_service_centers find_service_centers(offset=10, limit=5) server_with_mocks.service_center.find_all.assert_called_once_with( offset=10, limit=5 ) async def test_find_service_centers_failure(self, server_with_mocks): from tryton_mcp.server import find_service_centers server_with_mocks.service_center.find_all.return_value.is_error = True server_with_mocks.service_center.find_all.return_value.error = "Search failed" with pytest.raises(Exception, match="Failed to find service centers"): find_service_centers() @pytest.mark.asyncio class TestFindProductsAndServices: async def test_find_products_and_services_success(self, server_with_mocks): from tryton_mcp.server import find_products_and_services server_with_mocks.product.find_salable.return_value.data = [ {"id": 1, "name": "Product 1", "list_price": 100.0} ] result = find_products_and_services() assert result == [{"id": 1, "name": "Product 1", "list_price": 100.0}] server_with_mocks.product.find_salable.assert_called_once_with( offset=0, limit=None ) async def test_find_products_with_pagination(self, server_with_mocks): from tryton_mcp.server import find_products_and_services find_products_and_services(offset=5, limit=10) server_with_mocks.product.find_salable.assert_called_once_with( offset=5, limit=10 ) async def test_find_products_failure(self, server_with_mocks): from tryton_mcp.server import find_products_and_services server_with_mocks.product.find_salable.return_value.is_error = True server_with_mocks.product.find_salable.return_value.error = "Search failed" with pytest.raises(Exception, match="Failed to find products"): find_products_and_services()