mirror of
https://github.com/aljazceru/enclava.git
synced 2025-12-17 07:24:34 +01:00
348 lines
11 KiB
Python
348 lines
11 KiB
Python
"""
|
|
Comprehensive test suite for all dynamic modules
|
|
Tests individual module functionality, integration, and hot-reload capabilities
|
|
"""
|
|
|
|
import pytest
|
|
import asyncio
|
|
import json
|
|
import time
|
|
from pathlib import Path
|
|
from unittest.mock import Mock, patch, MagicMock
|
|
from typing import Dict, Any
|
|
import tempfile
|
|
import os
|
|
|
|
# Import modules for testing
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
# Add backend directory to Python path for app package imports
|
|
backend_path = Path(__file__).parent.parent
|
|
sys.path.insert(0, str(backend_path))
|
|
|
|
try:
|
|
from app.modules.rag.main import RAGModule
|
|
from app.modules.chatbot.main import ChatbotModule
|
|
|
|
from app.services.module_manager import ModuleManager, ModuleConfig
|
|
except ImportError as e:
|
|
print(f"Import error: {e}")
|
|
# Create mock modules for testing if imports fail
|
|
class MockModule:
|
|
def __init__(self):
|
|
self.name = "mock"
|
|
self.version = "1.0.0"
|
|
self.description = ""
|
|
self.initialized = False
|
|
|
|
async def initialize(self):
|
|
self.initialized = True
|
|
return True
|
|
|
|
async def cleanup(self):
|
|
self.initialized = False
|
|
|
|
def get_stats(self):
|
|
return {"mock": True}
|
|
|
|
RAGModule = MockModule
|
|
ChatbotModule = MockModule
|
|
|
|
# Mock ModuleManager for testing
|
|
class MockModuleManager:
|
|
def __init__(self):
|
|
self.initialized = False
|
|
self.modules = {}
|
|
self.module_order = ['rag', 'chatbot']
|
|
|
|
async def initialize(self):
|
|
self.initialized = True
|
|
|
|
async def cleanup(self):
|
|
self.initialized = False
|
|
|
|
def list_modules(self):
|
|
return self.module_order
|
|
|
|
def get_module(self, name):
|
|
return MockModule()
|
|
|
|
def is_module_loaded(self, name):
|
|
return True
|
|
|
|
async def reload_module(self, name):
|
|
pass
|
|
|
|
ModuleManager = MockModuleManager
|
|
|
|
class MockModuleConfig:
|
|
def __init__(self, name, enabled=True, config=None):
|
|
self.name = name
|
|
self.enabled = enabled
|
|
self.config = config or {}
|
|
|
|
ModuleConfig = MockModuleConfig
|
|
|
|
|
|
class TestModuleIndividual:
|
|
"""Test individual module functionality"""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_chatbot_module_initialization(self):
|
|
"""Test chatbot module initialization and basic operations"""
|
|
chatbot_module = ChatbotModule()
|
|
|
|
# Test initialization
|
|
result = await chatbot_module.initialize()
|
|
assert result is True
|
|
assert chatbot_module.initialized is True
|
|
|
|
# Test stats retrieval
|
|
stats = chatbot_module.get_stats()
|
|
assert isinstance(stats, dict)
|
|
|
|
await chatbot_module.cleanup()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_rag_module_initialization(self):
|
|
"""Test RAG module initialization with integrated content processing"""
|
|
rag_module = RAGModule()
|
|
|
|
# Test initialization
|
|
result = await rag_module.initialize()
|
|
assert result is True
|
|
assert rag_module.initialized is True
|
|
|
|
# Test content processing capabilities
|
|
stats = rag_module.get_stats()
|
|
assert stats['supported_types'] == 8 # Should support 8 file types
|
|
assert 'documents_processed' in stats
|
|
assert 'documents_indexed' in stats
|
|
|
|
await rag_module.cleanup()
|
|
|
|
|
|
class TestModuleIntegration:
|
|
"""Test module integration and interactions"""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_module_manager_initialization(self):
|
|
"""Test module manager loads all modules correctly"""
|
|
module_manager = ModuleManager()
|
|
|
|
# Test initialization
|
|
await module_manager.initialize()
|
|
assert module_manager.initialized is True
|
|
|
|
# Check all expected modules are loaded
|
|
expected_modules = ['chatbot', 'rag']
|
|
loaded_modules = module_manager.list_modules()
|
|
|
|
for module_name in expected_modules:
|
|
assert module_name in loaded_modules, f"Module {module_name} not loaded"
|
|
|
|
# Test module retrieval
|
|
rag_module = module_manager.get_module('rag')
|
|
assert rag_module is not None
|
|
|
|
chatbot_module = module_manager.get_module('chatbot')
|
|
assert chatbot_module is not None
|
|
|
|
await module_manager.cleanup()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_module_dependencies(self):
|
|
"""Test module dependency resolution"""
|
|
module_manager = ModuleManager()
|
|
await module_manager.initialize()
|
|
|
|
# Test that modules are loaded in correct order
|
|
# (This is implicit since no dependency errors should occur)
|
|
assert len(module_manager.module_order) >= 5
|
|
|
|
await module_manager.cleanup()
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_module_stats_collection(self):
|
|
"""Test that all modules provide stats correctly"""
|
|
module_manager = ModuleManager()
|
|
await module_manager.initialize()
|
|
|
|
for module_name in module_manager.list_modules():
|
|
module = module_manager.get_module(module_name)
|
|
if hasattr(module, 'get_stats'):
|
|
stats = module.get_stats()
|
|
assert isinstance(stats, dict)
|
|
assert len(stats) > 0
|
|
|
|
await module_manager.cleanup()
|
|
|
|
|
|
class TestModuleHotReload:
|
|
"""Test hot-reload functionality"""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_module_reload(self):
|
|
"""Test module hot-reload functionality"""
|
|
module_manager = ModuleManager()
|
|
await module_manager.initialize()
|
|
|
|
# Get initial module reference
|
|
initial_module = module_manager.get_module('rag')
|
|
assert initial_module is not None
|
|
|
|
# Test reload
|
|
await module_manager.reload_module('rag')
|
|
|
|
# Get module after reload
|
|
reloaded_module = module_manager.get_module('rag')
|
|
assert reloaded_module is not None
|
|
|
|
# Module should be reloaded (may be same object or different)
|
|
assert module_manager.is_module_loaded('rag')
|
|
|
|
await module_manager.cleanup()
|
|
|
|
|
|
|
|
class TestModulePerformance:
|
|
"""Test module performance characteristics"""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_module_initialization_speed(self):
|
|
"""Test that modules initialize within reasonable time"""
|
|
start_time = time.time()
|
|
|
|
module_manager = ModuleManager()
|
|
await module_manager.initialize()
|
|
|
|
initialization_time = time.time() - start_time
|
|
|
|
# All modules should initialize within 30 seconds
|
|
assert initialization_time < 30.0, f"Module initialization took {initialization_time:.2f}s"
|
|
|
|
await module_manager.cleanup()
|
|
|
|
|
|
|
|
class TestModuleErrorHandling:
|
|
"""Test module error handling and recovery"""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_module_initialization_failure_recovery(self):
|
|
"""Test module manager handles initialization failures gracefully"""
|
|
module_manager = ModuleManager()
|
|
|
|
# This should not raise an exception even if some modules fail to load
|
|
await module_manager.initialize()
|
|
|
|
# At least some modules should load successfully
|
|
assert len(module_manager.list_modules()) >= 2
|
|
|
|
await module_manager.cleanup()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_module_cleanup_robustness(self):
|
|
"""Test that module cleanup handles errors gracefully"""
|
|
module_manager = ModuleManager()
|
|
await module_manager.initialize()
|
|
|
|
# This should not raise exceptions even if individual cleanups fail
|
|
await module_manager.cleanup()
|
|
|
|
# Manager should be properly shut down
|
|
assert module_manager.initialized is False
|
|
|
|
|
|
class TestModuleAPI:
|
|
"""Test module API endpoints and interactions"""
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_modules_api_response_structure(self):
|
|
"""Test that module API responses have correct structure"""
|
|
module_manager = ModuleManager()
|
|
await module_manager.initialize()
|
|
|
|
# Simulate API response structure
|
|
modules_list = []
|
|
for module_name in module_manager.list_modules():
|
|
module = module_manager.get_module(module_name)
|
|
|
|
module_info = {
|
|
"name": module_name,
|
|
"version": getattr(module, 'version', '1.0.0'),
|
|
"description": getattr(module, 'description', ''),
|
|
"initialized": getattr(module, 'initialized', False),
|
|
"enabled": True
|
|
}
|
|
|
|
# Add stats if available
|
|
if hasattr(module, 'get_stats'):
|
|
module_info["stats"] = module.get_stats()
|
|
|
|
modules_list.append(module_info)
|
|
|
|
api_response = {
|
|
"total": len(modules_list),
|
|
"modules": modules_list,
|
|
"module_count": len(modules_list),
|
|
"initialized": True
|
|
}
|
|
|
|
# Verify response structure
|
|
assert isinstance(api_response["total"], int)
|
|
assert api_response["total"] >= 5 # Should have at least 5 modules
|
|
assert isinstance(api_response["modules"], list)
|
|
assert len(api_response["modules"]) == api_response["total"]
|
|
assert api_response["initialized"] is True
|
|
|
|
# Verify each module has required fields
|
|
for module_info in api_response["modules"]:
|
|
assert "name" in module_info
|
|
assert "version" in module_info
|
|
assert "description" in module_info
|
|
assert "initialized" in module_info
|
|
assert "enabled" in module_info
|
|
|
|
await module_manager.cleanup()
|
|
|
|
|
|
# Test configuration for pytest
|
|
@pytest.fixture(scope="session")
|
|
def event_loop():
|
|
"""Create an instance of the default event loop for the test session."""
|
|
loop = asyncio.get_event_loop_policy().new_event_loop()
|
|
yield loop
|
|
loop.close()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
# Run basic test manually if executed directly
|
|
async def run_basic_tests():
|
|
print("Running basic module tests...")
|
|
|
|
# Test individual modules
|
|
test_individual = TestModuleIndividual()
|
|
|
|
print("Testing chatbot module...")
|
|
await test_individual.test_chatbot_module_initialization()
|
|
print("✓ Chatbot module test passed")
|
|
|
|
print("Testing RAG module with content processing...")
|
|
await test_individual.test_rag_module_initialization()
|
|
print("✓ RAG module with content processing test passed")
|
|
|
|
# Test integration
|
|
test_integration = TestModuleIntegration()
|
|
|
|
print("Testing module manager integration...")
|
|
await test_integration.test_module_manager_initialization()
|
|
print("✓ Module manager integration test passed")
|
|
|
|
print("\nAll basic tests completed successfully! 🎉")
|
|
|
|
# Run the tests
|
|
asyncio.run(run_basic_tests())
|