Files
java-template/utils/test_batch_upload_interfaces.py
BrunoGaoandClaude aa41afaf00 feat: 全面优化前端界面和增强用户体验
- 新增科技风格的抽屉组件样式和主题系统,支持健康监测、设备管理、用户管理、告警配置等多个业务主题
- 优化TenantInfo组件的事件处理,修复Vue 3兼容性问题
- 重构路由器创建逻辑,提升代码可维护性和扩展性
- 统一所有抽屉弹窗的UI风格,增加操作横幅、分组布局、图标提示等现代化设计元素
- 修复customer租户管理权限控制逻辑,改进按钮状态管理和权限验证流程
- 新增批量数据上传测试工具,支持curl和Python接口测试
- 优化设备信息编辑界面,增加分组显示、帮助文本、状态指示等功能
- 创建完整的界面增强指南和自动化脚本,便于后续维护和扩展

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <[email protected]>
2025-09-22 06:40:24 +08:00

349 lines
14 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
ljwx-boot 批量上传接口测试脚本
测试三个核心接口:
1. upload_health_data - 健康数据批量上传
2. upload_device_info - 设备信息批量上传
3. upload_common_event - 通用事件上传
兼容原 Python ljwx-bigscreen 接口格式
"""
import requests
import json
import time
import random
from datetime import datetime, timedelta
from typing import Dict, List, Any
import argparse
class BatchUploadTester:
"""批量上传接口测试器"""
def __init__(self, base_url: str = "http://localhost:8080"):
self.base_url = base_url
self.session = requests.Session()
self.session.headers.update({
'Content-Type': 'application/json',
'User-Agent': 'ljwx-batch-upload-tester/1.0'
})
def generate_health_data(self, count: int = 10) -> List[Dict[str, Any]]:
"""生成测试健康数据"""
health_data = []
for i in range(count):
# 模拟不同设备和用户
device_id = f"DEVICE_{i % 5:03d}"
user_id = str(100 + (i % 20))
org_id = str(1 + (i % 3))
data = {
"device_id": device_id,
"user_id": user_id,
"org_id": org_id,
"customer_id": "8",
# 健康指标数据
"heart_rate": random.randint(60, 100),
"blood_oxygen": random.randint(95, 100),
"temperature": round(36.0 + random.uniform(0, 2.0), 1),
"pressure_high": random.randint(110, 140),
"pressure_low": random.randint(70, 90),
"stress": random.randint(1, 10),
"step": random.randint(1000, 15000),
"distance": round(random.uniform(0.5, 10.0), 2),
"calorie": round(random.uniform(200, 800), 1),
# 位置信息
"latitude": round(39.9 + random.uniform(-0.1, 0.1), 6),
"longitude": round(116.4 + random.uniform(-0.1, 0.1), 6),
"altitude": round(random.uniform(40, 60), 1),
# 时间戳
"create_time": (datetime.now() - timedelta(minutes=random.randint(1, 60))).strftime("%Y-%m-%d %H:%M:%S")
}
health_data.append(data)
return health_data
def generate_device_data(self, count: int = 5) -> List[Dict[str, Any]]:
"""生成测试设备数据"""
device_data = []
for i in range(count):
data = {
"device_id": f"DEVICE_{i:03d}",
"device_name": f"智能手环_{i}",
"device_type": "wearable",
"firmware_version": f"v2.{random.randint(1, 9)}.{random.randint(0, 9)}",
"battery_level": random.randint(10, 100),
"signal_strength": random.randint(-80, -30),
"customer_id": "8",
"status": random.choice(["online", "offline", "charging"]),
"last_sync": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
device_data.append(data)
return device_data
def generate_common_event_data(self) -> Dict[str, Any]:
"""生成通用事件测试数据"""
return {
"health_data": self.generate_health_data(5),
"device_info": self.generate_device_data(2),
"alert_data": [
{
"alert_type": "heart_rate_abnormal",
"device_id": "DEVICE_001",
"user_id": "101",
"severity": "high",
"message": "心率异常:检测到心率持续过高",
"timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S")
}
]
}
def test_upload_health_data(self, data_count: int = 10) -> Dict[str, Any]:
"""测试健康数据上传接口"""
print(f"\n🩺 测试健康数据上传接口 (数据量: {data_count})")
# 生成测试数据
health_data = self.generate_health_data(data_count)
# 测试新格式接口
url = f"{self.base_url}/batch/upload-health-data"
result1 = self._make_request("POST", url, health_data, "upload-health-data")
# 测试Python兼容接口
url_compat = f"{self.base_url}/batch/upload_health_data"
result2 = self._make_request("POST", url_compat, health_data, "upload_health_data (兼容)")
return {"modern": result1, "compatible": result2}
def test_upload_device_info(self, device_count: int = 5) -> Dict[str, Any]:
"""测试设备信息上传接口"""
print(f"\n📱 测试设备信息上传接口 (设备数: {device_count})")
# 生成测试数据
device_data = self.generate_device_data(device_count)
# 测试新格式接口
url = f"{self.base_url}/batch/upload-device-info"
result1 = self._make_request("POST", url, device_data, "upload-device-info")
# 测试Python兼容接口
url_compat = f"{self.base_url}/batch/upload_device_info"
result2 = self._make_request("POST", url_compat, device_data, "upload_device_info (兼容)")
return {"modern": result1, "compatible": result2}
def test_upload_common_event(self) -> Dict[str, Any]:
"""测试通用事件上传接口"""
print(f"\n🔄 测试通用事件上传接口")
# 生成测试数据
event_data = self.generate_common_event_data()
# 测试新格式接口
url = f"{self.base_url}/batch/upload-common-event"
result1 = self._make_request("POST", url, event_data, "upload-common-event")
# 测试Python兼容接口
url_compat = f"{self.base_url}/batch/upload_common_event"
result2 = self._make_request("POST", url_compat, event_data, "upload_common_event (兼容)")
return {"modern": result1, "compatible": result2}
def test_get_stats(self) -> Dict[str, Any]:
"""测试统计信息接口"""
print(f"\n📊 测试统计信息接口")
url = f"{self.base_url}/batch/stats"
return self._make_request("GET", url, None, "stats")
def test_health_check(self) -> Dict[str, Any]:
"""测试健康检查接口"""
print(f"\n💚 测试健康检查接口")
url = f"{self.base_url}/batch/health"
return self._make_request("GET", url, None, "health")
def test_performance(self, data_size: int = 1000) -> Dict[str, Any]:
"""测试性能测试接口"""
print(f"\n⚡ 测试性能测试接口 (数据规模: {data_size})")
url = f"{self.base_url}/batch/performance-test?dataSize={data_size}"
return self._make_request("POST", url, None, "performance-test")
def _make_request(self, method: str, url: str, data: Any, operation: str) -> Dict[str, Any]:
"""发送HTTP请求"""
start_time = time.time()
try:
if method.upper() == "GET":
response = self.session.get(url, timeout=30)
else:
response = self.session.post(url, json=data, timeout=30)
elapsed_time = (time.time() - start_time) * 1000
result = {
"operation": operation,
"method": method,
"url": url,
"status_code": response.status_code,
"elapsed_ms": round(elapsed_time, 2),
"success": response.status_code == 200
}
if response.status_code == 200:
try:
response_data = response.json()
result["response"] = response_data
print(f" ✅ {operation}: {response.status_code} ({elapsed_time:.1f}ms)")
# 显示关键统计信息
if "result" in response_data and isinstance(response_data["result"], dict):
stats = response_data["result"]
if "processed" in stats:
print(f" 📈 处理: {stats.get('processed', 0)} 条")
if "duplicates" in stats:
print(f" 🔄 重复: {stats.get('duplicates', 0)} 条")
if "processing_time_ms" in stats:
print(f" ⏱️ 耗时: {stats.get('processing_time_ms', 0)} ms")
except json.JSONDecodeError:
result["response"] = response.text
print(f" ⚠️ {operation}: {response.status_code} (响应格式异常)")
else:
result["error"] = response.text
print(f" ❌ {operation}: {response.status_code} - {response.text[:100]}")
except Exception as e:
elapsed_time = (time.time() - start_time) * 1000
result = {
"operation": operation,
"method": method,
"url": url,
"error": str(e),
"elapsed_ms": round(elapsed_time, 2),
"success": False
}
print(f" 💥 {operation}: 请求异常 - {str(e)}")
return result
def run_all_tests(self, health_count: int = 10, device_count: int = 5, perf_size: int = 1000):
"""运行所有测试"""
print("🚀 开始 ljwx-boot 批量上传接口测试")
print(f" 目标服务: {self.base_url}")
print(f" 测试时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
results = {}
# 1. 健康检查
results["health_check"] = self.test_health_check()
# 2. 健康数据上传测试
results["health_data"] = self.test_upload_health_data(health_count)
# 3. 设备信息上传测试
results["device_info"] = self.test_upload_device_info(device_count)
# 4. 通用事件上传测试
results["common_event"] = self.test_upload_common_event()
# 5. 统计信息查询
results["stats"] = self.test_get_stats()
# 6. 性能测试
results["performance"] = self.test_performance(perf_size)
print(f"\n📋 测试完成总结:")
self._print_test_summary(results)
return results
def _print_test_summary(self, results: Dict[str, Any]):
"""打印测试总结"""
total_tests = 0
passed_tests = 0
for test_name, test_result in results.items():
if isinstance(test_result, dict):
if "success" in test_result:
# 单个测试结果
total_tests += 1
if test_result["success"]:
passed_tests += 1
print(f" ✅ {test_name}: 通过 ({test_result.get('elapsed_ms', 0):.1f}ms)")
else:
print(f" ❌ {test_name}: 失败")
else:
# 多个测试结果 (如health_data的modern和compatible)
for sub_test, sub_result in test_result.items():
if isinstance(sub_result, dict) and "success" in sub_result:
total_tests += 1
if sub_result["success"]:
passed_tests += 1
print(f" ✅ {test_name}.{sub_test}: 通过 ({sub_result.get('elapsed_ms', 0):.1f}ms)")
else:
print(f" ❌ {test_name}.{sub_test}: 失败")
success_rate = (passed_tests / total_tests * 100) if total_tests > 0 else 0
print(f"\n🎯 测试通过率: {passed_tests}/{total_tests} ({success_rate:.1f}%)")
if success_rate == 100:
print("🎉 所有测试通过!接口运行正常")
elif success_rate >= 80:
print("⚠️ 大部分测试通过,部分功能可能存在问题")
else:
print("🚨 多个测试失败,建议检查服务状态")
def main():
"""主函数"""
parser = argparse.ArgumentParser(description="ljwx-boot 批量上传接口测试")
parser.add_argument("--url", default="http://localhost:8080", help="服务基础URL")
parser.add_argument("--health-count", type=int, default=10, help="健康数据测试条数")
parser.add_argument("--device-count", type=int, default=5, help="设备信息测试条数")
parser.add_argument("--perf-size", type=int, default=1000, help="性能测试数据规模")
# 添加单独测试选项
parser.add_argument("--test-health", action="store_true", help="仅测试健康数据接口")
parser.add_argument("--test-device", action="store_true", help="仅测试设备信息接口")
parser.add_argument("--test-event", action="store_true", help="仅测试通用事件接口")
parser.add_argument("--test-stats", action="store_true", help="仅测试统计信息接口")
parser.add_argument("--test-check", action="store_true", help="仅测试健康检查接口")
parser.add_argument("--test-perf", action="store_true", help="仅测试性能接口")
args = parser.parse_args()
# 初始化测试器
tester = BatchUploadTester(args.url)
# 运行指定的测试
if args.test_health:
tester.test_upload_health_data(args.health_count)
elif args.test_device:
tester.test_upload_device_info(args.device_count)
elif args.test_event:
tester.test_upload_common_event()
elif args.test_stats:
tester.test_get_stats()
elif args.test_check:
tester.test_health_check()
elif args.test_perf:
tester.test_performance(args.perf_size)
else:
# 运行所有测试
tester.run_all_tests(args.health_count, args.device_count, args.perf_size)
if __name__ == "__main__":
main()