OLD | NEW |
(Empty) | |
| 1 # -*- coding: utf8 -*- |
| 2 # Copyright 2016 The Chromium Authors. All rights reserved. |
| 3 # Use of this source code is govered by a BSD-style |
| 4 # license that can be found in the LICENSE file or at |
| 5 # https://developers.google.com/open-source/licenses/bsd |
| 6 |
| 7 """Tests for notify_helpers.py.""" |
| 8 |
| 9 import unittest |
| 10 |
| 11 from features import notify_helpers |
| 12 from framework import emailfmt |
| 13 from framework import framework_views |
| 14 from services import service_manager |
| 15 from testing import fake |
| 16 |
| 17 |
| 18 REPLY_NOT_ALLOWED = notify_helpers.REPLY_NOT_ALLOWED |
| 19 REPLY_MAY_COMMENT = notify_helpers.REPLY_MAY_COMMENT |
| 20 REPLY_MAY_UPDATE = notify_helpers.REPLY_MAY_UPDATE |
| 21 |
| 22 |
| 23 class ComputeIssueChangeAddressPermListTest(unittest.TestCase): |
| 24 |
| 25 def setUp(self): |
| 26 self.users_by_id = { |
| 27 111L: framework_views.UserView(111L, 'owner@example.com', True), |
| 28 222L: framework_views.UserView(222L, 'member@example.com', True), |
| 29 999L: framework_views.UserView(999L, 'visitor@example.com', True), |
| 30 } |
| 31 self.services = service_manager.Services( |
| 32 project=fake.ProjectService(), |
| 33 config=fake.ConfigService(), |
| 34 issue=fake.IssueService(), |
| 35 user=fake.UserService(), |
| 36 usergroup=fake.UserGroupService()) |
| 37 self.services.user.TestAddUser('owner@example.com', 111L) |
| 38 self.services.user.TestAddUser('member@example.com', 222L) |
| 39 self.services.user.TestAddUser('visitor@example.com', 999L) |
| 40 self.project = self.services.project.TestAddProject( |
| 41 'proj', owner_ids=[111L], committer_ids=[222L]) |
| 42 self.project.process_inbound_email = True |
| 43 self.issue = fake.MakeTestIssue( |
| 44 self.project.project_id, 1, 'summary', 'New', 111L) |
| 45 |
| 46 def testEmptyIDs(self): |
| 47 cnxn = 'fake cnxn' |
| 48 addr_perm_list = notify_helpers.ComputeIssueChangeAddressPermList( |
| 49 cnxn, [], self.project, self.issue, self.services, [], {}, |
| 50 pref_check_function=lambda *args: True) |
| 51 self.assertEqual([], addr_perm_list) |
| 52 |
| 53 def testRecipientIsMember(self): |
| 54 cnxn = 'fake cnxn' |
| 55 ids_to_consider = [111L, 222L, 999L] |
| 56 addr_perm_list = notify_helpers.ComputeIssueChangeAddressPermList( |
| 57 cnxn, ids_to_consider, self.project, self.issue, self.services, set(), |
| 58 self.users_by_id, pref_check_function=lambda *args: True) |
| 59 self.assertEqual( |
| 60 [(True, 'owner@example.com', REPLY_MAY_UPDATE), |
| 61 (True, 'member@example.com', REPLY_MAY_UPDATE), |
| 62 (False, 'visitor@example.com', REPLY_MAY_COMMENT)], |
| 63 addr_perm_list) |
| 64 |
| 65 |
| 66 class ComputeProjectAndIssueNotificationAddrListTest(unittest.TestCase): |
| 67 |
| 68 def setUp(self): |
| 69 self.services = service_manager.Services( |
| 70 project=fake.ProjectService(), |
| 71 user=fake.UserService()) |
| 72 self.project = self.services.project.TestAddProject('project') |
| 73 self.services.user.TestAddUser('alice@gmail.com', 111L) |
| 74 self.services.user.TestAddUser('bob@gmail.com', 222L) |
| 75 self.services.user.TestAddUser('fred@gmail.com', 555L) |
| 76 |
| 77 def testNotifyAddress(self): |
| 78 # No mailing list or filter rules are defined |
| 79 addr_perm_list = notify_helpers.ComputeProjectNotificationAddrList( |
| 80 self.project, True, set()) |
| 81 self.assertListEqual([], addr_perm_list) |
| 82 |
| 83 # Only mailing list is notified. |
| 84 self.project.issue_notify_address = 'mailing-list@domain.com' |
| 85 addr_perm_list = notify_helpers.ComputeProjectNotificationAddrList( |
| 86 self.project, True, set()) |
| 87 self.assertListEqual( |
| 88 [(False, 'mailing-list@domain.com', REPLY_NOT_ALLOWED)], |
| 89 addr_perm_list) |
| 90 |
| 91 # No one is notified because mailing list was already notified. |
| 92 omit_addrs = {'mailing-list@domain.com'} |
| 93 addr_perm_list = notify_helpers.ComputeProjectNotificationAddrList( |
| 94 self.project, False, omit_addrs) |
| 95 self.assertListEqual([], addr_perm_list) |
| 96 |
| 97 # No one is notified because anon users cannot view. |
| 98 addr_perm_list = notify_helpers.ComputeProjectNotificationAddrList( |
| 99 self.project, False, set()) |
| 100 self.assertListEqual([], addr_perm_list) |
| 101 |
| 102 def testFilterRuleNotifyAddresses(self): |
| 103 issue = fake.MakeTestIssue( |
| 104 self.project.project_id, 1, 'summary', 'New', 555L) |
| 105 issue.derived_notify_addrs.extend(['notify@domain.com']) |
| 106 |
| 107 addr_perm_list = notify_helpers.ComputeIssueNotificationAddrList( |
| 108 issue, set()) |
| 109 self.assertListEqual( |
| 110 [(False, 'notify@domain.com', REPLY_NOT_ALLOWED)], |
| 111 addr_perm_list) |
| 112 |
| 113 # Also-notify addresses can be omitted (e.g., if it is the same as |
| 114 # the email address of the user who made the change). |
| 115 addr_perm_list = notify_helpers.ComputeIssueNotificationAddrList( |
| 116 issue, {'notify@domain.com'}) |
| 117 self.assertListEqual([], addr_perm_list) |
| 118 |
| 119 |
| 120 class MakeBulletedEmailWorkItemsTest(unittest.TestCase): |
| 121 |
| 122 def setUp(self): |
| 123 self.project = fake.Project(project_name='proj1') |
| 124 self.commenter_view = framework_views.UserView( |
| 125 111L, 'test@example.com', True) |
| 126 |
| 127 def testEmptyAddrs(self): |
| 128 """Test the case where we found zero users to notify.""" |
| 129 email_tasks = notify_helpers.MakeBulletedEmailWorkItems( |
| 130 [], 'subject', 'body', 'body', self.project, 'example.com', |
| 131 self.commenter_view) |
| 132 self.assertEqual([], email_tasks) |
| 133 email_tasks = notify_helpers.MakeBulletedEmailWorkItems( |
| 134 [([], 'reason')], 'subject', 'body', 'body', self.project, |
| 135 'example.com', self.commenter_view) |
| 136 self.assertEqual([], email_tasks) |
| 137 |
| 138 |
| 139 class MakeEmailWorkItemTest(unittest.TestCase): |
| 140 |
| 141 def setUp(self): |
| 142 self.project = fake.Project(project_name='proj1') |
| 143 self.project.process_inbound_email = True |
| 144 self.commenter_view = framework_views.UserView( |
| 145 111L, 'test@example.com', True) |
| 146 self.expected_html_footer = ( |
| 147 'You received this message because:<br/> 1. reason<br/><br/>You may ' |
| 148 'adjust your notification preferences at:<br/><a href="https://' |
| 149 'example.com/hosting/settings">https://example.com/hosting/settings' |
| 150 '</a>') |
| 151 |
| 152 def testBodySelection(self): |
| 153 """We send non-members the email body that is indented for non-members.""" |
| 154 email_task = notify_helpers._MakeEmailWorkItem( |
| 155 (False, 'a@a.com', REPLY_NOT_ALLOWED), |
| 156 ['reason'], 'subject', 'body non', 'body mem', self.project, |
| 157 'example.com', self.commenter_view) |
| 158 |
| 159 self.assertEqual('a@a.com', email_task['to']) |
| 160 self.assertEqual('subject', email_task['subject']) |
| 161 self.assertIn('body non', email_task['body']) |
| 162 self.assertEqual( |
| 163 emailfmt.FormatFromAddr(self.project, commenter_view=self.commenter_view, |
| 164 can_reply_to=False), |
| 165 email_task['from_addr']) |
| 166 self.assertEqual(emailfmt.NoReplyAddress(), email_task['reply_to']) |
| 167 |
| 168 email_task = notify_helpers._MakeEmailWorkItem( |
| 169 (True, 'a@a.com', REPLY_NOT_ALLOWED), |
| 170 ['reason'], 'subject', 'body mem', 'body mem', self.project, |
| 171 'example.com', self.commenter_view) |
| 172 self.assertIn('body mem', email_task['body']) |
| 173 |
| 174 def testHtmlBody_NoDetailUrl(self): |
| 175 """"An html body is not be sent if detail_url is not specified.""" |
| 176 email_task = notify_helpers._MakeEmailWorkItem( |
| 177 (False, 'a@a.com', REPLY_NOT_ALLOWED), |
| 178 ['reason'], 'subject', 'body non', 'body mem', self.project, |
| 179 'example.com', self.commenter_view, detail_url=None) |
| 180 |
| 181 self.assertIsNone(email_task['html_body']) |
| 182 |
| 183 def testHtmlBody_WithDetailUrl(self): |
| 184 """"An html body is sent if a detail_url is specified.""" |
| 185 detail_url = 'http://test-detail-url.com/id=1234' |
| 186 email_task = notify_helpers._MakeEmailWorkItem( |
| 187 (False, 'a@a.com', REPLY_NOT_ALLOWED), |
| 188 ['reason'], 'subject', 'body non', 'body mem', self.project, |
| 189 'example.com', self.commenter_view, detail_url=detail_url) |
| 190 |
| 191 expected_html_body = ( |
| 192 notify_helpers.HTML_BODY_WITH_GMAIL_ACTION_TEMPLATE % ( |
| 193 detail_url, |
| 194 'body non-- <br/>%s' % self.expected_html_footer)) |
| 195 self.assertEquals(expected_html_body, email_task['html_body']) |
| 196 |
| 197 def testHtmlBody_WithUnicodeChars(self): |
| 198 """"An html body is sent if a detail_url is specified.""" |
| 199 detail_url = 'http://test-detail-url.com/id=1234' |
| 200 unicode_content = '\xe2\x9d\xa4 â â' |
| 201 email_task = notify_helpers._MakeEmailWorkItem( |
| 202 (False, 'a@a.com', REPLY_NOT_ALLOWED), |
| 203 ['reason'], 'subject', unicode_content, 'unused body mem', |
| 204 self.project, 'example.com', self.commenter_view, detail_url=detail_url) |
| 205 |
| 206 expected_html_body = ( |
| 207 notify_helpers.HTML_BODY_WITH_GMAIL_ACTION_TEMPLATE % ( |
| 208 detail_url, |
| 209 '%s-- <br/>%s' % (unicode_content.decode('utf-8'), |
| 210 self.expected_html_footer))) |
| 211 self.assertEquals(expected_html_body, email_task['html_body']) |
| 212 |
| 213 def testHtmlBody_WithLinks(self): |
| 214 """"An html body is sent if a detail_url is specified.""" |
| 215 detail_url = 'http://test-detail-url.com/id=1234' |
| 216 email_task = notify_helpers._MakeEmailWorkItem( |
| 217 (False, 'a@a.com', REPLY_NOT_ALLOWED), |
| 218 ['reason'], 'subject', 'test google.com test', 'unused body mem', |
| 219 self.project, 'example.com', self.commenter_view, detail_url=detail_url) |
| 220 |
| 221 expected_html_body = ( |
| 222 notify_helpers.HTML_BODY_WITH_GMAIL_ACTION_TEMPLATE % ( |
| 223 detail_url, |
| 224 'test <a href="http://google.com">google.com</a> test-- <br/>%s' % ( |
| 225 self.expected_html_footer))) |
| 226 self.assertEquals(expected_html_body, email_task['html_body']) |
| 227 |
| 228 def testHtmlBody_LinkWithinTags(self): |
| 229 """"An html body is sent with correct <a href>s.""" |
| 230 detail_url = 'http://test-detail-url.com/id=1234' |
| 231 email_task = notify_helpers._MakeEmailWorkItem( |
| 232 (False, 'a@a.com', REPLY_NOT_ALLOWED), |
| 233 ['reason'], 'subject', 'test <http://google.com> test', 'unused body', |
| 234 self.project, 'example.com', self.commenter_view, detail_url=detail_url) |
| 235 |
| 236 expected_html_body = ( |
| 237 notify_helpers.HTML_BODY_WITH_GMAIL_ACTION_TEMPLATE % ( |
| 238 detail_url, |
| 239 'test <a href="http://google.com"><http://google.com></a> ' |
| 240 'test-- <br/>%s' % self.expected_html_footer)) |
| 241 self.assertEquals(expected_html_body, email_task['html_body']) |
| 242 |
| 243 def testHtmlBody_EmailWithinTags(self): |
| 244 """"An html body is sent with correct <a href>s.""" |
| 245 detail_url = 'http://test-detail-url.com/id=1234' |
| 246 email_task = notify_helpers._MakeEmailWorkItem( |
| 247 (False, 'a@a.com', REPLY_NOT_ALLOWED), |
| 248 ['reason'], 'subject', 'test <t@chromium.org> <a@chromium.org> test', |
| 249 'unused body mem', self.project, 'example.com', self.commenter_view, |
| 250 detail_url=detail_url) |
| 251 |
| 252 expected_html_body = ( |
| 253 notify_helpers.HTML_BODY_WITH_GMAIL_ACTION_TEMPLATE % ( |
| 254 detail_url, |
| 255 'test <a href="mailto:t@chromium.org"><t@chromium.org></a> ' |
| 256 '<a href="mailto:a@chromium.org"><a@chromium.org></a> ' |
| 257 'test-- <br/>%s' % self.expected_html_footer)) |
| 258 self.assertEquals(expected_html_body, email_task['html_body']) |
| 259 |
| 260 def testHtmlBody_WithEscapedHtml(self): |
| 261 """"An html body is sent with html content escaped.""" |
| 262 detail_url = 'http://test-detail-url.com/id=1234' |
| 263 body_with_html_content = ( |
| 264 '<a href="http://www.google.com">test</a> \'something\'') |
| 265 email_task = notify_helpers._MakeEmailWorkItem( |
| 266 (False, 'a@a.com', REPLY_NOT_ALLOWED), |
| 267 ['reason'], 'subject', body_with_html_content, 'unused body mem', |
| 268 self.project, 'example.com', self.commenter_view, detail_url=detail_url) |
| 269 |
| 270 escaped_body_with_html_content = ( |
| 271 '<a href="http://www.google.com">test</a> ' |
| 272 ''something'') |
| 273 notify_helpers._MakeNotificationFooter( |
| 274 ['reason'], REPLY_NOT_ALLOWED, 'example.com') |
| 275 expected_html_body = ( |
| 276 notify_helpers.HTML_BODY_WITH_GMAIL_ACTION_TEMPLATE % ( |
| 277 detail_url, |
| 278 '%s-- <br/>%s' % (escaped_body_with_html_content, |
| 279 self.expected_html_footer))) |
| 280 self.assertEquals(expected_html_body, email_task['html_body']) |
| 281 |
| 282 def testReplyInvitation(self): |
| 283 """We include a footer about replying that is appropriate for that user.""" |
| 284 email_task = notify_helpers._MakeEmailWorkItem( |
| 285 (True, 'a@a.com', REPLY_NOT_ALLOWED), |
| 286 ['reason'], 'subject', 'body non', 'body mem', self.project, |
| 287 'example.com', self.commenter_view) |
| 288 self.assertEqual(emailfmt.NoReplyAddress(), email_task['reply_to']) |
| 289 self.assertNotIn('Reply to this email', email_task['body']) |
| 290 |
| 291 email_task = notify_helpers._MakeEmailWorkItem( |
| 292 (True, 'a@a.com', REPLY_MAY_COMMENT), |
| 293 ['reason'], 'subject', 'body non', 'body mem', self.project, |
| 294 'example.com', self.commenter_view) |
| 295 self.assertEqual( |
| 296 '%s@%s' % (self.project.project_name, emailfmt.MailDomain()), |
| 297 email_task['reply_to']) |
| 298 self.assertIn('Reply to this email to add a comment', email_task['body']) |
| 299 self.assertNotIn('make changes', email_task['body']) |
| 300 |
| 301 email_task = notify_helpers._MakeEmailWorkItem( |
| 302 (True, 'a@a.com', REPLY_MAY_UPDATE), |
| 303 ['reason'], 'subject', 'body non', 'body mem', self.project, |
| 304 'example.com', self.commenter_view) |
| 305 self.assertEqual( |
| 306 '%s@%s' % (self.project.project_name, emailfmt.MailDomain()), |
| 307 email_task['reply_to']) |
| 308 self.assertIn('Reply to this email to add a comment', email_task['body']) |
| 309 self.assertIn('make updates', email_task['body']) |
| 310 |
| 311 def testInboundEmailDisabled(self): |
| 312 """We don't invite replies if they are disabled for this project.""" |
| 313 self.project.process_inbound_email = False |
| 314 email_task = notify_helpers._MakeEmailWorkItem( |
| 315 (True, 'a@a.com', REPLY_MAY_UPDATE), |
| 316 ['reason'], 'subject', 'body non', 'body mem', self.project, |
| 317 'example.com', self.commenter_view) |
| 318 self.assertEqual(emailfmt.NoReplyAddress(), email_task['reply_to']) |
| 319 |
| 320 def testReasons(self): |
| 321 """The footer lists reasons why that email was sent to that user.""" |
| 322 email_task = notify_helpers._MakeEmailWorkItem( |
| 323 (True, 'a@a.com', REPLY_MAY_UPDATE), |
| 324 ['Funny', 'Caring', 'Near'], 'subject', 'body', 'body', self.project, |
| 325 'example.com', self.commenter_view) |
| 326 self.assertIn('because:', email_task['body']) |
| 327 self.assertIn('1. Funny', email_task['body']) |
| 328 self.assertIn('2. Caring', email_task['body']) |
| 329 self.assertIn('3. Near', email_task['body']) |
| 330 |
| 331 email_task = notify_helpers._MakeEmailWorkItem( |
| 332 (True, 'a@a.com', REPLY_MAY_UPDATE), |
| 333 [], 'subject', 'body', 'body', self.project, |
| 334 'example.com', self.commenter_view) |
| 335 self.assertNotIn('because', email_task['body']) |
| 336 |
| 337 |
| 338 class MakeNotificationFooterTest(unittest.TestCase): |
| 339 |
| 340 def testMakeNotificationFooter_NoReason(self): |
| 341 footer = notify_helpers._MakeNotificationFooter( |
| 342 [], REPLY_NOT_ALLOWED, 'example.com') |
| 343 self.assertEqual('', footer) |
| 344 |
| 345 def testMakeNotificationFooter_WithReason(self): |
| 346 footer = notify_helpers._MakeNotificationFooter( |
| 347 ['REASON'], REPLY_NOT_ALLOWED, 'example.com') |
| 348 self.assertIn('REASON', footer) |
| 349 self.assertIn('https://example.com/hosting/settings', footer) |
| 350 |
| 351 footer = notify_helpers._MakeNotificationFooter( |
| 352 ['REASON'], REPLY_NOT_ALLOWED, 'example.com') |
| 353 self.assertIn('REASON', footer) |
| 354 self.assertIn('https://example.com/hosting/settings', footer) |
| 355 |
| 356 def testMakeNotificationFooter_ManyReasons(self): |
| 357 footer = notify_helpers._MakeNotificationFooter( |
| 358 ['Funny', 'Caring', 'Warmblooded'], REPLY_NOT_ALLOWED, |
| 359 'example.com') |
| 360 self.assertIn('Funny', footer) |
| 361 self.assertIn('Caring', footer) |
| 362 self.assertIn('Warmblooded', footer) |
| 363 |
| 364 def testMakeNotificationFooter_WithReplyInstructions(self): |
| 365 footer = notify_helpers._MakeNotificationFooter( |
| 366 ['REASON'], REPLY_NOT_ALLOWED, 'example.com') |
| 367 self.assertNotIn('Reply', footer) |
| 368 self.assertIn('https://example.com/hosting/settings', footer) |
| 369 |
| 370 footer = notify_helpers._MakeNotificationFooter( |
| 371 ['REASON'], REPLY_MAY_COMMENT, 'example.com') |
| 372 self.assertIn('add a comment', footer) |
| 373 self.assertNotIn('make updates', footer) |
| 374 self.assertIn('https://example.com/hosting/settings', footer) |
| 375 |
| 376 footer = notify_helpers._MakeNotificationFooter( |
| 377 ['REASON'], REPLY_MAY_UPDATE, 'example.com') |
| 378 self.assertIn('add a comment', footer) |
| 379 self.assertIn('make updates', footer) |
| 380 self.assertIn('https://example.com/hosting/settings', footer) |
| 381 |
| 382 |
| 383 if __name__ == '__main__': |
| 384 unittest.main() |
OLD | NEW |