from __future__ import annotations import asyncio from backend.services import task_service from backend.services import reminder_dispatcher, reminder_service def test_health_endpoint(client): response = client.get("/health") assert response.status_code == 200 body = response.json() assert body["status"] == "ok" assert "app" in body def test_session_lifecycle(client): created = client.post("/api/history/sessions") assert created.status_code == 200 session = created.json() listed = client.get("/api/history/sessions") assert listed.status_code == 200 assert len(listed.json()) == 1 fetched = client.get(f"/api/history/sessions/{session['id']}") assert fetched.status_code == 200 assert fetched.json()["id"] == session["id"] deleted = client.delete(f"/api/history/sessions/{session['id']}") assert deleted.status_code == 200 assert deleted.json()["deleted"] is True missing = client.get(f"/api/history/sessions/{session['id']}") assert missing.status_code == 404 def test_task_routes(client): created = client.post("/api/tasks", json={"text": "Ship release notes"}) assert created.status_code == 200 task_id = created.json()["id"] listed = client.get("/api/tasks") assert listed.status_code == 200 assert listed.json()[0]["text"] == "Ship release notes" completed = client.patch(f"/api/tasks/{task_id}/complete") assert completed.status_code == 200 assert completed.json()["completed"] is True deleted = client.delete(f"/api/tasks/{task_id}") assert deleted.status_code == 200 assert deleted.json()["id"] == task_id def test_reminder_routes_and_validation(client): invalid = client.post("/api/reminders", json={"title": "Review sprint board", "date": "2026-06-01"}) assert invalid.status_code == 422 created = client.post( "/api/reminders", json={"title": "Review sprint board", "note": "Bring blockers", "date": "2020-01-01", "time": "10:00"}, ) assert created.status_code == 200 reminder_id = created.json()["id"] assert created.json()["title"] == "Review sprint board" assert created.json()["status"] == "overdue" listed = client.get("/api/reminders") assert listed.status_code == 200 assert len(listed.json()) == 1 assert listed.json()[0]["note"] == "Bring blockers" due = client.get("/api/reminders/due") assert due.status_code == 200 assert due.json()[0]["id"] == reminder_id updated = client.put( f"/api/reminders/{reminder_id}", json={"title": "Review sprint board updated", "note": "Updated note", "date": "2030-01-01", "time": "11:30"}, ) assert updated.status_code == 200 assert updated.json()["title"] == "Review sprint board updated" assert updated.json()["status"] == "scheduled" completed = client.patch(f"/api/reminders/{reminder_id}/complete") assert completed.status_code == 200 assert completed.json()["completed"] is True assert completed.json()["status"] == "done" postponed = client.patch(f"/api/reminders/{reminder_id}/postpone") assert postponed.status_code == 200 assert postponed.json()["completed"] is False deleted = client.delete(f"/api/reminders/{reminder_id}") assert deleted.status_code == 200 def test_note_routes(client): created = client.post("/api/notes", json={"text": "Remember the retro action items", "source": "manual"}) assert created.status_code == 200 note_id = created.json()["id"] listed = client.get("/api/notes") assert listed.status_code == 200 assert listed.json()[0]["id"] == note_id deleted = client.delete(f"/api/notes/{note_id}") assert deleted.status_code == 200 def test_chat_commands_history_search_and_save(client): created = client.post("/api/chat", json={"message": "add task finish QA audit"}) assert created.status_code == 200 payload = created.json() session_id = payload["session_id"] assert "Task added" in payload["reply"] follow_up = client.post("/api/chat", json={"session_id": session_id, "message": "show my tasks"}) assert follow_up.status_code == 200 assert "Your tasks" in follow_up.json()["reply"] session_detail = client.get(f"/api/history/sessions/{session_id}") assert session_detail.status_code == 200 messages = session_detail.json()["messages"] assistant_message = next(message for message in messages if message["role"] == "assistant") saved = client.post(f"/api/history/sessions/{session_id}/messages/{assistant_message['id']}/save") assert saved.status_code == 200 saved_messages = client.get("/api/history/saved") assert saved_messages.status_code == 200 assert len(saved_messages.json()) == 1 results = client.get("/api/history/search", params={"query": "finish QA audit"}) assert results.status_code == 200 assert len(results.json()) >= 1 def test_summary_counts(client): client.post("/api/tasks", json={"text": "Prepare 1:1 summary"}) client.post("/api/reminders", json={"title": "Prepare 1:1 summary", "date": "2020-01-01", "time": "10:00"}) client.post("/api/notes", json={"text": "Growth areas for next quarter", "source": "manual"}) response = client.get("/api/history/summary") assert response.status_code == 200 summary = response.json() assert summary["pending_tasks"] == 1 assert summary["active_reminders"] == 1 assert summary["notes"] == 1 assert summary["due_reminders"] == 1 def test_storage_recovers_from_invalid_json(client): task_service.STORE.path.write_text("{invalid json", encoding="utf-8") response = client.get("/api/tasks") assert response.status_code == 200 assert response.json() == [] def test_due_reminders_send_to_telegram_once(monkeypatch): sent_messages = [] async def fake_send(reminder): sent_messages.append(reminder["title"]) return True monkeypatch.setattr(reminder_dispatcher, "send_reminder_notification", fake_send) monkeypatch.setattr(reminder_dispatcher, "telegram_notifications_enabled", lambda: True) created = reminder_service.add_reminder( "Send standup update", reminder_service.datetime.now() - reminder_service.timedelta(minutes=1), note="Mention blockers", ) sent_count = asyncio.run(reminder_dispatcher.process_due_reminders()) assert sent_count == 1 assert sent_messages == ["Send standup update"] updated = reminder_service.get_reminder(created["id"], include_deleted=True) assert updated is not None assert updated["notified_at"] is not None sent_count_again = asyncio.run(reminder_dispatcher.process_due_reminders()) assert sent_count_again == 0 assert sent_messages == ["Send standup update"]