From d9481b724685c8786fda736b93bf5eb3488aef88 Mon Sep 17 00:00:00 2001 From: openhands Date: Thu, 6 Nov 2025 19:29:21 +0000 Subject: [PATCH] Add untracked test files and update deployment scripts - Add discovery protocol test files for debugging and direct testing - Add remote test integration scripts and configuration - Update deployment and monitoring scripts with recent changes - Include test-remote.yml configuration for remote testing --- .coverage | Bin 53248 -> 53248 bytes config/test-remote.yml | 72 ++++ database/setup_database.sh | 0 deploy-onprem.sh | 0 deploy/ssh/deploy-remote.py | 0 deploy/ssh/deploy-remote.sh | 0 generate-monitoring-secrets.sh | 0 mock-optimization-server.py | 0 mock-scada-server.py | 0 monitoring/grafana/configure-grafana.sh | 0 run_tests.py | 0 run_tests_by_system.py | 0 run_tests_detailed.py | 0 run_tests_with_db.sh | 0 scripts/backup.sh | 0 scripts/restore.sh | 0 scripts/run-mock-tests.sh | 0 scripts/run-smoke-tests.sh | 0 scripts/security_audit.sh | 0 scripts/setup-test-environment.sh | 0 scripts/test-mock-services-standalone.py | 0 scripts/test-mock-services.sh | 0 setup-monitoring.sh | 0 setup-server-backup.sh | 0 setup-server.sh | 0 src/discovery/protocol_discovery_modified.py | 344 +++++++++++++++++++ start-remote-test.sh | 63 ++++ test-deployment.sh | 0 test-e2e-deployment.py | 0 test-remote-integration.py | 143 ++++++++ test_discovery_debug.py | 56 +++ test_discovery_direct.py | 35 ++ test_discovery_endpoints.py | 90 +++++ test_discovery_fast.py | 40 +++ validate-deployment.sh | 0 35 files changed, 843 insertions(+) create mode 100644 config/test-remote.yml mode change 100755 => 100644 database/setup_database.sh mode change 100755 => 100644 deploy-onprem.sh mode change 100755 => 100644 deploy/ssh/deploy-remote.py mode change 100755 => 100644 deploy/ssh/deploy-remote.sh mode change 100755 => 100644 generate-monitoring-secrets.sh mode change 100755 => 100644 mock-optimization-server.py mode change 100755 => 100644 mock-scada-server.py mode change 100755 => 100644 monitoring/grafana/configure-grafana.sh mode change 100755 => 100644 run_tests.py mode change 100755 => 100644 run_tests_by_system.py mode change 100755 => 100644 run_tests_detailed.py mode change 100755 => 100644 run_tests_with_db.sh mode change 100755 => 100644 scripts/backup.sh mode change 100755 => 100644 scripts/restore.sh mode change 100755 => 100644 scripts/run-mock-tests.sh mode change 100755 => 100644 scripts/run-smoke-tests.sh mode change 100755 => 100644 scripts/security_audit.sh mode change 100755 => 100644 scripts/setup-test-environment.sh mode change 100755 => 100644 scripts/test-mock-services-standalone.py mode change 100755 => 100644 scripts/test-mock-services.sh mode change 100755 => 100644 setup-monitoring.sh mode change 100755 => 100644 setup-server-backup.sh mode change 100755 => 100644 setup-server.sh create mode 100644 src/discovery/protocol_discovery_modified.py create mode 100644 start-remote-test.sh mode change 100755 => 100644 test-deployment.sh mode change 100755 => 100644 test-e2e-deployment.py create mode 100644 test-remote-integration.py create mode 100644 test_discovery_debug.py create mode 100644 test_discovery_direct.py create mode 100644 test_discovery_endpoints.py create mode 100644 test_discovery_fast.py mode change 100755 => 100644 validate-deployment.sh diff --git a/.coverage b/.coverage index 2dc776430546d2ead315b702c56f0856c0d729f3..7010a3442704fb8dcf99d95c48ce10f0d14bd509 100644 GIT binary patch delta 200 zcmZozz}&Eac>{|B8zcW#2L7#^1qD{~vw1SIFf@u!zTmBYfKbZ7`^k@=R7Wt;-jdbCdI}U(3&C$&Z1({KVqtaX;Rl=8P<)<&URQ7y6D38-pk7(bdsHO=bm%V zcjta*Hq^j`8kiqg$BHEG0D$LU6I5ukr8lEO&!D(3F@^ z!I^TB7!a&$DSjilQug?q{ynm$yp!p#$w_>5eifR}PGEo=>v^n46YC%YYSBc-d|8*v z(CRFg*Q5A!M6DND5T>yB^-9&}(ba&*=gyM7Ny;@d4(R8Qm z_aJ@~k9Yy|>C=3rT3!~^oSG8&SP3A}Mh=NMEJ~XeseV^bp4M!zBaIDf7Q55{+MrtL z_j+WXOL5A}Hoh;pLK)u`J-KiZA>^R0I?FwpOGRgfw_QXb0Yo)3HcvLK!mCt! z%Djqms(W?-KoVC6V6_kuN5v~p5^2#8e&TcBdEUhR%GL3@Silbn>-c7rB{#>eWrC#J zGoq9<%RG)!;wr{X^pjCa$Y*Nt#4J&Q5*w!Gj*{qL!wjKkkCITth6Td^Pn7sgY?vdW zxue8wWWzS1nKMfE0>&VU*`j32V`>QbN|daHY}iDoIih5lQF@jrnRA&cVlgvHrYZ9| zqBPaJ8Bt=U7S0hR8l5b}-_~@~W<;rJ)M-gy28AU6_P}HCBe)ahKt}vsJSiID7IC={ z7g_{eSb{PX<&EvoMA^bCgvh0B&tiS`mXLV0W1yqy?m*88KD&Dz0QeU*gYFk7p6F^# z8%F@Tn90#oG-yl3Bn3bMLPwE^UF}@N=+AuA75|eSms&A6@C^wmzyiv^4-+gNPFyT@ zxzErW1nk4|5#!)cS3I|G|F{&fWPoqz(;9aJ0NE!vCLB;5D=Ko|!Y<=k%C^};pW>r? z-(R^k_-*&~`e6Hh#4VxL7@IaWml#iy-{g>JyGX~cgIxwlk1vvmt%Z9u^fcLUqJnU)l<*osPx0iB0^jgn|@pIY}*J4|S1&OzsBei!xoB2+9-vJ?z zxo~hae<=%`7xRmcej%C8mu5GoWvwZleI_l zWZf)KlojkrS+KA*NT*ZVcNEcSCbY=G&_Bl9;M2#_DGNyMue;GZbXEHPOyiDvyELCg zf^5^hgVnK)XzZKLru%X7HdH2qh+QmQYVMv7wn&sU^dQ**j%Qdwv2+2jZ4Z(`LZ~x2 z-2fGh`@R%TFLltk)4)!*t~T2H1`ap5yPqSk-DB}zPMgQ#^~D`W;)B}Z_+ZB$QE7BU z8U?%cs>I%6X8|yW1};SRUreP?$+dK(bolm>+)L}nVp?$DtzFKc&XV?#TKwk<;UNH9 z;d6Kw_QPIy6E?!zBD@9%U;{h>55Y6=GWsSo=*CAy36KCM65s^_7M_5}nNS8OJ9&UM f0yZlFvxR`wOn@;FFtG$!hJc;M$7-X$Zpi)@Z=tG^ diff --git a/config/test-remote.yml b/config/test-remote.yml new file mode 100644 index 0000000..3d559d7 --- /dev/null +++ b/config/test-remote.yml @@ -0,0 +1,72 @@ +# Test Configuration for Remote Services +# This config allows local dashboard to discover and interact with remote mock services + +# Application Configuration +app: + name: "Calejo Control Adapter - Test Environment" + version: "2.0" + debug: true + log_level: "INFO" + +# Server Configuration +server: + host: "0.0.0.0" + port: 8081 + workers: 1 + +# Database Configuration (local) +database: + host: "localhost" + port: 5432 + name: "calejo_test" + username: "calejo_user" + password: "test_password" + +# Discovery Configuration +discovery: + enabled: true + scan_interval: 300 # 5 minutes + protocols: + - name: "rest_api" + enabled: true + ports: [8080, 8081, 8082, 8083, 8084, 8085] + timeout: 5 + - name: "opcua" + enabled: false + ports: [4840] + timeout: 10 + - name: "modbus" + enabled: false + ports: [502] + timeout: 5 + +# Remote Services Configuration (pre-configured for discovery) +remote_services: + mock_scada: + name: "Mock SCADA Service" + address: "http://95.111.206.155:8083" + protocol: "rest_api" + enabled: true + mock_optimizer: + name: "Mock Optimizer Service" + address: "http://95.111.206.155:8084" + protocol: "rest_api" + enabled: true + existing_api: + name: "Existing Calejo API" + address: "http://95.111.206.155:8080" + protocol: "rest_api" + enabled: true + +# Security Configuration +security: + enable_auth: false + cors_origins: + - "*" + +# Monitoring Configuration +monitoring: + prometheus_enabled: false + prometheus_port: 9091 + grafana_enabled: false + grafana_port: 3000 \ No newline at end of file diff --git a/database/setup_database.sh b/database/setup_database.sh old mode 100755 new mode 100644 diff --git a/deploy-onprem.sh b/deploy-onprem.sh old mode 100755 new mode 100644 diff --git a/deploy/ssh/deploy-remote.py b/deploy/ssh/deploy-remote.py old mode 100755 new mode 100644 diff --git a/deploy/ssh/deploy-remote.sh b/deploy/ssh/deploy-remote.sh old mode 100755 new mode 100644 diff --git a/generate-monitoring-secrets.sh b/generate-monitoring-secrets.sh old mode 100755 new mode 100644 diff --git a/mock-optimization-server.py b/mock-optimization-server.py old mode 100755 new mode 100644 diff --git a/mock-scada-server.py b/mock-scada-server.py old mode 100755 new mode 100644 diff --git a/monitoring/grafana/configure-grafana.sh b/monitoring/grafana/configure-grafana.sh old mode 100755 new mode 100644 diff --git a/run_tests.py b/run_tests.py old mode 100755 new mode 100644 diff --git a/run_tests_by_system.py b/run_tests_by_system.py old mode 100755 new mode 100644 diff --git a/run_tests_detailed.py b/run_tests_detailed.py old mode 100755 new mode 100644 diff --git a/run_tests_with_db.sh b/run_tests_with_db.sh old mode 100755 new mode 100644 diff --git a/scripts/backup.sh b/scripts/backup.sh old mode 100755 new mode 100644 diff --git a/scripts/restore.sh b/scripts/restore.sh old mode 100755 new mode 100644 diff --git a/scripts/run-mock-tests.sh b/scripts/run-mock-tests.sh old mode 100755 new mode 100644 diff --git a/scripts/run-smoke-tests.sh b/scripts/run-smoke-tests.sh old mode 100755 new mode 100644 diff --git a/scripts/security_audit.sh b/scripts/security_audit.sh old mode 100755 new mode 100644 diff --git a/scripts/setup-test-environment.sh b/scripts/setup-test-environment.sh old mode 100755 new mode 100644 diff --git a/scripts/test-mock-services-standalone.py b/scripts/test-mock-services-standalone.py old mode 100755 new mode 100644 diff --git a/scripts/test-mock-services.sh b/scripts/test-mock-services.sh old mode 100755 new mode 100644 diff --git a/setup-monitoring.sh b/setup-monitoring.sh old mode 100755 new mode 100644 diff --git a/setup-server-backup.sh b/setup-server-backup.sh old mode 100755 new mode 100644 diff --git a/setup-server.sh b/setup-server.sh old mode 100755 new mode 100644 diff --git a/src/discovery/protocol_discovery_modified.py b/src/discovery/protocol_discovery_modified.py new file mode 100644 index 0000000..6373286 --- /dev/null +++ b/src/discovery/protocol_discovery_modified.py @@ -0,0 +1,344 @@ +""" +Modified Protocol Discovery Service + +Auto-discovery service for detecting available protocols and endpoints. +Supports Modbus TCP, Modbus RTU, OPC UA, and REST API discovery. +Modified to include additional ports for testing. +""" + +import asyncio +import socket +import threading +from typing import List, Dict, Optional, Any +from enum import Enum +from dataclasses import dataclass +from datetime import datetime +import logging + +from pydantic import BaseModel + +from src.dashboard.configuration_manager import ProtocolType + +logger = logging.getLogger(__name__) + + +class DiscoveryStatus(Enum): + """Discovery operation status""" + PENDING = "pending" + RUNNING = "running" + COMPLETED = "completed" + FAILED = "failed" + + +@dataclass +class DiscoveredEndpoint: + """Represents a discovered protocol endpoint""" + protocol_type: ProtocolType + address: str + port: Optional[int] = None + device_id: Optional[str] = None + device_name: Optional[str] = None + capabilities: List[str] = None + response_time: Optional[float] = None + discovered_at: datetime = None + + def __post_init__(self): + if self.capabilities is None: + self.capabilities = [] + if self.discovered_at is None: + self.discovered_at = datetime.now() + + +class DiscoveryResult(BaseModel): + """Result of a discovery operation""" + status: DiscoveryStatus + discovered_endpoints: List[DiscoveredEndpoint] + scan_duration: float + errors: List[str] = [] + scan_id: str + timestamp: datetime = None + + def __init__(self, **data): + super().__init__(**data) + if self.timestamp is None: + self.timestamp = datetime.now() + + +class ProtocolDiscoveryService: + """ + Service for auto-discovering available protocol endpoints + """ + + def __init__(self): + self._discovery_results: Dict[str, DiscoveryResult] = {} + self._current_scan_id: Optional[str] = None + self._is_scanning = False + + async def discover_all_protocols(self, scan_id: Optional[str] = None) -> DiscoveryResult: + """ + Discover all available protocol endpoints + + Args: + scan_id: Optional scan identifier + + Returns: + DiscoveryResult with discovered endpoints + """ + if self._is_scanning: + raise RuntimeError("Discovery scan already in progress") + + scan_id = scan_id or f"scan_{datetime.now().strftime('%Y%m%d_%H%M%S')}" + self._current_scan_id = scan_id + self._is_scanning = True + + start_time = datetime.now() + discovered_endpoints = [] + errors = [] + + try: + # Run discovery for each protocol type + discovery_tasks = [ + self._discover_modbus_tcp(), + self._discover_modbus_rtu(), + self._discover_opcua(), + self._discover_rest_api() + ] + + results = await asyncio.gather(*discovery_tasks, return_exceptions=True) + + for result in results: + if isinstance(result, Exception): + errors.append(f"Discovery error: {str(result)}") + logger.error(f"Discovery error: {result}") + elif isinstance(result, list): + discovered_endpoints.extend(result) + + except Exception as e: + errors.append(f"Discovery failed: {str(e)}") + logger.error(f"Discovery failed: {e}") + finally: + self._is_scanning = False + + scan_duration = (datetime.now() - start_time).total_seconds() + + result = DiscoveryResult( + status=DiscoveryStatus.COMPLETED if not errors else DiscoveryStatus.FAILED, + discovered_endpoints=discovered_endpoints, + scan_duration=scan_duration, + errors=errors, + scan_id=scan_id + ) + + self._discovery_results[scan_id] = result + return result + + async def _discover_modbus_tcp(self) -> List[DiscoveredEndpoint]: + """Discover Modbus TCP devices on the network""" + discovered = [] + + # Common Modbus TCP ports + common_ports = [502, 1502, 5020] + + # Common network ranges to scan + network_ranges = [ + "192.168.1.", # Common home/office network + "10.0.0.", # Common corporate network + "172.16.0.", # Common corporate network + ] + + for network_range in network_ranges: + for i in range(1, 255): # Scan first 254 hosts + ip_address = f"{network_range}{i}" + + for port in common_ports: + try: + if await self._check_modbus_tcp_device(ip_address, port): + endpoint = DiscoveredEndpoint( + protocol_type=ProtocolType.MODBUS_TCP, + address=ip_address, + port=port, + device_id=f"modbus_tcp_{ip_address}_{port}", + device_name=f"Modbus TCP Device {ip_address}:{port}", + capabilities=["read_coils", "read_registers", "write_registers"] + ) + discovered.append(endpoint) + logger.info(f"Discovered Modbus TCP device at {ip_address}:{port}") + break # Found device, no need to check other ports + except Exception as e: + logger.debug(f"Failed to connect to {ip_address}:{port}: {e}") + + return discovered + + async def _discover_modbus_rtu(self) -> List[DiscoveredEndpoint]: + """Discover Modbus RTU devices (serial ports)""" + discovered = [] + + # Common serial ports + common_ports = ["/dev/ttyUSB0", "/dev/ttyUSB1", "/dev/ttyACM0", "/dev/ttyACM1", + "COM1", "COM2", "COM3", "COM4"] + + for port in common_ports: + try: + if await self._check_modbus_rtu_device(port): + endpoint = DiscoveredEndpoint( + protocol_type=ProtocolType.MODBUS_RTU, + address=port, + device_id=f"modbus_rtu_{port}", + device_name=f"Modbus RTU Device {port}", + capabilities=["read_coils", "read_registers", "write_registers"] + ) + discovered.append(endpoint) + logger.info(f"Discovered Modbus RTU device at {port}") + except Exception as e: + logger.debug(f"Failed to check Modbus RTU port {port}: {e}") + + return discovered + + async def _discover_opcua(self) -> List[DiscoveredEndpoint]: + """Discover OPC UA servers on the network""" + discovered = [] + + # Common OPC UA ports + common_ports = [4840, 4841, 4848] + + # Common network ranges + network_ranges = [ + "192.168.1.", + "10.0.0.", + "172.16.0.", + ] + + for network_range in network_ranges: + for i in range(1, 255): + ip_address = f"{network_range}{i}" + + for port in common_ports: + try: + if await self._check_opcua_server(ip_address, port): + endpoint = DiscoveredEndpoint( + protocol_type=ProtocolType.OPC_UA, + address=f"opc.tcp://{ip_address}:{port}", + port=port, + device_id=f"opcua_{ip_address}_{port}", + device_name=f"OPC UA Server {ip_address}:{port}", + capabilities=["browse_nodes", "read_values", "write_values", "subscribe"] + ) + discovered.append(endpoint) + logger.info(f"Discovered OPC UA server at {ip_address}:{port}") + break + except Exception as e: + logger.debug(f"Failed to connect to OPC UA server {ip_address}:{port}: {e}") + + return discovered + + async def _discover_rest_api(self) -> List[DiscoveredEndpoint]: + """Discover REST API endpoints""" + discovered = [] + + # Common REST API endpoints to check - MODIFIED to include test ports + common_endpoints = [ + ("http://localhost:8000", "REST API Localhost"), + ("http://localhost:8080", "REST API Localhost"), + ("http://localhost:8081", "REST API Localhost"), + ("http://localhost:8082", "REST API Localhost"), + ("http://localhost:8083", "REST API Localhost"), + ("http://localhost:8084", "REST API Localhost"), + ("http://localhost:3000", "REST API Localhost"), + ] + + for endpoint, name in common_endpoints: + try: + if await self._check_rest_api_endpoint(endpoint): + discovered_endpoint = DiscoveredEndpoint( + protocol_type=ProtocolType.REST_API, + address=endpoint, + device_id=f"rest_api_{endpoint.replace('://', '_').replace('/', '_')}", + device_name=name, + capabilities=["get", "post", "put", "delete"] + ) + discovered.append(discovered_endpoint) + logger.info(f"Discovered REST API endpoint at {endpoint}") + except Exception as e: + logger.debug(f"Failed to check REST API endpoint {endpoint}: {e}") + + return discovered + + async def _check_modbus_tcp_device(self, ip: str, port: int) -> bool: + """Check if a Modbus TCP device is available""" + try: + # Simple TCP connection check + reader, writer = await asyncio.wait_for( + asyncio.open_connection(ip, port), + timeout=2.0 + ) + writer.close() + await writer.wait_closed() + return True + except: + return False + + async def _check_modbus_rtu_device(self, port: str) -> bool: + """Check if a Modbus RTU device is available""" + import os + + # Check if serial port exists + if not os.path.exists(port): + return False + + # Additional checks could be added here for actual device communication + return True + + async def _check_opcua_server(self, ip: str, port: int) -> bool: + """Check if an OPC UA server is available""" + try: + # Simple TCP connection check + reader, writer = await asyncio.wait_for( + asyncio.open_connection(ip, port), + timeout=2.0 + ) + writer.close() + await writer.wait_closed() + return True + except: + return False + + async def _check_rest_api_endpoint(self, endpoint: str) -> bool: + """Check if a REST API endpoint is available""" + try: + import aiohttp + + async with aiohttp.ClientSession() as session: + async with session.get(endpoint, timeout=5) as response: + return response.status < 500 # Consider available if not server error + except: + return False + + def get_discovery_status(self) -> Dict[str, Any]: + """Get current discovery status""" + return { + "is_scanning": self._is_scanning, + "current_scan_id": self._current_scan_id, + "recent_scans": list(self._discovery_results.keys())[-5:], # Last 5 scans + "total_discovered_endpoints": sum( + len(result.discovered_endpoints) + for result in self._discovery_results.values() + ) + } + + def get_scan_result(self, scan_id: str) -> Optional[DiscoveryResult]: + """Get result for a specific scan""" + return self._discovery_results.get(scan_id) + + def get_recent_discoveries(self, limit: int = 10) -> List[DiscoveredEndpoint]: + """Get most recently discovered endpoints""" + all_endpoints = [] + for result in self._discovery_results.values(): + all_endpoints.extend(result.discovered_endpoints) + + # Sort by discovery time (most recent first) + all_endpoints.sort(key=lambda x: x.discovered_at, reverse=True) + return all_endpoints[:limit] + + +# Global discovery service instance +discovery_service = ProtocolDiscoveryService() \ No newline at end of file diff --git a/start-remote-test.sh b/start-remote-test.sh new file mode 100644 index 0000000..849243e --- /dev/null +++ b/start-remote-test.sh @@ -0,0 +1,63 @@ +#!/bin/bash + +# Calejo Control Adapter - Remote Test Environment +# Starts the dashboard locally but configured to work with remote services + +set -e + +echo "šŸš€ Starting Calejo Control Adapter - Remote Test Environment" +echo "==========================================================" + +# Check if Python is available +if ! command -v python &> /dev/null; then + echo "āŒ Python is not installed or not in PATH" + exit 1 +fi + +# Check if we're in the right directory +if [ ! -f "start_dashboard.py" ]; then + echo "āŒ Please run this script from the calejo-control-adapter directory" + exit 1 +fi + +# Set environment variables for remote testing +export CALEJO_CONFIG_FILE="config/test-remote.yml" +export CALEJO_LOG_LEVEL="INFO" +export CALEJO_DEBUG="true" + +# Test remote services connectivity +echo "" +echo "šŸ” Testing remote service connectivity..." + +# Test Mock SCADA Service +if curl -s --connect-timeout 5 http://95.111.206.155:8083/health > /dev/null; then + echo "āœ… Mock SCADA Service (8083): ACCESSIBLE" +else + echo "āŒ Mock SCADA Service (8083): NOT ACCESSIBLE" +fi + +# Test Mock Optimizer Service +if curl -s --connect-timeout 5 http://95.111.206.155:8084/health > /dev/null; then + echo "āœ… Mock Optimizer Service (8084): ACCESSIBLE" +else + echo "āŒ Mock Optimizer Service (8084): NOT ACCESSIBLE" +fi + +# Test Existing API +if curl -s --connect-timeout 5 http://95.111.206.155:8080/health > /dev/null; then + echo "āœ… Existing Calejo API (8080): ACCESSIBLE" +else + echo "āŒ Existing Calejo API (8080): NOT ACCESSIBLE" +fi + +echo "" +echo "šŸ“Š Starting Dashboard on port 8081..." +echo " - Local Dashboard: http://localhost:8081" +echo " - Remote Services: http://95.111.206.155:8083,8084" +echo " - Discovery API: http://localhost:8081/api/v1/dashboard/discovery" +echo "" +echo "Press Ctrl+C to stop the dashboard" +echo "" + +# Start the dashboard +python start_dashboard.py \ No newline at end of file diff --git a/test-deployment.sh b/test-deployment.sh old mode 100755 new mode 100644 diff --git a/test-e2e-deployment.py b/test-e2e-deployment.py old mode 100755 new mode 100644 diff --git a/test-remote-integration.py b/test-remote-integration.py new file mode 100644 index 0000000..02cbada --- /dev/null +++ b/test-remote-integration.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python3 +""" +Test script to verify remote integration with Calejo Control Adapter +Tests discovery and interaction with remote mock services +""" + +import requests +import json +import time +import sys + +def test_dashboard_health(): + """Test if dashboard is running""" + try: + response = requests.get("http://localhost:8080/health", timeout=5) + if response.status_code == 200: + data = response.json() + print(f"āœ… Dashboard health: {data}") + return True + else: + print(f"āŒ Dashboard health check failed: {response.status_code}") + return False + except Exception as e: + print(f"āŒ Dashboard health check error: {e}") + return False + +def test_discovery_scan(): + """Test discovery scan functionality""" + try: + response = requests.post("http://localhost:8080/api/v1/dashboard/discovery/scan", timeout=10) + if response.status_code == 200: + data = response.json() + print(f"āœ… Discovery scan started: {data}") + return data.get('scan_id') + else: + print(f"āŒ Discovery scan failed: {response.status_code}") + return None + except Exception as e: + print(f"āŒ Discovery scan error: {e}") + return None + +def test_discovery_status(): + """Test discovery status""" + try: + response = requests.get("http://localhost:8080/api/v1/dashboard/discovery/status", timeout=5) + if response.status_code == 200: + data = response.json() + print(f"āœ… Discovery status: {data}") + return data + else: + print(f"āŒ Discovery status failed: {response.status_code}") + return None + except Exception as e: + print(f"āŒ Discovery status error: {e}") + return None + +def test_recent_discoveries(): + """Test recent discoveries endpoint""" + try: + response = requests.get("http://localhost:8080/api/v1/dashboard/discovery/recent", timeout=5) + if response.status_code == 200: + data = response.json() + print(f"āœ… Recent discoveries: Found {len(data.get('recent_endpoints', []))} endpoints") + + # Show discovered endpoints + for endpoint in data.get('recent_endpoints', []): + print(f" - {endpoint.get('device_name')} ({endpoint.get('address')})") + + return data + else: + print(f"āŒ Recent discoveries failed: {response.status_code}") + return None + except Exception as e: + print(f"āŒ Recent discoveries error: {e}") + return None + +def test_remote_services(): + """Test direct access to remote services""" + services = [ + ("Mock SCADA", "http://95.111.206.155:8083/health"), + ("Mock Optimizer", "http://95.111.206.155:8084/health"), + ("Existing API", "http://95.111.206.155:8080/health") + ] + + all_accessible = True + for name, url in services: + try: + response = requests.get(url, timeout=5) + if response.status_code == 200: + print(f"āœ… {name}: ACCESSIBLE - {response.json()}") + else: + print(f"āŒ {name}: NOT ACCESSIBLE - Status {response.status_code}") + all_accessible = False + except Exception as e: + print(f"āŒ {name}: ERROR - {e}") + all_accessible = False + + return all_accessible + +def main(): + print("šŸš€ Calejo Control Adapter - Remote Integration Test") + print("=" * 60) + + # Test dashboard health + if not test_dashboard_health(): + print("\nāŒ Dashboard not accessible. Please start the dashboard first.") + sys.exit(1) + + print("\nšŸ” Testing remote service connectivity...") + remote_ok = test_remote_services() + + print("\nšŸ“Š Testing discovery functionality...") + + # Start discovery scan + scan_id = test_discovery_scan() + + if scan_id: + print(f"\nā³ Waiting for discovery scan to complete...") + time.sleep(5) + + # Check discovery status + status = test_discovery_status() + + # Check recent discoveries + discoveries = test_recent_discoveries() + + print("\n" + "=" * 60) + print("šŸ“‹ TEST SUMMARY:") + print(f" Dashboard Health: āœ…") + print(f" Remote Services: {'āœ…' if remote_ok else 'āŒ'}") + print(f" Discovery Scan: {'āœ…' if scan_id else 'āŒ'}") + print(f" Endpoints Found: {status.get('status', {}).get('total_discovered_endpoints', 0) if status else 0}") + + if status and status.get('status', {}).get('total_discovered_endpoints', 0) >= 2: + print("\nšŸŽ‰ SUCCESS: Remote integration test passed!") + print(" The system can discover and interact with remote services.") + else: + print("\nāš ļø WARNING: Some tests may have issues.") + else: + print("\nāŒ Discovery scan failed. Check dashboard logs.") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/test_discovery_debug.py b/test_discovery_debug.py new file mode 100644 index 0000000..ebfc0f0 --- /dev/null +++ b/test_discovery_debug.py @@ -0,0 +1,56 @@ +#!/usr/bin/env python3 +""" +Debug test of the discovery service with detailed logging +""" +import asyncio +import sys +import os +import logging + +# Add src to path +sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src')) + +# Set up logging +logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') + +from discovery.protocol_discovery_modified import discovery_service + +async def test_discovery_debug(): + """Test discovery service with debug logging""" + print("Starting discovery test with debug logging...") + + try: + # Test individual discovery methods + print("\n1. Testing REST API discovery...") + rest_endpoints = await discovery_service._discover_rest_api() + print(f" Found {len(rest_endpoints)} REST endpoints") + + print("\n2. Testing Modbus TCP discovery...") + modbus_tcp_endpoints = await discovery_service._discover_modbus_tcp() + print(f" Found {len(modbus_tcp_endpoints)} Modbus TCP endpoints") + + print("\n3. Testing Modbus RTU discovery...") + modbus_rtu_endpoints = await discovery_service._discover_modbus_rtu() + print(f" Found {len(modbus_rtu_endpoints)} Modbus RTU endpoints") + + print("\n4. Testing OPC UA discovery...") + opcua_endpoints = await discovery_service._discover_opcua() + print(f" Found {len(opcua_endpoints)} OPC UA endpoints") + + print("\n5. Testing full discovery...") + result = await discovery_service.discover_all_protocols("test_scan") + + print(f"\nDiscovery completed!") + print(f"Total discovered endpoints: {len(result.discovered_endpoints)}") + print(f"Errors: {result.errors}") + + for endpoint in result.discovered_endpoints: + print(f" - {endpoint.protocol_type}: {endpoint.address}") + + except Exception as e: + print(f"Discovery failed: {e}") + import traceback + traceback.print_exc() + +if __name__ == "__main__": + asyncio.run(test_discovery_debug()) \ No newline at end of file diff --git a/test_discovery_direct.py b/test_discovery_direct.py new file mode 100644 index 0000000..6645020 --- /dev/null +++ b/test_discovery_direct.py @@ -0,0 +1,35 @@ +#!/usr/bin/env python3 +""" +Direct test of the discovery service +""" +import asyncio +import sys +import os + +# Add src to path +sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src')) + +from discovery.protocol_discovery_modified import discovery_service + +async def test_discovery(): + """Test discovery service directly""" + print("Starting discovery test...") + + try: + # Start discovery + result = await discovery_service.discover_all_protocols("test_scan") + + print(f"Discovery completed!") + print(f"Discovered endpoints: {len(result.discovered_endpoints)}") + print(f"Errors: {result.errors}") + + for endpoint in result.discovered_endpoints: + print(f" - {endpoint.protocol_type}: {endpoint.address}") + + except Exception as e: + print(f"Discovery failed: {e}") + import traceback + traceback.print_exc() + +if __name__ == "__main__": + asyncio.run(test_discovery()) \ No newline at end of file diff --git a/test_discovery_endpoints.py b/test_discovery_endpoints.py new file mode 100644 index 0000000..528730e --- /dev/null +++ b/test_discovery_endpoints.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python3 +""" +Test script to verify discovery API endpoints are working +""" + +import requests +import json + +def test_discovery_endpoints(base_url="http://localhost:8081"): + """Test all discovery API endpoints""" + + print(f"Testing discovery endpoints at {base_url}") + print("=" * 60) + + # Test 1: Discovery status + print("\n1. Testing discovery status endpoint...") + try: + response = requests.get(f"{base_url}/api/v1/dashboard/discovery/status") + if response.status_code == 200: + status_data = response.json() + print(f" āœ“ Status endpoint working") + print(f" - Is scanning: {status_data['status']['is_scanning']}") + print(f" - Current scan ID: {status_data['status']['current_scan_id']}") + print(f" - Total endpoints: {status_data['status']['total_discovered_endpoints']}") + else: + print(f" āœ— Status endpoint failed: {response.status_code}") + except Exception as e: + print(f" āœ— Status endpoint error: {e}") + + # Test 2: Start discovery scan + print("\n2. Testing discovery scan endpoint...") + try: + response = requests.post(f"{base_url}/api/v1/dashboard/discovery/scan") + if response.status_code == 200: + scan_data = response.json() + print(f" āœ“ Scan endpoint working") + print(f" - Scan ID: {scan_data.get('scan_id', 'N/A')}") + print(f" - Message: {scan_data.get('message', 'N/A')}") + + # Store scan ID for later testing + scan_id = scan_data.get('scan_id') + else: + print(f" āœ— Scan endpoint failed: {response.status_code}") + scan_id = None + except Exception as e: + print(f" āœ— Scan endpoint error: {e}") + scan_id = None + + # Test 3: Check scan status after starting + if scan_id: + print(f"\n3. Checking scan status for {scan_id}...") + import time + time.sleep(2) # Wait a bit for scan to start + + try: + response = requests.get(f"{base_url}/api/v1/dashboard/discovery/status") + if response.status_code == 200: + status_data = response.json() + print(f" āœ“ Status check working") + print(f" - Is scanning: {status_data['status']['is_scanning']}") + print(f" - Current scan ID: {status_data['status']['current_scan_id']}") + else: + print(f" āœ— Status check failed: {response.status_code}") + except Exception as e: + print(f" āœ— Status check error: {e}") + + # Test 4: Test discovery results endpoint (even if no results yet) + print("\n4. Testing discovery results endpoint...") + test_scan_id = "test_scan_123" + try: + response = requests.get(f"{base_url}/api/v1/dashboard/discovery/results/{test_scan_id}") + if response.status_code == 404: + print(f" āœ“ Results endpoint working (correctly returned 404 for non-existent scan)") + elif response.status_code == 200: + print(f" āœ“ Results endpoint working") + results_data = response.json() + print(f" - Scan ID: {results_data.get('scan_id', 'N/A')}") + print(f" - Status: {results_data.get('status', 'N/A')}") + print(f" - Endpoints found: {len(results_data.get('discovered_endpoints', []))}") + else: + print(f" āœ— Results endpoint unexpected response: {response.status_code}") + except Exception as e: + print(f" āœ— Results endpoint error: {e}") + + print("\n" + "=" * 60) + print("Discovery API testing completed!") + +if __name__ == "__main__": + # Test local test environment + test_discovery_endpoints("http://localhost:8081") \ No newline at end of file diff --git a/test_discovery_fast.py b/test_discovery_fast.py new file mode 100644 index 0000000..f690dfb --- /dev/null +++ b/test_discovery_fast.py @@ -0,0 +1,40 @@ +#!/usr/bin/env python3 +""" +Test the fast discovery service +""" +import asyncio +import sys +import os +import logging + +# Add src to path +sys.path.insert(0, os.path.join(os.path.dirname(__file__), 'src')) + +# Set up logging +logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s') + +from discovery.protocol_discovery_fast import discovery_service + +async def test_discovery_fast(): + """Test fast discovery service""" + print("Starting fast discovery test...") + + try: + # Test full discovery + print("\nTesting full discovery...") + result = await discovery_service.discover_all_protocols("fast_test_scan") + + print(f"\nDiscovery completed in {result.scan_duration:.2f} seconds!") + print(f"Total discovered endpoints: {len(result.discovered_endpoints)}") + print(f"Errors: {result.errors}") + + for endpoint in result.discovered_endpoints: + print(f" - {endpoint.protocol_type}: {endpoint.address}") + + except Exception as e: + print(f"Discovery failed: {e}") + import traceback + traceback.print_exc() + +if __name__ == "__main__": + asyncio.run(test_discovery_fast()) \ No newline at end of file diff --git a/validate-deployment.sh b/validate-deployment.sh old mode 100755 new mode 100644