Files
hms/crates/erp-server/tests/integration/health_consultation_tests.rs
iven 41a865cf68 feat(health+core+ai): 业务流程全面修复 Phase 4-6 + 集成测试修复
Phase 4 — Dead-letter 重试 + 内容推送 + 安全加固:
- erp-core: retry_dead_letters() 定时重试 + PII payload 脱敏
- erp-core: audit_service 哈希链定时验证 + 写入失败告警
- erp-health: article.published 消费者匹配 patient_tag 推送消息
- erp-health: care_plan 事件消费者 (激活通知 + 完成积分)

Phase 5 — 患者批量操作 + 咨询增强 + 护理事件:
- patient: batch_import_patients + bind_by_phone + refer_patient
- consultation: rate_session 满意度评价 (rating + feedback)
- consent: patient_sign_consent 患者端签署
- validation: source 枚举 (7值) + relationship 枚举 (7值) + 12 单元测试

Phase 6 — 咨询文件上传 + AI 引用标注:
- consultation_message: media_id 附件上传端点
- ai_suggestion: references JSONB + [ref:id] 格式引用标注
- AI system prompt 增加引用指令 + output_parser 提取逻辑

迁移: 000161 (media_id + references) + 000162 (rating + feedback)
集成测试: consultation/follow_up/pii_encryption 新字段同步修复
讨论文档: 2026-05-20-business-process-brainstorm.md (10域审核报告)
2026-05-21 01:34:20 +08:00

246 lines
7.5 KiB
Rust

//! erp-health 咨询管理集成测试
//!
//! 验证咨询会话 CRUD、消息收发、会话关闭、未读计数、租户隔离。
use erp_health::dto::consultation_dto::*;
use erp_health::service::consultation_service;
use super::test_fixture::TestApp;
/// 创建测试用会话(无医护)
async fn seed_session(app: &TestApp, patient_id: uuid::Uuid) -> SessionResp {
consultation_service::create_session(
app.health_state(),
app.tenant_id(),
Some(app.operator_id()),
CreateSessionReq {
patient_id,
doctor_id: None,
consultation_type: None,
},
)
.await
.expect("创建会话应成功")
}
// ---------------------------------------------------------------------------
// 测试 1: 创建会话(带医护)
// ---------------------------------------------------------------------------
#[tokio::test]
async fn test_consultation_session_create() {
let app = TestApp::new().await;
let patient_id = app.create_patient("咨询患者").await;
let doctor_id = app.create_doctor("咨询医生").await;
let session = consultation_service::create_session(
app.health_state(),
app.tenant_id(),
Some(app.operator_id()),
CreateSessionReq {
patient_id,
doctor_id: Some(doctor_id),
consultation_type: Some("doctor".to_string()),
},
)
.await
.expect("创建会话应成功");
assert_eq!(session.patient_id, patient_id);
assert_eq!(session.doctor_id, Some(doctor_id));
assert_eq!(session.consultation_type, "doctor");
assert_eq!(session.status, "waiting");
}
// ---------------------------------------------------------------------------
// 测试 2: 查询会话
// ---------------------------------------------------------------------------
#[tokio::test]
async fn test_consultation_session_get() {
let app = TestApp::new().await;
let patient_id = app.create_patient("查询患者").await;
let session = seed_session(&app, patient_id).await;
let fetched =
consultation_service::get_session(app.health_state(), app.tenant_id(), session.id)
.await
.expect("查询应成功");
assert_eq!(fetched.id, session.id);
assert_eq!(fetched.status, "waiting");
}
// ---------------------------------------------------------------------------
// 测试 3: 列表按患者过滤
// ---------------------------------------------------------------------------
#[tokio::test]
async fn test_consultation_session_list_by_patient() {
let app = TestApp::new().await;
let patient_a = app.create_patient("列表患者A").await;
let patient_b = app.create_patient("列表患者B").await;
seed_session(&app, patient_a).await;
seed_session(&app, patient_a).await;
seed_session(&app, patient_b).await;
let list_a = consultation_service::list_sessions(
app.health_state(),
app.tenant_id(),
1,
20,
None,
Some(patient_a),
None,
)
.await
.unwrap();
assert_eq!(list_a.total, 2);
let list_b = consultation_service::list_sessions(
app.health_state(),
app.tenant_id(),
1,
20,
None,
Some(patient_b),
None,
)
.await
.unwrap();
assert_eq!(list_b.total, 1);
}
// ---------------------------------------------------------------------------
// 测试 4: 发送消息
// ---------------------------------------------------------------------------
#[tokio::test]
async fn test_consultation_message_send() {
let app = TestApp::new().await;
let patient_id = app.create_patient("消息患者").await;
let session = seed_session(&app, patient_id).await;
let msg = consultation_service::create_message(
app.health_state(),
app.tenant_id(),
Some(app.operator_id()),
app.operator_id(),
"doctor".to_string(),
CreateMessageReq {
session_id: session.id,
content_type: Some("text".to_string()),
content: "您好,有什么可以帮您?".to_string(),
media_id: None,
},
)
.await
.expect("发送消息应成功");
assert_eq!(msg.session_id, session.id);
assert_eq!(msg.content, "您好,有什么可以帮您?");
assert_eq!(msg.sender_role, "doctor");
assert!(!msg.is_read);
}
// ---------------------------------------------------------------------------
// 测试 5: 查询消息列表
// ---------------------------------------------------------------------------
#[tokio::test]
async fn test_consultation_message_list() {
let app = TestApp::new().await;
let patient_id = app.create_patient("消息列表患者").await;
let session = seed_session(&app, patient_id).await;
for i in 0..3 {
consultation_service::create_message(
app.health_state(),
app.tenant_id(),
Some(app.operator_id()),
app.operator_id(),
"doctor".to_string(),
CreateMessageReq {
session_id: session.id,
content_type: None,
content: format!("消息{}", i + 1),
media_id: None,
},
)
.await
.unwrap();
}
let messages = consultation_service::list_messages(
app.health_state(),
app.tenant_id(),
session.id,
1,
20,
None,
)
.await
.expect("查询消息应成功");
assert_eq!(messages.total, 3);
}
// ---------------------------------------------------------------------------
// 测试 6: 关闭会话
// ---------------------------------------------------------------------------
#[tokio::test]
async fn test_consultation_session_close() {
let app = TestApp::new().await;
let patient_id = app.create_patient("关闭患者").await;
let session = seed_session(&app, patient_id).await;
assert_eq!(session.status, "waiting");
let closed = consultation_service::close_session(
app.health_state(),
app.tenant_id(),
session.id,
Some(app.operator_id()),
session.version,
)
.await
.expect("关闭应成功");
assert_eq!(closed.status, "closed");
}
// ---------------------------------------------------------------------------
// 测试 7: 租户隔离
// ---------------------------------------------------------------------------
#[tokio::test]
async fn test_consultation_session_tenant_isolation() {
let app = TestApp::new().await;
let patient_id = app.create_patient("隔离患者").await;
let session = seed_session(&app, patient_id).await;
let other_tenant = uuid::Uuid::new_v4();
let result =
consultation_service::get_session(app.health_state(), other_tenant, session.id).await;
assert!(result.is_err(), "不同租户不应看到此会话");
}
// ---------------------------------------------------------------------------
// 测试 8: 无效患者创建会话返回错误
// ---------------------------------------------------------------------------
#[tokio::test]
async fn test_consultation_session_invalid_patient() {
let app = TestApp::new().await;
let fake_patient = uuid::Uuid::new_v4();
let result = consultation_service::create_session(
app.health_state(),
app.tenant_id(),
None,
CreateSessionReq {
patient_id: fake_patient,
doctor_id: None,
consultation_type: None,
},
)
.await;
assert!(result.is_err(), "无效患者应返回错误");
}