PageRenderTime 94ms CodeModel.GetById 20ms RepoModel.GetById 8ms app.codeStats 0ms

/src/mailman/runners/tests/test_lmtp.py

https://gitlab.com/noc0lour/mailman
Python | 206 lines | 179 code | 8 blank | 19 comment | 2 complexity | 74346bafe9dc1e45c83c8bafaf0f499c MD5 | raw file
  1. # Copyright (C) 2012-2016 by the Free Software Foundation, Inc.
  2. #
  3. # This file is part of GNU Mailman.
  4. #
  5. # GNU Mailman is free software: you can redistribute it and/or modify it under
  6. # the terms of the GNU General Public License as published by the Free
  7. # Software Foundation, either version 3 of the License, or (at your option)
  8. # any later version.
  9. #
  10. # GNU Mailman is distributed in the hope that it will be useful, but WITHOUT
  11. # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12. # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  13. # more details.
  14. #
  15. # You should have received a copy of the GNU General Public License along with
  16. # GNU Mailman. If not, see <http://www.gnu.org/licenses/>.
  17. """Tests for the LMTP server."""
  18. import os
  19. import smtplib
  20. import unittest
  21. from datetime import datetime
  22. from mailman.app.lifecycle import create_list
  23. from mailman.config import config
  24. from mailman.database.transaction import transaction
  25. from mailman.testing.helpers import get_lmtp_client, get_queue_messages
  26. from mailman.testing.layers import LMTPLayer
  27. class TestLMTP(unittest.TestCase):
  28. """Test various aspects of the LMTP server."""
  29. layer = LMTPLayer
  30. def setUp(self):
  31. with transaction():
  32. self._mlist = create_list('test@example.com')
  33. self._lmtp = get_lmtp_client(quiet=True)
  34. self._lmtp.lhlo('remote.example.org')
  35. self.addCleanup(self._lmtp.close)
  36. def test_message_id_required(self):
  37. # The message is rejected if it does not have a Message-ID header.
  38. with self.assertRaises(smtplib.SMTPDataError) as cm:
  39. self._lmtp.sendmail('anne@example.com', ['test@example.com'], """\
  40. From: anne@example.com
  41. To: test@example.com
  42. Subject: This has no Message-ID header
  43. """)
  44. # LMTP returns a 550: Requested action not taken: mailbox unavailable
  45. # (e.g., mailbox not found, no access, or command rejected for policy
  46. # reasons)
  47. self.assertEqual(cm.exception.smtp_code, 550)
  48. self.assertEqual(cm.exception.smtp_error,
  49. b'No Message-ID header provided')
  50. def test_message_id_hash_is_added(self):
  51. self._lmtp.sendmail('anne@example.com', ['test@example.com'], """\
  52. From: anne@example.com
  53. To: test@example.com
  54. Message-ID: <ant>
  55. Subject: This has a Message-ID but no Message-ID-Hash
  56. """)
  57. items = get_queue_messages('in', expected_count=1)
  58. self.assertEqual(items[0].msg['message-id-hash'],
  59. 'MS6QLWERIJLGCRF44J7USBFDELMNT2BW')
  60. def test_original_message_id_hash_is_overwritten(self):
  61. self._lmtp.sendmail('anne@example.com', ['test@example.com'], """\
  62. From: anne@example.com
  63. To: test@example.com
  64. Message-ID: <ant>
  65. Message-ID-Hash: IGNOREME
  66. Subject: This has a Message-ID but no Message-ID-Hash
  67. """)
  68. items = get_queue_messages('in', expected_count=1)
  69. all_headers = items[0].msg.get_all('message-id-hash')
  70. self.assertEqual(len(all_headers), 1)
  71. self.assertEqual(items[0].msg['message-id-hash'],
  72. 'MS6QLWERIJLGCRF44J7USBFDELMNT2BW')
  73. def test_received_time(self):
  74. # The LMTP runner adds a `received_time` key to the metadata.
  75. self._lmtp.sendmail('anne@example.com', ['test@example.com'], """\
  76. From: anne@example.com
  77. To: test@example.com
  78. Subject: This has no Message-ID header
  79. Message-ID: <ant>
  80. """)
  81. items = get_queue_messages('in', expected_count=1)
  82. self.assertEqual(items[0].msgdata['received_time'],
  83. datetime(2005, 8, 1, 7, 49, 23))
  84. def test_queue_directory(self):
  85. # The LMTP runner is not queue runner, so it should not have a
  86. # directory in var/queue.
  87. queue_directory = os.path.join(config.QUEUE_DIR, 'lmtp')
  88. self.assertFalse(os.path.isdir(queue_directory))
  89. def test_nonexistent_mailing_list(self):
  90. # Trying to post to a nonexistent mailing list is an error.
  91. with self.assertRaises(smtplib.SMTPDataError) as cm:
  92. self._lmtp.sendmail('anne@example.com',
  93. ['notalist@example.com'], """\
  94. From: anne.person@example.com
  95. To: notalist@example.com
  96. Subject: An interesting message
  97. Message-ID: <aardvark>
  98. """)
  99. self.assertEqual(cm.exception.smtp_code, 550)
  100. self.assertEqual(cm.exception.smtp_error,
  101. b'Requested action not taken: mailbox unavailable')
  102. def test_missing_subaddress(self):
  103. # Trying to send a message to a bogus subaddress is an error.
  104. with self.assertRaises(smtplib.SMTPDataError) as cm:
  105. self._lmtp.sendmail('anne@example.com',
  106. ['test-bogus@example.com'], """\
  107. From: anne.person@example.com
  108. To: test-bogus@example.com
  109. Subject: An interesting message
  110. Message-ID: <aardvark>
  111. """)
  112. self.assertEqual(cm.exception.smtp_code, 550)
  113. self.assertEqual(cm.exception.smtp_error,
  114. b'Requested action not taken: mailbox unavailable')
  115. def test_mailing_list_with_subaddress(self):
  116. # A mailing list with a subaddress in its name should be recognized as
  117. # the mailing list, not as a command.
  118. with transaction():
  119. create_list('test-join@example.com')
  120. self._lmtp.sendmail('anne@example.com', ['test-join@example.com'], """\
  121. From: anne@example.com
  122. To: test-join@example.com
  123. Message-ID: <ant>
  124. Subject: This should not be recognized as a join command
  125. """)
  126. # The message is in the incoming queue but not the command queue.
  127. get_queue_messages('in', expected_count=1)
  128. get_queue_messages('command', expected_count=0)
  129. def test_mailing_list_with_subaddress_command(self):
  130. # Like above, but we can still send a command to the mailing list.
  131. with transaction():
  132. create_list('test-join@example.com')
  133. self._lmtp.sendmail('anne@example.com',
  134. ['test-join-join@example.com'], """\
  135. From: anne@example.com
  136. To: test-join-join@example.com
  137. Message-ID: <ant>
  138. Subject: This will be recognized as a join command.
  139. """)
  140. # The message is in the command queue but not the incoming queue.
  141. get_queue_messages('in', expected_count=0)
  142. get_queue_messages('command', expected_count=1)
  143. class TestBugs(unittest.TestCase):
  144. """Test some LMTP related bugs."""
  145. layer = LMTPLayer
  146. def setUp(self):
  147. self._lmtp = get_lmtp_client(quiet=True)
  148. self._lmtp.lhlo('remote.example.org')
  149. def test_lp1117176(self):
  150. # Upper cased list names can't be sent to via LMTP.
  151. with transaction():
  152. create_list('my-LIST@example.com')
  153. self._lmtp.sendmail('anne@example.com', ['my-list@example.com'], """\
  154. From: anne@example.com
  155. To: my-list@example.com
  156. Subject: My subject
  157. Message-ID: <alpha>
  158. """)
  159. items = get_queue_messages('in', expected_count=1)
  160. self.assertEqual(items[0].msgdata['listid'],
  161. 'my-list.example.com')
  162. def test_issue140(self):
  163. # Non-UTF-8 data sent to the LMTP server crashes it.
  164. with transaction():
  165. create_list('ant@example.com')
  166. self._lmtp.sendmail('anne@example.com', ['ant@example.com'], b"""\
  167. From: anne@example.com
  168. To: ant@example.com
  169. Subject: My subject
  170. Message-ID: <alpha>
  171. \xa0
  172. """)
  173. items = get_queue_messages('in', expected_count=1)
  174. self.assertEqual(items[0].msg['message-id'], '<alpha>')