fix(d1): Calendar-Suite + ai_proactive repariert — conftest CalendarPlugin-Import wiederhergestellt (abbe7a1-Regression), CalendarContract-Zugriffe snake_case→PascalCase (context_tools, services ×2, mail/routes), 2 stale Rate-Limit-Tests auf zentrale check_rate_limit-Grenze umgestellt; test_calendar 34/34, ai_proactive-Failures behoben; Mail-Vorbestand dokumentiert
Check Cross-Plugin Imports / check (push) Has been cancelled
Check Cross-Plugin Imports / check (push) Has been cancelled
This commit is contained in:
@@ -165,8 +165,8 @@ async def get_open_tasks_handler(arguments: dict[str, Any], context: dict[str, A
|
|||||||
|
|
||||||
from app.plugins.builtins.calendar.contracts import get_contract as get_calendar_contract
|
from app.plugins.builtins.calendar.contracts import get_contract as get_calendar_contract
|
||||||
_cal = get_calendar_contract()
|
_cal = get_calendar_contract()
|
||||||
calendar_entry = _cal.calendar_entry
|
calendar_entry = _cal.CalendarEntry
|
||||||
calendar_entry_link = _cal.calendar_entry_link
|
calendar_entry_link = _cal.CalendarEntryLink
|
||||||
|
|
||||||
db, tenant_id, _ = await _get_db_and_tenant(context)
|
db, tenant_id, _ = await _get_db_and_tenant(context)
|
||||||
entity_type = arguments["entity_type"]
|
entity_type = arguments["entity_type"]
|
||||||
|
|||||||
@@ -274,8 +274,8 @@ async def gather_context(
|
|||||||
# Upcoming calendar events
|
# Upcoming calendar events
|
||||||
from app.plugins.builtins.calendar.contracts import get_contract as get_calendar_contract
|
from app.plugins.builtins.calendar.contracts import get_contract as get_calendar_contract
|
||||||
_cal = get_calendar_contract()
|
_cal = get_calendar_contract()
|
||||||
calendar_entry = _cal.calendar_entry
|
calendar_entry = _cal.CalendarEntry
|
||||||
calendar_entry_link = _cal.calendar_entry_link
|
calendar_entry_link = _cal.CalendarEntryLink
|
||||||
|
|
||||||
now = datetime.now(UTC)
|
now = datetime.now(UTC)
|
||||||
event_result = await db.execute(
|
event_result = await db.execute(
|
||||||
@@ -389,8 +389,8 @@ async def gather_context(
|
|||||||
# Upcoming events
|
# Upcoming events
|
||||||
from app.plugins.builtins.calendar.contracts import get_contract as get_calendar_contract
|
from app.plugins.builtins.calendar.contracts import get_contract as get_calendar_contract
|
||||||
_cal = get_calendar_contract()
|
_cal = get_calendar_contract()
|
||||||
calendar_entry = _cal.calendar_entry
|
calendar_entry = _cal.CalendarEntry
|
||||||
calendar_entry_link = _cal.calendar_entry_link
|
calendar_entry_link = _cal.CalendarEntryLink
|
||||||
|
|
||||||
now = datetime.now(UTC)
|
now = datetime.now(UTC)
|
||||||
event_result = await db.execute(
|
event_result = await db.execute(
|
||||||
|
|||||||
@@ -1494,8 +1494,8 @@ async def create_event_from_mail(
|
|||||||
try:
|
try:
|
||||||
from app.plugins.builtins.calendar.contracts import get_contract as get_calendar_contract
|
from app.plugins.builtins.calendar.contracts import get_contract as get_calendar_contract
|
||||||
_cal = get_calendar_contract()
|
_cal = get_calendar_contract()
|
||||||
calendar = _cal.calendar
|
calendar = _cal.Calendar
|
||||||
calendar_entry = _cal.calendar_entry
|
calendar_entry = _cal.CalendarEntry
|
||||||
except ImportError:
|
except ImportError:
|
||||||
return {"created": False, "error": "calendar plugin not available"}
|
return {"created": False, "error": "calendar plugin not available"}
|
||||||
cal_id = _parse_uuid(data.calendar_id, "calendar_id")
|
cal_id = _parse_uuid(data.calendar_id, "calendar_id")
|
||||||
|
|||||||
@@ -53,6 +53,7 @@ from app.models.tenant import Tenant
|
|||||||
from app.models.user import User, UserTenant
|
from app.models.user import User, UserTenant
|
||||||
from app.models.user_preference import UserPreference # noqa: F401
|
from app.models.user_preference import UserPreference # noqa: F401
|
||||||
from app.models.workflow import Workflow, WorkflowInstance, WorkflowStepHistory # noqa: F401
|
from app.models.workflow import Workflow, WorkflowInstance, WorkflowStepHistory # noqa: F401
|
||||||
|
from app.plugins.builtins.calendar import CalendarPlugin # noqa: F401
|
||||||
from app.models.outbox import EventOutbox # noqa: F401
|
from app.models.outbox import EventOutbox # noqa: F401
|
||||||
from app.models.consumer_inbox import ConsumerInbox # noqa: F401
|
from app.models.consumer_inbox import ConsumerInbox # noqa: F401
|
||||||
from app.models.saved_filter import SavedFilter # noqa: F401
|
from app.models.saved_filter import SavedFilter # noqa: F401
|
||||||
|
|||||||
+13
-10
@@ -15,6 +15,7 @@ from unittest.mock import AsyncMock, MagicMock, patch
|
|||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import pytest_asyncio
|
import pytest_asyncio
|
||||||
|
from fastapi import HTTPException
|
||||||
from httpx import ASGITransport, AsyncClient
|
from httpx import ASGITransport, AsyncClient
|
||||||
from sqlalchemy import text
|
from sqlalchemy import text
|
||||||
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, async_sessionmaker
|
from sqlalchemy.ext.asyncio import AsyncEngine, AsyncSession, async_sessionmaker
|
||||||
@@ -1104,14 +1105,11 @@ async def test_generate_suggestion_llm_failure():
|
|||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@patch("app.plugins.builtins.ai_proactive.services.create_db_session")
|
@patch("app.plugins.builtins.ai_proactive.services.create_db_session")
|
||||||
async def test_handle_context_change_rate_limited(mock_create_session, redis_client):
|
async def test_handle_context_change_rate_limited(mock_create_session):
|
||||||
"""Rate-limit prevents suggestion generation."""
|
"""Rate-limit prevents suggestion generation."""
|
||||||
tenant_id = uuid.uuid4()
|
tenant_id = uuid.uuid4()
|
||||||
user_id = uuid.uuid4()
|
user_id = uuid.uuid4()
|
||||||
|
|
||||||
# Pre-set rate limit key in Redis
|
|
||||||
await redis_client.setex(f"ai_proactive:rate:{user_id}", 10, "1")
|
|
||||||
|
|
||||||
mock_session = AsyncMock()
|
mock_session = AsyncMock()
|
||||||
mock_session.__aenter__ = AsyncMock(return_value=mock_session)
|
mock_session.__aenter__ = AsyncMock(return_value=mock_session)
|
||||||
mock_session.__aexit__ = AsyncMock(return_value=None)
|
mock_session.__aexit__ = AsyncMock(return_value=None)
|
||||||
@@ -1127,8 +1125,14 @@ async def test_handle_context_change_rate_limited(mock_create_session, redis_cli
|
|||||||
rate_limit_seconds=10,
|
rate_limit_seconds=10,
|
||||||
model="ollama/deepseek-v4",
|
model="ollama/deepseek-v4",
|
||||||
)
|
)
|
||||||
|
# Since bb36378 the rate limit goes through app.core.rate_limit.check_rate_limit;
|
||||||
|
# simulate an exceeded limit instead of patching the removed services.get_cache.
|
||||||
with (
|
with (
|
||||||
patch("app.plugins.builtins.ai_proactive.services.get_cache", return_value=redis_client),
|
patch(
|
||||||
|
"app.core.rate_limit.check_rate_limit",
|
||||||
|
new_callable=AsyncMock,
|
||||||
|
side_effect=HTTPException(status_code=429),
|
||||||
|
),
|
||||||
patch(
|
patch(
|
||||||
"app.plugins.builtins.ai_proactive.services.get_user_settings",
|
"app.plugins.builtins.ai_proactive.services.get_user_settings",
|
||||||
new_callable=AsyncMock,
|
new_callable=AsyncMock,
|
||||||
@@ -1147,7 +1151,7 @@ async def test_handle_context_change_rate_limited(mock_create_session, redis_cli
|
|||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
@patch("app.plugins.builtins.ai_proactive.services.create_db_session")
|
@patch("app.plugins.builtins.ai_proactive.services.create_db_session")
|
||||||
async def test_handle_context_change_disabled(mock_create_session, redis_client):
|
async def test_handle_context_change_disabled(mock_create_session):
|
||||||
"""Settings disabled → no suggestion."""
|
"""Settings disabled → no suggestion."""
|
||||||
tenant_id = uuid.uuid4()
|
tenant_id = uuid.uuid4()
|
||||||
user_id = uuid.uuid4()
|
user_id = uuid.uuid4()
|
||||||
@@ -1167,13 +1171,12 @@ async def test_handle_context_change_disabled(mock_create_session, redis_client)
|
|||||||
rate_limit_seconds=10,
|
rate_limit_seconds=10,
|
||||||
model="ollama/deepseek-v4",
|
model="ollama/deepseek-v4",
|
||||||
)
|
)
|
||||||
with (
|
# Disabled settings cause an early return before any Redis access;
|
||||||
patch("app.plugins.builtins.ai_proactive.services.get_cache", return_value=redis_client),
|
# no cache/rate-limit patch needed since bb36378.
|
||||||
patch(
|
with patch(
|
||||||
"app.plugins.builtins.ai_proactive.services.get_user_settings",
|
"app.plugins.builtins.ai_proactive.services.get_user_settings",
|
||||||
new_callable=AsyncMock,
|
new_callable=AsyncMock,
|
||||||
return_value=disabled_settings,
|
return_value=disabled_settings,
|
||||||
),
|
|
||||||
):
|
):
|
||||||
await handle_context_change({
|
await handle_context_change({
|
||||||
"user_id": str(user_id),
|
"user_id": str(user_id),
|
||||||
|
|||||||
Reference in New Issue
Block a user