📄 test_email_routing.py 6,038 bytes Apr 23, 2026 📋 Raw

"""Test email classification and routing."""

import sys
sys.path.insert(0, '.')

import asyncio
from family.classifier import EmailClassifier
from family.pipeline import FamilyPipeline
from shared.llm import LLMClient

async def test_classifier():
"""Test email classification."""
print("=" * 70)
print("EMAIL CLASSIFICATION TEST")
print("=" * 70)
print()

llm = LLMClient()
classifier = EmailClassifier(llm)

test_emails = [
    {
        "subject": "Your appointment with Dr. Smith is confirmed for Friday",
        "body": "Dear Matt, your appointment is scheduled for Friday, April 25 at 2:00 PM.",
        "sender": "doctor@clinic.com",
        "expected": "appointment"
    },
    {
        "subject": "Weekly Tech Digest: AI News This Week",
        "body": "Here's what's happening in AI this week: OpenAI released...",
        "sender": "newsletter@techdigest.com",
        "expected": "newsletter"
    },
    {
        "subject": "Sullivan's soccer practice schedule",
        "body": "Hi Matt, Sullivan has soccer practice every Tuesday at 4 PM.",
        "sender": "coach@soccerclub.com",
        "expected": "family"
    },
    {
        "subject": "Your Amazon order has shipped",
        "body": "Order #12345 has been shipped and will arrive on Friday.",
        "sender": "ship-confirmation@amazon.com",
        "expected": "other"
    },
    {
        "subject": "School calendar update - Spring break dates",
        "body": "Dear parents, please note the updated spring break dates...",
        "sender": "school@district.edu",
        "expected": "family"
    }
]

correct = 0
total = len(test_emails)

for i, email in enumerate(test_emails, 1):
    print(f"Test {i}/{total}: {email['subject'][:50]}...")

    try:
        result = await classifier.classify(
            email["subject"],
            email["body"],
            email["sender"]
        )

        status = "✓" if result == email["expected"] else "✗"
        print(f"  {status} Classified as: {result} (expected: {email['expected']})")

        if result == email["expected"]:
            correct += 1
    except Exception as e:
        print(f"  ✗ Error: {e}")
    print()

print("-" * 70)
print(f"Results: {correct}/{total} correct ({correct/total*100:.0f}%)")
print("-" * 70)

await llm.close()

return correct == total

async def test_pipeline_integration():
"""Test full pipeline with newsletter."""
print()
print("=" * 70)
print("PIPELINE INTEGRATION TEST — Newsletter")
print("=" * 70)
print()

llm = LLMClient()

# Mock calendar and telegram
class MockCalendar:
    async def create_event(self, **kwargs):
        return {"created": True}
    async def health(self):
        return {"ok": True}

class MockTelegram:
    async def to_family(self, msg):
        print(f"  [Telegram would send: {msg[:100]}...]")
        return {"ok": True}
    async def send(self, *args, **kwargs):
        return {"ok": True}

pipeline = FamilyPipeline(
    llm_client=llm,
    calendar_client=MockCalendar(),
    telegram=MockTelegram()
)

# Test newsletter
newsletter_email = {
    "subject": "Weekly AI Digest: LLM Updates",
    "body": """
    Hello subscriber,

    This week's AI news:

    1. OpenAI released GPT-5 with improved reasoning capabilities
    2. Anthropic announced Claude 4 with 200K context window
    3. Local LLM performance benchmarks show phi4:14b competitive with cloud models
    4. New tools for running models on consumer GPUs

    Action items:
    - Try phi4:14b for coding tasks
    - Evaluate Claude 4 for customer support
    - Update your local model stack

    Best,
    The AI Weekly Team
    """,
    "sender": "newsletter@aiweekly.com"
}

print("Processing newsletter email...")
print(f"  Subject: {newsletter_email['subject']}")

try:
    result = await pipeline.process_email(
        subject=newsletter_email["subject"],
        body=newsletter_email["body"],
        sender=newsletter_email["sender"],
        received_at="2026-04-23T10:00:00Z"
    )

    print(f"\n  Classification: {result['classification']}")
    print(f"  Handler: {result['handler']}")
    print(f"  Processed: {result['processed']}")

    if result.get('summary'):
        print(f"\n  Summary:")
        for line in result['summary'].split('\n')[:5]:
            print(f"    {line}")

    if result.get('event_created') is not None:
        print(f"\n  Calendar event: {'✓ Created' if result['event_created'] else '✗ Not created (correct for newsletter)'}")

    print(f"  Notification: {'✓ Sent' if result.get('notification_sent') else '✗ Failed'}")

    success = (
        result['classification'] == 'newsletter' and
        result['handler'] == 'newsletter' and
        result['processed'] and
        not result.get('event_created', False) and
        result.get('notification_sent', False)
    )

    print(f"\n  {'✓ PASS' if success else '✗ FAIL'}")

except Exception as e:
    print(f"  ✗ Pipeline error: {e}")
    import traceback
    traceback.print_exc()

await llm.close()

if name == "main":
print("Testing email routing v2...")
print()

# Run classifier test
asyncio.run(test_classifier())

# Run integration test
asyncio.run(test_pipeline_integration())

print()
print("=" * 70)
print("TEST COMPLETE")
print("=" * 70)