fix(session): bound continuation fallback sidecar reads
This commit is contained in:
1 parent
031856b3b5
commit
dd67f342d7
2 files changed
+91
-3
No files matched your search
+11
-3
@@ -540,6 +540,16 @@ def _find_top_level_json_key(text, key):
|
||||
return None
|
||||
|
||||
|
||||
def _read_file_head(path: Path, max_prefix_bytes: int = 4096) -> str:
|
||||
"""Read at most ``max_prefix_bytes`` bytes from ``path`` and decode UTF-8."""
|
||||
if not isinstance(path, Path):
|
||||
path = Path(path)
|
||||
if max_prefix_bytes <= 0:
|
||||
return ''
|
||||
with path.open('rb') as fp:
|
||||
return fp.read(max_prefix_bytes).decode('utf-8', errors='ignore')
|
||||
|
||||
|
||||
def _read_metadata_json_prefix(path, max_prefix_bytes=65536):
|
||||
"""Read only the metadata portion before the top-level messages array."""
|
||||
buf = ''
|
||||
@@ -2129,9 +2139,7 @@ def _has_compression_continuation(session) -> bool:
|
||||
if path.name.startswith('_') or path.stem == sid:
|
||||
continue
|
||||
try:
|
||||
head = path.read_text(encoding='utf-8', errors='ignore')[:4096]
|
||||
except TypeError:
|
||||
head = path.read_text(encoding='utf-8')[:4096]
|
||||
head = _read_file_head(path, max_prefix_bytes=4096)
|
||||
except OSError:
|
||||
continue
|
||||
if needle in head:
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
import api.models as models
|
||||
|
||||
|
||||
def test_compression_continuation_fallback_reads_only_file_head(monkeypatch, tmp_path):
|
||||
session_dir = tmp_path / "sessions"
|
||||
session_dir.mkdir()
|
||||
index_file = tmp_path / "_index.json"
|
||||
index_file.write_text("[]", encoding="utf-8")
|
||||
|
||||
monkeypatch.setattr(models, "SESSION_DIR", session_dir)
|
||||
monkeypatch.setattr(models, "SESSION_INDEX_FILE", index_file)
|
||||
models.SESSIONS.clear()
|
||||
|
||||
parent_sid = "parent"
|
||||
candidate = session_dir / "child.json"
|
||||
candidate.write_text("x" * 8192 + f'"parent_session_id": "{parent_sid}"', encoding="utf-8")
|
||||
|
||||
opened_for_read = []
|
||||
read_text_calls = []
|
||||
|
||||
original_path_open = models.Path.open
|
||||
original_path_read_text = models.Path.read_text
|
||||
|
||||
class _TrackingHandle:
|
||||
def __init__(self, path, inner):
|
||||
self._path = str(path)
|
||||
self._inner = inner
|
||||
|
||||
def read(self, size=-1):
|
||||
opened_for_read.append((self._path, size))
|
||||
return self._inner.read(size)
|
||||
|
||||
def __enter__(self):
|
||||
return self
|
||||
|
||||
def __exit__(self, exc_type, exc, tb):
|
||||
return self._inner.__exit__(exc_type, exc, tb)
|
||||
|
||||
def __getattr__(self, name):
|
||||
return getattr(self._inner, name)
|
||||
|
||||
def tracking_open(path, *args, **kwargs):
|
||||
return _TrackingHandle(path, original_path_open(path, *args, **kwargs))
|
||||
|
||||
def tracking_read_text(self, *args, **kwargs):
|
||||
read_text_calls.append(str(self))
|
||||
return original_path_read_text(self, *args, **kwargs)
|
||||
|
||||
monkeypatch.setattr(models.Path, "open", tracking_open)
|
||||
monkeypatch.setattr(models.Path, "read_text", tracking_read_text)
|
||||
|
||||
session = models.Session(session_id=parent_sid)
|
||||
|
||||
assert models._has_compression_continuation(session) is False
|
||||
|
||||
assert str(index_file) in read_text_calls
|
||||
assert all(path != str(candidate) for path in read_text_calls)
|
||||
|
||||
candidate_reads = [size for path, size in opened_for_read if path == str(candidate)]
|
||||
assert candidate_reads, "fallback should read the candidate sidecar"
|
||||
assert all(size != -1 and size <= 4096 for size in candidate_reads)
|
||||
|
||||
|
||||
def test_compression_continuation_prefix_match_stays_true(monkeypatch, tmp_path):
|
||||
session_dir = tmp_path / "sessions"
|
||||
session_dir.mkdir()
|
||||
index_file = tmp_path / "_index.json"
|
||||
index_file.write_text("[]", encoding="utf-8")
|
||||
|
||||
monkeypatch.setattr(models, "SESSION_DIR", session_dir)
|
||||
monkeypatch.setattr(models, "SESSION_INDEX_FILE", index_file)
|
||||
models.SESSIONS.clear()
|
||||
|
||||
parent_sid = "parent"
|
||||
candidate = session_dir / "child.json"
|
||||
candidate.write_text('{"session_id":"child", "parent_session_id": "parent",', encoding="utf-8")
|
||||
|
||||
session = models.Session(session_id=parent_sid)
|
||||
|
||||
assert models._has_compression_continuation(session) is True
|
||||
Reference in new issue
Block a user