Code

600bc81fdc2c350a5f4fb74c3ac1baa426b261d3
[roundup.git] / test / test_mailgw.py
1 # -*- encoding: utf-8 -*-
2 #
3 # Copyright (c) 2001 Richard Jones, richard@bofh.asn.au.
4 # This module is free software, and you may redistribute it and/or modify
5 # under the same terms as Python, so long as this copyright message and
6 # disclaimer are retained in their original form.
7 #
8 # This module is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
11 #
12 # $Id: test_mailgw.py,v 1.96 2008-08-19 01:40:59 richard Exp $
14 # TODO: test bcc
16 import unittest, tempfile, os, shutil, errno, imp, sys, difflib, rfc822, time
18 from cStringIO import StringIO
20 if not os.environ.has_key('SENDMAILDEBUG'):
21     os.environ['SENDMAILDEBUG'] = 'mail-test.log'
22 SENDMAILDEBUG = os.environ['SENDMAILDEBUG']
24 from roundup import mailgw, i18n, roundupdb
25 from roundup.mailgw import MailGW, Unauthorized, uidFromAddress, \
26     parseContent, IgnoreLoop, IgnoreBulk, MailUsageError, MailUsageHelp
27 from roundup import init, instance, password, rfc2822, __version__
28 from roundup.anypy.sets_ import set
30 #import db_test_base
31 import memorydb
33 class Message(rfc822.Message):
34     """String-based Message class with equivalence test."""
35     def __init__(self, s):
36         rfc822.Message.__init__(self, StringIO(s.strip()))
38     def __eq__(self, other):
39         return (self.dict == other.dict and
40                 self.fp.read() == other.fp.read())
42 class Tracker(object):
43     def open(self, journaltag):
44         return self.db
46 class DiffHelper:
47     def compareMessages(self, new, old):
48         """Compare messages for semantic equivalence."""
49         new, old = Message(new), Message(old)
51         # all Roundup-generated messages have "Precedence: bulk"
52         old['Precedence'] = 'bulk'
54         # don't try to compare the date
55         del new['date'], old['date']
57         if not new == old:
58             res = []
60             replace = {}
61             for key in new.keys():
62                 if key.startswith('from '):
63                     # skip the unix from line
64                     continue
65                 if key.lower() == 'x-roundup-version':
66                     # version changes constantly, so handle it specially
67                     if new[key] != __version__:
68                         res.append('  %s: %r != %r' % (key, __version__,
69                             new[key]))
70                 elif key.lower() == 'content-type' and 'boundary=' in new[key]:
71                     # handle mime messages
72                     newmime = new[key].split('=',1)[-1].strip('"')
73                     oldmime = old.get(key, '').split('=',1)[-1].strip('"')
74                     replace ['--' + newmime] = '--' + oldmime
75                     replace ['--' + newmime + '--'] = '--' + oldmime + '--'
76                 elif new.get(key, '') != old.get(key, ''):
77                     res.append('  %s: %r != %r' % (key, old.get(key, ''),
78                         new.get(key, '')))
80             body_diff = self.compareStrings(new.fp.read(), old.fp.read(),
81                 replace=replace)
82             if body_diff:
83                 res.append('')
84                 res.extend(body_diff)
86             if res:
87                 res.insert(0, 'Generated message not correct (diff follows, expected vs. actual):')
88                 raise AssertionError, '\n'.join(res)
90     def compareStrings(self, s2, s1, replace={}):
91         '''Note the reversal of s2 and s1 - difflib.SequenceMatcher wants
92            the first to be the "original" but in the calls in this file,
93            the second arg is the original. Ho hum.
94            Do replacements over the replace dict -- used for mime boundary
95         '''
96         l1 = s1.strip().split('\n')
97         l2 = [replace.get(i,i) for i in s2.strip().split('\n')]
98         if l1 == l2:
99             return
100         s = difflib.SequenceMatcher(None, l1, l2)
101         res = []
102         for value, s1s, s1e, s2s, s2e in s.get_opcodes():
103             if value == 'equal':
104                 for i in range(s1s, s1e):
105                     res.append('  %s'%l1[i])
106             elif value == 'delete':
107                 for i in range(s1s, s1e):
108                     res.append('- %s'%l1[i])
109             elif value == 'insert':
110                 for i in range(s2s, s2e):
111                     res.append('+ %s'%l2[i])
112             elif value == 'replace':
113                 for i, j in zip(range(s1s, s1e), range(s2s, s2e)):
114                     res.append('- %s'%l1[i])
115                     res.append('+ %s'%l2[j])
117         return res
119 class MailgwTestCase(unittest.TestCase, DiffHelper):
120     count = 0
121     schema = 'classic'
122     def setUp(self):
123         self.old_translate_ = mailgw._
124         roundupdb._ = mailgw._ = i18n.get_translation(language='C').gettext
125         MailgwTestCase.count = MailgwTestCase.count + 1
127         # and open the database / "instance"
128         self.db = memorydb.create('admin')
129         self.instance = Tracker()
130         self.instance.db = self.db
131         self.instance.config = self.db.config
132         self.instance.MailGW = MailGW
134         self.chef_id = self.db.user.create(username='Chef',
135             address='chef@bork.bork.bork', realname='Bork, Chef', roles='User')
136         self.richard_id = self.db.user.create(username='richard',
137             address='richard@test.test', roles='User')
138         self.mary_id = self.db.user.create(username='mary',
139             address='mary@test.test', roles='User', realname='Contrary, Mary')
140         self.john_id = self.db.user.create(username='john',
141             address='john@test.test', roles='User', realname='John Doe',
142             alternate_addresses='jondoe@test.test\njohn.doe@test.test')
143         self.rgg_id = self.db.user.create(username='rgg',
144             address='rgg@test.test', roles='User')
146     def tearDown(self):
147         roundupdb._ = mailgw._ = self.old_translate_
148         if os.path.exists(SENDMAILDEBUG):
149             os.remove(SENDMAILDEBUG)
150         self.db.close()
152     def _create_mailgw(self, message):
153         class MailGW(self.instance.MailGW):
154             def handle_message(self, message):
155                 return self._handle_message(message)
156         handler = MailGW(self.instance)
157         handler.db = self.db
158         return handler
160     def _handle_mail(self, message):
161         handler = self._create_mailgw(message)
162         handler.trapExceptions = 0
163         return handler.main(StringIO(message))
165     def _get_mail(self):
166         f = open(SENDMAILDEBUG)
167         try:
168             return f.read()
169         finally:
170             f.close()
172     def testEmptyMessage(self):
173         nodeid = self._handle_mail('''Content-Type: text/plain;
174   charset="iso-8859-1"
175 From: Chef <chef@bork.bork.bork>
176 To: issue_tracker@your.tracker.email.domain.example
177 Cc: richard@test.test
178 Reply-To: chef@bork.bork.bork
179 Message-Id: <dummy_test_message_id>
180 Subject: [issue] Testing...
182 ''')
183         assert not os.path.exists(SENDMAILDEBUG)
184         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
186     def testMessageWithFromInIt(self):
187         nodeid = self._handle_mail('''Content-Type: text/plain;
188   charset="iso-8859-1"
189 From: Chef <chef@bork.bork.bork>
190 To: issue_tracker@your.tracker.email.domain.example
191 Cc: richard@test.test
192 Reply-To: chef@bork.bork.bork
193 Message-Id: <dummy_test_message_id>
194 Subject: [issue] Testing...
196 From here to there!
197 ''')
198         assert not os.path.exists(SENDMAILDEBUG)
199         msgid = self.db.issue.get(nodeid, 'messages')[0]
200         self.assertEqual(self.db.msg.get(msgid, 'content'), 'From here to there!')
202     def doNewIssue(self):
203         nodeid = self._handle_mail('''Content-Type: text/plain;
204   charset="iso-8859-1"
205 From: Chef <chef@bork.bork.bork>
206 To: issue_tracker@your.tracker.email.domain.example
207 Cc: richard@test.test
208 Message-Id: <dummy_test_message_id>
209 Subject: [issue] Testing...
211 This is a test submission of a new issue.
212 ''')
213         assert not os.path.exists(SENDMAILDEBUG)
214         l = self.db.issue.get(nodeid, 'nosy')
215         l.sort()
216         self.assertEqual(l, [self.chef_id, self.richard_id])
217         return nodeid
219     def testNewIssue(self):
220         self.doNewIssue()
222     def testNewIssueNosy(self):
223         self.instance.config.ADD_AUTHOR_TO_NOSY = 'yes'
224         nodeid = self._handle_mail('''Content-Type: text/plain;
225   charset="iso-8859-1"
226 From: Chef <chef@bork.bork.bork>
227 To: issue_tracker@your.tracker.email.domain.example
228 Cc: richard@test.test
229 Message-Id: <dummy_test_message_id>
230 Subject: [issue] Testing...
232 This is a test submission of a new issue.
233 ''')
234         assert not os.path.exists(SENDMAILDEBUG)
235         l = self.db.issue.get(nodeid, 'nosy')
236         l.sort()
237         self.assertEqual(l, [self.chef_id, self.richard_id])
239     def testAlternateAddress(self):
240         self._handle_mail('''Content-Type: text/plain;
241   charset="iso-8859-1"
242 From: John Doe <john.doe@test.test>
243 To: issue_tracker@your.tracker.email.domain.example
244 Message-Id: <dummy_test_message_id>
245 Subject: [issue] Testing...
247 This is a test submission of a new issue.
248 ''')
249         userlist = self.db.user.list()
250         assert not os.path.exists(SENDMAILDEBUG)
251         self.assertEqual(userlist, self.db.user.list(),
252             "user created when it shouldn't have been")
254     def testNewIssueNoClass(self):
255         self._handle_mail('''Content-Type: text/plain;
256   charset="iso-8859-1"
257 From: Chef <chef@bork.bork.bork>
258 To: issue_tracker@your.tracker.email.domain.example
259 Cc: richard@test.test
260 Message-Id: <dummy_test_message_id>
261 Subject: Testing...
263 This is a test submission of a new issue.
264 ''')
265         assert not os.path.exists(SENDMAILDEBUG)
267     def testNewIssueAuthMsg(self):
268         # TODO: fix the damn config - this is apalling
269         self.db.config.MESSAGES_TO_AUTHOR = 'yes'
270         self._handle_mail('''Content-Type: text/plain;
271   charset="iso-8859-1"
272 From: Chef <chef@bork.bork.bork>
273 To: issue_tracker@your.tracker.email.domain.example
274 Message-Id: <dummy_test_message_id>
275 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
277 This is a test submission of a new issue.
278 ''')
279         self.compareMessages(self._get_mail(),
280 '''FROM: roundup-admin@your.tracker.email.domain.example
281 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
282 Content-Type: text/plain; charset="utf-8"
283 Subject: [issue1] Testing...
284 To: chef@bork.bork.bork, mary@test.test, richard@test.test
285 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
286 Reply-To: Roundup issue tracker
287  <issue_tracker@your.tracker.email.domain.example>
288 MIME-Version: 1.0
289 Message-Id: <dummy_test_message_id>
290 X-Roundup-Name: Roundup issue tracker
291 X-Roundup-Loop: hello
292 X-Roundup-Issue-Status: unread
293 Content-Transfer-Encoding: quoted-printable
296 New submission from Bork, Chef <chef@bork.bork.bork>:
298 This is a test submission of a new issue.
300 ----------
301 assignedto: richard
302 messages: 1
303 nosy: Chef, mary, richard
304 status: unread
305 title: Testing...
307 _______________________________________________________________________
308 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
309 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
310 _______________________________________________________________________
311 ''')
313     def testNewIssueNoAuthorInfo(self):
314         self.db.config.MAIL_ADD_AUTHORINFO = 'no'
315         self._handle_mail('''Content-Type: text/plain;
316   charset="iso-8859-1"
317 From: Chef <chef@bork.bork.bork>
318 To: issue_tracker@your.tracker.email.domain.example
319 Message-Id: <dummy_test_message_id>
320 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
322 This is a test submission of a new issue.
323 ''')
324         self.compareMessages(self._get_mail(),
325 '''FROM: roundup-admin@your.tracker.email.domain.example
326 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
327 Content-Type: text/plain; charset="utf-8"
328 Subject: [issue1] Testing...
329 To: mary@test.test, richard@test.test
330 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
331 Reply-To: Roundup issue tracker
332  <issue_tracker@your.tracker.email.domain.example>
333 MIME-Version: 1.0
334 Message-Id: <dummy_test_message_id>
335 X-Roundup-Name: Roundup issue tracker
336 X-Roundup-Loop: hello
337 X-Roundup-Issue-Status: unread
338 Content-Transfer-Encoding: quoted-printable
340 This is a test submission of a new issue.
342 ----------
343 assignedto: richard
344 messages: 1
345 nosy: Chef, mary, richard
346 status: unread
347 title: Testing...
349 _______________________________________________________________________
350 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
351 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
352 _______________________________________________________________________
353 ''')
355     def testNewIssueNoAuthorEmail(self):
356         self.db.config.MAIL_ADD_AUTHOREMAIL = 'no'
357         self._handle_mail('''Content-Type: text/plain;
358   charset="iso-8859-1"
359 From: Chef <chef@bork.bork.bork>
360 To: issue_tracker@your.tracker.email.domain.example
361 Message-Id: <dummy_test_message_id>
362 Subject: [issue] Testing... [nosy=mary; assignedto=richard]
364 This is a test submission of a new issue.
365 ''')
366         self.compareMessages(self._get_mail(),
367 '''FROM: roundup-admin@your.tracker.email.domain.example
368 TO: chef@bork.bork.bork, mary@test.test, richard@test.test
369 Content-Type: text/plain; charset="utf-8"
370 Subject: [issue1] Testing...
371 To: mary@test.test, richard@test.test
372 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
373 Reply-To: Roundup issue tracker
374  <issue_tracker@your.tracker.email.domain.example>
375 MIME-Version: 1.0
376 Message-Id: <dummy_test_message_id>
377 X-Roundup-Name: Roundup issue tracker
378 X-Roundup-Loop: hello
379 X-Roundup-Issue-Status: unread
380 Content-Transfer-Encoding: quoted-printable
382 New submission from Bork, Chef:
384 This is a test submission of a new issue.
386 ----------
387 assignedto: richard
388 messages: 1
389 nosy: Chef, mary, richard
390 status: unread
391 title: Testing...
393 _______________________________________________________________________
394 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
395 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
396 _______________________________________________________________________
397 ''')
399     multipart_msg = '''From: mary <mary@test.test>
400 To: issue_tracker@your.tracker.email.domain.example
401 Message-Id: <followup_dummy_id>
402 In-Reply-To: <dummy_test_message_id>
403 Subject: [issue1] Testing...
404 Content-Type: multipart/mixed; boundary="bxyzzy"
405 Content-Disposition: inline
408 --bxyzzy
409 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWE"
410 Content-Disposition: inline
412 --bCsyhTFzCvuiizWE
413 Content-Type: text/plain; charset=us-ascii
414 Content-Disposition: inline
416 test attachment first text/plain
418 --bCsyhTFzCvuiizWE
419 Content-Type: application/octet-stream
420 Content-Disposition: attachment; filename="first.dvi"
421 Content-Transfer-Encoding: base64
423 SnVzdCBhIHRlc3QgAQo=
425 --bCsyhTFzCvuiizWE
426 Content-Type: text/plain; charset=us-ascii
427 Content-Disposition: inline
429 test attachment second text/plain
431 --bCsyhTFzCvuiizWE
432 Content-Type: text/html
433 Content-Disposition: inline
435 <html>
436 to be ignored.
437 </html>
439 --bCsyhTFzCvuiizWE--
441 --bxyzzy
442 Content-Type: multipart/alternative; boundary="bCsyhTFzCvuiizWF"
443 Content-Disposition: inline
445 --bCsyhTFzCvuiizWF
446 Content-Type: text/plain; charset=us-ascii
447 Content-Disposition: inline
449 test attachment third text/plain
451 --bCsyhTFzCvuiizWF
452 Content-Type: application/octet-stream
453 Content-Disposition: attachment; filename="second.dvi"
454 Content-Transfer-Encoding: base64
456 SnVzdCBhIHRlc3QK
458 --bCsyhTFzCvuiizWF--
460 --bxyzzy--
461 '''
463     def testMultipartKeepAlternatives(self):
464         self.doNewIssue()
465         self._handle_mail(self.multipart_msg)
466         messages = self.db.issue.get('1', 'messages')
467         messages.sort()
468         msg = self.db.msg.getnode (messages[-1])
469         assert(len(msg.files) == 5)
470         names = {0 : 'first.dvi', 4 : 'second.dvi'}
471         content = {3 : 'test attachment third text/plain\n',
472                    4 : 'Just a test\n'}
473         for n, id in enumerate (msg.files):
474             f = self.db.file.getnode (id)
475             self.assertEqual(f.name, names.get (n, 'unnamed'))
476             if n in content :
477                 self.assertEqual(f.content, content [n])
478         self.assertEqual(msg.content, 'test attachment second text/plain')
480     def testMultipartDropAlternatives(self):
481         self.doNewIssue()
482         self.db.config.MAILGW_IGNORE_ALTERNATIVES = True
483         self._handle_mail(self.multipart_msg)
484         messages = self.db.issue.get('1', 'messages')
485         messages.sort()
486         msg = self.db.msg.getnode (messages[-1])
487         assert(len(msg.files) == 2)
488         names = {1 : 'second.dvi'}
489         content = {0 : 'test attachment third text/plain\n',
490                    1 : 'Just a test\n'}
491         for n, id in enumerate (msg.files):
492             f = self.db.file.getnode (id)
493             self.assertEqual(f.name, names.get (n, 'unnamed'))
494             if n in content :
495                 self.assertEqual(f.content, content [n])
496         self.assertEqual(msg.content, 'test attachment second text/plain')
498     def testSimpleFollowup(self):
499         self.doNewIssue()
500         self._handle_mail('''Content-Type: text/plain;
501   charset="iso-8859-1"
502 From: mary <mary@test.test>
503 To: issue_tracker@your.tracker.email.domain.example
504 Message-Id: <followup_dummy_id>
505 In-Reply-To: <dummy_test_message_id>
506 Subject: [issue1] Testing...
508 This is a second followup
509 ''')
510         self.compareMessages(self._get_mail(),
511 '''FROM: roundup-admin@your.tracker.email.domain.example
512 TO: chef@bork.bork.bork, richard@test.test
513 Content-Type: text/plain; charset="utf-8"
514 Subject: [issue1] Testing...
515 To: chef@bork.bork.bork, richard@test.test
516 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
517 Reply-To: Roundup issue tracker
518  <issue_tracker@your.tracker.email.domain.example>
519 MIME-Version: 1.0
520 Message-Id: <followup_dummy_id>
521 In-Reply-To: <dummy_test_message_id>
522 X-Roundup-Name: Roundup issue tracker
523 X-Roundup-Loop: hello
524 X-Roundup-Issue-Status: chatting
525 Content-Transfer-Encoding: quoted-printable
528 Contrary, Mary <mary@test.test> added the comment:
530 This is a second followup
532 ----------
533 status: unread -> chatting
535 _______________________________________________________________________
536 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
537 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
538 _______________________________________________________________________
539 ''')
541     def testFollowup(self):
542         self.doNewIssue()
544         self._handle_mail('''Content-Type: text/plain;
545   charset="iso-8859-1"
546 From: richard <richard@test.test>
547 To: issue_tracker@your.tracker.email.domain.example
548 Message-Id: <followup_dummy_id>
549 In-Reply-To: <dummy_test_message_id>
550 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
552 This is a followup
553 ''')
554         l = self.db.issue.get('1', 'nosy')
555         l.sort()
556         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
557             self.john_id])
559         self.compareMessages(self._get_mail(),
560 '''FROM: roundup-admin@your.tracker.email.domain.example
561 TO: chef@bork.bork.bork, john@test.test, mary@test.test
562 Content-Type: text/plain; charset="utf-8"
563 Subject: [issue1] Testing...
564 To: chef@bork.bork.bork, john@test.test, mary@test.test
565 From: richard <issue_tracker@your.tracker.email.domain.example>
566 Reply-To: Roundup issue tracker
567  <issue_tracker@your.tracker.email.domain.example>
568 MIME-Version: 1.0
569 Message-Id: <followup_dummy_id>
570 In-Reply-To: <dummy_test_message_id>
571 X-Roundup-Name: Roundup issue tracker
572 X-Roundup-Loop: hello
573 X-Roundup-Issue-Status: chatting
574 Content-Transfer-Encoding: quoted-printable
577 richard <richard@test.test> added the comment:
579 This is a followup
581 ----------
582 assignedto:  -> mary
583 nosy: +john, mary
584 status: unread -> chatting
586 _______________________________________________________________________
587 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
588 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
589 _______________________________________________________________________
590 ''')
592     def testFollowupNoSubjectChange(self):
593         self.db.config.MAILGW_SUBJECT_UPDATES_TITLE = 'no'
594         self.doNewIssue()
596         self._handle_mail('''Content-Type: text/plain;
597   charset="iso-8859-1"
598 From: richard <richard@test.test>
599 To: issue_tracker@your.tracker.email.domain.example
600 Message-Id: <followup_dummy_id>
601 In-Reply-To: <dummy_test_message_id>
602 Subject: [issue1] Wrzlbrmft... [assignedto=mary; nosy=+john]
604 This is a followup
605 ''')
606         l = self.db.issue.get('1', 'nosy')
607         l.sort()
608         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
609             self.john_id])
611         self.compareMessages(self._get_mail(),
612 '''FROM: roundup-admin@your.tracker.email.domain.example
613 TO: chef@bork.bork.bork, john@test.test, mary@test.test
614 Content-Type: text/plain; charset="utf-8"
615 Subject: [issue1] Testing...
616 To: chef@bork.bork.bork, john@test.test, mary@test.test
617 From: richard <issue_tracker@your.tracker.email.domain.example>
618 Reply-To: Roundup issue tracker
619  <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 X-Roundup-Issue-Status: chatting
626 Content-Transfer-Encoding: quoted-printable
629 richard <richard@test.test> added the comment:
631 This is a followup
633 ----------
634 assignedto:  -> mary
635 nosy: +john, mary
636 status: unread -> chatting
638 _______________________________________________________________________
639 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
640 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
641 _______________________________________________________________________
642 ''')
643         self.assertEqual(self.db.issue.get('1','title'), 'Testing...')
645     def testFollowupExplicitSubjectChange(self):
646         self.doNewIssue()
648         self._handle_mail('''Content-Type: text/plain;
649   charset="iso-8859-1"
650 From: richard <richard@test.test>
651 To: issue_tracker@your.tracker.email.domain.example
652 Message-Id: <followup_dummy_id>
653 In-Reply-To: <dummy_test_message_id>
654 Subject: [issue1] Wrzlbrmft... [assignedto=mary; nosy=+john; title=new title]
656 This is a followup
657 ''')
658         l = self.db.issue.get('1', 'nosy')
659         l.sort()
660         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
661             self.john_id])
663         self.compareMessages(self._get_mail(),
664 '''FROM: roundup-admin@your.tracker.email.domain.example
665 TO: chef@bork.bork.bork, john@test.test, mary@test.test
666 Content-Type: text/plain; charset="utf-8"
667 Subject: [issue1] new title
668 To: chef@bork.bork.bork, john@test.test, mary@test.test
669 From: richard <issue_tracker@your.tracker.email.domain.example>
670 Reply-To: Roundup issue tracker
671  <issue_tracker@your.tracker.email.domain.example>
672 MIME-Version: 1.0
673 Message-Id: <followup_dummy_id>
674 In-Reply-To: <dummy_test_message_id>
675 X-Roundup-Name: Roundup issue tracker
676 X-Roundup-Loop: hello
677 X-Roundup-Issue-Status: chatting
678 Content-Transfer-Encoding: quoted-printable
681 richard <richard@test.test> added the comment:
683 This is a followup
685 ----------
686 assignedto:  -> mary
687 nosy: +john, mary
688 status: unread -> chatting
689 title: Testing... -> new title
691 _______________________________________________________________________
692 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
693 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
694 _______________________________________________________________________
695 ''')
697     def testNosyGeneration(self):
698         self.db.issue.create(title='test')
700         # create a nosy message
701         msg = self.db.msg.create(content='This is a test',
702             author=self.richard_id, messageid='<dummy_test_message_id>')
703         self.db.journaltag = 'richard'
704         l = self.db.issue.create(title='test', messages=[msg],
705             nosy=[self.chef_id, self.mary_id, self.john_id])
707         self.compareMessages(self._get_mail(),
708 '''FROM: roundup-admin@your.tracker.email.domain.example
709 TO: chef@bork.bork.bork, john@test.test, mary@test.test
710 Content-Type: text/plain; charset="utf-8"
711 Subject: [issue2] test
712 To: chef@bork.bork.bork, john@test.test, mary@test.test
713 From: richard <issue_tracker@your.tracker.email.domain.example>
714 Reply-To: Roundup issue tracker
715  <issue_tracker@your.tracker.email.domain.example>
716 MIME-Version: 1.0
717 Message-Id: <dummy_test_message_id>
718 X-Roundup-Name: Roundup issue tracker
719 X-Roundup-Loop: hello
720 X-Roundup-Issue-Status: unread
721 Content-Transfer-Encoding: quoted-printable
724 New submission from richard <richard@test.test>:
726 This is a test
728 ----------
729 messages: 1
730 nosy: Chef, john, mary, richard
731 status: unread
732 title: test
734 _______________________________________________________________________
735 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
736 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue2>
737 _______________________________________________________________________
738 ''')
740     def testPropertyChangeOnly(self):
741         self.doNewIssue()
742         oldvalues = self.db.getnode('issue', '1').copy()
743         oldvalues['assignedto'] = None
744         # reconstruct old behaviour: This would reuse the
745         # database-handle from the doNewIssue above which has committed
746         # as user "Chef". So we close and reopen the db as that user.
747         #self.db.close() actually don't close 'cos this empties memorydb
748         self.db = self.instance.open('Chef')
749         self.db.issue.set('1', assignedto=self.chef_id)
750         self.db.commit()
751         self.db.issue.nosymessage('1', None, oldvalues)
753         new_mail = ""
754         for line in self._get_mail().split("\n"):
755             if "Message-Id: " in line:
756                 continue
757             if "Date: " in line:
758                 continue
759             new_mail += line+"\n"
761         self.compareMessages(new_mail, """
762 FROM: roundup-admin@your.tracker.email.domain.example
763 TO: chef@bork.bork.bork, richard@test.test
764 Content-Type: text/plain; charset="utf-8"
765 Subject: [issue1] Testing...
766 To: chef@bork.bork.bork, richard@test.test
767 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
768 X-Roundup-Name: Roundup issue tracker
769 X-Roundup-Loop: hello
770 X-Roundup-Issue-Status: unread
771 X-Roundup-Version: 1.3.3
772 In-Reply-To: <dummy_test_message_id>
773 MIME-Version: 1.0
774 Reply-To: Roundup issue tracker
775  <issue_tracker@your.tracker.email.domain.example>
776 Content-Transfer-Encoding: quoted-printable
779 Change by Bork, Chef <chef@bork.bork.bork>:
782 ----------
783 assignedto:  -> Chef
785 _______________________________________________________________________
786 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
787 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
788 _______________________________________________________________________
789 """)
792     #
793     # FOLLOWUP TITLE MATCH
794     #
795     def testFollowupTitleMatch(self):
796         self.doNewIssue()
797         self._handle_mail('''Content-Type: text/plain;
798   charset="iso-8859-1"
799 From: richard <richard@test.test>
800 To: issue_tracker@your.tracker.email.domain.example
801 Message-Id: <followup_dummy_id>
802 Subject: Re: Testing... [assignedto=mary; nosy=+john]
804 This is a followup
805 ''')
806         self.compareMessages(self._get_mail(),
807 '''FROM: roundup-admin@your.tracker.email.domain.example
808 TO: chef@bork.bork.bork, john@test.test, mary@test.test
809 Content-Type: text/plain; charset="utf-8"
810 Subject: [issue1] Testing...
811 To: chef@bork.bork.bork, john@test.test, mary@test.test
812 From: richard <issue_tracker@your.tracker.email.domain.example>
813 Reply-To: Roundup issue tracker
814  <issue_tracker@your.tracker.email.domain.example>
815 MIME-Version: 1.0
816 Message-Id: <followup_dummy_id>
817 In-Reply-To: <dummy_test_message_id>
818 X-Roundup-Name: Roundup issue tracker
819 X-Roundup-Loop: hello
820 X-Roundup-Issue-Status: chatting
821 Content-Transfer-Encoding: quoted-printable
824 richard <richard@test.test> added the comment:
826 This is a followup
828 ----------
829 assignedto:  -> mary
830 nosy: +john, mary
831 status: unread -> chatting
833 _______________________________________________________________________
834 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
835 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
836 _______________________________________________________________________
837 ''')
839     def testFollowupTitleMatchMultiRe(self):
840         nodeid1 = self.doNewIssue()
841         nodeid2 = self._handle_mail('''Content-Type: text/plain;
842   charset="iso-8859-1"
843 From: richard <richard@test.test>
844 To: issue_tracker@your.tracker.email.domain.example
845 Message-Id: <followup_dummy_id>
846 Subject: Re: Testing... [assignedto=mary; nosy=+john]
848 This is a followup
849 ''')
851         nodeid3 = self._handle_mail('''Content-Type: text/plain;
852   charset="iso-8859-1"
853 From: richard <richard@test.test>
854 To: issue_tracker@your.tracker.email.domain.example
855 Message-Id: <followup2_dummy_id>
856 Subject: Ang: Re: Testing...
858 This is a followup
859 ''')
860         self.assertEqual(nodeid1, nodeid2)
861         self.assertEqual(nodeid1, nodeid3)
863     def testFollowupTitleMatchNever(self):
864         nodeid = self.doNewIssue()
865         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'never'
866         self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
867   charset="iso-8859-1"
868 From: richard <richard@test.test>
869 To: issue_tracker@your.tracker.email.domain.example
870 Message-Id: <followup_dummy_id>
871 Subject: Re: Testing...
873 This is a followup
874 '''), nodeid)
876     def testFollowupTitleMatchNeverInterval(self):
877         nodeid = self.doNewIssue()
878         # force failure of the interval
879         time.sleep(2)
880         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation 00:00:01'
881         self.assertNotEqual(self._handle_mail('''Content-Type: text/plain;
882   charset="iso-8859-1"
883 From: richard <richard@test.test>
884 To: issue_tracker@your.tracker.email.domain.example
885 Message-Id: <followup_dummy_id>
886 Subject: Re: Testing...
888 This is a followup
889 '''), nodeid)
892     def testFollowupTitleMatchInterval(self):
893         nodeid = self.doNewIssue()
894         self.db.config.MAILGW_SUBJECT_CONTENT_MATCH = 'creation +1d'
895         self.assertEqual(self._handle_mail('''Content-Type: text/plain;
896   charset="iso-8859-1"
897 From: richard <richard@test.test>
898 To: issue_tracker@your.tracker.email.domain.example
899 Message-Id: <followup_dummy_id>
900 Subject: Re: Testing...
902 This is a followup
903 '''), nodeid)
906     def testFollowupNosyAuthor(self):
907         self.doNewIssue()
908         self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
909         self._handle_mail('''Content-Type: text/plain;
910   charset="iso-8859-1"
911 From: john@test.test
912 To: issue_tracker@your.tracker.email.domain.example
913 Message-Id: <followup_dummy_id>
914 In-Reply-To: <dummy_test_message_id>
915 Subject: [issue1] Testing...
917 This is a followup
918 ''')
920         self.compareMessages(self._get_mail(),
921 '''FROM: roundup-admin@your.tracker.email.domain.example
922 TO: chef@bork.bork.bork, richard@test.test
923 Content-Type: text/plain; charset="utf-8"
924 Subject: [issue1] Testing...
925 To: chef@bork.bork.bork, richard@test.test
926 From: John Doe <issue_tracker@your.tracker.email.domain.example>
927 Reply-To: Roundup issue tracker
928  <issue_tracker@your.tracker.email.domain.example>
929 MIME-Version: 1.0
930 Message-Id: <followup_dummy_id>
931 In-Reply-To: <dummy_test_message_id>
932 X-Roundup-Name: Roundup issue tracker
933 X-Roundup-Loop: hello
934 X-Roundup-Issue-Status: chatting
935 Content-Transfer-Encoding: quoted-printable
938 John Doe <john@test.test> added the comment:
940 This is a followup
942 ----------
943 nosy: +john
944 status: unread -> chatting
946 _______________________________________________________________________
947 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
948 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
949 _______________________________________________________________________
951 ''')
953     def testFollowupNosyRecipients(self):
954         self.doNewIssue()
955         self.db.config.ADD_RECIPIENTS_TO_NOSY = 'yes'
956         self._handle_mail('''Content-Type: text/plain;
957   charset="iso-8859-1"
958 From: richard@test.test
959 To: issue_tracker@your.tracker.email.domain.example
960 Cc: john@test.test
961 Message-Id: <followup_dummy_id>
962 In-Reply-To: <dummy_test_message_id>
963 Subject: [issue1] Testing...
965 This is a followup
966 ''')
967         self.compareMessages(self._get_mail(),
968 '''FROM: roundup-admin@your.tracker.email.domain.example
969 TO: chef@bork.bork.bork
970 Content-Type: text/plain; charset="utf-8"
971 Subject: [issue1] Testing...
972 To: chef@bork.bork.bork
973 From: richard <issue_tracker@your.tracker.email.domain.example>
974 Reply-To: Roundup issue tracker
975  <issue_tracker@your.tracker.email.domain.example>
976 MIME-Version: 1.0
977 Message-Id: <followup_dummy_id>
978 In-Reply-To: <dummy_test_message_id>
979 X-Roundup-Name: Roundup issue tracker
980 X-Roundup-Loop: hello
981 X-Roundup-Issue-Status: chatting
982 Content-Transfer-Encoding: quoted-printable
985 richard <richard@test.test> added the comment:
987 This is a followup
989 ----------
990 nosy: +john
991 status: unread -> chatting
993 _______________________________________________________________________
994 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
995 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
996 _______________________________________________________________________
998 ''')
1000     def testFollowupNosyAuthorAndCopy(self):
1001         self.doNewIssue()
1002         self.db.config.ADD_AUTHOR_TO_NOSY = 'yes'
1003         self.db.config.MESSAGES_TO_AUTHOR = 'yes'
1004         self._handle_mail('''Content-Type: text/plain;
1005   charset="iso-8859-1"
1006 From: john@test.test
1007 To: issue_tracker@your.tracker.email.domain.example
1008 Message-Id: <followup_dummy_id>
1009 In-Reply-To: <dummy_test_message_id>
1010 Subject: [issue1] Testing...
1012 This is a followup
1013 ''')
1014         self.compareMessages(self._get_mail(),
1015 '''FROM: roundup-admin@your.tracker.email.domain.example
1016 TO: chef@bork.bork.bork, john@test.test, richard@test.test
1017 Content-Type: text/plain; charset="utf-8"
1018 Subject: [issue1] Testing...
1019 To: chef@bork.bork.bork, john@test.test, richard@test.test
1020 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1021 Reply-To: Roundup issue tracker
1022  <issue_tracker@your.tracker.email.domain.example>
1023 MIME-Version: 1.0
1024 Message-Id: <followup_dummy_id>
1025 In-Reply-To: <dummy_test_message_id>
1026 X-Roundup-Name: Roundup issue tracker
1027 X-Roundup-Loop: hello
1028 X-Roundup-Issue-Status: chatting
1029 Content-Transfer-Encoding: quoted-printable
1032 John Doe <john@test.test> added the comment:
1034 This is a followup
1036 ----------
1037 nosy: +john
1038 status: unread -> chatting
1040 _______________________________________________________________________
1041 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1042 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1043 _______________________________________________________________________
1045 ''')
1047     def testFollowupNoNosyAuthor(self):
1048         self.doNewIssue()
1049         self.instance.config.ADD_AUTHOR_TO_NOSY = 'no'
1050         self._handle_mail('''Content-Type: text/plain;
1051   charset="iso-8859-1"
1052 From: john@test.test
1053 To: issue_tracker@your.tracker.email.domain.example
1054 Message-Id: <followup_dummy_id>
1055 In-Reply-To: <dummy_test_message_id>
1056 Subject: [issue1] Testing...
1058 This is a followup
1059 ''')
1060         self.compareMessages(self._get_mail(),
1061 '''FROM: roundup-admin@your.tracker.email.domain.example
1062 TO: chef@bork.bork.bork, richard@test.test
1063 Content-Type: text/plain; charset="utf-8"
1064 Subject: [issue1] Testing...
1065 To: chef@bork.bork.bork, richard@test.test
1066 From: John Doe <issue_tracker@your.tracker.email.domain.example>
1067 Reply-To: Roundup issue tracker
1068  <issue_tracker@your.tracker.email.domain.example>
1069 MIME-Version: 1.0
1070 Message-Id: <followup_dummy_id>
1071 In-Reply-To: <dummy_test_message_id>
1072 X-Roundup-Name: Roundup issue tracker
1073 X-Roundup-Loop: hello
1074 X-Roundup-Issue-Status: chatting
1075 Content-Transfer-Encoding: quoted-printable
1078 John Doe <john@test.test> added the comment:
1080 This is a followup
1082 ----------
1083 status: unread -> chatting
1085 _______________________________________________________________________
1086 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1087 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1088 _______________________________________________________________________
1090 ''')
1092     def testFollowupNoNosyRecipients(self):
1093         self.doNewIssue()
1094         self.instance.config.ADD_RECIPIENTS_TO_NOSY = 'no'
1095         self._handle_mail('''Content-Type: text/plain;
1096   charset="iso-8859-1"
1097 From: richard@test.test
1098 To: issue_tracker@your.tracker.email.domain.example
1099 Cc: john@test.test
1100 Message-Id: <followup_dummy_id>
1101 In-Reply-To: <dummy_test_message_id>
1102 Subject: [issue1] Testing...
1104 This is a followup
1105 ''')
1106         self.compareMessages(self._get_mail(),
1107 '''FROM: roundup-admin@your.tracker.email.domain.example
1108 TO: chef@bork.bork.bork
1109 Content-Type: text/plain; charset="utf-8"
1110 Subject: [issue1] Testing...
1111 To: chef@bork.bork.bork
1112 From: richard <issue_tracker@your.tracker.email.domain.example>
1113 Reply-To: Roundup issue tracker
1114  <issue_tracker@your.tracker.email.domain.example>
1115 MIME-Version: 1.0
1116 Message-Id: <followup_dummy_id>
1117 In-Reply-To: <dummy_test_message_id>
1118 X-Roundup-Name: Roundup issue tracker
1119 X-Roundup-Loop: hello
1120 X-Roundup-Issue-Status: chatting
1121 Content-Transfer-Encoding: quoted-printable
1124 richard <richard@test.test> added the comment:
1126 This is a followup
1128 ----------
1129 status: unread -> chatting
1131 _______________________________________________________________________
1132 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1133 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1134 _______________________________________________________________________
1136 ''')
1138     def testFollowupEmptyMessage(self):
1139         self.doNewIssue()
1141         self._handle_mail('''Content-Type: text/plain;
1142   charset="iso-8859-1"
1143 From: richard <richard@test.test>
1144 To: issue_tracker@your.tracker.email.domain.example
1145 Message-Id: <followup_dummy_id>
1146 In-Reply-To: <dummy_test_message_id>
1147 Subject: [issue1] Testing... [assignedto=mary; nosy=+john]
1149 ''')
1150         l = self.db.issue.get('1', 'nosy')
1151         l.sort()
1152         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1153             self.john_id])
1155         # should be no file created (ie. no message)
1156         assert not os.path.exists(SENDMAILDEBUG)
1158     def testFollowupEmptyMessageNoSubject(self):
1159         self.doNewIssue()
1161         self._handle_mail('''Content-Type: text/plain;
1162   charset="iso-8859-1"
1163 From: richard <richard@test.test>
1164 To: issue_tracker@your.tracker.email.domain.example
1165 Message-Id: <followup_dummy_id>
1166 In-Reply-To: <dummy_test_message_id>
1167 Subject: [issue1] [assignedto=mary; nosy=+john]
1169 ''')
1170         l = self.db.issue.get('1', 'nosy')
1171         l.sort()
1172         self.assertEqual(l, [self.chef_id, self.richard_id, self.mary_id,
1173             self.john_id])
1175         # should be no file created (ie. no message)
1176         assert not os.path.exists(SENDMAILDEBUG)
1178     def testNosyRemove(self):
1179         self.doNewIssue()
1181         self._handle_mail('''Content-Type: text/plain;
1182   charset="iso-8859-1"
1183 From: richard <richard@test.test>
1184 To: issue_tracker@your.tracker.email.domain.example
1185 Message-Id: <followup_dummy_id>
1186 In-Reply-To: <dummy_test_message_id>
1187 Subject: [issue1] Testing... [nosy=-richard]
1189 ''')
1190         l = self.db.issue.get('1', 'nosy')
1191         l.sort()
1192         self.assertEqual(l, [self.chef_id])
1194         # NO NOSY MESSAGE SHOULD BE SENT!
1195         assert not os.path.exists(SENDMAILDEBUG)
1197     def testNewUserAuthor(self):
1198         self.db.commit()
1199         l = self.db.user.list()
1200         l.sort()
1201         message = '''Content-Type: text/plain;
1202   charset="iso-8859-1"
1203 From: fubar <fubar@bork.bork.bork>
1204 To: issue_tracker@your.tracker.email.domain.example
1205 Message-Id: <dummy_test_message_id>
1206 Subject: [issue] Testing...
1208 This is a test submission of a new issue.
1209 '''
1210         self.db.security.role['anonymous'].permissions=[]
1211         anonid = self.db.user.lookup('anonymous')
1212         self.db.user.set(anonid, roles='Anonymous')
1213         try:
1214             self._handle_mail(message)
1215         except Unauthorized, value:
1216             body_diff = self.compareMessages(str(value), """
1217 You are not a registered user.
1219 Unknown address: fubar@bork.bork.bork
1220 """)
1221             assert not body_diff, body_diff
1222         else:
1223             raise AssertionError, "Unathorized not raised when handling mail"
1225         # Add Web Access role to anonymous, and try again to make sure
1226         # we get a "please register at:" message this time.
1227         p = [
1228             self.db.security.getPermission('Register', 'user'),
1229             self.db.security.getPermission('Web Access', None),
1230         ]
1231         self.db.security.role['anonymous'].permissions=p
1232         try:
1233             self._handle_mail(message)
1234         except Unauthorized, value:
1235             body_diff = self.compareMessages(str(value), """
1236 You are not a registered user. Please register at:
1238 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1240 ...before sending mail to the tracker.
1242 Unknown address: fubar@bork.bork.bork
1243 """)
1244             assert not body_diff, body_diff
1245         else:
1246             raise AssertionError, "Unathorized not raised when handling mail"
1248         # Make sure list of users is the same as before.
1249         m = self.db.user.list()
1250         m.sort()
1251         self.assertEqual(l, m)
1253         # now with the permission
1254         p = [
1255             self.db.security.getPermission('Register', 'user'),
1256             self.db.security.getPermission('Email Access', None),
1257         ]
1258         self.db.security.role['anonymous'].permissions=p
1259         self._handle_mail(message)
1260         m = self.db.user.list()
1261         m.sort()
1262         self.assertNotEqual(l, m)
1264     def testNewUserAuthorEncodedName(self):
1265         l = set(self.db.user.list())
1266         # From: name has Euro symbol in it
1267         message = '''Content-Type: text/plain;
1268   charset="iso-8859-1"
1269 From: =?utf8?b?SOKCrGxsbw==?= <fubar@bork.bork.bork>
1270 To: issue_tracker@your.tracker.email.domain.example
1271 Message-Id: <dummy_test_message_id>
1272 Subject: [issue] Testing...
1274 This is a test submission of a new issue.
1275 '''
1276         p = [
1277             self.db.security.getPermission('Register', 'user'),
1278             self.db.security.getPermission('Email Access', None),
1279             self.db.security.getPermission('Create', 'issue'),
1280             self.db.security.getPermission('Create', 'msg'),
1281         ]
1282         self.db.security.role['anonymous'].permissions = p
1283         self._handle_mail(message)
1284         m = set(self.db.user.list())
1285         new = list(m - l)[0]
1286         name = self.db.user.get(new, 'realname')
1287         self.assertEquals(name, 'H€llo')
1289     def testUnknownUser(self):
1290         l = set(self.db.user.list())
1291         message = '''Content-Type: text/plain;
1292   charset="iso-8859-1"
1293 From: Nonexisting User <nonexisting@bork.bork.bork>
1294 To: issue_tracker@your.tracker.email.domain.example
1295 Message-Id: <dummy_test_message_id>
1296 Subject: [issue] Testing nonexisting user...
1298 This is a test submission of a new issue.
1299 '''
1300         handler = self._create_mailgw(message)
1301         # we want a bounce message:
1302         handler.trapExceptions = 1
1303         ret = handler.main(StringIO(message))
1304         self.compareMessages(self._get_mail(),
1305 '''FROM: Roundup issue tracker <roundup-admin@your.tracker.email.domain.example>
1306 TO: nonexisting@bork.bork.bork
1307 From nobody Tue Jul 14 12:04:11 2009
1308 Content-Type: multipart/mixed; boundary="===============0639262320=="
1309 MIME-Version: 1.0
1310 Subject: Failed issue tracker submission
1311 To: nonexisting@bork.bork.bork
1312 From: Roundup issue tracker <roundup-admin@your.tracker.email.domain.example>
1313 Date: Tue, 14 Jul 2009 12:04:11 +0000
1314 Precedence: bulk
1315 X-Roundup-Name: Roundup issue tracker
1316 X-Roundup-Loop: hello
1317 X-Roundup-Version: 1.4.8
1318 MIME-Version: 1.0
1320 --===============0639262320==
1321 Content-Type: text/plain; charset="us-ascii"
1322 MIME-Version: 1.0
1323 Content-Transfer-Encoding: 7bit
1327 You are not a registered user. Please register at:
1329 http://tracker.example/cgi-bin/roundup.cgi/bugs/user?template=register
1331 ...before sending mail to the tracker.
1333 Unknown address: nonexisting@bork.bork.bork
1335 --===============0639262320==
1336 Content-Type: text/plain; charset="us-ascii"
1337 MIME-Version: 1.0
1338 Content-Transfer-Encoding: 7bit
1340 Content-Type: text/plain;
1341   charset="iso-8859-1"
1342 From: Nonexisting User <nonexisting@bork.bork.bork>
1343 To: issue_tracker@your.tracker.email.domain.example
1344 Message-Id: <dummy_test_message_id>
1345 Subject: [issue] Testing nonexisting user...
1347 This is a test submission of a new issue.
1349 --===============0639262320==--
1350 ''')
1352     def testEnc01(self):
1353         self.db.user.set(self.mary_id,
1354             realname='\xe4\xf6\xfc\xc4\xd6\xdc\xdf, Mary'.decode
1355             ('latin-1').encode('utf-8'))
1356         self.doNewIssue()
1357         self._handle_mail('''Content-Type: text/plain;
1358   charset="iso-8859-1"
1359 From: mary <mary@test.test>
1360 To: issue_tracker@your.tracker.email.domain.example
1361 Message-Id: <followup_dummy_id>
1362 In-Reply-To: <dummy_test_message_id>
1363 Subject: [issue1] Testing...
1364 Content-Type: text/plain;
1365         charset="iso-8859-1"
1366 Content-Transfer-Encoding: quoted-printable
1368 A message with encoding (encoded oe =F6)
1370 ''')
1371         self.compareMessages(self._get_mail(),
1372 '''FROM: roundup-admin@your.tracker.email.domain.example
1373 TO: chef@bork.bork.bork, richard@test.test
1374 Content-Type: text/plain; charset="utf-8"
1375 Subject: [issue1] Testing...
1376 To: chef@bork.bork.bork, richard@test.test
1377 From: =?utf-8?b?w6TDtsO8w4TDlsOcw58sIE1hcnk=?=
1378  <issue_tracker@your.tracker.email.domain.example>
1379 Reply-To: Roundup issue tracker
1380  <issue_tracker@your.tracker.email.domain.example>
1381 MIME-Version: 1.0
1382 Message-Id: <followup_dummy_id>
1383 In-Reply-To: <dummy_test_message_id>
1384 X-Roundup-Name: Roundup issue tracker
1385 X-Roundup-Loop: hello
1386 X-Roundup-Issue-Status: chatting
1387 Content-Transfer-Encoding: quoted-printable
1390 =C3=A4=C3=B6=C3=BC=C3=84=C3=96=C3=9C=C3=9F, Mary <mary@test.test> added the=
1391  comment:
1393 A message with encoding (encoded oe =C3=B6)
1395 ----------
1396 status: unread -> chatting
1398 _______________________________________________________________________
1399 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1400 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1401 _______________________________________________________________________
1402 ''')
1404     def testEncNonUTF8(self):
1405         self.doNewIssue()
1406         self.instance.config.EMAIL_CHARSET = 'iso-8859-1'
1407         self._handle_mail('''Content-Type: text/plain;
1408   charset="iso-8859-1"
1409 From: mary <mary@test.test>
1410 To: issue_tracker@your.tracker.email.domain.example
1411 Message-Id: <followup_dummy_id>
1412 In-Reply-To: <dummy_test_message_id>
1413 Subject: [issue1] Testing...
1414 Content-Type: text/plain;
1415         charset="iso-8859-1"
1416 Content-Transfer-Encoding: quoted-printable
1418 A message with encoding (encoded oe =F6)
1420 ''')
1421         self.compareMessages(self._get_mail(),
1422 '''FROM: roundup-admin@your.tracker.email.domain.example
1423 TO: chef@bork.bork.bork, richard@test.test
1424 Content-Type: text/plain; charset="iso-8859-1"
1425 Subject: [issue1] Testing...
1426 To: chef@bork.bork.bork, richard@test.test
1427 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1428 Reply-To: Roundup issue tracker
1429  <issue_tracker@your.tracker.email.domain.example>
1430 MIME-Version: 1.0
1431 Message-Id: <followup_dummy_id>
1432 In-Reply-To: <dummy_test_message_id>
1433 X-Roundup-Name: Roundup issue tracker
1434 X-Roundup-Loop: hello
1435 X-Roundup-Issue-Status: chatting
1436 Content-Transfer-Encoding: quoted-printable
1439 Contrary, Mary <mary@test.test> added the comment:
1441 A message with encoding (encoded oe =F6)
1443 ----------
1444 status: unread -> chatting
1446 _______________________________________________________________________
1447 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1448 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1449 _______________________________________________________________________
1450 ''')
1453     def testMultipartEnc01(self):
1454         self.doNewIssue()
1455         self._handle_mail('''Content-Type: text/plain;
1456   charset="iso-8859-1"
1457 From: mary <mary@test.test>
1458 To: issue_tracker@your.tracker.email.domain.example
1459 Message-Id: <followup_dummy_id>
1460 In-Reply-To: <dummy_test_message_id>
1461 Subject: [issue1] Testing...
1462 Content-Type: multipart/mixed;
1463         boundary="----_=_NextPart_000_01"
1465 This message is in MIME format. Since your mail reader does not understand
1466 this format, some or all of this message may not be legible.
1468 ------_=_NextPart_000_01
1469 Content-Type: text/plain;
1470         charset="iso-8859-1"
1471 Content-Transfer-Encoding: quoted-printable
1473 A message with first part encoded (encoded oe =F6)
1475 ''')
1476         self.compareMessages(self._get_mail(),
1477 '''FROM: roundup-admin@your.tracker.email.domain.example
1478 TO: chef@bork.bork.bork, richard@test.test
1479 Content-Type: text/plain; charset="utf-8"
1480 Subject: [issue1] Testing...
1481 To: chef@bork.bork.bork, richard@test.test
1482 From: "Contrary, Mary" <issue_tracker@your.tracker.email.domain.example>
1483 Reply-To: Roundup issue tracker
1484  <issue_tracker@your.tracker.email.domain.example>
1485 MIME-Version: 1.0
1486 Message-Id: <followup_dummy_id>
1487 In-Reply-To: <dummy_test_message_id>
1488 X-Roundup-Name: Roundup issue tracker
1489 X-Roundup-Loop: hello
1490 X-Roundup-Issue-Status: chatting
1491 Content-Transfer-Encoding: quoted-printable
1494 Contrary, Mary <mary@test.test> added the comment:
1496 A message with first part encoded (encoded oe =C3=B6)
1498 ----------
1499 status: unread -> chatting
1501 _______________________________________________________________________
1502 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1503 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1504 _______________________________________________________________________
1505 ''')
1507     def testContentDisposition(self):
1508         self.doNewIssue()
1509         self._handle_mail('''Content-Type: text/plain;
1510   charset="iso-8859-1"
1511 From: mary <mary@test.test>
1512 To: issue_tracker@your.tracker.email.domain.example
1513 Message-Id: <followup_dummy_id>
1514 In-Reply-To: <dummy_test_message_id>
1515 Subject: [issue1] Testing...
1516 Content-Type: multipart/mixed; boundary="bCsyhTFzCvuiizWE"
1517 Content-Disposition: inline
1520 --bCsyhTFzCvuiizWE
1521 Content-Type: text/plain; charset=us-ascii
1522 Content-Disposition: inline
1524 test attachment binary
1526 --bCsyhTFzCvuiizWE
1527 Content-Type: application/octet-stream
1528 Content-Disposition: attachment; filename="main.dvi"
1529 Content-Transfer-Encoding: base64
1531 SnVzdCBhIHRlc3QgAQo=
1533 --bCsyhTFzCvuiizWE--
1534 ''')
1535         messages = self.db.issue.get('1', 'messages')
1536         messages.sort()
1537         file = self.db.file.getnode (self.db.msg.get(messages[-1], 'files')[0])
1538         self.assertEqual(file.name, 'main.dvi')
1539         self.assertEqual(file.content, 'Just a test \001\n')
1541     def testFollowupStupidQuoting(self):
1542         self.doNewIssue()
1544         self._handle_mail('''Content-Type: text/plain;
1545   charset="iso-8859-1"
1546 From: richard <richard@test.test>
1547 To: issue_tracker@your.tracker.email.domain.example
1548 Message-Id: <followup_dummy_id>
1549 In-Reply-To: <dummy_test_message_id>
1550 Subject: Re: "[issue1] Testing... "
1552 This is a followup
1553 ''')
1554         self.compareMessages(self._get_mail(),
1555 '''FROM: roundup-admin@your.tracker.email.domain.example
1556 TO: chef@bork.bork.bork
1557 Content-Type: text/plain; charset="utf-8"
1558 Subject: [issue1] Testing...
1559 To: chef@bork.bork.bork
1560 From: richard <issue_tracker@your.tracker.email.domain.example>
1561 Reply-To: Roundup issue tracker
1562  <issue_tracker@your.tracker.email.domain.example>
1563 MIME-Version: 1.0
1564 Message-Id: <followup_dummy_id>
1565 In-Reply-To: <dummy_test_message_id>
1566 X-Roundup-Name: Roundup issue tracker
1567 X-Roundup-Loop: hello
1568 X-Roundup-Issue-Status: chatting
1569 Content-Transfer-Encoding: quoted-printable
1572 richard <richard@test.test> added the comment:
1574 This is a followup
1576 ----------
1577 status: unread -> chatting
1579 _______________________________________________________________________
1580 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
1581 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
1582 _______________________________________________________________________
1583 ''')
1585     def testEmailQuoting(self):
1586         self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'no'
1587         self.innerTestQuoting('''This is a followup
1588 ''')
1590     def testEmailQuotingRemove(self):
1591         self.instance.config.EMAIL_KEEP_QUOTED_TEXT = 'yes'
1592         self.innerTestQuoting('''Blah blah wrote:
1593 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
1594 >  skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
1597 This is a followup
1598 ''')
1600     def innerTestQuoting(self, expect):
1601         nodeid = self.doNewIssue()
1603         messages = self.db.issue.get(nodeid, 'messages')
1605         self._handle_mail('''Content-Type: text/plain;
1606   charset="iso-8859-1"
1607 From: richard <richard@test.test>
1608 To: issue_tracker@your.tracker.email.domain.example
1609 Message-Id: <followup_dummy_id>
1610 In-Reply-To: <dummy_test_message_id>
1611 Subject: Re: [issue1] Testing...
1613 Blah blah wrote:
1614 > Blah bklaskdfj sdf asdf jlaskdf skj sdkfjl asdf
1615 >  skdjlkjsdfalsdkfjasdlfkj dlfksdfalksd fj
1618 This is a followup
1619 ''')
1620         # figure the new message id
1621         newmessages = self.db.issue.get(nodeid, 'messages')
1622         for msg in messages:
1623             newmessages.remove(msg)
1624         messageid = newmessages[0]
1626         self.compareMessages(self.db.msg.get(messageid, 'content'), expect)
1628     def testUserLookup(self):
1629         i = self.db.user.create(username='user1', address='user1@foo.com')
1630         self.assertEqual(uidFromAddress(self.db, ('', 'user1@foo.com'), 0), i)
1631         self.assertEqual(uidFromAddress(self.db, ('', 'USER1@foo.com'), 0), i)
1632         i = self.db.user.create(username='user2', address='USER2@foo.com')
1633         self.assertEqual(uidFromAddress(self.db, ('', 'USER2@foo.com'), 0), i)
1634         self.assertEqual(uidFromAddress(self.db, ('', 'user2@foo.com'), 0), i)
1636     def testUserAlternateLookup(self):
1637         i = self.db.user.create(username='user1', address='user1@foo.com',
1638                                 alternate_addresses='user1@bar.com')
1639         self.assertEqual(uidFromAddress(self.db, ('', 'user1@bar.com'), 0), i)
1640         self.assertEqual(uidFromAddress(self.db, ('', 'USER1@bar.com'), 0), i)
1642     def testUserCreate(self):
1643         i = uidFromAddress(self.db, ('', 'user@foo.com'), 1)
1644         self.assertNotEqual(uidFromAddress(self.db, ('', 'user@bar.com'), 1), i)
1646     def testRFC2822(self):
1647         ascii_header = "[issue243] This is a \"test\" - with 'quotation' marks"
1648         unicode_header = '[issue244] \xd0\xb0\xd0\xbd\xd0\xb4\xd1\x80\xd0\xb5\xd0\xb9'
1649         unicode_encoded = '=?utf-8?q?[issue244]_=D0=B0=D0=BD=D0=B4=D1=80=D0=B5=D0=B9?='
1650         self.assertEqual(rfc2822.encode_header(ascii_header), ascii_header)
1651         self.assertEqual(rfc2822.encode_header(unicode_header), unicode_encoded)
1653     def testRegistrationConfirmation(self):
1654         otk = "Aj4euk4LZSAdwePohj90SME5SpopLETL"
1655         self.db.getOTKManager().set(otk, username='johannes')
1656         self._handle_mail('''Content-Type: text/plain;
1657   charset="iso-8859-1"
1658 From: Chef <chef@bork.bork.bork>
1659 To: issue_tracker@your.tracker.email.domain.example
1660 Cc: richard@test.test
1661 Message-Id: <dummy_test_message_id>
1662 Subject: Re: Complete your registration to Roundup issue tracker
1663  -- key %s
1665 This is a test confirmation of registration.
1666 ''' % otk)
1667         self.db.user.lookup('johannes')
1669     def testFollowupOnNonIssue(self):
1670         self.db.keyword.create(name='Foo')
1671         self._handle_mail('''Content-Type: text/plain;
1672   charset="iso-8859-1"
1673 From: richard <richard@test.test>
1674 To: issue_tracker@your.tracker.email.domain.example
1675 Message-Id: <followup_dummy_id>
1676 In-Reply-To: <dummy_test_message_id>
1677 Subject: [keyword1] Testing... [name=Bar]
1679 ''')
1680         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1682     def testResentFrom(self):
1683         nodeid = self._handle_mail('''Content-Type: text/plain;
1684   charset="iso-8859-1"
1685 From: Chef <chef@bork.bork.bork>
1686 Resent-From: mary <mary@test.test>
1687 To: issue_tracker@your.tracker.email.domain.example
1688 Cc: richard@test.test
1689 Message-Id: <dummy_test_message_id>
1690 Subject: [issue] Testing...
1692 This is a test submission of a new issue.
1693 ''')
1694         assert not os.path.exists(SENDMAILDEBUG)
1695         l = self.db.issue.get(nodeid, 'nosy')
1696         l.sort()
1697         self.assertEqual(l, [self.richard_id, self.mary_id])
1698         return nodeid
1700     def testDejaVu(self):
1701         self.assertRaises(IgnoreLoop, self._handle_mail,
1702             '''Content-Type: text/plain;
1703   charset="iso-8859-1"
1704 From: Chef <chef@bork.bork.bork>
1705 X-Roundup-Loop: hello
1706 To: issue_tracker@your.tracker.email.domain.example
1707 Cc: richard@test.test
1708 Message-Id: <dummy_test_message_id>
1709 Subject: Re: [issue] Testing...
1711 Hi, I've been mis-configured to loop messages back to myself.
1712 ''')
1714     def testItsBulkStupid(self):
1715         self.assertRaises(IgnoreBulk, self._handle_mail,
1716             '''Content-Type: text/plain;
1717   charset="iso-8859-1"
1718 From: Chef <chef@bork.bork.bork>
1719 Precedence: bulk
1720 To: issue_tracker@your.tracker.email.domain.example
1721 Cc: richard@test.test
1722 Message-Id: <dummy_test_message_id>
1723 Subject: Re: [issue] Testing...
1725 Hi, I'm on holidays, and this is a dumb auto-responder.
1726 ''')
1728     def testAutoReplyEmailsAreIgnored(self):
1729         self.assertRaises(IgnoreBulk, self._handle_mail,
1730             '''Content-Type: text/plain;
1731   charset="iso-8859-1"
1732 From: Chef <chef@bork.bork.bork>
1733 To: issue_tracker@your.tracker.email.domain.example
1734 Cc: richard@test.test
1735 Message-Id: <dummy_test_message_id>
1736 Subject: Re: [issue] Out of office AutoReply: Back next week
1738 Hi, I am back in the office next week
1739 ''')
1741     def testNoSubject(self):
1742         self.assertRaises(MailUsageError, self._handle_mail,
1743             '''Content-Type: text/plain;
1744   charset="iso-8859-1"
1745 From: Chef <chef@bork.bork.bork>
1746 To: issue_tracker@your.tracker.email.domain.example
1747 Cc: richard@test.test
1748 Reply-To: chef@bork.bork.bork
1749 Message-Id: <dummy_test_message_id>
1751 ''')
1753     #
1754     # TEST FOR INVALID DESIGNATOR HANDLING
1755     #
1756     def testInvalidDesignator(self):
1757         self.assertRaises(MailUsageError, self._handle_mail,
1758             '''Content-Type: text/plain;
1759   charset="iso-8859-1"
1760 From: Chef <chef@bork.bork.bork>
1761 To: issue_tracker@your.tracker.email.domain.example
1762 Subject: [frobulated] testing
1763 Cc: richard@test.test
1764 Reply-To: chef@bork.bork.bork
1765 Message-Id: <dummy_test_message_id>
1767 ''')
1768         self.assertRaises(MailUsageError, self._handle_mail,
1769             '''Content-Type: text/plain;
1770   charset="iso-8859-1"
1771 From: Chef <chef@bork.bork.bork>
1772 To: issue_tracker@your.tracker.email.domain.example
1773 Subject: [issue12345] testing
1774 Cc: richard@test.test
1775 Reply-To: chef@bork.bork.bork
1776 Message-Id: <dummy_test_message_id>
1778 ''')
1780     def testInvalidClassLoose(self):
1781         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1782         nodeid = self._handle_mail('''Content-Type: text/plain;
1783   charset="iso-8859-1"
1784 From: Chef <chef@bork.bork.bork>
1785 To: issue_tracker@your.tracker.email.domain.example
1786 Subject: [frobulated] testing
1787 Cc: richard@test.test
1788 Reply-To: chef@bork.bork.bork
1789 Message-Id: <dummy_test_message_id>
1791 ''')
1792         assert not os.path.exists(SENDMAILDEBUG)
1793         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1794             '[frobulated] testing')
1796     def testInvalidClassLooseReply(self):
1797         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1798         nodeid = self._handle_mail('''Content-Type: text/plain;
1799   charset="iso-8859-1"
1800 From: Chef <chef@bork.bork.bork>
1801 To: issue_tracker@your.tracker.email.domain.example
1802 Subject: Re: [frobulated] testing
1803 Cc: richard@test.test
1804 Reply-To: chef@bork.bork.bork
1805 Message-Id: <dummy_test_message_id>
1807 ''')
1808         assert not os.path.exists(SENDMAILDEBUG)
1809         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1810             '[frobulated] testing')
1812     def testInvalidClassLoose(self):
1813         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1814         nodeid = self._handle_mail('''Content-Type: text/plain;
1815   charset="iso-8859-1"
1816 From: Chef <chef@bork.bork.bork>
1817 To: issue_tracker@your.tracker.email.domain.example
1818 Subject: [issue1234] testing
1819 Cc: richard@test.test
1820 Reply-To: chef@bork.bork.bork
1821 Message-Id: <dummy_test_message_id>
1823 ''')
1824         assert not os.path.exists(SENDMAILDEBUG)
1825         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1826             '[issue1234] testing')
1828     def testClassLooseOK(self):
1829         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1830         self.db.keyword.create(name='Foo')
1831         nodeid = self._handle_mail('''Content-Type: text/plain;
1832   charset="iso-8859-1"
1833 From: Chef <chef@bork.bork.bork>
1834 To: issue_tracker@your.tracker.email.domain.example
1835 Subject: [keyword1] Testing... [name=Bar]
1836 Cc: richard@test.test
1837 Reply-To: chef@bork.bork.bork
1838 Message-Id: <dummy_test_message_id>
1840 ''')
1841         assert not os.path.exists(SENDMAILDEBUG)
1842         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1844     def testClassStrictInvalid(self):
1845         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
1846         self.instance.config.MAILGW_DEFAULT_CLASS = ''
1848         message = '''Content-Type: text/plain;
1849   charset="iso-8859-1"
1850 From: Chef <chef@bork.bork.bork>
1851 To: issue_tracker@your.tracker.email.domain.example
1852 Subject: Testing...
1853 Cc: richard@test.test
1854 Reply-To: chef@bork.bork.bork
1855 Message-Id: <dummy_test_message_id>
1857 '''
1858         self.assertRaises(MailUsageError, self._handle_mail, message)
1860     def testClassStrictValid(self):
1861         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'strict'
1862         self.instance.config.MAILGW_DEFAULT_CLASS = ''
1864         nodeid = self._handle_mail('''Content-Type: text/plain;
1865   charset="iso-8859-1"
1866 From: Chef <chef@bork.bork.bork>
1867 To: issue_tracker@your.tracker.email.domain.example
1868 Subject: [issue] Testing...
1869 Cc: richard@test.test
1870 Reply-To: chef@bork.bork.bork
1871 Message-Id: <dummy_test_message_id>
1873 ''')
1875         assert not os.path.exists(SENDMAILDEBUG)
1876         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'Testing...')
1878     #
1879     # TEST FOR INVALID COMMANDS HANDLING
1880     #
1881     def testInvalidCommands(self):
1882         self.assertRaises(MailUsageError, self._handle_mail,
1883             '''Content-Type: text/plain;
1884   charset="iso-8859-1"
1885 From: Chef <chef@bork.bork.bork>
1886 To: issue_tracker@your.tracker.email.domain.example
1887 Subject: testing [frobulated]
1888 Cc: richard@test.test
1889 Reply-To: chef@bork.bork.bork
1890 Message-Id: <dummy_test_message_id>
1892 ''')
1894     def testInvalidCommandPassthrough(self):
1895         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'none'
1896         nodeid = self._handle_mail('''Content-Type: text/plain;
1897   charset="iso-8859-1"
1898 From: Chef <chef@bork.bork.bork>
1899 To: issue_tracker@your.tracker.email.domain.example
1900 Subject: testing [frobulated]
1901 Cc: richard@test.test
1902 Reply-To: chef@bork.bork.bork
1903 Message-Id: <dummy_test_message_id>
1905 ''')
1906         assert not os.path.exists(SENDMAILDEBUG)
1907         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1908             'testing [frobulated]')
1910     def testInvalidCommandPassthroughLoose(self):
1911         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
1912         nodeid = self._handle_mail('''Content-Type: text/plain;
1913   charset="iso-8859-1"
1914 From: Chef <chef@bork.bork.bork>
1915 To: issue_tracker@your.tracker.email.domain.example
1916 Subject: testing [frobulated]
1917 Cc: richard@test.test
1918 Reply-To: chef@bork.bork.bork
1919 Message-Id: <dummy_test_message_id>
1921 ''')
1922         assert not os.path.exists(SENDMAILDEBUG)
1923         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1924             'testing [frobulated]')
1926     def testInvalidCommandPassthroughLooseOK(self):
1927         self.instance.config.MAILGW_SUBJECT_SUFFIX_PARSING = 'loose'
1928         nodeid = self._handle_mail('''Content-Type: text/plain;
1929   charset="iso-8859-1"
1930 From: Chef <chef@bork.bork.bork>
1931 To: issue_tracker@your.tracker.email.domain.example
1932 Subject: testing [assignedto=mary]
1933 Cc: richard@test.test
1934 Reply-To: chef@bork.bork.bork
1935 Message-Id: <dummy_test_message_id>
1937 ''')
1938         assert not os.path.exists(SENDMAILDEBUG)
1939         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
1940         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
1942     def testCommandDelimiters(self):
1943         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1944         nodeid = self._handle_mail('''Content-Type: text/plain;
1945   charset="iso-8859-1"
1946 From: Chef <chef@bork.bork.bork>
1947 To: issue_tracker@your.tracker.email.domain.example
1948 Subject: testing {assignedto=mary}
1949 Cc: richard@test.test
1950 Reply-To: chef@bork.bork.bork
1951 Message-Id: <dummy_test_message_id>
1953 ''')
1954         assert not os.path.exists(SENDMAILDEBUG)
1955         self.assertEqual(self.db.issue.get(nodeid, 'title'), 'testing')
1956         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), self.mary_id)
1958     def testPrefixDelimiters(self):
1959         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1960         self.db.keyword.create(name='Foo')
1961         self._handle_mail('''Content-Type: text/plain;
1962   charset="iso-8859-1"
1963 From: richard <richard@test.test>
1964 To: issue_tracker@your.tracker.email.domain.example
1965 Message-Id: <followup_dummy_id>
1966 In-Reply-To: <dummy_test_message_id>
1967 Subject: {keyword1} Testing... {name=Bar}
1969 ''')
1970         assert not os.path.exists(SENDMAILDEBUG)
1971         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
1973     def testCommandDelimitersIgnore(self):
1974         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '{}'
1975         nodeid = self._handle_mail('''Content-Type: text/plain;
1976   charset="iso-8859-1"
1977 From: Chef <chef@bork.bork.bork>
1978 To: issue_tracker@your.tracker.email.domain.example
1979 Subject: testing [assignedto=mary]
1980 Cc: richard@test.test
1981 Reply-To: chef@bork.bork.bork
1982 Message-Id: <dummy_test_message_id>
1984 ''')
1985         assert not os.path.exists(SENDMAILDEBUG)
1986         self.assertEqual(self.db.issue.get(nodeid, 'title'),
1987             'testing [assignedto=mary]')
1988         self.assertEqual(self.db.issue.get(nodeid, 'assignedto'), None)
1990     def testReplytoMatch(self):
1991         self.instance.config.MAILGW_SUBJECT_PREFIX_PARSING = 'loose'
1992         nodeid = self.doNewIssue()
1993         nodeid2 = self._handle_mail('''Content-Type: text/plain;
1994   charset="iso-8859-1"
1995 From: Chef <chef@bork.bork.bork>
1996 To: issue_tracker@your.tracker.email.domain.example
1997 Message-Id: <dummy_test_message_id2>
1998 In-Reply-To: <dummy_test_message_id>
1999 Subject: Testing...
2001 Followup message.
2002 ''')
2004         nodeid3 = self._handle_mail('''Content-Type: text/plain;
2005   charset="iso-8859-1"
2006 From: Chef <chef@bork.bork.bork>
2007 To: issue_tracker@your.tracker.email.domain.example
2008 Message-Id: <dummy_test_message_id3>
2009 In-Reply-To: <dummy_test_message_id2>
2010 Subject: Testing...
2012 Yet another message in the same thread/issue.
2013 ''')
2015         self.assertEqual(nodeid, nodeid2)
2016         self.assertEqual(nodeid, nodeid3)
2018     def testHelpSubject(self):
2019         message = '''Content-Type: text/plain;
2020   charset="iso-8859-1"
2021 From: Chef <chef@bork.bork.bork>
2022 To: issue_tracker@your.tracker.email.domain.example
2023 Message-Id: <dummy_test_message_id2>
2024 In-Reply-To: <dummy_test_message_id>
2025 Subject: hElp
2028 '''
2029         self.assertRaises(MailUsageHelp, self._handle_mail, message)
2031     def testMaillistSubject(self):
2032         self.instance.config.MAILGW_SUBJECT_SUFFIX_DELIMITERS = '[]'
2033         self.db.keyword.create(name='Foo')
2034         self._handle_mail('''Content-Type: text/plain;
2035   charset="iso-8859-1"
2036 From: Chef <chef@bork.bork.bork>
2037 To: issue_tracker@your.tracker.email.domain.example
2038 Subject: [mailinglist-name] [keyword1] Testing.. [name=Bar]
2039 Cc: richard@test.test
2040 Reply-To: chef@bork.bork.bork
2041 Message-Id: <dummy_test_message_id>
2043 ''')
2045         assert not os.path.exists(SENDMAILDEBUG)
2046         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2048     def testUnknownPrefixSubject(self):
2049         self.db.keyword.create(name='Foo')
2050         self._handle_mail('''Content-Type: text/plain;
2051   charset="iso-8859-1"
2052 From: Chef <chef@bork.bork.bork>
2053 To: issue_tracker@your.tracker.email.domain.example
2054 Subject: VeryStrangeRe: [keyword1] Testing.. [name=Bar]
2055 Cc: richard@test.test
2056 Reply-To: chef@bork.bork.bork
2057 Message-Id: <dummy_test_message_id>
2059 ''')
2061         assert not os.path.exists(SENDMAILDEBUG)
2062         self.assertEqual(self.db.keyword.get('1', 'name'), 'Bar')
2064     def testOneCharSubject(self):
2065         message = '''Content-Type: text/plain;
2066   charset="iso-8859-1"
2067 From: Chef <chef@bork.bork.bork>
2068 To: issue_tracker@your.tracker.email.domain.example
2069 Subject: b
2070 Cc: richard@test.test
2071 Reply-To: chef@bork.bork.bork
2072 Message-Id: <dummy_test_message_id>
2074 '''
2075         try:
2076             self._handle_mail(message)
2077         except MailUsageError:
2078             self.fail('MailUsageError raised')
2080     def testIssueidLast(self):
2081         nodeid1 = self.doNewIssue()
2082         nodeid2 = self._handle_mail('''Content-Type: text/plain;
2083   charset="iso-8859-1"
2084 From: mary <mary@test.test>
2085 To: issue_tracker@your.tracker.email.domain.example
2086 Message-Id: <followup_dummy_id>
2087 In-Reply-To: <dummy_test_message_id>
2088 Subject: New title [issue1]
2090 This is a second followup
2091 ''')
2093         assert nodeid1 == nodeid2
2094         self.assertEqual(self.db.issue.get(nodeid2, 'title'), "Testing...")
2096     def testSecurityMessagePermissionContent(self):
2097         id = self.doNewIssue()
2098         issue = self.db.issue.getnode (id)
2099         self.db.security.addRole(name='Nomsg')
2100         self.db.security.addPermissionToRole('Nomsg', 'Email Access')
2101         for cl in 'issue', 'file', 'keyword':
2102             for p in 'View', 'Edit', 'Create':
2103                 self.db.security.addPermissionToRole('Nomsg', p, cl)
2104         self.db.user.set(self.mary_id, roles='Nomsg')
2105         nodeid = self._handle_mail('''Content-Type: text/plain;
2106   charset="iso-8859-1"
2107 From: Chef <chef@bork.bork.bork>
2108 To: issue_tracker@your.tracker.email.domain.example
2109 Message-Id: <dummy_test_message_id_2>
2110 Subject: [issue%(id)s] Testing... [nosy=+mary]
2112 Just a test reply
2113 '''%locals())
2114         assert os.path.exists(SENDMAILDEBUG)
2115         self.compareMessages(self._get_mail(),
2116 '''FROM: roundup-admin@your.tracker.email.domain.example
2117 TO: chef@bork.bork.bork, richard@test.test
2118 Content-Type: text/plain; charset="utf-8"
2119 Subject: [issue1] Testing...
2120 To: richard@test.test
2121 From: "Bork, Chef" <issue_tracker@your.tracker.email.domain.example>
2122 Reply-To: Roundup issue tracker
2123  <issue_tracker@your.tracker.email.domain.example>
2124 MIME-Version: 1.0
2125 Message-Id: <dummy_test_message_id_2>
2126 In-Reply-To: <dummy_test_message_id>
2127 X-Roundup-Name: Roundup issue tracker
2128 X-Roundup-Loop: hello
2129 X-Roundup-Issue-Status: chatting
2130 Content-Transfer-Encoding: quoted-printable
2133 Bork, Chef <chef@bork.bork.bork> added the comment:
2135 Just a test reply
2137 ----------
2138 nosy: +mary
2139 status: unread -> chatting
2141 _______________________________________________________________________
2142 Roundup issue tracker <issue_tracker@your.tracker.email.domain.example>
2143 <http://tracker.example/cgi-bin/roundup.cgi/bugs/issue1>
2144 _______________________________________________________________________
2145 ''')
2147     def testOutlookAttachment(self):
2148         message = '''X-MimeOLE: Produced By Microsoft Exchange V6.5
2149 Content-class: urn:content-classes:message
2150 MIME-Version: 1.0
2151 Content-Type: multipart/mixed;
2152         boundary="----_=_NextPart_001_01CACA65.40A51CBC"
2153 Subject: Example of a failed outlook attachment e-mail
2154 Date: Tue, 23 Mar 2010 01:43:44 -0700
2155 Message-ID: <CA37F17219784343816CA6613D2E339205E7D0F9@nrcwstexb1.nrc.ca>
2156 X-MS-Has-Attach: yes
2157 X-MS-TNEF-Correlator: 
2158 Thread-Topic: Example of a failed outlook attachment e-mail
2159 Thread-Index: AcrKJo/t3pUBBwTpSwWNE3LE67UBDQ==
2160 From: "Hugh" <richard@test.test>
2161 To: <richard@test.test>
2162 X-OriginalArrivalTime: 23 Mar 2010 08:45:57.0350 (UTC) FILETIME=[41893860:01CACA65]
2164 This is a multi-part message in MIME format.
2166 ------_=_NextPart_001_01CACA65.40A51CBC
2167 Content-Type: multipart/alternative;
2168         boundary="----_=_NextPart_002_01CACA65.40A51CBC"
2171 ------_=_NextPart_002_01CACA65.40A51CBC
2172 Content-Type: text/plain;
2173         charset="us-ascii"
2174 Content-Transfer-Encoding: quoted-printable
2177 Hi Richard,
2179 I suppose this isn't the exact message that was sent but is a resend of
2180 one of my trial messages that failed.  For your benefit I changed the
2181 subject line and am adding these words to the message body.  Should
2182 still be as problematic, but if you like I can resend an exact copy of a
2183 failed message changing nothing except putting your address instead of
2184 our tracker.
2186 Thanks very much for taking time to look into this.  Much appreciated.
2188  <<battery backup>>=20
2190 ------_=_NextPart_002_01CACA65.40A51CBC
2191 Content-Type: text/html;
2192         charset="us-ascii"
2193 Content-Transfer-Encoding: quoted-printable
2195 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
2196 <HTML>
2197 <HEAD>
2198 <META HTTP-EQUIV=3D"Content-Type" CONTENT=3D"text/html; =
2199 charset=3Dus-ascii">
2200 <META NAME=3D"Generator" CONTENT=3D"MS Exchange Server version =
2201 6.5.7654.12">
2202 <TITLE>Example of a failed outlook attachment e-mail</TITLE>
2203 </HEAD>
2204 <BODY>
2205 <!-- Converted from text/rtf format -->
2206 <BR>
2208 <P><FONT SIZE=3D2 FACE=3D"Arial">Hi Richard,</FONT>
2209 </P>
2211 <P><FONT SIZE=3D2 FACE=3D"Arial">I suppose this isn't the exact message =
2212 that was sent but is a resend of one of my trial messages that =
2213 failed.&nbsp; For your benefit I changed the subject line and am adding =
2214 these words to the message body.&nbsp; Should still be as problematic, =
2215 but if you like I can resend an exact copy of a failed message changing =
2216 nothing except putting your address instead of our tracker.</FONT></P>
2218 <P><FONT SIZE=3D2 FACE=3D"Arial">Thanks very much for taking time to =
2219 look into this.&nbsp; Much appreciated.</FONT>
2220 </P>
2221 <BR>
2223 <P><FONT FACE=3D"Arial" SIZE=3D2 COLOR=3D"#000000"> &lt;&lt;battery =
2224 backup&gt;&gt; </FONT>
2225 </P>
2227 </BODY>
2228 </HTML>
2229 ------_=_NextPart_002_01CACA65.40A51CBC--
2231 ------_=_NextPart_001_01CACA65.40A51CBC
2232 Content-Type: message/rfc822
2233 Content-Transfer-Encoding: 7bit
2235 X-MimeOLE: Produced By Microsoft Exchange V6.5
2236 MIME-Version: 1.0
2237 Content-Type: multipart/alternative;
2238         boundary="----_=_NextPart_003_01CAC15A.29717800"
2239 X-OriginalArrivalTime: 11 Mar 2010 20:33:51.0249 (UTC) FILETIME=[28FEE010:01CAC15A]
2240 Content-class: urn:content-classes:message
2241 Subject: battery backup
2242 Date: Thu, 11 Mar 2010 13:33:43 -0700
2243 Message-ID: <p06240809c7bf02f9624c@[128.114.22.203]>
2244 X-MS-Has-Attach: 
2245 X-MS-TNEF-Correlator: 
2246 Thread-Topic: battery backup
2247 Thread-Index: AcrBWimtulTrSvBdQ2CcfZ8lyQdxmQ==
2248 From: "Jerry" <jerry@test.test>
2249 To: "Hugh" <hugh@test.test>
2251 This is a multi-part message in MIME format.
2253 ------_=_NextPart_003_01CAC15A.29717800
2254 Content-Type: text/plain;
2255         charset="iso-8859-1"
2256 Content-Transfer-Encoding: quoted-printable
2258 Dear Hugh,
2259         A car batter has an energy capacity of ~ 500Wh.  A UPS=20
2260 battery is worse than this.
2262 if we need to provied 100kW for 30 minutes that will take 100 car=20
2263 batteries.  This seems like an awful lot of batteries.
2265 Of course I like your idea of making the time 1 minute, so we get to=20
2266 a more modest number of batteries
2268 Jerry
2271 ------_=_NextPart_003_01CAC15A.29717800
2272 Content-Type: text/html;
2273         charset="iso-8859-1"
2274 Content-Transfer-Encoding: quoted-printable
2276 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
2277 <HTML>
2278 <HEAD>
2279 <META HTTP-EQUIV=3D"Content-Type" CONTENT=3D"text/html; =
2280 charset=3Diso-8859-1">
2281 <META NAME=3D"Generator" CONTENT=3D"MS Exchange Server version =
2282 6.5.7654.12">
2283 <TITLE>battery backup</TITLE>
2284 </HEAD>
2285 <BODY>
2286 <!-- Converted from text/plain format -->
2288 <P><FONT SIZE=3D2>Dear Hugh,</FONT>
2290 <BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <FONT SIZE=3D2>A car =
2291 batter has an energy capacity of ~ 500Wh.&nbsp; A UPS </FONT>
2293 <BR><FONT SIZE=3D2>battery is worse than this.</FONT>
2294 </P>
2296 <P><FONT SIZE=3D2>if we need to provied 100kW for 30 minutes that will =
2297 take 100 car </FONT>
2299 <BR><FONT SIZE=3D2>batteries.&nbsp; This seems like an awful lot of =
2300 batteries.</FONT>
2301 </P>
2303 <P><FONT SIZE=3D2>Of course I like your idea of making the time 1 =
2304 minute, so we get to </FONT>
2306 <BR><FONT SIZE=3D2>a more modest number of batteries</FONT>
2307 </P>
2309 <P><FONT SIZE=3D2>Jerry</FONT>
2310 </P>
2312 </BODY>
2313 </HTML>
2314 ------_=_NextPart_003_01CAC15A.29717800--
2316 ------_=_NextPart_001_01CACA65.40A51CBC--
2317 '''
2318         nodeid = self._handle_mail(message)
2319         assert not os.path.exists(SENDMAILDEBUG)
2320         msgid = self.db.issue.get(nodeid, 'messages')[0]
2321         self.assert_(self.db.msg.get(msgid, 'content').startswith('Hi Richard'))
2322         self.assertEqual(self.db.msg.get(msgid, 'files'), ['1', '2'])
2323         fileid = self.db.msg.get(msgid, 'files')[0]
2324         self.assertEqual(self.db.file.get(fileid, 'type'), 'text/html')
2325         fileid = self.db.msg.get(msgid, 'files')[1]
2326         self.assertEqual(self.db.file.get(fileid, 'type'), 'message/rfc822')
2328     def testForwardedMessageAttachment(self):
2329         message = '''Return-Path: <rgg@test.test>
2330 Received: from localhost(127.0.0.1), claiming to be "[115.130.26.69]"
2331 via SMTP by localhost, id smtpdAAApLaWrq; Tue Apr 13 23:10:05 2010
2332 Message-ID: <4BC4F9C7.50409@test.test>
2333 Date: Wed, 14 Apr 2010 09:09:59 +1000
2334 From: Rupert Goldie <rgg@test.test>
2335 User-Agent: Thunderbird 2.0.0.24 (Windows/20100228)
2336 MIME-Version: 1.0
2337 To: ekit issues <issues@test.test>
2338 Subject: [Fwd: PHP ERROR (fb)] post limit reached
2339 Content-Type: multipart/mixed; boundary="------------000807090608060304010403"
2341 This is a multi-part message in MIME format.
2342 --------------000807090608060304010403
2343 Content-Type: text/plain; charset=ISO-8859-1; format=flowed
2344 Content-Transfer-Encoding: 7bit
2346 Catch this exception and log it without emailing.
2348 --------------000807090608060304010403
2349 Content-Type: message/rfc822; name="PHP ERROR (fb).eml"
2350 Content-Transfer-Encoding: 7bit
2351 Content-Disposition: inline; filename="PHP ERROR (fb).eml"
2353 Return-Path: <ektravj@test.test>
2354 X-Sieve: CMU Sieve 2.2
2355 via SMTP by crown.off.ekorp.com, id smtpdAAA1JaW1o; Tue Apr 13 23:01:04 2010
2356 X-Virus-Scanned: by amavisd-new at ekit.com
2357 To: facebook-errors@test.test
2358 From: ektravj@test.test
2359 Subject: PHP ERROR (fb)
2360 Message-Id: <20100413230100.D601D27E84@mail2.elax3.ekorp.com>
2361 Date: Tue, 13 Apr 2010 23:01:00 +0000 (UTC)
2363 [13-Apr-2010 22:49:02] PHP Fatal error:  Uncaught exception 'Exception' with message 'Facebook Error Message: Feed action request limit reached' in /app/01/www/virtual/fb.ekit.com/htdocs/includes/functions.php:280
2364 Stack trace:
2365 #0 /app/01/www/virtual/fb.ekit.com/htdocs/gateway/ekit/feed/index.php(178): fb_exceptions(Object(FacebookRestClientException))
2366 #1 {main}
2367  thrown in /app/01/www/virtual/fb.ekit.com/htdocs/includes/functions.php on line 280
2370 --------------000807090608060304010403--
2371 '''
2372         nodeid = self._handle_mail(message)
2373         assert not os.path.exists(SENDMAILDEBUG)
2374         msgid = self.db.issue.get(nodeid, 'messages')[0]
2375         self.assertEqual(self.db.msg.get(msgid, 'content'),
2376             'Catch this exception and log it without emailing.')
2377         self.assertEqual(self.db.msg.get(msgid, 'files'), ['1'])
2378         fileid = self.db.msg.get(msgid, 'files')[0]
2379         self.assertEqual(self.db.file.get(fileid, 'type'), 'message/rfc822')
2381 def test_suite():
2382     suite = unittest.TestSuite()
2383     suite.addTest(unittest.makeSuite(MailgwTestCase))
2384     return suite
2386 if __name__ == '__main__':
2387     runner = unittest.TextTestRunner()
2388     unittest.main(testRunner=runner)
2390 # vim: set filetype=python sts=4 sw=4 et si :