mirror of
https://github.com/zvx-echo6/meshai.git
synced 2026-08-26 17:31:34 +00:00
fix(tests): stop poisoning sys.modules session-wide with a bare MagicMock
Three test files (test_llm_scoping, test_fix_meshcore_save_and_llm_test, test_config_partial_save_merge) did `sys.modules.setdefault(_mod, MagicMock())` to stub an optional import. `setdefault` installs the MagicMock into sys.modules for the ENTIRE pytest session even when the real package is present — so any LATER test that does `await <that module>.<coro>(...)` (e.g. `await aiosqlite.connect(...)`) fails with "object MagicMock can't be used in 'await' expression" / "Event loop is closed". This is what made test_fire_tracker_phase4::test_natural_language_fire_ question_routes_to_llm pass in isolation but fail in full-suite order — the leak came from an earlier file, not the victim. #140 hardened the victim's own config/history isolation but couldn't fix an external sys.modules poison. Fix: only fall back to the MagicMock when the real module genuinely fails to import (guarded assignment), so a present package is never replaced. Root-cause fix in the polluters, not a skip on the victim. Suite: 2422 passed, 0 failed, 72 skipped — fully green (was 6 failed before #140, then 1 order-dependent failure after). Confirmed deterministic across repeated full runs. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
cd226689da
commit
2d359ea6f1
3 changed files with 48 additions and 5 deletions
|
|
@ -32,6 +32,7 @@ omitted keys keep their live values while explicitly-sent keys still apply.
|
|||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib
|
||||
import sys
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
|
|
@ -41,8 +42,22 @@ from fastapi import FastAPI
|
|||
from fastapi.testclient import TestClient
|
||||
|
||||
# Stub heavy optional deps so config_routes imports without them.
|
||||
#
|
||||
# Try the real import first -- sys.modules.setdefault() alone is only a
|
||||
# no-op "in production where the real packages are installed" if some
|
||||
# earlier-run test has already imported the real module. When this file
|
||||
# collects first (test order is alphabetical, not guaranteed), setdefault()
|
||||
# permanently replaces a genuinely-installed module (e.g. aiosqlite) with a
|
||||
# bare MagicMock for the rest of the pytest session -- every later test's
|
||||
# `await aiosqlite.connect(...)` then breaks with "MagicMock can't be used
|
||||
# in 'await' expression". Only fall back to the mock when the real package
|
||||
# truly isn't importable.
|
||||
for _mod in ("openai", "aiosqlite", "anthropic", "google", "google.genai"):
|
||||
sys.modules.setdefault(_mod, MagicMock())
|
||||
if _mod not in sys.modules:
|
||||
try:
|
||||
importlib.import_module(_mod)
|
||||
except ImportError:
|
||||
sys.modules[_mod] = MagicMock()
|
||||
|
||||
from meshai.config import ( # noqa: E402
|
||||
Config,
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ Bug 2 — POST /api/config/test-llm "string indices must be integers, not 'str'"
|
|||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import importlib
|
||||
import sys
|
||||
from types import SimpleNamespace
|
||||
from unittest.mock import AsyncMock, MagicMock, patch
|
||||
|
|
@ -20,9 +21,23 @@ import pytest
|
|||
|
||||
# -----------------------------------------------------------------------
|
||||
# Stub heavy optional deps so config_routes can be imported without them.
|
||||
#
|
||||
# Try the real import first -- sys.modules.setdefault() alone is only a
|
||||
# no-op "in production where the real packages are installed" if some
|
||||
# earlier-run test has already imported the real module. When this file
|
||||
# collects first (test order is alphabetical, not guaranteed), setdefault()
|
||||
# permanently replaces a genuinely-installed module (e.g. aiosqlite) with a
|
||||
# bare MagicMock for the rest of the pytest session -- every later test's
|
||||
# `await aiosqlite.connect(...)` then breaks with "MagicMock can't be used
|
||||
# in 'await' expression". Only fall back to the mock when the real package
|
||||
# truly isn't importable.
|
||||
# -----------------------------------------------------------------------
|
||||
for _mod in ("openai", "aiosqlite", "anthropic", "google", "google.genai"):
|
||||
sys.modules.setdefault(_mod, MagicMock())
|
||||
if _mod not in sys.modules:
|
||||
try:
|
||||
importlib.import_module(_mod)
|
||||
except ImportError:
|
||||
sys.modules[_mod] = MagicMock()
|
||||
|
||||
|
||||
# ==========================================================================
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ Covers:
|
|||
(d) ContextConfig.max_age default is 14 days (1_209_600 seconds)
|
||||
"""
|
||||
|
||||
import importlib
|
||||
import sys
|
||||
from unittest.mock import MagicMock
|
||||
|
||||
|
|
@ -14,11 +15,23 @@ import pytest
|
|||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Stub optional heavy deps so meshai.router can be imported in this env.
|
||||
# These stubs are set before any meshai.router import in this process;
|
||||
# they are no-ops in production where the real packages are installed.
|
||||
#
|
||||
# Try the real import first -- sys.modules.setdefault() alone is only a
|
||||
# no-op "in production where the real packages are installed" if some
|
||||
# earlier-run test has already imported the real module. When this file
|
||||
# collects first (test order is alphabetical, not guaranteed), setdefault()
|
||||
# permanently replaces a genuinely-installed module (e.g. aiosqlite) with a
|
||||
# bare MagicMock for the rest of the pytest session -- every later test's
|
||||
# `await aiosqlite.connect(...)` then breaks with "MagicMock can't be used
|
||||
# in 'await' expression". Only fall back to the mock when the real package
|
||||
# truly isn't importable.
|
||||
# ---------------------------------------------------------------------------
|
||||
for _mod in ("openai", "aiosqlite", "anthropic", "google", "google.genai"):
|
||||
sys.modules.setdefault(_mod, MagicMock())
|
||||
if _mod not in sys.modules:
|
||||
try:
|
||||
importlib.import_module(_mod)
|
||||
except ImportError:
|
||||
sys.modules[_mod] = MagicMock()
|
||||
|
||||
from meshai.config import ( # noqa: E402
|
||||
BotConfig,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue