373 lines
14 KiB
Python
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()
|