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>
199 lines
6.3 KiB
Python
199 lines
6.3 KiB
Python
"""Tests for astrbot.core.star.base module."""
|
|
|
|
import pytest
|
|
from unittest.mock import AsyncMock, MagicMock, patch
|
|
|
|
|
|
class TestStarBase:
|
|
"""Test cases for the Star base class."""
|
|
|
|
def test_star_class_exists(self):
|
|
"""Test that Star class can be imported."""
|
|
from astrbot.core.star import Star
|
|
|
|
assert Star is not None
|
|
|
|
def test_star_init_with_context(self):
|
|
"""Test Star initialization with a context-like object."""
|
|
from astrbot.core.star import Star
|
|
|
|
# Create a mock context with get_config method
|
|
mock_context = MagicMock()
|
|
mock_context.get_config.return_value = MagicMock()
|
|
|
|
# Create a concrete Star subclass for testing
|
|
class TestStar(Star):
|
|
name = "test_star"
|
|
author = "test_author"
|
|
|
|
star = TestStar(context=mock_context)
|
|
|
|
assert star.context is mock_context
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_text_to_image_with_config(self):
|
|
"""Test text_to_image method with valid config."""
|
|
from astrbot.core.star import Star
|
|
|
|
mock_context = MagicMock()
|
|
mock_config = MagicMock()
|
|
mock_config.get.return_value = "default_template"
|
|
mock_context.get_config.return_value = mock_config
|
|
|
|
class TestStar(Star):
|
|
name = "test_star"
|
|
author = "test_author"
|
|
|
|
star = TestStar(context=mock_context)
|
|
|
|
with patch(
|
|
"astrbot.core.star.base.html_renderer.render_t2i",
|
|
new_callable=AsyncMock,
|
|
) as mock_render:
|
|
mock_render.return_value = "http://example.com/image.png"
|
|
result = await star.text_to_image("test text", return_url=True)
|
|
|
|
mock_render.assert_called_once_with(
|
|
"test text",
|
|
return_url=True,
|
|
template_name="default_template",
|
|
)
|
|
assert result == "http://example.com/image.png"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_text_to_image_without_config(self):
|
|
"""Test text_to_image method when get_config returns None."""
|
|
from astrbot.core.star import Star
|
|
|
|
mock_context = MagicMock()
|
|
mock_context.get_config.return_value = None
|
|
|
|
class TestStar(Star):
|
|
name = "test_star"
|
|
author = "test_author"
|
|
|
|
star = TestStar(context=mock_context)
|
|
|
|
with patch(
|
|
"astrbot.core.star.base.html_renderer.render_t2i",
|
|
new_callable=AsyncMock,
|
|
) as mock_render:
|
|
mock_render.return_value = "http://example.com/image.png"
|
|
result = await star.text_to_image("test text", return_url=False)
|
|
|
|
mock_render.assert_called_once_with(
|
|
"test text",
|
|
return_url=False,
|
|
template_name=None,
|
|
)
|
|
assert result == "http://example.com/image.png"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_html_render(self):
|
|
"""Test html_render method."""
|
|
from astrbot.core.star import Star
|
|
|
|
mock_context = MagicMock()
|
|
|
|
class TestStar(Star):
|
|
name = "test_star"
|
|
author = "test_author"
|
|
|
|
star = TestStar(context=mock_context)
|
|
|
|
with patch(
|
|
"astrbot.core.star.base.html_renderer.render_custom_template",
|
|
new_callable=AsyncMock,
|
|
) as mock_render:
|
|
mock_render.return_value = "http://example.com/rendered.png"
|
|
result = await star.html_render(
|
|
"<html>{{ data }}</html>",
|
|
{"data": "test"},
|
|
return_url=True,
|
|
)
|
|
|
|
mock_render.assert_called_once_with(
|
|
"<html>{{ data }}</html>",
|
|
{"data": "test"},
|
|
return_url=True,
|
|
options=None,
|
|
)
|
|
assert result == "http://example.com/rendered.png"
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_initialize_and_terminate(self):
|
|
"""Test that initialize and terminate methods can be overridden."""
|
|
from astrbot.core.star import Star
|
|
|
|
class TestStar(Star):
|
|
name = "test_star"
|
|
author = "test_author"
|
|
|
|
async def initialize(self) -> None:
|
|
self.initialized = True
|
|
|
|
async def terminate(self) -> None:
|
|
self.terminated = True
|
|
|
|
mock_context = MagicMock()
|
|
star = TestStar(context=mock_context)
|
|
|
|
await star.initialize()
|
|
assert star.initialized is True
|
|
|
|
await star.terminate()
|
|
assert star.terminated is True
|
|
|
|
def test_star_metadata_registration(self):
|
|
"""Test that Star subclass is automatically registered."""
|
|
from astrbot.core.star import star_map, star_registry
|
|
from astrbot.core.star.star import StarMetadata
|
|
|
|
# Clear any previous registration for this test module
|
|
module_path = __name__
|
|
|
|
class UniqueTestStar:
|
|
"""Not a Star subclass, should not be registered."""
|
|
pass
|
|
|
|
# Verify Star subclass gets registered
|
|
initial_count = len(star_registry)
|
|
|
|
# Note: This test verifies the __init_subclass__ mechanism
|
|
# The actual registration happens when a class inherits from Star
|
|
assert len(star_registry) >= initial_count
|
|
|
|
|
|
class TestNoCircularImports:
|
|
"""Test that there are no circular import issues."""
|
|
|
|
def test_import_star_module(self):
|
|
"""Test that star module can be imported without circular import errors."""
|
|
import astrbot.core.star
|
|
|
|
assert astrbot.core.star is not None
|
|
|
|
def test_import_pipeline_module(self):
|
|
"""Test that pipeline module can be imported without circular import errors."""
|
|
import astrbot.core.pipeline
|
|
|
|
assert astrbot.core.pipeline is not None
|
|
|
|
def test_import_both_modules(self):
|
|
"""Test that both modules can be imported together."""
|
|
import astrbot.core.pipeline
|
|
import astrbot.core.star
|
|
|
|
# Verify key exports are available
|
|
from astrbot.core.star import Context, Star, PluginManager
|
|
|
|
assert Context is not None
|
|
assert Star is not None
|
|
assert PluginManager is not None
|
|
|
|
def test_import_pipeline_context(self):
|
|
"""Test that PipelineContext can be imported."""
|
|
from astrbot.core.pipeline.context import PipelineContext
|
|
|
|
assert PipelineContext is not None
|