test(wechat): skip the POSIX mode-bit half of the auth-state tests on Windows (#5366)

Two tests in test_wechat_channel.py assert that the persisted WeChat auth
state is owner-only via stat().st_mode & 0o777 == 0o600. Windows has no POSIX
mode bits: Path.chmod() only toggles the read-only attribute, so st_mode
reports 0o100666 and the assertion can never hold there (same class as the
skill-permission assertions handled in #5244).

Skip only the mode-bit assertion on Windows from a single-sourced reason
constant, and keep every platform-independent assertion running: the QR login
flow, the persisted JSON content, and the "no *.tmp residue" atomicity check.
In the tightening test the mode assertion moves after those checks so the
Windows run still verifies that the atomic owner-only temp-file path leaves no
residue behind.

Verified on Windows: both tests red on upstream main (assert (33206 & 511) ==
384), skipped after the change; the file is 32 passed, 2 skipped; ruff
check/format clean.
This commit is contained in:
Shxiao 2026-09-12 10:00:48 +09:00 committed by GitHub
parent 572744975d
commit e92c2c62f7
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -6,13 +6,18 @@ import asyncio
import base64
import json
import logging
import os
from pathlib import Path
from typing import Any
from unittest import mock
from unittest.mock import AsyncMock
import pytest
from app.channels.message_bus import InboundMessageType, MessageBus, OutboundMessage
_POSIX_MODE_BITS_REASON = "Windows chmod only toggles the read-only bit, so the 0o600 mode asserted here is never observable"
def _run(coro):
loop = asyncio.new_event_loop()
@ -1478,6 +1483,8 @@ def test_qrcode_login_binds_and_persists_auth_state(monkeypatch, tmp_path: Path)
assert auth_state["status"] == "confirmed"
assert auth_state["bot_token"] == "bound-token"
assert auth_state["ilink_bot_id"] == "bot-99"
if os.name == "nt":
pytest.skip(_POSIX_MODE_BITS_REASON)
assert ((state_dir / "wechat-auth.json").stat().st_mode & 0o777) == 0o600
_run(go())
@ -1506,10 +1513,14 @@ def test_save_auth_state_tightens_preexisting_loose_file(tmp_path: Path):
)
channel._save_auth_state(status="confirmed", bot_token="bound-token", ilink_bot_id="bot-1")
assert (auth_path.stat().st_mode & 0o777) == 0o600
assert json.loads(auth_path.read_text(encoding="utf-8"))["bot_token"] == "bound-token"
# Atomic write leaves no temp-file residue behind.
assert list(state_dir.glob("*.tmp")) == []
# Keep the platform-independent half running on Windows; only the mode-bit
# half of the "owner-only inode" contract is unobservable there.
if os.name == "nt":
pytest.skip(_POSIX_MODE_BITS_REASON)
assert (auth_path.stat().st_mode & 0o777) == 0o600
def test_save_auth_state_chmod_failure_is_logged_not_warned(tmp_path: Path, caplog):