agentic.email/backend/tests/test_human_handoff_service.py
2026-10-06 01:51:23 +05:30

124 lines
3.6 KiB
Python

import pytest
from bson import ObjectId
from app.services.human_handoff_service import (
MESSAGE_SCOPE_EXTERNAL,
MESSAGE_SCOPE_HANDOFF,
resolve_handoff_from_inbound,
)
class FakeCollection:
def __init__(self, documents=None):
self.documents = list(documents or [])
async def find_one(self, query):
for document in self.documents:
if all(document.get(key) == value for key, value in query.items()):
return document
if "$ne" in query.get("status", {}):
if document.get("status") == query["status"]["$ne"]:
continue
for document in self.documents:
matches = True
for key, value in query.items():
if key == "status" and isinstance(value, dict) and "$ne" in value:
if document.get("status") == value["$ne"]:
matches = False
break
elif document.get(key) != value:
matches = False
break
if matches:
return document
return None
def find(self, query):
class Cursor:
def __init__(self, items):
self.items = items
async def to_list(self, length):
return self.items[:length]
filtered = [
document
for document in self.documents
if all(document.get(key) == value for key, value in query.items())
]
return Cursor(filtered)
class FakeDatabase:
def __init__(self):
self.human_handoff_rules = FakeCollection()
self.messages = FakeCollection()
self.mailbox_entries = FakeCollection()
self.human_handoffs = FakeCollection()
@pytest.mark.asyncio
async def test_resolve_handoff_requires_owner_and_thread_context():
database = FakeDatabase()
handoff_thread_id = ObjectId()
message_id = ObjectId()
database.human_handoff_rules.documents = [
{
"account_id": "acct-1",
"owner_email": "owner@gmail.com",
"active": True,
}
]
database.messages.documents = [
{
"_id": message_id,
"message_id": "<handoff-1@gentic.email>",
"message_scope": MESSAGE_SCOPE_HANDOFF,
}
]
database.mailbox_entries.documents = [
{
"account_id": "acct-1",
"message_id": message_id,
"thread_id": handoff_thread_id,
"message_scope": MESSAGE_SCOPE_HANDOFF,
}
]
database.human_handoffs.documents = [
{
"_id": ObjectId(),
"account_id": "acct-1",
"handoff_thread_id": handoff_thread_id,
"human_email": "owner@gmail.com",
"status": "WAITING_FOR_HUMAN",
}
]
handoff = await resolve_handoff_from_inbound(
database,
account_id="acct-1",
agent_email="support@gentic.email",
sender_address="owner@gmail.com",
in_reply_to="<handoff-1@gentic.email>",
references=[],
)
assert handoff is not None
@pytest.mark.asyncio
async def test_resolve_handoff_rejects_unknown_sender():
database = FakeDatabase()
handoff = await resolve_handoff_from_inbound(
database,
account_id="acct-1",
agent_email="support@gentic.email",
sender_address="stranger@example.com",
in_reply_to="<handoff-1@gentic.email>",
references=[],
)
assert handoff is None
@pytest.mark.asyncio
async def test_external_scope_constant_isolated_from_handoff():
assert MESSAGE_SCOPE_EXTERNAL != MESSAGE_SCOPE_HANDOFF