Files
wehub-resource-sync 4b6817381b
CI (OpenClaw E2E) / openclaw test (push) Has been cancelled
CI / coverage-report (push) Has been cancelled
CI / test-kubernetes (push) Has been cancelled
CI / should-run-thorough (push) Has been cancelled
CI / test-thorough (cloudwatch-demo) (push) Has been cancelled
CI / test-thorough (flink-ecs) (push) Has been cancelled
CI / test-thorough (upstream-lambda) (push) Has been cancelled
CI / test-thorough (prefect-ecs-fargate) (push) Has been cancelled
Release / build-binaries (zip, opensre.exe, onefile, windows-latest, windows-x64) (push) Has been cancelled
Benchmark image — build + push to ECR (any adapter) / build + push (push) Has been cancelled
CI / quality (ubuntu-latest) (push) Has been cancelled
CI / test (tools-runtime) (push) Has been cancelled
CI / test (e2e-general) (push) Has been cancelled
CI / test (cli-runtime) (push) Has been cancelled
CI / test (e2e-provider-and-openclaw) (push) Has been cancelled
CI / test (integrations-and-misc) (push) Has been cancelled
Release / verify (push) Has been cancelled
Release / build-python-dist (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-15-intel, darwin-x64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, macos-latest, darwin-arm64) (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04, linux-x64) (push) Has been cancelled
Release / publish-release (push) Has been cancelled
Release / publish-main-release (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-checks (no-LLM) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
Interactive Shell Live (PR + post-merge) / turn-live shard ${{ matrix.shard_index }} (push) Has been cancelled
Release / prepare (push) Has been cancelled
Release / build-binaries (tar.gz, opensre, onedir, ubuntu-22.04-arm, linux-arm64) (push) Has been cancelled
Synthetic Deterministic Tests / Synthetic offline (deterministic) (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:10:45 +08:00

73 lines
2.8 KiB
Python

"""Tests for :class:`IncrementalJsonlSource` rotation detection (#2023)."""
from __future__ import annotations
from pathlib import Path
from tools.system.fleet_monitoring.token_sources import IncrementalJsonlSource, _PerPidState
def test_detect_rotation_returns_none_on_transient_stat_error(tmp_path: Path) -> None:
"""A transient stat failure must leave the cached state intact.
Regression: an earlier version reset ``offset`` to ``0`` whenever
stat raised, so the next time the file reappeared on the same
inode the source would re-read every historical byte from 0 and
inflate the 60 s token window. The fix returns ``None`` so the
caller keeps the cached offset and only re-cold-starts on
positive rotation evidence (inode change, size regression, or
mtime regression).
"""
missing = tmp_path / "vanished.jsonl" # never created → stat raises
cached = _PerPidState(log_path=missing, inode=42, mtime=1.0, offset=100)
assert IncrementalJsonlSource._detect_rotation(cached) is None
def test_detect_rotation_returns_new_state_on_inode_change(tmp_path: Path) -> None:
"""Same-path delete+recreate must still trigger a cold-start.
The OSError fix above must not regress the inode-change branch:
that one is positive evidence of rotation, and the new state
should seek to the new file's EOF.
"""
session = tmp_path / "session.jsonl"
session.write_text("first\n", encoding="utf-8")
fake_inode = session.stat().st_ino - 1 # any value different from the real one
cached = _PerPidState(
log_path=session,
inode=fake_inode,
mtime=session.stat().st_mtime,
offset=0,
)
rotated = IncrementalJsonlSource._detect_rotation(cached)
assert rotated is not None
# ``offset`` set to the real file size = "seek to EOF" so we
# never retro-price the content already on disk.
assert rotated.offset == session.stat().st_size
assert rotated.inode == session.stat().st_ino
def test_detect_rotation_returns_new_state_on_size_regression(tmp_path: Path) -> None:
"""Inode-reused truncate-and-rewrite must also trigger a cold-start.
ext4 and APFS happily reuse a freshly-freed inode within the
same second; without the size-regression signal the inode-change
branch would miss it. The cached offset is past the new EOF,
which would otherwise yield negative deltas.
"""
session = tmp_path / "session.jsonl"
session.write_text("hi\n", encoding="utf-8")
stat = session.stat()
cached = _PerPidState(
log_path=session,
inode=stat.st_ino,
mtime=stat.st_mtime,
offset=stat.st_size + 1000, # cached offset > current size
)
rotated = IncrementalJsonlSource._detect_rotation(cached)
assert rotated is not None
assert rotated.offset == stat.st_size