def test_add_in_classical_thread(self): # msg1 # |-msg2 # | `-msg4 # `-msg3 msgs = [] for num in range(1, 5): msg = Message() msg["From"] = "*****@*****.**" % num msg["Message-ID"] = "<msg%d>" % num msg.set_payload("message %d" % num) msgs.append(msg) msgs[1]["In-Reply-To"] = "<msg1>" msgs[2]["In-Reply-To"] = "<msg1>" msgs[3]["In-Reply-To"] = "<msg2>" for msg in msgs: add_to_list("example-list", msg) msgs = [] for num in range(1, 5): msg = Email.objects.filter(mailinglist=self.mlist, message_id="msg%d" % num).first() msgs.append(msg) msg1, msg2, msg3, msg4 = msgs # pylint: disable=unbalanced-tuple-unpacking self.assertEqual(msg1.thread_order, 0) self.assertEqual(msg1.thread_depth, 0) self.assertEqual(msg2.thread_order, 1) self.assertEqual(msg2.thread_depth, 1) self.assertEqual(msg3.thread_order, 3) self.assertEqual(msg3.thread_depth, 1) self.assertEqual(msg4.thread_order, 2) self.assertEqual(msg4.thread_depth, 2)
def setUp(self): self.user = User.objects.create_user( 'testuser', '*****@*****.**', 'testPass') self.client.login(username='******', password='******') # Create test data MailingList.objects.create( name="*****@*****.**", subject_prefix="[example] ") # Create 3 threads messages = [] for msgnum in range(3): msg = Message() msg["From"] = "*****@*****.**" msg["Message-ID"] = "<id%d>" % (msgnum+1) msg["Subject"] = "Dummy message %d" % (msgnum+1) msg.set_payload("Dummy message") add_to_list("*****@*****.**", msg) messages.append(msg) # 1st is unread, 2nd is read, 3rd is updated thread_2 = Thread.objects.get(thread_id=get_message_id_hash("<id2>")) thread_3 = Thread.objects.get(thread_id=get_message_id_hash("<id3>")) LastView.objects.create(user=self.user, thread=thread_2) LastView.objects.create(user=self.user, thread=thread_3) msg4 = Message() msg4["From"] = "*****@*****.**" msg4["Message-ID"] = "<id4>" msg4["Subject"] = "Dummy message 4" msg4["In-Reply-To"] = "<id3>" msg4.set_payload("Dummy message") add_to_list("*****@*****.**", msg4)
def test_weird_timezone(self): # An email has a timezone with a strange offset (seen in the wild). # Make sure it does not break our _is_old_enough() method. mbox = mailbox.mbox(os.path.join(self.tmpdir, "test.mbox")) # First message is already imported msg1 = Message() msg1["From"] = "*****@*****.**" msg1["Message-ID"] = "<msg1>" msg1["Date"] = "2008-01-01 12:00:00" msg1.set_payload("msg1") add_to_list("*****@*****.**", msg1) # Second message is in the mbox to import msg2 = Message() msg2["From"] = "*****@*****.**" msg2["Message-ID"] = "<msg2>" msg2["Date"] = "Sat, 30 Aug 2008 16:40:31 +05-30" msg2.set_payload("msg2") mbox.add(msg2) # do the import output = StringIO() kw = self.common_cmd_args.copy() kw["stdout"] = kw["stderr"] = output try: self.command.execute(os.path.join(self.tmpdir, "test.mbox"), **kw) except ValueError as e: self.fail(format_exc(e)) # Message must have been accepted self.assertEqual(MailingList.objects.count(), 1) self.assertEqual(Email.objects.count(), 2)
def test_delete_all_messages_in_thread(self): self.user.is_staff = True self.user.save() msg = Email.objects.get(message_id="msg") msg2 = Message() msg2["From"] = "*****@*****.**" msg2["Message-ID"] = "<msg2>" msg2["In-Reply-To"] = "<msg>" msg2.set_payload("Dummy message") add_to_list("*****@*****.**", msg2) msg2 = Email.objects.get(message_id="msg2") thread_id = msg.thread.pk url = reverse('hk_thread_delete', args=("*****@*****.**", msg.thread.thread_id)) response = self.client.post(url, {"email": [msg.pk, msg2.pk]}) self.assertRedirects( response, reverse('hk_list_overview', kwargs={ "mlist_fqdn": "*****@*****.**"})) # Flash message messages = get_flash_messages(response) self.assertEqual(len(messages), 1) self.assertEqual(messages[0].tags, "success") # Alls messages and the thread must be deleted. self.assertFalse(Email.objects.filter(message_id="msg").exists()) self.assertFalse(Email.objects.filter(message_id="msg2").exists()) self.assertFalse(Thread.objects.filter(pk=thread_id).exists())
def test_vote_cancel(self): msg = Message() msg["From"] = "*****@*****.**" msg["Message-ID"] = "<msg1>" msg.set_payload("Dummy message") add_to_list("*****@*****.**", msg) msg.replace_header("Message-ID", "<msg2>") add_to_list("*****@*****.**", msg) msg1 = Email.objects.get(mailinglist__name="*****@*****.**", message_id="msg1") msg1.vote(1, self.user) msg2 = Email.objects.get(mailinglist__name="*****@*****.**", message_id="msg2") msg2.vote(-1, self.user) self.assertEqual(msg1.get_votes()["likes"], 1) self.assertEqual(msg2.get_votes()["dislikes"], 1) for msg in (msg1, msg2): url = reverse('hk_message_vote', args=("*****@*****.**", msg.message_id_hash)) resp = self.client.post(url, {"vote": "0"}) self.assertEqual(resp.status_code, 200) votes = msg.get_votes() self.assertEqual(votes["likes"], 0) self.assertEqual(votes["dislikes"], 0) result = json.loads(resp.content) self.assertEqual(result["like"], 0) self.assertEqual(result["dislike"], 0)
def test_impacted_threads(self): # existing message msg1 = Message() msg1["From"] = "*****@*****.**" msg1["Message-ID"] = "<msg1>" msg1["Date"] = "2015-01-01 12:00:00" msg1.set_payload("msg1") add_to_list("*****@*****.**", msg1) # new message in the imported mbox msg2 = Message() msg2["From"] = "*****@*****.**" msg2["Message-ID"] = "<msg2>" msg2["Date"] = "2015-02-01 12:00:00" msg2.set_payload("msg1") mbox = mailbox.mbox(os.path.join(self.tmpdir, "test.mbox")) mbox.add(msg2) # do the import output = StringIO() with patch("hyperkitty.management.commands.hyperkitty_import.compute_thread_order_and_depth") as mock_compute: self.command.execute(os.path.join(self.tmpdir, "test.mbox"), verbosity=2, stdout=output, stderr=output, list_address="*****@*****.**", since=None, no_download=True, no_sync_mailman=True, ) #print(mock_compute.call_args_list) self.assertEqual(mock_compute.call_count, 1) thread = mock_compute.call_args[0][0] self.assertEqual(thread.emails.count(), 1) self.assertEqual(thread.starting_email.message_id, "msg2")
def test_get_threads_between(self): # the get_threads_between method should return all threads that have # been active between the two specified dates, including the threads # started in between those dates but updated later msg1 = Message() msg1["From"] = "*****@*****.**" msg1["Message-ID"] = "<msg1>" msg1["Date"] = "2015-02-15 00:00:00 UTC" msg1.set_payload("message 1") add_to_list(self.ml.name, msg1) # The thread started in Feb, it should show up in the Feb threads but # not in the January or March threads. self.assertEqual(Thread.objects.count(), 1) jan_threads = self.ml.get_threads_between( datetime(2015, 1, 1, 0, 0, 0, tzinfo=utc), datetime(2015, 1, 31, 0, 0, 0, tzinfo=utc), ) self.assertEqual(jan_threads.count(), 0) feb_threads = self.ml.get_threads_between( datetime(2015, 2, 1, 0, 0, 0, tzinfo=utc), datetime(2015, 2, 28, 0, 0, 0, tzinfo=utc), ) self.assertEqual(feb_threads.count(), 1) march_threads = self.ml.get_threads_between( datetime(2015, 3, 1, 0, 0, 0, tzinfo=utc), datetime(2015, 3, 31, 0, 0, 0, tzinfo=utc), ) self.assertEqual(march_threads.count(), 0)
def test_since_override(self): # When there's mail already and the "since" option is not used, it # defaults to the last email's date msg1 = Message() msg1["From"] = "*****@*****.**" msg1["Message-ID"] = "<msg1>" msg1["Date"] = "2015-01-01 12:00:00" msg1.set_payload("msg1") add_to_list("*****@*****.**", msg1) mailbox.mbox(os.path.join(self.tmpdir, "test.mbox")) # do the import output = StringIO() with patch("hyperkitty.management.commands.hyperkitty_import.DbImporter" ) as DbImporterMock: instance = Mock() instance.impacted_thread_ids = [] DbImporterMock.side_effect = lambda *a, **kw: instance self.command.execute(os.path.join(self.tmpdir, "test.mbox"), verbosity=2, stdout=output, stderr=output, list_address="*****@*****.**", since="2010-01-01 00:00:00 UTC", no_download=True, no_sync_mailman=True, ) self.assertEqual(DbImporterMock.call_args[0][1]["since"], datetime(2010, 1, 1, tzinfo=utc))
def test_as_message_attachments(self): msg_in = Message() msg_in["From"] = "*****@*****.**" msg_in["Message-ID"] = "<msg>" msg_in.attach(MIMEText("Dummy message")) msg_in.attach(MIMEText("<html><body>Dummy message</body></html>", _subtype="html")) add_to_list("*****@*****.**", msg_in) email = Email.objects.get(message_id="msg") msg = email.as_message() self.assertEqual(msg["From"], "dummy at example.com") self.assertEqual(msg["Message-ID"], "<msg>") self.assertTrue(msg.is_multipart()) payload = msg.get_payload() self.assertEqual(len(payload), 2) self.assertEqual( payload[0].get_payload(decode=True).strip(), "Dummy message") # The filename extension detection from content type is a bit random # (depends on the PYTHON_HASHSEED), make sure we get the right one # here for testing. expected_ext = guess_all_extensions("text/html", strict=False)[0] self.assertEqual(payload[1].get_content_type(), "text/html") self.assertEqual(payload[1]["Content-Disposition"], 'attachment; filename="attachment%s"' % expected_ext) self.assertEqual( payload[1].get_payload(decode=True), "<html><body>Dummy message</body></html>")
def test_get_threads_between_across_two_months(self): # the get_threads_between method should return all threads that have # been active between the two specified dates, including the threads # started in between those dates but updated later msg1 = Message() msg1["From"] = "*****@*****.**" msg1["Message-ID"] = "<msg1>" msg1["Date"] = "2015-01-15 00:00:00 UTC" msg1.set_payload("message 1") add_to_list(self.ml.name, msg1) msg2 = Message() msg2["From"] = "*****@*****.**" msg2["Message-ID"] = "<msg2>" msg2["In-Reply-To"] = "<msg1>" msg2["Date"] = "2015-03-15 00:00:00 UTC" msg2.set_payload("message 2") add_to_list(self.ml.name, msg2) # The thread started in Jan, was updated in March. It should show up in # the Jan, Feb and March threads. self.assertEqual(Thread.objects.count(), 1) jan_threads = self.ml.get_threads_between( datetime(2015, 1, 1, 0, 0, 0, tzinfo=utc), datetime(2015, 1, 31, 0, 0, 0, tzinfo=utc), ) self.assertEqual(jan_threads.count(), 1) feb_threads = self.ml.get_threads_between( datetime(2015, 2, 1, 0, 0, 0, tzinfo=utc), datetime(2015, 2, 28, 0, 0, 0, tzinfo=utc), ) self.assertEqual(feb_threads.count(), 1) march_threads = self.ml.get_threads_between( datetime(2015, 3, 1, 0, 0, 0, tzinfo=utc), datetime(2015, 3, 31, 0, 0, 0, tzinfo=utc), ) self.assertEqual(march_threads.count(), 1)
def test_delete_single_in_thread(self): # Delete an email in a thread that contains other emails self.user.is_staff = True self.user.save() msg = Email.objects.get(message_id="msg") msg2 = Message() msg2["From"] = "*****@*****.**" msg2["Message-ID"] = "<msg2>" msg2["In-Reply-To"] = "<msg>" msg2.set_payload("Dummy message") add_to_list("*****@*****.**", msg2) msg2 = Email.objects.get(message_id="msg2") thread_id = msg.thread.thread_id url = reverse('hk_message_delete', args=("*****@*****.**", msg.message_id_hash)) response = self.client.post(url, {"email": msg.pk}) self.assertRedirects( response, reverse('hk_thread', kwargs={ "mlist_fqdn": "*****@*****.**", "threadid": thread_id})) # Flash message messages = get_flash_messages(response) self.assertEqual(len(messages), 1) self.assertEqual(messages[0].tags, "success") # The message must be deleted, but not the other message or the thread. self.assertFalse(Email.objects.filter(message_id="msg").exists()) self.assertTrue(Email.objects.filter(message_id="msg2").exists()) thread = Thread.objects.get(thread_id=thread_id) self.assertIsNotNone(thread) # msg2 must now be the thread starter. msg2.refresh_from_db() self.assertIsNone(msg2.parent_id) self.assertEqual(thread.starting_email.message_id, "msg2")
def setUp(self): # Create the list by adding a dummy message msg = Message() msg["From"] = "*****@*****.**" msg["Message-ID"] = "<msg>" msg.set_payload("Dummy message") add_to_list("*****@*****.**", msg)
def from_mbox(self, mbfile): """ Insert all the emails contained in an mbox file into the database. :arg mbfile: a mailbox file """ #self.store.search_index = make_delayed(self.store.search_index) mbox = mailbox.mbox(mbfile) progress_marker = ProgressMarker(self.verbose, self.stdout) if not self.since: progress_marker.total = len(mbox) for message in mbox: if self._is_too_old(message): continue progress_marker.tick(message["Message-Id"]) # Un-wrap the subject line if necessary if message["subject"]: message.replace_header("subject", TEXTWRAP_RE.sub(" ", message["subject"])) # Now insert the message try: with transaction.atomic(): add_to_list(self.list_address, message) except DuplicateMessage as e: if self.verbose: self.stderr.write( "Duplicate email with message-id '%s'" % e.args[0]) continue except ValueError as e: if len(e.args) != 2: raise # Regular ValueError exception try: self.stderr.write("%s from %s about %s" % (e.args[0], e.args[1].get("From"), e.args[1].get("Subject"))) except UnicodeDecodeError: self.stderr.write("%s with message-id %s" % (e.args[0], e.args[1].get("Message-ID"))) continue except DatabaseError: try: print_exc(file=self.stderr) except UnicodeError: pass self.stderr.write("Message %s failed to import, skipping" % unquote(message["Message-Id"])) continue email = Email.objects.get( mailinglist__name=self.list_address, message_id=get_message_id(message)) ## Commit every time to be able to rollback on error #if not transaction.get_autocommit(): # transaction.commit() # Store the list of impacted threads to be able to compute the # thread_order and thread_depth values self.impacted_thread_ids.add(email.thread_id) progress_marker.count_imported += 1 #self.store.search_index.flush() # Now commit to the search index progress_marker.finish()
def test_attachment_insert_order(self): """Attachments must not be inserted in the DB before the email""" with open(get_test_file("attachment-1.txt")) as email_file: msg = message_from_file(email_file) try: add_to_list("example-list", msg) except IntegrityError, e: self.fail(e)
def setUp(self): self.user = User.objects.create(username="******") msg = Message() msg["From"] = "*****@*****.**" msg["Message-ID"] = "<msg>" msg.set_payload("message") add_to_list("example-list", msg) self.thread = Thread.objects.all()[0]
def test_get_sender_name(self): msg = Message() msg["From"] = "Sender Name <*****@*****.**>" msg["Message-ID"] = "<dummy>" msg.set_payload("Dummy message") add_to_list("example-list", msg) self.assertEqual(Email.objects.count(), 1) stored_msg = Email.objects.all()[0] self.assertEqual(stored_msg.sender.name, "Sender Name")
def test_date_aware(self): msg = Message() msg["From"] = "*****@*****.**" msg["Message-ID"] = "<dummy>" msg["Date"] = "Fri, 02 Nov 2012 16:07:54 +0100" msg.set_payload("Dummy message") try: add_to_list("example-list", msg) except IntegrityError, e: self.fail(e)
def test_as_message_timezone(self): msg_in = Message() msg_in["From"] = "*****@*****.**" msg_in["Message-ID"] = "<msg>" msg_in["Date"] = "Fri, 02 Nov 2012 16:07:54 +0400" msg_in.set_payload("Dummy message") add_to_list("*****@*****.**", msg_in) email = Email.objects.get(message_id="msg") msg = email.as_message() self.assertEqual(msg["Date"], msg_in["Date"])
def test_non_ascii_email_address(self): """Non-ascii email addresses should raise a ValueError exception""" msg = Message() msg["From"] = b"dummy-non-ascii-\xc3\[email protected]" msg["Message-ID"] = "<dummy>" msg.set_payload("Dummy message") try: add_to_list("example-list", msg) except ValueError, e: self.assertEqual(e.__class__.__name__, "ValueError")
def setUp(self): # Create the list by adding a dummy message # The message must be old to create multiple year accordion panels in # the months list. msg = Message() msg["From"] = "*****@*****.**" msg["Message-ID"] = "<msg>" msg["Date"] = "2010-02-01 00:00:00 UTC" msg.set_payload("Dummy message") add_to_list("*****@*****.**", msg)
def test_duplicate(self): msg = Message() msg["From"] = "*****@*****.**" msg["Message-ID"] = "<dummy>" msg.set_payload("Dummy message") add_to_list("example-list", msg) mlist = MailingList.objects.get(name="example-list") self.assertEqual(mlist.emails.count(), 1) self.assertTrue(mlist.emails.filter(message_id="dummy").exists()) self.assertRaises(DuplicateMessage, add_to_list, "example-list", msg) self.assertEqual(mlist.emails.count(), 1)
def test_subject(self): msg = Message() msg["From"] = "*****@*****.**" msg["Message-ID"] = "<dummymsg>" msg["Date"] = "Fri, 02 Nov 2012 16:07:54 +0000" msg["Subject"] = "Dummy subject" msg.set_payload("Dummy message") add_to_list("example-list", msg) self.assertEqual(Thread.objects.count(), 1) thread = Thread.objects.all()[0] self.assertEqual(thread.subject, "Dummy subject")
def test_between_dates(self): msg = Message() msg["From"] = "*****@*****.**" msg["Date"] = "2015-09-01 00:00:00" msg["Message-ID"] = "<msg2>" msg.set_payload("Dummy message") add_to_list("*****@*****.**", msg) mbox = self._get_mbox(qs="start=2015-09-01&end=2015-10-01") self.assertEqual(len(mbox), 1) mbox_msg = mbox.values()[0] self.assertEqual(mbox_msg["Message-ID"], "<msg2>")
def setUp(self): self.user = User.objects.create_user('testuser', '*****@*****.**', 'testPass') self.client.login(username='******', password='******') # Create a dummy message to test on msg = Message() msg["From"] = "Dummy Sender <*****@*****.**>" msg["Subject"] = "Dummy Subject" msg["Date"] = "Mon, 02 Feb 2015 13:00:00 +0300" msg["Message-ID"] = "<msg>" msg.set_payload("Dummy message") add_to_list("*****@*****.**", msg)
def test_email_escaped_body(self): msg = Message() msg["From"] = "Dummy Sender <*****@*****.**>" msg["Subject"] = "Dummy Subject" msg["Date"] = "Mon, 02 Feb 2015 13:00:00 +0300" msg["Message-ID"] = "<msgid2>" msg["In-Reply-To"] = "<msgid>" msg.set_payload("Email address: [email protected]") add_to_list("*****@*****.**", msg) url = reverse('hk_thread', args=["*****@*****.**", self.threadid]) response = self.client.get(url) self.assertNotContains(response, "*****@*****.**", status_code=200)
def test_long_message_id(self): # Some message-ids are more than 255 chars long # Check with assert here because SQLite will not enforce the limit # (http://www.sqlite.org/faq.html#q9) msg = Message() msg["From"] = "*****@*****.**" msg["Message-ID"] = "X" * 260 msg.set_payload("Dummy message") try: add_to_list("example-list", msg) except IntegrityError, e: self.fail(e)
def test_email_escaped_sender(self): msg = Message() msg["From"] = "*****@*****.**" msg["Subject"] = "Dummy Subject" msg["Date"] = "Mon, 02 Feb 2015 13:00:00 +0300" msg["Message-ID"] = "<msg2>" msg.set_payload("Dummy content") add_to_list("*****@*****.**", msg) url = reverse('hk_message_index', args=("*****@*****.**", get_message_id_hash("msg2"))) response = self.client.get(url) self.assertNotContains(response, "*****@*****.**", status_code=200)
def setUp(self): self.user = User.objects.create_user( 'testuser', '*****@*****.**', 'testPass') self.client.login(username='******', password='******') # Create a dummy message to test on msg = Message() msg["From"] = "Dummy Sender <*****@*****.**>" msg["Subject"] = "Dummy Subject" msg["Date"] = "Mon, 02 Feb 2015 13:00:00 +0300" msg["Message-ID"] = "<msg>" msg.set_payload("Dummy message") add_to_list("*****@*****.**", msg)
def test_do_not_catch_exceptions(self): class SpecificError(Exception): pass def boom(sender, **kwargs): # pylint: disable=unused-argument raise SpecificError new_email.connect(boom) msg = self._make_message() try: add_to_list("example-list", msg) except SpecificError: pass else: self.fail("The exception should have been propagated")
def test_long_subject(self): msg = Message() msg["From"] = "*****@*****.**" msg["Message-ID"] = "<dummy>" msg["Subject"] = "x" * 600 msg.set_payload("Dummy message") try: add_to_list("example-list", msg) except IntegrityError as e: self.fail(e) self.assertEqual(Email.objects.count(), 1) stored_msg = Email.objects.all()[0] self.assertEqual(len(stored_msg.subject), 512)
def _create_tree(self, tree): emails = [] for msgid in tree: msg = Message() msg["From"] = "*****@*****.**" msg["Message-ID"] = "<%s>" % msgid parent_id = msgid.rpartition(".")[0] if Email.objects.filter(message_id=parent_id).exists(): msg["In-Reply-To"] = "<%s>" % parent_id msg.set_payload("dummy message") add_to_list("example-list", msg) emails.append(Email.objects.get(message_id=msgid)) return emails
def test_no_sender_name_or_address(self): msg = Message() msg["From"] = "" msg["Message-ID"] = "<dummy>" msg.set_payload("Dummy message") try: add_to_list("example-list", msg) except IntegrityError as e: self.fail(e) self.assertEqual(Email.objects.count(), 1) stored_msg = Email.objects.all()[0] self.assertEqual(stored_msg.sender.name, "") self.assertEqual(stored_msg.sender.address, "*****@*****.**")
def test_no_sender_name_or_address(self): msg = EmailMessage() msg["From"] = "" msg["Message-ID"] = "<dummy>" msg.set_payload("Dummy message") try: add_to_list("example-list", msg) except IntegrityError as e: self.fail(e) self.assertEqual(Email.objects.count(), 1) stored_msg = Email.objects.all()[0] self.assertEqual(stored_msg.sender_name, "") self.assertEqual(stored_msg.sender.address, "*****@*****.**")
def test_long_subject(self): msg = EmailMessage() msg["From"] = "*****@*****.**" msg["Message-ID"] = "<dummy>" msg["Subject"] = "x" * 600 msg.set_payload("Dummy message") try: add_to_list("example-list", msg) except IntegrityError as e: self.fail(e) self.assertEqual(Email.objects.count(), 1) stored_msg = Email.objects.all()[0] self.assertEqual(len(stored_msg.subject), 512)
def test_archived_date_unparseable(self): msg = EmailMessage() msg["From"] = "*****@*****.**" msg["Subject"] = "Fake Subject" msg["Message-ID"] = "<dummy>" msg["Date"] = "Fri, 02 Nov 2012 16:07:54" msg.set_payload("Fake Message") msg.set_unixfrom("[email protected] Something that cant be parsed") add_to_list("example-list", msg) self.assertEqual(Email.objects.count(), 1) stored_msg = Email.objects.all()[0] one_hour_ago = timezone.now() - datetime.timedelta(hours=1) self.assertTrue(stored_msg.archived_date > one_hour_ago)
def test_no_date(self): msg = EmailMessage() msg["From"] = "*****@*****.**" msg["Message-ID"] = "<dummy>" msg.set_payload("Dummy message") now = timezone.now() try: add_to_list("example-list", msg) except IntegrityError as e: self.fail(e) self.assertEqual(Email.objects.count(), 1) stored_msg = Email.objects.all()[0] self.assertTrue(stored_msg.date >= now)
def test_non_ascii_email_address(self): """Non-ascii email addresses should raise a ValueError exception""" msg = EmailMessage(policy=default) msg["From"] = "dummy-non-ascii-\xc3\[email protected]" msg["Message-ID"] = "<dummy>" msg.set_payload("Dummy message") try: add_to_list("example-list", msg) except ValueError as e: self.assertEqual(e.__class__.__name__, "ValueError") else: self.fail("No ValueError was raised") self.assertEqual( MailingList.objects.get(name="example-list").emails.count(), 0)
def test_archived_date(self): msg = EmailMessage() msg["From"] = "*****@*****.**" msg["Subject"] = "Fake Subject" msg["Message-ID"] = "<dummy>" msg["Date"] = "Fri, 02 Nov 2012 16:07:54" msg.set_payload("Fake Message") msg.set_unixfrom("[email protected] Mon Jul 21 11:59:48 2013") add_to_list("example-list", msg) self.assertEqual(Email.objects.count(), 1) stored_msg = Email.objects.all()[0] self.assertEqual( stored_msg.archived_date, datetime.datetime(2013, 7, 21, 11, 59, 48, tzinfo=timezone.utc))
def test_as_message_unicode(self): msg_in = EmailMessage() msg_in["From"] = "*****@*****.**" msg_in["Message-ID"] = "<msg>" msg_in.set_payload("Dummy message ünîcödé", charset="utf-8") add_to_list("*****@*****.**", msg_in) email = Email.objects.get(message_id="msg") msg = email.as_message() self.assertEqual(msg["From"], "*****@*****.**") self.assertEqual(msg["Message-ID"], "<msg>") self.assertTrue(msg.is_multipart()) payload = msg.get_payload() self.assertEqual(len(payload), 1) payload = payload[0] self.assertEqual(payload.get_payload(), "Dummy message ünîcödé\n")
def archive(request): if request.method != 'POST': raise SuspiciousOperation mlist_fqdn = request.POST["mlist"] if "message" not in request.FILES: raise SuspiciousOperation msg = message_from_file(request.FILES['message']) try: add_to_list(mlist_fqdn, msg) except DuplicateMessage as e: logger.info("Duplicate email with message-id '%s'", e.args[0]) url = _get_url(mlist_fqdn, msg['Message-Id']) logger.info("Archived message %s to %s", msg['Message-Id'], url) return HttpResponse(json.dumps({"url": url}), content_type='application/javascript')
def _send_message(self): msg = EmailMessage() msg["From"] = "Dummy Sender <*****@*****.**>" msg["Message-ID"] = "<msg>" msg["Subject"] = "Dummy message" msg.set_payload("Dummy content") return add_to_list("*****@*****.**", msg)
def test_top_participants(self): expected = [ ("name3", "email3", 3), ("name2", "email2", 2), ("name1", "email1", 1), ] for name, email, count in expected: for num in range(count): msg = Message() msg["From"] = "%s <%s>" % (name, email) msg["Message-ID"] = "<%s_%s>" % (name, num) msg.set_payload("Dummy message") add_to_list("example-list", msg) mlist = MailingList.objects.get(name="example-list") result = [(p.name, p.address, p.count) for p in mlist.top_posters] self.assertEqual(expected, result)
def _send_message(self, mlist): msg = Message() msg["From"] = "Dummy Sender <*****@*****.**>" msg["Message-ID"] = "<msg>" msg["Subject"] = "Dummy message" msg.set_payload("Dummy content with keyword") return add_to_list(mlist.name, msg)
def test_email_in_link_in_body(self): msg = Message() msg["From"] = "Dummy Sender <*****@*****.**>" msg["Subject"] = "Dummy Subject" msg["Date"] = "Mon, 02 Feb 2015 13:00:00 +0300" msg["Message-ID"] = "<msgid2>" msg["In-Reply-To"] = "<msgid>" link = "http://example.com/list/[email protected]/message" msg.set_payload("Email address in link: %s" % link) add_to_list("*****@*****.**", msg) url = reverse('hk_thread', args=["*****@*****.**", self.threadid]) response = self.client.get(url) self.assertContains( response, '<a href="{0}" rel="nofollow">{0}</a>'.format(link), status_code=200)
def _add_message(self, msgid="msg", list="*****@*****.**"): msg = EmailMessage() msg["From"] = "Dummy Sender <*****@*****.**>" msg["Message-ID"] = "<%s>" % msgid msg["Subject"] = "Dummy message" msg.set_payload("Dummy content with keyword") return add_to_list(list, msg)
def test_same_msgid_different_lists(self): # Vote on messages with the same msgid but on different lists msg = Message() msg["From"] = "*****@*****.**" msg["Message-ID"] = "<msg>" msg.set_payload("message") add_to_list("example-list-1", msg) add_to_list("example-list-2", msg) self.assertEqual(Email.objects.count(), 2) for msg in Email.objects.all(): msg.vote(1, self.user) self.assertEqual(Thread.objects.count(), 2) for thread in Thread.objects.all(): votes = thread.get_votes() self.assertEqual(votes["likes"], 1) self.assertEqual(votes["dislikes"], 0)
def test_non_ascii_text_attachment_declared_as_ascii(self): # Some defective mail has a text attachment declared as ascii but # containing non-ascii. We should just replace the non-ascii character. with open(get_test_file("attachment-4.txt")) as email_file: msg = message_from_file(email_file, EmailMessage, policy=default) try: add_to_list("example-list", msg) except Exception as e: self.fail(e) self.assertEqual(Attachment.objects.count(), 1) self.assertEqual( Attachment.objects.all()[0].content, b'All votes are reported in the form "*Y-N-A*" ' b'(*in favor-Y???opposed-N???abstentions-A*; e.g. ' b'"5-1-2" means "5 in favor, 1 opposed, and 2 ' b'abstentions").\n')
def test_duplicate_nonascii(self): msg = EmailMessage() msg["From"] = "*****@*****.**" msg["Message-ID"] = "<dummy>" msg.set_payload("Dummy message") add_to_list("example-list", msg) mlist = MailingList.objects.get(name="example-list") self.assertEqual(mlist.emails.count(), 1) self.assertTrue(mlist.emails.filter(message_id="dummy").exists()) msg.replace_header("From", "dummy-non-ascii\xc3\[email protected]") try: self.assertRaises(DuplicateMessage, add_to_list, "example-list", msg) except UnicodeDecodeError as e: self.fail("Died on a non-ascii header message: %s" % (e)) self.assertEqual(mlist.emails.count(), 1)
def test_order(self): # The Thread instances returned by get_or_set() should be returned in # the order of the list returned by get_value(). # Create users to vote users = [] for uid in range(20): users.append(User.objects.create(username="******" % uid)) # Create the threads to be voted on votes_count = list(range(1, 21)) shuffle(votes_count) # Add the emails in random order for votes_num in votes_count: msg = EmailMessage() msg["From"] = "*****@*****.**" msg["Message-ID"] = "<msg%d>" % votes_num msg["Date"] = datetime.now().strftime("%d %b %Y %H:%M:%S %Z") msg.set_payload("message %d" % votes_num) msg_id = add_to_list(self.ml.name, msg) # Vote on the thread thread = Thread.objects.get(thread_id=msg_id) for uid in range(votes_num): thread.starting_email.vote(1, users[uid]) # The PopularThreads value should be reverse-sorted by vote. self.assertListEqual( [t.starting_email.message_id for t in self.cached_value()], ["msg%d" % i for i in range(20, 0, -1)])
def test_starting_message_1(self): # A basic thread: msg2 replies to msg1 msg1 = EmailMessage() msg1["From"] = "*****@*****.**" msg1["Message-ID"] = "<msg1>" msg1.set_payload("message 1") add_to_list("example-list", msg1) msg2 = EmailMessage() msg2["From"] = "*****@*****.**" msg2["Message-ID"] = "<msg2>" msg2.set_payload("message 2") msg2["In-Reply-To"] = msg1["Message-ID"] add_to_list("example-list", msg2) self.assertEqual(Thread.objects.count(), 1) thread = Thread.objects.all()[0] self.assertEqual(thread.starting_email.message_id, "msg1")
def test_display_fixed(self): msg = Message() msg["From"] = "Dummy Sender <*****@*****.**>" msg["Subject"] = "Dummy Subject" msg["Date"] = "Mon, 02 Feb 2015 13:00:00 +0300" msg["Message-ID"] = "<msg2>" msg.set_payload("Dummy message with @@ signs (looks like a patch)") add_to_list("*****@*****.**", msg) url1 = reverse('hk_message_index', args=("*****@*****.**", get_message_id_hash("msg"))) response1 = self.client.get(url1) self.assertNotContains(response1, "email-body fixed", status_code=200) url2 = reverse('hk_message_index', args=("*****@*****.**", get_message_id_hash("msg2"))) response2 = self.client.get(url2) self.assertContains(response2, "email-body fixed", status_code=200)
def setUp(self): self.user = User.objects.create_user('testuser', '*****@*****.**', 'testPass') MailingList.objects.create(name="*****@*****.**", subject_prefix="[example] ", archive_policy=ArchivePolicy.private.value) msg = Message() msg["From"] = "*****@*****.**" msg["Message-ID"] = "<msgid>" msg["Subject"] = "Dummy message" msg.set_payload("Dummy message") msg["Message-ID-Hash"] = self.msgid = add_to_list( "*****@*****.**", msg) # Set the mailman_client after the message has been added to the list, # otherwise MailingList.update_from_mailman() will overwrite the list # properties. self.mailman_client.get_list.side_effect = \ lambda name: FakeMMList(name) self.mm_user = Mock() self.mm_user.user_id = "dummy" self.mailman_client.get_user.side_effect = lambda name: self.mm_user self.mm_user.subscriptions = [ FakeMMMember("list.example.com", self.user.email), ] self.mm_user.addresses = ['*****@*****.**']
def setUp(self): MailingList.objects.create(name="*****@*****.**", subject_prefix="[example] ", archive_policy=ArchivePolicy.private.value) msg = EmailMessage() msg["From"] = "*****@*****.**" msg["Message-ID"] = "<msgid>" msg["Subject"] = "Dummy message" msg.set_payload("Dummy message") msg["Message-ID-Hash"] = self.msgid = add_to_list( "*****@*****.**", msg) self.mailman_client.get_list.side_effect = \ lambda name: FakeMMList(name) User.objects.create_user('superuser', '*****@*****.**', 'testPass', is_superuser=True) self.mm_subbed_user = self._create_user('subbeduser', '*****@*****.**') self.mm_subbed_user.subscriptions = [ FakeMMMember("list.example.com", '*****@*****.**'), ] self.mm_unsubbed_user = self._create_user('unsubbeduser', '*****@*****.**') self.mm_unsubbed_user.subscriptions = [] def mm_get_user(email): if email == '*****@*****.**': return self.mm_subbed_user else: return self.mm_unsubbed_user self.mailman_client.get_user.side_effect = mm_get_user
def _create_email(num, reply_to=None): msg = EmailMessage() msg["From"] = "*****@*****.**" % num msg["Message-ID"] = "<msg%d>" % num msg.set_payload("message %d" % num) if reply_to is not None: msg["In-Reply-To"] = "<msg%d>" % reply_to return add_to_list("example-list", msg)
def test_thread(self): msg = Message() msg["From"] = "*****@*****.**" msg["Message-ID"] = "<msg2>" msg["In-Reply-To"] = "<msg>" msg.set_payload("Dummy message") add_to_list("*****@*****.**", msg) # Add a message in a different thread: msg = Message() msg["From"] = "*****@*****.**" msg["Message-ID"] = "<msg3>" msg.set_payload("Dummy message") add_to_list("*****@*****.**", msg) thread_id = Email.objects.get(message_id="msg").thread.thread_id mbox = self._get_mbox(qs="thread=%s" % thread_id) self.assertEqual(len(mbox), 2) self.assertEqual([m["Message-ID"] for m in mbox], ["<msg>", "<msg2>"])
def test_starting_message_2(self): # A partially-imported thread: msg1 replies to something we don't have msg1 = EmailMessage() msg1["From"] = "*****@*****.**" msg1["Message-ID"] = "<msg1>" msg1["In-Reply-To"] = "<msg0>" msg1.set_payload("message 1") add_to_list("example-list", msg1) msg2 = EmailMessage() msg2["From"] = "*****@*****.**" msg2["Message-ID"] = "<msg2>" msg2["In-Reply-To"] = msg1["Message-ID"] msg2.set_payload("message 2") add_to_list("example-list", msg2) self.assertEqual(Thread.objects.count(), 1) thread = Thread.objects.all()[0] self.assertEqual(thread.starting_email.message_id, "msg1")
def test_long_message_id(self): # Some message-ids are more than 255 chars long # Check with assert here because SQLite will not enforce the limit # (http://www.sqlite.org/faq.html#q9) msg = EmailMessage() msg["From"] = "*****@*****.**" msg["Message-ID"] = "X" * 260 msg.set_payload("Dummy message") try: add_to_list("example-list", msg) except IntegrityError as e: self.fail(e) self.assertEqual(Email.objects.count(), 1) stored_msg = Email.objects.all()[0] self.assertTrue( len(stored_msg.message_id) <= 255, "Very long message-id headers are not truncated")