test_ticket_rules.py 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151
  1. from unittest import mock
  2. from django.urls import reverse
  3. from rest_framework.test import APITestCase as BaseAPITestCase
  4. from fixtures.integrations.jira.mock import MockJira
  5. from sentry.eventstore.models import Event
  6. from sentry.integrations.jira import JiraCreateTicketAction
  7. from sentry.models.integrations.external_issue import ExternalIssue
  8. from sentry.models.integrations.integration import Integration
  9. from sentry.models.rule import Rule
  10. from sentry.testutils.cases import RuleTestCase
  11. from sentry.testutils.skips import requires_snuba
  12. from sentry.types.rules import RuleFuture
  13. pytestmark = [requires_snuba]
  14. class JiraTicketRulesTestCase(RuleTestCase, BaseAPITestCase):
  15. rule_cls = JiraCreateTicketAction
  16. mock_jira = None
  17. def get_client(self):
  18. if not self.mock_jira:
  19. self.mock_jira = MockJira()
  20. return self.mock_jira
  21. def setUp(self):
  22. super().setUp()
  23. self.project_name = "Jira Cloud"
  24. self.integration = Integration.objects.create(
  25. provider="jira",
  26. name=self.project_name,
  27. metadata={
  28. "oauth_client_id": "oauth-client-id",
  29. "shared_secret": "a-super-secret-key-from-atlassian",
  30. "base_url": "https://example.atlassian.net",
  31. "domain_name": "example.atlassian.net",
  32. },
  33. )
  34. self.integration.add_organization(self.organization, self.user)
  35. self.installation = self.integration.get_installation(self.organization.id)
  36. self.login_as(user=self.user)
  37. def trigger(self, event, rule_object):
  38. action = rule_object.data.get("actions", ())[0]
  39. action_inst = self.get_rule(data=action, rule=rule_object)
  40. results = list(action_inst.after(event=event, state=self.get_state()))
  41. assert len(results) == 1
  42. rule_future = RuleFuture(rule=rule_object, kwargs=results[0].kwargs)
  43. return results[0].callback(event, futures=[rule_future])
  44. def get_key(self, event: Event):
  45. return ExternalIssue.objects.get_linked_issues(event, self.integration).values_list(
  46. "key", flat=True
  47. )[0]
  48. def test_ticket_rules(self):
  49. with mock.patch(
  50. "sentry.integrations.jira.integration.JiraIntegration.get_client", self.get_client
  51. ):
  52. # Create a new Rule
  53. response = self.client.post(
  54. reverse(
  55. "sentry-api-0-project-rules",
  56. kwargs={
  57. "organization_slug": self.organization.slug,
  58. "project_slug": self.project.slug,
  59. },
  60. ),
  61. format="json",
  62. data={
  63. "name": "hello world",
  64. "owner": self.user.id,
  65. "environment": None,
  66. "actionMatch": "any",
  67. "frequency": 5,
  68. "actions": [
  69. {
  70. "id": "sentry.integrations.jira.notify_action.JiraCreateTicketAction",
  71. "integration": self.integration.id,
  72. "dynamic_form_fields": [{"name": "project"}],
  73. "issuetype": "1",
  74. "name": "Create a Jira ticket in the Jira Cloud account",
  75. "project": "10000",
  76. }
  77. ],
  78. "conditions": [],
  79. },
  80. )
  81. assert response.status_code == 200
  82. # Get the rule from DB
  83. rule_object = Rule.objects.get(id=response.data["id"])
  84. event = self.get_event()
  85. # Trigger its `after`
  86. self.trigger(event, rule_object)
  87. # assert ticket created in DB
  88. key = self.get_key(event)
  89. external_issue_count = len(ExternalIssue.objects.filter(key=key))
  90. assert external_issue_count == 1
  91. # assert ticket created on jira
  92. data = self.installation.get_issue(key)
  93. assert event.message in data["description"]
  94. # Trigger its `after` _again_
  95. self.trigger(event, rule_object)
  96. # assert new ticket NOT created in DB
  97. assert ExternalIssue.objects.count() == external_issue_count
  98. def test_fails_validation(self):
  99. """
  100. Test that the absence of dynamic_form_fields in the action fails validation
  101. """
  102. with mock.patch(
  103. "sentry.integrations.jira.integration.JiraIntegration.get_client", self.get_client
  104. ):
  105. # Create a new Rule
  106. response = self.client.post(
  107. reverse(
  108. "sentry-api-0-project-rules",
  109. kwargs={
  110. "organization_slug": self.organization.slug,
  111. "project_slug": self.project.slug,
  112. },
  113. ),
  114. format="json",
  115. data={
  116. "name": "hello world",
  117. "environment": None,
  118. "actionMatch": "any",
  119. "frequency": 5,
  120. "actions": [
  121. {
  122. "id": "sentry.integrations.jira.notify_action.JiraCreateTicketAction",
  123. "integration": self.integration.id,
  124. "issuetype": "1",
  125. "name": "Create a Jira ticket in the Jira Cloud account",
  126. "project": "10000",
  127. }
  128. ],
  129. "conditions": [],
  130. },
  131. )
  132. assert response.status_code == 400