- 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.
150 lines
5.2 KiB
Rust
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);
|
|
}
|