mcp-arduino/tests/test_integration.py
Ryan Malloy eb524b8c1d Major project refactor: Rename to mcp-arduino with smart client capabilities
BREAKING CHANGES:
- Package renamed from mcp-arduino-server to mcp-arduino
- Command changed to 'mcp-arduino' (was 'mcp-arduino-server')
- Repository moved to git.supported.systems/MCP/mcp-arduino

NEW FEATURES:
 Smart client capability detection and dual-mode sampling support
 Intelligent WireViz templates with component-specific circuits (LED, motor, sensor, button, display)
 Client debug tools for MCP capability inspection
 Enhanced error handling with progressive enhancement patterns

IMPROVEMENTS:
🧹 Major repository cleanup - removed 14+ experimental files and tests
📝 Consolidated and reorganized documentation
🐛 Fixed import issues and applied comprehensive linting with ruff
📦 Updated author information to Ryan Malloy (ryan@supported.systems)
🔧 Fixed package version references in startup code

TECHNICAL DETAILS:
- Added dual-mode WireViz: AI generation for sampling clients, smart templates for others
- Implemented client capability detection via MCP handshake inspection
- Created progressive enhancement pattern for universal MCP client compatibility
- Organized test files into proper structure (tests/examples/)
- Applied comprehensive code formatting and lint fixes

The server now provides excellent functionality for ALL MCP clients regardless
of their sampling capabilities, while preserving advanced features for clients
that support them.

Version: 2025.09.27.1
2025-09-27 20:16:43 -06:00

204 lines
7.8 KiB
Python

"""
Integration tests for the Arduino MCP Server (cleaned version)
These tests verify server architecture and component integration
without requiring full MCP protocol simulation.
"""
import pytest
from src.mcp_arduino_server.config import ArduinoServerConfig
from src.mcp_arduino_server.server_refactored import create_server
class TestServerIntegration:
"""Test suite for server architecture integration"""
@pytest.fixture
def test_config(self, tmp_path):
"""Create test configuration with temporary directories"""
return ArduinoServerConfig(
arduino_cli_path="/usr/bin/arduino-cli",
sketches_base_dir=tmp_path / "sketches",
build_temp_dir=tmp_path / "build",
wireviz_path="/usr/bin/wireviz",
command_timeout=30,
enable_client_sampling=True
)
@pytest.fixture
def mcp_server(self, test_config):
"""Create a test MCP server instance"""
return create_server(test_config)
def test_server_creation(self, test_config):
"""Test that server creates successfully with all components"""
server = create_server(test_config)
assert server is not None
assert server.name == "Arduino Development Server"
# Verify directories were created
assert test_config.sketches_base_dir.exists()
assert test_config.build_temp_dir.exists()
@pytest.mark.asyncio
async def test_server_tools_registration(self, mcp_server):
"""Test that all expected tools are registered"""
# Get all registered tools
tools = await mcp_server.get_tools()
tool_names = list(tools.keys())
# Verify sketch tools
sketch_tools = [name for name in tool_names if name.startswith('arduino_') and 'sketch' in name]
assert len(sketch_tools) >= 5 # create, list, read, write, compile, upload
# Verify library tools
library_tools = [name for name in tool_names if 'librar' in name]
assert len(library_tools) >= 3 # search, install, list examples
# Verify board tools
board_tools = [name for name in tool_names if 'board' in name or 'core' in name]
assert len(board_tools) >= 4 # list boards, search boards, install core, list cores
# Verify debug tools
debug_tools = [name for name in tool_names if 'debug' in name]
assert len(debug_tools) >= 5 # start, interactive, break, run, print, etc.
# Verify WireViz tools
wireviz_tools = [name for name in tool_names if 'wireviz' in name]
assert len(wireviz_tools) >= 2 # generate from yaml, generate from description
@pytest.mark.asyncio
async def test_server_resources_registration(self, mcp_server):
"""Test that all expected resources are registered"""
# Get all registered resources
resources = await mcp_server.get_resources()
resource_uris = list(resources.keys())
expected_resources = [
"arduino://sketches",
"arduino://libraries",
"arduino://boards",
"arduino://debug/sessions",
"wireviz://instructions",
"server://info"
]
for expected_uri in expected_resources:
assert expected_uri in resource_uris, f"Resource {expected_uri} not found in {resource_uris}"
@pytest.mark.asyncio
async def test_server_info_resource(self, mcp_server):
"""Test the server info resource provides correct information"""
# Get the server info resource
info_resource = await mcp_server.get_resource("server://info")
info_content = await info_resource.read()
assert "Arduino Development Server" in info_content
assert "Configuration:" in info_content
assert "Components:" in info_content
assert "Available Tool Categories:" in info_content
assert "Sketch Tools:" in info_content
assert "Library Tools:" in info_content
assert "Board Tools:" in info_content
assert "Debug Tools:" in info_content
assert "WireViz Tools:" in info_content
def test_component_isolation(self, test_config):
"""Test that components can be created independently"""
from src.mcp_arduino_server.components import (
ArduinoBoard,
ArduinoDebug,
ArduinoLibrary,
ArduinoSketch,
WireViz,
)
# Each component should initialize without errors
sketch = ArduinoSketch(test_config)
library = ArduinoLibrary(test_config)
board = ArduinoBoard(test_config)
debug = ArduinoDebug(test_config)
wireviz = WireViz(test_config)
# Components should have expected attributes
assert hasattr(sketch, 'config')
assert hasattr(library, 'config')
assert hasattr(board, 'config')
assert hasattr(debug, 'config')
assert hasattr(wireviz, 'config')
def test_configuration_flexibility(self, tmp_path):
"""Test that server handles various configuration scenarios"""
# Test minimal configuration
minimal_config = ArduinoServerConfig(
sketches_base_dir=tmp_path / "minimal"
)
server1 = create_server(minimal_config)
assert server1 is not None
# Test custom configuration
custom_config = ArduinoServerConfig(
arduino_cli_path="/custom/arduino-cli",
wireviz_path="/custom/wireviz",
sketches_base_dir=tmp_path / "custom",
command_timeout=60,
enable_client_sampling=False
)
server2 = create_server(custom_config)
assert server2 is not None
# Test that different configs create distinct servers
assert server1 is not server2
@pytest.mark.asyncio
async def test_tool_naming_consistency(self, mcp_server):
"""Test that tools follow consistent naming patterns"""
tools = await mcp_server.get_tools()
tool_names = list(tools.keys())
arduino_tools = [name for name in tool_names if name.startswith('arduino_')]
wireviz_tools = [name for name in tool_names if name.startswith('wireviz_')]
# Should have both Arduino and WireViz tools
assert len(arduino_tools) > 0, "No Arduino tools found"
assert len(wireviz_tools) > 0, "No WireViz tools found"
# Arduino tools should follow patterns
for tool_name in arduino_tools:
# Should have component_action pattern
parts = tool_name.split('_')
assert len(parts) >= 2, f"Arduino tool {tool_name} doesn't follow naming pattern"
assert parts[0] == 'arduino'
# WireViz tools should follow patterns
for tool_name in wireviz_tools:
parts = tool_name.split('_')
assert len(parts) >= 2, f"WireViz tool {tool_name} doesn't follow naming pattern"
assert parts[0] == 'wireviz'
@pytest.mark.asyncio
async def test_resource_uri_patterns(self, mcp_server):
"""Test that resource URIs follow expected patterns"""
resources = await mcp_server.get_resources()
# Group by scheme
schemes = {}
for uri in resources.keys():
scheme = str(uri).split('://')[0]
if scheme not in schemes:
schemes[scheme] = []
schemes[scheme].append(uri)
# Should have expected schemes
assert 'arduino' in schemes, "No arduino:// resources found"
assert 'wireviz' in schemes, "No wireviz:// resources found"
assert 'server' in schemes, "No server:// resources found"
# Each scheme should have reasonable number of resources
assert len(schemes['arduino']) >= 3, "Too few arduino:// resources"
assert len(schemes['wireviz']) >= 1, "Too few wireviz:// resources"
assert len(schemes['server']) >= 1, "Too few server:// resources"