test(simulation): isolate voice::lookup cache dirs — fix flaky cache_miss (T-1035)

The four voice::lookup tests shared one on-disk cache directory (base_dir
temp/sr-voice-lookup-test + world_seed 99). VoiceCacheStore persists on Drop
(save_all) and reloads on first zone access (load_zone), and cache_hit stores
'Voiced line.' under the identical (zone_id=100, CacheKey) that cache_miss looks
up — so under parallel execution the hit test's Drop/save could leak into the
miss test's lookup, returning 'Voiced line.' instead of 'Base line.'.

Give each test a directory keyed by test label + process id, so neither parallel
tests nor concurrent cargo test runs collide. Verified clean across repeated runs.

Closes T-1035.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-06-09 08:18:58 +02:00
co-authored by Claude Opus 4.8
parent 4984d59bf4
commit 7776d99c14
3 changed files with 21 additions and 6 deletions
+18 -6
View File
@@ -72,8 +72,20 @@ pub fn voiced_behavior(
mod tests {
use super::*;
fn test_cache() -> Arc<Mutex<VoiceCacheStore>> {
let dir = std::env::temp_dir().join("sr-voice-lookup-test");
/// Build a store with a directory unique to this test (T-1035).
///
/// `VoiceCacheStore` persists to disk on `Drop` (`save_all`) and reads it back
/// on first zone access (`load_zone`). A shared directory therefore lets one
/// test's stored entry leak into another's lookup under parallel execution —
/// the `cache_hit`/`cache_miss` pair use an identical `(zone_id, CacheKey)`,
/// which is exactly how this module flaked. Isolating by test label + process
/// id keeps both parallel tests and concurrent `cargo test` runs from colliding.
fn test_cache(label: &str) -> Arc<Mutex<VoiceCacheStore>> {
let dir = std::env::temp_dir().join(format!(
"sr-voice-lookup-test/{}-{}",
std::process::id(),
label
));
let _ = std::fs::remove_dir_all(&dir);
Arc::new(Mutex::new(VoiceCacheStore::new(
dir,
@@ -85,7 +97,7 @@ mod tests {
#[test]
fn cache_hit_returns_voiced_text() {
let cache = test_cache();
let cache = test_cache("cache-hit");
let key = CacheKey {
culture_id: "van-maanens-star".into(),
npc_stable_id: 42,
@@ -111,7 +123,7 @@ mod tests {
#[test]
fn cache_miss_returns_base_text() {
let cache = test_cache();
let cache = test_cache("cache-miss");
let result = voiced_behavior(
&cache,
100,
@@ -128,7 +140,7 @@ mod tests {
#[test]
fn factual_content_always_passthrough() {
let cache = test_cache();
let cache = test_cache("factual");
// Store a voiced version under the Factual key — it must never be returned.
let key = CacheKey {
culture_id: "van-maanens-star".into(),
@@ -158,7 +170,7 @@ mod tests {
#[test]
fn tell_behavior_always_passthrough() {
let cache = test_cache();
let cache = test_cache("tell");
// Even if cache has a voiced version, tell behaviors return base text
let key = CacheKey {
culture_id: "van-maanens-star".into(),