def test_hold_chain(self): msg = mfs("""\ From: [email protected] To: [email protected] Subject: A message Message-ID: <ant> MIME-Version: 1.0 A message body. """) msgdata = dict(moderation_reasons=[ 'TEST-REASON-1', 'TEST-REASON-2', ]) logfile = LogFileMark('mailman.vette') process_chain(self._mlist, msg, msgdata, start_chain='hold') messages = get_queue_messages('virgin', expected_count=2) payloads = {} for item in messages: if item.msg['to'] == '*****@*****.**': part = item.msg.get_payload(0) payloads['owner'] = part.get_payload().splitlines() elif item.msg['To'] == '*****@*****.**': payloads['sender'] = item.msg.get_payload().splitlines() else: self.fail('Unexpected message: %s' % item.msg) self.assertIn(' TEST-REASON-1', payloads['owner']) self.assertIn(' TEST-REASON-2', payloads['owner']) self.assertIn(' TEST-REASON-1', payloads['sender']) self.assertIn(' TEST-REASON-2', payloads['sender']) logged = logfile.read() self.assertIn('TEST-REASON-1', logged) self.assertIn('TEST-REASON-2', logged)
def test_reject(self): msgdata = dict( dmarc_action='reject', moderation_reasons=['DMARC violation'], ) # When a message is reject, an event will be triggered and the message # will be bounced. events = [] def handler(event): # noqa: E306 if isinstance(event, RejectEvent): events.append(event) with event_subscribers(handler): process_chain(self._mlist, self._msg, msgdata, start_chain='dmarc') self.assertEqual(len(events), 1) self.assertIs(events[0].msg, self._msg) items = get_queue_messages('virgin', expected_count=1) # Unpack the rejection message. rejection = items[0].msg.get_payload(0).get_payload() self.assertEqual( rejection, """\ Your message to the Ant mailing-list was rejected for the following reasons: DMARC violation The original message as received by Mailman is attached. """)
def test_hold_chain_charset(self): # Issue #144 - UnicodeEncodeError in the hold chain. self._mlist.admin_immed_notify = True self._mlist.respond_to_post_requests = False path = resource_filename('mailman.chains.tests', 'issue144.eml') with open(path, 'rb') as fp: msg = mfb(fp.read()) msg.sender = '*****@*****.**' process_chain(self._mlist, msg, {}, start_chain='hold') # The postauth.txt message is now in the virgin queue awaiting # delivery to the moderators. items = get_queue_messages('virgin', expected_count=1) msgdata = items[0].msgdata self.assertTrue(msgdata['tomoderators']) self.assertEqual(msgdata['recipients'], {'*****@*****.**'}) # Ensure that the subject looks correct in the postauth.txt. msg = items[0].msg value = None for line in msg.get_payload(0).get_payload().splitlines(): if line.strip().startswith('Subject:'): header, colon, value = line.partition(':') break self.assertEqual(value.lstrip(), 'Vi?enamjenski pi?tolj za vodu 8/1') self.assertEqual( msg['Subject'], '[email protected] post from [email protected] requires approval')
def test_hold_chain_charset(self): # Issue #144 - UnicodeEncodeError in the hold chain. self._mlist.admin_immed_notify = True self._mlist.respond_to_post_requests = False bart = self._user_manager.create_user('*****@*****.**', 'Bart User') address = set_preferred(bart) self._mlist.subscribe(address, MemberRole.moderator) path = resource_filename('mailman.chains.tests', 'issue144.eml') with open(path, 'rb') as fp: msg = mfb(fp.read()) msg.sender = '*****@*****.**' process_chain(self._mlist, msg, {}, start_chain='hold') # The postauth.txt message is now in the virgin queue awaiting # delivery to the moderators. items = get_queue_messages('virgin', expected_count=1) msgdata = items[0].msgdata # Should get sent to -owner address. self.assertEqual(msgdata['recipients'], {'*****@*****.**'}) # Ensure that the subject looks correct in the postauth.txt. msg = items[0].msg value = None for line in msg.get_payload(0).get_payload().splitlines(): if line.strip().startswith('Subject:'): header, colon, value = line.partition(':') break self.assertEqual(value.lstrip(), 'Vi?enamjenski pi?tolj za vodu 8/1') self.assertEqual( msg['Subject'], '[email protected] post from [email protected] requires approval')
def test_hold_chain_crosspost(self): mlist2 = create_list('*****@*****.**') msg = mfs("""\ From: [email protected] To: [email protected], [email protected] Subject: A message Message-ID: <ant> MIME-Version: 1.0 A message body. """) process_chain(self._mlist, msg, {}, start_chain='hold') process_chain(mlist2, msg, {}, start_chain='hold') # There are four items in the virgin queue. Two of them are for the # list owners who need to moderate the held message, and the other is # for anne telling her that her message was held for approval. items = get_queue_messages('virgin', expected_count=4) anne_froms = set() owner_tos = set() for item in items: if item.msg['to'] == '*****@*****.**': anne_froms.add(item.msg['from']) else: owner_tos.add(item.msg['to']) self.assertEqual( anne_froms, set(['*****@*****.**', '*****@*****.**'])) self.assertEqual( owner_tos, set(['*****@*****.**', '*****@*****.**'])) # And the message appears in the store. messages = list(getUtility(IMessageStore).messages) self.assertEqual(len(messages), 1) self.assertEqual(messages[0]['message-id'], '<ant>')
def test_hold_chain_crosspost(self): mlist2 = create_list('*****@*****.**') msg = mfs("""\ From: [email protected] To: [email protected], [email protected] Subject: A message Message-ID: <ant> MIME-Version: 1.0 A message body. """) process_chain(self._mlist, msg, {}, start_chain='hold') process_chain(mlist2, msg, {}, start_chain='hold') # There are four items in the virgin queue. Two of them are for the # list owners who need to moderate the held message, and the other is # for anne telling her that her message was held for approval. items = get_queue_messages('virgin', expected_count=4) anne_froms = set() owner_tos = set() for item in items: if item.msg['to'] == '*****@*****.**': anne_froms.add(item.msg['from']) else: owner_tos.add(item.msg['to']) self.assertEqual(anne_froms, set(['*****@*****.**', '*****@*****.**'])) self.assertEqual(owner_tos, set(['*****@*****.**', '*****@*****.**'])) # And the message appears in the store. messages = list(getUtility(IMessageStore).messages) self.assertEqual(len(messages), 1) self.assertEqual(messages[0]['message-id'], '<ant>')
def test_discard_no_reasons(self): # The log message contains n/a if no moderation reasons. msgdata = {} log_file = LogFileMark('mailman.vette') process_chain(self._mlist, self._msg, msgdata, start_chain='discard') log_entry = log_file.read() self.assertIn('DISCARD: <*****@*****.**>', log_entry) self.assertIn('[n/a]', log_entry)
def test_discard_reasons(self): # The log message must contain the moderation reasons. msgdata = dict(moderation_reasons=['TEST-REASON-1', 'TEST-REASON-2']) log_file = LogFileMark('mailman.vette') process_chain(self._mlist, self._msg, msgdata, start_chain='discard') log_entry = log_file.read() self.assertIn('DISCARD: <*****@*****.**>', log_entry) self.assertIn('TEST-REASON-1', log_entry) self.assertIn('TEST-REASON-2', log_entry)
def test_rule_hits(self): config.chains['mine'] = MyChain() self.addCleanup(config.chains.pop, 'mine') hits = None def handler(event): # noqa: E306 nonlocal hits if isinstance(event, AcceptEvent): hits = event.msg['x-mailman-rule-hits'] with event_subscribers(handler): process_chain(self._mlist, self._msg, {}, start_chain='mine') self.assertEqual(hits, 'first; second; third')
def test_reject_reasons(self): # The bounce message must contain the moderation reasons. msgdata = dict(moderation_reasons=[ 'TEST-REASON-1', 'TEST-REASON-2', ]) process_chain(self._mlist, self._msg, msgdata, start_chain='reject') bounces = get_queue_messages('virgin', expected_count=1) payload = bounces[0].msg.get_payload(0).as_string() self.assertIn('TEST-REASON-1', payload) self.assertIn('TEST-REASON-2', payload)
def test_rule_hits(self): config.chains['mine'] = MyChain() self.addCleanup(config.chains.pop, 'mine') hits = None def handler(event): # noqa nonlocal hits if isinstance(event, AcceptEvent): hits = event.msg['x-mailman-rule-hits'] with event_subscribers(handler): process_chain(self._mlist, self._msg, {}, start_chain='mine') self.assertEqual(hits, 'first; second; third')
def test_discard(self): msgdata = dict(dmarc_action='discard') # When a message is discarded, the only artifacts are a log message # and an event. Catch the event to prove it happened. events = [] def handler(event): # noqa: E306 if isinstance(event, DiscardEvent): events.append(event) with event_subscribers(handler): process_chain(self._mlist, self._msg, msgdata, start_chain='dmarc') self.assertEqual(len(events), 1) self.assertIs(events[0].msg, self._msg)
def test_hold_chain_no_reasons_given(self): msg = mfs("""\ From: [email protected] To: [email protected] Subject: A message Message-ID: <ant> MIME-Version: 1.0 A message body. """) process_chain(self._mlist, msg, {}, start_chain='hold') # No reason was given, so a default is used. requests = IListRequests(self._mlist) self.assertEqual(requests.count_of(RequestType.held_message), 1) request = requests.of_type(RequestType.held_message)[0] key, data = requests.get_request(request.id) self.assertEqual(data.get('_mod_reason'), 'n/a')
def test_hold_chain(self): msg = mfs("""\ From: [email protected] To: [email protected] Subject: A message Message-ID: <ant> MIME-Version: 1.0 A message body. """) msgdata = dict(moderation_reasons=[ 'TEST-REASON-1', 'TEST-REASON-2', ('TEST-{}-REASON-{}', 'FORMAT', 3), ]) logfile = LogFileMark('mailman.vette') process_chain(self._mlist, msg, msgdata, start_chain='hold') messages = get_queue_messages('virgin', expected_count=2) payloads = {} for item in messages: if item.msg['to'] == '*****@*****.**': part = item.msg.get_payload(0) payloads['owner'] = part.get_payload().splitlines() elif item.msg['To'] == '*****@*****.**': payloads['sender'] = item.msg.get_payload().splitlines() else: self.fail('Unexpected message: %s' % item.msg) self.assertIn(' TEST-REASON-1', payloads['owner']) self.assertIn(' TEST-REASON-2', payloads['owner']) self.assertIn(' TEST-FORMAT-REASON-3', payloads['owner']) self.assertIn(' TEST-REASON-1', payloads['sender']) self.assertIn(' TEST-REASON-2', payloads['sender']) self.assertIn(' TEST-FORMAT-REASON-3', payloads['sender']) logged = logfile.read() self.assertIn('TEST-REASON-1', logged) self.assertIn('TEST-REASON-2', logged) self.assertIn('TEST-FORMAT-REASON-3', logged) # Check the reason passed to hold_message(). requests = IListRequests(self._mlist) self.assertEqual(requests.count_of(RequestType.held_message), 1) request = requests.of_type(RequestType.held_message)[0] key, data = requests.get_request(request.id) self.assertEqual( data.get('_mod_reason'), 'TEST-REASON-1; TEST-REASON-2; TEST-FORMAT-REASON-3')
def test_no_reason(self): # There may be no moderation reasons. process_chain(self._mlist, self._msg, {}, start_chain='reject') bounces = get_queue_messages('virgin', expected_count=1) payload = bounces[0].msg.get_payload(0).as_string() self.assertIn('No bounce details are available', payload)