- 实现账户管理改进设计文档中的所有核心功能 - 三科目余额管理 (个人余额、劳动报酬、冻结余额) - 交易状态机 (created → pending → bank_submitted → success/failed/timeout → reversed) - 三键幂等体系 (JZTxId/BankTxId/SourceKey) - 优先级扣款规则 (先个人后劳动) - 在途资金管理 (可用→在途→结转/回退) - 三账对账闭环 (总账 = 银行账 + 在途净额) - 补偿服务域 (超时检测、重试、死信队列) - 虚拟银行模拟器用于业务测试 - 完整的集成测试套件 (133 个测试全部通过) - Docker 容器化部署配置 - 前端 Vue3 + TypeScript 项目结构
204 lines
5.4 KiB
Rust
204 lines
5.4 KiB
Rust
//! 虚拟银行测试设置
|
|
//!
|
|
//! 提供虚拟银行的初始化和配置辅助函数
|
|
|
|
use rust_decimal::Decimal;
|
|
use rust_decimal_macros::dec;
|
|
|
|
use rustjr::infrastructure::bank_integration::{
|
|
BankClient,
|
|
mock_bank::{FailureConfig, MockBankClient, MockBankTestEnv},
|
|
};
|
|
|
|
use super::fixtures::{
|
|
gen_inmate_account_no, FAMILY_ACCOUNT, FAMILY_ACCOUNT_NAME,
|
|
PRISON_MAIN_ACCOUNT, PRISON_MAIN_ACCOUNT_NAME,
|
|
};
|
|
|
|
// ==================== 虚拟银行环境 ====================
|
|
|
|
/// 标准测试银行环境
|
|
pub struct TestBankEnv {
|
|
/// 虚拟银行客户端
|
|
pub client: MockBankClient,
|
|
/// 监狱主账户号
|
|
pub prison_account: String,
|
|
/// 家属账户号
|
|
pub family_account: String,
|
|
}
|
|
|
|
impl TestBankEnv {
|
|
/// 创建标准测试环境
|
|
///
|
|
/// 包含:
|
|
/// - 监狱主账户:初始余额 1,000,000
|
|
/// - 家属账户:初始余额 100,000
|
|
pub fn new() -> Self {
|
|
let client = MockBankClient::new();
|
|
|
|
// 创建监狱主账户
|
|
client
|
|
.create_account(
|
|
PRISON_MAIN_ACCOUNT,
|
|
PRISON_MAIN_ACCOUNT_NAME,
|
|
dec!(1000000.00),
|
|
)
|
|
.expect("创建监狱账户失败");
|
|
|
|
// 创建家属账户
|
|
client
|
|
.create_account(FAMILY_ACCOUNT, FAMILY_ACCOUNT_NAME, dec!(100000.00))
|
|
.expect("创建家属账户失败");
|
|
|
|
Self {
|
|
client,
|
|
prison_account: PRISON_MAIN_ACCOUNT.to_string(),
|
|
family_account: FAMILY_ACCOUNT.to_string(),
|
|
}
|
|
}
|
|
|
|
/// 创建罪犯子账户
|
|
pub fn create_inmate_account(
|
|
&self,
|
|
inmate_id: i64,
|
|
initial_balance: Decimal,
|
|
) -> String {
|
|
let account_no = gen_inmate_account_no(inmate_id);
|
|
let account_name = format!("罪犯{}账户", inmate_id);
|
|
|
|
self.client
|
|
.create_account(&account_no, &account_name, initial_balance)
|
|
.expect("创建罪犯账户失败");
|
|
|
|
account_no
|
|
}
|
|
|
|
/// 启用故障注入
|
|
pub fn enable_failures(&self) {
|
|
self.client
|
|
.set_failure_config(FailureConfig::for_testing());
|
|
}
|
|
|
|
/// 禁用故障注入
|
|
pub fn disable_failures(&self) {
|
|
self.client.set_failure_enabled(false);
|
|
}
|
|
|
|
/// 配置强制超时
|
|
pub fn force_timeout(&self) {
|
|
self.client.set_failure_config(FailureConfig::force_timeout());
|
|
}
|
|
|
|
/// 配置强制失败
|
|
pub fn force_failure(&self) {
|
|
self.client.set_failure_config(FailureConfig::force_failure());
|
|
}
|
|
|
|
/// 重置环境
|
|
pub fn reset(&self) {
|
|
self.client.reset();
|
|
// 重新创建账户
|
|
self.client
|
|
.create_account(
|
|
PRISON_MAIN_ACCOUNT,
|
|
PRISON_MAIN_ACCOUNT_NAME,
|
|
dec!(1000000.00),
|
|
)
|
|
.expect("重建监狱账户失败");
|
|
|
|
self.client
|
|
.create_account(FAMILY_ACCOUNT, FAMILY_ACCOUNT_NAME, dec!(100000.00))
|
|
.expect("重建家属账户失败");
|
|
}
|
|
}
|
|
|
|
impl Default for TestBankEnv {
|
|
fn default() -> Self {
|
|
Self::new()
|
|
}
|
|
}
|
|
|
|
// ==================== 快捷创建函数 ====================
|
|
|
|
/// 创建标准测试银行环境
|
|
pub fn setup_test_bank() -> TestBankEnv {
|
|
TestBankEnv::new()
|
|
}
|
|
|
|
/// 创建带故障注入的测试银行环境
|
|
pub fn setup_test_bank_with_failures() -> TestBankEnv {
|
|
let env = TestBankEnv::new();
|
|
env.enable_failures();
|
|
env
|
|
}
|
|
|
|
/// 创建强制超时的测试银行环境
|
|
pub fn setup_test_bank_force_timeout() -> TestBankEnv {
|
|
let env = TestBankEnv::new();
|
|
env.force_timeout();
|
|
env
|
|
}
|
|
|
|
/// 创建强制失败的测试银行环境
|
|
pub fn setup_test_bank_force_failure() -> TestBankEnv {
|
|
let env = TestBankEnv::new();
|
|
env.force_failure();
|
|
env
|
|
}
|
|
|
|
// ==================== 验证辅助函数 ====================
|
|
|
|
/// 验证银行余额
|
|
pub async fn assert_bank_balance(
|
|
client: &MockBankClient,
|
|
account_no: &str,
|
|
expected: Decimal,
|
|
) {
|
|
let balance = client.query_balance(account_no).await.expect("查询余额失败");
|
|
assert_eq!(
|
|
balance.balance, expected,
|
|
"账户 {} 余额不符: 期望 {}, 实际 {}",
|
|
account_no, expected, balance.balance
|
|
);
|
|
}
|
|
|
|
/// 验证银行可用余额
|
|
pub async fn assert_available_balance(
|
|
client: &MockBankClient,
|
|
account_no: &str,
|
|
expected: Decimal,
|
|
) {
|
|
let balance = client.query_balance(account_no).await.expect("查询余额失败");
|
|
assert_eq!(
|
|
balance.available_balance, expected,
|
|
"账户 {} 可用余额不符: 期望 {}, 实际 {}",
|
|
account_no, expected, balance.available_balance
|
|
);
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[tokio::test]
|
|
async fn test_setup_env() {
|
|
let env = setup_test_bank();
|
|
|
|
let prison_balance = env.client.query_balance(&env.prison_account).await.unwrap();
|
|
assert_eq!(prison_balance.balance, dec!(1000000.00));
|
|
|
|
let family_balance = env.client.query_balance(&env.family_account).await.unwrap();
|
|
assert_eq!(family_balance.balance, dec!(100000.00));
|
|
}
|
|
|
|
#[tokio::test]
|
|
async fn test_create_inmate_account() {
|
|
let env = setup_test_bank();
|
|
let inmate_account = env.create_inmate_account(1001, dec!(5000.00));
|
|
|
|
let balance = env.client.query_balance(&inmate_account).await.unwrap();
|
|
assert_eq!(balance.balance, dec!(5000.00));
|
|
}
|
|
}
|
|
|