use noxu_dbi::EnvironmentImpl;
use noxu_rep::{NodeType, RepConfig, RepNode, ReplicatedEnvironment};
use std::fs;
use std::sync::Arc;
use std::time::{Duration, Instant};
use tempfile::TempDir;
#[test]
fn replica_auto_bootstraps_on_needs_restore() {
let master_dir = TempDir::new().unwrap();
let master_home = master_dir.path().to_path_buf();
fs::write(master_home.join("00000001.ndb"), b"master log file 1").unwrap();
fs::write(master_home.join("00000002.ndb"), b"master log file 2 longer")
.unwrap();
fs::write(master_home.join("00000003.ndb"), b"master log 3").unwrap();
let master_cfg = RepConfig::builder("g_auto", "master", "127.0.0.1")
.node_port(0)
.env_home(&master_home)
.build();
let master_env = ReplicatedEnvironment::new(master_cfg).unwrap();
let master_addr = master_env.bound_addr().expect("master must bind");
let replica_dir = TempDir::new().unwrap();
let replica_home = replica_dir.path().to_path_buf();
let replica_cfg = RepConfig::builder("g_auto", "replica", "127.0.0.1")
.node_port(0)
.env_home(&replica_home)
.build();
let replica_env =
Arc::new(ReplicatedEnvironment::new(replica_cfg).unwrap());
replica_env.init_self_weak();
let live_env_dir = TempDir::new().unwrap();
let env_impl = Arc::new(
EnvironmentImpl::new(live_env_dir.path(), false, false).unwrap(),
);
replica_env.with_environment(env_impl);
replica_env
.add_peer(RepNode::new(
"master".to_string(),
NodeType::Electable,
"127.0.0.1".to_string(),
master_addr.port(),
1,
))
.unwrap();
let pre: Vec<_> = fs::read_dir(&replica_home)
.unwrap()
.filter_map(|e| e.ok())
.filter(|e| {
e.path()
.extension()
.and_then(|s| s.to_str())
.is_some_and(|s| s == "ndb")
})
.collect();
assert_eq!(pre.len(), 0, "replica env_home must start empty");
replica_env.become_replica("master").unwrap();
let deadline = Instant::now() + Duration::from_secs(10);
let mut copied: usize = 0;
while Instant::now() < deadline {
copied = fs::read_dir(&replica_home)
.unwrap()
.filter_map(|e| e.ok())
.filter(|e| {
e.path()
.extension()
.and_then(|s| s.to_str())
.is_some_and(|s| s == "ndb")
})
.count();
if copied >= 3 {
break;
}
std::thread::sleep(Duration::from_millis(100));
}
assert!(
copied >= 3,
"replica I/O thread should auto-bootstrap and copy 3 .ndb files; \
found {} after 10s",
copied,
);
let body1 = fs::read(replica_home.join("00000001.ndb")).unwrap();
assert_eq!(body1, b"master log file 1");
let body2 = fs::read(replica_home.join("00000002.ndb")).unwrap();
assert_eq!(body2, b"master log file 2 longer");
let body3 = fs::read(replica_home.join("00000003.ndb")).unwrap();
assert_eq!(body3, b"master log 3");
replica_env.close().unwrap();
master_env.close().unwrap();
}