99from mcp_client import MCPTestHelper
1010
1111
12+ def assert_has_response (context ):
13+ assert hasattr (context , 'mcp_response' ), "No MCP response was recorded"
14+ assert context .mcp_response is not None , "MCP response was None"
15+
16+ def is_error_response (response ):
17+ return (
18+ not response .get ("success" , True ) or
19+ "error" in response or
20+ any ("error" in str (content ).lower () or "failed" in str (content ).lower ()
21+ for content in response .get ("content" , []))
22+ )
23+
24+ def has_text_content (response , text_check ):
25+ for content_item in response .get ("content" , []):
26+ if content_item .get ("type" ) == "text" :
27+ text = content_item .get ("text" , "" )
28+ if text_check (text ):
29+ return True
30+ return False
31+
32+
1233@given ('I have a running Tower MCP server' )
1334def step_start_mcp_server (context ):
1435 context .server_responsive = True
@@ -37,7 +58,7 @@ def step_create_long_running_app(context):
3758@when ('I call {tool_name} via MCP' )
3859def step_call_mcp_tool (context , tool_name ):
3960 start_time = time .time ()
40-
61+
4162 try :
4263 async def call_tool ():
4364 return await context .mcp_client .call_tool (tool_name )
@@ -46,14 +67,14 @@ async def call_tool():
4667 except Exception as e :
4768 context .mcp_response = {"success" : False , "error" : str (e )}
4869 context .operation_success = False
49-
70+
5071 context .operation_duration = time .time () - start_time
5172
5273
5374@when ('I call {tool_name} with app name "{app_name}"' )
5475def step_call_mcp_tool_with_app_name (context , tool_name , app_name ):
5576 start_time = time .time ()
56-
77+
5778 try :
5879 async def call_tool ():
5980 return await context .mcp_client .call_tool (tool_name , {"name" : app_name })
@@ -62,7 +83,7 @@ async def call_tool():
6283 except Exception as e :
6384 context .mcp_response = {"success" : False , "error" : str (e )}
6485 context .operation_success = False
65-
86+
6687 context .operation_duration = time .time () - start_time
6788
6889
@@ -71,80 +92,52 @@ async def call_tool():
7192
7293@then ('I should receive a response' )
7394def step_check_response_exists (context ):
74- """Verify we received some response."""
75- assert hasattr (context , 'mcp_response' ), "No MCP response was recorded"
76- assert context .mcp_response is not None , "MCP response was None"
95+ assert_has_response (context )
7796
7897
7998@then ('I should receive a response with apps data' )
8099def step_check_apps_data_response (context ):
81- """Verify the response contains apps data."""
82- assert hasattr (context , 'mcp_response' ), "No MCP response was recorded"
83- response_content = context .mcp_response .get ("content" , [])
84-
85- # The response should have content
86- assert len (response_content ) > 0 , "Response should have content"
87-
88- # Try to find JSON content that looks like apps data
89- found_apps_data = False
90- for content_item in response_content :
91- if content_item .get ("type" ) == "text" :
92- text = content_item .get ("text" , "" )
93- if "apps" in text .lower () or "[]" in text :
94- found_apps_data = True
95- break
96-
97- assert found_apps_data , f"Response should contain apps data, got: { response_content } "
100+ assert_has_response (context )
101+ assert len (context .mcp_response .get ("content" , [])) > 0 , "Response should have content"
102+
103+ found_apps_data = has_text_content (
104+ context .mcp_response ,
105+ lambda text : "apps" in text .lower () or "[]" in text
106+ )
107+ assert found_apps_data , f"Response should contain apps data, got: { context .mcp_response .get ('content' )} "
98108
99109
100110@then ('I should receive an error response' )
101111def step_check_error_response (context ):
102- """Verify we received an error response."""
103- assert hasattr (context , 'mcp_response' ), "No MCP response was recorded"
104-
105- # Either the success flag is False, or the content indicates an error
106- is_error = (
107- not context .mcp_response .get ("success" , True ) or
108- "error" in context .mcp_response or
109- any ("error" in str (content ).lower () or "failed" in str (content ).lower ()
110- for content in context .mcp_response .get ("content" , []))
111- )
112-
113- assert is_error , f"Expected error response, got: { context .mcp_response } "
112+ assert_has_response (context )
113+ assert is_error_response (context .mcp_response ), f"Expected error response, got: { context .mcp_response } "
114114
115115
116116@then ('I should receive an error response about missing Towerfile' )
117117def step_check_missing_towerfile_error (context ):
118- """Verify the error mentions missing Towerfile."""
119- assert hasattr (context , 'mcp_response' ), "No MCP response was recorded"
120-
118+ assert_has_response (context )
121119 response_text = str (context .mcp_response ).lower ()
122120 assert "towerfile" in response_text , f"Error should mention Towerfile, got: { context .mcp_response } "
123121
124122
125123@then ('I should receive a success response' )
126124def step_check_success_response (context ):
127- """Verify we received a success response."""
128- assert hasattr (context , 'mcp_response' ), "No MCP response was recorded"
129-
130- # Check if the operation was successful
125+ assert_has_response (context )
131126 is_success = (
132127 context .mcp_response .get ("success" , False ) or
133- any ("valid" in str (content ).lower () and "true" in str (content ).lower ()
134- for content in context .mcp_response .get ("content" , []))
128+ has_text_content (context .mcp_response , lambda text : "valid" in text .lower () and "true" in text .lower ())
135129 )
136-
137130 assert is_success , f"Expected success response, got: { context .mcp_response } "
138131
139132
140133@then ('I should receive the parsed Towerfile configuration' )
141134def step_check_parsed_towerfile (context ):
142135 """Verify the response contains parsed Towerfile data."""
143136 assert hasattr (context , 'mcp_response' ), "No MCP response was recorded"
144-
137+
145138 response_content = context .mcp_response .get ("content" , [])
146139 assert len (response_content ) > 0 , "Response should have content"
147-
140+
148141 # Look for Towerfile structure in the response
149142 found_config = False
150143 for content_item in response_content :
@@ -153,18 +146,18 @@ def step_check_parsed_towerfile(context):
153146 if "app" in text and "name" in text and "script" in text :
154147 found_config = True
155148 break
156-
149+
157150 assert found_config , f"Response should contain Towerfile config, got: { response_content } "
158151
159152
160153@then ('I should receive a response about the run' )
161154def step_check_run_response (context ):
162155 """Verify the response is about running the application."""
163156 assert hasattr (context , 'mcp_response' ), "No MCP response was recorded"
164-
157+
165158 response_text = str (context .mcp_response ).lower ()
166159 run_keywords = ["run" , "app" , "local" , "complet" , "success" , "fail" ]
167-
160+
168161 found_run_keyword = any (keyword in response_text for keyword in run_keywords )
169162 assert found_run_keyword , f"Response should be about app run, got: { context .mcp_response } "
170163
@@ -173,10 +166,10 @@ def step_check_run_response(context):
173166def step_check_timeout_message (context ):
174167 """Verify the response indicates a timeout occurred."""
175168 assert hasattr (context , 'mcp_response' ), "No MCP response was recorded"
176-
169+
177170 response_text = str (context .mcp_response ).lower ()
178171 timeout_keywords = ["timeout" , "timed out" , "1 seconds" ]
179-
172+
180173 found_timeout = any (keyword in response_text for keyword in timeout_keywords )
181174 assert found_timeout , f"Response should indicate timeout, got: { context .mcp_response } "
182175
@@ -185,10 +178,10 @@ def step_check_timeout_message(context):
185178def step_check_app_not_deployed_error (context ):
186179 """Verify the error mentions app not being deployed."""
187180 assert hasattr (context , 'mcp_response' ), "No MCP response was recorded"
188-
181+
189182 response_text = str (context .mcp_response ).lower ()
190183 deployment_keywords = ["not found" , "deploy" , "cloud" , "not deployed" ]
191-
184+
192185 found_deployment_error = any (keyword in response_text for keyword in deployment_keywords )
193186 assert found_deployment_error , f"Error should mention deployment, got: { context .mcp_response } "
194187
@@ -210,7 +203,7 @@ async def test_responsiveness():
210203 except Exception as e :
211204 context .server_responsive = False
212205 print (f"Warning: Server responsiveness test failed: { e } " )
213-
206+
214207 # For timeout scenarios, it's acceptable if the server is not responsive
215208 if not context .server_responsive :
216209 print ("Note: Server may be unresponsive after timeout, which is expected" )
0 commit comments