@@ -142,16 +142,42 @@ def test_operation_args_parsed_with_explicit_choice(self):
142142
143143 assert self .handler .effective_resource_view == 'RESOURCE'
144144
145- def test_operation_args_parsed_without_flag (self ):
146- """Test storing monitoring flag when disabled ."""
145+ def test_operation_args_parsed_without_monitor_resources (self ):
146+ """Test that no monitoring settings are stored without flag ."""
147147 parsed_args = Mock ()
148148 parsed_args .monitor_resources = None
149+ parsed_args .monitor_mode = None
149150 parsed_globals = Mock ()
150151
151152 self .handler .operation_args_parsed (parsed_args , parsed_globals )
152153
153154 assert self .handler .effective_resource_view is None
154155
156+ def test_operation_args_parsed_mode_without_resources_raises_error (self ):
157+ """Test that using --monitor-mode without --monitor-resources raises ValueError."""
158+ parsed_args = Mock ()
159+ parsed_args .monitor_resources = None
160+ parsed_args .monitor_mode = (
161+ 'text-only' # Mode specified but no resources
162+ )
163+ parsed_globals = Mock ()
164+
165+ with pytest .raises (
166+ ValueError , match = "can only be used with --monitor-resources"
167+ ):
168+ self .handler .operation_args_parsed (parsed_args , parsed_globals )
169+
170+ def test_operation_args_parsed_with_interactive_mode (self ):
171+ """Test operation_args_parsed with explicit interactive mode."""
172+ parsed_args = Mock ()
173+ parsed_args .monitor_resources = 'DEPLOYMENT'
174+ parsed_args .monitor_mode = 'interactive'
175+ parsed_globals = Mock ()
176+
177+ self .handler .operation_args_parsed (parsed_args , parsed_globals )
178+
179+ assert self .handler .effective_mode == 'interactive'
180+
155181 def test_operation_args_parsed_missing_attribute (self ):
156182 """Test handling missing monitor_resources attribute."""
157183 # Mock without monitor_resources attribute
@@ -204,7 +230,8 @@ def test_after_call_missing_service_arn(self):
204230
205231 # No assertions needed - just verify no exceptions
206232
207- def test_after_call_missing_session (self , capsys ):
233+ @patch ("sys.stdout.isatty" , return_value = True )
234+ def test_after_call_missing_session (self , mock_isatty , capsys ):
208235 """Test handling when session is not available."""
209236 self .handler .effective_resource_view = 'DEPLOYMENT'
210237 self .handler .session = None
@@ -224,8 +251,9 @@ def test_after_call_missing_session(self, capsys):
224251 "Unable to create ECS client. Skipping monitoring." in captured .err
225252 )
226253
227- def test_after_call_successful_monitoring (self ):
228- """Test successful monitoring initiation."""
254+ @patch ('sys.stdout.isatty' , return_value = True )
255+ def test_after_call_successful_monitoring (self , mock_isatty ):
256+ """Test successful monitoring invocation after API call."""
229257 # Setup handler state
230258 mock_watcher_class = Mock ()
231259 mock_watcher = Mock ()
@@ -236,8 +264,8 @@ def test_after_call_successful_monitoring(self):
236264 'DEPLOYMENT' ,
237265 watcher_class = mock_watcher_class ,
238266 )
239- handler .monitor_resources = '__DEFAULT__'
240267 handler .effective_resource_view = 'DEPLOYMENT'
268+ handler .effective_mode = 'TEXT-ONLY' # TEXT-ONLY mode for testing
241269
242270 mock_session = Mock ()
243271 mock_parsed_globals = Mock ()
@@ -264,38 +292,31 @@ def test_after_call_successful_monitoring(self):
264292 # Execute
265293 handler .after_call (parsed , context , http_response )
266294
267- # Verify client creation
268- mock_session .create_client .assert_called_once_with (
269- 'ecs' ,
270- region_name = 'us-west-2' ,
271- endpoint_url = 'https://ecs.us-west-2.amazonaws.com' ,
272- verify = True ,
273- )
274-
275- # Verify watcher was created and executed
295+ # Verify watcher was called correctly with display_mode parameter
276296 mock_watcher_class .assert_called_once_with (
277297 mock_client ,
278- service_arn ,
298+ 'arn:aws:ecs:us-west-2:123456789012:service/test-service' ,
279299 'DEPLOYMENT' ,
300+ 'TEXT-ONLY' ,
280301 use_color = False ,
281302 )
282303 mock_watcher .exec .assert_called_once ()
304+
283305 # Verify parsed response was cleared
284306 assert parsed == {}
285307
286- def test_after_call_monitoring_not_available ( self , capsys ):
287- """Test that monitoring is skipped when not available (no TTY)."""
288- # Setup handler state
308+ @ patch ( 'sys.stdout.isatty' , return_value = False ) # Not TTY
309+ def test_after_call_monitoring_requires_tty ( self , mock_isatty , capsys ):
310+ """Test after_call fails when monitoring without TTY"""
289311 mock_watcher_class = Mock ()
290- mock_watcher_class .is_monitoring_available .return_value = False
291-
292312 handler = MonitorMutatingGatewayService (
293- 'create-gateway-service' ,
313+ 'create-express- gateway-service' ,
294314 'DEPLOYMENT' ,
295315 watcher_class = mock_watcher_class ,
296316 )
297317 handler .effective_resource_view = 'DEPLOYMENT'
298-
318+ handler .effective_mode = 'TEXT-ONLY' # Try TEXT-ONLY without TTY
319+ handler .use_color = False
299320 mock_session = Mock ()
300321 mock_parsed_globals = Mock ()
301322 mock_parsed_globals .region = 'us-west-2'
@@ -307,33 +328,25 @@ def test_after_call_monitoring_not_available(self, capsys):
307328 handler .session = mock_session
308329 handler .parsed_globals = mock_parsed_globals
309330
310- # Setup mocks
311- mock_client = Mock ()
312- mock_session .create_client .return_value = mock_client
313-
314331 # Setup call parameters
315332 service_arn = 'arn:aws:ecs:us-west-2:123456789012:service/test-service'
316333 parsed = {'service' : {'serviceArn' : service_arn }}
317- original_parsed = dict (parsed )
318334 context = Mock ()
319335 http_response = Mock ()
320336 http_response .status_code = 200
321337
322338 # Execute
323339 handler .after_call (parsed , context , http_response )
324340
325- # Verify parsed response was not cleared
326- assert parsed == original_parsed
341+ # TEXT-ONLY mode now works without TTY, so watcher WAS called
342+ mock_watcher_class . assert_called_once ()
327343
328- # Verify warning message was printed
329- captured = capsys .readouterr ()
330- assert (
331- "Monitoring is not available (requires TTY). Skipping monitoring.\n "
332- in captured .err
333- )
344+ # Verify parsed response was NOT cleared (error return early)
345+ assert 'service' not in parsed # Cleared because monitoring ran
334346
335- def test_after_call_exception_handling (self , capsys ):
336- """Test exception handling in after_call method."""
347+ @patch ('sys.stdout.isatty' , return_value = True )
348+ def test_after_call_exception_propagates (self , mock_isatty ):
349+ """Test exceptions propagate from after_call method."""
337350 # Setup handler state
338351 mock_watcher_class = Mock ()
339352 mock_watcher = Mock ()
@@ -346,6 +359,7 @@ def test_after_call_exception_handling(self, capsys):
346359 watcher_class = mock_watcher_class ,
347360 )
348361 handler .effective_resource_view = 'DEPLOYMENT'
362+ handler .effective_mode = 'TEXT-ONLY'
349363
350364 mock_session = Mock ()
351365 mock_parsed_globals = Mock ()
@@ -369,12 +383,9 @@ def test_after_call_exception_handling(self, capsys):
369383 http_response = Mock ()
370384 http_response .status_code = 200
371385
372- # Execute - should not raise exception
373- handler .after_call (parsed , context , http_response )
374-
375- captured = capsys .readouterr ()
376- assert "Encountered an error, terminating monitoring" in captured .err
377- assert "Test exception" in captured .err
386+ # Execute - should raise exception
387+ with pytest .raises (Exception , match = "Test exception" ):
388+ handler .after_call (parsed , context , http_response )
378389
379390 def test_events (self ):
380391 """Test that correct events are returned for CLI integration."""
0 commit comments