test(channels): drop the POSIX-only utime flag that breaks 9 tests on Windows (#7750)

* test(channels): drop the POSIX-only utime flag that breaks 9 tests on Windows

os.utime(..., follow_symlinks=False) is not implemented on Windows, so every test in
tests/test_channel_credential_staging.py that ages a staging file dies in _age before
it exercises anything (NotImplementedError). CI runs backend unit tests on ubuntu only,
so this never surfaced. Every file aged here is a regular file, and the other 15+
os.utime call sites in the suite already omit the flag.

Verified on Windows 11 / Python 3.12: 9 failed, 2 passed before; 11 passed after.

* test(channels): keep the symlink aging the flag was there for

Review follow-up on #7750. Dropping follow_symlinks=False kept Windows green but
quietly lost POSIX coverage: _age(link) in the os.name != "nt" block used to stamp the
symlink's own mtime two days into the past, and without the flag os.utime follows the
link and ages backup.tmp instead. cleanup_stale_credential_staging keeps that symlink
alive through its entry.stat(follow_symlinks=False) + S_ISREG type guard, and with a
fresh mtime the age guard alone would retain it too, so the test no longer proved that
an old staging-pattern symlink is spared by the type check.

Pass the flag through instead of hard-coding it: _age(path, *, follow_symlinks=True)
forwards it, and only the POSIX-only symlink call site asks for follow_symlinks=False.
Windows never passes it, so os.utime still cannot raise NotImplementedError there.

Also corrects the comment: _age also ages a directory, so "every file aged here is a
regular file" overstated the case. os.utime on a directory works on Windows; the flag
only matters for the symlink below.

Verified on Windows 11 / Python 3.12: 11 passed.

Addresses review feedback on #7750.

---------

Co-authored-by: luoyi0000 <luoyi0000@users.noreply.github.com>
This commit is contained in:
onhm 2026-11-01 23:25:44 +08:00 committed by GitHub
parent 980cf3a448
commit 51f732304a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -16,9 +16,12 @@ from app.channels.runtime_config_store import ChannelRuntimeConfigStore, SqlChan
from app.channels.wechat import WechatChannel
def _age(path: Path) -> None:
def _age(path: Path, *, follow_symlinks: bool = True) -> None:
old = time.time() - 2 * 24 * 60 * 60
os.utime(path, (old, old), follow_symlinks=False)
# The flag is only meaningful for the symlink aged in the POSIX-only block below,
# where the mtime must land on the link itself rather than on its target. os.utime
# raises NotImplementedError for it on Windows, so callers there never pass it.
os.utime(path, (old, old), follow_symlinks=follow_symlinks)
def _load(kind: str, target: Path):
@ -95,7 +98,7 @@ def test_restart_sweeps_crash_orphans_without_touching_other_state(tmp_path, mon
if os.name != "nt":
link = tmp_path / f".{target.name}.deerflow-symlink.tmp"
link.symlink_to(retained[0])
_age(link)
_age(link, follow_symlinks=False)
retained.append(link)
if not destination_exists:
target.unlink()