feat: 完善服务端工程化、发布流程和自动化测试
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
import hashlib
|
||||
import io
|
||||
import json
|
||||
from types import SimpleNamespace
|
||||
import uuid
|
||||
|
||||
|
||||
def crash_metadata(client_report_id: str, minidump: bytes):
|
||||
return {
|
||||
"schemaVersion": 1,
|
||||
"clientReportId": client_report_id,
|
||||
"crashTimeUtc": "2026-07-16T00:00:00Z",
|
||||
"product": "SIMCAE",
|
||||
"appVersion": "1.0.0",
|
||||
"gitCommit": "test-commit",
|
||||
"buildType": "Release",
|
||||
"channel": "stable",
|
||||
"platform": {"os": "Windows", "arch": "x64"},
|
||||
"crash": {"exceptionCode": "0xC0000005"},
|
||||
"userConsent": {"upload": True},
|
||||
"files": [
|
||||
{
|
||||
"kind": "minidump",
|
||||
"name": "crash.dmp",
|
||||
"sha256": hashlib.sha256(minidump).hexdigest(),
|
||||
}
|
||||
],
|
||||
}
|
||||
|
||||
|
||||
class FakeHeaders(dict):
|
||||
def __init__(self, values: dict[str, str]):
|
||||
super().__init__((key.lower(), value) for key, value in values.items())
|
||||
|
||||
def get(self, key: str, default=None):
|
||||
return super().get(key.lower(), default)
|
||||
|
||||
|
||||
class FakeUpload:
|
||||
def __init__(self, filename: str, data: bytes):
|
||||
self.filename = filename
|
||||
self._stream = io.BytesIO(data)
|
||||
|
||||
async def read(self, size: int = -1) -> bytes:
|
||||
return self._stream.read(size)
|
||||
|
||||
|
||||
class FakeMultipartRequest:
|
||||
def __init__(self, headers: dict[str, str], form: dict, host: str = "127.0.0.1"):
|
||||
self.headers = FakeHeaders(headers)
|
||||
self._form = form
|
||||
self.client = SimpleNamespace(host=host)
|
||||
|
||||
async def form(self):
|
||||
return self._form
|
||||
|
||||
|
||||
async def run_crash_report_upload_detail_and_duplicate(server_module):
|
||||
async with server_module.lifespan(server_module.app):
|
||||
from app.services import crash_api_service
|
||||
|
||||
minidump = b"fake minidump bytes"
|
||||
client_report_id = str(uuid.uuid4())
|
||||
metadata = crash_metadata(client_report_id, minidump)
|
||||
metadata_bytes = json.dumps(metadata).encode()
|
||||
headers = {
|
||||
"Authorization": "Bearer CrashReportTokenForTests2026",
|
||||
"Idempotency-Key": client_report_id,
|
||||
"Content-Type": "multipart/form-data; boundary=test",
|
||||
"Content-Length": str(len(metadata_bytes) + len(minidump)),
|
||||
"X-SimCAE-Client": "SIMCAE",
|
||||
"X-SimCAE-Version": "1.0.0",
|
||||
}
|
||||
|
||||
upload = await crash_api_service.create_crash_report(
|
||||
FakeMultipartRequest(
|
||||
headers,
|
||||
{
|
||||
"metadata": FakeUpload("metadata.json", metadata_bytes),
|
||||
"minidump": FakeUpload("crash.dmp", minidump),
|
||||
},
|
||||
)
|
||||
)
|
||||
assert upload.status_code == 201
|
||||
upload_body = json.loads(upload.body)
|
||||
report_id = upload_body["reportId"]
|
||||
|
||||
duplicate = await crash_api_service.create_crash_report(
|
||||
FakeMultipartRequest(
|
||||
headers,
|
||||
{
|
||||
"metadata": FakeUpload("metadata.json", metadata_bytes),
|
||||
"minidump": FakeUpload("crash.dmp", minidump),
|
||||
},
|
||||
)
|
||||
)
|
||||
assert duplicate.status_code == 200
|
||||
assert json.loads(duplicate.body)["duplicate"] is True
|
||||
|
||||
detail = crash_api_service.get_crash_report_detail(
|
||||
report_id,
|
||||
FakeMultipartRequest(
|
||||
{"Authorization": "Bearer CrashAdminTokenForTests2026"},
|
||||
{},
|
||||
),
|
||||
)
|
||||
assert detail["clientReportId"] == client_report_id
|
||||
|
||||
|
||||
def test_crash_report_upload_detail_and_duplicate(server_module):
|
||||
import asyncio
|
||||
|
||||
asyncio.run(run_crash_report_upload_detail_and_duplicate(server_module))
|
||||
Reference in New Issue
Block a user