Skip to content

Commit 5b482ea

Browse files
committed
test(examples): cover writeback temp cleanup
1 parent 623b521 commit 5b482ea

1 file changed

Lines changed: 51 additions & 0 deletions

File tree

examples/optimization/eval_optimize_loop/tests/test_writeback.py

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,57 @@ def fail_once_for_candidate_system(path: Path):
158158
assert {name: path.read_bytes() for name, path in paths.items()} == baseline
159159

160160

161+
def test_commit_removes_temp_file_when_replace_fails(tmp_path: Path, monkeypatch):
162+
target = tmp_path / "system.txt"
163+
baseline = b"system baseline"
164+
target.write_bytes(baseline)
165+
snapshot = snapshot_prompt_files({"system": target})
166+
original_replace = os.replace
167+
replace_calls = 0
168+
169+
def fail_first_replace(source: str | bytes | Path, destination: str | bytes | Path):
170+
nonlocal replace_calls
171+
replace_calls += 1
172+
if replace_calls == 1:
173+
raise OSError("candidate replace failed")
174+
return original_replace(source, destination)
175+
176+
monkeypatch.setattr(writeback.os, "replace", fail_first_replace)
177+
178+
result = commit_prompt_bundle(snapshot, {"system": "candidate system"})
179+
180+
assert result.status == "rolled_back"
181+
assert target.read_bytes() == baseline
182+
assert list(tmp_path.glob(f".{target.name}.*.tmp")) == []
183+
184+
185+
def test_atomic_replace_preserves_replace_error_when_temp_unlink_fails(tmp_path: Path, monkeypatch):
186+
target = tmp_path / "system.txt"
187+
baseline = b"system baseline"
188+
target.write_bytes(baseline)
189+
original_unlink = Path.unlink
190+
191+
def fail_replace(source: str | bytes | Path, destination: str | bytes | Path):
192+
raise OSError("primary replace failed")
193+
194+
def fail_temp_unlink(path: Path, missing_ok: bool = False):
195+
if path.parent == tmp_path and path.name.startswith(f".{target.name}.") and path.suffix == ".tmp":
196+
raise OSError("temp unlink failed")
197+
return original_unlink(path, missing_ok=missing_ok)
198+
199+
with monkeypatch.context() as injected_failure:
200+
injected_failure.setattr(writeback.os, "replace", fail_replace)
201+
injected_failure.setattr(Path, "unlink", fail_temp_unlink)
202+
with pytest.raises(OSError) as error_info:
203+
writeback._atomic_replace_bytes(target, b"candidate system")
204+
205+
for temp_path in tmp_path.glob(f".{target.name}.*.tmp"):
206+
original_unlink(temp_path)
207+
208+
assert str(error_info.value) == "primary replace failed"
209+
assert target.read_bytes() == baseline
210+
211+
161212
def test_commit_rolls_back_all_files_when_second_replace_fails(tmp_path: Path, monkeypatch):
162213
paths, baseline = _prompt_files(tmp_path)
163214
snapshot = snapshot_prompt_files(paths)

0 commit comments

Comments
 (0)