242 lines
7.8 KiB
Python
242 lines
7.8 KiB
Python
from __future__ import annotations
|
|
|
|
from asgiref.sync import async_to_sync
|
|
from django.test import TestCase
|
|
|
|
from core.commands.base import CommandContext
|
|
from core.commands.engine import _matches_trigger, process_inbound_message
|
|
from core.messaging.reply_sync import extract_reply_ref, resolve_reply_target
|
|
from core.models import (
|
|
ChatSession,
|
|
CommandChannelBinding,
|
|
CommandProfile,
|
|
Message,
|
|
Person,
|
|
PersonIdentifier,
|
|
User,
|
|
)
|
|
|
|
|
|
class Phase1ReplyResolutionTests(TestCase):
|
|
def setUp(self):
|
|
self.user = User.objects.create_user(
|
|
username="phase1-reply-user",
|
|
email="phase1-reply@example.com",
|
|
password="x",
|
|
)
|
|
self.person = Person.objects.create(user=self.user, name="Reply Person")
|
|
self.identifier = PersonIdentifier.objects.create(
|
|
user=self.user,
|
|
person=self.person,
|
|
service="signal",
|
|
identifier="+15550000001",
|
|
)
|
|
self.session = ChatSession.objects.create(
|
|
user=self.user,
|
|
identifier=self.identifier,
|
|
)
|
|
|
|
def test_resolve_reply_target_by_source_message_id(self):
|
|
anchor = Message.objects.create(
|
|
user=self.user,
|
|
session=self.session,
|
|
sender_uuid="+15550000001",
|
|
text="anchor",
|
|
ts=1000,
|
|
source_service="signal",
|
|
source_message_id="signal-msg-1",
|
|
)
|
|
resolved = async_to_sync(resolve_reply_target)(
|
|
self.user,
|
|
self.session,
|
|
{
|
|
"reply_source_service": "signal",
|
|
"reply_source_message_id": "signal-msg-1",
|
|
},
|
|
)
|
|
self.assertEqual(anchor.id, resolved.id if resolved else None)
|
|
|
|
def test_resolve_reply_target_with_bridge_ref_fallback(self):
|
|
anchor = Message.objects.create(
|
|
user=self.user,
|
|
session=self.session,
|
|
sender_uuid="+15550000001",
|
|
text="anchor",
|
|
ts=2000,
|
|
receipt_payload={
|
|
"bridge_refs": {
|
|
"signal": [
|
|
{
|
|
"xmpp_message_id": "xmpp-bridge-1",
|
|
"upstream_message_id": "signal-upstream-1",
|
|
"upstream_author": "+15550000001",
|
|
"upstream_ts": 2000,
|
|
"updated_at": 2000,
|
|
}
|
|
]
|
|
}
|
|
},
|
|
)
|
|
resolved = async_to_sync(resolve_reply_target)(
|
|
self.user,
|
|
self.session,
|
|
{
|
|
"reply_source_service": "signal",
|
|
"reply_source_message_id": "signal-upstream-1",
|
|
},
|
|
)
|
|
self.assertEqual(anchor.id, resolved.id if resolved else None)
|
|
|
|
def test_resolve_reply_target_miss(self):
|
|
resolved = async_to_sync(resolve_reply_target)(
|
|
self.user,
|
|
self.session,
|
|
{
|
|
"reply_source_service": "signal",
|
|
"reply_source_message_id": "does-not-exist",
|
|
},
|
|
)
|
|
self.assertIsNone(resolved)
|
|
|
|
def test_extract_reply_ref_xmpp(self):
|
|
result = extract_reply_ref(
|
|
"xmpp",
|
|
{
|
|
"reply_source_message_id": "xmpp-msg-1",
|
|
"reply_source_chat_id": "alice@example.test",
|
|
},
|
|
)
|
|
self.assertEqual("xmpp-msg-1", result.get("reply_source_message_id"))
|
|
self.assertEqual("xmpp", result.get("reply_source_service"))
|
|
|
|
def test_extract_reply_ref_signal(self):
|
|
result = extract_reply_ref(
|
|
"signal",
|
|
{
|
|
"envelope": {
|
|
"dataMessage": {
|
|
"quote": {"id": "signal-msg-quoted"},
|
|
}
|
|
}
|
|
},
|
|
)
|
|
self.assertEqual("signal-msg-quoted", result.get("reply_source_message_id"))
|
|
self.assertEqual("signal", result.get("reply_source_service"))
|
|
|
|
def test_extract_reply_ref_whatsapp(self):
|
|
result = extract_reply_ref(
|
|
"whatsapp",
|
|
{
|
|
"extendedTextMessage": {
|
|
"contextInfo": {
|
|
"stanzaId": "wa-msg-quoted",
|
|
"participant": "12345@s.whatsapp.net",
|
|
}
|
|
}
|
|
},
|
|
)
|
|
self.assertEqual("wa-msg-quoted", result.get("reply_source_message_id"))
|
|
self.assertEqual("whatsapp", result.get("reply_source_service"))
|
|
|
|
def test_extract_reply_ref_whatsapp_stanza_id_variant(self):
|
|
result = extract_reply_ref(
|
|
"whatsapp",
|
|
{
|
|
"extendedTextMessage": {
|
|
"contextInfo": {
|
|
"stanzaID": "wa-msg-quoted-2",
|
|
}
|
|
}
|
|
},
|
|
)
|
|
self.assertEqual("wa-msg-quoted-2", result.get("reply_source_message_id"))
|
|
self.assertEqual("whatsapp", result.get("reply_source_service"))
|
|
|
|
|
|
class Phase1CommandEngineTests(TestCase):
|
|
def setUp(self):
|
|
self.user = User.objects.create_user(
|
|
username="phase1-command-user",
|
|
email="phase1-command@example.com",
|
|
password="x",
|
|
)
|
|
self.person = Person.objects.create(user=self.user, name="Command Person")
|
|
self.identifier = PersonIdentifier.objects.create(
|
|
user=self.user,
|
|
person=self.person,
|
|
service="signal",
|
|
identifier="+15550000002",
|
|
)
|
|
self.session = ChatSession.objects.create(
|
|
user=self.user,
|
|
identifier=self.identifier,
|
|
)
|
|
self.profile = CommandProfile.objects.create(
|
|
user=self.user,
|
|
slug="bp",
|
|
name="Business Plan",
|
|
enabled=True,
|
|
trigger_token="#bp#",
|
|
reply_required=True,
|
|
exact_match_only=True,
|
|
)
|
|
CommandChannelBinding.objects.create(
|
|
profile=self.profile,
|
|
direction="ingress",
|
|
service="web",
|
|
channel_identifier="web-chan-1",
|
|
enabled=True,
|
|
)
|
|
|
|
def test_matches_trigger_exact_only(self):
|
|
self.assertTrue(_matches_trigger(self.profile, "#bp#"))
|
|
self.assertFalse(_matches_trigger(self.profile, " #bp# extra "))
|
|
|
|
def test_process_inbound_message_requires_reply(self):
|
|
msg = Message.objects.create(
|
|
user=self.user,
|
|
session=self.session,
|
|
sender_uuid="",
|
|
text="#bp#",
|
|
ts=3000,
|
|
source_service="web",
|
|
source_chat_id="web-chan-1",
|
|
message_meta={},
|
|
)
|
|
results = async_to_sync(process_inbound_message)(
|
|
CommandContext(
|
|
service="web",
|
|
channel_identifier="web-chan-1",
|
|
message_id=str(msg.id),
|
|
user_id=self.user.id,
|
|
message_text="#bp#",
|
|
payload={},
|
|
)
|
|
)
|
|
self.assertEqual(1, len(results))
|
|
self.assertEqual("skipped", results[0].status)
|
|
self.assertEqual("reply_required", results[0].error)
|
|
|
|
def test_process_inbound_message_skips_mirrored_origin(self):
|
|
msg = Message.objects.create(
|
|
user=self.user,
|
|
session=self.session,
|
|
sender_uuid="",
|
|
text="#bp#",
|
|
ts=4000,
|
|
source_service="web",
|
|
source_chat_id="web-chan-1",
|
|
message_meta={"origin_tag": "translation:test"},
|
|
)
|
|
results = async_to_sync(process_inbound_message)(
|
|
CommandContext(
|
|
service="web",
|
|
channel_identifier="web-chan-1",
|
|
message_id=str(msg.id),
|
|
user_id=self.user.id,
|
|
message_text="#bp#",
|
|
payload={},
|
|
)
|
|
)
|
|
self.assertEqual([], results)
|