def test_running_total(self): tasks.statistics.delay() stats = models.Statistic.objects.get() self.assertEqual(stats.emails["email_count__sum"], 0) self.assertEqual(stats.emails["running_total"], 0) stats.delete() factories.InboxFactory() factories.EmailFactory.create_batch(2) # first count tasks.statistics.delay() stats = models.Statistic.objects.get() self.assertEqual(stats.emails["email_count__sum"], 2) self.assertEqual(stats.emails["running_total"], 2) # running total should not have gone down models.Email.objects.first().delete() tasks.statistics.delay() stats = models.Statistic.objects.latest("date") self.assertEqual(stats.emails["email_count__sum"], 1) self.assertEqual(stats.emails["running_total"], 2) # running total should now increase factories.EmailFactory() tasks.statistics.delay() stats = models.Statistic.objects.latest("date") self.assertEqual(stats.emails["email_count__sum"], 2) self.assertEqual(stats.emails["running_total"], 3)
def test_task(self): params = [ [True, False], # important [True, False], # read [True, False], # auto-delete [ # received_date timedelta(days=settings.INBOX_AUTO_DELETE_TIME - 1), timedelta(days=settings.INBOX_AUTO_DELETE_TIME), timedelta(days=settings.INBOX_AUTO_DELETE_TIME + 1), ], ] now = timezone.now() for args in itertools.product(*params): email = factories.EmailFactory(important=args[0], read=args[1], received_date=now - args[3], inbox__user=factories.UserFactory()) email.inbox.user.inboxenprofile.auto_delete = args[2] email.inbox.user.inboxenprofile.save() self.assertEqual(models.Email.objects.count(), 24) tasks.auto_delete_emails.delay() # 2/3 of emails will be old enough # 1/2 not marked import # 1/2 users have auto-deleted enabled # therefore 1/6 emails can be deleted self.assertEqual(models.Email.objects.count(), 20)
def test_header_null_bytes(self): name = "X-Hello" data = "Hewwo \x00 test" body = models.Body.objects.create(data=b"Hello", hashed="fakehash") part = models.PartList.objects.create(email=factories.EmailFactory(), body=body) header, _ = part.header_set.create(name=name, data=data, ordinal=0) self.assertNotEqual(header.data.data, data) self.assertEqual(header.data.data, "Hewwo test")
def test_encoders_used(self): # make message with base64 part, uuencode part, 8bit part, 7bit part, # quopri part, and some invalid part body_data = b"Hello\n\nHow are you?\n" email = factories.EmailFactory(inbox=self.inbox) body = factories.BodyFactory(data=body_data) first_part = factories.PartListFactory( email=email, body=factories.BodyFactory(data=b"")) factories.HeaderFactory( part=first_part, name="Content-Type", data="multipart/mixed; boundary=\"=-3BRZDE/skgKPPh+RuFa/\"") encodings = { "base64": check_base64, "quoted-printable": check_quopri, "uuencode": check_uu, "x-uuencode": check_uu, "uue": check_uu, "x-uue": check_uu, "7-bit": check_noop, "8-bit": check_noop, "9-bit": check_unknown, # unknown encoding } for enc in encodings.keys(): part = factories.PartListFactory(email=email, parent=first_part, body=body) factories.HeaderFactory(part=part, name="Content-Type", data="text/plain; name=\"my-file.txt\"") factories.HeaderFactory(part=part, name="Content-Transfer-Encoding", data=enc) # finally, make a part without content headers factories.PartListFactory(email=email, parent=first_part, body=body) # and now export message_object = make_message(email) for message_part in message_object.walk(): ct = message_part.get("Content-Type", None) cte = message_part.get("Content-Transfer-Encoding", None) if ct is None: # default is to assume 7-bit check_noop(message_part, body_data) self.assertEqual(message_part.get_payload(decode=True), body_data) elif ct.startswith("multipart/mixed"): pass else: encodings[cte](message_part, body_data) self.assertEqual(message_part.get_payload(decode=True), body_data)
def test_delete_inboxen_item(self): email = factories.EmailFactory(inbox__user=self.user) tasks.delete_inboxen_item.delay("email", email.id) with self.assertRaises(models.Email.DoesNotExist): models.Email.objects.get(id=email.id) # we can send off the same task, but it won't error if there's no object tasks.delete_inboxen_item.delay("email", email.id) # test with an empty list tasks.delete_inboxen_item.chunks([], 500)()
def test_get_cached_result(self, task_mock): factories.EmailFactory(inbox__user=self.user) task_mock.return_value.id = "abc" task_mock.return_value.get.side_effect = exceptions.TimeoutError cache.cache.set( self.key, { "results": list( SearchEntry.objects.values_list("id", flat=True)), "has_next": True, "has_previous": False, "first": "some-randomstring", "last": "somerandom-string", }) response = self.client.get(self.url) self.assertEqual(response.status_code, 200) self.assertEqual(task_mock.call_count, 0) self.assertCountEqual(response.context["search_results"]["results"], SearchEntry.objects.all()) self.assertEqual(response.context["search_results"]["has_next"], True) self.assertEqual(response.context["search_results"]["last"], "somerandom-string") self.assertEqual(response.context["search_results"]["has_previous"], False) self.assertEqual(response.context["search_results"]["first"], "some-randomstring") self.assertEqual(response.context["waiting"], False) cache.cache.set( self.key, { "results": [], "has_next": True, "has_previous": False, "first": "some-randomstring", "last": "somerandom-string", }) response = self.client.get(self.url) self.assertEqual(response.status_code, 200) self.assertEqual(task_mock.call_count, 0) self.assertCountEqual(response.context["search_results"]["results"], []) self.assertEqual(response.context["search_results"]["has_next"], False) self.assertEqual(response.context["search_results"]["last"], None) self.assertEqual(response.context["search_results"]["has_previous"], False) self.assertEqual(response.context["search_results"]["first"], None)
def test_add_last_activity(self): now = timezone.now() email = factories.EmailFactory(received_date=now) email.inbox.created = now - datetime.timedelta(2) email.inbox.save() inbox = factories.InboxFactory() inbox.created = now - datetime.timedelta(1) inbox.save() inboxes = list(models.Inbox.objects.all().add_last_activity()) self.assertEqual(inboxes[0].last_activity, now) self.assertEqual(inboxes[1].last_activity, now - datetime.timedelta(1))
def setUp(self): super(AttachmentTestCase, self).setUp() self.user = factories.UserFactory() self.email = factories.EmailFactory(inbox__user=self.user) body = factories.BodyFactory(data=BODY) self.part = factories.PartListFactory(email=self.email, body=body) self.content_type_header, _ = factories.HeaderFactory(part=self.part, name="Content-Type", data="text/html; charset=\"utf-8\"") login = self.client.login(username=self.user.username, password="******", request=MockRequest(self.user)) if not login: raise Exception("Could not log in")
def setUp(self): super(BadEmailTestCase, self).setUp() self.user = factories.UserFactory() self.email = factories.EmailFactory(inbox__user=self.user) body = factories.BodyFactory(data=BODY) part = factories.PartListFactory(email=self.email, body=body) factories.HeaderFactory(part=part, name="From") factories.HeaderFactory(part=part, name="Subject") factories.HeaderFactory(part=part, name="Content-Type", data="text/html; charset=\"windows-1252\"") factories.HeaderFactory(part=part, name="Content-Disposition", data="inline; filename=\"He\n\rl\rlo\nß.jpg\"") self.email_metaless = factories.EmailFactory(inbox__user=self.user) body = factories.BodyFactory(data=METALESS_BODY) part = factories.PartListFactory(email=self.email_metaless, body=body) factories.HeaderFactory(part=part, name="From") factories.HeaderFactory(part=part, name="Subject") factories.HeaderFactory(part=part, name="Content-Type", data="text/html; charset=\"ascii\"") login = self.client.login(username=self.user.username, password="******", request=MockRequest(self.user)) if not login: raise Exception("Could not log in")
def test_header_create(self): name = "X-Hello" data = "Hewwo" body = models.Body.objects.create(data=b"Hello", hashed="fakehash") part = models.PartList.objects.create(email=factories.EmailFactory(), body=body) header1 = part.header_set.create(name=name, data=data, ordinal=0) header2 = part.header_set.create(name=name, data=data, ordinal=1) self.assertEqual(header1[0].name_id, header2[0].name_id) self.assertEqual(header1[0].data_id, header2[0].data_id) self.assertEqual(header1[0].name.name, name) self.assertEqual(header1[0].data.data, data) self.assertTrue(header1[1]) self.assertFalse(header2[1])
def test_email_viewable(self): user = factories.UserFactory() other_user = factories.UserFactory(username="******") # all the permutations of Emailss that can be viewed params = ( [0, models.Inbox.flags.deleted, ~models.Inbox.flags.deleted], [user, other_user, None], [0, models.Email.flags.deleted, ~models.Email.flags.deleted], ) for args in itertools.product(*params): factories.EmailFactory(inbox__flags=args[0], inbox__user=args[1], flags=args[2]) count = models.Email.objects.viewable(user).count() self.assertEqual(count, 4)
def test_find_bodies_with_bad_mime_tree(self): email = factories.EmailFactory() body = factories.BodyFactory( data=b"This mail body is searchable") # build 1 body and use that # the root part, multipart/alternative root_part = factories.PartListFactory(email=email, body=body) factories.HeaderFactory(part=root_part, name="Content-Type", data="multipart/alternative") # first text part alt1_part = factories.PartListFactory(email=email, body=body, parent=root_part) factories.HeaderFactory(part=alt1_part, name="Content-Type", data="text/plain; charset=\"ascii\"") # second text part alt2_part = factories.PartListFactory(email=email, body=body, parent=root_part) factories.HeaderFactory(part=alt2_part, name="Content-Type", data="text/plain; charset=\"ascii\"") # make first text part invalid by giving it a child alt1_child_part = factories.PartListFactory(email=email, body=body, parent=alt1_part) factories.HeaderFactory(part=alt1_child_part, name="Content-Type", data="text/plain; charset=\"ascii\"") # find_bodies returns a list of lists, so flatten it out bodies = [ part for part_list in email_utils.find_bodies(email.get_parts()) for part in part_list ] # we should only see one part self.assertEqual(len(bodies), 1) # and it should be a leaf node self.assertTrue(bodies[0].is_leaf_node()) self.assertEqual(bodies[0], alt2_part)
def test_delete_inboxen_item(self): email = factories.EmailFactory(inbox__user=self.user) self.assertEqual( SearchEntry.objects.filter(content_type__model="email").count(), 1) tasks.delete_inboxen_item.delay("email", email.id) self.assertEqual( SearchEntry.objects.filter(content_type__model="email").count(), 0) with self.assertRaises(models.Email.DoesNotExist): models.Email.objects.get(id=email.id) # we can send off the same task, but it won't error if there's no object tasks.delete_inboxen_item.delay("email", email.id) # test with an empty list tasks.delete_inboxen_item.chunks([], 500)()
def test_email_viewable(self): user = factories.UserFactory() other_user = factories.UserFactory(username="******") # all the permutations of Emailss that can be viewed params = ( [True, False], # inbox deleted [True, False], # inbox disabled [user, other_user, None], # user [True, False], # email deleted [True, False], # email read (i.e. any other bool has been set) ) for args in itertools.product(*params): factories.EmailFactory( inbox__deleted=args[0], inbox__disabled=args[1], inbox__user=args[2], deleted=args[3], read=args[4], ) count = models.Email.objects.viewable(user).count() self.assertEqual(count, 4)
def test_encoders_used(self): # make message with base64 part, uuencode part, 8bit part, 7bit part, # quopri part, and some invalid part unicode_body_data = "Hello\n\nHow are you?\nPó på pə pë\n".encode() ascii_body_data = "Hello\n\nHow are you?\n".encode() email = factories.EmailFactory(inbox=self.inbox) unicode_body = factories.BodyFactory(data=unicode_body_data) ascii_body = factories.BodyFactory(data=ascii_body_data) first_part = factories.PartListFactory( email=email, body=factories.BodyFactory(data=b"")) factories.HeaderFactory( part=first_part, name="Content-Type", data="multipart/mixed; boundary=\"=-3BRZDE/skgKPPh+RuFa/\"") unicode_encodings = { "base64": check_base64, "quoted-printable": check_quopri, "uuencode": check_uu, "x-uuencode": check_uu, "uue": check_uu, "x-uue": check_uu, } ascii_encodings = { "7-bit": check_noop, "8-bit": check_noop, "9-bit": check_unknown, # unknown encoding } encodings = {} encodings.update(unicode_encodings) encodings.update(ascii_encodings) for enc in unicode_encodings.keys(): part = factories.PartListFactory(email=email, parent=first_part, body=unicode_body) factories.HeaderFactory(part=part, name="Content-Type", data="text/plain; name=\"my-file.txt\"") factories.HeaderFactory(part=part, name="Content-Transfer-Encoding", data=enc) for enc in ascii_encodings.keys(): part = factories.PartListFactory(email=email, parent=first_part, body=ascii_body) factories.HeaderFactory(part=part, name="Content-Type", data="text/plain; name=\"my-file.txt\"") factories.HeaderFactory(part=part, name="Content-Transfer-Encoding", data=enc) # finally, make a part without content headers factories.PartListFactory(email=email, parent=first_part, body=ascii_body) # and now export message_object = make_message(email) for message_part in message_object.walk(): ct = message_part.get("Content-Type", None) cte = message_part.get("Content-Transfer-Encoding", None) if ct is None: # default is to assume 7-bit check_noop(message_part, ascii_body_data) self.assertEqual(message_part.get_payload(decode=True), ascii_body_data) elif ct.startswith("multipart/mixed"): pass elif cte in ascii_encodings: encodings[cte](message_part, ascii_body_data) self.assertEqual(message_part.get_payload(decode=True), ascii_body_data) elif cte in unicode_encodings: encodings[cte](message_part, unicode_body_data) self.assertEqual(message_part.get_payload(decode=True), unicode_body_data) else: raise AssertionError( "Unknown Content-Type or Content-Type-Encoding") # check that we can decode the whole lot in one go output_bytes = message_object.as_string().encode("ascii") self.assertNotEqual(len(output_bytes), 0) self.assertEqual( output_bytes.count(b"text/plain; name=\"my-file.txt\""), len(encodings))