@@ -153,3 +153,140 @@ def test_get_apis_in_service_no_apis(mock_get):
153153 mock_get .return_value .json .return_value = {}
154154 with pytest .raises (KeyError ):
155155 api_meta_client .ApiMetaClient .get_apis_in_service ('ecs' , '2014-05-26' )
156+
157+ @patch ('alibaba_cloud_ops_mcp_server.alibabacloud.api_meta_client.requests.get' )
158+ def test_get_api_parameters_schema_not_dict (mock_get ):
159+ # get_api_meta返回的schema不是dict
160+ api_meta = {
161+ 'parameters' : [
162+ {'name' : 'foo' , 'in' : 'query' , 'schema' : None },
163+ {'name' : 'bar' , 'in' : 'query' , 'schema' : 'notadict' }
164+ ]
165+ }
166+ with patch .object (api_meta_client .ApiMetaClient , 'get_api_meta' , return_value = (api_meta , '2014-05-26' )):
167+ params = api_meta_client .ApiMetaClient .get_api_parameters ('ecs' , 'DescribeInstances' )
168+ # 两个参数都应该被返回
169+ assert 'foo' in params
170+ assert 'bar' in params
171+
172+ @patch ('alibaba_cloud_ops_mcp_server.alibabacloud.api_meta_client.requests.get' )
173+ def test_get_apis_in_service_normal (mock_get ):
174+ """测试get_apis_in_service方法正常返回API列表"""
175+ mock_get .return_value .json .return_value = {"apis" : {"DescribeInstances" : {}, "StartInstance" : {}}}
176+ apis = api_meta_client .ApiMetaClient .get_apis_in_service ('ecs' , '2014-05-26' )
177+ assert set (apis ) == {"DescribeInstances" , "StartInstance" }
178+ assert len (apis ) == 2
179+
180+ @patch ('alibaba_cloud_ops_mcp_server.alibabacloud.api_meta_client.ApiMetaClient.get_service_version' , return_value = '2014-05-26' )
181+ @patch ('alibaba_cloud_ops_mcp_server.alibabacloud.api_meta_client.ApiMetaClient.get_standard_service_and_api' , return_value = (None , None ))
182+ @patch ('alibaba_cloud_ops_mcp_server.alibabacloud.api_meta_client.ApiMetaClient.get_response_from_pop_api' )
183+ def test_get_api_meta_service_none_exception (mock_pop_api , mock_get_std , mock_get_ver ):
184+ """测试get_api_meta方法中service_standard为None时抛出异常"""
185+ with pytest .raises (Exception ) as e :
186+ api_meta_client .ApiMetaClient .get_api_meta ('ecs' , 'DescribeInstances' )
187+ assert 'InvalidServiceName' in str (e .value )
188+
189+ @patch ('alibaba_cloud_ops_mcp_server.alibabacloud.api_meta_client.ApiMetaClient.get_service_version' , return_value = '2014-05-26' )
190+ @patch ('alibaba_cloud_ops_mcp_server.alibabacloud.api_meta_client.ApiMetaClient.get_standard_service_and_api' , return_value = ('ecs' , None ))
191+ @patch ('alibaba_cloud_ops_mcp_server.alibabacloud.api_meta_client.ApiMetaClient.get_response_from_pop_api' )
192+ def test_get_api_meta_api_none_exception (mock_pop_api , mock_get_std , mock_get_ver ):
193+ """测试get_api_meta方法中api_standard为None时抛出异常"""
194+ with pytest .raises (Exception ) as e :
195+ api_meta_client .ApiMetaClient .get_api_meta ('ecs' , 'DescribeInstances' )
196+ assert 'InvalidAPIName' in str (e .value )
197+
198+ @patch ('alibaba_cloud_ops_mcp_server.alibabacloud.api_meta_client.ApiMetaClient.get_api_meta' )
199+ def test_get_api_parameters_schema_not_dict_more_cases (mock_get_meta ):
200+ """测试get_api_parameters中更多非dict类型的schema"""
201+ api_meta = {
202+ 'parameters' : [
203+ {'name' : 'foo' , 'in' : 'query' , 'schema' : 'string' }, # 字符串
204+ {'name' : 'bar' , 'in' : 'query' , 'schema' : 123 }, # 数字
205+ {'name' : 'baz' , 'in' : 'query' , 'schema' : []}, # 列表
206+ {'name' : 'qux' , 'in' : 'query' , 'schema' : None }, # None
207+ ]
208+ }
209+ mock_get_meta .return_value = (api_meta , '2014-05-26' )
210+ params = api_meta_client .ApiMetaClient .get_api_parameters ('ecs' , 'DescribeInstances' )
211+ assert 'foo' in params
212+ assert 'bar' in params
213+ assert 'baz' in params
214+ assert 'qux' in params
215+
216+ @patch ('alibaba_cloud_ops_mcp_server.alibabacloud.api_meta_client.requests.get' )
217+ def test_get_apis_in_service_normal (mock_get ):
218+ """测试get_apis_in_service方法正常返回API列表"""
219+ mock_get .return_value .json .return_value = {"apis" : {"DescribeInstances" : {}, "StartInstance" : {}}}
220+ apis = api_meta_client .ApiMetaClient .get_apis_in_service ('ecs' , '2014-05-26' )
221+ assert set (apis ) == {"DescribeInstances" , "StartInstance" }
222+ assert len (apis ) == 2
223+
224+
225+ @patch ('alibaba_cloud_ops_mcp_server.alibabacloud.api_meta_client.ApiMetaClient.get_standard_service_and_api' , return_value = ('ecs' , 'api' ))
226+ @patch ('alibaba_cloud_ops_mcp_server.alibabacloud.api_meta_client.ApiMetaClient.get_response_from_pop_api' )
227+ def test_get_ref_api_meta_invalid_path (mock_pop_api , mock_std ):
228+ # 模拟 ref_path 指向不存在的 key
229+ mock_pop_api .return_value = {'apis' : {'DescribeInstances' : {}}}
230+ with pytest .raises (KeyError ):
231+ api_meta_client .ApiMetaClient .get_ref_api_meta ({'$ref' : '#/notfound' }, 'ecs' , '2014-05-26' )
232+
233+ @patch ('alibaba_cloud_ops_mcp_server.alibabacloud.api_meta_client.ApiMetaClient.get_standard_service_and_api' , return_value = ('ecs' , 'api' ))
234+ @patch ('alibaba_cloud_ops_mcp_server.alibabacloud.api_meta_client.ApiMetaClient.get_response_from_pop_api' )
235+ def test_get_ref_api_meta_invalid_path (mock_pop_api , mock_std ):
236+ # 模拟 ref_path 指向不存在的 key
237+ mock_pop_api .return_value = {'apis' : {'DescribeInstances' : {}}}
238+ with pytest .raises (KeyError ):
239+ api_meta_client .ApiMetaClient .get_ref_api_meta ({'$ref' : '#/notfound' }, 'ecs' , '2014-05-26' )
240+
241+ @patch ('alibaba_cloud_ops_mcp_server.alibabacloud.api_meta_client.ApiMetaClient.get_api_meta' )
242+ def test_get_api_field_default_value (mock_get_meta ):
243+ # 模拟 get_api_meta 返回无 field_type 的数据
244+ mock_get_meta .return_value = ({}, '2014-05-26' )
245+ val = api_meta_client .ApiMetaClient .get_api_field ('parameters' , 'ecs' , 'DescribeInstances' , default = 'default_val' )
246+ assert val == 'default_val'
247+
248+ @patch ('alibaba_cloud_ops_mcp_server.alibabacloud.api_meta_client.ApiMetaClient.get_api_meta' )
249+ def test_get_api_parameters_nested_ref (mock_get_meta ):
250+ # 模拟嵌套 $ref
251+ api_meta = {
252+ 'parameters' : [
253+ {'name' : 'foo' , 'in' : 'query' , 'schema' : {'$ref' : '#/defs/A' }}
254+ ]
255+ }
256+ def fake_get_ref (data , service , version ):
257+ if '#/defs/A' in data .get ('$ref' , '' ):
258+ return {'properties' : {'a' : {'$ref' : '#/defs/B' }}}
259+ elif '#/defs/B' in data .get ('$ref' , '' ):
260+ return {'properties' : {'b' : {}}}
261+ return {}
262+ with patch .object (api_meta_client .ApiMetaClient , 'get_ref_api_meta' , side_effect = fake_get_ref ):
263+ mock_get_meta .return_value = (api_meta , '2014-05-26' )
264+ params = api_meta_client .ApiMetaClient .get_api_parameters ('ecs' , 'DescribeInstances' )
265+ assert 'a' in params and 'b' in params # 深层嵌套属性应被提取
266+
267+ @patch ('alibaba_cloud_ops_mcp_server.alibabacloud.api_meta_client.ApiMetaClient.get_standard_service_and_api' , return_value = ('ecs' , 'api' ))
268+ @patch ('alibaba_cloud_ops_mcp_server.alibabacloud.api_meta_client.ApiMetaClient.get_response_from_pop_api' )
269+ def test_get_ref_api_meta_valid_path (mock_pop_api , mock_std ):
270+ # 模拟 get_response_from_pop_api 返回包含 defs/A 的结构
271+ mock_pop_api .return_value = {
272+ 'defs' : {
273+ 'A' : {
274+ 'properties' : {
275+ 'prop1' : {'type' : 'string' },
276+ 'prop2' : {'type' : 'integer' }
277+ }
278+ }
279+ }
280+ }
281+
282+ # 调用 get_ref_api_meta,传入 $ref 指向 #/defs/A
283+ result = api_meta_client .ApiMetaClient .get_ref_api_meta ({'$ref' : '#/defs/A' }, 'ecs' , '2014-05-26' )
284+
285+ # 验证返回结果是否与 defs/A 的结构一致
286+ expected = {
287+ 'properties' : {
288+ 'prop1' : {'type' : 'string' },
289+ 'prop2' : {'type' : 'integer' }
290+ }
291+ }
292+ assert result == expected
0 commit comments