use super::execute::{root_with_source, NEW_DIM, SEEDED};
use super::switchover::journal_phase;
use super::*;
use crate::embedder::HashEmbedder;
fn migrate(root: &std::path::Path) -> Result<super::super::MigrateOutcome, crate::MemoryError> {
let embedder = HashEmbedder::new(NEW_DIM);
super::super::migrate(
&root.join("store"),
root,
&TargetContract::automatic("hash", NEW_DIM),
&root.join("rebuilt"),
&embedder,
1024,
)
}
#[test]
fn a_fresh_migrate_runs_the_whole_chain_to_committed() {
let root = root_with_source();
let outcome = migrate(root.path()).expect("migrate");
let executed = outcome.executed.expect("a fresh run rebuilds, and says so");
assert_eq!(executed.rebuild.facts, SEEDED);
let validated = outcome
.validated
.expect("a fresh run validates, and says so");
assert_eq!(validated.facts, SEEDED);
let store = root.path().join("store");
assert_eq!(
outcome.switched.activated,
store.canonicalize().expect("exists"),
"the chain must end with the rebuilt store live at the source's path"
);
let journalled = MigrationState::read(&executed.workspace)
.expect("read journal")
.expect("journal exists");
assert_eq!(journalled.phase, Phase::Committed);
}
#[test]
fn migrate_resumes_past_a_crash_at_source_archived() {
let root = root_with_source();
let executed = super::execute::run(root.path()).expect("execute");
super::super::validate_destination(
&root.path().join("store"),
&executed.destination,
&TargetContract::automatic("hash", NEW_DIM),
1024,
)
.expect("validate");
let store = root.path().join("store");
std::fs::rename(&store, root.path().join("store.archive")).expect("crashed first rename");
journal_phase(&executed.workspace, Phase::SourceArchived);
let outcome = migrate(root.path()).expect("the re-run must resume at the switch");
assert!(
outcome.executed.is_none() && outcome.validated.is_none(),
"a resume past validation must not re-run the earlier stages — with \
the source vacant it could not, and pretending it did would misreport"
);
assert_eq!(
outcome.switched.activated,
store.canonicalize().expect("exists"),
"the switch must have completed from where the journal stood"
);
assert_eq!(
MigrationState::read(&executed.workspace)
.expect("read journal")
.expect("journal exists")
.phase,
Phase::Committed
);
}
struct PanickingEmbedder(usize);
impl crate::Embedder for PanickingEmbedder {
fn dimension(&self) -> usize {
self.0
}
fn embed(&self, _text: &str) -> Result<Vec<f32>, crate::EmbedError> {
panic!("reuse must never call the embedder — this call IS the regression");
}
}
#[test]
fn reuse_migrates_end_to_end_without_ever_calling_the_embedder() {
let root = root_with_source();
let store = root.path().join("store");
crate::embedding_provenance::write(
&store,
&crate::embedding_provenance::EmbeddingProvenance::new("hash", DIM),
)
.expect("record provenance matching the target");
let embedder = PanickingEmbedder(DIM);
let outcome = super::super::migrate(
&store,
root.path(),
&TargetContract::automatic("hash", DIM),
&root.path().join("rebuilt"),
&embedder,
1024,
)
.expect("a provenance-matched store migrates under reuse");
let executed = outcome.executed.expect("a fresh run rebuilds");
assert!(
matches!(executed.report.resolution, Resolution::Reuse),
"positive control: the regime must actually have been reuse, or the \
panicking embedder proved nothing — got {:?}",
executed.report.resolution
);
let db = velesdb_core::Database::open(&store).expect("activated store opens");
let facts = super::super::enumerate_by_cursor(&db, "_semantic_memory", 1024).expect("walk");
assert_eq!(
facts.len() as u64,
SEEDED,
"every fact crossed, no embedder involved"
);
}