use std::time::{Duration, Instant};
use sz_orm_core::{
rw_split_enhanced::{AutoFailoverCoordinator, ProbeResult},
FailbackStrategy, FailoverConfig,
};
fn make_ha_config() -> FailoverConfig {
FailoverConfig {
primary_url: "mysql://root:test123@127.0.0.1:3306/sz_orm_test".into(),
replica_url: "mysql://root:test123@127.0.0.1:3307/sz_orm_test".into(),
probe_interval: Duration::from_secs(1),
probe_failure_threshold: 3,
failback_strategy: FailbackStrategy::Auto,
}
}
#[tokio::test]
#[ignore = "需要真实主备库(MySQL 3306 + 3307)"]
async fn failover_e2e_primary_down_failover_within_5s() {
let coord = AutoFailoverCoordinator::new(make_ha_config());
coord.set_primary_lsn(100);
coord.set_replica_lsn(100);
let start = Instant::now();
for _ in 0..3 {
coord.record_probe(ProbeResult {
success: false,
timestamp_ms: chrono::Utc::now().timestamp_millis(),
error: Some("connection refused".to_string()),
});
}
let elapsed = start.elapsed();
assert!(coord.is_failed_over(), "应已故障转移到备库");
assert!(
elapsed <= Duration::from_secs(5),
"RTO 应 ≤ 5s,实际 {:?}",
elapsed
);
let history = coord.decision_history();
assert!(!history.is_empty());
assert!(history[0].switched);
}
#[tokio::test]
#[ignore = "需要真实主备库(MySQL 3306 + 3307)"]
async fn failover_e2e_lsn_check_and_failback() {
let coord = AutoFailoverCoordinator::new(make_ha_config());
coord.set_primary_lsn(100);
coord.set_replica_lsn(100);
coord.trigger_failover().unwrap();
assert!(coord.is_failed_over());
coord.record_probe(ProbeResult {
success: true,
timestamp_ms: chrono::Utc::now().timestamp_millis(),
error: None,
});
coord.set_replica_lsn(100);
coord.failback(FailbackStrategy::Auto).unwrap();
assert!(!coord.is_failed_over(), "应已回切到主库");
}