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.58 2003-11-03 18:34:03 jlgijsbers Exp $
13 import unittest, tempfile, os, shutil, errno, imp, sys, difflib, rfc822
15 from cStringIO import StringIO
17 if not os.environ.has_key('SENDMAILDEBUG'):
18 os.environ['SENDMAILDEBUG'] = 'mail-test.log'
19 SENDMAILDEBUG = os.environ['SENDMAILDEBUG']
21 from roundup.mailgw import MailGW, Unauthorized, uidFromAddress, parseContent
22 from roundup import init, instance, rfc2822
25 class Message(rfc822.Message):
26 """String-based Message class with equivalence test."""
27 def __init__(self, s):
28 rfc822.Message.__init__(self, StringIO(s.strip()))
30 def __eq__(self, other):
31 del self['date'], other['date']
33 return (self.dict == other.dict and
34 self.fp.read() == other.fp.read())
36 # TODO: Do a semantic diff instead of a straight text diff when a test fails.
37 class DiffHelper:
38 def compareMessages(self, s2, s1):
39 """Compare messages for semantic equivalence."""
40 if not Message(s2) == Message(s1):
41 self.compareStrings(s2, s1)
43 def compareStrings(self, s2, s1):
44 '''Note the reversal of s2 and s1 - difflib.SequenceMatcher wants
45 the first to be the "original" but in the calls in this file,
46 the second arg is the original. Ho hum.
47 '''
48 # we have to special-case the Date: header here 'cos we can't test
49 # for it properly
50 l1=s1.strip().split('\n')
51 l2=[x for x in s2.strip().split('\n') if not x.startswith('Date: ')]
52 if l1 == l2:
53 return
55 s = difflib.SequenceMatcher(None, l1, l2)
56 res = ['Generated message not correct (diff follows):']
57 for value, s1s, s1e, s2s, s2e in s.get_opcodes():
58 if value == 'equal':
59 for i in range(s1s, s1e):
60 res.append(' %s'%l1[i])
61 elif value == 'delete':
62 for i in range(s1s, s1e):
63 res.append('- %s'%l1[i])
64 elif value == 'insert':
65 for i in range(s2s, s2e):
66 res.append('+ %s'%l2[i])
67 elif value == 'replace':
68 for i, j in zip(range(s1s, s1e), range(s2s, s2e)):
69 res.append('- %s'%l1[i])
70 res.append('+ %s'%l2[j])
72 raise AssertionError, '\n'.join(res)
74 class MailgwTestCase(unittest.TestCase, DiffHelper):
75 count = 0
76 schema = 'classic'
77 def setUp(self):
78 MailgwTestCase.count = MailgwTestCase.count + 1
79 self.dirname = '_test_mailgw_%s'%self.count
80 try:
81 shutil.rmtree(self.dirname)
82 except OSError, error:
83 if error.errno not in (errno.ENOENT, errno.ESRCH): raise
84 # create the instance
85 init.install(self.dirname, 'templates/classic')
86 init.write_select_db(self.dirname, 'anydbm')
87 init.initialise(self.dirname, 'sekrit')
89 # check we can load the package
90 self.instance = instance.open(self.dirname)
92 # and open the database
93 self.db = self.instance.open('admin')
94 self.db.user.create(username='Chef', address='chef@bork.bork.bork',
95 realname='Bork, Chef', roles='User')
96 self.db.user.create(username='richard', address='richard@test',
97 roles='User')
98 self.db.user.create(username='mary', address='mary@test',
99 roles='User', realname='Contrary, Mary')
100 self.db.user.create(username='john', address='john@test',
101 alternate_addresses='jondoe@test\njohn.doe@test', roles='User',
102 realname='John Doe')
104 def tearDown(self):
105 if os.path.exists(SENDMAILDEBUG):
106 os.remove(SENDMAILDEBUG)
107 self.db.close()
108 try:
109 shutil.rmtree(self.dirname)
110 except OSError, error:
111 if error.errno not in (errno.ENOENT, errno.ESRCH): raise
113 def _get_mail(self):
114 f = open(SENDMAILDEBUG)
115 try:
116 return f.read()
117 finally:
118 f.close()
120 def testEmptyMessage(self):
121 message = StringIO('''Content-Type: text/plain;
122 charset="iso-8859-1"
123 From: Chef <chef@bork.bork.bork>
124 To: issue_tracker@your.tracker.email.domain.example
125 Cc: richard@test
126 Message-Id: <dummy_test_message_id>
127 Subject: [issue] Testing...
129 ''')
130 handler = self.instance.MailGW(self.instance, self.db)
131 handler.trapExceptions = 0
132 nodeid = handler.main(message)
133 assert not os.path.exists(SENDMAILDEBUG)
134 self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
136 def doNewIssue(self):
137 message = StringIO('''Content-Type: text/plain;
138 charset="iso-8859-1"
139 From: Chef <chef@bork.bork.bork>
140 To: issue_tracker@your.tracker.email.domain.example
141 Cc: richard@test
142 Message-Id: <dummy_test_message_id>
143 Subject: [issue] Testing...
145 This is a test submission of a new issue.
146 ''')
147 handler = self.instance.MailGW(self.instance, self.db)
148 handler.trapExceptions = 0
149 nodeid = handler.main(message)
150 assert not os.path.exists(SENDMAILDEBUG)
151 l = self.db.issue.get(nodeid, 'nosy')
152 l.sort()
153 self.assertEqual(l, ['3', '4'])
154 return nodeid
156 def testNewIssue(self):
157 self.doNewIssue()
159 def testNewIssueNosy(self):
160 self.instance.config.ADD_AUTHOR_TO_NOSY = 'yes'
161 message = StringIO('''Content-Type: text/plain;
162 charset="iso-8859-1"
163 From: Chef <chef@bork.bork.bork>
164 To: issue_tracker@your.tracker.email.domain.example
165 Cc: richard@test
166 Message-Id: <dummy_test_message_id>
167 Subject: [issue] Testing...
169 This is a test submission of a new issue.
170 ''')
171 handler = self.instance.MailGW(self.instance, self.db)
172 handler.trapExceptions = 0
173 nodeid = handler.main(message)
174 assert not os.path.exists(SENDMAILDEBUG)
175 l = self.db.issue.get(nodeid, 'nosy')
176 l.sort()
177 self.assertEqual(l, ['3', '4'])
179 def testAlternateAddress(self):
180 message = StringIO('''Content-Type: text/plain;
181 charset="iso-8859-1"
182 From: John Doe <john.doe@test>
183 To: issue_tracker@your.tracker.email.domain.example
184 Message-Id: <dummy_test_message_id>
185 Subject: [issue] Testing...
187 This is a test submission of a new issue.
188 ''')
189 userlist = self.db.user.list()
190 handler = self.instance.MailGW(self.instance, self.db)
191 handler.trapExceptions = 0
192 handler.main(message)
193 assert not os.path.exists(SENDMAILDEBUG)
194 self.assertEqual(userlist, self.db.user.list(),
195 "user created when it shouldn't have been")
197 def testNewIssueNoClass(self):
198 message = StringIO('''Content-Type: text/plain;
199 charset="iso-8859-1"
200 From: Chef <chef@bork.bork.bork>
201 To: issue_tracker@your.tracker.email.domain.example
202 Cc: richard@test
203 Message-Id: <dummy_test_message_id>
204 Subject: Testing...
206 This is a test submission of a new issue.
207 ''')
208 handler = self.instance.MailGW(self.instance, self.db)
209 handler.trapExceptions = 0
210 handler.main(message)
211 assert not os.path.exists(SENDMAILDEBUG)
213 def testNewIssueAuthMsg(self):
214 message = StringIO('''Content-Type: text/plain;
215 charset="iso-8859-1"
216 From: Chef <chef@bork.bork.bork>
217 To: issue_tracker@your.tracker.email.domain.example
218 Message-Id: <dummy_test_message_id>
219 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
221 This is a test submission of a new issue.
222 ''')
223 handler = self.instance.MailGW(self.instance, self.db)
224 handler.trapExceptions = 0
225 # TODO: fix the damn config - this is apalling
226 self.db.config.MESSAGES_TO_AUTHOR = 'yes'
227 handler.main(message)
229 self.compareMessages(self._get_mail(),
230 '''FROM: roundup-admin@your.tracker.email.domain.example
231 TO: chef@bork.bork.bork, mary@test, richard@test
232 Content-Type: text/plain; charset=utf-8
233 Subject: [issue1] Testing...
234 To: chef@bork.bork.bork, mary@test, richard@test
235 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
236 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
237 MIME-Version: 1.0
238 Message-Id: <dummy_test_message_id>
239 X-Roundup-Name: Roundup issue tracker
240 X-Roundup-Loop: hello
241 Content-Transfer-Encoding: quoted-printable
244 New submission from Bork, Chef <chef@bork.bork.bork>:
246 This is a test submission of a new issue.
248 ----------
249 assignedto: richard
250 messages: 1
251 nosy: Chef, mary, richard
252 status: unread
253 title: Testing...
254 _______________________________________________________________________
255 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
256 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
257 _______________________________________________________________________
258 ''')
260 # BUG
261 # def testMultipart(self):
262 # '''With more than one part'''
263 # see MultipartEnc tests: but if there is more than one part
264 # we return a multipart/mixed and the boundary contains
265 # the ip address of the test machine.
267 # BUG should test some binary attamchent too.
269 def testSimpleFollowup(self):
270 self.doNewIssue()
271 message = StringIO('''Content-Type: text/plain;
272 charset="iso-8859-1"
273 From: mary <mary@test>
274 To: issue_tracker@your.tracker.email.domain.example
275 Message-Id: <followup_dummy_id>
276 In-Reply-To: <dummy_test_message_id>
277 Subject: [issue1] Testing...
279 This is a second followup
280 ''')
281 handler = self.instance.MailGW(self.instance, self.db)
282 handler.trapExceptions = 0
283 handler.main(message)
284 self.compareMessages(self._get_mail(),
285 '''FROM: roundup-admin@your.tracker.email.domain.example
286 TO: chef@bork.bork.bork, richard@test
287 Content-Type: text/plain; charset=utf-8
288 Subject: [issue1] Testing...
289 To: chef@bork.bork.bork, richard@test
290 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
291 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
292 MIME-Version: 1.0
293 Message-Id: <followup_dummy_id>
294 In-Reply-To: <dummy_test_message_id>
295 X-Roundup-Name: Roundup issue tracker
296 X-Roundup-Loop: hello
297 Content-Transfer-Encoding: quoted-printable
300 Contrary, Mary <mary@test> added the comment:
302 This is a second followup
304 ----------
305 status: unread -> chatting
306 _______________________________________________________________________
307 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
308 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
309 _______________________________________________________________________
310 ''')
312 def testFollowup(self):
313 self.doNewIssue()
315 message = StringIO('''Content-Type: text/plain;
316 charset="iso-8859-1"
317 From: richard <richard@test>
318 To: issue_tracker@your.tracker.email.domain.example
319 Message-Id: <followup_dummy_id>
320 In-Reply-To: <dummy_test_message_id>
321 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
323 This is a followup
324 ''')
325 handler = self.instance.MailGW(self.instance, self.db)
326 handler.trapExceptions = 0
327 handler.main(message)
328 l = self.db.issue.get('1', 'nosy')
329 l.sort()
330 self.assertEqual(l, ['3', '4', '5', '6'])
332 self.compareMessages(self._get_mail(),
333 '''FROM: roundup-admin@your.tracker.email.domain.example
334 TO: chef@bork.bork.bork, john@test, mary@test
335 Content-Type: text/plain; charset=utf-8
336 Subject: [issue1] Testing...
337 To: chef@bork.bork.bork, john@test, mary@test
338 From: richard <issue_tracker@your.tracker.email.domain.example>
339 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
340 MIME-Version: 1.0
341 Message-Id: <followup_dummy_id>
342 In-Reply-To: <dummy_test_message_id>
343 X-Roundup-Name: Roundup issue tracker
344 X-Roundup-Loop: hello
345 Content-Transfer-Encoding: quoted-printable
348 richard <richard@test> added the comment:
350 This is a followup
352 ----------
353 assignedto: -> mary
354 nosy: +john, mary
355 status: unread -> chatting
356 _______________________________________________________________________
357 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
358 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
359 _______________________________________________________________________
360 ''')
362 def testFollowupTitleMatch(self):
363 self.doNewIssue()
364 message = StringIO('''Content-Type: text/plain;
365 charset="iso-8859-1"
366 From: richard <richard@test>
367 To: issue_tracker@your.tracker.email.domain.example
368 Message-Id: <followup_dummy_id>
369 In-Reply-To: <dummy_test_message_id>
370 Subject: Re: Testing... [assignedto=mary; nosy=+john]
372 This is a followup
373 ''')
374 handler = self.instance.MailGW(self.instance, self.db)
375 handler.trapExceptions = 0
376 handler.main(message)
378 self.compareMessages(self._get_mail(),
379 '''FROM: roundup-admin@your.tracker.email.domain.example
380 TO: chef@bork.bork.bork, john@test, mary@test
381 Content-Type: text/plain; charset=utf-8
382 Subject: [issue1] Testing...
383 To: chef@bork.bork.bork, john@test, mary@test
384 From: richard <issue_tracker@your.tracker.email.domain.example>
385 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
386 MIME-Version: 1.0
387 Message-Id: <followup_dummy_id>
388 In-Reply-To: <dummy_test_message_id>
389 X-Roundup-Name: Roundup issue tracker
390 X-Roundup-Loop: hello
391 Content-Transfer-Encoding: quoted-printable
394 richard <richard@test> added the comment:
396 This is a followup
398 ----------
399 assignedto: -> mary
400 nosy: +john, mary
401 status: unread -> chatting
402 _______________________________________________________________________
403 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
404 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
405 _______________________________________________________________________
406 ''')
408 def testFollowupNosyAuthor(self):
409 self.doNewIssue()
410 self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
411 message = StringIO('''Content-Type: text/plain;
412 charset="iso-8859-1"
413 From: john@test
414 To: issue_tracker@your.tracker.email.domain.example
415 Message-Id: <followup_dummy_id>
416 In-Reply-To: <dummy_test_message_id>
417 Subject: [issue1] Testing...
419 This is a followup
420 ''')
421 handler = self.instance.MailGW(self.instance, self.db)
422 handler.trapExceptions = 0
423 handler.main(message)
425 self.compareMessages(self._get_mail(),
426 '''FROM: roundup-admin@your.tracker.email.domain.example
427 TO: chef@bork.bork.bork, richard@test
428 Content-Type: text/plain; charset=utf-8
429 Subject: [issue1] Testing...
430 To: chef@bork.bork.bork, richard@test
431 From: John Doe <issue_tracker@your.tracker.email.domain.example>
432 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
433 MIME-Version: 1.0
434 Message-Id: <followup_dummy_id>
435 In-Reply-To: <dummy_test_message_id>
436 X-Roundup-Name: Roundup issue tracker
437 X-Roundup-Loop: hello
438 Content-Transfer-Encoding: quoted-printable
441 John Doe <john@test> added the comment:
443 This is a followup
445 ----------
446 nosy: +john
447 status: unread -> chatting
448 _______________________________________________________________________
449 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
450 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
451 _______________________________________________________________________
453 ''')
455 def testFollowupNosyRecipients(self):
456 self.doNewIssue()
457 self.db.config.ADD_RECIPIENTS_TO_NOSY = 'yes'
458 message = StringIO('''Content-Type: text/plain;
459 charset="iso-8859-1"
460 From: richard@test
461 To: issue_tracker@your.tracker.email.domain.example
462 Cc: john@test
463 Message-Id: <followup_dummy_id>
464 In-Reply-To: <dummy_test_message_id>
465 Subject: [issue1] Testing...
467 This is a followup
468 ''')
469 handler = self.instance.MailGW(self.instance, self.db)
470 handler.trapExceptions = 0
471 handler.main(message)
473 self.compareMessages(self._get_mail(),
474 '''FROM: roundup-admin@your.tracker.email.domain.example
475 TO: chef@bork.bork.bork
476 Content-Type: text/plain; charset=utf-8
477 Subject: [issue1] Testing...
478 To: chef@bork.bork.bork
479 From: richard <issue_tracker@your.tracker.email.domain.example>
480 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
481 MIME-Version: 1.0
482 Message-Id: <followup_dummy_id>
483 In-Reply-To: <dummy_test_message_id>
484 X-Roundup-Name: Roundup issue tracker
485 X-Roundup-Loop: hello
486 Content-Transfer-Encoding: quoted-printable
489 richard <richard@test> added the comment:
491 This is a followup
493 ----------
494 nosy: +john
495 status: unread -> chatting
496 _______________________________________________________________________
497 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
498 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
499 _______________________________________________________________________
501 ''')
503 def testFollowupNosyAuthorAndCopy(self):
504 self.doNewIssue()
505 self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
506 self.db.config.MESSAGES_TO_AUTHOR = 'yes'
507 message = StringIO('''Content-Type: text/plain;
508 charset="iso-8859-1"
509 From: john@test
510 To: issue_tracker@your.tracker.email.domain.example
511 Message-Id: <followup_dummy_id>
512 In-Reply-To: <dummy_test_message_id>
513 Subject: [issue1] Testing...
515 This is a followup
516 ''')
517 handler = self.instance.MailGW(self.instance, self.db)
518 handler.trapExceptions = 0
519 handler.main(message)
521 self.compareMessages(self._get_mail(),
522 '''FROM: roundup-admin@your.tracker.email.domain.example
523 TO: chef@bork.bork.bork, john@test, richard@test
524 Content-Type: text/plain; charset=utf-8
525 Subject: [issue1] Testing...
526 To: chef@bork.bork.bork, john@test, richard@test
527 From: John Doe <issue_tracker@your.tracker.email.domain.example>
528 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
529 MIME-Version: 1.0
530 Message-Id: <followup_dummy_id>
531 In-Reply-To: <dummy_test_message_id>
532 X-Roundup-Name: Roundup issue tracker
533 X-Roundup-Loop: hello
534 Content-Transfer-Encoding: quoted-printable
537 John Doe <john@test> added the comment:
539 This is a followup
541 ----------
542 nosy: +john
543 status: unread -> chatting
544 _______________________________________________________________________
545 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
546 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
547 _______________________________________________________________________
549 ''')
551 def testFollowupNoNosyAuthor(self):
552 self.doNewIssue()
553 self.instance.config.ADD_AUTHOR_TO_NOSY = 'no'
554 message = StringIO('''Content-Type: text/plain;
555 charset="iso-8859-1"
556 From: john@test
557 To: issue_tracker@your.tracker.email.domain.example
558 Message-Id: <followup_dummy_id>
559 In-Reply-To: <dummy_test_message_id>
560 Subject: [issue1] Testing...
562 This is a followup
563 ''')
564 handler = self.instance.MailGW(self.instance, self.db)
565 handler.trapExceptions = 0
566 handler.main(message)
568 self.compareMessages(self._get_mail(),
569 '''FROM: roundup-admin@your.tracker.email.domain.example
570 TO: chef@bork.bork.bork, richard@test
571 Content-Type: text/plain; charset=utf-8
572 Subject: [issue1] Testing...
573 To: chef@bork.bork.bork, richard@test
574 From: John Doe <issue_tracker@your.tracker.email.domain.example>
575 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
576 MIME-Version: 1.0
577 Message-Id: <followup_dummy_id>
578 In-Reply-To: <dummy_test_message_id>
579 X-Roundup-Name: Roundup issue tracker
580 X-Roundup-Loop: hello
581 Content-Transfer-Encoding: quoted-printable
584 John Doe <john@test> added the comment:
586 This is a followup
588 ----------
589 status: unread -> chatting
590 _______________________________________________________________________
591 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
592 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
593 _______________________________________________________________________
595 ''')
597 def testFollowupNoNosyRecipients(self):
598 self.doNewIssue()
599 self.instance.config.ADD_RECIPIENTS_TO_NOSY = 'no'
600 message = StringIO('''Content-Type: text/plain;
601 charset="iso-8859-1"
602 From: richard@test
603 To: issue_tracker@your.tracker.email.domain.example
604 Cc: john@test
605 Message-Id: <followup_dummy_id>
606 In-Reply-To: <dummy_test_message_id>
607 Subject: [issue1] Testing...
609 This is a followup
610 ''')
611 handler = self.instance.MailGW(self.instance, self.db)
612 handler.trapExceptions = 0
613 handler.main(message)
615 self.compareMessages(self._get_mail(),
616 '''FROM: roundup-admin@your.tracker.email.domain.example
617 TO: chef@bork.bork.bork
618 Content-Type: text/plain; charset=utf-8
619 Subject: [issue1] Testing...
620 To: chef@bork.bork.bork
621 From: richard <issue_tracker@your.tracker.email.domain.example>
622 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
623 MIME-Version: 1.0
624 Message-Id: <followup_dummy_id>
625 In-Reply-To: <dummy_test_message_id>
626 X-Roundup-Name: Roundup issue tracker
627 X-Roundup-Loop: hello
628 Content-Transfer-Encoding: quoted-printable
631 richard <richard@test> added the comment:
633 This is a followup
635 ----------
636 status: unread -> chatting
637 _______________________________________________________________________
638 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
639 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
640 _______________________________________________________________________
642 ''')
644 def testFollowupEmptyMessage(self):
645 self.doNewIssue()
647 message = StringIO('''Content-Type: text/plain;
648 charset="iso-8859-1"
649 From: richard <richard@test>
650 To: issue_tracker@your.tracker.email.domain.example
651 Message-Id: <followup_dummy_id>
652 In-Reply-To: <dummy_test_message_id>
653 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
655 ''')
656 handler = self.instance.MailGW(self.instance, self.db)
657 handler.trapExceptions = 0
658 handler.main(message)
659 l = self.db.issue.get('1', 'nosy')
660 l.sort()
661 self.assertEqual(l, ['3', '4', '5', '6'])
663 # should be no file created (ie. no message)
664 assert not os.path.exists(SENDMAILDEBUG)
666 def testNosyRemove(self):
667 self.doNewIssue()
669 message = StringIO('''Content-Type: text/plain;
670 charset="iso-8859-1"
671 From: richard <richard@test>
672 To: issue_tracker@your.tracker.email.domain.example
673 Message-Id: <followup_dummy_id>
674 In-Reply-To: <dummy_test_message_id>
675 Subject: [issue1] Testing... [nosy=-richard]
677 ''')
678 handler = self.instance.MailGW(self.instance, self.db)
679 handler.trapExceptions = 0
680 handler.main(message)
681 l = self.db.issue.get('1', 'nosy')
682 l.sort()
683 self.assertEqual(l, ['3'])
685 # NO NOSY MESSAGE SHOULD BE SENT!
686 assert not os.path.exists(SENDMAILDEBUG)
688 def testNewUserAuthor(self):
689 # first without the permission
690 # heh... just ignore the API for a second ;)
691 self.db.security.role['anonymous'].permissions=[]
692 anonid = self.db.user.lookup('anonymous')
693 self.db.user.set(anonid, roles='Anonymous')
695 self.db.security.hasPermission('Email Registration', anonid)
696 l = self.db.user.list()
697 l.sort()
698 s = '''Content-Type: text/plain;
699 charset="iso-8859-1"
700 From: fubar <fubar@bork.bork.bork>
701 To: issue_tracker@your.tracker.email.domain.example
702 Message-Id: <dummy_test_message_id>
703 Subject: [issue] Testing...
705 This is a test submission of a new issue.
706 '''
707 message = StringIO(s)
708 handler = self.instance.MailGW(self.instance, self.db)
709 handler.trapExceptions = 0
710 self.assertRaises(Unauthorized, handler.main, message)
711 m = self.db.user.list()
712 m.sort()
713 self.assertEqual(l, m)
715 # now with the permission
716 p = self.db.security.getPermission('Email Registration')
717 self.db.security.role['anonymous'].permissions=[p]
718 handler = self.instance.MailGW(self.instance, self.db)
719 handler.trapExceptions = 0
720 message = StringIO(s)
721 handler.main(message)
722 m = self.db.user.list()
723 m.sort()
724 self.assertNotEqual(l, m)
726 def testEnc01(self):
727 self.doNewIssue()
728 message = StringIO('''Content-Type: text/plain;
729 charset="iso-8859-1"
730 From: mary <mary@test>
731 To: issue_tracker@your.tracker.email.domain.example
732 Message-Id: <followup_dummy_id>
733 In-Reply-To: <dummy_test_message_id>
734 Subject: [issue1] Testing...
735 Content-Type: text/plain;
736 charset="iso-8859-1"
737 Content-Transfer-Encoding: quoted-printable
739 A message with encoding (encoded oe =F6)
741 ''')
742 handler = self.instance.MailGW(self.instance, self.db)
743 handler.trapExceptions = 0
744 handler.main(message)
745 self.compareMessages(self._get_mail(),
746 '''FROM: roundup-admin@your.tracker.email.domain.example
747 TO: chef@bork.bork.bork, richard@test
748 Content-Type: text/plain; charset=utf-8
749 Subject: [issue1] Testing...
750 To: chef@bork.bork.bork, richard@test
751 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
752 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
753 MIME-Version: 1.0
754 Message-Id: <followup_dummy_id>
755 In-Reply-To: <dummy_test_message_id>
756 X-Roundup-Name: Roundup issue tracker
757 X-Roundup-Loop: hello
758 Content-Transfer-Encoding: quoted-printable
761 Contrary, Mary <mary@test> added the comment:
763 A message with encoding (encoded oe =C3=B6)
765 ----------
766 status: unread -> chatting
767 _______________________________________________________________________
768 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
769 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
770 _______________________________________________________________________
771 ''')
774 def testMultipartEnc01(self):
775 self.doNewIssue()
776 message = StringIO('''Content-Type: text/plain;
777 charset="iso-8859-1"
778 From: mary <mary@test>
779 To: issue_tracker@your.tracker.email.domain.example
780 Message-Id: <followup_dummy_id>
781 In-Reply-To: <dummy_test_message_id>
782 Subject: [issue1] Testing...
783 Content-Type: multipart/mixed;
784 boundary="----_=_NextPart_000_01"
786 This message is in MIME format. Since your mail reader does not understand
787 this format, some or all of this message may not be legible.
789 ------_=_NextPart_000_01
790 Content-Type: text/plain;
791 charset="iso-8859-1"
792 Content-Transfer-Encoding: quoted-printable
794 A message with first part encoded (encoded oe =F6)
796 ''')
797 handler = self.instance.MailGW(self.instance, self.db)
798 handler.trapExceptions = 0
799 handler.main(message)
800 self.compareMessages(self._get_mail(),
801 '''FROM: roundup-admin@your.tracker.email.domain.example
802 TO: chef@bork.bork.bork, richard@test
803 Content-Type: text/plain; charset=utf-8
804 Subject: [issue1] Testing...
805 To: chef@bork.bork.bork, richard@test
806 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
807 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
808 MIME-Version: 1.0
809 Message-Id: <followup_dummy_id>
810 In-Reply-To: <dummy_test_message_id>
811 X-Roundup-Name: Roundup issue tracker
812 X-Roundup-Loop: hello
813 Content-Transfer-Encoding: quoted-printable
816 Contrary, Mary <mary@test> added the comment:
818 A message with first part encoded (encoded oe =C3=B6)
820 ----------
821 status: unread -> chatting
822 _______________________________________________________________________
823 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
824 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
825 _______________________________________________________________________
826 ''')
828 def testContentDisposition(self):
829 self.doNewIssue()
830 message = StringIO('''Content-Type: text/plain;
831 charset="iso-8859-1"
832 From: mary <mary@test>
833 To: issue_tracker@your.tracker.email.domain.example
834 Message-Id: <followup_dummy_id>
835 In-Reply-To: <dummy_test_message_id>
836 Subject: [issue1] Testing...
837 Content-Type: multipart/mixed; boundary="bCsyhTFzCvuiizWE"
838 Content-Disposition: inline
841 --bCsyhTFzCvuiizWE
842 Content-Type: text/plain; charset=us-ascii
843 Content-Disposition: inline
845 test attachment binary
847 --bCsyhTFzCvuiizWE
848 Content-Type: application/octet-stream
849 Content-Disposition: attachment; filename="main.dvi"
851 xxxxxx
853 --bCsyhTFzCvuiizWE--
854 ''')
855 handler = self.instance.MailGW(self.instance, self.db)
856 handler.trapExceptions = 0
857 handler.main(message)
858 messages = self.db.issue.get('1', 'messages')
859 messages.sort()
860 file = self.db.msg.get(messages[-1], 'files')[0]
861 self.assertEqual(self.db.file.get(file, 'name'), 'main.dvi')
863 def testFollowupStupidQuoting(self):
864 self.doNewIssue()
866 message = StringIO('''Content-Type: text/plain;
867 charset="iso-8859-1"
868 From: richard <richard@test>
869 To: issue_tracker@your.tracker.email.domain.example
870 Message-Id: <followup_dummy_id>
871 In-Reply-To: <dummy_test_message_id>
872 Subject: Re: "[issue1] Testing... "
874 This is a followup
875 ''')
876 handler = self.instance.MailGW(self.instance, self.db)
877 handler.trapExceptions = 0
878 handler.main(message)
880 self.compareMessages(self._get_mail(),
881 '''FROM: roundup-admin@your.tracker.email.domain.example
882 TO: chef@bork.bork.bork
883 Content-Type: text/plain; charset=utf-8
884 Subject: [issue1] Testing...
885 To: chef@bork.bork.bork
886 From: richard <issue_tracker@your.tracker.email.domain.example>
887 Reply-To: Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
888 MIME-Version: 1.0
889 Message-Id: <followup_dummy_id>
890 In-Reply-To: <dummy_test_message_id>
891 X-Roundup-Name: Roundup issue tracker
892 X-Roundup-Loop: hello
893 Content-Transfer-Encoding: quoted-printable
896 richard <richard@test> added the comment:
898 This is a followup
900 ----------
901 status: unread -> chatting
902 _______________________________________________________________________
903 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
904 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
905 _______________________________________________________________________
906 ''')
908 def testEmailQuoting(self):
909 self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'no'
910 self.innerTestQuoting('''This is a followup
911 ''')
913 def testEmailQuotingRemove(self):
914 self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'yes'
915 self.innerTestQuoting('''Blah blah wrote:
916 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
917 > skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
918 >
920 This is a followup
921 ''')
923 def innerTestQuoting(self, expect):
924 nodeid = self.doNewIssue()
926 messages = self.db.issue.get(nodeid, 'messages')
928 message = StringIO('''Content-Type: text/plain;
929 charset="iso-8859-1"
930 From: richard <richard@test>
931 To: issue_tracker@your.tracker.email.domain.example
932 Message-Id: <followup_dummy_id>
933 In-Reply-To: <dummy_test_message_id>
934 Subject: Re: [issue1] Testing...
936 Blah blah wrote:
937 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
938 > skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
939 >
941 This is a followup
942 ''')
943 handler = self.instance.MailGW(self.instance, self.db)
944 handler.trapExceptions = 0
945 handler.main(message)
947 # figure the new message id
948 newmessages = self.db.issue.get(nodeid, 'messages')
949 for msg in messages:
950 newmessages.remove(msg)
951 messageid = newmessages[0]
953 self.compareMessages(self.db.msg.get(messageid, 'content'), expect)
955 def testUserLookup(self):
956 i = self.db.user.create(username='user1', address='user1@foo.com')
957 self.assertEqual(uidFromAddress(self.db, ('', 'user1@foo.com'), 0), i)
958 self.assertEqual(uidFromAddress(self.db, ('', 'USER1@foo.com'), 0), i)
959 i = self.db.user.create(username='user2', address='USER2@foo.com')
960 self.assertEqual(uidFromAddress(self.db, ('', 'USER2@foo.com'), 0), i)
961 self.assertEqual(uidFromAddress(self.db, ('', 'user2@foo.com'), 0), i)
963 def testUserAlternateLookup(self):
964 i = self.db.user.create(username='user1', address='user1@foo.com',
965 alternate_addresses='user1@bar.com')
966 self.assertEqual(uidFromAddress(self.db, ('', 'user1@bar.com'), 0), i)
967 self.assertEqual(uidFromAddress(self.db, ('', 'USER1@bar.com'), 0), i)
969 def testUserCreate(self):
970 i = uidFromAddress(self.db, ('', 'user@foo.com'), 1)
971 self.assertNotEqual(uidFromAddress(self.db, ('', 'user@bar.com'), 1), i)
973 def testRFC2822(self):
974 ascii_header = "[issue243] This is a \"test\" - with 'quotation' marks"
975 unicode_header = '[issue244] \xd0\xb0\xd0\xbd\xd0\xb4\xd1\x80\xd0\xb5\xd0\xb9'
976 unicode_encoded = '=?utf-8?q?[issue244]_=D0=B0=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?='
977 self.assertEqual(rfc2822.encode_header(ascii_header), ascii_header)
978 self.assertEqual(rfc2822.encode_header(unicode_header), unicode_encoded)
980 def testRegistrationConfirmation(self):
981 otk = "Aj4euk4LZSAdwePohj90SME5SpopLETL"
982 self.db.otks.set(otk, username='johannes', __time='')
983 message = StringIO('''Content-Type: text/plain;
984 charset="iso-8859-1"
985 From: Chef <chef@bork.bork.bork>
986 To: issue_tracker@your.tracker.email.domain.example
987 Cc: richard@test
988 Message-Id: <dummy_test_message_id>
989 Subject: Re: Complete your registration to Roundup issue tracker\r
990 -- key %s
992 This is a test confirmation of registration.
993 ''' % otk)
994 handler = self.instance.MailGW(self.instance, self.db)
995 handler.trapExceptions = 0
996 handler.main(message)
998 self.db.user.lookup('johannes')
1000 def testFollowupOnNonIssue(self):
1001 self.db.keyword.create(name='Foo')
1002 message = StringIO('''Content-Type: text/plain;
1003 charset="iso-8859-1"
1004 From: richard <richard@test>
1005 To: issue_tracker@your.tracker.email.domain.example
1006 Message-Id: <followup_dummy_id>
1007 In-Reply-To: <dummy_test_message_id>
1008 Subject: [keyword1] Testing... [name=Bar]
1010 ''')
1011 handler = self.instance.MailGW(self.instance, self.db)
1012 handler.trapExceptions = 0
1013 handler.main(message)
1015 self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1017 def test_suite():
1018 suite = unittest.TestSuite()
1019 suite.addTest(unittest.makeSuite(MailgwTestCase))
1020 return suite
1022 if __name__ == '__main__':
1023 runner = unittest.TextTestRunner()
1024 unittest.main(testRunner=runner)
1026 # vim: set filetype=python ts=4 sw=4 et si