test_plugin.py 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. from datetime import timedelta
  2. from unittest.mock import Mock, patch
  3. import pytest
  4. from django.utils import timezone
  5. from sentry.exceptions import HookValidationError
  6. from sentry.models import (
  7. Commit,
  8. Deploy,
  9. Environment,
  10. ProjectOption,
  11. Release,
  12. ReleaseCommit,
  13. ReleaseHeadCommit,
  14. Repository,
  15. User,
  16. )
  17. from sentry.testutils import TestCase
  18. from sentry.utils import json
  19. from sentry_plugins.heroku.plugin import HerokuReleaseHook
  20. class SetRefsTest(TestCase):
  21. """
  22. tests that when finish_release is called on a release hook,
  23. we try to get the previous commits based on the version ref
  24. and that we create `ReleaseHeadCommit`s for the version
  25. """
  26. @patch("sentry.tasks.commits.fetch_commits")
  27. def test_minimal(self, mock_fetch_commits):
  28. project = self.create_project()
  29. version = "bbee5b51f84611e4b14834363b8514c2"
  30. data_list = [
  31. {
  32. "id": "c7155651831549cf8a5e47889fce17eb",
  33. "message": "foo",
  34. "author_email": "jane@example.com",
  35. },
  36. {
  37. "id": "62de626b7c7cfb8e77efb4273b1a3df4123e6216",
  38. "message": "hello",
  39. "author_name": "Jess",
  40. },
  41. {
  42. "id": "58de626b7c7cfb8e77efb4273b1a3df4123e6345",
  43. "message": "bar",
  44. "author_name": "Joe^^",
  45. },
  46. {
  47. "id": "bbee5b51f84611e4b14834363b8514c2",
  48. "message": "blah",
  49. "author_email": "katie@example.com",
  50. },
  51. ]
  52. user = User.objects.create(email="stebe@sentry.io")
  53. repo = Repository.objects.create(
  54. organization_id=project.organization_id, name=project.name, provider="dummy"
  55. )
  56. ProjectOption.objects.set_value(key="heroku:repository", project=project, value=repo.name)
  57. for data in data_list:
  58. Commit.objects.create(
  59. key=data["id"], organization_id=self.project.organization_id, repository_id=repo.id
  60. )
  61. old_release = Release.objects.create(
  62. version="a" * 40,
  63. organization_id=project.organization_id,
  64. date_added=timezone.now() - timedelta(minutes=30),
  65. )
  66. old_release.add_project(project)
  67. ReleaseCommit.objects.create(
  68. organization_id=project.organization_id,
  69. project_id=project.id,
  70. release=old_release,
  71. commit=Commit.objects.get(key="c7155651831549cf8a5e47889fce17eb"),
  72. order=0,
  73. )
  74. ReleaseHeadCommit.objects.create(
  75. organization_id=project.organization_id,
  76. repository_id=repo.id,
  77. release=old_release,
  78. commit=Commit.objects.get(key="c7155651831549cf8a5e47889fce17eb"),
  79. )
  80. release_heads = ReleaseHeadCommit.objects.filter(
  81. organization_id=project.organization_id,
  82. repository_id=repo.id,
  83. commit=Commit.objects.get(key="bbee5b51f84611e4b14834363b8514c2"),
  84. )
  85. assert len(release_heads) == 0
  86. hook = HerokuReleaseHook(project)
  87. hook.finish_release(version=version, owner_id=user.id)
  88. release = Release.objects.get(projects=project, version=version)
  89. new_release_heads = ReleaseHeadCommit.objects.filter(
  90. organization_id=project.organization_id,
  91. repository_id=repo.id,
  92. release=release,
  93. commit=Commit.objects.get(key="bbee5b51f84611e4b14834363b8514c2"),
  94. )
  95. assert len(new_release_heads) == 1
  96. assert release.version == "bbee5b51f84611e4b14834363b8514c2"
  97. deploy = Deploy.objects.filter(
  98. organization_id=project.organization_id,
  99. release=release,
  100. environment_id=Environment.objects.get(
  101. organization_id=project.organization_id, name="production"
  102. ).id,
  103. )
  104. assert len(deploy) == 1
  105. mock_fetch_commits.apply_async.assert_called_with(
  106. kwargs={
  107. "release_id": release.id,
  108. "user_id": user.id,
  109. "refs": [{"commit": "bbee5b51f84611e4b14834363b8514c2", "repository": repo.name}],
  110. "prev_release_id": old_release.id,
  111. }
  112. )
  113. class HookHandleTest(TestCase):
  114. def test_user_success(self):
  115. user = self.create_user()
  116. organization = self.create_organization(owner=user)
  117. project = self.create_project(organization=organization)
  118. hook = HerokuReleaseHook(project)
  119. hook.is_valid_signature = Mock()
  120. hook.set_refs = Mock()
  121. req = Mock()
  122. body = {
  123. "data": {
  124. "user": {"email": user.email},
  125. "slug": {"commit": "abcd123"},
  126. "app": {"name": "example"},
  127. },
  128. "action": "update",
  129. }
  130. req.body = bytes(json.dumps(body), "utf-8")
  131. hook.handle(req)
  132. assert Release.objects.filter(version=body["data"]["slug"]["commit"]).exists()
  133. assert hook.set_refs.call_count == 1
  134. def test_only_run_on_update(self):
  135. user = self.create_user()
  136. organization = self.create_organization(owner=user)
  137. project = self.create_project(organization=organization)
  138. hook = HerokuReleaseHook(project)
  139. hook.is_valid_signature = Mock()
  140. hook.set_refs = Mock()
  141. req = Mock()
  142. body = {
  143. "data": {
  144. "user": {"email": user.email},
  145. "slug": {"commit": "abcd123"},
  146. "app": {"name": "example"},
  147. },
  148. "action": "create",
  149. }
  150. req.body = bytes(json.dumps(body), "utf-8")
  151. hook.handle(req)
  152. assert not Release.objects.filter(version=body["data"]["slug"]["commit"]).exists()
  153. assert hook.set_refs.call_count == 0
  154. def test_actor_email_success(self):
  155. user = self.create_user()
  156. organization = self.create_organization(owner=user)
  157. project = self.create_project(organization=organization)
  158. hook = HerokuReleaseHook(project)
  159. hook.is_valid_signature = Mock()
  160. hook.set_refs = Mock()
  161. req = Mock()
  162. body = {
  163. "data": {
  164. "actor": {"email": user.email},
  165. "slug": {"commit": "abcd123"},
  166. "app": {"name": "example"},
  167. },
  168. "action": "update",
  169. }
  170. req.body = bytes(json.dumps(body), "utf-8")
  171. hook.handle(req)
  172. assert Release.objects.filter(version=body["data"]["slug"]["commit"]).exists()
  173. assert hook.set_refs.call_count == 1
  174. def test_email_mismatch(self):
  175. user = self.create_user()
  176. organization = self.create_organization(owner=user)
  177. project = self.create_project(organization=organization)
  178. hook = HerokuReleaseHook(project)
  179. hook.is_valid_signature = Mock()
  180. req = Mock()
  181. body = {
  182. "data": {
  183. "user": {"email": "wrong@example.com"},
  184. "slug": {"commit": "v999"},
  185. "app": {"name": "example"},
  186. },
  187. "action": "update",
  188. }
  189. req.body = bytes(json.dumps(body), "utf-8")
  190. hook.handle(req)
  191. assert Release.objects.filter(version=body["data"]["slug"]["commit"]).exists()
  192. def test_bad_version(self):
  193. project = self.create_project()
  194. user = self.create_user()
  195. hook = HerokuReleaseHook(project)
  196. hook.is_valid_signature = Mock()
  197. req = Mock()
  198. body = {
  199. "data": {
  200. "actor": {"email": user.email},
  201. "slug": {"commit": ""},
  202. "app": {"name": "example"},
  203. },
  204. "action": "update",
  205. }
  206. req.body = bytes(json.dumps(body), "utf-8")
  207. with pytest.raises(HookValidationError):
  208. hook.handle(req)