144 lines
4.5 KiB
Python
144 lines
4.5 KiB
Python
from __future__ import annotations
|
|
|
|
import os
|
|
import sys
|
|
import types
|
|
from datetime import datetime, timedelta
|
|
|
|
import pytest
|
|
import pytest_asyncio
|
|
from sqlalchemy import JSON
|
|
from sqlalchemy.ext.asyncio import async_sessionmaker, create_async_engine
|
|
|
|
os.environ["DATABASE_URL"] = "sqlite+aiosqlite:///:memory:"
|
|
|
|
from app.models.base import Base
|
|
from app.models.cognitive_conflict import CognitiveConflict
|
|
from app.models.project import Project
|
|
from app.models.project_signal_link import ProjectSignalLink
|
|
from app.models.signal import Signal
|
|
from app.models.task import Task
|
|
from app.models.truth_node import TruthNode
|
|
from app.models.user import User
|
|
|
|
|
|
def _use_sqlite_json_types() -> None:
|
|
User.__table__.c.assigned_domains.type = JSON()
|
|
TruthNode.__table__.c.content.type = JSON()
|
|
Task.__table__.c.ai_recommended_assignees.type = JSON()
|
|
Task.__table__.c.ai_breakdown_payload.type = JSON()
|
|
Task.__table__.c.manual_overrides.type = JSON()
|
|
Task.__table__.c.required_skill_tag_ids.type = JSON()
|
|
CognitiveConflict.__table__.c.involved_user_ids.type = JSON()
|
|
|
|
|
|
@pytest_asyncio.fixture
|
|
async def briefing_session():
|
|
engine = create_async_engine("sqlite+aiosqlite:///:memory:")
|
|
_use_sqlite_json_types()
|
|
async with engine.begin() as conn:
|
|
await conn.run_sync(
|
|
lambda sync_conn: Base.metadata.create_all(
|
|
sync_conn,
|
|
tables=[
|
|
User.__table__,
|
|
Project.__table__,
|
|
TruthNode.__table__,
|
|
Task.__table__,
|
|
Signal.__table__,
|
|
ProjectSignalLink.__table__,
|
|
CognitiveConflict.__table__,
|
|
],
|
|
)
|
|
)
|
|
maker = async_sessionmaker(engine, expire_on_commit=False)
|
|
async with maker() as session:
|
|
yield session
|
|
await engine.dispose()
|
|
|
|
|
|
@pytest.mark.asyncio
|
|
async def test_generate_personalized_briefing_uses_naive_time_window(briefing_session, monkeypatch) -> None:
|
|
fixed_now = datetime(2026, 3, 25, 14, 43, 24)
|
|
stub_database_module = types.ModuleType("app.core.database")
|
|
stub_database_module.AsyncSessionLocal = None
|
|
monkeypatch.setitem(sys.modules, "app.core.database", stub_database_module)
|
|
|
|
import app.services.daily_briefing_core.mixin_personal as daily_briefing_personal_module
|
|
from app.services.daily_briefing_core import DailyBriefingService
|
|
|
|
monkeypatch.setattr(daily_briefing_personal_module, "now_cn_naive", lambda: fixed_now)
|
|
|
|
async def fake_generate_ai_summary(self, user, data, tenant_id): # noqa: ANN001
|
|
_ = self, user, data, tenant_id
|
|
return "今日简报"
|
|
|
|
monkeypatch.setattr(DailyBriefingService, "_generate_ai_summary", fake_generate_ai_summary)
|
|
|
|
user = User(
|
|
tenant_id=1,
|
|
username="tester",
|
|
email="tester@example.com",
|
|
password_hash="hash",
|
|
name="测试用户",
|
|
role="BE",
|
|
status="active",
|
|
is_active=True,
|
|
)
|
|
project = Project(
|
|
tenant_id=1,
|
|
name="demo-project",
|
|
title="Demo Project",
|
|
status="active",
|
|
)
|
|
briefing_session.add_all([user, project])
|
|
await briefing_session.flush()
|
|
|
|
truth_node = TruthNode(
|
|
tenant_id=1,
|
|
node_type="task",
|
|
parent_id=None,
|
|
project_id=project.id,
|
|
signal_id=None,
|
|
created_by=user.id,
|
|
title="修复简报时间窗",
|
|
content={},
|
|
version=1,
|
|
status="active",
|
|
)
|
|
briefing_session.add(truth_node)
|
|
await briefing_session.flush()
|
|
|
|
task = Task(
|
|
tenant_id=1,
|
|
truth_node_id=truth_node.id,
|
|
project_id=project.id,
|
|
assignee_id=user.id,
|
|
ai_recommended_assignees={},
|
|
ai_breakdown_payload=None,
|
|
manual_overrides=None,
|
|
title="修复简报时间窗",
|
|
description="",
|
|
required_skill_tag_ids=[],
|
|
status="in_progress",
|
|
priority="HIGH",
|
|
estimated_hours=2.0,
|
|
actual_hours=None,
|
|
quality_score=None,
|
|
due_date=None,
|
|
completed_at=None,
|
|
created_at=fixed_now - timedelta(hours=4),
|
|
updated_at=fixed_now - timedelta(hours=2),
|
|
)
|
|
briefing_session.add(task)
|
|
await briefing_session.commit()
|
|
|
|
briefing = await DailyBriefingService(briefing_session).generate_personalized_briefing(
|
|
user_id=user.id,
|
|
tenant_id=1,
|
|
)
|
|
|
|
assert briefing["summary"] == "今日简报"
|
|
assert len(briefing["your_tasks"]) == 1
|
|
assert briefing["your_tasks"][0]["title"] == "修复简报时间窗"
|