2a6863cf70
* test: add tests for star base class and config management - Add Star base class safety helper tests - Expand config management unit tests - Update cron manager tests Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test: fix plugin_manager test isolation issues - Use local mock plugin instead of real network requests - Clear sys.modules cache for entire data module tree - Clear star_map and star_registry in teardown - Use pytest_asyncio.fixture for async fixture support Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test: fix test isolation and compatibility issues - test_main.py: fix version comparison and path assertions for Windows - test_smoke.py: add missing apscheduler.triggers mock modules - test_tool_loop_agent_runner.py: update assertion for new interrupt behavior - test_api_key_open_api.py: use unique session IDs to avoid test conflicts Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * test: add unit tests for _version_info comparisons * test: enhance plugin manager tests with mock implementations and improved assertions * test: add mock plugin builder and updater for plugin management tests * fix: resolve pipeline and star import cycles (#5353) * fix: resolve pipeline and star import cycles - Add bootstrap.py and stage_order.py to break circular dependencies - Export Context, PluginManager, StarTools from star module - Update pipeline __init__ to defer imports - Split pipeline initialization into separate bootstrap module Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix: add logging for get_config() failure in Star class * fix: reorder logger initialization in base.py --------- Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> * test: update cron job scheduling tests and refactor star base tests for clarity * test: expand star base tests for comprehensive coverage - Add tests for Star class initialization and context handling - Add tests for text_to_image with/without config - Add tests for html_render method - Add tests for initialize/terminate lifecycle methods - Add type hint validation tests for Context - Add circular import prevention tests Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: address PR review feedback - use TYPE_CHECKING instead of Any - pipeline/context.py: Use TYPE_CHECKING to import PluginManager instead of Any - pipeline/__init__.py: Add TYPE_CHECKING imports for __all__ exports to satisfy static analyzers - star/register/star_handler.py: Use TYPE_CHECKING to import AstrAgentContext instead of Any - tests: Remove invalid type hint tests that tested incorrect assumptions Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix: improve TYPE_CHECKING pattern for circular import resolution - star/register/star_handler.py: Use AstrAgentContext instead of Any in generic types - star/context.py: Remove unnecessary else branch with CronJobManager = Any (with __future__ annotations, TYPE_CHECKING imports are sufficient) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: whatevertogo <whatevertogo@users.noreply.github.com> Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Soulter <37870767+Soulter@users.noreply.github.com>
122 lines
4.3 KiB
Python
122 lines
4.3 KiB
Python
"""Smoke tests for critical startup and import paths."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
from astrbot.core.pipeline.bootstrap import ensure_builtin_stages_registered
|
|
from astrbot.core.pipeline.process_stage.method.agent_sub_stages.internal import (
|
|
InternalAgentSubStage,
|
|
)
|
|
from astrbot.core.pipeline.process_stage.method.agent_sub_stages.third_party import (
|
|
ThirdPartyAgentSubStage,
|
|
)
|
|
from astrbot.core.pipeline.stage import Stage, registered_stages
|
|
from astrbot.core.pipeline.stage_order import STAGES_ORDER
|
|
|
|
REPO_ROOT = Path(__file__).resolve().parents[1]
|
|
|
|
|
|
def _run_code_in_fresh_interpreter(code: str, failure_message: str) -> None:
|
|
proc = subprocess.run(
|
|
[sys.executable, "-c", code],
|
|
cwd=REPO_ROOT,
|
|
capture_output=True,
|
|
text=True,
|
|
check=False,
|
|
)
|
|
assert proc.returncode == 0, (
|
|
f"{failure_message}\nstdout:\n{proc.stdout}\nstderr:\n{proc.stderr}\n"
|
|
)
|
|
|
|
|
|
def test_smoke_critical_imports_in_fresh_interpreter() -> None:
|
|
code = (
|
|
"import importlib;"
|
|
"mods=["
|
|
"'astrbot.core.core_lifecycle',"
|
|
"'astrbot.core.astr_main_agent',"
|
|
"'astrbot.core.pipeline.scheduler',"
|
|
"'astrbot.core.pipeline.process_stage.method.agent_sub_stages.internal',"
|
|
"'astrbot.core.pipeline.process_stage.method.agent_sub_stages.third_party'"
|
|
"];"
|
|
"[importlib.import_module(m) for m in mods]"
|
|
)
|
|
_run_code_in_fresh_interpreter(code, "Smoke import check failed.")
|
|
|
|
|
|
def test_smoke_pipeline_stage_registration_matches_order() -> None:
|
|
ensure_builtin_stages_registered()
|
|
stage_names = {cls.__name__ for cls in registered_stages}
|
|
|
|
assert set(STAGES_ORDER).issubset(stage_names)
|
|
assert len(stage_names) == len(registered_stages)
|
|
|
|
|
|
def test_smoke_agent_sub_stages_are_stage_subclasses() -> None:
|
|
assert issubclass(InternalAgentSubStage, Stage)
|
|
assert issubclass(ThirdPartyAgentSubStage, Stage)
|
|
|
|
|
|
def test_pipeline_package_exports_remain_compatible() -> None:
|
|
import astrbot.core.pipeline as pipeline
|
|
|
|
assert pipeline.ProcessStage is not None
|
|
assert pipeline.RespondStage is not None
|
|
assert isinstance(pipeline.STAGES_ORDER, list)
|
|
assert "ProcessStage" in pipeline.STAGES_ORDER
|
|
|
|
|
|
def test_builtin_stage_bootstrap_is_idempotent() -> None:
|
|
ensure_builtin_stages_registered()
|
|
before_count = len(registered_stages)
|
|
stage_names = {cls.__name__ for cls in registered_stages}
|
|
|
|
expected_stage_names = {
|
|
"WakingCheckStage",
|
|
"WhitelistCheckStage",
|
|
"SessionStatusCheckStage",
|
|
"RateLimitStage",
|
|
"ContentSafetyCheckStage",
|
|
"PreProcessStage",
|
|
"ProcessStage",
|
|
"ResultDecorateStage",
|
|
"RespondStage",
|
|
}
|
|
|
|
assert expected_stage_names.issubset(stage_names)
|
|
|
|
ensure_builtin_stages_registered()
|
|
assert len(registered_stages) == before_count
|
|
|
|
|
|
def test_pipeline_import_is_stable_with_mocked_apscheduler() -> None:
|
|
"""Regression: importing pipeline should not require cron/apscheduler modules."""
|
|
code = (
|
|
"import sys;"
|
|
"from unittest.mock import MagicMock;"
|
|
"mock_apscheduler = MagicMock();"
|
|
"mock_apscheduler.schedulers = MagicMock();"
|
|
"mock_apscheduler.schedulers.asyncio = MagicMock();"
|
|
"mock_apscheduler.schedulers.background = MagicMock();"
|
|
"mock_apscheduler.triggers = MagicMock();"
|
|
"mock_apscheduler.triggers.cron = MagicMock();"
|
|
"mock_apscheduler.triggers.date = MagicMock();"
|
|
"sys.modules['apscheduler'] = mock_apscheduler;"
|
|
"sys.modules['apscheduler.schedulers'] = mock_apscheduler.schedulers;"
|
|
"sys.modules['apscheduler.schedulers.asyncio'] = mock_apscheduler.schedulers.asyncio;"
|
|
"sys.modules['apscheduler.schedulers.background'] = mock_apscheduler.schedulers.background;"
|
|
"sys.modules['apscheduler.triggers'] = mock_apscheduler.triggers;"
|
|
"sys.modules['apscheduler.triggers.cron'] = mock_apscheduler.triggers.cron;"
|
|
"sys.modules['apscheduler.triggers.date'] = mock_apscheduler.triggers.date;"
|
|
"import astrbot.core.pipeline as pipeline;"
|
|
"assert pipeline.ProcessStage is not None;"
|
|
"assert pipeline.RespondStage is not None"
|
|
)
|
|
_run_code_in_fresh_interpreter(
|
|
code,
|
|
"Pipeline import should not depend on real apscheduler package.",
|
|
)
|