compliance/tests/test_remote_seismic_api.py
2025-05-16 15:18:02 +08:00

238 lines
9.6 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/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()