/ tests / gateway / test_delivery.py
test_delivery.py
  1  """Tests for the delivery routing module."""
  2  
  3  from gateway.config import Platform
  4  from gateway.delivery import DeliveryTarget
  5  from gateway.session import SessionSource
  6  
  7  
  8  class TestParseTargetPlatformChat:
  9      def test_explicit_telegram_chat(self):
 10          target = DeliveryTarget.parse("telegram:12345")
 11          assert target.platform == Platform.TELEGRAM
 12          assert target.chat_id == "12345"
 13          assert target.is_explicit is True
 14  
 15      def test_platform_only_no_chat_id(self):
 16          target = DeliveryTarget.parse("discord")
 17          assert target.platform == Platform.DISCORD
 18          assert target.chat_id is None
 19          assert target.is_explicit is False
 20  
 21      def test_local_target(self):
 22          target = DeliveryTarget.parse("local")
 23          assert target.platform == Platform.LOCAL
 24          assert target.chat_id is None
 25  
 26      def test_origin_with_source(self):
 27          origin = SessionSource(platform=Platform.TELEGRAM, chat_id="789", thread_id="42")
 28          target = DeliveryTarget.parse("origin", origin=origin)
 29          assert target.platform == Platform.TELEGRAM
 30          assert target.chat_id == "789"
 31          assert target.thread_id == "42"
 32          assert target.is_origin is True
 33  
 34      def test_origin_without_source(self):
 35          target = DeliveryTarget.parse("origin")
 36          assert target.platform == Platform.LOCAL
 37          assert target.is_origin is True
 38  
 39      def test_unknown_platform(self):
 40          target = DeliveryTarget.parse("unknown_platform")
 41          assert target.platform == Platform.LOCAL
 42  
 43  
 44  class TestTargetToStringRoundtrip:
 45      def test_origin_roundtrip(self):
 46          origin = SessionSource(platform=Platform.TELEGRAM, chat_id="111", thread_id="42")
 47          target = DeliveryTarget.parse("origin", origin=origin)
 48          assert target.to_string() == "origin"
 49  
 50      def test_local_roundtrip(self):
 51          target = DeliveryTarget.parse("local")
 52          assert target.to_string() == "local"
 53  
 54      def test_platform_only_roundtrip(self):
 55          target = DeliveryTarget.parse("discord")
 56          assert target.to_string() == "discord"
 57  
 58      def test_explicit_chat_roundtrip(self):
 59          target = DeliveryTarget.parse("telegram:999")
 60          s = target.to_string()
 61          assert s == "telegram:999"
 62  
 63          reparsed = DeliveryTarget.parse(s)
 64          assert reparsed.platform == Platform.TELEGRAM
 65          assert reparsed.chat_id == "999"
 66  
 67  
 68  class TestCaseSensitiveChatIdParsing:
 69      """Test that chat IDs preserve their original case (issue #11768)."""
 70      
 71      def test_slack_uppercase_chat_id_preserved(self):
 72          """Slack channel IDs like C123ABC should preserve case."""
 73          target = DeliveryTarget.parse("slack:C123ABC")
 74          assert target.platform == Platform.SLACK
 75          assert target.chat_id == "C123ABC"  # Should NOT be lowercased to c123abc
 76          assert target.is_explicit is True
 77      
 78      def test_slack_chat_id_with_thread_preserved(self):
 79          """Slack channel:thread IDs should preserve case."""
 80          target = DeliveryTarget.parse("slack:C123ABC:thread123")
 81          assert target.platform == Platform.SLACK
 82          assert target.chat_id == "C123ABC"
 83          assert target.thread_id == "thread123"
 84      
 85      def test_matrix_room_id_preserved(self):
 86          """Matrix room IDs like !RoomABC:example.org should preserve case.
 87          
 88          Note: Matrix room IDs contain colons (e.g., !RoomABC:example.org).
 89          Due to the platform:chat_id:thread_id format, these are parsed as
 90          chat_id=!RoomABC and thread_id=example.org. This is a known limitation
 91          of the current format. The fix preserves case but doesn't change the
 92          parsing structure.
 93          """
 94          target = DeliveryTarget.parse("matrix:!RoomABC:example.org")
 95          assert target.platform == Platform.MATRIX
 96          # The room ID is split at the first colon after the platform prefix
 97          # This is a format limitation - the case is preserved but the structure is split
 98          assert target.chat_id == "!RoomABC"
 99          assert target.thread_id == "example.org"
100      
101      def test_mixed_case_chat_id_roundtrip(self):
102          """Mixed-case chat IDs should survive parse-to_string roundtrip."""
103          original = "telegram:ChatId123ABC"
104          target = DeliveryTarget.parse(original)
105          s = target.to_string()
106          reparsed = DeliveryTarget.parse(s)
107          assert reparsed.chat_id == "ChatId123ABC"
108  
109  
110  class TestPlatformNameCaseInsensitivity:
111      """Test that platform names are case-insensitive."""
112      
113      def test_uppercase_platform_name(self):
114          """Platform names should be case-insensitive."""
115          target = DeliveryTarget.parse("TELEGRAM:12345")
116          assert target.platform == Platform.TELEGRAM
117          assert target.chat_id == "12345"
118      
119      def test_mixed_case_platform_name(self):
120          """Mixed-case platform names should work."""
121          target = DeliveryTarget.parse("TeleGram:12345")
122          assert target.platform == Platform.TELEGRAM
123          assert target.chat_id == "12345"
124  
125  
126