1e186369c9
Project CI / AI game creator shell Rust crates (push) Successful in 1m24s
Project CI / AI game creator shell Rust smoke (push) Successful in 1m56s
Project CI / AI game creator shell Rust lane 1/2 (push) Has been cancelled
Project CI / Frontend tests (push) Has been cancelled
Project CI / Backend tests (push) Has been cancelled
Project CI / Repository checks (push) Has been cancelled
Project CI / AI game creator shell web tests (push) Has been cancelled
Project CI / AI game creator shell Rust lane 2/2 (push) Has been cancelled
Project CI / Native shell tests (push) Has been cancelled
Reviewed-on: https://git.genarrative.world/git/GenarrativeAI/Genarrative/pulls/446 Co-authored-by: Linghong <ink29535@proton.me> Co-committed-by: Linghong <ink29535@proton.me>
102 lines
3.9 KiB
Rust
102 lines
3.9 KiB
Rust
use super::*;
|
|
|
|
fn fixture() -> (tempfile::TempDir, std::path::PathBuf, SessionRecord) {
|
|
let dir = tempfile::tempdir().unwrap();
|
|
let id = uuid::Uuid::new_v4().to_string();
|
|
let instance = dir.path().join(&id);
|
|
fs::create_dir(&instance).unwrap();
|
|
let record = SessionRecord {
|
|
schema_version: 1,
|
|
editor_session_id: id,
|
|
route: Route {
|
|
user_id: Some("user".into()),
|
|
destination_origin: Some("https://example.com".into()),
|
|
},
|
|
lifecycle_state: LifecycleState::Active,
|
|
focus_interval_id: None,
|
|
updated_at: "2026-09-21T00:00:00.000Z".into(),
|
|
incomplete_detected_at: None,
|
|
};
|
|
(dir, instance, record)
|
|
}
|
|
|
|
#[test]
|
|
fn locked_owner_is_live_and_released_owner_is_recovered_once() {
|
|
let (dir, path, record) = fixture();
|
|
let owner = claim(&path).unwrap();
|
|
write(&path, &record, &record.editor_session_id).unwrap();
|
|
recover(dir.path(), "another");
|
|
assert_eq!(read(&path).unwrap().lifecycle_state, LifecycleState::Active);
|
|
drop(owner);
|
|
recover(dir.path(), "another");
|
|
let recovered = read(&path).unwrap();
|
|
assert_eq!(recovered.lifecycle_state, LifecycleState::Incomplete);
|
|
assert_eq!(recovered.updated_at, record.updated_at);
|
|
let bytes = fs::read(path.join("session.json")).unwrap();
|
|
recover(dir.path(), "another");
|
|
assert_eq!(fs::read(path.join("session.json")).unwrap(), bytes);
|
|
}
|
|
|
|
#[test]
|
|
fn missing_proof_and_wrong_identity_are_untouched() {
|
|
let (dir, path, record) = fixture();
|
|
write(&path, &record, &record.editor_session_id).unwrap();
|
|
recover(dir.path(), "another");
|
|
assert_eq!(read(&path).unwrap().lifecycle_state, LifecycleState::Active);
|
|
drop(claim(&path).unwrap());
|
|
let mut wrong = record.clone();
|
|
wrong.editor_session_id = uuid::Uuid::new_v4().to_string();
|
|
fs::write(
|
|
path.join("session.json"),
|
|
serde_json::to_vec(&wrong).unwrap(),
|
|
)
|
|
.unwrap();
|
|
let before = fs::read(path.join("session.json")).unwrap();
|
|
recover(dir.path(), "another");
|
|
assert_eq!(fs::read(path.join("session.json")).unwrap(), before);
|
|
}
|
|
|
|
#[test]
|
|
fn metadata_prune_skips_live_owner_and_removes_inactive_record() {
|
|
let (dir, path, mut record) = fixture();
|
|
let owner = claim(&path).unwrap();
|
|
record.lifecycle_state = LifecycleState::Closed;
|
|
write(&path, &record, &record.editor_session_id).unwrap();
|
|
prune(dir.path(), "other", 0, 0, Duration::ZERO, || 100);
|
|
assert!(path.join("session.json").exists());
|
|
drop(owner);
|
|
prune(dir.path(), "other", 0, 0, Duration::ZERO, || 100);
|
|
assert!(!path.join("session.json").exists());
|
|
}
|
|
|
|
#[test]
|
|
fn corrupt_and_abandoned_session_files_are_bounded_and_empty_instance_is_removed() {
|
|
let (dir, path, _) = fixture();
|
|
drop(claim(&path).unwrap());
|
|
fs::create_dir(path.join("batches")).unwrap();
|
|
fs::write(path.join("session.json"), b"broken-json").unwrap();
|
|
let temporary = path.join(format!(".session-{}.tmp", uuid::Uuid::new_v4()));
|
|
fs::write(&temporary, b"unfinished").unwrap();
|
|
prune(dir.path(), "other", 0, u64::MAX, Duration::ZERO, || 100);
|
|
assert!(!path.exists());
|
|
}
|
|
|
|
#[test]
|
|
fn pressure_prunes_corrupt_metadata_but_keeps_live_and_unknown_files() {
|
|
let (dir, path, _) = fixture();
|
|
let owner = claim(&path).unwrap();
|
|
fs::write(path.join("session.json"), b"broken").unwrap();
|
|
let temporary = path.join(format!(".session-{}.tmp", uuid::Uuid::new_v4()));
|
|
fs::write(&temporary, b"unfinished").unwrap();
|
|
fs::write(path.join("unknown.json"), b"untouched").unwrap();
|
|
prune(dir.path(), "other", 1, 0, Duration::MAX, || 100);
|
|
assert!(path.join("session.json").exists());
|
|
assert!(temporary.exists());
|
|
drop(owner);
|
|
prune(dir.path(), "other", 1, 0, Duration::MAX, || 100);
|
|
assert!(!path.join("session.json").exists());
|
|
assert!(!temporary.exists());
|
|
assert!(path.join("unknown.json").exists());
|
|
assert!(path.join("owner.lock").exists());
|
|
}
|