]> git.ozlabs.org Git - patchwork/blob - apps/patchwork/tests/patchparser.py
[models] Make patches unique on (msgid, project), not just (msgid)
[patchwork] / apps / patchwork / tests / patchparser.py
1 # Patchwork - automated patch tracking system
2 # Copyright (C) 2008 Jeremy Kerr <jk@ozlabs.org>
3 #
4 # This file is part of the Patchwork package.
5 #
6 # Patchwork is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 #
11 # Patchwork is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with Patchwork; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
20 import unittest
21 import os
22 from email import message_from_string
23 from patchwork.models import Project, Person, Patch, Comment
24 from patchwork.tests.utils import read_patch, create_email, defaults
25
26 try:
27     from email.mime.text import MIMEText
28 except ImportError:
29     # Python 2.4 compatibility
30     from email.MIMEText import MIMEText
31
32 class PatchTest(unittest.TestCase):
33     default_sender = defaults.sender
34     default_subject = defaults.subject
35     project = defaults.project
36
37 from patchwork.bin.parsemail import find_content, find_author, parse_mail
38
39 class InlinePatchTest(PatchTest):
40     patch_filename = '0001-add-line.patch'
41     test_comment = 'Test for attached patch'
42
43     def setUp(self):
44         self.orig_patch = read_patch(self.patch_filename)
45         email = create_email(self.test_comment + '\n' + self.orig_patch)
46         (self.patch, self.comment) = find_content(self.project, email)
47
48     def testPatchPresence(self):
49         self.assertTrue(self.patch is not None)
50
51     def testPatchContent(self):
52         self.assertEquals(self.patch.content, self.orig_patch)
53
54     def testCommentPresence(self):
55         self.assertTrue(self.comment is not None)
56
57     def testCommentContent(self):
58         self.assertEquals(self.comment.content, self.test_comment)
59
60
61 class AttachmentPatchTest(InlinePatchTest):
62     patch_filename = '0001-add-line.patch'
63     test_comment = 'Test for attached patch'
64     content_subtype = 'x-patch'
65
66     def setUp(self):
67         self.orig_patch = read_patch(self.patch_filename)
68         email = create_email(self.test_comment, multipart = True)
69         attachment = MIMEText(self.orig_patch, _subtype = self.content_subtype)
70         email.attach(attachment)
71         (self.patch, self.comment) = find_content(self.project, email)
72
73 class AttachmentXDiffPatchTest(AttachmentPatchTest):
74     content_subtype = 'x-diff'
75
76 class UTF8InlinePatchTest(InlinePatchTest):
77     patch_filename = '0002-utf-8.patch'
78     patch_encoding = 'utf-8'
79
80     def setUp(self):
81         self.orig_patch = read_patch(self.patch_filename, self.patch_encoding)
82         email = create_email(self.test_comment + '\n' + self.orig_patch,
83                              content_encoding = self.patch_encoding)
84         (self.patch, self.comment) = find_content(self.project, email)
85
86 class NoCharsetInlinePatchTest(InlinePatchTest):
87     """ Test mails with no content-type or content-encoding header """
88     patch_filename = '0001-add-line.patch'
89
90     def setUp(self):
91         self.orig_patch = read_patch(self.patch_filename)
92         email = create_email(self.test_comment + '\n' + self.orig_patch)
93         del email['Content-Type']
94         del email['Content-Transfer-Encoding']
95         (self.patch, self.comment) = find_content(self.project, email)
96
97 class SignatureCommentTest(InlinePatchTest):
98     patch_filename = '0001-add-line.patch'
99     test_comment = 'Test comment\nmore comment'
100
101     def setUp(self):
102         self.orig_patch = read_patch(self.patch_filename)
103         email = create_email( \
104                 self.test_comment + '\n' + \
105                 '-- \nsig\n' + self.orig_patch)
106         (self.patch, self.comment) = find_content(self.project, email)
107
108
109 class ListFooterTest(InlinePatchTest):
110     patch_filename = '0001-add-line.patch'
111     test_comment = 'Test comment\nmore comment'
112
113     def setUp(self):
114         self.orig_patch = read_patch(self.patch_filename)
115         email = create_email( \
116                 self.test_comment + '\n' + \
117                 '_______________________________________________\n' + \
118                 'Linuxppc-dev mailing list\n' + \
119                 self.orig_patch)
120         (self.patch, self.comment) = find_content(self.project, email)
121
122
123 class UpdateCommentTest(InlinePatchTest):
124     """ Test for '---\nUpdate: v2' style comments to patches. """
125     patch_filename = '0001-add-line.patch'
126     test_comment = 'Test comment\nmore comment\n---\nUpdate: test update'
127
128 class UpdateSigCommentTest(SignatureCommentTest):
129     """ Test for '---\nUpdate: v2' style comments to patches, with a sig """
130     patch_filename = '0001-add-line.patch'
131     test_comment = 'Test comment\nmore comment\n---\nUpdate: test update'
132
133 class SenderEncodingTest(unittest.TestCase):
134     sender_name = u'example user'
135     sender_email = 'user@example.com'
136     from_header = 'example user <user@example.com>'
137
138     def setUp(self):
139         mail = 'From: %s\n' % self.from_header + \
140                'Subject: test\n\n' + \
141                'test'
142         self.email = message_from_string(mail)
143         (self.person, new) = find_author(self.email)
144         self.person.save()
145
146     def tearDown(self):
147         self.person.delete()
148
149     def testName(self):
150         self.assertEquals(self.person.name, self.sender_name)
151
152     def testEmail(self):
153         self.assertEquals(self.person.email, self.sender_email)
154
155     def testDBQueryName(self):
156         db_person = Person.objects.get(name = self.sender_name)
157         self.assertEquals(self.person, db_person)
158
159     def testDBQueryEmail(self):
160         db_person = Person.objects.get(email = self.sender_email)
161         self.assertEquals(self.person, db_person)
162
163
164 class SenderUTF8QPEncodingTest(SenderEncodingTest):
165     sender_name = u'\xe9xample user'
166     from_header = '=?utf-8?q?=C3=A9xample=20user?= <user@example.com>'
167
168 class SenderUTF8QPSplitEncodingTest(SenderEncodingTest):
169     sender_name = u'\xe9xample user'
170     from_header = '=?utf-8?q?=C3=A9xample?= user <user@example.com>'
171
172 class SenderUTF8B64EncodingTest(SenderUTF8QPEncodingTest):
173     from_header = '=?utf-8?B?w6l4YW1wbGUgdXNlcg==?= <user@example.com>'
174
175
176 class SenderCorrelationTest(unittest.TestCase):
177     existing_sender = 'Existing Sender <existing@example.com>'
178     non_existing_sender = 'Non-existing Sender <nonexisting@example.com>'
179
180     def mail(self, sender):
181         return message_from_string('From: %s\nSubject: Test\n\ntest\n' % sender)
182
183     def setUp(self):
184         self.existing_sender_mail = self.mail(self.existing_sender)
185         self.non_existing_sender_mail = self.mail(self.non_existing_sender)
186         (self.person, new) = find_author(self.existing_sender_mail)
187         self.person.save()
188
189     def testExisingSender(self):
190         (person, new) = find_author(self.existing_sender_mail)
191         self.assertEqual(new, False)
192         self.assertEqual(person.id, self.person.id)
193
194     def testNonExisingSender(self):
195         (person, new) = find_author(self.non_existing_sender_mail)
196         self.assertEqual(new, True)
197         self.assertEqual(person.id, None)
198
199     def testExistingDifferentFormat(self):
200         mail = self.mail('existing@example.com')
201         (person, new) = find_author(mail)
202         self.assertEqual(new, False)
203         self.assertEqual(person.id, self.person.id)
204
205     def testExistingDifferentCase(self):
206         mail = self.mail(self.existing_sender.upper())
207         (person, new) = find_author(mail)
208         self.assertEqual(new, False)
209         self.assertEqual(person.id, self.person.id)
210
211     def tearDown(self):
212         self.person.delete()
213
214 class MultipleProjectPatchTest(unittest.TestCase):
215     """ Test that patches sent to multiple patchwork projects are
216         handled correctly """
217
218     test_comment = 'Test Comment'
219     patch_filename = '0001-add-line.patch'
220     msgid = '<1@example.com>'
221
222     def setUp(self):
223         self.p1 = Project(linkname = 'test-project-1', name = 'Project 1',
224                 listid = '1.example.com', listemail='1@example.com')
225         self.p2 = Project(linkname = 'test-project-2', name = 'Project 2',
226                 listid = '2.example.com', listemail='2@example.com')
227
228         self.p1.save()
229         self.p2.save()
230
231         patch = read_patch(self.patch_filename)
232         email = create_email(self.test_comment + '\n' + patch)
233         email['Message-Id'] = self.msgid
234
235         del email['List-ID']
236         email['List-ID'] = '<' + self.p1.listid + '>'
237         parse_mail(email)
238
239         del email['List-ID']
240         email['List-ID'] = '<' + self.p2.listid + '>'
241         parse_mail(email)
242
243     def testParsedProjects(self):
244         self.assertEquals(Patch.objects.filter(project = self.p1).count(), 1)
245         self.assertEquals(Patch.objects.filter(project = self.p2).count(), 1)
246
247     def tearDown(self):
248         self.p1.delete()
249         self.p2.delete()
250
251
252 class MultipleProjectPatchCommentTest(MultipleProjectPatchTest):
253     """ Test that followups to multiple-project patches end up on the
254         correct patch """
255
256     comment_msgid = '<2@example.com>'
257     comment_content = 'test comment'
258
259     def setUp(self):
260         super(MultipleProjectPatchCommentTest, self).setUp()
261
262         for project in [self.p1, self.p2]:
263             email = MIMEText(self.comment_content)
264             email['From'] = defaults.sender
265             email['Subject'] = defaults.subject
266             email['Message-Id'] = self.comment_msgid
267             email['List-ID'] = '<' + project.listid + '>'
268             email['In-Reply-To'] = self.msgid
269             parse_mail(email)
270
271     def testParsedComment(self):
272         for project in [self.p1, self.p2]:
273             patch = Patch.objects.filter(project = project)[0]
274             # we should see two comments now - the original mail with the patch,
275             # and the one we parsed in setUp()
276             self.assertEquals(Comment.objects.filter(patch = patch).count(), 2)
277