KeiSeiKit-1.0/_primitives/_rust/kei-store/tests/integration.rs
Parfii-bot 19ee220e0a feat(primitives): 4 Rust crates for deep-sleep — conflict-scan, refactor-engine, graph-check, store
- kei-conflict-scan: rules/hooks/blocks/orphans/CP detection (6 tests)
- kei-refactor-engine: plan-mode + advisory patch format, zero-conflict guarantee (5 tests)
- kei-graph-check: wikilinks/handoffs/block-refs validator (4 tests)
- kei-store: trait + 5 backends (filesystem/github/forgejo/gitea prod, s3 stub) (8 tests)

1916 LOC Rust total; all files <200 LOC; 23/23 tests pass.
2026-04-22 08:28:22 +08:00

150 lines
5.2 KiB
Rust

//! Integration tests for kei-store.
use std::fs;
use std::path::PathBuf;
use tempfile::TempDir;
fn bin() -> PathBuf {
PathBuf::from(env!("CARGO_BIN_EXE_kei-store"))
}
fn write_config(tmp: &TempDir, backend: &str, local: &PathBuf) -> PathBuf {
let cfg_path = tmp.path().join("c.toml");
let body = format!(
"[active]\nbackend = \"{b}\"\nlocal_path = \"{p}\"\n\n[filesystem]\npath = \"{p}\"\n\n[s3]\ncache_path = \"{p}\"\n",
b = backend,
p = local.to_string_lossy()
);
fs::write(&cfg_path, body).unwrap();
cfg_path
}
fn run(args: &[&str]) -> std::process::Output {
std::process::Command::new(bin()).args(args).output().unwrap()
}
#[test]
fn init_writes_config() {
let tmp = TempDir::new().unwrap();
let cfg = tmp.path().join("store.toml");
let out = run(&[
"--config",
cfg.to_str().unwrap(),
"init",
"filesystem",
]);
assert!(out.status.success(), "{}", String::from_utf8_lossy(&out.stderr));
assert!(cfg.exists());
let text = fs::read_to_string(&cfg).unwrap();
assert!(text.contains("backend = \"filesystem\""));
}
#[test]
fn filesystem_read_write_roundtrip() {
let tmp = TempDir::new().unwrap();
let local = tmp.path().join("repo");
let cfg = write_config(&tmp, "filesystem", &local);
let file = tmp.path().join("input.bin");
fs::write(&file, b"hello world").unwrap();
let w = run(&[
"--config", cfg.to_str().unwrap(),
"write", "a/b.txt", file.to_str().unwrap(),
]);
assert!(w.status.success(), "{}", String::from_utf8_lossy(&w.stderr));
let r = run(&[
"--config", cfg.to_str().unwrap(),
"read", "a/b.txt",
]);
assert!(r.status.success());
assert_eq!(r.stdout, b"hello world");
}
#[test]
fn filesystem_list_shows_files() {
let tmp = TempDir::new().unwrap();
let local = tmp.path().join("repo");
let cfg = write_config(&tmp, "filesystem", &local);
let file = tmp.path().join("x");
fs::write(&file, b"x").unwrap();
run(&["--config", cfg.to_str().unwrap(), "write", "dir/a", file.to_str().unwrap()]);
run(&["--config", cfg.to_str().unwrap(), "write", "dir/b", file.to_str().unwrap()]);
let out = run(&["--config", cfg.to_str().unwrap(), "list", "dir"]);
assert!(out.status.success());
let s = String::from_utf8(out.stdout).unwrap();
assert!(s.contains("a"));
assert!(s.contains("b"));
}
#[test]
fn filesystem_commit_returns_hash() {
let tmp = TempDir::new().unwrap();
let local = tmp.path().join("repo");
let cfg = write_config(&tmp, "filesystem", &local);
let file = tmp.path().join("x");
fs::write(&file, b"x").unwrap();
run(&["--config", cfg.to_str().unwrap(), "write", "a.txt", file.to_str().unwrap()]);
let out = run(&["--config", cfg.to_str().unwrap(), "commit", "--message", "init"]);
assert!(out.status.success(), "{}", String::from_utf8_lossy(&out.stderr));
let hash = String::from_utf8(out.stdout).unwrap();
assert!(hash.trim().len() >= 7);
}
#[test]
fn filesystem_push_pull_are_noop() {
let tmp = TempDir::new().unwrap();
let local = tmp.path().join("repo");
let cfg = write_config(&tmp, "filesystem", &local);
let file = tmp.path().join("x");
fs::write(&file, b"x").unwrap();
run(&["--config", cfg.to_str().unwrap(), "write", "a.txt", file.to_str().unwrap()]);
run(&["--config", cfg.to_str().unwrap(), "commit", "--message", "init"]);
let p1 = run(&["--config", cfg.to_str().unwrap(), "push", "main"]);
let p2 = run(&["--config", cfg.to_str().unwrap(), "pull", "main"]);
assert!(p1.status.success());
assert!(p2.status.success());
}
#[test]
fn s3_stub_commit_writes_manifest() {
let tmp = TempDir::new().unwrap();
let local = tmp.path().join("cache");
let cfg = write_config(&tmp, "s3", &local);
let file = tmp.path().join("x");
fs::write(&file, b"x").unwrap();
run(&["--config", cfg.to_str().unwrap(), "write", "a.txt", file.to_str().unwrap()]);
let out = run(&["--config", cfg.to_str().unwrap(), "commit", "--message", "first"]);
assert!(out.status.success(), "{}", String::from_utf8_lossy(&out.stderr));
let entries: Vec<_> = fs::read_dir(&local)
.unwrap()
.filter_map(|e| e.ok())
.filter(|e| e.file_name().to_string_lossy().starts_with("manifest-"))
.collect();
assert_eq!(entries.len(), 1);
}
#[test]
fn status_reports_backend() {
let tmp = TempDir::new().unwrap();
let local = tmp.path().join("repo");
let cfg = write_config(&tmp, "filesystem", &local);
let out = run(&["--config", cfg.to_str().unwrap(), "status"]);
assert!(out.status.success());
let s = String::from_utf8(out.stdout).unwrap();
assert!(s.contains("filesystem"));
}
#[test]
fn unknown_backend_errors() {
let tmp = TempDir::new().unwrap();
let local = tmp.path().join("repo");
let cfg_path = tmp.path().join("c.toml");
let body = format!(
"[active]\nbackend = \"xyz\"\nlocal_path = \"{p}\"\n",
p = local.to_string_lossy()
);
fs::write(&cfg_path, body).unwrap();
let out = run(&["--config", cfg_path.to_str().unwrap(), "status"]);
assert!(!out.status.success());
let e = String::from_utf8_lossy(&out.stderr);
assert!(e.contains("unknown backend"), "{}", e);
}