first commit
This commit is contained in:
@@ -0,0 +1,186 @@
|
||||
"""Exact endpoint and fail-closed tests for diagnosis-detail mutations."""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import time
|
||||
from datetime import date
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
|
||||
import pytest
|
||||
|
||||
from doctor_workstation.services.mock_repository import DemoDoctorRepository
|
||||
from doctor_workstation.services.repository import RemoteDoctorRepository
|
||||
|
||||
|
||||
class RecordingClient:
|
||||
"""Minimal no-network client that preserves exact endpoint DTOs."""
|
||||
|
||||
def __init__(self) -> None:
|
||||
self.get_calls: list[tuple[str, dict[str, Any]]] = []
|
||||
self.post_calls: list[tuple[str, dict[str, Any]]] = []
|
||||
|
||||
def get(self, endpoint: str, params: dict[str, Any] | None = None) -> Any:
|
||||
body = dict(params or {})
|
||||
self.get_calls.append((endpoint, body))
|
||||
if endpoint == "tcm.diagnosis/getImChatMessages":
|
||||
return {"lists": [], "patient_im_id": "patient_301"}
|
||||
return {"lists": [], "count": 0}
|
||||
|
||||
def post(self, endpoint: str, payload: dict[str, Any] | None = None) -> Any:
|
||||
body = dict(payload or {})
|
||||
self.post_calls.append((endpoint, body))
|
||||
if endpoint == "tcm.diagnosis/createManualCallRecord":
|
||||
return {"id": 88}
|
||||
if endpoint == "tcm.diagnosis/generateMiniProgramQrcode":
|
||||
return {"qrcode_url": "https://example.invalid/mini.png"}
|
||||
if endpoint == "tcm.diagnosis/generateOrderQrcode":
|
||||
return {"qrcode_url": "https://example.invalid/order.png"}
|
||||
if endpoint == "order.order/create":
|
||||
return {"id": 99, "order_no": "ORDER99"}
|
||||
return {"ok": True}
|
||||
|
||||
|
||||
def test_remote_detail_actions_use_exact_confirmed_endpoints() -> None:
|
||||
client = RecordingClient()
|
||||
repository = RemoteDoctorRepository(client) # type: ignore[arg-type]
|
||||
today = date.today().isoformat()
|
||||
|
||||
repository.set_revisit_slot_start_offset(501, 4)
|
||||
repository.add_blood_record(
|
||||
diagnosis_id=501,
|
||||
patient_id=301,
|
||||
record_date=today,
|
||||
record_time="09:30",
|
||||
fasting_blood_sugar=6.2,
|
||||
)
|
||||
repository.add_diet_record(
|
||||
diagnosis_id=501,
|
||||
patient_id=301,
|
||||
record_date=today,
|
||||
breakfast_foods="燕麦",
|
||||
breakfast_images=[],
|
||||
lunch_images=[],
|
||||
dinner_images=[],
|
||||
)
|
||||
repository.add_exercise_record(
|
||||
diagnosis_id=501,
|
||||
patient_id=301,
|
||||
record_date=today,
|
||||
exercise_type="步行",
|
||||
duration=30,
|
||||
intensity=2,
|
||||
images=[],
|
||||
)
|
||||
repository.add_tracking_note(501, "继续观察")
|
||||
repository.add_diagnosis_todo(501, "复测餐后血糖", int(time.time()) + 120)
|
||||
repository.cancel_diagnosis_todo(77)
|
||||
repository.list_call_records(501)
|
||||
repository.create_manual_call_record(501)
|
||||
repository.attach_local_call_recording(
|
||||
501, "https://media.example.invalid/replay.mp4", call_record_id=88
|
||||
)
|
||||
assert repository.list_im_chat_messages(501)["lists"] == []
|
||||
repository.sync_im_chat_messages(501)
|
||||
repository.list_appointment_logs(501)
|
||||
repository.generate_video_qrcode(1001, 301, 1001)
|
||||
repository.generate_diagnosis_qrcode(501, 1001, 301, 1001)
|
||||
repository.create_diagnosis_order(301, 2, 88.6, remark="检查费")
|
||||
repository.generate_order_qrcode("ORDER99")
|
||||
repository.cancel_diagnosis_appointment(101)
|
||||
|
||||
assert ("tcm.diagnosis/getCallRecords", {"diagnosis_id": 501}) in client.get_calls
|
||||
assert (
|
||||
"tcm.diagnosis/getImChatMessages",
|
||||
{"diagnosis_id": 501, "only_archived": 1},
|
||||
) in client.get_calls
|
||||
assert ("tcm.diagnosis/guahaoLogList", {"id": 501}) in client.get_calls
|
||||
assert (
|
||||
"doctor.appointment/cancel",
|
||||
{"id": 101},
|
||||
) in client.post_calls
|
||||
assert (
|
||||
"tcm.diagnosis/setRevisitSlotStartOffset",
|
||||
{"id": 501, "revisit_slot_start_offset": 4},
|
||||
) in client.post_calls
|
||||
assert (
|
||||
"order.order/create",
|
||||
{"patient_id": 301, "order_type": 2, "amount": 88.6, "remark": "检查费"},
|
||||
) in client.post_calls
|
||||
qr_payloads = [
|
||||
body
|
||||
for endpoint, body in client.post_calls
|
||||
if endpoint == "tcm.diagnosis/generateMiniProgramQrcode"
|
||||
]
|
||||
assert qr_payloads[0] == {
|
||||
"doctor_id": 1001,
|
||||
"patient_id": 301,
|
||||
"share_user_id": 1001,
|
||||
"mini_program_path": "pages/login/login",
|
||||
}
|
||||
assert qr_payloads[1] == {
|
||||
"diagnosis_id": 501,
|
||||
"doctor_id": 1001,
|
||||
"patient_id": 301,
|
||||
"share_user_id": 1001,
|
||||
}
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
("call", "message"),
|
||||
[
|
||||
(lambda repo: repo.set_revisit_slot_start_offset(501, 21), "between 0 and 20"),
|
||||
(lambda repo: repo.add_tracking_note(501, ""), "1 to 1000"),
|
||||
(
|
||||
lambda repo: repo.add_diagnosis_todo(501, "稍后", int(time.time()) + 5),
|
||||
"30 seconds",
|
||||
),
|
||||
(lambda repo: repo.cancel_diagnosis_todo(0), "positive"),
|
||||
(lambda repo: repo.create_diagnosis_order(301, 9, 1), "between 1 and 8"),
|
||||
(lambda repo: repo.cancel_diagnosis_appointment(0), "positive"),
|
||||
],
|
||||
)
|
||||
def test_remote_detail_validation_fails_before_transport(call: Any, message: str) -> None:
|
||||
client = RecordingClient()
|
||||
repository = RemoteDoctorRepository(client) # type: ignore[arg-type]
|
||||
|
||||
with pytest.raises(ValueError, match=message):
|
||||
call(repository)
|
||||
assert client.get_calls == []
|
||||
assert client.post_calls == []
|
||||
|
||||
|
||||
def test_demo_detail_mutations_round_trip(tmp_path: Path) -> None:
|
||||
repository = DemoDoctorRepository(today=date(2026, 8, 10))
|
||||
blood = repository.add_blood_record(
|
||||
diagnosis_id=501,
|
||||
patient_id=301,
|
||||
record_date="2026-08-10",
|
||||
fasting_blood_sugar=5.8,
|
||||
)
|
||||
assert blood["id"] > 0
|
||||
assert (
|
||||
repository.get_tracking_window(501, start_date="2026-08-10", end_date="2026-08-10")[
|
||||
"blood_records"
|
||||
][-1]["fasting_blood_sugar"]
|
||||
== 5.8
|
||||
)
|
||||
|
||||
todo = repository.add_diagnosis_todo(501, "今晚回访", int(time.time()) + 120)
|
||||
cancelled = repository.cancel_diagnosis_todo(todo["id"])
|
||||
assert cancelled["status_text"] == "已取消"
|
||||
|
||||
replay = tmp_path / "replay.mp4"
|
||||
replay.write_bytes(b"demo-video")
|
||||
uploaded = repository.upload_call_recording(replay, 501)
|
||||
assert uploaded["file_url"].startswith("/demo/uploads/video/")
|
||||
assert uploaded["file_url"] in repository.list_call_records(501)[0]["recording_urls_list"]
|
||||
|
||||
archive = repository.list_im_chat_messages(501, only_archived=True)
|
||||
assert archive["only_archived"] is True
|
||||
assert {row["msg_type"] for row in archive["lists"]} >= {"text", "image", "file"}
|
||||
assert repository.sync_im_chat_messages(501)["queued"] is True
|
||||
|
||||
repository.set_revisit_slot_start_offset(501, 7)
|
||||
assert repository.get_diagnosis_detail(501)["diagnosis"]["revisit_slot_start_offset"] == 7
|
||||
assert repository.cancel_diagnosis_appointment(101)["status"] == 2
|
||||
Reference in New Issue
Block a user