use std::time::Duration;
use reifydb_runtime::actor::context::Context;
use super::helpers::*;
#[test]
fn scope_shares_clock() {
let parent = test_system();
let child = parent.scope();
parent.advance_time(Duration::from_millis(500));
assert_eq!(parent.clock().now_millis(), 500);
assert_eq!(child.clock().now_millis(), 500);
}
#[test]
fn scope_has_own_actors() {
let parent = test_system();
let child = parent.scope();
let _pa = parent.spawn("pa", CounterActor);
let _ca = child.spawn("ca", CounterActor);
assert_eq!(parent.alive_count(), 1);
assert_eq!(child.alive_count(), 1);
}
#[test]
fn scope_has_own_cancel() {
let parent = test_system();
let child = parent.scope();
let _pa = parent.spawn("pa", CounterActor);
let _ca = child.spawn("ca", CounterActor);
child.shutdown();
assert!(child.is_cancelled());
assert!(!parent.is_cancelled());
assert_eq!(child.alive_count(), 0);
assert_eq!(parent.alive_count(), 1);
}
#[test]
fn parent_shutdown_cancels_child_scope() {
let parent = test_system();
let child = parent.scope();
let _pa = parent.spawn("pa", CounterActor);
let ch = child.spawn("ca", CounterActor);
parent.shutdown();
assert!(parent.is_cancelled());
assert!(child.is_cancelled());
assert_eq!(parent.alive_count(), 0);
assert_eq!(child.alive_count(), 0);
assert!(ch.actor_ref.send(CounterMessage::Inc).is_err());
}
#[test]
fn scope_shares_timer_heap() {
let parent = test_system();
let child = parent.scope();
let log = new_log();
let handle = child.spawn(
"log",
LogActor {
log: log.clone(),
},
);
let ctx = Context::new(handle.actor_ref.clone(), parent.clone(), parent.cancellation_token());
ctx.schedule_once(Duration::from_millis(100), || "from_parent_timer".to_string());
parent.advance_time(Duration::from_millis(100));
child.run_until_idle();
assert_eq!(log_contents(&log), vec!["from_parent_timer"]);
}
#[test]
fn cross_scope_messaging() {
let parent = test_system();
let child = parent.scope();
let log = new_log();
let child_actor = child.spawn(
"child_log",
LogActor {
log: log.clone(),
},
);
child_actor.actor_ref.send("cross_scope".into()).unwrap();
child.run_until_idle();
assert_eq!(log_contents(&log), vec!["cross_scope"]);
}
#[test]
fn nested_scope_must_shutdown_recursively() {
let root = test_system();
let level1 = root.scope();
let level2 = level1.scope();
let _r = root.spawn("root_actor", CounterActor);
let _l1 = level1.spawn("level1_actor", CounterActor);
let _l2 = level2.spawn("level2_actor", CounterActor);
assert_eq!(root.alive_count(), 1);
assert_eq!(level1.alive_count(), 1);
assert_eq!(level2.alive_count(), 1);
level1.shutdown();
assert!(level1.is_cancelled());
assert!(level2.is_cancelled(), "Child scope level2 should have been cancelled by level1 shutdown");
assert!(!root.is_cancelled());
assert_eq!(level1.alive_count(), 0);
assert_eq!(level2.alive_count(), 0, "Actors in child scope level2 should have been shut down");
assert_eq!(root.alive_count(), 1);
}
#[test]
fn clock_advancement_is_asymmetric() {
let parent = test_system();
let child = parent.scope();
child.advance_time(std::time::Duration::from_millis(100));
assert_eq!(child.clock().now_millis(), 100);
assert_eq!(parent.clock().now_millis(), 0, "Child clock advancement leaked to parent!");
parent.advance_time(std::time::Duration::from_millis(200));
assert_eq!(parent.clock().now_millis(), 200);
assert!(child.clock().now_millis() >= 200, "Child clock failed to advance with parent!");
}