Use isolated document extraction in shared indexing and desktop reconciliation

This commit is contained in:
karl committed 2026-10-13 15:17:42 +02:00
1 parent 844fdbf89f
commit ab31870260
8 files changed
+378 -23

No files matched your search

+72 -1
View File
@@ -57,6 +57,7 @@ fn compressed_document_limits_are_enforced() -> Result<()> {
);
docx(&root.path().join("over-limit.docx"), &xml)?;
let mut index = SearchIndex::open(":memory:")?;
index.use_in_process_document_parser_for_tests();
assert_eq!(index.index_folder(root.path())?.failures, 2);
assert_eq!(index.stats()?.content_files, 0);
assert!(index.search("bomb.pdf", 10)?[0].extraction_error.is_some());
@@ -90,6 +91,7 @@ fn encrypted_pdf_is_explicitly_unsupported() -> Result<()> {
document.encrypt(&state)?;
document.save(&path)?;
let mut index = SearchIndex::open(":memory:")?;
index.use_in_process_document_parser_for_tests();
assert_eq!(index.index_folder(root.path())?.failures, 1);
assert!(index.search("protected.pdf", 10)?[0]
.extraction_error
@@ -122,6 +124,72 @@ fn docx(path: &Path, xml: &str) -> Result<()> {
Ok(())
}
#[test]
fn missing_worker_preserves_filename_clears_passages_and_retries() -> Result<()> {
let root = tempfile::tempdir()?;
pdf(&root.path().join("agreement.pdf"))?;
let mut index = SearchIndex::open(":memory:")?;
index.use_in_process_document_parser_for_tests();
index.index_folder(root.path())?;
assert!(!index.search("cancellation", 10)?.is_empty());
index.set_document_worker(root.path().join("missing-helper.exe"));
// Force a changed snapshot so a previous successful extraction is replaced.
pdf_with_text(
&root.path().join("agreement.pdf"),
&["different cancellation"],
)?;
assert_eq!(index.index_folder(root.path())?.failures, 1);
assert!(index.search("cancellation", 10)?.is_empty());
assert!(index.search("agreement.pdf", 10)?[0]
.extraction_error
.is_some());
// A same-stat, same-byte failed source must not be skipped on retry.
index.use_in_process_document_parser_for_tests();
assert_eq!(index.index_folder(root.path())?.indexed, 1);
assert!(!index.search("cancellation", 10)?.is_empty());
Ok(())
}
#[test]
#[ignore = "requires built helper in SEARCHI_EXTRACT_WORKER"]
fn normal_adapter_uses_real_document_worker_and_cancellation_rolls_back() -> Result<()> {
anyhow::ensure!(
std::env::var_os("SEARCHI_EXTRACT_WORKER").is_some(),
"Set actual document helper path"
);
let root = tempfile::tempdir()?;
pdf(&root.path().join("agreement.pdf"))?;
let mut index = SearchIndex::open(":memory:")?;
assert_eq!(index.index_folder(root.path())?.failures, 0);
assert_eq!(
index.search("cancellation", 10)?[0]
.source
.as_ref()
.unwrap()
.number,
2
);
let before = index.stats()?.files;
let cancelled = std::sync::atomic::AtomicBool::new(true);
assert!(index
.index_folder_cancellable(
root.path(),
&searchi_core::IndexOptions::default(),
&cancelled
)
.is_err());
assert_eq!(index.stats()?.files, before);
assert_eq!(
index.search("cancellation", 10)?[0]
.source
.as_ref()
.unwrap()
.number,
2
);
Ok(())
}
#[test]
fn real_pdf_and_docx_return_matching_locations_and_persist() -> Result<()> {
let root = tempfile::tempdir()?;
@@ -132,6 +200,7 @@ fn real_pdf_and_docx_return_matching_locations_and_persist() -> Result<()> {
)?;
let db = root.path().join("index.db");
let mut index = SearchIndex::open(&db)?;
index.use_in_process_document_parser_for_tests();
assert_eq!(index.index_folder(root.path())?.indexed, 2);
let result = index.search("cancellation", 10)?;
assert_eq!(result[0].source.as_ref().unwrap().kind, "page");
@@ -180,6 +249,7 @@ fn corrupt_document_reports_failure_and_preserves_filename_search() -> Result<()
let root = tempfile::tempdir()?;
fs::write(root.path().join("notes.txt"), "persistent evidence")?;
let mut index = SearchIndex::open(":memory:")?;
index.use_in_process_document_parser_for_tests();
index.index_folder(root.path())?;
fs::write(root.path().join("broken.pdf"), b"not a PDF")?;
assert_eq!(index.index_folder(root.path())?.failures, 1);
@@ -199,7 +269,8 @@ fn corrupt_document_reports_failure_and_preserves_filename_search() -> Result<()
index.index_folder(root.path())?;
assert_eq!(index.search("cancellation", 10)?.len(), 1);
fs::write(root.path().join("agreement.pdf"), "corrupted replacement")?;
assert_eq!(index.index_folder(root.path())?.failures, 1);
// Previously rejected DOCX is retried too; failures are per current scan.
assert_eq!(index.index_folder(root.path())?.failures, 2);
assert!(index.search("cancellation", 10)?.is_empty());
assert!(index.search("agreement.pdf", 10)?[0]
.extraction_error