Import AITURK IDE 1.0.0-beta.1 from Hermes 63279301; preserve MIT license
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
"""A transient read failure on auth.json must not degrade to an empty store.
|
||||
|
||||
``_load_auth_store`` treated every exception as corruption and returned
|
||||
``{"version": ..., "providers": {}}``. This module does read-modify-write in
|
||||
roughly fifteen places, so an ``OSError`` (EMFILE under fd exhaustion, EACCES,
|
||||
EIO, a stalled mount) followed by any ``_save_auth_store`` rewrote auth.json
|
||||
with an empty provider set and destroyed every stored credential.
|
||||
|
||||
Genuine corruption still degrades, still preserves a copy, and now only claims
|
||||
to have preserved one when the copy actually landed.
|
||||
"""
|
||||
|
||||
import errno
|
||||
import json
|
||||
import logging
|
||||
|
||||
import pytest
|
||||
|
||||
import hermes_cli.auth as auth
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def store_file(tmp_path):
|
||||
f = tmp_path / "auth.json"
|
||||
f.write_text(
|
||||
json.dumps({"version": 1, "providers": {"nous": {"api_key": "secret"}}}),
|
||||
encoding="utf-8",
|
||||
)
|
||||
return f
|
||||
|
||||
|
||||
def _fail_read(exc):
|
||||
def _read(self, *args, **kwargs):
|
||||
raise exc
|
||||
return _read
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
"exc",
|
||||
[
|
||||
OSError(errno.EMFILE, "Too many open files"),
|
||||
PermissionError(errno.EACCES, "Permission denied"),
|
||||
OSError(errno.EIO, "Input/output error"),
|
||||
],
|
||||
ids=["emfile", "eacces", "eio"],
|
||||
)
|
||||
def test_read_failure_raises_and_leaves_the_store_alone(store_file, monkeypatch, exc):
|
||||
from pathlib import Path
|
||||
|
||||
before = store_file.read_bytes()
|
||||
monkeypatch.setattr(Path, "read_text", _fail_read(exc))
|
||||
|
||||
with pytest.raises(OSError):
|
||||
auth._load_auth_store(store_file)
|
||||
|
||||
assert store_file.read_bytes() == before, "the store on disk was modified"
|
||||
assert not store_file.with_suffix(".json.corrupt").exists(), (
|
||||
"a read failure is not corruption and must not write a .corrupt sidecar"
|
||||
)
|
||||
|
||||
|
||||
def test_unparseable_json_still_degrades_and_preserves_a_copy(store_file):
|
||||
store_file.write_text("{ not json", encoding="utf-8")
|
||||
|
||||
result = auth._load_auth_store(store_file)
|
||||
|
||||
assert result == {"version": auth.AUTH_STORE_VERSION, "providers": {}}
|
||||
corrupt = store_file.with_suffix(".json.corrupt")
|
||||
assert corrupt.exists(), "genuine corruption must still be preserved"
|
||||
assert corrupt.read_text(encoding="utf-8") == "{ not json"
|
||||
|
||||
|
||||
def test_healthy_store_is_returned_unchanged(store_file):
|
||||
result = auth._load_auth_store(store_file)
|
||||
assert result["providers"]["nous"]["api_key"] == "secret"
|
||||
|
||||
|
||||
def test_log_does_not_claim_a_backup_that_was_not_written(
|
||||
store_file, monkeypatch, caplog
|
||||
):
|
||||
"""The old message advertised the .corrupt path even when copy2 failed."""
|
||||
import shutil
|
||||
|
||||
store_file.write_text("{ not json", encoding="utf-8")
|
||||
|
||||
def _no_copy(*args, **kwargs):
|
||||
raise OSError(errno.EMFILE, "Too many open files")
|
||||
|
||||
monkeypatch.setattr(shutil, "copy2", _no_copy)
|
||||
|
||||
with caplog.at_level(logging.WARNING, logger="hermes_cli.auth"):
|
||||
result = auth._load_auth_store(store_file)
|
||||
|
||||
assert result == {"version": auth.AUTH_STORE_VERSION, "providers": {}}
|
||||
assert not store_file.with_suffix(".json.corrupt").exists()
|
||||
text = caplog.text
|
||||
assert "could NOT be preserved" in text
|
||||
assert "Corrupt file preserved at" not in text
|
||||
Reference in New Issue
Block a user