@@ -64,41 +64,46 @@ def test_extract_resource_from_command(self):
6464 mock_func = Mock ()
6565 mock_func .name = "hyp-jumpstart-endpoint"
6666
67- result = _extract_resource_from_command (mock_func )
68- assert result == "jumpstart endpoint"
67+ raw_resource_type , display_name = _extract_resource_from_command (mock_func )
68+ assert raw_resource_type == "jumpstart-endpoint"
69+ assert display_name == "JumpStart Endpoint"
6970
7071 def test_extract_resource_from_pytorch_command (self ):
7172 """Test resource type extraction for PyTorch jobs."""
7273 mock_func = Mock ()
7374 mock_func .name = "hyp-pytorch-job"
7475
75- result = _extract_resource_from_command (mock_func )
76- assert result == "pytorch job"
76+ raw_resource_type , display_name = _extract_resource_from_command (mock_func )
77+ assert raw_resource_type == "pytorch-job"
78+ assert display_name == "PyTorch Job"
7779
7880 def test_extract_resource_from_custom_command (self ):
7981 """Test resource type extraction for custom endpoints."""
8082 mock_func = Mock ()
8183 mock_func .name = "hyp-custom-endpoint"
8284
83- result = _extract_resource_from_command (mock_func )
84- assert result == "custom endpoint"
85+ raw_resource_type , display_name = _extract_resource_from_command (mock_func )
86+ assert raw_resource_type == "custom-endpoint"
87+ assert display_name == "Custom Endpoint"
8588
8689 def test_extract_resource_from_future_template (self ):
8790 """Test resource type extraction works with future templates."""
8891 mock_func = Mock ()
8992 mock_func .name = "hyp-llama-job"
9093
91- result = _extract_resource_from_command (mock_func )
92- assert result == "llama job"
94+ raw_resource_type , display_name = _extract_resource_from_command (mock_func )
95+ assert raw_resource_type == "llama-job"
96+ assert display_name == "Llama Job"
9397
9498 def test_extract_resource_fallback (self ):
9599 """Test resource type extraction fallback."""
96100 mock_func = Mock ()
97101 mock_func .name = None
98102 mock_func .__name__ = "js_delete"
99103
100- result = _extract_resource_from_command (mock_func )
101- assert result == "js resource"
104+ raw_resource_type , display_name = _extract_resource_from_command (mock_func )
105+ assert raw_resource_type == "resource"
106+ assert display_name == "Resource"
102107
103108 def test_detect_operation_from_function_name (self ):
104109 """Test operation type detection from function names."""
@@ -126,40 +131,48 @@ def test_detect_operation_list(self):
126131
127132 def test_get_list_command_generation (self ):
128133 """Test list command generation from resource types."""
129- result = _get_list_command_from_resource_type ("jumpstart endpoint" )
134+ result = _get_list_command_from_resource_type ("jumpstart- endpoint" )
130135 assert result == "hyp list hyp-jumpstart-endpoint"
131136
132- result = _get_list_command_from_resource_type ("pytorch job" )
137+ result = _get_list_command_from_resource_type ("pytorch- job" )
133138 assert result == "hyp list hyp-pytorch-job"
134139
135- result = _get_list_command_from_resource_type ("future template" )
140+ result = _get_list_command_from_resource_type ("future- template" )
136141 assert result == "hyp list hyp-future-template"
137142
138143
139144class TestTemplateAgnostic404Handling :
140145 """Test template-agnostic 404 handling functionality."""
141146
147+ @patch ('sagemaker.hyperpod.common.cli_decorators._get_available_resource_count' )
142148 @patch ('sagemaker.hyperpod.common.cli_decorators.click' )
143149 @patch ('sagemaker.hyperpod.common.cli_decorators.sys' )
144- def test_404_exception_with_dynamic_detection (self , mock_sys , mock_click ):
150+ def test_404_exception_with_dynamic_detection (self , mock_sys , mock_click , mock_get_count ):
145151 """Test 404 exception handling with dynamic resource/operation detection."""
152+ # Mock the resource count to avoid actual API calls
153+ mock_get_count .return_value = 3
154+
146155 api_exception = ApiException (status = 404 , reason = "Not Found" )
147156
148- # Mock function that looks like a JumpStart delete command
157+ # Test the decorator directly
149158 @handle_cli_exceptions ()
150- @click .command ("hyp-jumpstart-endpoint" )
151159 def js_delete (name , namespace = "default" ):
152160 raise api_exception
153161
162+ # Manually set the function attributes to simulate Click command
163+ js_delete .name = "hyp-jumpstart-endpoint"
164+
154165 js_delete (name = "test" , namespace = "default" )
155166
156- # Should display template-agnostic 404 message
157- mock_click .echo .assert_called_once ()
158- call_args = mock_click .echo .call_args [0 ][0 ]
159- assert "jumpstart endpoint" in call_args .lower ()
160- assert "'test' not found" in call_args
161- assert "namespace 'default'" in call_args
162- mock_sys .exit .assert_called_once_with (1 )
167+ # With mocked sys.exit, both enhanced and standard handling occur
168+ assert mock_click .echo .call_count == 2
169+ # First call should be our enhanced 404 message
170+ first_call_args = mock_click .echo .call_args_list [0 ][0 ][0 ]
171+ assert "'test' not found" in first_call_args
172+ assert "namespace 'default'" in first_call_args
173+ assert "There are 3 resources" in first_call_args
174+ assert "hyp list" in first_call_args
175+ mock_sys .exit .assert_called_with (1 )
163176
164177 @patch ('sagemaker.hyperpod.common.cli_decorators.click' )
165178 @patch ('sagemaker.hyperpod.common.cli_decorators.sys' )
@@ -174,10 +187,14 @@ def failing_function():
174187 mock_click .echo .assert_called_once_with ("Generic error" )
175188 mock_sys .exit .assert_called_once_with (1 )
176189
190+ @patch ('sagemaker.hyperpod.common.cli_decorators._get_available_resource_count' )
177191 @patch ('sagemaker.hyperpod.common.cli_decorators.click' )
178192 @patch ('sagemaker.hyperpod.common.cli_decorators.sys' )
179- def test_fallback_404_message (self , mock_sys , mock_click ):
193+ def test_fallback_404_message (self , mock_sys , mock_click , mock_get_count ):
180194 """Test fallback message when dynamic detection fails."""
195+ # Mock the resource count to fail and trigger fallback
196+ mock_get_count .side_effect = Exception ("Count failed" )
197+
181198 api_exception = ApiException (status = 404 , reason = "Not Found" )
182199
183200 @handle_cli_exceptions ()
@@ -186,8 +203,11 @@ def unknown_function(name, namespace):
186203
187204 unknown_function (name = "test" , namespace = "default" )
188205
189- # Should display fallback message
190- mock_click .echo .assert_called_once ()
191- call_args = mock_click .echo .call_args [0 ][0 ]
192- assert "resource 'test' not found" in call_args .lower ()
193- mock_sys .exit .assert_called_once_with (1 )
206+ # Should display fallback message - expecting 2 calls due to mocked sys.exit
207+ assert mock_click .echo .call_count == 2
208+ # First call should be the fallback message
209+ first_call_args = mock_click .echo .call_args_list [0 ][0 ][0 ]
210+ assert "'test' not found" in first_call_args
211+ assert "namespace 'default'" in first_call_args
212+ assert "Unknown" in first_call_args or "Resource" in first_call_args
213+ mock_sys .exit .assert_called_with (1 )
0 commit comments