CtrEditor/tsnet_edge_test_suite.py

373 lines
14 KiB
Python

#!/usr/bin/env python3
"""
TSNet Phase 2 - Edge Cases and Error Handling Test
Tests específicos para casos edge y manejo de errores
"""
import requests
import time
from datetime import datetime
class TSNetEdgeTestSuite:
def __init__(self, base_url="http://localhost:5006"):
self.base_url = base_url
self.results = []
def send_request(self, method, params=None, timeout=15):
"""Enviar request MCP con manejo robusto"""
try:
payload = {
'jsonrpc': '2.0',
'method': method,
'id': int(time.time() * 1000)
}
if params:
payload['params'] = params
response = requests.post(self.base_url, json=payload, timeout=timeout)
if response.status_code == 200:
result = response.json()
return 'error' not in result, result
return False, {'error': f'HTTP {response.status_code}'}
except Exception as e:
return False, {'error': f'Exception: {str(e)}'}
def log_result(self, test_name, passed, details=""):
"""Registrar resultado"""
status = "" if passed else ""
print(f"{status} {test_name}")
if details:
print(f" {details}")
self.results.append({'test': test_name, 'passed': passed, 'details': details})
def test_null_reference_prevention(self):
"""Test: Prevención de NullReferenceException"""
print("\n🔍 Testing NullReference Prevention...")
code = """
import clr
try:
# Intentar crear objetos sin inicialización previa
from CtrEditor.ObjetosSim import osHydTank, osHydPump, osHydPipe
from CtrEditor.HydraulicSimulator.TSNet.Components import TSNetTankAdapter
# Test 1: Crear tanque sin ID
tank = osHydTank()
# No llamar CheckData() intencionalmente
# Esto DEBERÍA fallar con una excepción controlada, no NullReference
try:
adapter = TSNetTankAdapter(tank)
result = "ERROR: Should have failed with null ID"
except Exception as e:
if "Id válido" in str(e):
result = "SUCCESS: Proper validation error for null ID"
else:
result = f"PARTIAL: Got error but wrong type: {str(e)}"
except Exception as e:
result = f"SETUP_ERROR: {str(e)}"
print(result)
"""
success, response = self.send_request('execute_python', {'code': code})
test_passed = success and "SUCCESS" in str(response)
self.log_result("NullReference Prevention", test_passed, str(response)[:150])
def test_checkdata_initialization(self):
"""Test: Inicialización correcta con CheckData"""
print("\n🔍 Testing CheckData Initialization...")
code = """
try:
from CtrEditor.ObjetosSim import osHydTank
from CtrEditor.HydraulicSimulator.TSNet.Components import TSNetTankAdapter
# Test: Crear tanque y asegurar CheckData
tank = osHydTank()
tank.CheckData() # Esto debe inicializar el ID
# Ahora crear el adaptador debe funcionar
adapter = TSNetTankAdapter(tank)
if adapter.TankId and "TANK_" in adapter.TankId:
result = f"SUCCESS: Adapter created with ID {adapter.TankId}"
else:
result = f"ERROR: Invalid adapter ID: {adapter.TankId}"
except Exception as e:
result = f"ERROR: {str(e)}"
print(result)
"""
success, response = self.send_request('execute_python', {'code': code})
test_passed = success and "SUCCESS" in str(response)
self.log_result("CheckData Initialization", test_passed, str(response)[:150])
def test_adapter_registration_safety(self):
"""Test: Seguridad en registro de adaptadores"""
print("\n🔍 Testing Adapter Registration Safety...")
code = """
try:
# Test registro seguro con objetos válidos e inválidos
valid_count = 0
error_count = 0
for obj in app.ObjetosSimulables:
if obj.GetType().Name.startswith("osHyd"):
try:
# Forzar CheckData antes del registro
obj.CheckData()
app.tsnetSimulationManager.RegisterHydraulicObject(obj)
valid_count += 1
except Exception as e:
error_count += 1
print(f"Registration error for {obj.Nombre}: {str(e)[:50]}")
result = f"SUCCESS: {valid_count} registered, {error_count} errors handled safely"
except Exception as e:
result = f"ERROR: {str(e)}"
print(result)
"""
success, response = self.send_request('execute_python', {'code': code})
test_passed = success and "SUCCESS" in str(response)
self.log_result("Adapter Registration Safety", test_passed, str(response)[:150])
def test_multiple_registrations(self):
"""Test: Registros múltiples del mismo objeto"""
print("\n🔍 Testing Multiple Registrations...")
code = """
try:
# Test registrar el mismo objeto múltiples veces
registration_attempts = 0
successful_registrations = 0
# Tomar el primer objeto hidráulico
test_obj = None
for obj in app.ObjetosSimulables:
if obj.GetType().Name.startswith("osHyd"):
test_obj = obj
break
if test_obj:
test_obj.CheckData()
# Intentar registrar 5 veces
for i in range(5):
try:
app.tsnetSimulationManager.RegisterHydraulicObject(test_obj)
registration_attempts += 1
# Verificar si realmente se agregó o se detectó duplicado
obj_id = test_obj.Id.Value.toString()
if obj_id in app.tsnetSimulationManager._objectMapping:
successful_registrations += 1
except Exception as e:
print(f"Registration {i+1} error: {str(e)[:50]}")
result = f"SUCCESS: {registration_attempts} attempts, handled duplicates properly"
else:
result = "SKIP: No hydraulic objects found"
except Exception as e:
result = f"ERROR: {str(e)}"
print(result)
"""
success, response = self.send_request('execute_python', {'code': code})
test_passed = success and ("SUCCESS" in str(response) or "SKIP" in str(response))
self.log_result("Multiple Registrations", test_passed, str(response)[:150])
def test_configuration_validation_edge_cases(self):
"""Test: Casos edge en validación de configuración"""
print("\n🔍 Testing Configuration Validation Edge Cases...")
code = """
try:
# Test validación con configuraciones extremas
from CtrEditor.ObjetosSim import osHydTank
from CtrEditor.HydraulicSimulator.TSNet.Components import TSNetTankAdapter
# Crear tanque con valores extremos
tank = osHydTank()
tank.CheckData()
# Valores edge
tank.MinLevelM = -1.0 # Negativo (debería dar error)
tank.MaxLevelM = 0.5 # Menor que min (debería dar error)
tank.CurrentLevelM = 2.0 # Mayor que max
adapter = TSNetTankAdapter(tank)
adapter.CaptureConfigurationForSimulation()
# Validar configuración
errors = adapter.ValidateConfiguration()
expected_errors = 2 # MinLevel negativo y MaxLevel < MinLevel
actual_errors = len(errors)
if actual_errors >= expected_errors:
result = f"SUCCESS: Found {actual_errors} validation errors as expected"
else:
result = f"PARTIAL: Found {actual_errors} errors, expected at least {expected_errors}"
for error in errors:
print(f"Validation error: {error}")
except Exception as e:
result = f"ERROR: {str(e)}"
print(result)
"""
success, response = self.send_request('execute_python', {'code': code})
test_passed = success and "SUCCESS" in str(response)
self.log_result("Configuration Validation Edge Cases", test_passed, str(response)[:200])
def test_memory_cleanup(self):
"""Test: Limpieza de memoria y recursos"""
print("\n🔍 Testing Memory Cleanup...")
code = """
try:
# Test limpieza de adaptadores
initial_tanks = len(app.tsnetSimulationManager._tankAdapters) if hasattr(app.tsnetSimulationManager, '_tankAdapters') else 0
initial_pumps = len(app.tsnetSimulationManager._pumpAdapters) if hasattr(app.tsnetSimulationManager, '_pumpAdapters') else 0
initial_pipes = len(app.tsnetSimulationManager._pipeAdapters) if hasattr(app.tsnetSimulationManager, '_pipeAdapters') else 0
# Registrar objetos
for obj in app.ObjetosSimulables:
if obj.GetType().Name.startswith("osHyd"):
obj.CheckData()
app.tsnetSimulationManager.RegisterHydraulicObject(obj)
mid_tanks = len(app.tsnetSimulationManager._tankAdapters) if hasattr(app.tsnetSimulationManager, '_tankAdapters') else 0
mid_pumps = len(app.tsnetSimulationManager._pumpAdapters) if hasattr(app.tsnetSimulationManager, '_pumpAdapters') else 0
mid_pipes = len(app.tsnetSimulationManager._pipeAdapters) if hasattr(app.tsnetSimulationManager, '_pipeAdapters') else 0
# Resetear valores calculados
app.tsnetSimulationManager.ResetAllCalculatedValues()
final_tanks = len(app.tsnetSimulationManager._tankAdapters) if hasattr(app.tsnetSimulationManager, '_tankAdapters') else 0
final_pumps = len(app.tsnetSimulationManager._pumpAdapters) if hasattr(app.tsnetSimulationManager, '_pumpAdapters') else 0
final_pipes = len(app.tsnetSimulationManager._pipeAdapters) if hasattr(app.tsnetSimulationManager, '_pipeAdapters') else 0
result = f"SUCCESS: Initial: T{initial_tanks}/P{initial_pumps}/Pi{initial_pipes}, Mid: T{mid_tanks}/P{mid_pumps}/Pi{mid_pipes}, Final: T{final_tanks}/P{final_pumps}/Pi{final_pipes}"
except Exception as e:
result = f"ERROR: {str(e)}"
print(result)
"""
success, response = self.send_request('execute_python', {'code': code})
test_passed = success and "SUCCESS" in str(response)
self.log_result("Memory Cleanup", test_passed, str(response)[:200])
def test_concurrent_operations(self):
"""Test: Operaciones concurrentes simuladas"""
print("\n🔍 Testing Concurrent Operations...")
code = """
try:
# Simular operaciones concurrentes
operations_completed = 0
errors_handled = 0
# Múltiples operaciones en secuencia rápida
for i in range(10):
try:
# Reset
app.tsnetSimulationManager.ResetAllCalculatedValues()
operations_completed += 1
# Register objects
for obj in app.ObjetosSimulables:
if obj.GetType().Name.startswith("osHyd"):
obj.CheckData()
app.tsnetSimulationManager.RegisterHydraulicObject(obj)
operations_completed += 1
# Validate
errors = app.tsnetSimulationManager.ValidateAllConfigurations()
operations_completed += 1
# Rebuild network
app.tsnetSimulationManager.RebuildNetwork()
operations_completed += 1
except Exception as e:
errors_handled += 1
print(f"Operation {i} error: {str(e)[:50]}")
result = f"SUCCESS: {operations_completed} operations completed, {errors_handled} errors handled"
except Exception as e:
result = f"ERROR: {str(e)}"
print(result)
"""
success, response = self.send_request('execute_python', {'code': code})
test_passed = success and "SUCCESS" in str(response)
self.log_result("Concurrent Operations", test_passed, str(response)[:150])
def run_edge_tests(self):
"""Ejecutar todos los tests de casos edge"""
print("🧪 TSNet Phase 2 - Edge Cases & Error Handling Test Suite")
print("=" * 65)
print(f"Started at: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
# Verificar conectividad
success, _ = self.send_request('get_ctreditor_status')
if not success:
print("❌ Cannot connect to CtrEditor MCP server")
return
# Ejecutar tests
tests = [
self.test_null_reference_prevention,
self.test_checkdata_initialization,
self.test_adapter_registration_safety,
self.test_multiple_registrations,
self.test_configuration_validation_edge_cases,
self.test_memory_cleanup,
self.test_concurrent_operations
]
for test_func in tests:
try:
test_func()
time.sleep(0.5)
except Exception as e:
self.log_result(f"Test Execution: {test_func.__name__}", False, f"Exception: {str(e)}")
# Resumen
print("\n" + "=" * 65)
print("📊 EDGE TESTS SUMMARY")
print("=" * 65)
passed = len([r for r in self.results if r['passed']])
total = len(self.results)
print(f"Tests Executed: {total}")
print(f"Passed: {passed}")
print(f"Failed: {total - passed}")
print(f"Success Rate: {passed/total*100:.1f}%")
if passed == total:
print("\n🎉 ALL EDGE TESTS PASSED! Error handling is robust.")
elif passed >= total * 0.8:
print("\n✅ Most edge tests passed. System is resilient.")
else:
print("\n⚠️ Multiple edge test failures. Review error handling.")
def main():
test_suite = TSNetEdgeTestSuite()
test_suite.run_edge_tests()
if __name__ == "__main__":
main()