9
9
import requests
10
10
from unittest .mock import patch
11
11
12
+
12
13
class ProcessManager :
13
14
"""Manages background processes for HTTP server testing."""
14
-
15
+
15
16
def __init__ (self ):
16
17
self .processes = []
17
-
18
+
18
19
def start_http_server (self , timeout = 30 ):
19
20
"""Start HTTP server in background and wait for it to be ready."""
20
21
print ("Starting HTTP server for testing..." )
21
-
22
+
22
23
# Change to project root directory
23
24
project_root = Path (__file__ ).parent .parent .parent
24
-
25
+
25
26
# Start server process
26
27
cmd = [
27
- sys .executable , "-m" , "uvicorn" ,
28
+ sys .executable ,
29
+ "-m" ,
30
+ "uvicorn" ,
28
31
"src.adaptive_graph_of_thoughts.main:app" ,
29
- "--host" , "0.0.0.0" ,
30
- "--port" , "8000" ,
31
- "--log-level" , "info"
32
+ "--host" ,
33
+ "0.0.0.0" ,
34
+ "--port" ,
35
+ "8000" ,
36
+ "--log-level" ,
37
+ "info" ,
32
38
]
33
-
39
+
34
40
process = subprocess .Popen (
35
41
cmd ,
36
42
stdout = subprocess .PIPE ,
37
43
stderr = subprocess .PIPE ,
38
44
preexec_fn = os .setsid , # Create new process group
39
- cwd = project_root
45
+ cwd = project_root ,
40
46
)
41
47
self .processes .append (process )
42
48
@@ -56,7 +62,7 @@ def start_http_server(self, timeout=30):
56
62
time .sleep (2 )
57
63
58
64
raise TimeoutError ("HTTP server failed to start within timeout" )
59
-
65
+
60
66
def cleanup (self ):
61
67
"""Clean up all managed processes."""
62
68
for proc in self .processes :
@@ -69,22 +75,22 @@ def cleanup(self):
69
75
except ProcessLookupError :
70
76
pass
71
77
78
+
72
79
def run_with_retry (command , max_retries = 2 , timeout = 180 ):
73
80
"""Run command with retry logic and proper timeout handling."""
74
81
for attempt in range (max_retries + 1 ):
75
82
try :
76
83
print (f"Attempt { attempt + 1 } /{ max_retries + 1 } : { ' ' .join (command )} " )
77
84
result = subprocess .run (
78
- command ,
79
- capture_output = True ,
80
- text = True ,
81
- timeout = timeout
85
+ command , capture_output = True , text = True , timeout = timeout
82
86
)
83
87
if result .returncode == 0 :
84
88
print ("✅ MCP Inspector validation passed!" )
85
89
print ("Output:" , result .stdout )
86
90
return True
87
- print (f"❌ Exit { result .returncode } . Stdout: { result .stdout } Stderr: { result .stderr } " )
91
+ print (
92
+ f"❌ Exit { result .returncode } . Stdout: { result .stdout } Stderr: { result .stderr } "
93
+ )
88
94
if attempt < max_retries :
89
95
wait = 5 * (attempt + 1 )
90
96
print (f"⏳ Retrying in { wait } s..." )
@@ -101,14 +107,13 @@ def run_with_retry(command, max_retries=2, timeout=180):
101
107
time .sleep (5 )
102
108
return False
103
109
110
+
104
111
@pytest .fixture (autouse = True )
105
112
def setup_test_environment ():
106
113
"""Setup test environment and ensure dependencies are available."""
107
114
try :
108
115
res = subprocess .run (
109
- ["mcp-inspector" , "--version" ],
110
- capture_output = True ,
111
- timeout = 10
116
+ ["mcp-inspector" , "--version" ], capture_output = True , timeout = 10
112
117
)
113
118
if res .returncode != 0 :
114
119
pytest .skip ("mcp-inspector not available" )
@@ -120,21 +125,27 @@ def setup_test_environment():
120
125
yield
121
126
os .chdir (original_cwd )
122
127
128
+
123
129
def test_inspector_http ():
124
130
"""Test MCP Inspector with HTTP transport using improved process management."""
125
131
pm = ProcessManager ()
126
132
try :
127
133
pm .start_http_server (timeout = 30 )
128
134
cmd = ["mcp-inspector" , "-v" , "validate" , "http://localhost:8000/mcp" ]
129
- assert run_with_retry (cmd , max_retries = 2 , timeout = 120 ), \
135
+ assert run_with_retry (cmd , max_retries = 2 , timeout = 120 ), (
130
136
"MCP Inspector HTTP validation failed after retries"
137
+ )
131
138
except Exception as e :
132
139
pytest .fail (f"HTTP server setup failed: { e } " )
133
140
finally :
134
141
print ("🧹 Cleaning up HTTP server..." )
135
142
pm .cleanup ()
136
143
137
- @pytest .mark .parametrize ("transport_mode" , ["stdio" ])
144
+
145
+ @pytest .mark .parametrize (
146
+ "transport_mode" ,
147
+ ["stdio" ],
148
+ )
138
149
def test_inspector_stdio (transport_mode ):
139
150
"""Test MCP Inspector with STDIO transport using improved protocol handling."""
140
151
os .chdir (Path (__file__ ).parent .parent .parent )
@@ -147,34 +158,44 @@ def test_inspector_stdio(transport_mode):
147
158
sys .executable ,
148
159
"src/adaptive_graph_of_thoughts/main_stdio.py" ,
149
160
]
150
- assert run_with_retry (cmd , max_retries = 2 , timeout = 180 ), \
161
+ assert run_with_retry (cmd , max_retries = 2 , timeout = 180 ), (
151
162
f"MCP Inspector { transport_mode } validation failed after retries"
163
+ )
164
+
152
165
153
166
def test_inspector_both_transports ():
154
167
"""Test MCP Inspector with both HTTP and STDIO transports comprehensively."""
155
168
pm = ProcessManager ()
156
169
results = {}
157
170
try :
158
- print ("\n " + "=" * 50 + "\n Testing STDIO transport\n " + "=" * 50 )
171
+ print ("\n " + "=" * 50 + "\n Testing STDIO transport\n " + "=" * 50 )
159
172
stdio_cmd = [
160
- "mcp-inspector" , "-v" , "validate" , "stdio" ,
161
- "--program" , sys .executable , "src/adaptive_graph_of_thoughts/main_stdio.py" ,
173
+ "mcp-inspector" ,
174
+ "-v" ,
175
+ "validate" ,
176
+ "stdio" ,
177
+ "--program" ,
178
+ sys .executable ,
179
+ "src/adaptive_graph_of_thoughts/main_stdio.py" ,
162
180
]
163
- results [' stdio' ] = run_with_retry (stdio_cmd , max_retries = 2 , timeout = 180 )
181
+ results [" stdio" ] = run_with_retry (stdio_cmd , max_retries = 2 , timeout = 180 )
164
182
165
- print ("\n " + "=" * 50 + "\n Testing HTTP transport\n " + "=" * 50 )
183
+ print ("\n " + "=" * 50 + "\n Testing HTTP transport\n " + "=" * 50 )
166
184
pm .start_http_server (timeout = 30 )
167
185
http_cmd = ["mcp-inspector" , "-v" , "validate" , "http://localhost:8000/mcp" ]
168
- results [' http' ] = run_with_retry (http_cmd , max_retries = 2 , timeout = 120 )
186
+ results [" http" ] = run_with_retry (http_cmd , max_retries = 2 , timeout = 120 )
169
187
except Exception as e :
170
188
pytest .fail (f"Transport testing failed: { e } " )
171
189
finally :
172
190
pm .cleanup ()
173
191
174
- print (f"\n 📊 Test Results:\n STDIO: { '✅ PASS' if results .get ('stdio' ) else '❌ FAIL' } \n " +
175
- f"HTTP: { '✅ PASS' if results .get ('http' ) else '❌ FAIL' } " )
176
- assert results .get ('stdio' ), "STDIO transport validation failed"
177
- assert results .get ('http' ), "HTTP transport validation failed"
192
+ print (
193
+ f"\n 📊 Test Results:\n STDIO: { '✅ PASS' if results .get ('stdio' ) else '❌ FAIL' } \n "
194
+ + f"HTTP: { '✅ PASS' if results .get ('http' ) else '❌ FAIL' } "
195
+ )
196
+ assert results .get ("stdio" ), "STDIO transport validation failed"
197
+ assert results .get ("http" ), "HTTP transport validation failed"
198
+
178
199
179
200
def test_mcp_configuration_validity ():
180
201
"""Test that MCP configuration is valid and includes necessary timeout settings."""
@@ -183,4 +204,4 @@ def test_mcp_configuration_validity():
183
204
content = cfg .read_text ()
184
205
for key in ("mcp_stdio_timeout" , "mcp_http_timeout" , "mcp_inspector_retries" ):
185
206
assert key in content , f"Missing { key } setting"
186
- print ("✅ MCP configuration includes required timeout and retry settings" )
207
+ print ("✅ MCP configuration includes required timeout and retry settings" )
0 commit comments