test(health): 扩展患者集成测试 +3 — 更新乐观锁/PII加密验证/姓名搜索
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
//! 使用 TestDb 创建隔离 PostgreSQL 数据库,直接调用 service 层函数。
|
//! 使用 TestDb 创建隔离 PostgreSQL 数据库,直接调用 service 层函数。
|
||||||
|
|
||||||
use erp_core::events::EventBus;
|
use erp_core::events::EventBus;
|
||||||
use erp_health::dto::patient_dto::CreatePatientReq;
|
use erp_health::dto::patient_dto::{CreatePatientReq, UpdatePatientReq};
|
||||||
use erp_health::service::patient_service;
|
use erp_health::service::patient_service;
|
||||||
use erp_health::state::HealthState;
|
use erp_health::state::HealthState;
|
||||||
use erp_core::crypto::PiiCrypto;
|
use erp_core::crypto::PiiCrypto;
|
||||||
@@ -206,3 +206,114 @@ async fn test_patient_soft_delete() {
|
|||||||
let lookup = patient_service::get_patient(&state, tenant_id, patient.id).await;
|
let lookup = patient_service::get_patient(&state, tenant_id, patient.id).await;
|
||||||
assert!(lookup.is_err(), "软删除后查询应返回错误");
|
assert!(lookup.is_err(), "软删除后查询应返回错误");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_patient_update_and_optimistic_lock() {
|
||||||
|
let test_db = TestDb::new().await;
|
||||||
|
let state = make_state(test_db.db());
|
||||||
|
let tenant_id = uuid::Uuid::new_v4();
|
||||||
|
let operator_id = uuid::Uuid::new_v4();
|
||||||
|
|
||||||
|
let patient = patient_service::create_patient(&state, tenant_id, Some(operator_id), CreatePatientReq {
|
||||||
|
name: "更新前".to_string(),
|
||||||
|
gender: Some("male".to_string()),
|
||||||
|
birth_date: None, blood_type: None, id_number: None,
|
||||||
|
allergy_history: None, medical_history_summary: None,
|
||||||
|
emergency_contact_name: None, emergency_contact_phone: None,
|
||||||
|
source: None, notes: None,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.expect("创建应成功");
|
||||||
|
|
||||||
|
// 正确版本更新
|
||||||
|
let updated = patient_service::update_patient(
|
||||||
|
&state, tenant_id, patient.id, Some(operator_id),
|
||||||
|
UpdatePatientReq {
|
||||||
|
name: Some("更新后".to_string()),
|
||||||
|
gender: None, birth_date: None, blood_type: None,
|
||||||
|
id_number: None, allergy_history: None,
|
||||||
|
medical_history_summary: None, emergency_contact_name: None,
|
||||||
|
emergency_contact_phone: None, source: None, notes: None,
|
||||||
|
status: None, verification_status: None,
|
||||||
|
},
|
||||||
|
patient.version,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.expect("更新应成功");
|
||||||
|
assert_eq!(updated.name, "更新后");
|
||||||
|
assert_eq!(updated.version, 2);
|
||||||
|
|
||||||
|
// 旧版本更新应失败
|
||||||
|
let result = patient_service::update_patient(
|
||||||
|
&state, tenant_id, patient.id, Some(operator_id),
|
||||||
|
UpdatePatientReq {
|
||||||
|
name: Some("冲突".to_string()),
|
||||||
|
gender: None, birth_date: None, blood_type: None,
|
||||||
|
id_number: None, allergy_history: None,
|
||||||
|
medical_history_summary: None, emergency_contact_name: None,
|
||||||
|
emergency_contact_phone: None, source: None, notes: None,
|
||||||
|
status: None, verification_status: None,
|
||||||
|
},
|
||||||
|
patient.version, // 旧版本
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
assert!(result.is_err(), "旧版本更新应失败");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_patient_pii_encrypted() {
|
||||||
|
let test_db = TestDb::new().await;
|
||||||
|
let state = make_state(test_db.db());
|
||||||
|
let tenant_id = uuid::Uuid::new_v4();
|
||||||
|
|
||||||
|
let patient = patient_service::create_patient(&state, tenant_id, None, CreatePatientReq {
|
||||||
|
name: "加密患者".to_string(),
|
||||||
|
gender: None,
|
||||||
|
birth_date: None, blood_type: None,
|
||||||
|
id_number: Some("330102199001011234".to_string()),
|
||||||
|
allergy_history: Some("花粉过敏".to_string()),
|
||||||
|
medical_history_summary: Some("高血压".to_string()),
|
||||||
|
emergency_contact_name: Some("王五".to_string()),
|
||||||
|
emergency_contact_phone: Some("13900139000".to_string()),
|
||||||
|
source: None, notes: None,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.expect("创建应成功");
|
||||||
|
|
||||||
|
// 列表视图应隐藏 id_number
|
||||||
|
assert!(patient.id_number.is_none(), "列表视图不应返回身份证号");
|
||||||
|
|
||||||
|
// get_patient 详情应包含 PII 解密后的字段(部分脱敏)
|
||||||
|
let detail = patient_service::get_patient(&state, tenant_id, patient.id)
|
||||||
|
.await
|
||||||
|
.expect("查询详情应成功");
|
||||||
|
// id_number 返回脱敏版本
|
||||||
|
assert!(detail.id_number.is_some(), "详情应返回 id_number(脱敏)");
|
||||||
|
assert_eq!(detail.allergy_history, Some("花粉过敏".to_string()));
|
||||||
|
assert_eq!(detail.emergency_contact_name, Some("王五".to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[tokio::test]
|
||||||
|
async fn test_patient_search_by_name() {
|
||||||
|
let test_db = TestDb::new().await;
|
||||||
|
let state = make_state(test_db.db());
|
||||||
|
let tenant_id = uuid::Uuid::new_v4();
|
||||||
|
|
||||||
|
for name in &["赵一", "钱二", "孙三"] {
|
||||||
|
patient_service::create_patient(&state, tenant_id, None, CreatePatientReq {
|
||||||
|
name: name.to_string(),
|
||||||
|
gender: None, birth_date: None, blood_type: None, id_number: None,
|
||||||
|
allergy_history: None, medical_history_summary: None,
|
||||||
|
emergency_contact_name: None, emergency_contact_phone: None,
|
||||||
|
source: None, notes: None,
|
||||||
|
})
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
let result = patient_service::list_patients(&state, tenant_id, 1, 10, Some("钱".to_string()), None)
|
||||||
|
.await
|
||||||
|
.expect("搜索应成功");
|
||||||
|
assert_eq!(result.total, 1);
|
||||||
|
assert_eq!(result.data[0].name, "钱二");
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user