1 #
2 # Copyright (c) 2001 Richard Jones, richard@bofh.asn.au.
3 # This module is free software, and you may redistribute it and/or modify
4 # under the same terms as Python, so long as this copyright message and
5 # disclaimer are retained in their original form.
6 #
7 # This module is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
10 #
11 # $Id: test_mailgw.py,v 1.54 2003-10-24 14:59:38 jlgijsbers Exp $
13 import unittest, tempfile, os, shutil, errno, imp, sys, difflib, rfc822
15 from cStringIO import StringIO
17 from roundup.mailgw import MailGW, Unauthorized, uidFromAddress, parseContent
18 from roundup import init, instance, rfc2822
20 NEEDS_INSTANCE = 1
22 class Message(rfc822.Message):
23 """String-based Message class with equivalence test."""
24 def __init__(self, s):
25 rfc822.Message.__init__(self, StringIO(s.strip()))
27 def __eq__(self, other):
28 del self['date'], other['date']
30 return (self.dict == other.dict and
31 self.fp.read() == other.fp.read())
33 # TODO: Do a semantic diff instead of a straight text diff when a test fails.
34 class DiffHelper:
35 def compareMessages(self, s2, s1):
36 """Compare messages for semantic equivalence."""
37 if not Message(s2) == Message(s1):
38 self.compareStrings(s2, s1)
40 def compareStrings(self, s2, s1):
41 '''Note the reversal of s2 and s1 - difflib.SequenceMatcher wants
42 the first to be the "original" but in the calls in this file,
43 the second arg is the original. Ho hum.
44 '''
45 # we have to special-case the Date: header here 'cos we can't test
46 # for it properly
47 l1=s1.strip().split('\n')
48 l2=[x for x in s2.strip().split('\n') if not x.startswith('Date: ')]
49 if l1 == l2:
50 return
52 s = difflib.SequenceMatcher(None, l1, l2)
53 res = ['Generated message not correct (diff follows):']
54 for value, s1s, s1e, s2s, s2e in s.get_opcodes():
55 if value == 'equal':
56 for i in range(s1s, s1e):
57 res.append(' %s'%l1[i])
58 elif value == 'delete':
59 for i in range(s1s, s1e):
60 res.append('- %s'%l1[i])
61 elif value == 'insert':
62 for i in range(s2s, s2e):
63 res.append('+ %s'%l2[i])
64 elif value == 'replace':
65 for i, j in zip(range(s1s, s1e), range(s2s, s2e)):
66 res.append('- %s'%l1[i])
67 res.append('+ %s'%l2[j])
69 raise AssertionError, '\n'.join(res)
71 class MailgwTestCase(unittest.TestCase, DiffHelper):
72 count = 0
73 schema = 'classic'
74 def setUp(self):
75 MailgwTestCase.count = MailgwTestCase.count + 1
76 self.dirname = '_test_mailgw_%s'%self.count
77 try:
78 shutil.rmtree(self.dirname)
79 except OSError, error:
80 if error.errno not in (errno.ENOENT, errno.ESRCH): raise
81 # create the instance
82 shutil.copytree('_empty_instance', self.dirname)
84 # check we can load the package
85 self.instance = instance.open(self.dirname)
86 # and open the database
87 self.db = self.instance.open('admin')
88 self.db.user.create(username='Chef', address='chef@bork.bork.bork',
89 realname='Bork, Chef', roles='User')
90 self.db.user.create(username='richard', address='richard@test',
91 roles='User')
92 self.db.user.create(username='mary', address='mary@test',
93 roles='User', realname='Contrary, Mary')
94 self.db.user.create(username='john', address='john@test',
95 alternate_addresses='jondoe@test\njohn.doe@test', roles='User',
96 realname='John Doe')
98 def tearDown(self):
99 if os.path.exists(os.environ['SENDMAILDEBUG']):
100 os.remove(os.environ['SENDMAILDEBUG'])
101 self.db.close()
102 try:
103 shutil.rmtree(self.dirname)
104 except OSError, error:
105 if error.errno not in (errno.ENOENT, errno.ESRCH): raise
107 def testEmptyMessage(self):
108 message = StringIO('''Content-Type: text/plain;
109 charset="iso-8859-1"
110 From: Chef <chef@bork.bork.bork>
111 To: issue_tracker@your.tracker.email.domain.example
112 Cc: richard@test
113 Message-Id: <dummy_test_message_id>
114 Subject: [issue] Testing...
116 ''')
117 handler = self.instance.MailGW(self.instance, self.db)
118 handler.trapExceptions = 0
119 nodeid = handler.main(message)
120 if os.path.exists(os.environ['SENDMAILDEBUG']):
121 error = open(os.environ['SENDMAILDEBUG']).read()
122 self.assertEqual('no error', error)
123 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
125 def doNewIssue(self):
126 message = StringIO('''Content-Type: text/plain;
127 charset="iso-8859-1"
128 From: Chef <chef@bork.bork.bork>
129 To: issue_tracker@your.tracker.email.domain.example
130 Cc: richard@test
131 Message-Id: <dummy_test_message_id>
132 Subject: [issue] Testing...
134 This is a test submission of a new issue.
135 ''')
136 handler = self.instance.MailGW(self.instance, self.db)
137 handler.trapExceptions = 0
138 nodeid = handler.main(message)
139 if os.path.exists(os.environ['SENDMAILDEBUG']):
140 error = open(os.environ['SENDMAILDEBUG']).read()
141 self.assertEqual('no error', error)
142 l = self.db.issue.get(nodeid, 'nosy')
143 l.sort()
144 self.assertEqual(l, ['3', '4'])
145 return nodeid
147 def testNewIssue(self):
148 self.doNewIssue()
150 def testNewIssueNosy(self):
151 self.instance.config.ADD_AUTHOR_TO_NOSY = 'yes'
152 message = StringIO('''Content-Type: text/plain;
153 charset="iso-8859-1"
154 From: Chef <chef@bork.bork.bork>
155 To: issue_tracker@your.tracker.email.domain.example
156 Cc: richard@test
157 Message-Id: <dummy_test_message_id>
158 Subject: [issue] Testing...
160 This is a test submission of a new issue.
161 ''')
162 handler = self.instance.MailGW(self.instance, self.db)
163 handler.trapExceptions = 0
164 nodeid = handler.main(message)
165 if os.path.exists(os.environ['SENDMAILDEBUG']):
166 error = open(os.environ['SENDMAILDEBUG']).read()
167 self.assertEqual('no error', error)
168 l = self.db.issue.get(nodeid, 'nosy')
169 l.sort()
170 self.assertEqual(l, ['3', '4'])
172 def testAlternateAddress(self):
173 message = StringIO('''Content-Type: text/plain;
174 charset="iso-8859-1"
175 From: John Doe <john.doe@test>
176 To: issue_tracker@your.tracker.email.domain.example
177 Message-Id: <dummy_test_message_id>
178 Subject: [issue] Testing...
180 This is a test submission of a new issue.
181 ''')
182 userlist = self.db.user.list()
183 handler = self.instance.MailGW(self.instance, self.db)
184 handler.trapExceptions = 0
185 handler.main(message)
186 if os.path.exists(os.environ['SENDMAILDEBUG']):
187 error = open(os.environ['SENDMAILDEBUG']).read()
188 self.assertEqual('no error', error)
189 self.assertEqual(userlist, self.db.user.list(),
190 "user created when it shouldn't have been")
192 def testNewIssueNoClass(self):
193 message = StringIO('''Content-Type: text/plain;
194 charset="iso-8859-1"
195 From: Chef <chef@bork.bork.bork>
196 To: issue_tracker@your.tracker.email.domain.example
197 Cc: richard@test
198 Message-Id: <dummy_test_message_id>
199 Subject: Testing...
201 This is a test submission of a new issue.
202 ''')
203 handler = self.instance.MailGW(self.instance, self.db)
204 handler.trapExceptions = 0
205 handler.main(message)
206 if os.path.exists(os.environ['SENDMAILDEBUG']):
207 error = open(os.environ['SENDMAILDEBUG']).read()
208 self.assertEqual('no error', error)
210 def testNewIssueAuthMsg(self):
211 message = StringIO('''Content-Type: text/plain;
212 charset="iso-8859-1"
213 From: Chef <chef@bork.bork.bork>
214 To: issue_tracker@your.tracker.email.domain.example
215 Message-Id: <dummy_test_message_id>
216 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
218 This is a test submission of a new issue.
219 ''')
220 handler = self.instance.MailGW(self.instance, self.db)
221 handler.trapExceptions = 0
222 # TODO: fix the damn config - this is apalling
223 self.db.config.MESSAGES_TO_AUTHOR = 'yes'
224 handler.main(message)
226 self.compareMessages(open(os.environ['SENDMAILDEBUG']).read(),
227 '''FROM: roundup-admin@your.tracker.email.domain.example
228 TO: chef@bork.bork.bork, mary@test, richard@test
229 Content-Type: text/plain; charset=utf-8
230 Subject: [issue1] Testing...
231 To: chef@bork.bork.bork, mary@test, richard@test
232 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
233 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
234 MIME-Version: 1.0
235 Message-Id: <dummy_test_message_id>
236 X-Roundup-Name: Roundup issue tracker
237 X-Roundup-Loop: hello
238 Content-Transfer-Encoding: quoted-printable
241 New submission from Bork, Chef <chef@bork.bork.bork>:
243 This is a test submission of a new issue.
245 ----------
246 assignedto: richard
247 messages: 1
248 nosy: Chef, mary, richard
249 status: unread
250 title: Testing...
251 _______________________________________________________________________
252 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
253 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
254 _______________________________________________________________________
255 ''')
257 # BUG
258 # def testMultipart(self):
259 # '''With more than one part'''
260 # see MultipartEnc tests: but if there is more than one part
261 # we return a multipart/mixed and the boundary contains
262 # the ip address of the test machine.
264 # BUG should test some binary attamchent too.
266 def testSimpleFollowup(self):
267 self.doNewIssue()
268 message = StringIO('''Content-Type: text/plain;
269 charset="iso-8859-1"
270 From: mary <mary@test>
271 To: issue_tracker@your.tracker.email.domain.example
272 Message-Id: <followup_dummy_id>
273 In-Reply-To: <dummy_test_message_id>
274 Subject: [issue1] Testing...
276 This is a second followup
277 ''')
278 handler = self.instance.MailGW(self.instance, self.db)
279 handler.trapExceptions = 0
280 handler.main(message)
281 self.compareMessages(open(os.environ['SENDMAILDEBUG']).read(),
282 '''FROM: roundup-admin@your.tracker.email.domain.example
283 TO: chef@bork.bork.bork, richard@test
284 Content-Type: text/plain; charset=utf-8
285 Subject: [issue1] Testing...
286 To: chef@bork.bork.bork, richard@test
287 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
288 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
289 MIME-Version: 1.0
290 Message-Id: <followup_dummy_id>
291 In-Reply-To: <dummy_test_message_id>
292 X-Roundup-Name: Roundup issue tracker
293 X-Roundup-Loop: hello
294 Content-Transfer-Encoding: quoted-printable
297 Contrary, Mary <mary@test> added the comment:
299 This is a second followup
301 ----------
302 status: unread -> chatting
303 _______________________________________________________________________
304 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
305 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
306 _______________________________________________________________________
307 ''')
309 def testFollowup(self):
310 self.doNewIssue()
312 message = StringIO('''Content-Type: text/plain;
313 charset="iso-8859-1"
314 From: richard <richard@test>
315 To: issue_tracker@your.tracker.email.domain.example
316 Message-Id: <followup_dummy_id>
317 In-Reply-To: <dummy_test_message_id>
318 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
320 This is a followup
321 ''')
322 handler = self.instance.MailGW(self.instance, self.db)
323 handler.trapExceptions = 0
324 handler.main(message)
325 l = self.db.issue.get('1', 'nosy')
326 l.sort()
327 self.assertEqual(l, ['3', '4', '5', '6'])
329 self.compareMessages(open(os.environ['SENDMAILDEBUG']).read(),
330 '''FROM: roundup-admin@your.tracker.email.domain.example
331 TO: chef@bork.bork.bork, john@test, mary@test
332 Content-Type: text/plain; charset=utf-8
333 Subject: [issue1] Testing...
334 To: chef@bork.bork.bork, john@test, mary@test
335 From: richard <issue_tracker@your.tracker.email.domain.example>
336 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
337 MIME-Version: 1.0
338 Message-Id: <followup_dummy_id>
339 In-Reply-To: <dummy_test_message_id>
340 X-Roundup-Name: Roundup issue tracker
341 X-Roundup-Loop: hello
342 Content-Transfer-Encoding: quoted-printable
345 richard <richard@test> added the comment:
347 This is a followup
349 ----------
350 assignedto: -> mary
351 nosy: +john, mary
352 status: unread -> chatting
353 _______________________________________________________________________
354 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
355 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
356 _______________________________________________________________________
357 ''')
359 def testFollowupTitleMatch(self):
360 self.doNewIssue()
361 message = StringIO('''Content-Type: text/plain;
362 charset="iso-8859-1"
363 From: richard <richard@test>
364 To: issue_tracker@your.tracker.email.domain.example
365 Message-Id: <followup_dummy_id>
366 In-Reply-To: <dummy_test_message_id>
367 Subject: Re: Testing... [assignedto=mary; nosy=+john]
369 This is a followup
370 ''')
371 handler = self.instance.MailGW(self.instance, self.db)
372 handler.trapExceptions = 0
373 handler.main(message)
375 self.compareMessages(open(os.environ['SENDMAILDEBUG']).read(),
376 '''FROM: roundup-admin@your.tracker.email.domain.example
377 TO: chef@bork.bork.bork, john@test, mary@test
378 Content-Type: text/plain; charset=utf-8
379 Subject: [issue1] Testing...
380 To: chef@bork.bork.bork, john@test, mary@test
381 From: richard <issue_tracker@your.tracker.email.domain.example>
382 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
383 MIME-Version: 1.0
384 Message-Id: <followup_dummy_id>
385 In-Reply-To: <dummy_test_message_id>
386 X-Roundup-Name: Roundup issue tracker
387 X-Roundup-Loop: hello
388 Content-Transfer-Encoding: quoted-printable
391 richard <richard@test> added the comment:
393 This is a followup
395 ----------
396 assignedto: -> mary
397 nosy: +john, mary
398 status: unread -> chatting
399 _______________________________________________________________________
400 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
401 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
402 _______________________________________________________________________
403 ''')
405 def testFollowupNosyAuthor(self):
406 self.doNewIssue()
407 self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
408 message = StringIO('''Content-Type: text/plain;
409 charset="iso-8859-1"
410 From: john@test
411 To: issue_tracker@your.tracker.email.domain.example
412 Message-Id: <followup_dummy_id>
413 In-Reply-To: <dummy_test_message_id>
414 Subject: [issue1] Testing...
416 This is a followup
417 ''')
418 handler = self.instance.MailGW(self.instance, self.db)
419 handler.trapExceptions = 0
420 handler.main(message)
422 self.compareMessages(open(os.environ['SENDMAILDEBUG']).read(),
423 '''FROM: roundup-admin@your.tracker.email.domain.example
424 TO: chef@bork.bork.bork, richard@test
425 Content-Type: text/plain; charset=utf-8
426 Subject: [issue1] Testing...
427 To: chef@bork.bork.bork, richard@test
428 From: John Doe <issue_tracker@your.tracker.email.domain.example>
429 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
430 MIME-Version: 1.0
431 Message-Id: <followup_dummy_id>
432 In-Reply-To: <dummy_test_message_id>
433 X-Roundup-Name: Roundup issue tracker
434 X-Roundup-Loop: hello
435 Content-Transfer-Encoding: quoted-printable
438 John Doe <john@test> added the comment:
440 This is a followup
442 ----------
443 nosy: +john
444 status: unread -> chatting
445 _______________________________________________________________________
446 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
447 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
448 _______________________________________________________________________
450 ''')
452 def testFollowupNosyRecipients(self):
453 self.doNewIssue()
454 self.db.config.ADD_RECIPIENTS_TO_NOSY = 'yes'
455 message = StringIO('''Content-Type: text/plain;
456 charset="iso-8859-1"
457 From: richard@test
458 To: issue_tracker@your.tracker.email.domain.example
459 Cc: john@test
460 Message-Id: <followup_dummy_id>
461 In-Reply-To: <dummy_test_message_id>
462 Subject: [issue1] Testing...
464 This is a followup
465 ''')
466 handler = self.instance.MailGW(self.instance, self.db)
467 handler.trapExceptions = 0
468 handler.main(message)
470 self.compareMessages(open(os.environ['SENDMAILDEBUG']).read(),
471 '''FROM: roundup-admin@your.tracker.email.domain.example
472 TO: chef@bork.bork.bork
473 Content-Type: text/plain; charset=utf-8
474 Subject: [issue1] Testing...
475 To: chef@bork.bork.bork
476 From: richard <issue_tracker@your.tracker.email.domain.example>
477 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
478 MIME-Version: 1.0
479 Message-Id: <followup_dummy_id>
480 In-Reply-To: <dummy_test_message_id>
481 X-Roundup-Name: Roundup issue tracker
482 X-Roundup-Loop: hello
483 Content-Transfer-Encoding: quoted-printable
486 richard <richard@test> added the comment:
488 This is a followup
490 ----------
491 nosy: +john
492 status: unread -> chatting
493 _______________________________________________________________________
494 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
495 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
496 _______________________________________________________________________
498 ''')
500 def testFollowupNosyAuthorAndCopy(self):
501 self.doNewIssue()
502 self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
503 self.db.config.MESSAGES_TO_AUTHOR = 'yes'
504 message = StringIO('''Content-Type: text/plain;
505 charset="iso-8859-1"
506 From: john@test
507 To: issue_tracker@your.tracker.email.domain.example
508 Message-Id: <followup_dummy_id>
509 In-Reply-To: <dummy_test_message_id>
510 Subject: [issue1] Testing...
512 This is a followup
513 ''')
514 handler = self.instance.MailGW(self.instance, self.db)
515 handler.trapExceptions = 0
516 handler.main(message)
518 self.compareMessages(open(os.environ['SENDMAILDEBUG']).read(),
519 '''FROM: roundup-admin@your.tracker.email.domain.example
520 TO: chef@bork.bork.bork, john@test, richard@test
521 Content-Type: text/plain; charset=utf-8
522 Subject: [issue1] Testing...
523 To: chef@bork.bork.bork, john@test, richard@test
524 From: John Doe <issue_tracker@your.tracker.email.domain.example>
525 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
526 MIME-Version: 1.0
527 Message-Id: <followup_dummy_id>
528 In-Reply-To: <dummy_test_message_id>
529 X-Roundup-Name: Roundup issue tracker
530 X-Roundup-Loop: hello
531 Content-Transfer-Encoding: quoted-printable
534 John Doe <john@test> added the comment:
536 This is a followup
538 ----------
539 nosy: +john
540 status: unread -> chatting
541 _______________________________________________________________________
542 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
543 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
544 _______________________________________________________________________
546 ''')
548 def testFollowupNoNosyAuthor(self):
549 self.doNewIssue()
550 self.instance.config.ADD_AUTHOR_TO_NOSY = 'no'
551 message = StringIO('''Content-Type: text/plain;
552 charset="iso-8859-1"
553 From: john@test
554 To: issue_tracker@your.tracker.email.domain.example
555 Message-Id: <followup_dummy_id>
556 In-Reply-To: <dummy_test_message_id>
557 Subject: [issue1] Testing...
559 This is a followup
560 ''')
561 handler = self.instance.MailGW(self.instance, self.db)
562 handler.trapExceptions = 0
563 handler.main(message)
565 self.compareMessages(open(os.environ['SENDMAILDEBUG']).read(),
566 '''FROM: roundup-admin@your.tracker.email.domain.example
567 TO: chef@bork.bork.bork, richard@test
568 Content-Type: text/plain; charset=utf-8
569 Subject: [issue1] Testing...
570 To: chef@bork.bork.bork, richard@test
571 From: John Doe <issue_tracker@your.tracker.email.domain.example>
572 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
573 MIME-Version: 1.0
574 Message-Id: <followup_dummy_id>
575 In-Reply-To: <dummy_test_message_id>
576 X-Roundup-Name: Roundup issue tracker
577 X-Roundup-Loop: hello
578 Content-Transfer-Encoding: quoted-printable
581 John Doe <john@test> added the comment:
583 This is a followup
585 ----------
586 status: unread -> chatting
587 _______________________________________________________________________
588 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
589 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
590 _______________________________________________________________________
592 ''')
594 def testFollowupNoNosyRecipients(self):
595 self.doNewIssue()
596 self.instance.config.ADD_RECIPIENTS_TO_NOSY = 'no'
597 message = StringIO('''Content-Type: text/plain;
598 charset="iso-8859-1"
599 From: richard@test
600 To: issue_tracker@your.tracker.email.domain.example
601 Cc: john@test
602 Message-Id: <followup_dummy_id>
603 In-Reply-To: <dummy_test_message_id>
604 Subject: [issue1] Testing...
606 This is a followup
607 ''')
608 handler = self.instance.MailGW(self.instance, self.db)
609 handler.trapExceptions = 0
610 handler.main(message)
612 self.compareMessages(open(os.environ['SENDMAILDEBUG']).read(),
613 '''FROM: roundup-admin@your.tracker.email.domain.example
614 TO: chef@bork.bork.bork
615 Content-Type: text/plain; charset=utf-8
616 Subject: [issue1] Testing...
617 To: chef@bork.bork.bork
618 From: richard <issue_tracker@your.tracker.email.domain.example>
619 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
620 MIME-Version: 1.0
621 Message-Id: <followup_dummy_id>
622 In-Reply-To: <dummy_test_message_id>
623 X-Roundup-Name: Roundup issue tracker
624 X-Roundup-Loop: hello
625 Content-Transfer-Encoding: quoted-printable
628 richard <richard@test> added the comment:
630 This is a followup
632 ----------
633 status: unread -> chatting
634 _______________________________________________________________________
635 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
636 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
637 _______________________________________________________________________
639 ''')
641 def testFollowupEmptyMessage(self):
642 self.doNewIssue()
644 message = StringIO('''Content-Type: text/plain;
645 charset="iso-8859-1"
646 From: richard <richard@test>
647 To: issue_tracker@your.tracker.email.domain.example
648 Message-Id: <followup_dummy_id>
649 In-Reply-To: <dummy_test_message_id>
650 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
652 ''')
653 handler = self.instance.MailGW(self.instance, self.db)
654 handler.trapExceptions = 0
655 handler.main(message)
656 l = self.db.issue.get('1', 'nosy')
657 l.sort()
658 self.assertEqual(l, ['3', '4', '5', '6'])
660 # should be no file created (ie. no message)
661 assert not os.path.exists(os.environ['SENDMAILDEBUG'])
663 def testNosyRemove(self):
664 self.doNewIssue()
666 message = StringIO('''Content-Type: text/plain;
667 charset="iso-8859-1"
668 From: richard <richard@test>
669 To: issue_tracker@your.tracker.email.domain.example
670 Message-Id: <followup_dummy_id>
671 In-Reply-To: <dummy_test_message_id>
672 Subject: [issue1] Testing... [nosy=-richard]
674 ''')
675 handler = self.instance.MailGW(self.instance, self.db)
676 handler.trapExceptions = 0
677 handler.main(message)
678 l = self.db.issue.get('1', 'nosy')
679 l.sort()
680 self.assertEqual(l, ['3'])
682 # NO NOSY MESSAGE SHOULD BE SENT!
683 self.assert_(not os.path.exists(os.environ['SENDMAILDEBUG']))
685 def testNewUserAuthor(self):
686 # first without the permission
687 # heh... just ignore the API for a second ;)
688 self.db.security.role['anonymous'].permissions=[]
689 anonid = self.db.user.lookup('anonymous')
690 self.db.user.set(anonid, roles='Anonymous')
692 self.db.security.hasPermission('Email Registration', anonid)
693 l = self.db.user.list()
694 l.sort()
695 s = '''Content-Type: text/plain;
696 charset="iso-8859-1"
697 From: fubar <fubar@bork.bork.bork>
698 To: issue_tracker@your.tracker.email.domain.example
699 Message-Id: <dummy_test_message_id>
700 Subject: [issue] Testing...
702 This is a test submission of a new issue.
703 '''
704 message = StringIO(s)
705 handler = self.instance.MailGW(self.instance, self.db)
706 handler.trapExceptions = 0
707 self.assertRaises(Unauthorized, handler.main, message)
708 m = self.db.user.list()
709 m.sort()
710 self.assertEqual(l, m)
712 # now with the permission
713 p = self.db.security.getPermission('Email Registration')
714 self.db.security.role['anonymous'].permissions=[p]
715 handler = self.instance.MailGW(self.instance, self.db)
716 handler.trapExceptions = 0
717 message = StringIO(s)
718 handler.main(message)
719 m = self.db.user.list()
720 m.sort()
721 self.assertNotEqual(l, m)
723 def testEnc01(self):
724 self.doNewIssue()
725 message = StringIO('''Content-Type: text/plain;
726 charset="iso-8859-1"
727 From: mary <mary@test>
728 To: issue_tracker@your.tracker.email.domain.example
729 Message-Id: <followup_dummy_id>
730 In-Reply-To: <dummy_test_message_id>
731 Subject: [issue1] Testing...
732 Content-Type: text/plain;
733 charset="iso-8859-1"
734 Content-Transfer-Encoding: quoted-printable
736 A message with encoding (encoded oe =F6)
738 ''')
739 handler = self.instance.MailGW(self.instance, self.db)
740 handler.trapExceptions = 0
741 handler.main(message)
742 self.compareMessages(open(os.environ['SENDMAILDEBUG']).read(),
743 '''FROM: roundup-admin@your.tracker.email.domain.example
744 TO: chef@bork.bork.bork, richard@test
745 Content-Type: text/plain; charset=utf-8
746 Subject: [issue1] Testing...
747 To: chef@bork.bork.bork, richard@test
748 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
749 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
750 MIME-Version: 1.0
751 Message-Id: <followup_dummy_id>
752 In-Reply-To: <dummy_test_message_id>
753 X-Roundup-Name: Roundup issue tracker
754 X-Roundup-Loop: hello
755 Content-Transfer-Encoding: quoted-printable
758 Contrary, Mary <mary@test> added the comment:
760 A message with encoding (encoded oe =C3=B6)
762 ----------
763 status: unread -> chatting
764 _______________________________________________________________________
765 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
766 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
767 _______________________________________________________________________
768 ''')
771 def testMultipartEnc01(self):
772 self.doNewIssue()
773 message = StringIO('''Content-Type: text/plain;
774 charset="iso-8859-1"
775 From: mary <mary@test>
776 To: issue_tracker@your.tracker.email.domain.example
777 Message-Id: <followup_dummy_id>
778 In-Reply-To: <dummy_test_message_id>
779 Subject: [issue1] Testing...
780 Content-Type: multipart/mixed;
781 boundary="----_=_NextPart_000_01"
783 This message is in MIME format. Since your mail reader does not understand
784 this format, some or all of this message may not be legible.
786 ------_=_NextPart_000_01
787 Content-Type: text/plain;
788 charset="iso-8859-1"
789 Content-Transfer-Encoding: quoted-printable
791 A message with first part encoded (encoded oe =F6)
793 ''')
794 handler = self.instance.MailGW(self.instance, self.db)
795 handler.trapExceptions = 0
796 handler.main(message)
797 self.compareMessages(open(os.environ['SENDMAILDEBUG']).read(),
798 '''FROM: roundup-admin@your.tracker.email.domain.example
799 TO: chef@bork.bork.bork, richard@test
800 Content-Type: text/plain; charset=utf-8
801 Subject: [issue1] Testing...
802 To: chef@bork.bork.bork, richard@test
803 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
804 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
805 MIME-Version: 1.0
806 Message-Id: <followup_dummy_id>
807 In-Reply-To: <dummy_test_message_id>
808 X-Roundup-Name: Roundup issue tracker
809 X-Roundup-Loop: hello
810 Content-Transfer-Encoding: quoted-printable
813 Contrary, Mary <mary@test> added the comment:
815 A message with first part encoded (encoded oe =C3=B6)
817 ----------
818 status: unread -> chatting
819 _______________________________________________________________________
820 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
821 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
822 _______________________________________________________________________
823 ''')
825 def testContentDisposition(self):
826 self.doNewIssue()
827 message = StringIO('''Content-Type: text/plain;
828 charset="iso-8859-1"
829 From: mary <mary@test>
830 To: issue_tracker@your.tracker.email.domain.example
831 Message-Id: <followup_dummy_id>
832 In-Reply-To: <dummy_test_message_id>
833 Subject: [issue1] Testing...
834 Content-Type: multipart/mixed; boundary="bCsyhTFzCvuiizWE"
835 Content-Disposition: inline
838 --bCsyhTFzCvuiizWE
839 Content-Type: text/plain; charset=us-ascii
840 Content-Disposition: inline
842 test attachment binary
844 --bCsyhTFzCvuiizWE
845 Content-Type: application/octet-stream
846 Content-Disposition: attachment; filename="main.dvi"
848 xxxxxx
850 --bCsyhTFzCvuiizWE--
851 ''')
852 handler = self.instance.MailGW(self.instance, self.db)
853 handler.trapExceptions = 0
854 handler.main(message)
855 messages = self.db.issue.get('1', 'messages')
856 messages.sort()
857 file = self.db.msg.get(messages[-1], 'files')[0]
858 self.assertEqual(self.db.file.get(file, 'name'), 'main.dvi')
860 def testFollowupStupidQuoting(self):
861 self.doNewIssue()
863 message = StringIO('''Content-Type: text/plain;
864 charset="iso-8859-1"
865 From: richard <richard@test>
866 To: issue_tracker@your.tracker.email.domain.example
867 Message-Id: <followup_dummy_id>
868 In-Reply-To: <dummy_test_message_id>
869 Subject: Re: "[issue1] Testing... "
871 This is a followup
872 ''')
873 handler = self.instance.MailGW(self.instance, self.db)
874 handler.trapExceptions = 0
875 handler.main(message)
877 self.compareMessages(open(os.environ['SENDMAILDEBUG']).read(),
878 '''FROM: roundup-admin@your.tracker.email.domain.example
879 TO: chef@bork.bork.bork
880 Content-Type: text/plain; charset=utf-8
881 Subject: [issue1] Testing...
882 To: chef@bork.bork.bork
883 From: richard <issue_tracker@your.tracker.email.domain.example>
884 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
885 MIME-Version: 1.0
886 Message-Id: <followup_dummy_id>
887 In-Reply-To: <dummy_test_message_id>
888 X-Roundup-Name: Roundup issue tracker
889 X-Roundup-Loop: hello
890 Content-Transfer-Encoding: quoted-printable
893 richard <richard@test> added the comment:
895 This is a followup
897 ----------
898 status: unread -> chatting
899 _______________________________________________________________________
900 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
901 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
902 _______________________________________________________________________
903 ''')
905 def testEmailQuoting(self):
906 self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'no'
907 self.innerTestQuoting('''This is a followup
908 ''')
910 def testEmailQuotingRemove(self):
911 self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'yes'
912 self.innerTestQuoting('''Blah blah wrote:
913 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
914 > skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
915 >
917 This is a followup
918 ''')
920 def innerTestQuoting(self, expect):
921 nodeid = self.doNewIssue()
923 messages = self.db.issue.get(nodeid, 'messages')
925 message = StringIO('''Content-Type: text/plain;
926 charset="iso-8859-1"
927 From: richard <richard@test>
928 To: issue_tracker@your.tracker.email.domain.example
929 Message-Id: <followup_dummy_id>
930 In-Reply-To: <dummy_test_message_id>
931 Subject: Re: [issue1] Testing...
933 Blah blah wrote:
934 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
935 > skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
936 >
938 This is a followup
939 ''')
940 handler = self.instance.MailGW(self.instance, self.db)
941 handler.trapExceptions = 0
942 handler.main(message)
944 # figure the new message id
945 newmessages = self.db.issue.get(nodeid, 'messages')
946 for msg in messages:
947 newmessages.remove(msg)
948 messageid = newmessages[0]
950 self.compareMessages(self.db.msg.get(messageid, 'content'), expect)
952 def testUserLookup(self):
953 i = self.db.user.create(username='user1', address='user1@foo.com')
954 self.assertEqual(uidFromAddress(self.db, ('', 'user1@foo.com'), 0), i)
955 self.assertEqual(uidFromAddress(self.db, ('', 'USER1@foo.com'), 0), i)
956 i = self.db.user.create(username='user2', address='USER2@foo.com')
957 self.assertEqual(uidFromAddress(self.db, ('', 'USER2@foo.com'), 0), i)
958 self.assertEqual(uidFromAddress(self.db, ('', 'user2@foo.com'), 0), i)
960 def testUserAlternateLookup(self):
961 i = self.db.user.create(username='user1', address='user1@foo.com',
962 alternate_addresses='user1@bar.com')
963 self.assertEqual(uidFromAddress(self.db, ('', 'user1@bar.com'), 0), i)
964 self.assertEqual(uidFromAddress(self.db, ('', 'USER1@bar.com'), 0), i)
966 def testUserCreate(self):
967 i = uidFromAddress(self.db, ('', 'user@foo.com'), 1)
968 self.assertNotEqual(uidFromAddress(self.db, ('', 'user@bar.com'), 1), i)
970 def testRFC2822(self):
971 ascii_header = "[issue243] This is a \"test\" - with 'quotation' marks"
972 unicode_header = '[issue244] \xd0\xb0\xd0\xbd\xd0\xb4\xd1\x80\xd0\xb5\xd0\xb9'
973 unicode_encoded = '=?utf-8?q?[issue244]_=D0=B0=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?='
974 self.assertEqual(rfc2822.encode_header(ascii_header), ascii_header)
975 self.assertEqual(rfc2822.encode_header(unicode_header), unicode_encoded)
977 def testRegistrationConfirmation(self):
978 otk = "Aj4euk4LZSAdwePohj90SME5SpopLETL"
979 self.db.otks.set(otk, username='johannes', __time='')
980 message = StringIO('''Content-Type: text/plain;
981 charset="iso-8859-1"
982 From: Chef <chef@bork.bork.bork>
983 To: issue_tracker@your.tracker.email.domain.example
984 Cc: richard@test
985 Message-Id: <dummy_test_message_id>
986 Subject: Re: Complete your registration to Roundup issue tracker\r
987 -- key %s
989 This is a test confirmation of registration.
990 ''' % otk)
991 handler = self.instance.MailGW(self.instance, self.db)
992 handler.trapExceptions = 0
993 handler.main(message)
995 self.db.user.lookup('johannes')
998 class ParseContentTestCase(unittest.TestCase):
999 def testSignatureRemoval(self):
1000 summary, content = parseContent('''Testing, testing.
1002 --
1003 Signature''', 1, 0)
1004 self.assertEqual(content, 'Testing, testing.')
1006 def testKeepMultipleHyphens(self):
1007 body = '''Testing, testing.
1009 ----
1010 Testing, testing.'''
1011 summary, content = parseContent(body, 1, 0)
1012 self.assertEqual(body, content)
1014 def suite():
1015 l = [#unittest.makeSuite(MailgwTestCase),
1016 unittest.makeSuite(ParseContentTestCase)]
1017 return unittest.TestSuite(l)
1020 # vim: set filetype=python ts=4 sw=4 et si