aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorValentin Popov <valentin@popov.link>2026-06-30 01:43:25 +0300
committerValentin Popov <valentin@popov.link>2026-06-30 01:43:25 +0300
commit0a7ba55b441f3b36a294b18e96b2887d6fd47b45 (patch)
tree4f21b7b0672c4b560dde4b2abf7f63e1227e8c55
parent29f7a398ffbc66520127122b0bdb2edae7f327fb (diff)
downloadfparkan-0a7ba55b441f3b36a294b18e96b2887d6fd47b45.tar.xz
fparkan-0a7ba55b441f3b36a294b18e96b2887d6fd47b45.zip
test(resource): cover archive byte-budget eviction
-rw-r--r--crates/fparkan-resource/src/lib.rs52
-rw-r--r--fixtures/acceptance/coverage.tsv2
2 files changed, 53 insertions, 1 deletions
diff --git a/crates/fparkan-resource/src/lib.rs b/crates/fparkan-resource/src/lib.rs
index 666245f..e60b3ba 100644
--- a/crates/fparkan-resource/src/lib.rs
+++ b/crates/fparkan-resource/src/lib.rs
@@ -1477,6 +1477,58 @@ mod tests {
}
#[test]
+ fn archive_cache_evicts_by_byte_budget() {
+ let first_path = archive_path(b"cache/first-bytes.lib").expect("first path");
+ let second_path = archive_path(b"cache/second-bytes.lib").expect("second path");
+ let first_bytes = build_nres(&[("a.bin", b"first".as_slice())]);
+ let second_bytes = build_nres(&[("b.bin", b"second".as_slice())]);
+ let second_budget = second_bytes.len();
+ let mut vfs = MemoryVfs::default();
+ vfs.insert(
+ first_path.clone(),
+ Arc::from(first_bytes.into_boxed_slice()),
+ );
+ vfs.insert(
+ second_path.clone(),
+ Arc::from(second_bytes.into_boxed_slice()),
+ );
+ let repo = CachedResourceRepository::with_limits(
+ Arc::new(vfs),
+ RepositoryLimits {
+ max_open_archives: 2,
+ max_archive_bytes: second_budget,
+ max_decoded_payload_entries: 64,
+ max_decoded_payload_bytes: 64 * 1024 * 1024,
+ },
+ );
+
+ let first_archive = repo.open_archive(&first_path).expect("open first");
+ let first_handle = repo
+ .find(first_archive, &resource_name(b"a.bin"))
+ .expect("find first")
+ .expect("first handle");
+ assert_eq!(
+ repo.read(first_handle).expect("read first").as_slice(),
+ b"first"
+ );
+
+ let second_archive = repo.open_archive(&second_path).expect("open second");
+ let second_handle = repo
+ .find(second_archive, &resource_name(b"b.bin"))
+ .expect("find second")
+ .expect("second handle");
+ assert_eq!(
+ repo.read(second_handle).expect("read second").as_slice(),
+ b"second"
+ );
+
+ assert!(matches!(
+ repo.read(first_handle),
+ Err(ResourceError::StaleHandle)
+ ));
+ }
+
+ #[test]
fn resource_error_display_is_actionable() {
let path = archive_path(b"bad/rsli.lib").expect("path");
let err = ResourceError::EntryRead {
diff --git a/fixtures/acceptance/coverage.tsv b/fixtures/acceptance/coverage.tsv
index 991e174..2917c62 100644
--- a/fixtures/acceptance/coverage.tsv
+++ b/fixtures/acceptance/coverage.tsv
@@ -151,7 +151,7 @@ S1-RES-001 covered cargo test -p fparkan-resource --offline cached_repository_re
S1-RES-002 covered cargo test -p fparkan-resource --offline entry_handles_are_archive_qualified
S1-RES-003 covered cargo test -p fparkan-resource --offline archive_cache_and_decoded_payload_cache_evict_independently
S1-RES-004 covered cargo test -p fparkan-resource --offline entry_read_error_carries_archive_path_and_entry_name
-S1-RES-005 partial cargo test -p fparkan-resource --offline archive_cache_and_decoded_payload_cache_evict_independently; explicit max_archive_bytes eviction test is still missing
+S1-RES-005 covered cargo test -p fparkan-resource --offline archive_cache_evicts_by_byte_budget
S1-RES-006 covered cargo test -p fparkan-resource --offline archive_cache_eviction_makes_old_handles_stale
S1-RES-007 covered cargo test -p fparkan-resource --offline lossy_equivalent_archive_paths_remain_distinct
S1-DIAG-001 partial cargo test -p fparkan-inspection --offline archive_diagnostic_preserves_source_path; entry/span coverage is still missing