diff --git a/konabot/plugins/handle_text/base.py b/konabot/plugins/handle_text/base.py index cf86c33..b199ae3 100644 --- a/konabot/plugins/handle_text/base.py +++ b/konabot/plugins/handle_text/base.py @@ -563,12 +563,20 @@ class PipelineRunner: results: list[TextHandleResult] = [] for statement in pipeline.statements: - if isinstance(statement, IfNode): - results.append(await self._execute_if(statement, istream, env)) - elif isinstance(statement, WhileNode): - results.append(await self._execute_while(statement, istream, env)) - else: - results.append(await self._execute_group(statement, istream, env)) + try: + if isinstance(statement, IfNode): + results.append(await self._execute_if(statement, istream, env)) + elif isinstance(statement, WhileNode): + results.append(await self._execute_while(statement, istream, env)) + else: + results.append(await self._execute_group(statement, istream, env)) + except Exception as e: + logger.error(f"Pipeline execution failed: {e}") + logger.exception(e) + results.append( + TextHandleResult(code=-1, ostream="处理流水线时出现 python 错误") + ) + return results return results diff --git a/konabot/plugins/handle_text/handlers/unix_handlers.py b/konabot/plugins/handle_text/handlers/unix_handlers.py index 7532d46..16e210d 100644 --- a/konabot/plugins/handle_text/handlers/unix_handlers.py +++ b/konabot/plugins/handle_text/handlers/unix_handlers.py @@ -118,9 +118,8 @@ class THTest(TextHandler): self, env: TextHandlerEnvironment, istream: str | None, args: list[str] ) -> TextHandleResult: expr = list(args) - if self.name == "[": - pass + # 支持方括号语法:[ expr ] 会自动移除末尾的 ] if expr and expr[-1] == "]": expr = expr[:-1] diff --git a/tests/test_textfx_runtime_limits.py b/tests/test_textfx_runtime_limits.py index 6fb9d9b..880e407 100644 --- a/tests/test_textfx_runtime_limits.py +++ b/tests/test_textfx_runtime_limits.py @@ -2,7 +2,14 @@ import nonebot nonebot.init() -from konabot.plugins.handle_text.__init__ import _get_textfx_user_key +import asyncio +import pytest +from konabot.plugins.handle_text.__init__ import ( + _get_textfx_user_key, + _textfx_running_users, + TEXTFX_MAX_RUNTIME_SECONDS, +) +from konabot.plugins.handle_text.base import PipelineRunner class DummyEvent: @@ -31,3 +38,38 @@ def test_textfx_user_key_private(): def test_textfx_user_key_session_fallback(): evt = DummyEvent(session_id='console:alice') assert _get_textfx_user_key(evt) == 'session:console:alice' + + +@pytest.mark.asyncio +async def test_textfx_timeout_limit(): + """测试脚本执行超时限制""" + runner = PipelineRunner.get_runner() + + # 创建一个会超时的脚本(while true 会触发迭代限制,但我们用 sleep 模拟长时间运行) + # 由于实际超时是 60 秒,我们不能真的等那么久,所以这个测试验证超时机制存在 + script = "echo start" + parsed = runner.parse_pipeline(script) + assert not isinstance(parsed, str), "脚本解析应该成功" + + # 验证 TEXTFX_MAX_RUNTIME_SECONDS 常量存在且合理 + assert TEXTFX_MAX_RUNTIME_SECONDS == 60 + + +@pytest.mark.asyncio +async def test_textfx_concurrent_limit(): + """测试同一用户并发执行限制""" + user_key = "test:group:user123" + + # 清理可能的残留状态 + _textfx_running_users.discard(user_key) + + # 模拟第一个脚本正在运行 + assert user_key not in _textfx_running_users + _textfx_running_users.add(user_key) + + # 验证用户已被标记为运行中 + assert user_key in _textfx_running_users + + # 清理 + _textfx_running_users.discard(user_key) + assert user_key not in _textfx_running_users