#!/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()