blob: c1ebe8316546e0599105141e398af09dcc892af5 [file] [log] [blame]
Copybara854996b2021-09-07 19:36:02 +00001# -*- coding: utf-8 -*-
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +01002# Copyright 2016 The Chromium Authors
3# Use of this source code is governed by a BSD-style license that can be
4# found in the LICENSE file.
Copybara854996b2021-09-07 19:36:02 +00005
6"""Tests for notify_helpers.py."""
7from __future__ import print_function
8from __future__ import division
9from __future__ import absolute_import
10
11import json
12import mock
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +010013import six
Copybara854996b2021-09-07 19:36:02 +000014import unittest
15import os
16
17from features import features_constants
18from features import notify_helpers
19from features import notify_reasons
20from framework import emailfmt
21from framework import framework_views
22from framework import urls
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +010023from mrproto import user_pb2
Copybara854996b2021-09-07 19:36:02 +000024from services import service_manager
25from testing import fake
26
27
28REPLY_NOT_ALLOWED = notify_reasons.REPLY_NOT_ALLOWED
29REPLY_MAY_COMMENT = notify_reasons.REPLY_MAY_COMMENT
30REPLY_MAY_UPDATE = notify_reasons.REPLY_MAY_UPDATE
31
32
33class TaskQueueingFunctionsTest(unittest.TestCase):
34
35 @mock.patch('framework.cloud_tasks_helpers._get_client')
36 def testAddAllEmailTasks(self, get_client_mock):
37 notify_helpers.AddAllEmailTasks(
38 tasks=[{'to': 'user'}, {'to': 'user2'}])
39
40 self.assertEqual(get_client_mock().create_task.call_count, 2)
41
42 queue_call_args = get_client_mock().queue_path.call_args_list
43 ((_app_id, _region, queue), _kwargs) = queue_call_args[0]
44 self.assertEqual(queue, features_constants.QUEUE_OUTBOUND_EMAIL)
45 ((_app_id, _region, queue), _kwargs) = queue_call_args[1]
46 self.assertEqual(queue, features_constants.QUEUE_OUTBOUND_EMAIL)
47
48 task_call_args = get_client_mock().create_task.call_args_list
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +010049 _, kwargs = task_call_args[0]
Copybara854996b2021-09-07 19:36:02 +000050 expected_task = {
51 'app_engine_http_request':
52 {
53 'relative_uri': urls.OUTBOUND_EMAIL_TASK + '.do',
54 'body': json.dumps({
55 'to': 'user'
56 }).encode(),
57 'headers': {
58 'Content-type': 'application/json'
59 }
60 }
61 }
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +010062 self.assertEqual(kwargs['task'], expected_task)
63 _, kwargs = task_call_args[1]
Copybara854996b2021-09-07 19:36:02 +000064 expected_task = {
65 'app_engine_http_request':
66 {
67 'relative_uri': urls.OUTBOUND_EMAIL_TASK + '.do',
68 'body': json.dumps({
69 'to': 'user2'
70 }).encode(),
71 'headers': {
72 'Content-type': 'application/json'
73 }
74 }
75 }
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +010076 self.assertEqual(kwargs['task'], expected_task)
Copybara854996b2021-09-07 19:36:02 +000077
78
79class MergeLinkedAccountReasonsTest(unittest.TestCase):
80
81 def setUp(self):
82 parent = user_pb2.User(
83 user_id=111, email='parent@example.org',
84 linked_child_ids=[222])
85 child = user_pb2.User(
86 user_id=222, email='child@example.org',
87 linked_parent_id=111)
88 user_3 = user_pb2.User(
89 user_id=333, email='user4@example.org')
90 user_4 = user_pb2.User(
91 user_id=444, email='user4@example.org')
92 self.addr_perm_parent = notify_reasons.AddrPerm(
93 False, parent.email, parent, notify_reasons.REPLY_NOT_ALLOWED,
94 user_pb2.UserPrefs())
95 self.addr_perm_child = notify_reasons.AddrPerm(
96 False, child.email, child, notify_reasons.REPLY_NOT_ALLOWED,
97 user_pb2.UserPrefs())
98 self.addr_perm_3 = notify_reasons.AddrPerm(
99 False, user_3.email, user_3, notify_reasons.REPLY_NOT_ALLOWED,
100 user_pb2.UserPrefs())
101 self.addr_perm_4 = notify_reasons.AddrPerm(
102 False, user_4.email, user_4, notify_reasons.REPLY_NOT_ALLOWED,
103 user_pb2.UserPrefs())
104 self.addr_perm_5 = notify_reasons.AddrPerm(
105 False, 'alias@example.com', None, notify_reasons.REPLY_NOT_ALLOWED,
106 user_pb2.UserPrefs())
107
108 def testEmptyDict(self):
109 """Zero users to notify."""
110 self.assertEqual(
111 {},
112 notify_helpers._MergeLinkedAccountReasons({}, {}))
113
114 def testNormal(self):
115 """No users are related."""
116 addr_to_addrperm = {
117 self.addr_perm_parent.address: self.addr_perm_parent,
118 self.addr_perm_3.address: self.addr_perm_3,
119 self.addr_perm_4.address: self.addr_perm_4,
120 self.addr_perm_5.address: self.addr_perm_5,
121 }
122 addr_to_reasons = {
123 self.addr_perm_parent.address: [notify_reasons.REASON_CCD],
124 self.addr_perm_3.address: [notify_reasons.REASON_OWNER],
125 self.addr_perm_4.address: [notify_reasons.REASON_CCD],
126 self.addr_perm_5.address: [notify_reasons.REASON_CCD],
127 }
128 self.assertEqual(
129 {self.addr_perm_parent.address: [notify_reasons.REASON_CCD],
130 self.addr_perm_3.address: [notify_reasons.REASON_OWNER],
131 self.addr_perm_4.address: [notify_reasons.REASON_CCD],
132 self.addr_perm_5.address: [notify_reasons.REASON_CCD]
133 },
134 notify_helpers._MergeLinkedAccountReasons(
135 addr_to_addrperm, addr_to_reasons))
136
137 def testMerged(self):
138 """A child is merged into parent notification."""
139 addr_to_addrperm = {
140 self.addr_perm_parent.address: self.addr_perm_parent,
141 self.addr_perm_child.address: self.addr_perm_child,
142 }
143 addr_to_reasons = {
144 self.addr_perm_parent.address: [notify_reasons.REASON_OWNER],
145 self.addr_perm_child.address: [notify_reasons.REASON_CCD],
146 }
147 self.assertEqual(
148 {self.addr_perm_parent.address:
149 [notify_reasons.REASON_OWNER,
150 notify_reasons.REASON_LINKED_ACCOUNT]
151 },
152 notify_helpers._MergeLinkedAccountReasons(
153 addr_to_addrperm, addr_to_reasons))
154
155
156class MakeBulletedEmailWorkItemsTest(unittest.TestCase):
157
158 def setUp(self):
159 self.project = fake.Project(project_name='proj1')
160 self.commenter_view = framework_views.StuffUserView(
161 111, 'test@example.com', True)
162 self.issue = fake.MakeTestIssue(
163 self.project.project_id, 1234, 'summary', 'New', 111)
164 self.detail_url = 'http://test-detail-url.com/id=1234'
165
166 def testEmptyAddrs(self):
167 """Test the case where we found zero users to notify."""
168 email_tasks = notify_helpers.MakeBulletedEmailWorkItems(
169 [], self.issue, 'link only body', 'non-member body', 'member body',
170 self.project, 'example.com',
171 self.commenter_view, self.detail_url)
172 self.assertEqual([], email_tasks)
173 email_tasks = notify_helpers.MakeBulletedEmailWorkItems(
174 [([], 'reason')], self.issue, 'link only body', 'non-member body',
175 'member body', self.project,
176 'example.com', self.commenter_view, self.detail_url)
177 self.assertEqual([], email_tasks)
178
179
180class LinkOnlyLogicTest(unittest.TestCase):
181
182 def setUp(self):
183 self.user_prefs = user_pb2.UserPrefs()
184 self.user = user_pb2.User()
185 self.issue = fake.MakeTestIssue(
186 789, 1, 'summary one', 'New', 111)
187 self.rvg_issue = fake.MakeTestIssue(
188 789, 2, 'summary two', 'New', 111, labels=['Restrict-View-Google'])
189 self.more_restricted_issue = fake.MakeTestIssue(
190 789, 3, 'summary three', 'New', 111, labels=['Restrict-View-Core'])
191 self.both_restricted_issue = fake.MakeTestIssue(
192 789, 4, 'summary four', 'New', 111,
193 labels=['Restrict-View-Google', 'Restrict-View-Core'])
194 self.addr_perm = notify_reasons.AddrPerm(
195 False, 'user@example.com', self.user, notify_reasons.REPLY_MAY_COMMENT,
196 self.user_prefs)
197
198 def testGetNotifyRestrictedIssues_NoPrefsPassed(self):
199 """AlsoNotify and all-issues addresses have no UserPrefs. None is used."""
200 actual = notify_helpers._GetNotifyRestrictedIssues(
201 None, 'user@example.com', self.user)
202 self.assertEqual('notify with link only', actual)
203
204 self.user.last_visit_timestamp = 123456789
205 actual = notify_helpers._GetNotifyRestrictedIssues(
206 None, 'user@example.com', self.user)
207 self.assertEqual('notify with details', actual)
208
209 def testGetNotifyRestrictedIssues_PrefIsSet(self):
210 """When the notify_restricted_issues pref is set, we use it."""
211 self.user_prefs.prefs.extend([
212 user_pb2.UserPrefValue(name='x', value='y'),
213 user_pb2.UserPrefValue(name='notify_restricted_issues', value='z'),
214 ])
215 actual = notify_helpers._GetNotifyRestrictedIssues(
216 self.user_prefs, 'user@example.com', self.user)
217 self.assertEqual('z', actual)
218
219 def testGetNotifyRestrictedIssues_UserHasVisited(self):
220 """If user has ever visited, we know that they are not a mailing list."""
221 self.user.last_visit_timestamp = 123456789
222 actual = notify_helpers._GetNotifyRestrictedIssues(
223 self.user_prefs, 'user@example.com', self.user)
224 self.assertEqual('notify with details', actual)
225
226 def testGetNotifyRestrictedIssues_GooglerNeverVisited(self):
227 """It could be a noogler or google mailing list."""
228 actual = notify_helpers._GetNotifyRestrictedIssues(
229 self.user_prefs, 'user@google.com', self.user)
230 self.assertEqual('notify with details: Google', actual)
231
232 def testGetNotifyRestrictedIssues_NonGooglerNeverVisited(self):
233 """It could be a new non-noogler or public mailing list."""
234 actual = notify_helpers._GetNotifyRestrictedIssues(
235 self.user_prefs, 'user@example.com', self.user)
236 self.assertEqual('notify with link only', actual)
237
238 # If email does not match any known user, user object will be None.
239 actual = notify_helpers._GetNotifyRestrictedIssues(
240 self.user_prefs, 'user@example.com', None)
241 self.assertEqual('notify with link only', actual)
242
243 def testShouldUseLinkOnly_UnrestrictedIssue(self):
244 """Issue is not restricted, so go ahead and send comment details."""
245 self.assertFalse(notify_helpers.ShouldUseLinkOnly(
246 self.addr_perm, self.issue))
247
248 def testShouldUseLinkOnly_AlwaysDetailed(self):
249 """Issue is not restricted, so go ahead and send comment details."""
250 self.assertFalse(
251 notify_helpers.ShouldUseLinkOnly(self.addr_perm, self.issue, True))
252
253 @mock.patch('features.notify_helpers._GetNotifyRestrictedIssues')
254 def testShouldUseLinkOnly_NotifyWithDetails(self, fake_gnri):
255 """Issue is restricted, and user is allowed to get full comment details."""
256 fake_gnri.return_value = notify_helpers.NOTIFY_WITH_DETAILS
257 self.assertFalse(notify_helpers.ShouldUseLinkOnly(
258 self.addr_perm, self.rvg_issue))
259 self.assertFalse(notify_helpers.ShouldUseLinkOnly(
260 self.addr_perm, self.more_restricted_issue))
261 self.assertFalse(notify_helpers.ShouldUseLinkOnly(
262 self.addr_perm, self.both_restricted_issue))
263
264
265class MakeEmailWorkItemTest(unittest.TestCase):
266
267 def setUp(self):
268 self.project = fake.Project(project_name='proj1')
269 self.project.process_inbound_email = True
270 self.project2 = fake.Project(project_name='proj2')
271 self.project2.issue_notify_always_detailed = True
272 self.commenter_view = framework_views.StuffUserView(
273 111, 'test@example.com', True)
274 self.expected_html_footer = (
275 'You received this message because:<br/> 1. reason<br/><br/>You may '
276 'adjust your notification preferences at:<br/><a href="https://'
277 'example.com/hosting/settings">https://example.com/hosting/settings'
278 '</a>')
279 self.services = service_manager.Services(
280 user=fake.UserService())
281 self.member = self.services.user.TestAddUser('member@example.com', 222)
282 self.issue = fake.MakeTestIssue(
283 self.project.project_id, 1234, 'summary', 'New', 111,
284 project_name='proj1')
285 self.detail_url = 'http://test-detail-url.com/id=1234'
286
287 @mock.patch('features.notify_helpers.ShouldUseLinkOnly')
288 def testBodySelection_LinkOnly(self, mock_sulo):
289 """We send a link-only body when ShouldUseLinkOnly() is true."""
290 mock_sulo.return_value = True
291 email_task = notify_helpers._MakeEmailWorkItem(
292 notify_reasons.AddrPerm(
293 True, 'a@a.com', self.member, REPLY_NOT_ALLOWED,
294 user_pb2.UserPrefs()),
295 ['reason'], self.issue,
296 'body link-only', 'body mem', 'body mem', self.project,
297 'example.com', self.commenter_view, self.detail_url)
298 self.assertIn('body link-only', email_task['body'])
299
300 def testBodySelection_Member(self):
301 """We send members the email body that is indented for members."""
302 email_task = notify_helpers._MakeEmailWorkItem(
303 notify_reasons.AddrPerm(
304 True, 'a@a.com', self.member, REPLY_NOT_ALLOWED,
305 user_pb2.UserPrefs()),
306 ['reason'], self.issue,
307 'body link-only', 'body mem', 'body mem', self.project,
308 'example.com', self.commenter_view, self.detail_url)
309 self.assertIn('body mem', email_task['body'])
310
311 def testBodySelection_AlwaysDetailed(self):
312 """Always send full email when project configuration requires it."""
313 email_task = notify_helpers._MakeEmailWorkItem(
314 notify_reasons.AddrPerm(
315 True, 'a@a.com', self.member, REPLY_NOT_ALLOWED,
316 user_pb2.UserPrefs()), ['reason'], self.issue, 'body link-only',
317 'body mem', 'body mem', self.project2, 'example.com',
318 self.commenter_view, self.detail_url)
319 self.assertIn('body mem', email_task['body'])
320
321 def testBodySelection_NonMember(self):
322 """We send non-members the email body that is indented for non-members."""
323 email_task = notify_helpers._MakeEmailWorkItem(
324 notify_reasons.AddrPerm(
325 False, 'a@a.com', self.member, REPLY_NOT_ALLOWED,
326 user_pb2.UserPrefs()),
327 ['reason'], self.issue,
328 'body link-only', 'body non', 'body mem', self.project,
329 'example.com', self.commenter_view, self.detail_url)
330
331 self.assertEqual('a@a.com', email_task['to'])
332 self.assertEqual('Issue 1234 in proj1: summary', email_task['subject'])
333 self.assertIn('body non', email_task['body'])
334 self.assertEqual(
335 emailfmt.FormatFromAddr(self.project, commenter_view=self.commenter_view,
336 can_reply_to=False),
337 email_task['from_addr'])
338 self.assertEqual(emailfmt.NoReplyAddress(), email_task['reply_to'])
339
340 def testHtmlBody(self):
341 """"An html body is sent if a detail_url is specified."""
342 email_task = notify_helpers._MakeEmailWorkItem(
343 notify_reasons.AddrPerm(
344 False, 'a@a.com', self.member, REPLY_NOT_ALLOWED,
345 user_pb2.UserPrefs()),
346 ['reason'], self.issue,
347 'body link-only', 'body non', 'body mem', self.project,
348 'example.com', self.commenter_view, self.detail_url)
349
350 expected_html_body = (
351 notify_helpers.HTML_BODY_WITH_GMAIL_ACTION_TEMPLATE % {
352 'url': self.detail_url,
353 'body': 'body non-- <br/>%s' % self.expected_html_footer})
354 self.assertEqual(expected_html_body, email_task['html_body'])
355
356 def testHtmlBody_WithUnicodeChars(self):
357 """"An html body is sent if a detail_url is specified."""
358 unicode_content = '\xe2\x9d\xa4 â â'
359 email_task = notify_helpers._MakeEmailWorkItem(
360 notify_reasons.AddrPerm(
361 False, 'a@a.com', self.member, REPLY_NOT_ALLOWED,
362 user_pb2.UserPrefs()),
363 ['reason'], self.issue,
364 'body link-only', unicode_content, 'unused body mem',
365 self.project, 'example.com', self.commenter_view, self.detail_url)
366
367 expected_html_body = (
368 notify_helpers.HTML_BODY_WITH_GMAIL_ACTION_TEMPLATE % {
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +0100369 'url':
370 self.detail_url,
371 'body':
372 '%s-- <br/>%s' %
373 (six.ensure_text(unicode_content), self.expected_html_footer)
374 })
Copybara854996b2021-09-07 19:36:02 +0000375 self.assertEqual(expected_html_body, email_task['html_body'])
376
377 def testHtmlBody_WithLinks(self):
378 """"An html body is sent if a detail_url is specified."""
379 email_task = notify_helpers._MakeEmailWorkItem(
380 notify_reasons.AddrPerm(
381 False, 'a@a.com', self.member, REPLY_NOT_ALLOWED,
382 user_pb2.UserPrefs()),
383 ['reason'], self.issue,
384 'body link-only', 'test google.com test', 'unused body mem',
385 self.project, 'example.com', self.commenter_view, self.detail_url)
386
387 expected_html_body = (
388 notify_helpers.HTML_BODY_WITH_GMAIL_ACTION_TEMPLATE % {
389 'url': self.detail_url,
390 'body': (
391 'test <a href="http://google.com">google.com</a> test-- <br/>%s' % (
392 self.expected_html_footer))})
393 self.assertEqual(expected_html_body, email_task['html_body'])
394
395 def testHtmlBody_LinkWithinTags(self):
396 """"An html body is sent with correct <a href>s."""
397 email_task = notify_helpers._MakeEmailWorkItem(
398 notify_reasons.AddrPerm(
399 False, 'a@a.com', self.member, REPLY_NOT_ALLOWED,
400 user_pb2.UserPrefs()),
401 ['reason'], self.issue,
402 'body link-only', 'a <http://google.com> z', 'unused body',
403 self.project, 'example.com', self.commenter_view,
404 self.detail_url)
405
406 expected_html_body = (
407 notify_helpers.HTML_BODY_WITH_GMAIL_ACTION_TEMPLATE % {
408 'url': self.detail_url,
409 'body': (
410 'a &lt;<a href="http://google.com">http://google.com</a>&gt; '
411 'z-- <br/>%s' % self.expected_html_footer)})
412 self.assertEqual(expected_html_body, email_task['html_body'])
413
414 def testHtmlBody_EmailWithinTags(self):
415 """"An html body is sent with correct <a href>s."""
416 email_task = notify_helpers._MakeEmailWorkItem(
417 notify_reasons.AddrPerm(
418 False, 'a@a.com', self.member, REPLY_NOT_ALLOWED,
419 user_pb2.UserPrefs()),
420 ['reason'], self.issue,
421 'body link-only', 'a <tt@chromium.org> <aa@chromium.org> z',
422 'unused body mem', self.project, 'example.com', self.commenter_view,
423 self.detail_url)
424
425 expected_html_body = (
426 notify_helpers.HTML_BODY_WITH_GMAIL_ACTION_TEMPLATE % {
427 'url': self.detail_url,
428 'body': (
429 'a &lt;<a href="mailto:tt@chromium.org">tt@chromium.org</a>&gt;'
430 ' &lt;<a href="mailto:aa@chromium.org">aa@chromium.org</a>&gt; '
431 'z-- <br/>%s' % self.expected_html_footer)})
432 self.assertEqual(expected_html_body, email_task['html_body'])
433
434 def testHtmlBody_WithEscapedHtml(self):
435 """"An html body is sent with html content escaped."""
436 body_with_html_content = (
437 '<a href="http://www.google.com">test</a> \'something\'')
438 email_task = notify_helpers._MakeEmailWorkItem(
439 notify_reasons.AddrPerm(
440 False, 'a@a.com', self.member, REPLY_NOT_ALLOWED,
441 user_pb2.UserPrefs()),
442 ['reason'], self.issue,
443 'body link-only', body_with_html_content, 'unused body mem',
444 self.project, 'example.com', self.commenter_view, self.detail_url)
445
446 escaped_body_with_html_content = (
447 '&lt;a href=&quot;http://www.google.com&quot;&gt;test&lt;/a&gt; '
Adrià Vilanova Martínezf19ea432024-01-23 20:20:52 +0100448 '&#x27;something&#x27;')
Copybara854996b2021-09-07 19:36:02 +0000449 notify_helpers._MakeNotificationFooter(
450 ['reason'], REPLY_NOT_ALLOWED, 'example.com')
451 expected_html_body = (
452 notify_helpers.HTML_BODY_WITH_GMAIL_ACTION_TEMPLATE % {
453 'url': self.detail_url,
454 'body': '%s-- <br/>%s' % (escaped_body_with_html_content,
455 self.expected_html_footer)})
456 self.assertEqual(expected_html_body, email_task['html_body'])
457
458 def doTestAddHTMLTags(self, body, expected):
459 actual = notify_helpers._AddHTMLTags(body)
460 self.assertEqual(expected, actual)
461
462 def testAddHTMLTags_Email(self):
463 """An email address produces <a href="mailto:...">...</a>."""
464 self.doTestAddHTMLTags(
465 'test test@example.com.',
466 ('test <a href="mailto:test@example.com">'
467 'test@example.com</a>.'))
468
469 def testAddHTMLTags_EmailInQuotes(self):
470 """Quoted "test@example.com" produces "<a href="...">...</a>"."""
471 self.doTestAddHTMLTags(
472 'test "test@example.com".',
473 ('test &quot;<a href="mailto:test@example.com">'
474 'test@example.com</a>&quot;.'))
475
476 def testAddHTMLTags_EmailInAngles(self):
477 """Bracketed <test@example.com> produces &lt;<a href="...">...</a>&gt;."""
478 self.doTestAddHTMLTags(
479 'test <test@example.com>.',
480 ('test &lt;<a href="mailto:test@example.com">'
481 'test@example.com</a>&gt;.'))
482
483 def testAddHTMLTags_Website(self):
484 """A website URL produces <a href="http:...">...</a>."""
485 self.doTestAddHTMLTags(
486 'test http://www.example.com.',
487 ('test <a href="http://www.example.com">'
488 'http://www.example.com</a>.'))
489
490 def testAddHTMLTags_WebsiteInQuotes(self):
491 """A link in quotes gets the quotes escaped."""
492 self.doTestAddHTMLTags(
493 'test "http://www.example.com".',
494 ('test &quot;<a href="http://www.example.com">'
495 'http://www.example.com</a>&quot;.'))
496
497 def testAddHTMLTags_WebsiteInAngles(self):
498 """Bracketed <www.example.com> produces &lt;<a href="...">...</a>&gt;."""
499 self.doTestAddHTMLTags(
500 'test <http://www.example.com>.',
501 ('test &lt;<a href="http://www.example.com">'
502 'http://www.example.com</a>&gt;.'))
503
504 def testReplyInvitation(self):
505 """We include a footer about replying that is appropriate for that user."""
506 email_task = notify_helpers._MakeEmailWorkItem(
507 notify_reasons.AddrPerm(
508 True, 'a@a.com', self.member, REPLY_NOT_ALLOWED,
509 user_pb2.UserPrefs()),
510 ['reason'], self.issue,
511 'body link-only', 'body non', 'body mem', self.project,
512 'example.com', self.commenter_view, self.detail_url)
513 self.assertEqual(emailfmt.NoReplyAddress(), email_task['reply_to'])
514 self.assertNotIn('Reply to this email', email_task['body'])
515
516 email_task = notify_helpers._MakeEmailWorkItem(
517 notify_reasons.AddrPerm(
518 True, 'a@a.com', self.member, REPLY_MAY_COMMENT,
519 user_pb2.UserPrefs()),
520 ['reason'], self.issue,
521 'body link-only', 'body non', 'body mem', self.project,
522 'example.com', self.commenter_view, self.detail_url)
523 self.assertEqual(
524 '%s@%s' % (self.project.project_name, emailfmt.MailDomain()),
525 email_task['reply_to'])
526 self.assertIn('Reply to this email to add a comment', email_task['body'])
527 self.assertNotIn('make changes', email_task['body'])
528
529 email_task = notify_helpers._MakeEmailWorkItem(
530 notify_reasons.AddrPerm(
531 True, 'a@a.com', self.member, REPLY_MAY_UPDATE,
532 user_pb2.UserPrefs()),
533 ['reason'], self.issue,
534 'body link-only', 'body non', 'body mem', self.project,
535 'example.com', self.commenter_view, self.detail_url)
536 self.assertEqual(
537 '%s@%s' % (self.project.project_name, emailfmt.MailDomain()),
538 email_task['reply_to'])
539 self.assertIn('Reply to this email to add a comment', email_task['body'])
540 self.assertIn('make updates', email_task['body'])
541
542 def testInboundEmailDisabled(self):
543 """We don't invite replies if they are disabled for this project."""
544 self.project.process_inbound_email = False
545 email_task = notify_helpers._MakeEmailWorkItem(
546 notify_reasons.AddrPerm(
547 True, 'a@a.com', self.member, REPLY_MAY_UPDATE,
548 user_pb2.UserPrefs()),
549 ['reason'], self.issue,
550 'body link-only', 'body non', 'body mem',
551 self.project, 'example.com', self.commenter_view, self.detail_url)
552 self.assertEqual(emailfmt.NoReplyAddress(), email_task['reply_to'])
553
554 def testReasons(self):
555 """The footer lists reasons why that email was sent to that user."""
556 email_task = notify_helpers._MakeEmailWorkItem(
557 notify_reasons.AddrPerm(
558 True, 'a@a.com', self.member, REPLY_MAY_UPDATE,
559 user_pb2.UserPrefs()),
560 ['Funny', 'Caring', 'Near'], self.issue,
561 'body link-only', 'body non', 'body mem',
562 self.project, 'example.com', self.commenter_view, self.detail_url)
563 self.assertIn('because:', email_task['body'])
564 self.assertIn('1. Funny', email_task['body'])
565 self.assertIn('2. Caring', email_task['body'])
566 self.assertIn('3. Near', email_task['body'])
567
568 email_task = notify_helpers._MakeEmailWorkItem(
569 notify_reasons.AddrPerm(
570 True, 'a@a.com', self.member, REPLY_MAY_UPDATE,
571 user_pb2.UserPrefs()),
572 [], self.issue,
573 'body link-only', 'body non', 'body mem',
574 self.project, 'example.com', self.commenter_view, self.detail_url)
575 self.assertNotIn('because', email_task['body'])
576
577
578class MakeNotificationFooterTest(unittest.TestCase):
579
580 def testMakeNotificationFooter_NoReason(self):
581 footer = notify_helpers._MakeNotificationFooter(
582 [], REPLY_NOT_ALLOWED, 'example.com')
583 self.assertEqual('', footer)
584
585 def testMakeNotificationFooter_WithReason(self):
586 footer = notify_helpers._MakeNotificationFooter(
587 ['REASON'], REPLY_NOT_ALLOWED, 'example.com')
588 self.assertIn('REASON', footer)
589 self.assertIn('https://example.com/hosting/settings', footer)
590
591 footer = notify_helpers._MakeNotificationFooter(
592 ['REASON'], REPLY_NOT_ALLOWED, 'example.com')
593 self.assertIn('REASON', footer)
594 self.assertIn('https://example.com/hosting/settings', footer)
595
596 def testMakeNotificationFooter_ManyReasons(self):
597 footer = notify_helpers._MakeNotificationFooter(
598 ['Funny', 'Caring', 'Warmblooded'], REPLY_NOT_ALLOWED,
599 'example.com')
600 self.assertIn('Funny', footer)
601 self.assertIn('Caring', footer)
602 self.assertIn('Warmblooded', footer)
603
604 def testMakeNotificationFooter_WithReplyInstructions(self):
605 footer = notify_helpers._MakeNotificationFooter(
606 ['REASON'], REPLY_NOT_ALLOWED, 'example.com')
607 self.assertNotIn('Reply', footer)
608 self.assertIn('https://example.com/hosting/settings', footer)
609
610 footer = notify_helpers._MakeNotificationFooter(
611 ['REASON'], REPLY_MAY_COMMENT, 'example.com')
612 self.assertIn('add a comment', footer)
613 self.assertNotIn('make updates', footer)
614 self.assertIn('https://example.com/hosting/settings', footer)
615
616 footer = notify_helpers._MakeNotificationFooter(
617 ['REASON'], REPLY_MAY_UPDATE, 'example.com')
618 self.assertIn('add a comment', footer)
619 self.assertIn('make updates', footer)
620 self.assertIn('https://example.com/hosting/settings', footer)