fix(cleanup): invalidate sandbox_dirs_cache after purge (#7527) #11040
@@ -0,0 +1,17 @@
|
||||
@unit @cleanup
|
||||
Feature: Sandbox dirs cache invalidation after purge
|
||||
|
||||
This test verifies the fix for issue #7527: _purge_sandboxes() must
|
||||
invalidate the sandbox_dirs_cache so subsequent scan() calls re-read
|
||||
the filesystem. Without this fix, a stale cached list of directories
|
||||
persisted even after those directories were deleted by shutil.rmtree().
|
||||
|
||||
Scenario: Cache is invalidated after purge completes removals
|
||||
|
|
||||
Given cleanup coverage has a CleanupService with default settings
|
||||
When cleanup coverage purges sandboxes and cache is cleared for tracking
|
||||
Then cleanup coverage _sandbox_dirs_cache should be None after purge
|
||||
|
||||
Scenario: Purge with no stale dirs still invalidates cache
|
||||
Given cleanup coverage has a CleanupService with default settings
|
||||
When cleanup coverage purges sandboxes with an empty cache
|
||||
Then cleanup coverage _sandbox_dirs_cache should be None after purge
|
||||
@@ -425,3 +425,79 @@ def step_cleanup_cov_age_desc(context: Context, expected: str) -> None:
|
||||
assert context.cleanup_age_desc == expected, (
|
||||
f"Expected {expected!r}, got {context.cleanup_age_desc!r}"
|
||||
)
|
||||
|
||||
|
||||
# ── sandbox_cache_invalidation steps ────────────────────────────────
|
||||
|
||||
|
||||
@when("cleanup coverage purges sandboxes and cache is cleared for tracking")
|
||||
def step_cleanup_cov_purge_sandboxes_cache_tracking(context: Context) -> None:
|
||||
"""Set up real sandbox dirs, preload cache, purge, then verify cache invalidation."""
|
||||
svc = context.cleanup_service
|
||||
report = CleanupReport(dry_run=False)
|
||||
|
||||
# Create temporary stub directories that look like sandbox dirs
|
||||
tmp_dir = tempfile.mkdtemp()
|
||||
sandbox_names = [f"ca-sandbox-plan{i}-stub{i}" for i in range(2)]
|
||||
sandbox_paths = []
|
||||
for name in sandbox_names:
|
||||
p = Path(tmp_dir) / name
|
||||
p.mkdir()
|
||||
# Mark as stale (old mtime)
|
||||
old_time = time.time() - 43200 * 180 # ~6 months ago
|
||||
os.utime(p, (old_time, old_time))
|
||||
sandbox_paths.append(p)
|
||||
|
||||
context.cleanup_stale_dir_paths = sandbox_paths
|
||||
|
||||
# Pre-populate cache with real Path objects
|
||||
cached_dirs = [Path(tmp_dir) / name for name in sandbox_names]
|
||||
svc._sandbox_dirs_cache = cached_dirs
|
||||
|
||||
# Temporarily replace gettempdir to point at tmp_dir so _purge_sandboxes
|
||||
# will find our dirs
|
||||
original_gettempdir = tempfile.gettempdir
|
||||
try:
|
||||
tempfile.gettempdir = lambda: tmp_dir
|
||||
svc._purge_sandboxes(report)
|
||||
finally:
|
||||
tempfile.gettempdir = original_gettempdir
|
||||
|
||||
context.cleanup_report = report
|
||||
|
||||
|
||||
@when("cleanup coverage purges sandboxes with an empty cache")
|
||||
def step_cleanup_cov_purge_empty_cache(context: Context) -> None:
|
||||
"""Purge when _get_sandbox_dirs returns nothing — cache still invalidated."""
|
||||
svc = context.cleanup_service
|
||||
report = CleanupReport(dry_run=False)
|
||||
|
||||
# Set cache to empty list to force fresh scan path
|
||||
svc._sandbox_dirs_cache = []
|
||||
|
||||
def fake_gettempdir():
|
||||
return "/nonexistent_tmp_xyz_empty"
|
||||
|
||||
original_gettempdir = tempfile.gettempdir
|
||||
try:
|
||||
tempfile.gettempdir = fake_gettempdir
|
||||
# Patch Path.exists to return False so we hit the early-return path but
|
||||
# still want to verify cache is set to None
|
||||
with patch("cleveragents.application.services.cleanup_service.tempfile"):
|
||||
# tempfile module was already imported in cleanup_service.py,
|
||||
# but we patched gettempdir directly above
|
||||
|
||||
svc._purge_sandboxes(report)
|
||||
finally:
|
||||
tempfile.gettempdir = original_gettempdir
|
||||
|
||||
context.cleanup_report = report
|
||||
|
||||
|
||||
@then("cleanup coverage _sandbox_dirs_cache should be None after purge")
|
||||
def step_cleanup_cov_cache_is_none(context: Context) -> None:
|
||||
"""Verify the cache was invalidated (set to None) by _purge_sandboxes."""
|
||||
assert context.cleanup_service._sandbox_dirs_cache is None, (
|
||||
"Expected _sandbox_dirs_cache to be None after purge, "
|
||||
f"but got {context.cleanup_service._sandbox_dirs_cache!r}"
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user
BLOCKING — Missing
@tdd_issue_7527regression tagPer CONTRIBUTING.md, bug fix regression tests must carry a
@tdd_issue_Ntag. This marks the scenario as a permanent regression guard and ensures the CI test suite permanently tracks the fix.The issue body itself states: "After this bug issue is verified, a corresponding Type/Testing issue will be created for TDD with @tdd_expected_fail tags."
Fix: Add
@tdd_issue_7527tag to the primary regression scenario ("Cache is invalidated after purge completes removals").Example:
Automated by CleverAgents Bot
Supervisor: PR Review | Agent: pr-review-worker