test_pagure_lib_notify_email.py 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. # -*- coding: utf-8 -*-
  2. """
  3. (c) 2016 - Copyright Red Hat Inc
  4. Authors:
  5. Adam Williamson <awilliam@redhat.com>
  6. """
  7. from __future__ import unicode_literals, absolute_import
  8. import unittest
  9. import sys
  10. import os
  11. import mock
  12. import munch
  13. import six
  14. sys.path.insert(
  15. 0, os.path.join(os.path.dirname(os.path.abspath(__file__)), "..")
  16. )
  17. import pagure.lib.query # pylint: disable=wrong-import-position
  18. import pagure.lib.model # pylint: disable=wrong-import-position
  19. import pagure.lib.notify # pylint: disable=wrong-import-position
  20. import tests # pylint: disable=wrong-import-position
  21. class PagureLibNotifyEmailtests(tests.Modeltests):
  22. """ Some tests for the various email construction functions. In
  23. their own class so they can have some shared fixtures.
  24. """
  25. def setUp(self):
  26. """ Override setUp to add more fixtures used for many tests. """
  27. super(PagureLibNotifyEmailtests, self).setUp()
  28. tests.create_projects(self.session)
  29. # we don't want to send any mails while setting up
  30. patcher = mock.patch("pagure.lib.notify.send_email")
  31. patcher.start()
  32. self.user1 = pagure.lib.query.get_user(self.session, "pingou")
  33. self.user2 = pagure.lib.query.get_user(self.session, "foo")
  34. self.project1 = pagure.lib.query._get_project(self.session, "test")
  35. self.project2 = pagure.lib.query._get_project(self.session, "test2")
  36. self.project3 = pagure.lib.query._get_project(
  37. self.session, "test3", namespace="somenamespace"
  38. )
  39. # Create a forked repo, should be project #4
  40. # Not using fork_project as it tries to do a git clone
  41. item = pagure.lib.model.Project(
  42. user_id=2, # foo
  43. name="test",
  44. description="test project #1",
  45. is_fork=True,
  46. parent_id=1,
  47. hook_token="aaabbbyyy",
  48. )
  49. self.session.add(item)
  50. self.session.commit()
  51. self.forkedproject = pagure.lib.query._get_project(
  52. self.session, "test", user="foo"
  53. )
  54. # Report an issue on project #1
  55. self.issue1 = pagure.lib.query.new_issue(
  56. session=self.session,
  57. repo=self.project1,
  58. title="issue",
  59. content="a bug report",
  60. user="pingou",
  61. )
  62. # Add a comment on the issue
  63. pagure.lib.query.add_issue_comment(
  64. self.session, self.issue1, comment="Test comment", user="pingou"
  65. )
  66. self.comment1 = pagure.lib.query.get_issue_comment(
  67. self.session, self.issue1.uid, 1
  68. )
  69. # Report an issue on project #3 (namespaced)
  70. self.issue2 = pagure.lib.query.new_issue(
  71. session=self.session,
  72. repo=self.project3,
  73. title="namespaced project issue",
  74. content="a bug report on a namespaced project",
  75. user="pingou",
  76. )
  77. # report an issue on foo's fork of project #1
  78. self.issue3 = pagure.lib.query.new_issue(
  79. session=self.session,
  80. repo=self.forkedproject,
  81. title="forked project issue",
  82. content="a bug report on a forked project",
  83. user="pingou",
  84. )
  85. patcher.stop()
  86. @mock.patch("pagure.lib.notify.send_email")
  87. def test_notify_new_comment(self, fakemail):
  88. """Simple test for notification about new comment."""
  89. exptext = """
  90. pingou added a new comment to an issue you are following:
  91. ``
  92. Test comment
  93. ``
  94. To reply, visit the link below
  95. http://localhost.localdomain/test/issue/1
  96. """
  97. pagure.lib.notify.notify_new_comment(self.comment1)
  98. (_, args, kwargs) = fakemail.mock_calls[0]
  99. # Mail text should be as expected.
  100. self.assertEqual(args[0], exptext)
  101. self.assertTrue(isinstance(args[0], six.text_type))
  102. # Mail subject should be as expected.
  103. self.assertEqual(args[1], "Issue #1: issue")
  104. # Mail should be sent to user #1.
  105. self.assertEqual(args[2], self.user1.default_email)
  106. # Mail ID should be comment #1's mail ID...
  107. self.assertEqual(kwargs["mail_id"], self.comment1.mail_id)
  108. # In reply to issue #1's mail ID.
  109. self.assertEqual(kwargs["in_reply_to"], self.issue1.mail_id)
  110. # Project name should be...project (full) name.
  111. self.assertEqual(kwargs["project_name"], self.project1.fullname)
  112. # Mail should be from user1 (who wrote the comment).
  113. self.assertEqual(kwargs["user_from"], self.user1.fullname)
  114. @mock.patch("pagure.lib.notify.send_email")
  115. def test_user_notified_new_comment(self, fakemail):
  116. """Check that users that are @mentionned are notified."""
  117. self.comment1.comment = "Hey @foo. Let's do it!"
  118. g = munch.Munch()
  119. g.session = self.session
  120. with mock.patch("flask.g", g):
  121. pagure.lib.notify.notify_new_comment(self.comment1)
  122. (_, args, kwargs) = fakemail.mock_calls[0]
  123. # Mail should be sent to both users
  124. self.assertIn(
  125. args[2],
  126. ["bar@pingou.com,foo@bar.com", "foo@bar.com,bar@pingou.com"],
  127. )
  128. # Mail ID should be comment #1's mail ID...
  129. self.assertEqual(kwargs["mail_id"], self.comment1.mail_id)
  130. # In reply to issue #1's mail ID.
  131. self.assertEqual(kwargs["in_reply_to"], self.issue1.mail_id)
  132. # Project name should be...project (full) name.
  133. self.assertEqual(kwargs["project_name"], self.project1.fullname)
  134. # Mail should be from user1 (who wrote the comment).
  135. self.assertEqual(kwargs["user_from"], self.user1.fullname)
  136. @mock.patch("pagure.lib.notify.send_email")
  137. def test_user_notified_new_comment_start_row(self, fakemail):
  138. """Check that users that are @mentionned are notified."""
  139. self.comment1.comment = "@foo, okidoki"
  140. g = munch.Munch()
  141. g.session = self.session
  142. with mock.patch("flask.g", g):
  143. pagure.lib.notify.notify_new_comment(self.comment1)
  144. (_, args, kwargs) = fakemail.mock_calls[0]
  145. # Mail should be sent to both users
  146. self.assertIn(
  147. args[2],
  148. ["bar@pingou.com,foo@bar.com", "foo@bar.com,bar@pingou.com"],
  149. )
  150. # Mail ID should be comment #1's mail ID...
  151. self.assertEqual(kwargs["mail_id"], self.comment1.mail_id)
  152. # In reply to issue #1's mail ID.
  153. self.assertEqual(kwargs["in_reply_to"], self.issue1.mail_id)
  154. # Project name should be...project (full) name.
  155. self.assertEqual(kwargs["project_name"], self.project1.fullname)
  156. # Mail should be from user1 (who wrote the comment).
  157. self.assertEqual(kwargs["user_from"], self.user1.fullname)
  158. @mock.patch("pagure.lib.notify.send_email")
  159. def test_user_notified_new_comment_with_email(self, fakemail):
  160. """Ensures that @mention doesn't over-reach."""
  161. self.comment1.comment = "So apparently bar@foo.com exists"
  162. g = munch.Munch()
  163. g.fas_user = tests.FakeUser(username="pingou")
  164. g.authenticated = True
  165. g.session = self.session
  166. with mock.patch("flask.g", g):
  167. pagure.lib.notify.notify_new_comment(self.comment1)
  168. (_, args, kwargs) = fakemail.mock_calls[0]
  169. # Mail should be sent to both users
  170. self.assertEqual(args[2], "bar@pingou.com")
  171. # Mail ID should be comment #1's mail ID...
  172. self.assertEqual(kwargs["mail_id"], self.comment1.mail_id)
  173. # In reply to issue #1's mail ID.
  174. self.assertEqual(kwargs["in_reply_to"], self.issue1.mail_id)
  175. # Project name should be...project (full) name.
  176. self.assertEqual(kwargs["project_name"], self.project1.fullname)
  177. # Mail should be from user1 (who wrote the comment).
  178. self.assertEqual(kwargs["user_from"], self.user1.fullname)
  179. @mock.patch("pagure.lib.notify.send_email")
  180. def test_user_notified_new_comment_with_email_with_number(self, fakemail):
  181. """Ensures that @mention doesn't over-reach."""
  182. self.comment1.comment = "So apparently bar123@foo.com exists"
  183. g = munch.Munch()
  184. g.fas_user = tests.FakeUser(username="pingou")
  185. g.authenticated = True
  186. g.session = self.session
  187. with mock.patch("flask.g", g):
  188. pagure.lib.notify.notify_new_comment(self.comment1)
  189. (_, args, kwargs) = fakemail.mock_calls[0]
  190. # Mail should be sent to both users
  191. self.assertEqual(args[2], "bar@pingou.com")
  192. # Mail ID should be comment #1's mail ID...
  193. self.assertEqual(kwargs["mail_id"], self.comment1.mail_id)
  194. # In reply to issue #1's mail ID.
  195. self.assertEqual(kwargs["in_reply_to"], self.issue1.mail_id)
  196. # Project name should be...project (full) name.
  197. self.assertEqual(kwargs["project_name"], self.project1.fullname)
  198. # Mail should be from user1 (who wrote the comment).
  199. self.assertEqual(kwargs["user_from"], self.user1.fullname)
  200. @mock.patch("pagure.lib.notify.send_email")
  201. def test_notify_new_issue_namespaced(
  202. self, fakemail
  203. ): # pylint: disable=invalid-name
  204. """Test for notifying of a new issue, namespaced project."""
  205. exptext = """
  206. pingou reported a new issue against the project: `test3` that you are following:
  207. ``
  208. a bug report on a namespaced project
  209. ``
  210. To reply, visit the link below
  211. http://localhost.localdomain/somenamespace/test3/issue/1
  212. """
  213. pagure.lib.notify.notify_new_issue(self.issue2)
  214. (_, args, kwargs) = fakemail.mock_calls[0]
  215. # Mail text should be as expected.
  216. self.assertEqual(args[0], exptext)
  217. self.assertTrue(isinstance(args[0], six.text_type))
  218. # Mail subject should be as expected.
  219. self.assertEqual(args[1], "Issue #1: namespaced project issue")
  220. # Mail should be sent to user #1.
  221. self.assertEqual(args[2], self.user1.default_email)
  222. # Mail ID should be issue's mail ID.
  223. self.assertEqual(kwargs["mail_id"], self.issue2.mail_id)
  224. # Project name should be...project (full) name.
  225. self.assertEqual(kwargs["project_name"], self.project3.fullname)
  226. # Mail should be from user1 (who submitted the issue).
  227. self.assertEqual(kwargs["user_from"], self.user1.fullname)
  228. @mock.patch("pagure.lib.notify.send_email")
  229. def test_notify_assigned_issue_forked(
  230. self, fakemail
  231. ): # pylint: disable=invalid-name
  232. """Test for notifying re-assignment of issue on forked project.
  233. 'foo' reassigns issue on his fork of 'test' to 'pingou'.
  234. """
  235. exptext = """
  236. The issue: `forked project issue` of project: `test` has been assigned to `pingou` by foo.
  237. http://localhost.localdomain/fork/foo/test/issue/1
  238. """
  239. pagure.lib.notify.notify_assigned_issue(
  240. self.issue3, self.user1, self.user2
  241. )
  242. (_, args, kwargs) = fakemail.mock_calls[0]
  243. # Mail text should be as expected.
  244. self.assertEqual(args[0], exptext)
  245. self.assertTrue(isinstance(args[0], six.text_type))
  246. # Mail subject should be as expected.
  247. self.assertEqual(args[1], "Issue #1: forked project issue")
  248. # Mail should be sent to user #1.
  249. # NOTE: Not sent to user #2...
  250. self.assertEqual(args[2], self.user1.default_email)
  251. # Mail ID should contain issue's mail ID and '/assigned/'
  252. self.assertIn(
  253. "{0}/assigned/".format(self.issue3.mail_id), kwargs["mail_id"]
  254. )
  255. # Project name should be...project (full) name.
  256. self.assertEqual(kwargs["project_name"], self.forkedproject.fullname)
  257. # Mail should be from user1 (who submitted the issue).
  258. self.assertEqual(kwargs["user_from"], self.user2.fullname)
  259. @mock.patch("pagure.lib.notify.send_email")
  260. # for non-ASCII testing, we mock these return values
  261. @mock.patch("pagure.lib.git.get_author", return_value="Cecil Cõmmîttër")
  262. @mock.patch(
  263. "pagure.lib.git.get_commit_subject", return_value="We love Motörhead"
  264. )
  265. def test_notify_new_commits(
  266. self, _, __, fakemail
  267. ): # pylint: disable=invalid-name
  268. """Test for notification on new commits, especially when
  269. non-ASCII text is involved.
  270. """
  271. exptext = """
  272. The following commits were pushed to the repo test on branch
  273. master, which you are following:
  274. abcdefg Cecil Cõmmîttër We love Motörhead
  275. To view more about the commits, visit:
  276. http://localhost.localdomain/test/commits/master
  277. """
  278. # first arg (abspath) doesn't matter and we can use a commit
  279. # ID that doesn't actually exist, as we are mocking
  280. # the get_author and get_commit_subject calls anyway
  281. pagure.lib.notify.notify_new_commits(
  282. "/", self.project1, "master", ["abcdefg"]
  283. )
  284. (_, args, kwargs) = fakemail.mock_calls[0]
  285. # Mail text should be as expected.
  286. self.assertEqual(args[0], exptext)
  287. self.assertTrue(isinstance(args[0], six.text_type))
  288. # Mail subject should be as expected.
  289. self.assertEqual(args[1], 'New Commits To "test" (master)')
  290. # Mail doesn't actually get sent to anyone by default
  291. self.assertEqual(args[2], "")
  292. # Project name should be...project (full) name.
  293. self.assertEqual(kwargs["project_name"], self.project1.fullname)
  294. # Add more tests to verify that correct mails are sent to correct people here
  295. if __name__ == "__main__":
  296. unittest.main(verbosity=2)