Files
OpenJarvis/tests/test_digest_integration.py
T
Jon Saad-FalconandClaude Opus 4.6 d73014d6bb feat: Morning Digest pipeline + unified OAuth + Apple connectors
Full morning digest system:
- MorningDigestAgent, DigestStore, digest_collect tool, TTS backends
- Connectors: Oura, Strava, Spotify, Google Tasks, Apple Health, Apple Music
- CLI `jarvis digest` command + FastAPI /api/digest endpoints
- Cartesia, Kokoro, OpenAI TTS backends with persona prompts

Unified OAuth setup across all surfaces:
- Generic OAuthProvider registry for Google, Strava, Spotify
- CLI auto-opens browser + catches callback (no more paste-code)
- Server /oauth/start + /oauth/callback endpoints for desktop/browser
- Frontend OAuthPanel with popup + polling

Apple connectors:
- Apple Health reads from HealthKit DB or iPhone export XML
- Apple Music queries Music.app via AppleScript

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 11:05:35 -07:00

80 lines
2.3 KiB
Python

"""End-to-end integration test for the morning digest pipeline.
Uses mocked connectors and engine to verify the full flow:
digest_collect -> LLM synthesis -> TTS -> DigestStore -> CLI delivery.
"""
from __future__ import annotations
from datetime import datetime
from pathlib import Path
from unittest.mock import MagicMock, patch
import pytest
from openjarvis.agents.digest_store import DigestStore
from openjarvis.core.types import ToolResult
def test_full_digest_pipeline(tmp_path):
"""Verify collect -> synthesize -> TTS -> store -> retrieve."""
from openjarvis.agents.morning_digest import MorningDigestAgent
# Mock engine returns a narrative
mock_engine = MagicMock()
mock_engine.generate.return_value = {
"content": (
"Good morning, sir. You slept 7.5 hours with a readiness score of 78. "
"You have 2 meetings today and 5 unread emails. "
"In the news, a new GPT-5 paper dropped on Arxiv."
),
"finish_reason": "stop",
"usage": {},
}
# Mock tool results
collect_result = ToolResult(
tool_name="digest_collect",
content="## gmail (3 items)\n## oura (1 items)\n## gcalendar (2 items)",
success=True,
metadata={"total_items": 6},
)
tts_result = ToolResult(
tool_name="text_to_speech",
content=str(tmp_path / "digest.mp3"),
success=True,
metadata={"audio_path": str(tmp_path / "digest.mp3")},
)
# Write fake audio
(tmp_path / "digest.mp3").write_bytes(b"fake-mp3-audio")
db_path = str(tmp_path / "digest.db")
agent = MorningDigestAgent(
mock_engine,
"claude-sonnet-4-6",
tools=[],
persona="neutral",
digest_store_path=db_path,
)
with patch.object(
agent._executor,
"execute",
side_effect=[collect_result, tts_result],
):
result = agent.run("Generate morning digest")
# Verify agent result
assert "Good morning" in result.content
assert result.metadata["audio_path"] == str(tmp_path / "digest.mp3")
# Verify stored in DigestStore
store = DigestStore(db_path=db_path)
artifact = store.get_latest()
assert artifact is not None
assert "Good morning" in artifact.text
assert artifact.model_used == "claude-sonnet-4-6"
store.close()