freeleaps-ops/apps/gitea-webhook-ambassador-python/test_webhook.py
Nicolas f6c515157c feat: 添加 Python 版本的 Gitea Webhook Ambassador
- 新增完整的 Python 实现,替代 Go 版本
- 添加 Web 登录界面和仪表板
- 实现 JWT 认证和 API 密钥管理
- 添加数据库存储功能
- 保持与 Go 版本一致的目录结构和启动脚本
- 包含完整的文档和测试脚本
2025-07-20 21:17:10 +08:00

307 lines
9.8 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Webhook 功能测试脚本
用于验证 Gitea Webhook Ambassador 的各项功能
"""
import asyncio
import json
import httpx
import time
from datetime import datetime
# 测试配置
BASE_URL = "http://localhost:8000"
WEBHOOK_SECRET = "your-secret-key-here-make-it-long-and-random"
# 测试数据
TEST_WEBHOOK_DATA = {
"ref": "refs/heads/dev",
"before": "abc1234567890abcdef1234567890abcdef123456",
"after": "def1234567890abcdef1234567890abcdef123456",
"compare_url": "https://gitea.freeleaps.com/freeleaps/test-project/compare/abc123...def123",
"commits": [
{
"id": "def1234567890abcdef1234567890abcdef123456",
"message": "feat: add new feature",
"url": "https://gitea.freeleaps.com/freeleaps/test-project/commit/def1234567890abcdef1234567890abcdef123456",
"author": {
"id": 1,
"login": "developer",
"full_name": "Test Developer",
"email": "dev@freeleaps.com"
}
}
],
"repository": {
"id": 1,
"name": "test-project",
"owner": {
"id": 1,
"login": "freeleaps",
"full_name": "Freeleaps Team",
"email": "team@freeleaps.com"
},
"full_name": "freeleaps/test-project",
"private": False,
"clone_url": "https://gitea.freeleaps.com/freeleaps/test-project.git",
"ssh_url": "git@gitea.freeleaps.com:freeleaps/test-project.git",
"html_url": "https://gitea.freeleaps.com/freeleaps/test-project",
"default_branch": "main"
},
"pusher": {
"id": 1,
"login": "developer",
"full_name": "Test Developer",
"email": "dev@freeleaps.com"
}
}
async def test_health_check():
"""测试健康检查"""
print("🔍 测试健康检查...")
async with httpx.AsyncClient() as client:
try:
response = await client.get(f"{BASE_URL}/health")
if response.status_code == 200:
data = response.json()
print(f"✅ 健康检查通过: {data['status']}")
return True
else:
print(f"❌ 健康检查失败: {response.status_code}")
return False
except Exception as e:
print(f"❌ 健康检查异常: {e}")
return False
async def test_queue_status():
"""测试队列状态"""
print("🔍 测试队列状态...")
async with httpx.AsyncClient() as client:
try:
response = await client.get(f"{BASE_URL}/health/queue")
if response.status_code == 200:
data = response.json()
print(f"✅ 队列状态: {data['queue_stats']}")
return True
else:
print(f"❌ 队列状态检查失败: {response.status_code}")
return False
except Exception as e:
print(f"❌ 队列状态检查异常: {e}")
return False
async def test_webhook_endpoint():
"""测试 Webhook 端点"""
print("🔍 测试 Webhook 端点...")
headers = {
"Content-Type": "application/json",
"X-Gitea-Signature": WEBHOOK_SECRET
}
async with httpx.AsyncClient() as client:
try:
response = await client.post(
f"{BASE_URL}/webhook/gitea",
headers=headers,
json=TEST_WEBHOOK_DATA
)
print(f"📊 响应状态: {response.status_code}")
print(f"📊 响应内容: {response.text}")
if response.status_code in [200, 202]:
print("✅ Webhook 端点测试通过")
return True
else:
print(f"❌ Webhook 端点测试失败: {response.status_code}")
return False
except Exception as e:
print(f"❌ Webhook 端点测试异常: {e}")
return False
async def test_metrics_endpoint():
"""测试监控指标端点"""
print("🔍 测试监控指标端点...")
async with httpx.AsyncClient() as client:
try:
response = await client.get(f"{BASE_URL}/metrics")
if response.status_code == 200:
print("✅ 监控指标端点测试通过")
# 打印一些关键指标
content = response.text
for line in content.split('\n'):
if 'webhook_requests_total' in line or 'queue_size' in line:
print(f"📊 {line}")
return True
else:
print(f"❌ 监控指标端点测试失败: {response.status_code}")
return False
except Exception as e:
print(f"❌ 监控指标端点测试异常: {e}")
return False
async def test_deduplication():
"""测试防抖功能"""
print("🔍 测试防抖功能...")
headers = {
"Content-Type": "application/json",
"X-Gitea-Signature": WEBHOOK_SECRET
}
async with httpx.AsyncClient() as client:
try:
# 第一次请求
print("📤 发送第一次请求...")
response1 = await client.post(
f"{BASE_URL}/webhook/gitea",
headers=headers,
json=TEST_WEBHOOK_DATA
)
print(f"📊 第一次响应: {response1.status_code}")
# 等待一秒
await asyncio.sleep(1)
# 第二次请求(相同数据,应该被防抖)
print("📤 发送第二次请求(相同数据)...")
response2 = await client.post(
f"{BASE_URL}/webhook/gitea",
headers=headers,
json=TEST_WEBHOOK_DATA
)
print(f"📊 第二次响应: {response2.status_code}")
# 修改提交哈希,发送第三次请求
modified_data = TEST_WEBHOOK_DATA.copy()
modified_data["after"] = "ghi1234567890abcdef1234567890abcdef123456"
print("📤 发送第三次请求(不同提交哈希)...")
response3 = await client.post(
f"{BASE_URL}/webhook/gitea",
headers=headers,
json=modified_data
)
print(f"📊 第三次响应: {response3.status_code}")
print("✅ 防抖功能测试完成")
return True
except Exception as e:
print(f"❌ 防抖功能测试异常: {e}")
return False
async def test_invalid_webhook():
"""测试无效的 Webhook 请求"""
print("🔍 测试无效的 Webhook 请求...")
async with httpx.AsyncClient() as client:
try:
# 测试缺少签名
print("📤 测试缺少签名...")
response1 = await client.post(
f"{BASE_URL}/webhook/gitea",
headers={"Content-Type": "application/json"},
json=TEST_WEBHOOK_DATA
)
print(f"📊 缺少签名响应: {response1.status_code}")
# 测试错误的签名
print("📤 测试错误的签名...")
response2 = await client.post(
f"{BASE_URL}/webhook/gitea",
headers={
"Content-Type": "application/json",
"X-Gitea-Signature": "wrong-secret"
},
json=TEST_WEBHOOK_DATA
)
print(f"📊 错误签名响应: {response2.status_code}")
# 测试无效的 JSON
print("📤 测试无效的 JSON...")
response3 = await client.post(
f"{BASE_URL}/webhook/gitea",
headers={
"Content-Type": "application/json",
"X-Gitea-Signature": WEBHOOK_SECRET
},
content="invalid json"
)
print(f"📊 无效 JSON 响应: {response3.status_code}")
print("✅ 无效请求测试完成")
return True
except Exception as e:
print(f"❌ 无效请求测试异常: {e}")
return False
async def main():
"""主测试函数"""
print("🚀 开始 Gitea Webhook Ambassador 功能测试")
print("=" * 50)
tests = [
("健康检查", test_health_check),
("队列状态", test_queue_status),
("Webhook 端点", test_webhook_endpoint),
("监控指标", test_metrics_endpoint),
("防抖功能", test_deduplication),
("无效请求", test_invalid_webhook),
]
results = []
for test_name, test_func in tests:
print(f"\n🧪 {test_name}")
print("-" * 30)
try:
result = await test_func()
results.append((test_name, result))
except Exception as e:
print(f"{test_name} 测试异常: {e}")
results.append((test_name, False))
# 等待一下再进行下一个测试
await asyncio.sleep(1)
# 输出测试结果
print("\n" + "=" * 50)
print("📊 测试结果汇总")
print("=" * 50)
passed = 0
total = len(results)
for test_name, result in results:
status = "✅ 通过" if result else "❌ 失败"
print(f"{test_name}: {status}")
if result:
passed += 1
print(f"\n📈 总体结果: {passed}/{total} 测试通过")
if passed == total:
print("🎉 所有测试通过!服务运行正常。")
else:
print("⚠️ 部分测试失败,请检查服务配置和日志。")
if __name__ == "__main__":
# 运行测试
asyncio.run(main())