mirror of
https://github.com/jwinterm/modoboa.git
synced 2026-10-17 05:41:25 +02:00
Added tests
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
# flake8: noqa
|
||||
|
||||
"""Tests data."""
|
||||
|
||||
BODYSTRUCTURE_SAMPLE_1 = [
|
||||
b"36 (FLAGS (\\Seen))",
|
||||
b'36 (UID 36 BODYSTRUCTURE (("text" "plain" ("charset" "UTF-8") NIL NIL "QUOTED-PRINTABLE" 959 29 NIL ("inline" NIL) NIL NIL)("text" "html" ("charset" "UTF-8") NIL NIL "QUOTED-PRINTABLE" 14695 322 NIL ("inline" NIL) NIL NIL) "alternative" ("boundary" "----=_Part_2437867_661044267.1501268072105") NIL NIL NIL))',
|
||||
]
|
||||
|
||||
BODYSTRUCTURE_SAMPLE_2 = [
|
||||
(
|
||||
b'19 (UID 19 FLAGS (\\Seen $label4 user_flag-1) BODYSTRUCTURE (("text" "plain" ("charset" "ISO-8859-1" "format" "flowed") NIL NIL "7bit" 2 1 NIL NIL NIL NIL)("message" "rfc822" ("name*" "ISO-8859-1\'\'%5B%49%4E%53%43%52%49%50%54%49%4F%4E%5D%20%52%E9%63%E9%70%74%69%6F%6E%20%64%65%20%76%6F%74%72%65%20%64%6F%73%73%69%65%72%20%64%27%69%6E%73%63%72%69%70%74%69%6F%6E%20%46%72%65%65%20%48%61%75%74%20%44%E9%62%69%74") NIL NIL "8bit" 3632 ("Wed, 13 Dec 2006 20:30:02 +0100" {70}',
|
||||
b"[INSCRIPTION] R\xe9c\xe9ption de votre dossier d'inscription Free Haut D\xe9bit",
|
||||
),
|
||||
(
|
||||
b' (("Free Haut Debit" NIL "inscription" "freetelecom.fr")) (("Free Haut Debit" NIL "inscription" "freetelecom.fr")) ((NIL NIL "hautdebit" "freetelecom.fr")) ((NIL NIL "nguyen.antoine" "wanadoo.fr")) NIL NIL NIL "<20061213193125.9DA0919AC@dgroup2-2.proxad.net>") ("text" "plain" ("charset" "iso-8859-1") NIL NIL "8bit" 1428 38 NIL ("inline" NIL) NIL NIL) 76 NIL ("inline" ("filename*" "ISO-8859-1\'\'%5B%49%4E%53%43%52%49%50%54%49%4F%4E%5D%20%52%E9%63%E9%70%74%69%6F%6E%20%64%65%20%76%6F%74%72%65%20%64%6F%73%73%69%65%72%20%64%27%69%6E%73%63%72%69%70%74%69%6F%6E%20%46%72%65%65%20%48%61%75%74%20%44%E9%62%69%74")) NIL NIL) "mixed" ("boundary" "------------040706080908000209030901") NIL NIL NIL) BODY[HEADER.FIELDS (DATE FROM TO CC SUBJECT)] {266}',
|
||||
b"Date: Tue, 19 Dec 2006 19:50:13 +0100\r\nFrom: Antoine Nguyen <nguyen.antoine@wanadoo.fr>\r\nTo: Antoine Nguyen <tonio@koalabs.org>\r\nSubject: [Fwd: [INSCRIPTION] =?ISO-8859-1?Q?R=E9c=E9ption_de_votre_?=\r\n =?ISO-8859-1?Q?dossier_d=27inscription_Free_Haut_D=E9bit=5D?=\r\n\r\n",
|
||||
),
|
||||
b")",
|
||||
]
|
||||
|
||||
BODYSTRUCTURE_SAMPLE_3 = [
|
||||
(
|
||||
b'58 (UID 123753 BODYSTRUCTURE ((("text" "plain" ("charset" "iso-8859-1") NIL NIL "quoted-printable" 90 10 NIL NIL NIL NIL)("text" "html" ("charset" "iso-8859-1") NIL NIL "quoted-printable" 1034 33 NIL NIL NIL NIL) "alternative" ("boundary" "_000_HE1PR10MB1642F2B8BA7FF8EAC0FC7AECD86E0HE1PR10MB1642EURP_") NIL NIL NIL)("application" "pdf" ("name" "=?iso-8859-1?Q?CV=5FAude=5FGIRODON=5FNGUYEN=5Fao=FBt2017_g=E9n=E9rique.pd?= =?iso-8859-1?Q?f?=") NIL {95}',
|
||||
"=?iso-8859-1?Q?CV=5FAude=5FGIRODON=5FNGUYEN=5Fao=FBt2017_g=E9n=E9rique.pd?=\n =?iso-8859-1?Q?f?=",
|
||||
),
|
||||
b' "base64" 94130 NIL ("attachment" ("filename" "=?iso-8859-1?Q?CV=5FAude=5FGIRODON=5FNGUYEN=5Fao=FBt2017_g=E9n=E9rique.pd?= =?iso-8859-1?Q?f?=" "size" "68787" "creation-date" "Wed, 13 Sep 2017 08:50:03 GMT" "modification-date" "Wed, 13 Sep 2017 08:50:03 GMT")) NIL NIL) "mixed" ("boundary" "_004_HE1PR10MB1642F2B8BA7FF8EAC0FC7AECD86E0HE1PR10MB1642EURP_") NIL ("fr-FR") NIL))',
|
||||
]
|
||||
|
||||
BODYSTRUCTURE_4 = b'BODYSTRUCTURE ((("text" "plain" ("charset" "iso-8859-1") NIL NIL "quoted-printable" 886 32 NIL NIL NIL NIL)("text" "html" ("charset" "us-ascii") NIL NIL "quoted-printable" 1208 16 NIL NIL NIL NIL) "alternative" ("boundary" "----=_NextPart_001_0003_01CCC564.B2F64FF0") NIL NIL NIL)("application" "octet-stream" ("name" "Carte Verte_2.pdf") NIL NIL "base64" 285610 NIL ("attachment" ("filename" "Carte Verte_2.pdf")) NIL NIL) "mixed" ("boundary" "----=_NextPart_000_0002_01CCC564.B2F64FF0") NIL NIL NIL)'
|
||||
|
||||
BODYSTRUCTURE_SAMPLE_4 = [
|
||||
(
|
||||
b"855 (UID 46931 "
|
||||
+ BODYSTRUCTURE_4
|
||||
+ b" BODY[HEADER.FIELDS (FROM TO CC DATE SUBJECT REPLY-TO MESSAGE-ID)] {235}",
|
||||
b"From: <Service.client10@maaf.fr>\r\nTo: <TONIO@NGYN.ORG>\r\nCc: \r\nSubject: Notre contact du 28/12/2011 - 192175092\r\nDate: Wed, 28 Dec 2011 13:29:17 +0100\r\nMessage-ID: <CABY0dkJspTaFn7v-1OG1nc9M0Qxn+VUTpcXzxyGNBnSnZtqMrw@mail.gmail.com>\r\n\r\n",
|
||||
),
|
||||
b")",
|
||||
]
|
||||
|
||||
BODYSTRUCTURE_ONLY_4 = [(b"855 (UID 46931 " + BODYSTRUCTURE_4), ")"]
|
||||
|
||||
BODYSTRUCTURE_ONLY_5 = [(b"855 (UID 46932 " + BODYSTRUCTURE_4), ")"]
|
||||
|
||||
BODY_PLAIN_4 = [
|
||||
(b"855 (UID 46931 BODY[1.1] {25}", b"This is a test message.\r\n"),
|
||||
b")",
|
||||
]
|
||||
|
||||
BODYSTRUCTURE_SAMPLE_5 = [
|
||||
(
|
||||
b'856 (UID 46936 BODYSTRUCTURE (("text" "plain" ("charset" "ISO-8859-1") NIL NIL "quoted-printable" 724 22 NIL NIL NIL NIL)("text" "html" ("charset" "ISO-8859-1") NIL NIL "quoted-printable" 2662 48 NIL NIL NIL NIL) "alternative" ("boundary" "----=_Part_1326887_254624357.1325083973970") NIL NIL NIL) BODY[HEADER.FIELDS (DATE FROM TO CC SUBJECT)] {258}',
|
||||
"Date: Wed, 28 Dec 2011 15:52:53 +0100 (CET)\r\nFrom: =?ISO-8859-1?Q?Malakoff_M=E9d=E9ric?= <communication@communication.malakoffmederic.com>\r\nTo: Antoine Nguyen <tonio@ngyn.org>\r\nSubject: =?ISO-8859-1?Q?Votre_inscription_au_grand_Jeu_Malakoff_M=E9d=E9ric?=\r\n\r\n",
|
||||
),
|
||||
b")",
|
||||
]
|
||||
|
||||
BODYSTRUCTURE_SAMPLE_6 = [
|
||||
(
|
||||
b'123 (UID 3 BODYSTRUCTURE (((("text" "plain" ("charset" "iso-8859-1") NIL NIL "quoted-printable" 1266 30 NIL NIL NIL NIL)("text" "html" ("charset" "iso-8859-1") NIL NIL "quoted-printable" 8830 227 NIL NIL NIL NIL) "alternative" ("boundary" "_000_152AC7ECD1F8AB43A9AD95DBDDCA3118082C09GKIMA24cmcicfr_") NIL NIL NIL)("image" "png" ("name" "image005.png") "<image005.png@01CC6CAA.4FADC490>" "image005.png" "base64" 7464 NIL ("inline" ("filename" "image005.png" "size" "5453" "creation-date" "Tue, 06 Sep 2011 13:33:49 GMT" "modification-date" "Tue, 06 Sep 2011 13:33:49 GMT")) NIL NIL)("image" "jpeg" ("name" "image006.jpg") "<image006.jpg@01CC6CAA.4FADC490>" "image006.jpg" "base64" 2492 NIL ("inline" ("filename" "image006.jpg" "size" "1819" "creation-date" "Tue, 06 Sep 2011 13:33:49 GMT" "modification-date" "Tue, 06 Sep 2011 13:33:49 GMT")) NIL NIL) "related" ("boundary" "_006_152AC7ECD1F8AB43A9AD95DBDDCA3118082C09GKIMA24cmcicfr_" "type" "multipart/alternative") NIL NIL NIL)("application" "pdf" ("name" "bilan assurance CIC.PDF") NIL "bilan assurance CIC.PDF" "base64" 459532 NIL ("attachment" ("filename" "bilan assurance CIC.PDF" "size" "335811" "creation-date" "Fri, 16 Sep 2011 12:45:23 GMT" "modification-date" "Fri, 16 Sep 2011 12:45:23 GMT")) NIL NIL)(("text" "plain" ("charset" "utf-8") NIL NIL "quoted-printable" 1389 29 NIL NIL NIL NIL)("text" "html" ("charset" "utf-8") NIL NIL "quoted-printable" 1457 27 NIL NIL NIL NIL) "alternative" ("boundary" "===============0775904800==") ("inline" NIL) NIL NIL) "mixed" ("boundary" "_007_152AC7ECD1F8AB43A9AD95DBDDCA3118082C09GKIMA24cmcicfr_") NIL ("fr-FR") NIL)',
|
||||
),
|
||||
b")",
|
||||
]
|
||||
|
||||
BODYSTRUCTURE_SAMPLE_7 = [
|
||||
(
|
||||
b'856 (UID 11111 BODYSTRUCTURE ((("text" "plain" ("charset" "UTF-8") NIL NIL "7bit" 0 0 NIL NIL NIL NIL) "mixed" ("boundary" "----=_Part_407172_3159001.1321948277321") NIL NIL NIL)("application" "octet-stream" ("name" "26274308.pdf") NIL NIL "base64" 14906 NIL ("attachment" ("filename" "(26274308.pdf")) NIL NIL) "mixed" ("boundary" "----=_Part_407171_9686991.1321948277321") NIL NIL NIL)',
|
||||
),
|
||||
b")",
|
||||
]
|
||||
|
||||
BODYSTRUCTURE_SAMPLE_8 = [
|
||||
(
|
||||
b'1 (UID 947 BODYSTRUCTURE ("text" "html" ("charset" "utf-8") NIL NIL "8bit" 889 34 NIL NIL NIL NIL) BODY[HEADER.FIELDS (FROM TO CC DATE SUBJECT)] {80}',
|
||||
"From: Antoine Nguyen <tonio@ngyn.org>\r\nDate: Sat, 26 Mar 2016 11:45:49 +0100\r\n\r\n",
|
||||
),
|
||||
b")",
|
||||
]
|
||||
|
||||
BODYSTRUCTURE_SAMPLE_9 = [
|
||||
(
|
||||
b"855 (UID 46932 "
|
||||
+ BODYSTRUCTURE_4
|
||||
+ b" BODY[HEADER.FIELDS (FROM TO CC DATE SUBJECT)] {235}",
|
||||
b"From: <Service.client10@maaf.fr>\r\nTo: <TONIO@NGYN.ORG>\r\nCc: \r\nSubject: Notre contact du 28/12/2011 - 192175092\r\nDate: Wed, 28 Dec 2011 13:29:17 +0100\r\nMessage-ID: <CABY0dkJspTaFn7v-1OG1nc9M0Qxn+VUTpcXzxyGNBnSnZtqMrw@mail.gmail.com>\r\n\r\n",
|
||||
),
|
||||
b")",
|
||||
]
|
||||
|
||||
BODYSTRUCTURE_SAMPLE_10 = [
|
||||
(
|
||||
b"855 (UID 46932 " + BODYSTRUCTURE_4 + b" BODY[1.1] {10})",
|
||||
b"XXXXXXXX\r\n",
|
||||
b"BODY[2] {10}",
|
||||
b"XXXXXXXX\r\n",
|
||||
b")",
|
||||
)
|
||||
]
|
||||
|
||||
BODYSTRUCTURE_SAMPLE_WITH_FLAGS = [
|
||||
(
|
||||
b'19 (UID 19 FLAGS (\\Seen) RFC822.SIZE 100000 BODYSTRUCTURE (("text" "plain" ("charset" "ISO-8859-1" "format" "flowed") NIL NIL "7bit" 2 1 NIL NIL NIL NIL)("message" "rfc822" ("name*" "ISO-8859-1\'\'%5B%49%4E%53%43%52%49%50%54%49%4F%4E%5D%20%52%E9%63%E9%70%74%69%6F%6E%20%64%65%20%76%6F%74%72%65%20%64%6F%73%73%69%65%72%20%64%27%69%6E%73%63%72%69%70%74%69%6F%6E%20%46%72%65%65%20%48%61%75%74%20%44%E9%62%69%74") NIL NIL "8bit" 3632 ("Wed, 13 Dec 2006 20:30:02 +0100" {70}', # noqa
|
||||
b"[INSCRIPTION] R\xe9c\xe9ption de votre dossier d'inscription Free Haut D\xe9bit",
|
||||
), # noqa
|
||||
(
|
||||
b' (("Free Haut Debit" NIL "inscription" "freetelecom.fr")) (("Free Haut Debit" NIL "inscription" "freetelecom.fr")) ((NIL NIL "hautdebit" "freetelecom.fr")) ((NIL NIL "nguyen.antoine" "wanadoo.fr")) NIL NIL NIL "<20061213193125.9DA0919AC@dgroup2-2.proxad.net>") ("text" "plain" ("charset" "iso-8859-1") NIL NIL "8bit" 1428 38 NIL ("inline" NIL) NIL NIL) 76 NIL ("inline" ("filename*" "ISO-8859-1\'\'%5B%49%4E%53%43%52%49%50%54%49%4F%4E%5D%20%52%E9%63%E9%70%74%69%6F%6E%20%64%65%20%76%6F%74%72%65%20%64%6F%73%73%69%65%72%20%64%27%69%6E%73%63%72%69%70%74%69%6F%6E%20%46%72%65%65%20%48%61%75%74%20%44%E9%62%69%74")) NIL NIL) "mixed" ("boundary" "------------040706080908000209030901") NIL NIL NIL) BODY[HEADER.FIELDS (DATE FROM TO CC SUBJECT)] {266}', # noqa
|
||||
b"Date: Tue, 19 Dec 2006 19:50:13 +0100\r\nFrom: Antoine Nguyen <nguyen.antoine@wanadoo.fr>\r\nTo: Antoine Nguyen <tonio@koalabs.org>\r\nSubject: [Fwd: [INSCRIPTION] =?ISO-8859-1?Q?R=E9c=E9ption_de_votre_?=\r\n =?ISO-8859-1?Q?dossier_d=27inscription_Free_Haut_D=E9bit=5D?=\r\n\r\n",
|
||||
),
|
||||
b")",
|
||||
]
|
||||
|
||||
BODYSTRUCTURE_EMPTY_MAIL = [
|
||||
b'33 (UID 33 BODYSTRUCTURE (("text" "plain" ("charset" "us-ascii") NIL NIL "quoted-printable" 0 0 NIL NIL NIL NIL)("application" "zip" ("name" "hotmail.com!ngyn.org!1435428000!1435514400.zip") NIL NIL "base64" 978 NIL ("attachment" ("filename" "hotmail.com!ngyn.org!1435428000!1435514400.zip")) NIL NIL) "mixed" ("boundary" "--boundary_32281_b52cf564-2a50-4f96-aeb0-ef5f83b05463") NIL NIL NIL))'
|
||||
]
|
||||
|
||||
EMPTY_BODY = [(b"33 (UID 33 BODY[1] {0}", b""), b")"]
|
||||
|
||||
COMPLETE_MAIL = [
|
||||
(
|
||||
b"109 (UID 133872 BODY[] {2504}",
|
||||
b"Return-Path: <test1@test.org>\r\nDelivered-To: test1@test.org\r\nReceived: from mail.testsrv.org\r\n\tby nelson.ngyn.org (Dovecot) with LMTP id E9jPFPHHe1u1bQAABvoInA\r\n\tfor <test1@test.org>; Tue, 21 Aug 2018 10:06:09 +0200\r\nReceived: from [192.168.0.12] (unknown [109.9.172.169])\r\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))\r\n\t(No client certificate requested)\r\n\tby mail.testsrv.org (Postfix) with ESMTPSA id 2B279E00D2\r\n\tfor <test1@test.org>; Tue, 21 Aug 2018 10:06:09 +0200 (CEST)\r\nDKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=test.org; s=test;\r\n\tt=1534838769; h=from:from:sender:reply-to:subject:subject:date:date:\r\n\t message-id:message-id:to:to:cc:mime-version:mime-version:\r\n\t content-type:content-type:\r\n\t content-transfer-encoding:content-transfer-encoding:in-reply-to:\r\n\t references; bh=EVfAHeUMDygbJe0SkMWJHjgXGjtiTLZnMQbyWqzsrCY=;\r\n\tb=fRc4i+WbPkbdD1BNfV9TqsZZ9nTbnHn6CKbH4nwrQnmUYQvvFUcpXC8PBURyglyLBAqPKb\r\n\tF6Dq7TnvcYdkIpR0XyMko+XB/qt8Wj0J0tC8bFxfknN8yNqj32SQAjtLrsjtzEgC1LkcLo\r\n\tcXU+FQbZR0D8EL7YD/nnsbO4mYnf3as=\r\nTo: Antoine Nguyen <test1@test.org>\r\nFrom: Antoine Nguyen <test1@test.org>\r\nSubject: Simple message\r\nMessage-ID: <7ed6e950-9e2b-b0fc-9e66-5b8358453b8d@test.org>\r\nDate: Tue, 21 Aug 2018 10:06:08 +0200\r\nUser-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:52.0) Gecko/20100101\r\n Thunderbird/52.9.1\r\nMIME-Version: 1.0\r\nContent-Type: text/plain; charset=utf-8\r\nContent-Transfer-Encoding: 7bit\r\nContent-Language: fr-FR\r\nARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=test.org;\r\n\ts=test; t=1534838769; h=from:from:sender:reply-to:subject:subject:date:date:\r\n\t message-id:message-id:to:to:cc:mime-version:mime-version:\r\n\t content-type:content-type:\r\n\t content-transfer-encoding:content-transfer-encoding:in-reply-to:\r\n\t references; bh=EVfAHeUMDygbJe0SkMWJHjgXGjtiTLZnMQbyWqzsrCY=;\r\n\tb=ZV1ndumHftEnhq8Z7zujDS9WUlpJmjrTIEzXsIy8+1HhZ6AEcmur5r8SmS/xfUvpoScNvF\r\n\tlYAHIdbKPX54Fpq7rZVgIhuy8vfcRGprHxH9DMhk3kHiuZLsJT1F6UdPwTYSGAWBTbg1u2\r\n\tHu2VoeSYBV5PrsINvPr1QCbo+GqTlJU=\r\nARC-Seal: i=1; s=test; d=test.org; t=1534838769; a=rsa-sha256; cv=none;\r\n\tb=CE7Q0SnkLMHx82eOtanv4pCtl3fhaPqOAYb3Nqxi5lqwDcO80vTMfGUwOv6r3Exv9Cnj3+nCxejzXtrO4TTKesL9bamOBf+veRYTLfy8wjRIfgEVXS/amOjf9u4UzGgwxL1HbhHWbCIqJhaVwrPZaHZwA9XPmboqGVQNP3i2nH0=\r\nARC-Authentication-Results: i=1; ORIGINATING;\r\n\tauth=pass smtp.auth=test1@test.org smtp.mailfrom=test1@test.org\r\nAuthentication-Results: ORIGINATING;\r\n\tauth=pass smtp.auth=test1@test.org smtp.mailfrom=test1@test.org\r\n\r\nHello!\r\n\r\n",
|
||||
),
|
||||
b")",
|
||||
]
|
||||
@@ -0,0 +1,112 @@
|
||||
"""FETCH parser tests."""
|
||||
|
||||
import io
|
||||
import unittest
|
||||
|
||||
from modoboa.webmail.lib.fetch_parser import FetchResponseParser
|
||||
|
||||
from . import data
|
||||
|
||||
|
||||
def dump_bodystructure(fp, bs, depth=0):
|
||||
"""Dump a parsed BODYSTRUCTURE."""
|
||||
indentation = " " * (depth * 4)
|
||||
for mp in bs:
|
||||
if isinstance(mp, list):
|
||||
if isinstance(mp[0], list):
|
||||
print(f"{indentation}multipart/{mp[1]}", file=fp)
|
||||
dump_bodystructure(fp, mp, depth + 1)
|
||||
else:
|
||||
dump_bodystructure(fp, mp, depth)
|
||||
elif isinstance(mp, dict):
|
||||
if isinstance(mp["struct"][0], list):
|
||||
print("{}multipart/{}".format(indentation, mp["struct"][1]), file=fp)
|
||||
dump_bodystructure(fp, mp["struct"][0], depth + 1)
|
||||
else:
|
||||
print("{}{}/{}".format(indentation, *mp["struct"][:2]), file=fp)
|
||||
fp.seek(0)
|
||||
result = fp.read()
|
||||
return result
|
||||
|
||||
|
||||
class FetchParserTestCase(unittest.TestCase):
|
||||
"""Test FETCH parser."""
|
||||
|
||||
def setUp(self):
|
||||
"""Setup test env."""
|
||||
self.parser = FetchResponseParser()
|
||||
|
||||
def _test_bodystructure_output(self, bs, expected):
|
||||
"""."""
|
||||
r = self.parser.parse(bs)
|
||||
fp = io.StringIO()
|
||||
output = dump_bodystructure(fp, r[list(r.keys())[0]]["BODYSTRUCTURE"])
|
||||
fp.close()
|
||||
self.assertEqual(output, expected)
|
||||
return r
|
||||
|
||||
def test_parse_bodystructure(self):
|
||||
"""Test the parsing of several responses containing BS."""
|
||||
self._test_bodystructure_output(
|
||||
data.BODYSTRUCTURE_SAMPLE_1,
|
||||
"""multipart/alternative
|
||||
text/plain
|
||||
text/html
|
||||
""",
|
||||
)
|
||||
self._test_bodystructure_output(
|
||||
data.BODYSTRUCTURE_SAMPLE_2,
|
||||
"""multipart/mixed
|
||||
text/plain
|
||||
message/rfc822
|
||||
""",
|
||||
)
|
||||
self._test_bodystructure_output(
|
||||
data.BODYSTRUCTURE_SAMPLE_3,
|
||||
"""multipart/mixed
|
||||
multipart/alternative
|
||||
text/plain
|
||||
text/html
|
||||
application/pdf
|
||||
""",
|
||||
)
|
||||
self._test_bodystructure_output(
|
||||
data.BODYSTRUCTURE_SAMPLE_4,
|
||||
"""multipart/mixed
|
||||
multipart/alternative
|
||||
text/plain
|
||||
text/html
|
||||
application/octet-stream
|
||||
""",
|
||||
)
|
||||
self._test_bodystructure_output(
|
||||
data.BODYSTRUCTURE_SAMPLE_5,
|
||||
"""multipart/alternative
|
||||
text/plain
|
||||
text/html
|
||||
""",
|
||||
)
|
||||
self._test_bodystructure_output(
|
||||
data.BODYSTRUCTURE_SAMPLE_6,
|
||||
"""multipart/mixed
|
||||
multipart/related
|
||||
multipart/alternative
|
||||
text/plain
|
||||
text/html
|
||||
image/png
|
||||
image/jpeg
|
||||
application/pdf
|
||||
multipart/alternative
|
||||
text/plain
|
||||
text/html
|
||||
""",
|
||||
)
|
||||
self._test_bodystructure_output(
|
||||
data.BODYSTRUCTURE_SAMPLE_7,
|
||||
"""multipart/mixed
|
||||
multipart/mixed
|
||||
text/plain
|
||||
application/octet-stream
|
||||
""",
|
||||
)
|
||||
self._test_bodystructure_output(data.BODYSTRUCTURE_SAMPLE_8, "text/html\n")
|
||||
@@ -0,0 +1,256 @@
|
||||
from datetime import timedelta
|
||||
from io import BytesIO
|
||||
import os
|
||||
import shutil
|
||||
import tempfile
|
||||
from unittest import mock
|
||||
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
|
||||
from oauth2_provider.models import get_access_token_model, get_application_model
|
||||
|
||||
from modoboa.core import models as core_models
|
||||
from modoboa.admin import factories as admin_factories
|
||||
from modoboa.lib.tests import ModoAPITestCase
|
||||
|
||||
from . import data as tests_data
|
||||
|
||||
|
||||
Application = get_application_model()
|
||||
AccessToken = get_access_token_model()
|
||||
|
||||
|
||||
def get_gif():
|
||||
"""Return gif."""
|
||||
gif = BytesIO(
|
||||
b"GIF87a\x01\x00\x01\x00\x80\x01\x00\x00\x00\x00ccc,\x00"
|
||||
b"\x00\x00\x00\x01\x00\x01\x00\x00\x02\x02D\x01\x00;"
|
||||
)
|
||||
gif.name = "image.gif"
|
||||
return gif
|
||||
|
||||
|
||||
class IMAP4Mock:
|
||||
"""Fake IMAP4 client."""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.untagged_responses = {}
|
||||
|
||||
def _quote(self, data):
|
||||
return data
|
||||
|
||||
def _simple_command(self, name, *args, **kwargs):
|
||||
if name == "CAPABILITY":
|
||||
self.untagged_responses["CAPABILITY"] = [b""]
|
||||
elif name == "LIST":
|
||||
self.untagged_responses["LIST"] = [b'() "." "INBOX"']
|
||||
elif name == "NAMESPACE":
|
||||
self.untagged_responses["NAMESPACE"] = [b'(("" "/")) NIL NIL']
|
||||
return "OK", None
|
||||
|
||||
def append(self, *args, **kwargs):
|
||||
pass
|
||||
|
||||
def create(self, name):
|
||||
return "OK", None
|
||||
|
||||
def delete(self, name):
|
||||
return "OK", None
|
||||
|
||||
def list(self):
|
||||
return "OK", [b'() "." "INBOX"']
|
||||
|
||||
def rename(self, oldname, newname):
|
||||
return "OK", None
|
||||
|
||||
def uid(self, command, *args):
|
||||
if command in ["SEARCH", "SORT"]:
|
||||
return "OK", [b"19"]
|
||||
elif command == "FETCH":
|
||||
uid = int(args[0])
|
||||
data = tests_data.BODYSTRUCTURE_SAMPLE_WITH_FLAGS
|
||||
if uid == 46931:
|
||||
if args[1] == "(BODYSTRUCTURE)":
|
||||
data = tests_data.BODYSTRUCTURE_ONLY_4
|
||||
elif "HEADER.FIELDS" in args[1]:
|
||||
data = tests_data.BODYSTRUCTURE_SAMPLE_4
|
||||
else:
|
||||
data = tests_data.BODY_PLAIN_4
|
||||
elif uid == 46932:
|
||||
if args[1] == "(BODYSTRUCTURE)":
|
||||
data = tests_data.BODYSTRUCTURE_ONLY_5
|
||||
elif "HEADER.FIELDS" in args[1]:
|
||||
data = tests_data.BODYSTRUCTURE_SAMPLE_9
|
||||
else:
|
||||
data = tests_data.BODYSTRUCTURE_SAMPLE_10
|
||||
elif uid == 33:
|
||||
if args[1] == "(BODYSTRUCTURE)":
|
||||
data = tests_data.BODYSTRUCTURE_EMPTY_MAIL
|
||||
else:
|
||||
data = tests_data.EMPTY_BODY
|
||||
elif uid == 133872:
|
||||
data = tests_data.COMPLETE_MAIL
|
||||
return "OK", data
|
||||
elif command == "STORE":
|
||||
return "OK", []
|
||||
|
||||
|
||||
class WebmailTestCase(ModoAPITestCase):
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
super().setUpTestData()
|
||||
admin_factories.populate_database()
|
||||
cls.user = core_models.User.objects.get(username="user@test.com")
|
||||
cls.application = Application.objects.create(
|
||||
name="Test Application",
|
||||
redirect_uris="http://localhost",
|
||||
user=cls.user,
|
||||
client_type=Application.CLIENT_PUBLIC,
|
||||
authorization_grant_type=Application.GRANT_AUTHORIZATION_CODE,
|
||||
)
|
||||
|
||||
cls.access_token = AccessToken.objects.create(
|
||||
user=cls.user,
|
||||
scope="read write",
|
||||
expires=timezone.now() + timedelta(seconds=300),
|
||||
token="secret-access-token-key",
|
||||
application=cls.application,
|
||||
)
|
||||
|
||||
def setUp(self):
|
||||
"""Connect with a simpler user."""
|
||||
patcher = mock.patch("imaplib.IMAP4")
|
||||
self.mock_imap4 = patcher.start()
|
||||
self.mock_imap4.return_value = IMAP4Mock()
|
||||
self.addCleanup(patcher.stop)
|
||||
self.set_global_parameter("imap_port", 1435)
|
||||
self.workdir = tempfile.mkdtemp()
|
||||
os.mkdir(f"{self.workdir}/webmail")
|
||||
self.set_global_parameter("update_scheme", False, app="core")
|
||||
|
||||
def tearDown(self):
|
||||
"""Cleanup."""
|
||||
shutil.rmtree(self.workdir)
|
||||
|
||||
def authenticate(self, username: str = "user@test.com"):
|
||||
self.client.credentials(Authorization="Bearer " + self.access_token.token)
|
||||
|
||||
|
||||
class UserMailboxViewSetTestCase(WebmailTestCase):
|
||||
|
||||
def test_list(self):
|
||||
self.authenticate()
|
||||
url = reverse("v2:webmail-mailbox-list")
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(len(response.json()["mailboxes"]), 5)
|
||||
|
||||
def test_quota(self):
|
||||
self.authenticate()
|
||||
url = reverse("v2:webmail-mailbox-quota")
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 404)
|
||||
response = self.client.get(f"{url}?mailbox=INBOX")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(response.json()["usage"], -1)
|
||||
|
||||
def test_create(self):
|
||||
self.authenticate()
|
||||
url = reverse("v2:webmail-mailbox-list")
|
||||
body = {"name": "Test"}
|
||||
response = self.client.post(url, body, format="json")
|
||||
self.assertEqual(response.status_code, 201)
|
||||
body = {"parent": "Test", "name": "Test"}
|
||||
response = self.client.post(url, body, format="json")
|
||||
self.assertEqual(response.status_code, 201)
|
||||
|
||||
def test_rename(self):
|
||||
self.authenticate()
|
||||
url = reverse("v2:webmail-mailbox-rename")
|
||||
body = {"name": "Test renamed", "oldname": "Test"}
|
||||
response = self.client.post(url, body, format="json")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
|
||||
def test_compress(self):
|
||||
self.authenticate()
|
||||
url = reverse("v2:webmail-mailbox-compress")
|
||||
body = {"name": "INBOX"}
|
||||
response = self.client.post(url, body, format="json")
|
||||
self.assertEqual(response.status_code, 204)
|
||||
|
||||
def test_empty(self):
|
||||
self.authenticate()
|
||||
url = reverse("v2:webmail-mailbox-empty")
|
||||
body = {"name": "INBOX"}
|
||||
response = self.client.post(url, body, format="json")
|
||||
self.assertEqual(response.status_code, 404)
|
||||
body = {"name": "Trash"}
|
||||
response = self.client.post(url, body, format="json")
|
||||
self.assertEqual(response.status_code, 204)
|
||||
|
||||
def test_delete(self):
|
||||
self.authenticate()
|
||||
url = reverse("v2:webmail-mailbox-delete")
|
||||
body = {"name": "Test"}
|
||||
response = self.client.post(url, body, format="json")
|
||||
self.assertEqual(response.status_code, 204)
|
||||
|
||||
|
||||
class UserEmailViewSetTestCase(WebmailTestCase):
|
||||
|
||||
def test_listmailbox(self):
|
||||
"""Check listmailbox action."""
|
||||
self.authenticate()
|
||||
url = reverse("v2:webmail-email-list")
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
content = response.json()
|
||||
self.assertEqual(content["count"], 1)
|
||||
self.assertEqual(
|
||||
content["results"][0]["from_address"]["address"],
|
||||
"nguyen.antoine@wanadoo.fr",
|
||||
)
|
||||
|
||||
response = self.client.get(f"{url}?search=Réception")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(
|
||||
content["results"][0]["from_address"]["address"],
|
||||
"nguyen.antoine@wanadoo.fr",
|
||||
)
|
||||
|
||||
def test_getmailsource(self):
|
||||
"""Try to display a message's source."""
|
||||
self.authenticate()
|
||||
url = reverse("v2:webmail-email-source")
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 404)
|
||||
response = self.client.get(f"{url}?mailbox=INBOX&mailid=133872")
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertIn("Message-ID", response.json()["source"])
|
||||
|
||||
|
||||
class ComposeSessionViewSetTestCase(WebmailTestCase):
|
||||
|
||||
def test_create(self):
|
||||
self.authenticate()
|
||||
url = reverse("v2:webmail-compose-session-list")
|
||||
response = self.client.post(url)
|
||||
self.assertEqual(response.status_code, 201)
|
||||
self.assertIn("uid", response.json())
|
||||
|
||||
def test_get_allowed_senders(self):
|
||||
self.authenticate()
|
||||
url = reverse("v2:webmail-compose-session-allowed-senders")
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
self.assertEqual(len(response.json()), 2)
|
||||
|
||||
def test_attachments(self):
|
||||
self.authenticate()
|
||||
url = reverse("v2:webmail-compose-session-list")
|
||||
response = self.client.post(url)
|
||||
uid = response.json()["uid"]
|
||||
url = reverse("v2:webmail-compose-session-attachments", args=[uid])
|
||||
response = self.client.get(url)
|
||||
self.assertEqual(response.status_code, 200)
|
||||
@@ -9,12 +9,14 @@ from rest_framework.decorators import action
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
|
||||
from modoboa.lib.paginator import Paginator
|
||||
from modoboa.lib.viewsets import HasMailbox
|
||||
from modoboa.webmail import lib, serializers
|
||||
from modoboa.webmail.lib import attachments
|
||||
|
||||
|
||||
class UserMailboxViewSet(viewsets.GenericViewSet):
|
||||
permission_classes = (IsAuthenticated,)
|
||||
|
||||
permission_classes = (IsAuthenticated, HasMailbox)
|
||||
|
||||
def get_serializer_class(self):
|
||||
if self.action == "list":
|
||||
@@ -101,6 +103,8 @@ class UserMailboxViewSet(viewsets.GenericViewSet):
|
||||
|
||||
class UserEmailViewSet(viewsets.GenericViewSet):
|
||||
|
||||
permission_classes = (IsAuthenticated, HasMailbox)
|
||||
|
||||
def get_serializer_class(self):
|
||||
if self.action == "list":
|
||||
return serializers.PaginatedEmailListSerializer
|
||||
@@ -262,6 +266,8 @@ class UserEmailViewSet(viewsets.GenericViewSet):
|
||||
|
||||
class ComposeSessionViewSet(viewsets.GenericViewSet):
|
||||
|
||||
permission_classes = (IsAuthenticated, HasMailbox)
|
||||
|
||||
def get_serializer_class(self):
|
||||
if self.action == "send":
|
||||
return serializers.SendEmailSerializer
|
||||
|
||||
Reference in New Issue
Block a user