Phase 4: Shell completion scripts and comprehensive test suite

This commit is contained in:
truetype committed 2026-03-20 17:54:46 +01:00
1 parent aba2fc11f4
commit 5e70e22780
5 files changed
+641 -7

No files matched your search

+186
View File
@@ -0,0 +1,186 @@
"""
Test suite for MaxClaw Agent configuration manager
"""
import os
import json
import tempfile
import pytest
from pathlib import Path
import sys
# Add parent directory to path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from config_manager import ConfigManager
class TestConfigManager:
"""Test cases for ConfigManager"""
def setup_method(self):
"""Set up test environment"""
self.temp_dir = tempfile.mkdtemp()
self.config_manager = ConfigManager(self.temp_dir)
def teardown_method(self):
"""Clean up test environment"""
import shutil
shutil.rmtree(self.temp_dir, ignore_errors=True)
def test_initialization(self):
"""Test ConfigManager initialization"""
assert self.config_manager.config_dir.exists()
assert self.config_manager.config_file.exists()
assert self.config_manager.key_file.exists()
assert self.config_manager.config == {"configurations": {}, "active_configuration": None, "version": "1.0"}
def test_add_configuration(self):
"""Test adding a configuration"""
config = {
"provider": "ollama",
"model_name": "gemma2:9b",
"base_url": "http://localhost:11434"
}
self.config_manager.add_configuration("test-config", config)
# Verify configuration was added
assert self.config_manager.configuration_exists("test-config")
retrieved = self.config_manager.get_configuration("test-config")
assert retrieved["provider"] == "ollama"
assert retrieved["model_name"] == "gemma2:9b"
assert retrieved["base_url"] == "http://localhost:11434"
def test_remove_configuration(self):
"""Test removing a configuration"""
config = {
"provider": "openai",
"model_name": "gpt-4o",
"api_key": "sk-test123"
}
self.config_manager.add_configuration("test-openai", config)
assert self.config_manager.configuration_exists("test-openai")
# Remove configuration
result = self.config_manager.remove_configuration("test-openai")
assert result is True
assert not self.config_manager.configuration_exists("test-openai")
def test_set_active_configuration(self):
"""Test setting active configuration"""
config = {
"provider": "ollama",
"model_name": "gemma2:9b",
"base_url": "http://localhost:11434"
}
self.config_manager.add_configuration("test-config", config)
# Set as active
result = self.config_manager.set_active_configuration("test-config")
assert result is True
assert self.config_manager.get_active_configuration() == "test-config"
def test_validation(self):
"""Test configuration validation"""
# Valid configuration
valid_config = {
"provider": "ollama",
"model_name": "gemma2:9b",
"base_url": "http://localhost:11434"
}
is_valid, errors = self.config_manager.validate_configuration(valid_config)
assert is_valid is True
assert len(errors) == 0
# Invalid configuration - missing provider
invalid_config = {
"model_name": "gemma2:9b",
"base_url": "http://localhost:11434"
}
is_valid, errors = self.config_manager.validate_configuration(invalid_config)
assert is_valid is False
assert "Provider is required" in errors
# Invalid configuration - OpenAI without API key
invalid_openai = {
"provider": "openai",
"model_name": "gpt-4o"
}
is_valid, errors = self.config_manager.validate_configuration(invalid_openai)
assert is_valid is False
assert "API key is required for OpenAI provider" in errors
def test_encryption(self):
"""Test that API keys are encrypted"""
config = {
"provider": "openai",
"model_name": "gpt-4o",
"api_key": "sk-test123456789"
}
self.config_manager.add_configuration("test-openai", config)
# Read the raw config file
with open(self.config_manager.config_file, 'r') as f:
raw_config = json.load(f)
# Check that API key is encrypted in the file
stored_config = raw_config["configurations"]["test-openai"]
assert "api_key" in stored_config
assert stored_config["api_key"] != "sk-test123456789" # Should be encrypted
assert len(stored_config["api_key"]) > 20 # Encrypted data is longer
# But when retrieved, it should be decrypted
retrieved = self.config_manager.get_configuration("test-openai")
assert retrieved["api_key"] == "sk-test123456789"
def test_list_configurations(self):
"""Test listing configurations"""
# Add multiple configurations
configs = [
("config1", {"provider": "ollama", "model_name": "gemma2:9b", "base_url": "http://localhost:11434"}),
("config2", {"provider": "openai", "model_name": "gpt-4o", "api_key": "sk-test"}),
("config3", {"provider": "openrouter", "model_name": "claude-3.5-sonnet", "api_key": "sk-or-test", "base_url": "https://openrouter.ai/api/v1"})
]
for name, config in configs:
self.config_manager.add_configuration(name, config)
# List configurations
config_names = self.config_manager.list_configuration_names()
assert len(config_names) == 3
assert "config1" in config_names
assert "config2" in config_names
assert "config3" in config_names
def test_backup_creation(self):
"""Test that backups are created"""
config = {
"provider": "ollama",
"model_name": "gemma2:9b",
"base_url": "http://localhost:11434"
}
# Add first configuration
self.config_manager.add_configuration("config1", config)
# Add second configuration (should create backup)
config2 = {
"provider": "openai",
"model_name": "gpt-4o",
"api_key": "sk-test"
}
self.config_manager.add_configuration("config2", config2)
# Check that backup file exists
backup_file = self.config_manager.config_file.with_suffix('.json.bak')
assert backup_file.exists()
if __name__ == "__main__":
pytest.main([__file__, "-v"])
+256
View File
@@ -0,0 +1,256 @@
"""
Test suite for MaxClaw Agent provider tools
"""
import os
import sys
import pytest
from unittest.mock import Mock, patch, MagicMock
# Add parent directory to path
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from tools.provider_tools import (
OllamaProviderTools,
OpenAIProviderTools,
OpenRouterProviderTools,
get_provider_tools
)
class TestOllamaProviderTools:
"""Test cases for OllamaProviderTools"""
def setup_method(self):
"""Set up test environment"""
self.tools = OllamaProviderTools(base_url="http://localhost:11434")
def test_initialization(self):
"""Test OllamaProviderTools initialization"""
assert self.tools.provider_name == "ollama"
assert self.tools.base_url == "http://localhost:11434"
assert self.tools.api_url == "http://localhost:11434/api"
@patch('requests.get')
def test_list_models_success(self, mock_get):
"""Test successful model listing"""
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {
"models": [
{"name": "gemma2:9b", "size": 5000000000},
{"name": "llama2:7b", "size": 4000000000}
]
}
mock_get.return_value = mock_response
result = self.tools.list_models()
assert "Available Ollama Models" in result
assert "gemma2:9b" in result
assert "llama2:7b" in result
@patch('requests.get')
def test_list_models_failure(self, mock_get):
"""Test failed model listing"""
mock_get.side_effect = Exception("Connection failed")
result = self.tools.list_models()
assert "Error listing models" in result
@patch('requests.post')
def test_get_model_info_success(self, mock_post):
"""Test successful model info retrieval"""
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {
"license": "Apache 2.0",
"parameters": "9B",
"details": {
"parameter_size": "9B",
"quantization_level": "Q4_0"
}
}
mock_post.return_value = mock_response
result = self.tools.get_model_info("gemma2:9b")
assert "Model Information: gemma2:9b" in result
assert "License: Apache 2.0" in result
assert "Parameter Size: 9B" in result
@patch('requests.get')
def test_test_connection_success(self, mock_get):
"""Test successful connection test"""
mock_response = Mock()
mock_response.status_code = 200
mock_get.return_value = mock_response
result = self.tools.test_connection()
assert "✅ Ollama instance at http://localhost:11434 is running" in result
@patch('requests.get')
def test_test_connection_failure(self, mock_get):
"""Test failed connection test"""
mock_get.side_effect = Exception("Connection failed")
result = self.tools.test_connection()
assert "❌ Cannot connect to Ollama instance" in result
def test_get_tools(self):
"""Test tool generation"""
tools = self.tools.get_tools()
assert len(tools) == 6
tool_names = [tool.name for tool in tools]
assert "ollama_list_models" in tool_names
assert "ollama_model_info" in tool_names
assert "ollama_test_connection" in tool_names
assert "ollama_get_default_model" in tool_names
assert "ollama_set_default_model" in tool_names
assert "ollama_info" in tool_names
class TestOpenAIProviderTools:
"""Test cases for OpenAIProviderTools"""
def setup_method(self):
"""Set up test environment"""
self.tools = OpenAIProviderTools(api_key="sk-test123")
def test_initialization(self):
"""Test OpenAIProviderTools initialization"""
assert self.tools.provider_name == "openai"
assert self.tools.api_key == "sk-test123"
assert self.tools.api_url == "https://api.openai.com/v1"
@patch('requests.get')
def test_list_models_success(self, mock_get):
"""Test successful model listing"""
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {
"data": [
{"id": "gpt-4o"},
{"id": "gpt-4o-mini"},
{"id": "gpt-3.5-turbo"}
]
}
mock_get.return_value = mock_response
result = self.tools.list_models()
assert "Available OpenAI Models" in result
assert "gpt-4o" in result
assert "gpt-4o-mini" in result
@patch('requests.get')
def test_test_connection_success(self, mock_get):
"""Test successful connection test"""
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {"data": []}
mock_get.return_value = mock_response
result = self.tools.test_connection()
assert "✅ OpenAI API connection successful" in result
def test_get_tools(self):
"""Test tool generation"""
tools = self.tools.get_tools()
assert len(tools) == 6
tool_names = [tool.name for tool in tools]
assert "openai_list_models" in tool_names
assert "openai_model_info" in tool_names
assert "openai_test_connection" in tool_names
class TestOpenRouterProviderTools:
"""Test cases for OpenRouterProviderTools"""
def setup_method(self):
"""Set up test environment"""
self.tools = OpenRouterProviderTools(
api_key="sk-or-test123",
base_url="https://openrouter.ai/api/v1"
)
def test_initialization(self):
"""Test OpenRouterProviderTools initialization"""
assert self.tools.provider_name == "openrouter"
assert self.tools.api_key == "sk-or-test123"
assert self.tools.base_url == "https://openrouter.ai/api/v1"
@patch('requests.get')
def test_list_models_success(self, mock_get):
"""Test successful model listing"""
mock_response = Mock()
mock_response.status_code = 200
mock_response.json.return_value = {
"data": [
{"id": "anthropic/claude-3.5-sonnet", "name": "Claude 3.5 Sonnet"},
{"id": "openai/gpt-4o", "name": "GPT-4o"}
]
}
mock_get.return_value = mock_response
result = self.tools.list_models()
assert "Available OpenRouter Models" in result
assert "anthropic/claude-3.5-sonnet" in result
assert "openai/gpt-4o" in result
def test_get_tools(self):
"""Test tool generation"""
tools = self.tools.get_tools()
assert len(tools) == 6
tool_names = [tool.name for tool in tools]
assert "openrouter_list_models" in tool_names
assert "openrouter_model_info" in tool_names
assert "openrouter_test_connection" in tool_names
class TestGetProviderTools:
"""Test cases for get_provider_tools function"""
@patch.dict(os.environ, {"OLLAMA_BASE_URL": "http://localhost:11434"})
def test_get_ollama_tools(self):
"""Test getting Ollama tools"""
tools = get_provider_tools("ollama")
assert len(tools) == 6
tool_names = [tool.name for tool in tools]
assert "ollama_list_models" in tool_names
@patch.dict(os.environ, {"OPENAI_API_KEY": "sk-test123"})
def test_get_openai_tools(self):
"""Test getting OpenAI tools"""
tools = get_provider_tools("openai")
assert len(tools) == 6
tool_names = [tool.name for tool in tools]
assert "openai_list_models" in tool_names
@patch.dict(os.environ, {"OPENROUTER_API_KEY": "sk-or-test123"})
def test_get_openrouter_tools(self):
"""Test getting OpenRouter tools"""
tools = get_provider_tools("openrouter")
assert len(tools) == 6
tool_names = [tool.name for tool in tools]
assert "openrouter_list_models" in tool_names
def test_get_unknown_provider_tools(self):
"""Test getting tools for unknown provider"""
tools = get_provider_tools("unknown")
assert len(tools) == 0
if __name__ == "__main__":
pytest.main([__file__, "-v"])