#!/usr/bin/env python # -*- coding: utf-8 -*- """ 远程地震体 API 集成测试 本测试模块连接到用户在5001端口启动的远程地震体API服务, 测试API调用器和JSON Schema验证器与外部API服务的集成。 """ import os import sys import json import logging import unittest import requests from pathlib import Path # 添加项目根目录到 Python 路径 sys.path.insert(0, str(Path(__file__).resolve().parents[1])) from ddms_compliance_suite.api_caller.caller import APICaller, APIRequest, APIResponse from ddms_compliance_suite.json_schema_validator.validator import JSONSchemaValidator # 配置日志 logging.basicConfig( level=logging.INFO, format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' ) logger = logging.getLogger(__name__) # 远程API服务器地址 REMOTE_API_SERVER = "http://localhost:5001" class TestRemoteSeismicAPI(unittest.TestCase): """远程地震体 API 集成测试类""" @classmethod def setUpClass(cls): """测试类开始前检查API服务器是否可用""" cls.server_available = False cls.server_endpoints = [] try: # 尝试连接到服务器,只要能连接就认为服务器在运行 response = requests.get(f"{REMOTE_API_SERVER}/", timeout=2) cls.server_available = True logger.info(f"远程API服务器 {REMOTE_API_SERVER} 可访问,HTTP状态码: {response.status_code}") # 尝试列出所有可用的端点(通常在开发环境中有帮助) try: routes_response = requests.get(f"{REMOTE_API_SERVER}/api/routes", timeout=2) if routes_response.status_code == 200: cls.server_endpoints = routes_response.json() logger.info(f"服务器提供了 {len(cls.server_endpoints)} 个端点") else: # 如果服务器不支持自省,查询几个关键端点确认API类型 for endpoint in [ "/api/gsc/appmodel/api/v1/seismic/file/list", "/api/gsc/appmodel/api/v1/seismic/traces/count" ]: try: endpoint_response = requests.head(f"{REMOTE_API_SERVER}{endpoint}", timeout=1) if endpoint_response.status_code not in (404, 405): # 405是方法不允许,表示端点存在 cls.server_endpoints.append(endpoint) except Exception: pass if cls.server_endpoints: logger.info(f"检测到地震体API服务器,可访问的端点: {cls.server_endpoints}") except Exception as e: logger.warning(f"无法列出服务器端点: {str(e)}") except Exception as e: logger.warning(f"无法连接到远程API服务器 {REMOTE_API_SERVER}: {str(e)}") cls.server_available = False def setUp(self): """为每个测试初始化环境""" if not self.__class__.server_available: self.skipTest(f"远程API服务器 {REMOTE_API_SERVER} 不可用") # 创建API调用器 self.api_caller = APICaller( default_timeout=10, default_headers={"Content-Type": "application/json"} ) # 创建JSON Schema验证器 self.schema_validator = JSONSchemaValidator() # 保存测试中创建的资源ID,以便后续测试或清理 self.created_resource_ids = [] def test_api_connection(self): """测试与API服务器的基本连接""" # 选择一个简单的端点进行测试,或尝试服务器根目录 try: response = requests.get(f"{REMOTE_API_SERVER}/", timeout=2) # 只要能连接,不管返回什么状态码,测试都通过 self.assertTrue(True, "成功连接到API服务器") logger.info(f"服务器连接测试成功,HTTP状态码: {response.status_code}") except Exception as e: self.fail(f"连接到API服务器失败: {str(e)}") def test_create_seismic_file(self): """测试创建地震体文件""" # 准备创建地震体的请求数据 seismic_data = { "projectId": "testPrj1", "surveyId": "20230117135924_2", "seismicName": "远程测试地震体", "dsType": 1, "dimensions": [ { "dimensionNo": 1, "dimensionName": "inline", "serviceMin": 100, "serviceMax": 500, "serviceSpan": 1 }, { "dimensionNo": 2, "dimensionName": "xline", "serviceMin": 200, "serviceMax": 600, "serviceSpan": 1 }, { "dimensionNo": 3, "dimensionName": "slice", "serviceMin": 3500, "serviceMax": 3600, "serviceSpan": 4 } ] } # 创建API请求 request = APIRequest( method="POST", url=f"{REMOTE_API_SERVER}/api/gsc/appmodel/api/v1/seismic/file/add", body=seismic_data ) try: # 调用API response = self.api_caller.call_api(request) # 验证响应状态码 logger.info(f"创建地震体API调用返回状态码: {response.status_code}") # 如果API服务器接受请求,保存响应用于进一步测试 if 200 <= response.status_code < 300 and response.json_content: # 响应可能包含更多字段,但至少应该有一个ID标识新创建的资源 if "result" in response.json_content: created_id = response.json_content.get("result") if created_id: self.created_resource_ids.append(created_id) logger.info(f"成功创建地震体,ID: {created_id}") else: logger.warning("API响应中的result字段为空") else: logger.warning(f"API响应中没有result字段: {response.json_content}") else: logger.warning(f"API调用未返回成功状态码或JSON内容: {response.status_code}, {response.content}") except Exception as e: logger.error(f"创建地震体过程中发生错误: {str(e)}") # 不触发测试失败,只记录错误,因为这是探索性测试 def test_query_sample_seismic(self): """查询样例地震体信息""" # 使用预定义的样例ID,通常由服务器在启动时创建 sample_id = "20221113181927_1" # 尝试对这个ID进行多种查询操作 self._try_query_trace_count(sample_id) self._try_query_h3200(sample_id) self._try_query_h400_keywords(sample_id) def _try_query_trace_count(self, seismic_id): """尝试查询地震体道数""" request = APIRequest( method="POST", url=f"{REMOTE_API_SERVER}/api/gsc/appmodel/api/v1/seismic/traces/count", body={"seismicId": seismic_id} ) try: response = self.api_caller.call_api(request) logger.info(f"查询道数API调用返回状态码: {response.status_code}") if 200 <= response.status_code < 300 and response.json_content: result = response.json_content.get("result", "未知") logger.info(f"地震体 {seismic_id} 的道数: {result}") except Exception as e: logger.warning(f"查询道数失败: {str(e)}") def _try_query_h3200(self, seismic_id): """尝试查询地震体3200头""" request = APIRequest( method="POST", url=f"{REMOTE_API_SERVER}/api/gsc/appmodel/api/v1/seismic/head/h3200", body={"seismicId": seismic_id} ) try: response = self.api_caller.call_api(request) logger.info(f"查询3200头API调用返回状态码: {response.status_code}") if 200 <= response.status_code < 300: if response.content: logger.info(f"地震体 {seismic_id} 的3200头数据长度: {len(response.content)} 字节") except Exception as e: logger.warning(f"查询3200头失败: {str(e)}") def _try_query_h400_keywords(self, seismic_id): """尝试查询地震体卷头关键字""" request = APIRequest( method="POST", url=f"{REMOTE_API_SERVER}/api/gsc/appmodel/api/v1/seismic/h400/keyword/list", body={"seismicId": seismic_id} ) try: response = self.api_caller.call_api(request) logger.info(f"查询卷头关键字API调用返回状态码: {response.status_code}") if 200 <= response.status_code < 300 and response.json_content: keywords = response.json_content.get("result", []) logger.info(f"地震体 {seismic_id} 的卷头关键字数量: {len(keywords)}") if keywords: logger.info(f"第一个关键字: {keywords[0]}") except Exception as e: logger.warning(f"查询卷头关键字失败: {str(e)}") if __name__ == "__main__": unittest.main()