mcp-proxy-adapter 2.0.1__py3-none-any.whl → 6.9.50__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of mcp-proxy-adapter might be problematic. Click here for more details.
- mcp_proxy_adapter/__init__.py +47 -0
- mcp_proxy_adapter/__main__.py +13 -0
- mcp_proxy_adapter/api/__init__.py +0 -0
- mcp_proxy_adapter/api/app.py +66 -0
- mcp_proxy_adapter/api/core/__init__.py +18 -0
- mcp_proxy_adapter/api/core/app_factory.py +400 -0
- mcp_proxy_adapter/api/core/lifespan_manager.py +55 -0
- mcp_proxy_adapter/api/core/registration_context.py +356 -0
- mcp_proxy_adapter/api/core/registration_manager.py +307 -0
- mcp_proxy_adapter/api/core/registration_tasks.py +84 -0
- mcp_proxy_adapter/api/core/ssl_context_factory.py +88 -0
- mcp_proxy_adapter/api/handlers.py +181 -0
- mcp_proxy_adapter/api/middleware/__init__.py +21 -0
- mcp_proxy_adapter/api/middleware/base.py +54 -0
- mcp_proxy_adapter/api/middleware/command_permission_middleware.py +73 -0
- mcp_proxy_adapter/api/middleware/error_handling.py +76 -0
- mcp_proxy_adapter/api/middleware/factory.py +147 -0
- mcp_proxy_adapter/api/middleware/logging.py +31 -0
- mcp_proxy_adapter/api/middleware/performance.py +51 -0
- mcp_proxy_adapter/api/middleware/protocol_middleware.py +140 -0
- mcp_proxy_adapter/api/middleware/transport_middleware.py +87 -0
- mcp_proxy_adapter/api/middleware/unified_security.py +223 -0
- mcp_proxy_adapter/api/middleware/user_info_middleware.py +132 -0
- mcp_proxy_adapter/api/openapi/__init__.py +21 -0
- mcp_proxy_adapter/api/openapi/command_integration.py +105 -0
- mcp_proxy_adapter/api/openapi/openapi_generator.py +40 -0
- mcp_proxy_adapter/api/openapi/openapi_registry.py +62 -0
- mcp_proxy_adapter/api/openapi/schema_loader.py +116 -0
- mcp_proxy_adapter/api/schemas.py +270 -0
- mcp_proxy_adapter/api/tool_integration.py +131 -0
- mcp_proxy_adapter/api/tools.py +163 -0
- mcp_proxy_adapter/cli/__init__.py +12 -0
- mcp_proxy_adapter/cli/commands/__init__.py +15 -0
- mcp_proxy_adapter/cli/commands/client.py +100 -0
- mcp_proxy_adapter/cli/commands/config_generate.py +105 -0
- mcp_proxy_adapter/cli/commands/config_validate.py +94 -0
- mcp_proxy_adapter/cli/commands/generate.py +259 -0
- mcp_proxy_adapter/cli/commands/server.py +174 -0
- mcp_proxy_adapter/cli/commands/sets.py +132 -0
- mcp_proxy_adapter/cli/commands/testconfig.py +177 -0
- mcp_proxy_adapter/cli/examples/__init__.py +8 -0
- mcp_proxy_adapter/cli/examples/http_basic.py +82 -0
- mcp_proxy_adapter/cli/examples/https_token.py +96 -0
- mcp_proxy_adapter/cli/examples/mtls_roles.py +103 -0
- mcp_proxy_adapter/cli/main.py +63 -0
- mcp_proxy_adapter/cli/parser.py +338 -0
- mcp_proxy_adapter/cli/validators.py +231 -0
- mcp_proxy_adapter/client/jsonrpc_client/__init__.py +9 -0
- mcp_proxy_adapter/client/jsonrpc_client/client.py +42 -0
- mcp_proxy_adapter/client/jsonrpc_client/command_api.py +45 -0
- mcp_proxy_adapter/client/jsonrpc_client/proxy_api.py +224 -0
- mcp_proxy_adapter/client/jsonrpc_client/queue_api.py +60 -0
- mcp_proxy_adapter/client/jsonrpc_client/transport.py +108 -0
- mcp_proxy_adapter/client/proxy.py +123 -0
- mcp_proxy_adapter/commands/__init__.py +66 -0
- mcp_proxy_adapter/commands/auth_validation_command.py +69 -0
- mcp_proxy_adapter/commands/base.py +389 -0
- mcp_proxy_adapter/commands/builtin_commands.py +30 -0
- mcp_proxy_adapter/commands/catalog/__init__.py +20 -0
- mcp_proxy_adapter/commands/catalog/catalog_loader.py +34 -0
- mcp_proxy_adapter/commands/catalog/catalog_manager.py +122 -0
- mcp_proxy_adapter/commands/catalog/catalog_syncer.py +149 -0
- mcp_proxy_adapter/commands/catalog/command_catalog.py +43 -0
- mcp_proxy_adapter/commands/catalog/dependency_manager.py +37 -0
- mcp_proxy_adapter/commands/catalog_manager.py +97 -0
- mcp_proxy_adapter/commands/cert_monitor_command.py +552 -0
- mcp_proxy_adapter/commands/certificate_management_command.py +562 -0
- mcp_proxy_adapter/commands/command_registry.py +298 -0
- mcp_proxy_adapter/commands/config_command.py +102 -0
- mcp_proxy_adapter/commands/dependency_container.py +40 -0
- mcp_proxy_adapter/commands/dependency_manager.py +143 -0
- mcp_proxy_adapter/commands/echo_command.py +48 -0
- mcp_proxy_adapter/commands/health_command.py +142 -0
- mcp_proxy_adapter/commands/help_command.py +175 -0
- mcp_proxy_adapter/commands/hooks.py +172 -0
- mcp_proxy_adapter/commands/key_management_command.py +484 -0
- mcp_proxy_adapter/commands/load_command.py +123 -0
- mcp_proxy_adapter/commands/plugins_command.py +246 -0
- mcp_proxy_adapter/commands/protocol_management_command.py +216 -0
- mcp_proxy_adapter/commands/proxy_registration_command.py +319 -0
- mcp_proxy_adapter/commands/queue_commands.py +750 -0
- mcp_proxy_adapter/commands/registration_status_command.py +76 -0
- mcp_proxy_adapter/commands/registry/__init__.py +18 -0
- mcp_proxy_adapter/commands/registry/command_info.py +103 -0
- mcp_proxy_adapter/commands/registry/command_loader.py +207 -0
- mcp_proxy_adapter/commands/registry/command_manager.py +119 -0
- mcp_proxy_adapter/commands/registry/command_registry.py +217 -0
- mcp_proxy_adapter/commands/reload_command.py +136 -0
- mcp_proxy_adapter/commands/result.py +157 -0
- mcp_proxy_adapter/commands/role_test_command.py +99 -0
- mcp_proxy_adapter/commands/roles_management_command.py +502 -0
- mcp_proxy_adapter/commands/security_command.py +472 -0
- mcp_proxy_adapter/commands/settings_command.py +113 -0
- mcp_proxy_adapter/commands/ssl_setup_command.py +306 -0
- mcp_proxy_adapter/commands/token_management_command.py +500 -0
- mcp_proxy_adapter/commands/transport_management_command.py +129 -0
- mcp_proxy_adapter/commands/unload_command.py +92 -0
- mcp_proxy_adapter/config.py +32 -0
- mcp_proxy_adapter/core/__init__.py +8 -0
- mcp_proxy_adapter/core/app_factory.py +560 -0
- mcp_proxy_adapter/core/app_runner.py +318 -0
- mcp_proxy_adapter/core/auth_validator.py +508 -0
- mcp_proxy_adapter/core/certificate/__init__.py +20 -0
- mcp_proxy_adapter/core/certificate/certificate_creator.py +372 -0
- mcp_proxy_adapter/core/certificate/certificate_extractor.py +185 -0
- mcp_proxy_adapter/core/certificate/certificate_utils.py +249 -0
- mcp_proxy_adapter/core/certificate/certificate_validator.py +481 -0
- mcp_proxy_adapter/core/certificate/ssl_context_manager.py +65 -0
- mcp_proxy_adapter/core/certificate_utils.py +249 -0
- mcp_proxy_adapter/core/client.py +608 -0
- mcp_proxy_adapter/core/client_manager.py +271 -0
- mcp_proxy_adapter/core/client_security.py +411 -0
- mcp_proxy_adapter/core/config/__init__.py +18 -0
- mcp_proxy_adapter/core/config/config.py +237 -0
- mcp_proxy_adapter/core/config/config_factory.py +22 -0
- mcp_proxy_adapter/core/config/config_loader.py +66 -0
- mcp_proxy_adapter/core/config/feature_manager.py +31 -0
- mcp_proxy_adapter/core/config/simple_config.py +204 -0
- mcp_proxy_adapter/core/config/simple_config_generator.py +131 -0
- mcp_proxy_adapter/core/config/simple_config_validator.py +476 -0
- mcp_proxy_adapter/core/config_converter.py +252 -0
- mcp_proxy_adapter/core/config_validator.py +211 -0
- mcp_proxy_adapter/core/crl_utils.py +362 -0
- mcp_proxy_adapter/core/errors.py +276 -0
- mcp_proxy_adapter/core/job_manager.py +54 -0
- mcp_proxy_adapter/core/logging.py +250 -0
- mcp_proxy_adapter/core/mtls_asgi.py +140 -0
- mcp_proxy_adapter/core/mtls_asgi_app.py +187 -0
- mcp_proxy_adapter/core/mtls_proxy.py +229 -0
- mcp_proxy_adapter/core/mtls_server.py +154 -0
- mcp_proxy_adapter/core/protocol_manager.py +232 -0
- mcp_proxy_adapter/core/proxy/__init__.py +19 -0
- mcp_proxy_adapter/core/proxy/auth_manager.py +26 -0
- mcp_proxy_adapter/core/proxy/proxy_registration_manager.py +160 -0
- mcp_proxy_adapter/core/proxy/registration_client.py +186 -0
- mcp_proxy_adapter/core/proxy/ssl_manager.py +101 -0
- mcp_proxy_adapter/core/proxy_client.py +184 -0
- mcp_proxy_adapter/core/proxy_registration.py +80 -0
- mcp_proxy_adapter/core/role_utils.py +103 -0
- mcp_proxy_adapter/core/security_adapter.py +343 -0
- mcp_proxy_adapter/core/security_factory.py +96 -0
- mcp_proxy_adapter/core/security_integration.py +342 -0
- mcp_proxy_adapter/core/server_adapter.py +251 -0
- mcp_proxy_adapter/core/server_engine.py +217 -0
- mcp_proxy_adapter/core/settings.py +260 -0
- mcp_proxy_adapter/core/signal_handler.py +107 -0
- mcp_proxy_adapter/core/ssl_utils.py +161 -0
- mcp_proxy_adapter/core/transport_manager.py +153 -0
- mcp_proxy_adapter/core/unified_config_adapter.py +471 -0
- mcp_proxy_adapter/core/utils.py +101 -0
- mcp_proxy_adapter/core/validation/__init__.py +21 -0
- mcp_proxy_adapter/core/validation/config_validator.py +219 -0
- mcp_proxy_adapter/core/validation/file_validator.py +131 -0
- mcp_proxy_adapter/core/validation/protocol_validator.py +205 -0
- mcp_proxy_adapter/core/validation/security_validator.py +140 -0
- mcp_proxy_adapter/core/validation/validation_result.py +27 -0
- mcp_proxy_adapter/custom_openapi.py +58 -0
- mcp_proxy_adapter/examples/__init__.py +16 -0
- mcp_proxy_adapter/examples/basic_framework/__init__.py +9 -0
- mcp_proxy_adapter/examples/basic_framework/commands/__init__.py +4 -0
- mcp_proxy_adapter/examples/basic_framework/hooks/__init__.py +4 -0
- mcp_proxy_adapter/examples/basic_framework/main.py +52 -0
- mcp_proxy_adapter/examples/bugfix_certificate_config.py +261 -0
- mcp_proxy_adapter/examples/cert_manager_bugfix.py +203 -0
- mcp_proxy_adapter/examples/check_config.py +413 -0
- mcp_proxy_adapter/examples/client_usage_example.py +164 -0
- mcp_proxy_adapter/examples/commands/__init__.py +5 -0
- mcp_proxy_adapter/examples/config_builder.py +234 -0
- mcp_proxy_adapter/examples/config_cli.py +282 -0
- mcp_proxy_adapter/examples/create_test_configs.py +174 -0
- mcp_proxy_adapter/examples/debug_request_state.py +130 -0
- mcp_proxy_adapter/examples/debug_role_chain.py +191 -0
- mcp_proxy_adapter/examples/demo_client.py +287 -0
- mcp_proxy_adapter/examples/full_application/__init__.py +12 -0
- mcp_proxy_adapter/examples/full_application/commands/__init__.py +8 -0
- mcp_proxy_adapter/examples/full_application/commands/custom_echo_command.py +45 -0
- mcp_proxy_adapter/examples/full_application/commands/dynamic_calculator_command.py +52 -0
- mcp_proxy_adapter/examples/full_application/commands/echo_command.py +32 -0
- mcp_proxy_adapter/examples/full_application/commands/help_command.py +54 -0
- mcp_proxy_adapter/examples/full_application/commands/list_command.py +57 -0
- mcp_proxy_adapter/examples/full_application/hooks/__init__.py +5 -0
- mcp_proxy_adapter/examples/full_application/hooks/application_hooks.py +29 -0
- mcp_proxy_adapter/examples/full_application/hooks/builtin_command_hooks.py +27 -0
- mcp_proxy_adapter/examples/full_application/main.py +311 -0
- mcp_proxy_adapter/examples/full_application/proxy_endpoints.py +161 -0
- mcp_proxy_adapter/examples/full_application/run_mtls.py +252 -0
- mcp_proxy_adapter/examples/full_application/run_simple.py +152 -0
- mcp_proxy_adapter/examples/full_application/test_minimal_server.py +45 -0
- mcp_proxy_adapter/examples/full_application/test_server.py +163 -0
- mcp_proxy_adapter/examples/full_application/test_simple_server.py +62 -0
- mcp_proxy_adapter/examples/generate_config.py +502 -0
- mcp_proxy_adapter/examples/proxy_registration_example.py +335 -0
- mcp_proxy_adapter/examples/queue_demo_simple.py +632 -0
- mcp_proxy_adapter/examples/queue_integration_example.py +578 -0
- mcp_proxy_adapter/examples/queue_server_demo.py +82 -0
- mcp_proxy_adapter/examples/queue_server_example.py +85 -0
- mcp_proxy_adapter/examples/queue_server_simple.py +173 -0
- mcp_proxy_adapter/examples/required_certificates.py +208 -0
- mcp_proxy_adapter/examples/run_example.py +77 -0
- mcp_proxy_adapter/examples/run_full_test_suite.py +619 -0
- mcp_proxy_adapter/examples/run_proxy_server.py +153 -0
- mcp_proxy_adapter/examples/run_security_tests_fixed.py +435 -0
- mcp_proxy_adapter/examples/security_test/__init__.py +18 -0
- mcp_proxy_adapter/examples/security_test/auth_manager.py +14 -0
- mcp_proxy_adapter/examples/security_test/ssl_context_manager.py +28 -0
- mcp_proxy_adapter/examples/security_test/test_client.py +159 -0
- mcp_proxy_adapter/examples/security_test/test_result.py +22 -0
- mcp_proxy_adapter/examples/security_test_client.py +72 -0
- mcp_proxy_adapter/examples/setup/__init__.py +24 -0
- mcp_proxy_adapter/examples/setup/certificate_manager.py +215 -0
- mcp_proxy_adapter/examples/setup/config_generator.py +12 -0
- mcp_proxy_adapter/examples/setup/config_validator.py +118 -0
- mcp_proxy_adapter/examples/setup/environment_setup.py +62 -0
- mcp_proxy_adapter/examples/setup/test_files_generator.py +10 -0
- mcp_proxy_adapter/examples/setup/test_runner.py +89 -0
- mcp_proxy_adapter/examples/setup_test_environment.py +235 -0
- mcp_proxy_adapter/examples/simple_protocol_test.py +125 -0
- mcp_proxy_adapter/examples/test_chk_hostname_automated.py +211 -0
- mcp_proxy_adapter/examples/test_config.py +205 -0
- mcp_proxy_adapter/examples/test_config_builder.py +110 -0
- mcp_proxy_adapter/examples/test_examples.py +308 -0
- mcp_proxy_adapter/examples/test_framework_complete.py +267 -0
- mcp_proxy_adapter/examples/test_mcp_server.py +187 -0
- mcp_proxy_adapter/examples/test_protocol_examples.py +337 -0
- mcp_proxy_adapter/examples/universal_client.py +674 -0
- mcp_proxy_adapter/examples/update_config_certificates.py +135 -0
- mcp_proxy_adapter/examples/validate_generator_compatibility.py +385 -0
- mcp_proxy_adapter/examples/validate_generator_compatibility_simple.py +61 -0
- mcp_proxy_adapter/integrations/__init__.py +25 -0
- mcp_proxy_adapter/integrations/queuemgr_integration.py +462 -0
- mcp_proxy_adapter/main.py +311 -0
- mcp_proxy_adapter/openapi.py +375 -0
- mcp_proxy_adapter/schemas/base_schema.json +114 -0
- mcp_proxy_adapter/schemas/openapi_schema.json +314 -0
- mcp_proxy_adapter/schemas/roles.json +37 -0
- mcp_proxy_adapter/schemas/roles_schema.json +162 -0
- mcp_proxy_adapter/version.py +5 -0
- mcp_proxy_adapter-6.9.50.dist-info/METADATA +1088 -0
- mcp_proxy_adapter-6.9.50.dist-info/RECORD +242 -0
- {mcp_proxy_adapter-2.0.1.dist-info → mcp_proxy_adapter-6.9.50.dist-info}/WHEEL +1 -1
- mcp_proxy_adapter-6.9.50.dist-info/entry_points.txt +14 -0
- mcp_proxy_adapter-6.9.50.dist-info/top_level.txt +1 -0
- adapters/__init__.py +0 -16
- analyzers/__init__.py +0 -14
- analyzers/docstring_analyzer.py +0 -199
- analyzers/type_analyzer.py +0 -151
- cli/__init__.py +0 -12
- cli/__main__.py +0 -79
- cli/command_runner.py +0 -233
- dispatchers/__init__.py +0 -14
- dispatchers/base_dispatcher.py +0 -85
- dispatchers/json_rpc_dispatcher.py +0 -198
- generators/__init__.py +0 -14
- generators/endpoint_generator.py +0 -172
- generators/openapi_generator.py +0 -254
- generators/rest_api_generator.py +0 -207
- mcp_proxy_adapter-2.0.1.dist-info/METADATA +0 -272
- mcp_proxy_adapter-2.0.1.dist-info/RECORD +0 -28
- mcp_proxy_adapter-2.0.1.dist-info/licenses/LICENSE +0 -21
- mcp_proxy_adapter-2.0.1.dist-info/top_level.txt +0 -7
- openapi_schema/__init__.py +0 -38
- openapi_schema/command_registry.py +0 -312
- openapi_schema/rest_schema.py +0 -510
- openapi_schema/rpc_generator.py +0 -307
- openapi_schema/rpc_schema.py +0 -416
- validators/__init__.py +0 -14
- validators/base_validator.py +0 -23
- validators/docstring_validator.py +0 -75
- validators/metadata_validator.py +0 -76
|
@@ -0,0 +1,619 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
"""
|
|
3
|
+
Author: Vasiliy Zdanovskiy
|
|
4
|
+
email: vasilyvz@gmail.com
|
|
5
|
+
Full test suite runner for MCP Proxy Adapter.
|
|
6
|
+
Automates the complete testing workflow.
|
|
7
|
+
"""
|
|
8
|
+
import os
|
|
9
|
+
import sys
|
|
10
|
+
import subprocess
|
|
11
|
+
from pathlib import Path
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class FullTestSuiteRunner:
|
|
15
|
+
"""Comprehensive test suite runner that automates the entire testing process."""
|
|
16
|
+
|
|
17
|
+
def __init__(self):
|
|
18
|
+
"""Initialize the test suite runner."""
|
|
19
|
+
self.working_dir = Path.cwd()
|
|
20
|
+
self.configs_dir = self.working_dir / "configs"
|
|
21
|
+
self.certs_dir = self.working_dir / "certs"
|
|
22
|
+
self.keys_dir = self.working_dir / "keys"
|
|
23
|
+
self.roles_file = self.working_dir / "configs" / "roles.json"
|
|
24
|
+
|
|
25
|
+
def print_step(self, step: str, description: str):
|
|
26
|
+
"""Print a formatted step header."""
|
|
27
|
+
print(f"\n{'=' * 60}")
|
|
28
|
+
print(f"🔧 STEP {step}: {description}")
|
|
29
|
+
print(f"{'=' * 60}")
|
|
30
|
+
|
|
31
|
+
def print_success(self, message: str):
|
|
32
|
+
"""Print a success message."""
|
|
33
|
+
print(f"✅ {message}")
|
|
34
|
+
|
|
35
|
+
def print_error(self, message: str):
|
|
36
|
+
"""Print an error message."""
|
|
37
|
+
print(f"❌ {message}")
|
|
38
|
+
|
|
39
|
+
def print_info(self, message: str):
|
|
40
|
+
"""Print an info message."""
|
|
41
|
+
print(f"ℹ️ {message}")
|
|
42
|
+
|
|
43
|
+
def check_environment(self) -> bool:
|
|
44
|
+
"""Check if the environment is properly set up."""
|
|
45
|
+
self.print_step("1", "Environment Validation")
|
|
46
|
+
|
|
47
|
+
# Check if we're in a virtual environment
|
|
48
|
+
if not hasattr(sys, "real_prefix") and not (
|
|
49
|
+
hasattr(sys, "base_prefix") and sys.base_prefix != sys.prefix
|
|
50
|
+
):
|
|
51
|
+
self.print_error("Not running in a virtual environment!")
|
|
52
|
+
self.print_info("Please activate your virtual environment first:")
|
|
53
|
+
self.print_info(" source venv/bin/activate # or .venv/bin/activate")
|
|
54
|
+
return False
|
|
55
|
+
|
|
56
|
+
self.print_success("Virtual environment is active")
|
|
57
|
+
|
|
58
|
+
# Check if mcp_proxy_adapter is installed
|
|
59
|
+
try:
|
|
60
|
+
import mcp_proxy_adapter
|
|
61
|
+
|
|
62
|
+
self.print_success(
|
|
63
|
+
f"mcp_proxy_adapter is installed (version: {mcp_proxy_adapter.__version__})"
|
|
64
|
+
)
|
|
65
|
+
except ImportError:
|
|
66
|
+
self.print_error("mcp_proxy_adapter is not installed!")
|
|
67
|
+
self.print_info("Please install it first:")
|
|
68
|
+
self.print_info(" pip install mcp_proxy_adapter")
|
|
69
|
+
return False
|
|
70
|
+
|
|
71
|
+
# Check Python version
|
|
72
|
+
python_version = sys.version_info
|
|
73
|
+
if python_version.major >= 3 and python_version.minor >= 8:
|
|
74
|
+
self.print_success(
|
|
75
|
+
f"Python version: {python_version.major}.{python_version.minor}.{python_version.micro}"
|
|
76
|
+
)
|
|
77
|
+
else:
|
|
78
|
+
self.print_error(
|
|
79
|
+
f"Python {python_version.major}.{python_version.minor} is not supported. Need Python 3.8+"
|
|
80
|
+
)
|
|
81
|
+
return False
|
|
82
|
+
|
|
83
|
+
return True
|
|
84
|
+
|
|
85
|
+
def create_directories(self) -> bool:
|
|
86
|
+
"""Create necessary directories for testing."""
|
|
87
|
+
self.print_step("2", "Directory Creation")
|
|
88
|
+
|
|
89
|
+
try:
|
|
90
|
+
# Create configs directory
|
|
91
|
+
self.configs_dir.mkdir(exist_ok=True)
|
|
92
|
+
self.print_success(
|
|
93
|
+
f"Created/verified configs directory: {self.configs_dir}"
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
# Create certs directory
|
|
97
|
+
self.certs_dir.mkdir(exist_ok=True)
|
|
98
|
+
self.print_success(f"Created/verified certs directory: {self.certs_dir}")
|
|
99
|
+
|
|
100
|
+
# Create keys directory
|
|
101
|
+
self.keys_dir.mkdir(exist_ok=True)
|
|
102
|
+
self.print_success(f"Created/verified keys directory: {self.keys_dir}")
|
|
103
|
+
|
|
104
|
+
return True
|
|
105
|
+
|
|
106
|
+
except Exception as e:
|
|
107
|
+
self.print_error(f"Failed to create directories: {e}")
|
|
108
|
+
return False
|
|
109
|
+
|
|
110
|
+
def generate_certificates(self) -> bool:
|
|
111
|
+
"""Generate SSL certificates for testing."""
|
|
112
|
+
self.print_step("3", "Certificate Generation")
|
|
113
|
+
|
|
114
|
+
try:
|
|
115
|
+
# Check if certificate generation script exists
|
|
116
|
+
cert_script = self.working_dir / "mcp_proxy_adapter" / "examples" / "generate_certificates.py"
|
|
117
|
+
if not cert_script.exists():
|
|
118
|
+
self.print_error(
|
|
119
|
+
f"Certificate generation script not found: {cert_script}"
|
|
120
|
+
)
|
|
121
|
+
return False
|
|
122
|
+
|
|
123
|
+
# Run certificate generation script
|
|
124
|
+
cmd = [sys.executable, str(cert_script)]
|
|
125
|
+
self.print_info("Running certificate generation script...")
|
|
126
|
+
|
|
127
|
+
result = subprocess.run(
|
|
128
|
+
cmd, capture_output=True, text=True, cwd=self.working_dir
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
if result.returncode == 0:
|
|
132
|
+
self.print_success("Certificates generated successfully")
|
|
133
|
+
if result.stdout:
|
|
134
|
+
print(result.stdout)
|
|
135
|
+
|
|
136
|
+
# Update configuration files with correct certificate paths
|
|
137
|
+
self.print_info("Updating configuration files with correct certificate paths...")
|
|
138
|
+
update_script = self.working_dir / "update_config_certificates.py"
|
|
139
|
+
if update_script.exists():
|
|
140
|
+
update_cmd = [sys.executable, str(update_script)]
|
|
141
|
+
update_result = subprocess.run(
|
|
142
|
+
update_cmd, capture_output=True, text=True, cwd=self.working_dir
|
|
143
|
+
)
|
|
144
|
+
if update_result.returncode == 0:
|
|
145
|
+
self.print_success("Configuration files updated successfully")
|
|
146
|
+
else:
|
|
147
|
+
self.print_error(f"Failed to update configuration files: {update_result.stderr}")
|
|
148
|
+
|
|
149
|
+
return True
|
|
150
|
+
else:
|
|
151
|
+
self.print_error("Certificate generation failed!")
|
|
152
|
+
if result.stderr:
|
|
153
|
+
print("Error output:")
|
|
154
|
+
print(result.stderr)
|
|
155
|
+
# Don't fail the entire suite if certificate generation fails
|
|
156
|
+
# Allow it to continue with existing certificates
|
|
157
|
+
self.print_info("Continuing with existing certificates...")
|
|
158
|
+
return True
|
|
159
|
+
|
|
160
|
+
except Exception as e:
|
|
161
|
+
self.print_error(f"Failed to generate certificates: {e}")
|
|
162
|
+
return False
|
|
163
|
+
|
|
164
|
+
def generate_configurations(self) -> bool:
|
|
165
|
+
"""Generate test configurations from comprehensive config."""
|
|
166
|
+
self.print_step("4", "Configuration Generation")
|
|
167
|
+
|
|
168
|
+
try:
|
|
169
|
+
# Check if create_test_configs.py exists
|
|
170
|
+
config_script = self.working_dir / "mcp_proxy_adapter" / "examples" / "create_test_configs.py"
|
|
171
|
+
if not config_script.exists():
|
|
172
|
+
self.print_error(f"Configuration generator not found: {config_script}")
|
|
173
|
+
return False
|
|
174
|
+
|
|
175
|
+
# Check if comprehensive_config.json exists
|
|
176
|
+
comprehensive_config = self.working_dir / "comprehensive_config.json"
|
|
177
|
+
if not comprehensive_config.exists():
|
|
178
|
+
self.print_error(
|
|
179
|
+
f"Comprehensive config not found: {comprehensive_config}"
|
|
180
|
+
)
|
|
181
|
+
return False
|
|
182
|
+
|
|
183
|
+
self.print_info(
|
|
184
|
+
"Generating test configurations from comprehensive config..."
|
|
185
|
+
)
|
|
186
|
+
self.print_info("This will create:")
|
|
187
|
+
self.print_info(" - HTTP configurations (simple and with auth)")
|
|
188
|
+
self.print_info(" - HTTPS configurations (simple and with auth)")
|
|
189
|
+
self.print_info(
|
|
190
|
+
" - mTLS configurations (simple, with roles, with proxy registration)"
|
|
191
|
+
)
|
|
192
|
+
self.print_info(" - Full featured configuration (everything enabled)")
|
|
193
|
+
|
|
194
|
+
# Run the configuration generator
|
|
195
|
+
cmd = [
|
|
196
|
+
sys.executable,
|
|
197
|
+
"mcp_proxy_adapter/examples/create_test_configs.py",
|
|
198
|
+
"--comprehensive-config",
|
|
199
|
+
"comprehensive_config.json",
|
|
200
|
+
]
|
|
201
|
+
result = subprocess.run(
|
|
202
|
+
cmd, capture_output=True, text=True, cwd=self.working_dir
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
if result.returncode == 0:
|
|
206
|
+
self.print_success("Configuration generation completed successfully!")
|
|
207
|
+
if result.stdout:
|
|
208
|
+
print("Generator output:")
|
|
209
|
+
print(result.stdout)
|
|
210
|
+
|
|
211
|
+
# Create roles.json file
|
|
212
|
+
self.print_info("Creating roles.json file...")
|
|
213
|
+
roles_content = {
|
|
214
|
+
"roles": {
|
|
215
|
+
"admin": {
|
|
216
|
+
"permissions": ["*"],
|
|
217
|
+
"description": "Full administrative access",
|
|
218
|
+
},
|
|
219
|
+
"user": {
|
|
220
|
+
"permissions": ["read", "write"],
|
|
221
|
+
"description": "Standard user access",
|
|
222
|
+
},
|
|
223
|
+
"readonly": {
|
|
224
|
+
"permissions": ["read"],
|
|
225
|
+
"description": "Read-only access",
|
|
226
|
+
},
|
|
227
|
+
"guest": {
|
|
228
|
+
"permissions": ["read"],
|
|
229
|
+
"description": "Limited guest access",
|
|
230
|
+
},
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
roles_file = self.configs_dir / "roles.json"
|
|
235
|
+
import json
|
|
236
|
+
|
|
237
|
+
with open(roles_file, "w", encoding="utf-8") as f:
|
|
238
|
+
json.dump(roles_content, f, indent=2, ensure_ascii=False)
|
|
239
|
+
self.print_success(f"Created roles.json: {roles_file}")
|
|
240
|
+
|
|
241
|
+
return True
|
|
242
|
+
else:
|
|
243
|
+
self.print_error("Configuration generation failed!")
|
|
244
|
+
if result.stdout:
|
|
245
|
+
print("Generator output:")
|
|
246
|
+
print(result.stdout)
|
|
247
|
+
if result.stderr:
|
|
248
|
+
print("Error output:")
|
|
249
|
+
print(result.stderr)
|
|
250
|
+
return False
|
|
251
|
+
|
|
252
|
+
except Exception as e:
|
|
253
|
+
self.print_error(f"Failed to generate configurations: {e}")
|
|
254
|
+
return False
|
|
255
|
+
|
|
256
|
+
def run_security_tests(self) -> bool:
|
|
257
|
+
"""Run the security test suite."""
|
|
258
|
+
self.print_step("5", "Security Testing")
|
|
259
|
+
|
|
260
|
+
try:
|
|
261
|
+
# Run security tests
|
|
262
|
+
cmd = [sys.executable, "run_security_tests_fixed.py", "--verbose"]
|
|
263
|
+
self.print_info("Running security tests...")
|
|
264
|
+
|
|
265
|
+
# Debug: show current working directory and check files
|
|
266
|
+
self.print_info(f"DEBUG: Current working directory: {os.getcwd()}")
|
|
267
|
+
self.print_info(f"DEBUG: Working directory from class: {self.working_dir}")
|
|
268
|
+
|
|
269
|
+
# Check if certificates exist before running tests
|
|
270
|
+
localhost_cert = self.certs_dir / "localhost_server.crt"
|
|
271
|
+
self.print_info(
|
|
272
|
+
f"DEBUG: localhost_server.crt exists: {localhost_cert.exists()}"
|
|
273
|
+
)
|
|
274
|
+
if localhost_cert.exists():
|
|
275
|
+
self.print_info(
|
|
276
|
+
f"DEBUG: localhost_server.crt is symlink: {localhost_cert.is_symlink()}"
|
|
277
|
+
)
|
|
278
|
+
if localhost_cert.is_symlink():
|
|
279
|
+
self.print_info(
|
|
280
|
+
f"DEBUG: localhost_server.crt symlink target: {localhost_cert.readlink()}"
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
# List all files in certs directory
|
|
284
|
+
self.print_info("DEBUG: Files in certs directory:")
|
|
285
|
+
for file in self.certs_dir.iterdir():
|
|
286
|
+
self.print_info(f"DEBUG: {file.name} -> {file}")
|
|
287
|
+
|
|
288
|
+
result = subprocess.run(
|
|
289
|
+
cmd, capture_output=True, text=True, cwd=self.working_dir
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
if result.returncode == 0:
|
|
293
|
+
self.print_success("Security tests completed successfully!")
|
|
294
|
+
if result.stdout:
|
|
295
|
+
print(result.stdout)
|
|
296
|
+
return True
|
|
297
|
+
else:
|
|
298
|
+
self.print_error("Security tests failed!")
|
|
299
|
+
if result.stdout:
|
|
300
|
+
print("Test output:")
|
|
301
|
+
print(result.stdout)
|
|
302
|
+
if result.stderr:
|
|
303
|
+
print("Error output:")
|
|
304
|
+
print(result.stderr)
|
|
305
|
+
return False
|
|
306
|
+
|
|
307
|
+
except Exception as e:
|
|
308
|
+
self.print_error(f"Failed to run security tests: {e}")
|
|
309
|
+
return False
|
|
310
|
+
|
|
311
|
+
def run_mtls_registration_test(self) -> bool:
|
|
312
|
+
"""Run mTLS with proxy registration test."""
|
|
313
|
+
self.print_step("6", "mTLS Proxy Registration Testing")
|
|
314
|
+
|
|
315
|
+
try:
|
|
316
|
+
# Check if test_proxy_registration.py exists
|
|
317
|
+
test_script = self.working_dir / "test_proxy_registration.py"
|
|
318
|
+
if not test_script.exists():
|
|
319
|
+
self.print_error(f"Test script not found: {test_script}")
|
|
320
|
+
return False
|
|
321
|
+
|
|
322
|
+
# Create test_proxy_registration.json config if it doesn't exist
|
|
323
|
+
test_config = self.configs_dir / "test_proxy_registration.json"
|
|
324
|
+
if not test_config.exists():
|
|
325
|
+
self.print_info(
|
|
326
|
+
"Creating test_proxy_registration.json configuration..."
|
|
327
|
+
)
|
|
328
|
+
test_config_content = {
|
|
329
|
+
"uuid": "550e8400-e29b-41d4-a716-446655440001",
|
|
330
|
+
"server": {"host": "127.0.0.1", "port": 20006},
|
|
331
|
+
"ssl": {
|
|
332
|
+
"enabled": True,
|
|
333
|
+
"cert_file": "certs/localhost_server.crt",
|
|
334
|
+
"key_file": "keys/server_key.pem",
|
|
335
|
+
"ca_cert": "certs/mcp_proxy_adapter_ca_ca.crt",
|
|
336
|
+
"client_cert_file": "certs/admin_cert.pem",
|
|
337
|
+
"client_key_file": "certs/admin_key.pem",
|
|
338
|
+
"verify_client": True,
|
|
339
|
+
},
|
|
340
|
+
"registration": {
|
|
341
|
+
"enabled": True,
|
|
342
|
+
"auth_method": "token",
|
|
343
|
+
"server_url": "https://127.0.0.1:20005/register",
|
|
344
|
+
"proxy_url": "https://127.0.0.1:20005",
|
|
345
|
+
"fallback_proxy_url": "http://127.0.0.1:20005",
|
|
346
|
+
"ssl": {
|
|
347
|
+
"verify_mode": "CERT_NONE",
|
|
348
|
+
"check_hostname": False
|
|
349
|
+
},
|
|
350
|
+
"server_id": "mcp_test_server",
|
|
351
|
+
"server_name": "MCP Test Server",
|
|
352
|
+
"description": "Test server for proxy registration",
|
|
353
|
+
"version": "1.0.0",
|
|
354
|
+
"token": {
|
|
355
|
+
"enabled": True,
|
|
356
|
+
"token": "proxy_registration_token_123",
|
|
357
|
+
},
|
|
358
|
+
"proxy_info": {
|
|
359
|
+
"name": "mcp_test_server",
|
|
360
|
+
"description": "Test server for proxy registration",
|
|
361
|
+
"version": "1.0.0",
|
|
362
|
+
"capabilities": [
|
|
363
|
+
"jsonrpc",
|
|
364
|
+
"rest",
|
|
365
|
+
"security",
|
|
366
|
+
"proxy_registration",
|
|
367
|
+
],
|
|
368
|
+
"endpoints": {
|
|
369
|
+
"jsonrpc": "/api/jsonrpc",
|
|
370
|
+
"rest": "/cmd",
|
|
371
|
+
"health": "/health",
|
|
372
|
+
},
|
|
373
|
+
},
|
|
374
|
+
"heartbeat": {
|
|
375
|
+
"enabled": True,
|
|
376
|
+
"interval": 30,
|
|
377
|
+
"timeout": 10,
|
|
378
|
+
"retry_attempts": 3,
|
|
379
|
+
"retry_delay": 60
|
|
380
|
+
},
|
|
381
|
+
},
|
|
382
|
+
"security": {
|
|
383
|
+
"enabled": True,
|
|
384
|
+
"auth": {"enabled": True, "methods": ["certificate"]},
|
|
385
|
+
"permissions": {
|
|
386
|
+
"enabled": True,
|
|
387
|
+
"roles_file": "configs/roles.json",
|
|
388
|
+
},
|
|
389
|
+
},
|
|
390
|
+
"protocols": {
|
|
391
|
+
"enabled": True,
|
|
392
|
+
"default_protocol": "mtls",
|
|
393
|
+
"allowed_protocols": ["https", "mtls"],
|
|
394
|
+
},
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
import json
|
|
398
|
+
|
|
399
|
+
with open(test_config, "w", encoding="utf-8") as f:
|
|
400
|
+
json.dump(test_config_content, f, indent=2)
|
|
401
|
+
self.print_success(f"Created test configuration: {test_config}")
|
|
402
|
+
|
|
403
|
+
self.print_info("Running mTLS proxy registration test...")
|
|
404
|
+
self.print_info("This test verifies:")
|
|
405
|
+
self.print_info(
|
|
406
|
+
" - mTLS server startup with client certificate verification"
|
|
407
|
+
)
|
|
408
|
+
self.print_info(" - Proxy registration functionality")
|
|
409
|
+
self.print_info(" - SSL configuration validation")
|
|
410
|
+
|
|
411
|
+
# Run the test
|
|
412
|
+
cmd = [sys.executable, "test_proxy_registration.py"]
|
|
413
|
+
result = subprocess.run(
|
|
414
|
+
cmd, capture_output=True, text=True, cwd=self.working_dir
|
|
415
|
+
)
|
|
416
|
+
|
|
417
|
+
if result.returncode == 0:
|
|
418
|
+
self.print_success(
|
|
419
|
+
"mTLS proxy registration test completed successfully!"
|
|
420
|
+
)
|
|
421
|
+
if result.stdout:
|
|
422
|
+
print("Test output:")
|
|
423
|
+
print(result.stdout)
|
|
424
|
+
return True
|
|
425
|
+
else:
|
|
426
|
+
self.print_error("mTLS proxy registration test failed!")
|
|
427
|
+
if result.stdout:
|
|
428
|
+
print("Test output:")
|
|
429
|
+
print(result.stdout)
|
|
430
|
+
if result.stderr:
|
|
431
|
+
print("Error output:")
|
|
432
|
+
print(result.stderr)
|
|
433
|
+
return False
|
|
434
|
+
|
|
435
|
+
except Exception as e:
|
|
436
|
+
self.print_error(f"Failed to run mTLS registration test: {e}")
|
|
437
|
+
return False
|
|
438
|
+
|
|
439
|
+
def cleanup(self):
|
|
440
|
+
"""Clean up temporary files and processes."""
|
|
441
|
+
self.print_info("Cleaning up...")
|
|
442
|
+
|
|
443
|
+
# Simple cleanup - just print success message
|
|
444
|
+
# Process cleanup is handled by the test scripts themselves
|
|
445
|
+
print("✅ Cleanup completed")
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
def test_all_configurations(self) -> bool:
|
|
449
|
+
"""Test all server configurations including proxy registration."""
|
|
450
|
+
self.print_step("7", "Testing All Server Configurations")
|
|
451
|
+
|
|
452
|
+
# List of all configuration files to test
|
|
453
|
+
config_files = [
|
|
454
|
+
"http_simple.json",
|
|
455
|
+
"http_auth.json",
|
|
456
|
+
"http_token.json",
|
|
457
|
+
"https_simple.json",
|
|
458
|
+
"https_auth.json",
|
|
459
|
+
"https_token.json",
|
|
460
|
+
"mtls_simple.json",
|
|
461
|
+
"mtls_no_roles.json",
|
|
462
|
+
"mtls_with_roles.json",
|
|
463
|
+
"mtls_with_proxy.json",
|
|
464
|
+
"full_featured.json"
|
|
465
|
+
]
|
|
466
|
+
|
|
467
|
+
results = []
|
|
468
|
+
errors = []
|
|
469
|
+
|
|
470
|
+
for config_file in config_files:
|
|
471
|
+
config_path = self.configs_dir / config_file
|
|
472
|
+
if not config_path.exists():
|
|
473
|
+
error_msg = f"Configuration file not found: {config_file}"
|
|
474
|
+
self.print_error(error_msg)
|
|
475
|
+
errors.append(error_msg)
|
|
476
|
+
results.append((config_file, False, error_msg))
|
|
477
|
+
continue
|
|
478
|
+
|
|
479
|
+
self.print_info(f"Testing configuration: {config_file}")
|
|
480
|
+
|
|
481
|
+
try:
|
|
482
|
+
# Test server startup with this configuration
|
|
483
|
+
cmd = [
|
|
484
|
+
sys.executable, "-m", "mcp_proxy_adapter",
|
|
485
|
+
"--config", str(config_path)
|
|
486
|
+
]
|
|
487
|
+
|
|
488
|
+
# Run server for 5 seconds to test startup
|
|
489
|
+
result = subprocess.run(
|
|
490
|
+
cmd,
|
|
491
|
+
capture_output=True,
|
|
492
|
+
text=True,
|
|
493
|
+
timeout=10,
|
|
494
|
+
cwd=self.working_dir
|
|
495
|
+
)
|
|
496
|
+
|
|
497
|
+
if result.returncode == 0:
|
|
498
|
+
self.print_success(f"✅ {config_file} - Server started successfully")
|
|
499
|
+
results.append((config_file, True, "Server started successfully"))
|
|
500
|
+
else:
|
|
501
|
+
error_msg = f"Server failed to start: {result.stderr[:200]}"
|
|
502
|
+
self.print_error(f"❌ {config_file} - {error_msg}")
|
|
503
|
+
errors.append(f"{config_file}: {error_msg}")
|
|
504
|
+
results.append((config_file, False, error_msg))
|
|
505
|
+
|
|
506
|
+
except subprocess.TimeoutExpired:
|
|
507
|
+
# Server started successfully (timeout means it's running)
|
|
508
|
+
self.print_success(f"✅ {config_file} - Server started and running")
|
|
509
|
+
results.append((config_file, True, "Server started and running"))
|
|
510
|
+
except Exception as e:
|
|
511
|
+
error_msg = f"Test failed: {str(e)}"
|
|
512
|
+
self.print_error(f"❌ {config_file} - {error_msg}")
|
|
513
|
+
errors.append(f"{config_file}: {error_msg}")
|
|
514
|
+
results.append((config_file, False, error_msg))
|
|
515
|
+
|
|
516
|
+
# Print summary
|
|
517
|
+
self.print_step("7.1", "Configuration Test Results Summary")
|
|
518
|
+
successful = sum(1 for _, success, _ in results if success)
|
|
519
|
+
total = len(results)
|
|
520
|
+
|
|
521
|
+
print(f"📊 Configuration Test Results:")
|
|
522
|
+
print(f" Total configurations tested: {total}")
|
|
523
|
+
print(f" Successful: {successful}")
|
|
524
|
+
print(f" Failed: {total - successful}")
|
|
525
|
+
print(f" Success rate: {(successful/total)*100:.1f}%")
|
|
526
|
+
|
|
527
|
+
if errors:
|
|
528
|
+
print(f"\n❌ Errors encountered:")
|
|
529
|
+
for error in errors:
|
|
530
|
+
print(f" • {error}")
|
|
531
|
+
|
|
532
|
+
return len(errors) == 0
|
|
533
|
+
|
|
534
|
+
def run_full_suite(self) -> bool:
|
|
535
|
+
"""Run the complete test suite."""
|
|
536
|
+
print("🚀 MCP Proxy Adapter - Full Test Suite")
|
|
537
|
+
print("=" * 60)
|
|
538
|
+
print(f"Working directory: {self.working_dir}")
|
|
539
|
+
print(f"Python executable: {sys.executable}")
|
|
540
|
+
|
|
541
|
+
try:
|
|
542
|
+
# Step 1: Environment validation
|
|
543
|
+
if not self.check_environment():
|
|
544
|
+
return False
|
|
545
|
+
|
|
546
|
+
# Step 2: Directory creation
|
|
547
|
+
if not self.create_directories():
|
|
548
|
+
return False
|
|
549
|
+
|
|
550
|
+
# Step 3: Certificate generation (skip if fails, use existing certificates)
|
|
551
|
+
self.generate_certificates() # Don't fail if certificates already exist
|
|
552
|
+
|
|
553
|
+
# Step 4: Configuration generation
|
|
554
|
+
if not self.generate_configurations():
|
|
555
|
+
return False
|
|
556
|
+
|
|
557
|
+
# Step 5: Security testing
|
|
558
|
+
if not self.run_security_tests():
|
|
559
|
+
return False
|
|
560
|
+
|
|
561
|
+
# Step 6: mTLS proxy registration testing
|
|
562
|
+
if not self.run_mtls_registration_test():
|
|
563
|
+
return False
|
|
564
|
+
|
|
565
|
+
# Step 7: Test all configurations
|
|
566
|
+
if not self.test_all_configurations():
|
|
567
|
+
return False
|
|
568
|
+
|
|
569
|
+
# All steps completed successfully
|
|
570
|
+
print(f"\n{'=' * 60}")
|
|
571
|
+
print("🎉 FULL TEST SUITE COMPLETED SUCCESSFULLY!")
|
|
572
|
+
print("=" * 60)
|
|
573
|
+
print("✅ Environment validated")
|
|
574
|
+
print("✅ Directories cleaned")
|
|
575
|
+
print("✅ Directories created")
|
|
576
|
+
print("✅ Certificates generated")
|
|
577
|
+
print("✅ Configurations generated")
|
|
578
|
+
print("✅ Security tests passed")
|
|
579
|
+
print("✅ mTLS proxy registration test passed")
|
|
580
|
+
print("✅ All server configurations tested")
|
|
581
|
+
print(f"\n📁 Test artifacts created in: {self.working_dir}")
|
|
582
|
+
print(f"📁 Configurations: {self.configs_dir}")
|
|
583
|
+
print(f"📁 Certificates: {self.certs_dir}")
|
|
584
|
+
print(f"📁 Keys: {self.keys_dir}")
|
|
585
|
+
|
|
586
|
+
return True
|
|
587
|
+
|
|
588
|
+
except KeyboardInterrupt:
|
|
589
|
+
print("\n\n⚠️ Test suite interrupted by user")
|
|
590
|
+
return False
|
|
591
|
+
except Exception as e:
|
|
592
|
+
self.print_error(f"Unexpected error during test suite execution: {e}")
|
|
593
|
+
return False
|
|
594
|
+
finally:
|
|
595
|
+
try:
|
|
596
|
+
self.print_info("Starting cleanup in finally block...")
|
|
597
|
+
self.cleanup()
|
|
598
|
+
self.print_info("Cleanup in finally block completed")
|
|
599
|
+
except Exception as e:
|
|
600
|
+
self.print_error(f"Cleanup failed in finally block: {e}")
|
|
601
|
+
import traceback
|
|
602
|
+
|
|
603
|
+
traceback.print_exc()
|
|
604
|
+
|
|
605
|
+
|
|
606
|
+
def main():
|
|
607
|
+
"""Main entry point."""
|
|
608
|
+
runner = FullTestSuiteRunner()
|
|
609
|
+
|
|
610
|
+
try:
|
|
611
|
+
success = runner.run_full_suite()
|
|
612
|
+
sys.exit(0 if success else 1)
|
|
613
|
+
except Exception as e:
|
|
614
|
+
print(f"❌ Fatal error: {e}")
|
|
615
|
+
sys.exit(1)
|
|
616
|
+
|
|
617
|
+
|
|
618
|
+
if __name__ == "__main__":
|
|
619
|
+
main()
|