| from __future__ import annotations |
|
|
| from dataclasses import dataclass |
| from datetime import datetime, timedelta, timezone |
|
|
| import pytest |
|
|
| from aura.agents.echo import tools as echo |
| from aura.agents.echo.models import EmailDraft |
| from aura.core.config import AppConfig, FeatureFlags, ModelSettings, PathsSettings |
|
|
|
|
| @dataclass |
| class FakeNotification: |
| ok: bool = True |
| message: str = "sent" |
|
|
|
|
| class FakeSMTP: |
| def __init__(self, host, port): |
| self.host = host |
| self.port = port |
| self.logged_in = False |
| self.sent = False |
|
|
| def login(self, username, password): |
| self.logged_in = True |
|
|
| def send_message(self, message): |
| self.sent = True |
|
|
| def __enter__(self): |
| return self |
|
|
| def __exit__(self, exc_type, exc, tb): |
| return False |
|
|
|
|
| @pytest.fixture() |
| def echo_config(tmp_path): |
| config = AppConfig( |
| name="AURA", |
| offline_mode=True, |
| log_level="INFO", |
| primary_model=ModelSettings(provider="ollama", name="llama3", host="http://127.0.0.1:11434"), |
| fallback_models=[], |
| paths=PathsSettings( |
| allowed_roots=[tmp_path], |
| data_dir=tmp_path, |
| log_dir=tmp_path / "logs", |
| memory_dir=tmp_path / "memory", |
| ipc_socket=tmp_path / "aura.sock", |
| ), |
| features=FeatureFlags(hotkey=True, tray=True, ipc=True, api=True), |
| source_path=tmp_path / "config.yaml", |
| ) |
| echo.CONFIG = config |
| return config |
|
|
|
|
| def test_parse_natural_time_and_reminder_persistence(monkeypatch, echo_config): |
| monkeypatch.setattr(echo, "notify_user", lambda *args, **kwargs: FakeNotification()) |
| iso = echo.parse_natural_time("tomorrow 9am") |
| reminder = echo.set_reminder("Standup", "tomorrow 9am") |
| upcoming = echo.get_upcoming_reminders(hours_ahead=48) |
| assert iso.endswith("+00:00") |
| assert reminder.text == "Standup" |
| assert upcoming and upcoming[0].id == reminder.id |
|
|
|
|
| def test_create_update_list_and_cancel_meeting(echo_config): |
| start = (datetime.now(timezone.utc) + timedelta(hours=1)).isoformat() |
| end = (datetime.now(timezone.utc) + timedelta(hours=2)).isoformat() |
| meeting = echo.create_meeting("Planning", start, end, ["a@example.com"], "offline", "demo") |
| meetings = echo.list_meetings({"start": (datetime.now(timezone.utc) - timedelta(minutes=5)).isoformat(), "end": (datetime.now(timezone.utc) + timedelta(hours=3)).isoformat()}) |
| updated = echo.update_meeting(meeting.id, {"title": "Planning 2"}) |
| cancelled = echo.cancel_meeting(meeting.id) |
| meetings_after = echo.list_meetings({"start": (datetime.now(timezone.utc) - timedelta(minutes=5)).isoformat(), "end": (datetime.now(timezone.utc) + timedelta(hours=3)).isoformat()}) |
|
|
| assert meeting.provider == "local-sqlite" |
| assert meetings and meetings[0].id == meeting.id |
| assert updated.title == "Planning 2" |
| assert cancelled.success is True |
| assert meetings_after == [] |
|
|
|
|
| def test_join_draft_and_send_email(monkeypatch, echo_config): |
| monkeypatch.setattr(echo, "open_path", lambda link: type("Result", (), {"ok": True, "message": "opened", "details": {"link": link}})()) |
| draft = echo.draft_email(["a@example.com"], "Subject", "Body") |
| assert isinstance(draft, EmailDraft) |
| assert draft.subject == "Subject" |
|
|
| echo.set_email_config({"smtp_host": "smtp.example.com", "smtp_port": 465, "username": "user", "password": "pass", "from_address": "user@example.com"}) |
| monkeypatch.setattr(echo.smtplib, "SMTP_SSL", FakeSMTP) |
| send_result = echo.send_email(draft.id) |
| join_result = echo.join_meeting("https://example.com/meet") |
|
|
| assert send_result.success is True |
| assert join_result.success is True |
|
|
|
|
| def test_send_email_without_config_and_invalid_time(echo_config): |
| echo.set_email_config(None) |
| result = echo.send_email("missing") |
| assert result.success is False |
| with pytest.raises(Exception): |
| echo.parse_natural_time("not a time") |
|
|