mirror of
https://github.com/NousResearch/hermes-agent.git
synced 2026-04-29 01:31:41 +00:00
Salvaged from PR #10643 by kshitijk4poor, updated for current main. Root causes fixed: 1. Telegram xdist mock pollution — new tests/gateway/conftest.py with shared mock that runs at collection time (prevents ChatType=None caching) 2. VIRTUAL_ENV env var leak — monkeypatch.delenv in _detect_venv_dir tests 3. Copilot base_url missing — add fallback in _resolve_runtime_from_pool_entry 4. Stale vision model assertion — zai now uses glm-5v-turbo 5. Reasoning item id intentionally stripped — assert 'id' not in (store=False) 6. Context length warning unreachable — pass base_url to AIAgent in test 7. Kimi provider label updated — 'Kimi / Kimi Coding Plan' matches models.py 8. Google Workspace calendar tests — rewritten for current production code, properly mock subprocess on api_module, removed stale +agenda assertions 9. Credential pool auto-seeding — mock _select_pool_entry / _resolve_auto / _import_codex_cli_tokens to prevent real credentials from leaking into tests
66 lines
2.6 KiB
Python
66 lines
2.6 KiB
Python
"""Shared fixtures for gateway tests.
|
|
|
|
The ``_ensure_telegram_mock`` helper guarantees that a minimal mock of
|
|
the ``telegram`` package is registered in :data:`sys.modules` **before**
|
|
any test file triggers ``from gateway.platforms.telegram import ...``.
|
|
|
|
Without this, ``pytest-xdist`` workers that happen to collect
|
|
``test_telegram_caption_merge.py`` (bare top-level import, no per-file
|
|
mock) first will cache ``ChatType = None`` from the production
|
|
ImportError fallback, causing 30+ downstream test failures wherever
|
|
``ChatType.GROUP`` / ``ChatType.SUPERGROUP`` is accessed.
|
|
|
|
Individual test files may still call their own ``_ensure_telegram_mock``
|
|
— it short-circuits when the mock is already present.
|
|
"""
|
|
|
|
import sys
|
|
from unittest.mock import MagicMock
|
|
|
|
|
|
def _ensure_telegram_mock() -> None:
|
|
"""Install a comprehensive telegram mock in sys.modules.
|
|
|
|
Idempotent — skips when the real library is already imported.
|
|
Uses ``sys.modules[name] = mod`` (overwrite) instead of
|
|
``setdefault`` so it wins even if a partial/broken import
|
|
already cached a module with ``ChatType = None``.
|
|
"""
|
|
if "telegram" in sys.modules and hasattr(sys.modules["telegram"], "__file__"):
|
|
return # Real library is installed — nothing to mock
|
|
|
|
mod = MagicMock()
|
|
mod.ext.ContextTypes.DEFAULT_TYPE = type(None)
|
|
mod.constants.ParseMode.MARKDOWN = "Markdown"
|
|
mod.constants.ParseMode.MARKDOWN_V2 = "MarkdownV2"
|
|
mod.constants.ParseMode.HTML = "HTML"
|
|
mod.constants.ChatType.PRIVATE = "private"
|
|
mod.constants.ChatType.GROUP = "group"
|
|
mod.constants.ChatType.SUPERGROUP = "supergroup"
|
|
mod.constants.ChatType.CHANNEL = "channel"
|
|
|
|
# Real exception classes so ``except (NetworkError, ...)`` clauses
|
|
# in production code don't blow up with TypeError.
|
|
mod.error.NetworkError = type("NetworkError", (OSError,), {})
|
|
mod.error.TimedOut = type("TimedOut", (OSError,), {})
|
|
mod.error.BadRequest = type("BadRequest", (Exception,), {})
|
|
mod.error.Forbidden = type("Forbidden", (Exception,), {})
|
|
mod.error.InvalidToken = type("InvalidToken", (Exception,), {})
|
|
mod.error.RetryAfter = type("RetryAfter", (Exception,), {"retry_after": 1})
|
|
mod.error.Conflict = type("Conflict", (Exception,), {})
|
|
|
|
# Update.ALL_TYPES used in start_polling()
|
|
mod.Update.ALL_TYPES = []
|
|
|
|
for name in (
|
|
"telegram",
|
|
"telegram.ext",
|
|
"telegram.constants",
|
|
"telegram.request",
|
|
):
|
|
sys.modules[name] = mod
|
|
sys.modules["telegram.error"] = mod.error
|
|
|
|
|
|
# Run at collection time — before any test file's module-level imports.
|
|
_ensure_telegram_mock()
|