Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(17)

Unified Diff: appengine/monorail/features/test/notify_helpers_test.py

Issue 1868553004: Open Source Monorail (Closed) Base URL: https://chromium.googlesource.com/infra/infra.git@master
Patch Set: Rebase Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: appengine/monorail/features/test/notify_helpers_test.py
diff --git a/appengine/monorail/features/test/notify_helpers_test.py b/appengine/monorail/features/test/notify_helpers_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..7267269e93b76f646ff2d24c3462025de81a6fb3
--- /dev/null
+++ b/appengine/monorail/features/test/notify_helpers_test.py
@@ -0,0 +1,384 @@
+# -*- coding: utf8 -*-
+# Copyright 2016 The Chromium Authors. All rights reserved.
+# Use of this source code is govered by a BSD-style
+# license that can be found in the LICENSE file or at
+# https://developers.google.com/open-source/licenses/bsd
+
+"""Tests for notify_helpers.py."""
+
+import unittest
+
+from features import notify_helpers
+from framework import emailfmt
+from framework import framework_views
+from services import service_manager
+from testing import fake
+
+
+REPLY_NOT_ALLOWED = notify_helpers.REPLY_NOT_ALLOWED
+REPLY_MAY_COMMENT = notify_helpers.REPLY_MAY_COMMENT
+REPLY_MAY_UPDATE = notify_helpers.REPLY_MAY_UPDATE
+
+
+class ComputeIssueChangeAddressPermListTest(unittest.TestCase):
+
+ def setUp(self):
+ self.users_by_id = {
+ 111L: framework_views.UserView(111L, 'owner@example.com', True),
+ 222L: framework_views.UserView(222L, 'member@example.com', True),
+ 999L: framework_views.UserView(999L, 'visitor@example.com', True),
+ }
+ self.services = service_manager.Services(
+ project=fake.ProjectService(),
+ config=fake.ConfigService(),
+ issue=fake.IssueService(),
+ user=fake.UserService(),
+ usergroup=fake.UserGroupService())
+ self.services.user.TestAddUser('owner@example.com', 111L)
+ self.services.user.TestAddUser('member@example.com', 222L)
+ self.services.user.TestAddUser('visitor@example.com', 999L)
+ self.project = self.services.project.TestAddProject(
+ 'proj', owner_ids=[111L], committer_ids=[222L])
+ self.project.process_inbound_email = True
+ self.issue = fake.MakeTestIssue(
+ self.project.project_id, 1, 'summary', 'New', 111L)
+
+ def testEmptyIDs(self):
+ cnxn = 'fake cnxn'
+ addr_perm_list = notify_helpers.ComputeIssueChangeAddressPermList(
+ cnxn, [], self.project, self.issue, self.services, [], {},
+ pref_check_function=lambda *args: True)
+ self.assertEqual([], addr_perm_list)
+
+ def testRecipientIsMember(self):
+ cnxn = 'fake cnxn'
+ ids_to_consider = [111L, 222L, 999L]
+ addr_perm_list = notify_helpers.ComputeIssueChangeAddressPermList(
+ cnxn, ids_to_consider, self.project, self.issue, self.services, set(),
+ self.users_by_id, pref_check_function=lambda *args: True)
+ self.assertEqual(
+ [(True, 'owner@example.com', REPLY_MAY_UPDATE),
+ (True, 'member@example.com', REPLY_MAY_UPDATE),
+ (False, 'visitor@example.com', REPLY_MAY_COMMENT)],
+ addr_perm_list)
+
+
+class ComputeProjectAndIssueNotificationAddrListTest(unittest.TestCase):
+
+ def setUp(self):
+ self.services = service_manager.Services(
+ project=fake.ProjectService(),
+ user=fake.UserService())
+ self.project = self.services.project.TestAddProject('project')
+ self.services.user.TestAddUser('alice@gmail.com', 111L)
+ self.services.user.TestAddUser('bob@gmail.com', 222L)
+ self.services.user.TestAddUser('fred@gmail.com', 555L)
+
+ def testNotifyAddress(self):
+ # No mailing list or filter rules are defined
+ addr_perm_list = notify_helpers.ComputeProjectNotificationAddrList(
+ self.project, True, set())
+ self.assertListEqual([], addr_perm_list)
+
+ # Only mailing list is notified.
+ self.project.issue_notify_address = 'mailing-list@domain.com'
+ addr_perm_list = notify_helpers.ComputeProjectNotificationAddrList(
+ self.project, True, set())
+ self.assertListEqual(
+ [(False, 'mailing-list@domain.com', REPLY_NOT_ALLOWED)],
+ addr_perm_list)
+
+ # No one is notified because mailing list was already notified.
+ omit_addrs = {'mailing-list@domain.com'}
+ addr_perm_list = notify_helpers.ComputeProjectNotificationAddrList(
+ self.project, False, omit_addrs)
+ self.assertListEqual([], addr_perm_list)
+
+ # No one is notified because anon users cannot view.
+ addr_perm_list = notify_helpers.ComputeProjectNotificationAddrList(
+ self.project, False, set())
+ self.assertListEqual([], addr_perm_list)
+
+ def testFilterRuleNotifyAddresses(self):
+ issue = fake.MakeTestIssue(
+ self.project.project_id, 1, 'summary', 'New', 555L)
+ issue.derived_notify_addrs.extend(['notify@domain.com'])
+
+ addr_perm_list = notify_helpers.ComputeIssueNotificationAddrList(
+ issue, set())
+ self.assertListEqual(
+ [(False, 'notify@domain.com', REPLY_NOT_ALLOWED)],
+ addr_perm_list)
+
+ # Also-notify addresses can be omitted (e.g., if it is the same as
+ # the email address of the user who made the change).
+ addr_perm_list = notify_helpers.ComputeIssueNotificationAddrList(
+ issue, {'notify@domain.com'})
+ self.assertListEqual([], addr_perm_list)
+
+
+class MakeBulletedEmailWorkItemsTest(unittest.TestCase):
+
+ def setUp(self):
+ self.project = fake.Project(project_name='proj1')
+ self.commenter_view = framework_views.UserView(
+ 111L, 'test@example.com', True)
+
+ def testEmptyAddrs(self):
+ """Test the case where we found zero users to notify."""
+ email_tasks = notify_helpers.MakeBulletedEmailWorkItems(
+ [], 'subject', 'body', 'body', self.project, 'example.com',
+ self.commenter_view)
+ self.assertEqual([], email_tasks)
+ email_tasks = notify_helpers.MakeBulletedEmailWorkItems(
+ [([], 'reason')], 'subject', 'body', 'body', self.project,
+ 'example.com', self.commenter_view)
+ self.assertEqual([], email_tasks)
+
+
+class MakeEmailWorkItemTest(unittest.TestCase):
+
+ def setUp(self):
+ self.project = fake.Project(project_name='proj1')
+ self.project.process_inbound_email = True
+ self.commenter_view = framework_views.UserView(
+ 111L, 'test@example.com', True)
+ self.expected_html_footer = (
+ 'You received this message because:<br/> 1. reason<br/><br/>You may '
+ 'adjust your notification preferences at:<br/><a href="https://'
+ 'example.com/hosting/settings">https://example.com/hosting/settings'
+ '</a>')
+
+ def testBodySelection(self):
+ """We send non-members the email body that is indented for non-members."""
+ email_task = notify_helpers._MakeEmailWorkItem(
+ (False, 'a@a.com', REPLY_NOT_ALLOWED),
+ ['reason'], 'subject', 'body non', 'body mem', self.project,
+ 'example.com', self.commenter_view)
+
+ self.assertEqual('a@a.com', email_task['to'])
+ self.assertEqual('subject', email_task['subject'])
+ self.assertIn('body non', email_task['body'])
+ self.assertEqual(
+ emailfmt.FormatFromAddr(self.project, commenter_view=self.commenter_view,
+ can_reply_to=False),
+ email_task['from_addr'])
+ self.assertEqual(emailfmt.NoReplyAddress(), email_task['reply_to'])
+
+ email_task = notify_helpers._MakeEmailWorkItem(
+ (True, 'a@a.com', REPLY_NOT_ALLOWED),
+ ['reason'], 'subject', 'body mem', 'body mem', self.project,
+ 'example.com', self.commenter_view)
+ self.assertIn('body mem', email_task['body'])
+
+ def testHtmlBody_NoDetailUrl(self):
+ """"An html body is not be sent if detail_url is not specified."""
+ email_task = notify_helpers._MakeEmailWorkItem(
+ (False, 'a@a.com', REPLY_NOT_ALLOWED),
+ ['reason'], 'subject', 'body non', 'body mem', self.project,
+ 'example.com', self.commenter_view, detail_url=None)
+
+ self.assertIsNone(email_task['html_body'])
+
+ def testHtmlBody_WithDetailUrl(self):
+ """"An html body is sent if a detail_url is specified."""
+ detail_url = 'http://test-detail-url.com/id=1234'
+ email_task = notify_helpers._MakeEmailWorkItem(
+ (False, 'a@a.com', REPLY_NOT_ALLOWED),
+ ['reason'], 'subject', 'body non', 'body mem', self.project,
+ 'example.com', self.commenter_view, detail_url=detail_url)
+
+ expected_html_body = (
+ notify_helpers.HTML_BODY_WITH_GMAIL_ACTION_TEMPLATE % (
+ detail_url,
+ 'body non-- <br/>%s' % self.expected_html_footer))
+ self.assertEquals(expected_html_body, email_task['html_body'])
+
+ def testHtmlBody_WithUnicodeChars(self):
+ """"An html body is sent if a detail_url is specified."""
+ detail_url = 'http://test-detail-url.com/id=1234'
+ unicode_content = '\xe2\x9d\xa4 â â'
+ email_task = notify_helpers._MakeEmailWorkItem(
+ (False, 'a@a.com', REPLY_NOT_ALLOWED),
+ ['reason'], 'subject', unicode_content, 'unused body mem',
+ self.project, 'example.com', self.commenter_view, detail_url=detail_url)
+
+ expected_html_body = (
+ notify_helpers.HTML_BODY_WITH_GMAIL_ACTION_TEMPLATE % (
+ detail_url,
+ '%s-- <br/>%s' % (unicode_content.decode('utf-8'),
+ self.expected_html_footer)))
+ self.assertEquals(expected_html_body, email_task['html_body'])
+
+ def testHtmlBody_WithLinks(self):
+ """"An html body is sent if a detail_url is specified."""
+ detail_url = 'http://test-detail-url.com/id=1234'
+ email_task = notify_helpers._MakeEmailWorkItem(
+ (False, 'a@a.com', REPLY_NOT_ALLOWED),
+ ['reason'], 'subject', 'test google.com test', 'unused body mem',
+ self.project, 'example.com', self.commenter_view, detail_url=detail_url)
+
+ expected_html_body = (
+ notify_helpers.HTML_BODY_WITH_GMAIL_ACTION_TEMPLATE % (
+ detail_url,
+ 'test <a href="http://google.com">google.com</a> test-- <br/>%s' % (
+ self.expected_html_footer)))
+ self.assertEquals(expected_html_body, email_task['html_body'])
+
+ def testHtmlBody_LinkWithinTags(self):
+ """"An html body is sent with correct <a href>s."""
+ detail_url = 'http://test-detail-url.com/id=1234'
+ email_task = notify_helpers._MakeEmailWorkItem(
+ (False, 'a@a.com', REPLY_NOT_ALLOWED),
+ ['reason'], 'subject', 'test <http://google.com> test', 'unused body',
+ self.project, 'example.com', self.commenter_view, detail_url=detail_url)
+
+ expected_html_body = (
+ notify_helpers.HTML_BODY_WITH_GMAIL_ACTION_TEMPLATE % (
+ detail_url,
+ 'test <a href="http://google.com"><http://google.com></a> '
+ 'test-- <br/>%s' % self.expected_html_footer))
+ self.assertEquals(expected_html_body, email_task['html_body'])
+
+ def testHtmlBody_EmailWithinTags(self):
+ """"An html body is sent with correct <a href>s."""
+ detail_url = 'http://test-detail-url.com/id=1234'
+ email_task = notify_helpers._MakeEmailWorkItem(
+ (False, 'a@a.com', REPLY_NOT_ALLOWED),
+ ['reason'], 'subject', 'test <t@chromium.org> <a@chromium.org> test',
+ 'unused body mem', self.project, 'example.com', self.commenter_view,
+ detail_url=detail_url)
+
+ expected_html_body = (
+ notify_helpers.HTML_BODY_WITH_GMAIL_ACTION_TEMPLATE % (
+ detail_url,
+ 'test <a href="mailto:t@chromium.org"><t@chromium.org></a> '
+ '<a href="mailto:a@chromium.org"><a@chromium.org></a> '
+ 'test-- <br/>%s' % self.expected_html_footer))
+ self.assertEquals(expected_html_body, email_task['html_body'])
+
+ def testHtmlBody_WithEscapedHtml(self):
+ """"An html body is sent with html content escaped."""
+ detail_url = 'http://test-detail-url.com/id=1234'
+ body_with_html_content = (
+ '<a href="http://www.google.com">test</a> \'something\'')
+ email_task = notify_helpers._MakeEmailWorkItem(
+ (False, 'a@a.com', REPLY_NOT_ALLOWED),
+ ['reason'], 'subject', body_with_html_content, 'unused body mem',
+ self.project, 'example.com', self.commenter_view, detail_url=detail_url)
+
+ escaped_body_with_html_content = (
+ '&lt;a href=&quot;http://www.google.com&quot;&gt;test&lt;/a&gt; '
+ '&#39;something&#39;')
+ notify_helpers._MakeNotificationFooter(
+ ['reason'], REPLY_NOT_ALLOWED, 'example.com')
+ expected_html_body = (
+ notify_helpers.HTML_BODY_WITH_GMAIL_ACTION_TEMPLATE % (
+ detail_url,
+ '%s-- <br/>%s' % (escaped_body_with_html_content,
+ self.expected_html_footer)))
+ self.assertEquals(expected_html_body, email_task['html_body'])
+
+ def testReplyInvitation(self):
+ """We include a footer about replying that is appropriate for that user."""
+ email_task = notify_helpers._MakeEmailWorkItem(
+ (True, 'a@a.com', REPLY_NOT_ALLOWED),
+ ['reason'], 'subject', 'body non', 'body mem', self.project,
+ 'example.com', self.commenter_view)
+ self.assertEqual(emailfmt.NoReplyAddress(), email_task['reply_to'])
+ self.assertNotIn('Reply to this email', email_task['body'])
+
+ email_task = notify_helpers._MakeEmailWorkItem(
+ (True, 'a@a.com', REPLY_MAY_COMMENT),
+ ['reason'], 'subject', 'body non', 'body mem', self.project,
+ 'example.com', self.commenter_view)
+ self.assertEqual(
+ '%s@%s' % (self.project.project_name, emailfmt.MailDomain()),
+ email_task['reply_to'])
+ self.assertIn('Reply to this email to add a comment', email_task['body'])
+ self.assertNotIn('make changes', email_task['body'])
+
+ email_task = notify_helpers._MakeEmailWorkItem(
+ (True, 'a@a.com', REPLY_MAY_UPDATE),
+ ['reason'], 'subject', 'body non', 'body mem', self.project,
+ 'example.com', self.commenter_view)
+ self.assertEqual(
+ '%s@%s' % (self.project.project_name, emailfmt.MailDomain()),
+ email_task['reply_to'])
+ self.assertIn('Reply to this email to add a comment', email_task['body'])
+ self.assertIn('make updates', email_task['body'])
+
+ def testInboundEmailDisabled(self):
+ """We don't invite replies if they are disabled for this project."""
+ self.project.process_inbound_email = False
+ email_task = notify_helpers._MakeEmailWorkItem(
+ (True, 'a@a.com', REPLY_MAY_UPDATE),
+ ['reason'], 'subject', 'body non', 'body mem', self.project,
+ 'example.com', self.commenter_view)
+ self.assertEqual(emailfmt.NoReplyAddress(), email_task['reply_to'])
+
+ def testReasons(self):
+ """The footer lists reasons why that email was sent to that user."""
+ email_task = notify_helpers._MakeEmailWorkItem(
+ (True, 'a@a.com', REPLY_MAY_UPDATE),
+ ['Funny', 'Caring', 'Near'], 'subject', 'body', 'body', self.project,
+ 'example.com', self.commenter_view)
+ self.assertIn('because:', email_task['body'])
+ self.assertIn('1. Funny', email_task['body'])
+ self.assertIn('2. Caring', email_task['body'])
+ self.assertIn('3. Near', email_task['body'])
+
+ email_task = notify_helpers._MakeEmailWorkItem(
+ (True, 'a@a.com', REPLY_MAY_UPDATE),
+ [], 'subject', 'body', 'body', self.project,
+ 'example.com', self.commenter_view)
+ self.assertNotIn('because', email_task['body'])
+
+
+class MakeNotificationFooterTest(unittest.TestCase):
+
+ def testMakeNotificationFooter_NoReason(self):
+ footer = notify_helpers._MakeNotificationFooter(
+ [], REPLY_NOT_ALLOWED, 'example.com')
+ self.assertEqual('', footer)
+
+ def testMakeNotificationFooter_WithReason(self):
+ footer = notify_helpers._MakeNotificationFooter(
+ ['REASON'], REPLY_NOT_ALLOWED, 'example.com')
+ self.assertIn('REASON', footer)
+ self.assertIn('https://example.com/hosting/settings', footer)
+
+ footer = notify_helpers._MakeNotificationFooter(
+ ['REASON'], REPLY_NOT_ALLOWED, 'example.com')
+ self.assertIn('REASON', footer)
+ self.assertIn('https://example.com/hosting/settings', footer)
+
+ def testMakeNotificationFooter_ManyReasons(self):
+ footer = notify_helpers._MakeNotificationFooter(
+ ['Funny', 'Caring', 'Warmblooded'], REPLY_NOT_ALLOWED,
+ 'example.com')
+ self.assertIn('Funny', footer)
+ self.assertIn('Caring', footer)
+ self.assertIn('Warmblooded', footer)
+
+ def testMakeNotificationFooter_WithReplyInstructions(self):
+ footer = notify_helpers._MakeNotificationFooter(
+ ['REASON'], REPLY_NOT_ALLOWED, 'example.com')
+ self.assertNotIn('Reply', footer)
+ self.assertIn('https://example.com/hosting/settings', footer)
+
+ footer = notify_helpers._MakeNotificationFooter(
+ ['REASON'], REPLY_MAY_COMMENT, 'example.com')
+ self.assertIn('add a comment', footer)
+ self.assertNotIn('make updates', footer)
+ self.assertIn('https://example.com/hosting/settings', footer)
+
+ footer = notify_helpers._MakeNotificationFooter(
+ ['REASON'], REPLY_MAY_UPDATE, 'example.com')
+ self.assertIn('add a comment', footer)
+ self.assertIn('make updates', footer)
+ self.assertIn('https://example.com/hosting/settings', footer)
+
+
+if __name__ == '__main__':
+ unittest.main()
« no previous file with comments | « appengine/monorail/features/test/inboundemail_test.py ('k') | appengine/monorail/features/test/notify_test.py » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698