mirror of
https://github.com/latinogino/dolibarr-mcp.git
synced 2026-04-12 05:45:35 +02:00
feat: Add comprehensive test suite with unit and integration tests
This commit is contained in:
185
tests/test_dolibarr_client.py
Normal file
185
tests/test_dolibarr_client.py
Normal file
@@ -0,0 +1,185 @@
|
||||
"""Tests for Dolibarr client functionality."""
|
||||
|
||||
import pytest
|
||||
from unittest.mock import AsyncMock, patch
|
||||
|
||||
from dolibarr_mcp.config import Config
|
||||
from dolibarr_mcp.dolibarr_client import DolibarrClient, DolibarrAPIError
|
||||
|
||||
|
||||
class TestDolibarrClient:
|
||||
"""Test cases for the DolibarrClient."""
|
||||
|
||||
def test_config_validation(self):
|
||||
"""Test configuration validation."""
|
||||
# Test valid configuration
|
||||
config = Config(
|
||||
dolibarr_url="https://test.dolibarr.com/api/index.php",
|
||||
api_key="test_key"
|
||||
)
|
||||
assert config.dolibarr_url == "https://test.dolibarr.com/api/index.php"
|
||||
assert config.api_key == "test_key"
|
||||
|
||||
# Test validation
|
||||
config.validate_config() # Should not raise
|
||||
|
||||
# Test invalid URL
|
||||
with pytest.raises(ValueError, match="must start with http"):
|
||||
invalid_config = Config(
|
||||
dolibarr_url="invalid-url",
|
||||
api_key="test_key"
|
||||
)
|
||||
invalid_config.validate_config()
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_client_session_management(self):
|
||||
"""Test client session management."""
|
||||
config = Config(
|
||||
dolibarr_url="https://test.dolibarr.com/api/index.php",
|
||||
api_key="test_key"
|
||||
)
|
||||
|
||||
client = DolibarrClient(config)
|
||||
|
||||
# Test session starts as None
|
||||
assert client.session is None
|
||||
|
||||
# Test session creation
|
||||
await client.start_session()
|
||||
assert client.session is not None
|
||||
|
||||
# Test session cleanup
|
||||
await client.close_session()
|
||||
assert client.session is None
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_context_manager(self):
|
||||
"""Test async context manager functionality."""
|
||||
config = Config(
|
||||
dolibarr_url="https://test.dolibarr.com/api/index.php",
|
||||
api_key="test_key"
|
||||
)
|
||||
|
||||
async with DolibarrClient(config) as client:
|
||||
assert client.session is not None
|
||||
|
||||
# Session should be closed after context exit
|
||||
assert client.session is None
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch('aiohttp.ClientSession.request')
|
||||
async def test_successful_api_request(self, mock_request):
|
||||
"""Test successful API request."""
|
||||
# Mock response
|
||||
mock_response = AsyncMock()
|
||||
mock_response.status = 200
|
||||
mock_response.text.return_value = '{"success": {"code": 200, "dolibarr_version": "21.0.1"}}'
|
||||
mock_request.return_value.__aenter__.return_value = mock_response
|
||||
|
||||
config = Config(
|
||||
dolibarr_url="https://test.dolibarr.com/api/index.php",
|
||||
api_key="test_key"
|
||||
)
|
||||
|
||||
async with DolibarrClient(config) as client:
|
||||
result = await client.get_status()
|
||||
|
||||
assert "success" in result
|
||||
assert result["success"]["code"] == 200
|
||||
assert result["success"]["dolibarr_version"] == "21.0.1"
|
||||
|
||||
@pytest.mark.asyncio
|
||||
@patch('aiohttp.ClientSession.request')
|
||||
async def test_api_error_handling(self, mock_request):
|
||||
"""Test API error handling."""
|
||||
# Mock error response
|
||||
mock_response = AsyncMock()
|
||||
mock_response.status = 404
|
||||
mock_response.reason = "Not Found"
|
||||
mock_response.text.return_value = '{"error": "Object not found"}'
|
||||
mock_request.return_value.__aenter__.return_value = mock_response
|
||||
|
||||
config = Config(
|
||||
dolibarr_url="https://test.dolibarr.com/api/index.php",
|
||||
api_key="test_key"
|
||||
)
|
||||
|
||||
async with DolibarrClient(config) as client:
|
||||
with pytest.raises(DolibarrAPIError) as exc_info:
|
||||
await client.get_customer_by_id(999)
|
||||
|
||||
assert exc_info.value.status_code == 404
|
||||
assert "Object not found" in str(exc_info.value)
|
||||
|
||||
def test_url_building(self):
|
||||
"""Test URL building functionality."""
|
||||
config = Config(
|
||||
dolibarr_url="https://test.dolibarr.com/api/index.php",
|
||||
api_key="test_key"
|
||||
)
|
||||
|
||||
client = DolibarrClient(config)
|
||||
|
||||
# Test with leading slash
|
||||
url = client._build_url("/users")
|
||||
assert url == "https://test.dolibarr.com/api/index.php/users"
|
||||
|
||||
# Test without leading slash
|
||||
url = client._build_url("users")
|
||||
assert url == "https://test.dolibarr.com/api/index.php/users"
|
||||
|
||||
# Test with trailing slash in base URL
|
||||
client.base_url = "https://test.dolibarr.com/api/index.php/"
|
||||
url = client._build_url("users")
|
||||
assert url == "https://test.dolibarr.com/api/index.php/users"
|
||||
|
||||
|
||||
class TestDolibarrAPIError:
|
||||
"""Test cases for DolibarrAPIError."""
|
||||
|
||||
def test_error_creation(self):
|
||||
"""Test error object creation."""
|
||||
error = DolibarrAPIError(
|
||||
message="Test error",
|
||||
status_code=400,
|
||||
response_data={"error": "Bad request"}
|
||||
)
|
||||
|
||||
assert str(error) == "Test error"
|
||||
assert error.status_code == 400
|
||||
assert error.response_data == {"error": "Bad request"}
|
||||
|
||||
def test_error_without_optional_params(self):
|
||||
"""Test error creation without optional parameters."""
|
||||
error = DolibarrAPIError("Simple error")
|
||||
|
||||
assert str(error) == "Simple error"
|
||||
assert error.status_code is None
|
||||
assert error.response_data is None
|
||||
|
||||
|
||||
# Example of how to add integration tests
|
||||
@pytest.mark.integration
|
||||
class TestDolibarrIntegration:
|
||||
"""Integration tests (require real Dolibarr instance)."""
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_real_connection(self):
|
||||
"""Test connection to real Dolibarr instance."""
|
||||
# Skip if no real credentials available
|
||||
try:
|
||||
config = Config.from_env()
|
||||
config.validate_config()
|
||||
except ValueError:
|
||||
pytest.skip("No valid Dolibarr configuration available")
|
||||
|
||||
async with DolibarrClient(config) as client:
|
||||
try:
|
||||
result = await client.get_status()
|
||||
assert "success" in result or "dolibarr_version" in str(result)
|
||||
except DolibarrAPIError as e:
|
||||
pytest.fail(f"API connection failed: {e}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
pytest.main([__file__])
|
||||
Reference in New Issue
Block a user