CalejoControl/tests/integration/test_dashboard_integration.py

253 lines
9.3 KiB
Python
Raw Normal View History

"""
Integration tests for Dashboard with REST API
"""
import pytest
from unittest.mock import Mock, patch
from fastapi.testclient import TestClient
from src.protocols.rest_api import RESTAPIServer
from src.core.setpoint_manager import SetpointManager
from src.core.emergency_stop import EmergencyStopManager
from src.core.security import SecurityManager
from src.monitoring.health_monitor import HealthMonitor
class TestDashboardIntegration:
"""Test dashboard integration with REST API"""
@pytest.fixture
def mock_managers(self):
"""Create mock managers for testing"""
setpoint_manager = Mock(spec=SetpointManager)
emergency_stop_manager = Mock(spec=EmergencyStopManager)
security_manager = Mock(spec=SecurityManager)
health_monitor = Mock(spec=HealthMonitor)
return {
'setpoint_manager': setpoint_manager,
'emergency_stop_manager': emergency_stop_manager,
'security_manager': security_manager,
'health_monitor': health_monitor
}
@pytest.fixture
def api_server(self, mock_managers):
"""Create REST API server with dashboard integration"""
server = RESTAPIServer(
setpoint_manager=mock_managers['setpoint_manager'],
emergency_stop_manager=mock_managers['emergency_stop_manager'],
health_monitor=mock_managers['health_monitor']
)
return server
@pytest.fixture
def client(self, api_server):
"""Create test client for REST API"""
return TestClient(api_server.app)
def test_dashboard_routes_available(self, client):
"""Test that dashboard routes are available through REST API"""
# Test dashboard root route
response = client.get("/dashboard")
assert response.status_code == 200
assert "text/html" in response.headers["content-type"]
# Test dashboard API routes
response = client.get("/api/v1/dashboard/config")
assert response.status_code == 200
response = client.get("/api/v1/dashboard/status")
assert response.status_code == 200
response = client.get("/api/v1/dashboard/logs")
assert response.status_code == 200
def test_static_files_served(self, client):
"""Test that static files (JavaScript) are served"""
response = client.get("/static/dashboard.js")
# Should either return the file or 404 if not found
# But the route should be available
assert response.status_code in [200, 404]
# If file exists, check content type (both text/javascript and application/javascript are valid)
if response.status_code == 200:
content_type = response.headers.get("content-type", "")
assert "javascript" in content_type or "text/javascript" in content_type
def test_dashboard_configuration_flow(self, client):
"""Test complete configuration flow through dashboard API"""
# 1. Get current configuration
response = client.get("/api/v1/dashboard/config")
assert response.status_code == 200
current_config = response.json()
# Verify structure
assert "database" in current_config
assert "opcua" in current_config
assert "modbus" in current_config
assert "rest_api" in current_config
assert "monitoring" in current_config
assert "security" in current_config
# 2. Update configuration (mock validation)
with patch('src.dashboard.api.validate_configuration') as mock_validate:
mock_validate.return_value = Mock(valid=True, errors=[], warnings=[])
update_data = {
"database": {
"db_host": "new_host",
"db_port": 5433,
"db_name": "new_db",
"db_user": "new_user",
"db_password": "new_password"
},
"opcua": {
"enabled": True,
"host": "localhost",
"port": 4841
},
"modbus": {
"enabled": True,
"host": "localhost",
"port": 503,
"unit_id": 2
},
"rest_api": {
"enabled": True,
"host": "127.0.0.1",
"port": 8081,
"cors_enabled": False
},
"monitoring": {
"health_monitor_port": 9091,
"metrics_enabled": True
},
"security": {
"jwt_secret_key": "new_secret",
"api_key": "new_api_key"
}
}
response = client.post("/api/v1/dashboard/config", json=update_data)
assert response.status_code == 200
update_result = response.json()
assert update_result["valid"] == True
def test_dashboard_system_actions(self, client):
"""Test system actions through dashboard API"""
# Test restart
response = client.post("/api/v1/dashboard/restart")
assert response.status_code == 200
restart_result = response.json()
assert "message" in restart_result
assert "status" in restart_result
# Test backup
response = client.get("/api/v1/dashboard/backup")
assert response.status_code == 200
backup_result = response.json()
assert "message" in backup_result
assert "status" in backup_result
def test_dashboard_status_integration(self, client, mock_managers):
"""Test dashboard status integration with health monitor"""
# Mock health monitor to return specific status
mock_health_status = {
"status": "healthy",
"timestamp": "2024-01-01T10:00:00",
"components": {
"database": {
"status": "connected",
"message": "Database connection successful",
"last_check": "2024-01-01T10:00:00",
"response_time_ms": 5.2
},
"opcua_server": {
"status": "listening",
"message": "OPC UA server running",
"last_check": "2024-01-01T10:00:00",
"response_time_ms": 1.5
}
}
}
mock_managers['health_monitor'].get_health_status.return_value = {
"status": "healthy",
"timestamp": "2024-01-01T10:00:00"
}
# Test health endpoint
response = client.get("/health")
assert response.status_code == 200
health_data = response.json()
assert "status" in health_data
# Test dashboard status endpoint
response = client.get("/api/v1/dashboard/status")
assert response.status_code == 200
status_data = response.json()
assert "application_status" in status_data
assert "database_status" in status_data
assert "opcua_status" in status_data
assert "modbus_status" in status_data
assert "rest_api_status" in status_data
assert "monitoring_status" in status_data
def test_dashboard_error_handling(self, client):
"""Test dashboard error handling"""
# Test with invalid configuration data
invalid_config = {
"database": {
"db_host": "", # Invalid - empty
"db_port": 70000, # Invalid port
"db_name": "", # Invalid - empty
"db_user": "", # Invalid - empty
"db_password": "password"
},
"opcua": {
"enabled": True,
"host": "localhost",
"port": 4840
},
"modbus": {
"enabled": True,
"host": "localhost",
"port": 502,
"unit_id": 1
},
"rest_api": {
"enabled": True,
"host": "0.0.0.0",
"port": 8080,
"cors_enabled": True
},
"monitoring": {
"health_monitor_port": 9090,
"metrics_enabled": True
},
"security": {
"jwt_secret_key": "secret",
"api_key": "api_key"
}
}
# Mock validation to return errors
with patch('src.dashboard.api.validate_configuration') as mock_validate:
mock_validate.return_value = Mock(
valid=False,
errors=[
"Database host is required",
"Database name is required",
"Database user is required",
"Database port must be between 1 and 65535"
],
warnings=[]
)
response = client.post("/api/v1/dashboard/config", json=invalid_config)
assert response.status_code == 200
result = response.json()
assert result["valid"] == False
assert len(result["errors"]) == 4