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