# backend/tests/test_proactive.py — 능동 감지 + 수락 실체화 from sqlmodel import select from app.models import CalEvent, FinanceCategory, FocusBlock, ProactiveCard, Task from app.worker.jobs.proactive import run_proactive def test_meeting_streak_card(session): s, _ = session for i, t in enumerate([("10:00", "11:00"), ("11:00", "12:00"), ("13:00", "14:00")]): s.add(CalEvent(id=f"te{i}", day=9, start=t[0], end=t[1], title=f"회의{i}", cal="meeting")) s.commit() cards = run_proactive(s) streak = [c for c in cards if c.kind == "schedule"] assert streak and "미팅 3연속" in streak[0].title assert streak[0].action_kind == "focus_block" def test_pricey_bill_card(session): s, _ = session s.add(FinanceCategory(id="cat-x", name="쇼핑", amt=298000, pct=120, icon="bag", over=True)) s.commit() cards = run_proactive(s) bill = [c for c in cards if c.kind == "finance"] assert bill and "평소보다 많아요" in bill[0].title and bill[0].tone == "amber" def test_run_proactive_idempotent(session): s, _ = session for i in range(3): s.add( CalEvent( id=f"te{i}", day=9, start=f"1{i}:00", end=f"1{i+1}:00", title="회의", cal="meeting" ) ) s.commit() run_proactive(s) run_proactive(s) # 2회차 streaks = s.exec(select(ProactiveCard).where(ProactiveCard.id == "pc-streak")).all() assert len(streaks) == 1 # 중복 생성 없음 def test_accept_focus_block_materializes(client, session): s, _ = session # 시드 pc1(schedule/focus_block) 수락 → FocusBlock 생성 out = client.post("/api/proactive/pc1/accept").json() assert out["action_kind"] == "focus_block" and out["created_id"] s.expire_all() assert s.get(FocusBlock, out["created_id"]) is not None # 카드는 accepted → active 목록에서 사라짐 active = client.get("/api/proactive").json() assert "pc1" not in [c["id"] for c in active] def test_accept_task_materializes(client, session): s, _ = session out = client.post("/api/proactive/pc2/accept").json() assert out["action_kind"] == "task" and out["created_id"] s.expire_all() assert s.get(Task, out["created_id"]) is not None def test_dismiss_proactive(client): assert client.post("/api/proactive/pc1/dismiss").json()["ok"] is True assert "pc1" not in [c["id"] for c in client.get("/api/proactive").json()] def test_worker_run_endpoint(client): r = client.post("/api/worker/run/proactive").json() assert r["job"] == "proactive" and r["ok"] is True assert client.post("/api/worker/run/nope").status_code == 404