204
205
"There is no such bug in Launchpad: 1", message)
208
class MaloneHandlerProcessTestCase(TestCaseWithFactory):
209
"""Test the bug mail processing loop."""
210
layer = LaunchpadFunctionalLayer
213
def getLatestBugNotification():
214
return BugNotification.selectFirst(orderBy='-id')
216
def test_new_bug(self):
217
project = self.factory.makeProduct(name='fnord')
219
handler = MaloneHandler()
220
with person_logged_in(project.owner):
221
msg = self.factory.makeSignedMessage(
222
body='borked\n affects fnord',
223
subject='subject borked',
224
to_address='new@bugs.launchpad.dev')
225
handler.process(msg, msg['To'])
226
notification = self.getLatestBugNotification()
227
bug = notification.bug
229
[project.owner], list(bug.getDirectSubscribers()))
230
self.assertEqual(project.owner, bug.owner)
231
self.assertEqual('subject borked', bug.title)
232
self.assertEqual(1, bug.messages.count())
233
self.assertEqual('borked\n affects fnord', bug.description)
234
self.assertEqual(1, len(bug.bugtasks))
235
self.assertEqual(project, bug.bugtasks[0].target)
237
def test_new_bug_with_one_misplaced_affects_line(self):
238
# Affects commands in the wrong position are processed as the user
239
# intended when the bug is new and there is only one affects.
240
project = self.factory.makeProduct(name='fnord')
241
assignee = self.factory.makePerson(name='pting')
243
handler = MaloneHandler()
244
with person_logged_in(project.owner):
245
msg = self.factory.makeSignedMessage(
246
body='borked\n assignee pting\n affects fnord',
247
subject='affects after assignee',
248
to_address='new@bugs.launchpad.dev')
249
handler.process(msg, msg['To'])
250
notification = self.getLatestBugNotification()
251
bug = notification.bug
252
self.assertEqual('affects after assignee', bug.title)
253
self.assertEqual(1, len(bug.bugtasks))
254
self.assertEqual(project, bug.bugtasks[0].target)
255
self.assertEqual(assignee, bug.bugtasks[0].assignee)
257
def test_new_affect_command_interleaved_with_bug_commands(self):
258
# The bug commands can appear before and after the affects command.
259
project = self.factory.makeProduct(name='fnord')
261
handler = MaloneHandler()
262
with person_logged_in(project.owner):
263
msg = self.factory.makeSignedMessage(
264
body='unsecure\n security yes\n affects fnord\n tag ajax',
265
subject='unsecure code',
266
to_address='new@bugs.launchpad.dev')
267
handler.process(msg, msg['To'])
268
notification = self.getLatestBugNotification()
269
bug = notification.bug
270
self.assertEqual('unsecure code', bug.title)
271
self.assertEqual(True, bug.security_related)
272
self.assertEqual(['ajax'], bug.tags)
273
self.assertEqual(1, len(bug.bugtasks))
274
self.assertEqual(project, bug.bugtasks[0].target)
276
def test_new_security_bug(self):
277
# Structural subscribers are not notified of security bugs.
278
maintainer = self.factory.makePerson(name='maintainer')
279
project = self.factory.makeProduct(name='fnord', owner=maintainer)
280
subscriber = self.factory.makePerson(name='subscriber')
281
with person_logged_in(subscriber):
282
project.addBugSubscription(subscriber, subscriber)
284
handler = MaloneHandler()
285
with person_logged_in(project.owner):
286
msg = self.factory.makeSignedMessage(
287
body='bad thing\n security yes\n affects fnord',
288
subject='security issue',
289
to_address='new@bugs.launchpad.dev')
290
handler.process(msg, msg['To'])
291
notification = self.getLatestBugNotification()
292
bug = notification.bug
293
self.assertEqual('security issue', bug.title)
294
self.assertEqual(True, bug.security_related)
295
self.assertEqual(1, len(bug.bugtasks))
296
self.assertEqual(project, bug.bugtasks[0].target)
298
for notification in BugNotification.select():
299
for recipient in notification.recipients:
300
recipients.add(recipient.person)
301
self.assertContentEqual([maintainer], recipients)
207
304
class BugTaskCommandGroupTestCase(TestCase):
209
306
def test_BugTaskCommandGroup_init_with_command(self):
309
406
self.assertFalse(group._groups is group.groups)
310
407
self.assertEqual([bugtask_group_1, bugtask_group_2], group.groups)
409
def test_BugCommandGroup_groups_new_bug_with_fixable_affects(self):
410
# A new bug that affects only one target does not require the
411
# affects command to be first.
412
group = BugCommandGroup(
413
BugEmailCommands.get('bug', ['new']))
414
status_command = BugEmailCommands.get('status', ['triaged'])
415
bugtask_group_1 = BugTaskCommandGroup(status_command)
416
group.add(bugtask_group_1)
417
affects_command = BugEmailCommands.get('affects', ['fnord'])
418
bugtask_group_2 = BugTaskCommandGroup(affects_command)
419
group.add(bugtask_group_2)
420
self.assertEqual(1, len(group.groups))
422
group._groups, group.groups,
423
"List reference returned instead of copy.")
425
[affects_command, status_command], group.groups[0].commands)
312
427
def test_BugCommandGroup__nonzero__false(self):
313
428
# A BugCommandGroup is zero is it has no commands or groups.
314
429
group = BugCommandGroup()