Files
2024-02-15 17:01:50 +00:00

299 lines
13 KiB
Python

from __future__ import annotations
from functools import cached_property
from typing import Any
import responses
from django.contrib.auth.models import AnonymousUser
from django.test import RequestFactory
from django.urls import reverse
from sentry.testutils.cases import TestCase
from sentry.utils import json
from sentry_plugins.jira.plugin import JiraPlugin
create_meta_response = {
"expand": "projects",
"projects": [
{
"expand": "issuetypes",
"self": "https://getsentry.atlassian.net/rest/api/2/project/10000",
"id": "10000",
"key": "SEN",
"name": "Sentry",
"avatarUrls": {
"48x48": "https://getsentry.atlassian.net/secure/projectavatar?avatarId=10324",
"24x24": "https://getsentry.atlassian.net/secure/projectavatar?size=small&avatarId=10324",
"16x16": "https://getsentry.atlassian.net/secure/projectavatar?size=xsmall&avatarId=10324",
"32x32": "https://getsentry.atlassian.net/secure/projectavatar?size=medium&avatarId=10324",
},
"issuetypes": [
{
"self": "https://getsentry.atlassian.net/rest/api/2/issuetype/10002",
"id": "10002",
"description": "A task that needs to be done.",
"iconUrl": "https://getsentry.atlassian.net/secure/viewavatar?size=xsmall&avatarId=10318&avatarType=issuetype",
"name": "Task",
"subtask": False,
"expand": "fields",
"fields": {
"summary": {
"required": True,
"schema": {"type": "string", "system": "summary"},
"name": "Summary",
"hasDefaultValue": False,
"operations": ["set"],
},
"issuetype": {
"required": True,
"schema": {"type": "issuetype", "system": "issuetype"},
"name": "Issue Type",
"hasDefaultValue": False,
"operations": [],
"allowedValues": [
{
"self": "https://getsentry.atlassian.net/rest/api/2/issuetype/10002",
"id": "10002",
"description": "A task that needs to be done.",
"iconUrl": "https://getsentry.atlassian.net/secure/viewavatar?size=xsmall&avatarId=10318&avatarType=issuetype",
"name": "Task",
"subtask": False,
"avatarId": 10318,
}
],
},
"components": {
"required": False,
"schema": {
"type": "array",
"items": "component",
"system": "components",
},
"name": "Component/s",
"hasDefaultValue": False,
"operations": ["add", "set", "remove"],
"allowedValues": [],
},
"description": {
"required": False,
"schema": {"type": "string", "system": "description"},
"name": "Description",
"hasDefaultValue": False,
"operations": ["set"],
},
"project": {
"required": True,
"schema": {"type": "project", "system": "project"},
"name": "Project",
"hasDefaultValue": False,
"operations": ["set"],
"allowedValues": [
{
"self": "https://getsentry.atlassian.net/rest/api/2/project/10000",
"id": "10000",
"key": "SEN",
"name": "Sentry",
"avatarUrls": {
"48x48": "https://getsentry.atlassian.net/secure/projectavatar?avatarId=10324",
"24x24": "https://getsentry.atlassian.net/secure/projectavatar?size=small&avatarId=10324",
"16x16": "https://getsentry.atlassian.net/secure/projectavatar?size=xsmall&avatarId=10324",
"32x32": "https://getsentry.atlassian.net/secure/projectavatar?size=medium&avatarId=10324",
},
}
],
},
"reporter": {
"required": True,
"schema": {"type": "user", "system": "reporter"},
"name": "Reporter",
"autoCompleteUrl": "https://getsentry.atlassian.net/rest/api/latest/user/search?username=",
"hasDefaultValue": False,
"operations": ["set"],
},
"fixVersions": {
"required": False,
"schema": {
"type": "array",
"items": "version",
"system": "fixVersions",
},
"name": "Fix Version/s",
"hasDefaultValue": False,
"operations": ["set", "add", "remove"],
"allowedValues": [],
},
"priority": {
"required": False,
"schema": {"type": "priority", "system": "priority"},
"name": "Priority",
"hasDefaultValue": True,
"operations": ["set"],
"allowedValues": [
{
"self": "https://getsentry.atlassian.net/rest/api/2/priority/1",
"iconUrl": "https://getsentry.atlassian.net/images/icons/priorities/highest.svg",
"name": "Highest",
"id": "1",
}
],
},
"customfield_10003": {
"required": False,
"schema": {
"type": "array",
"items": "string",
"custom": "com.pyxis.greenhopper.jira:gh-sprint",
"customId": 10003,
},
"name": "Sprint",
"hasDefaultValue": False,
"operations": ["set"],
},
"labels": {
"required": False,
"schema": {"type": "array", "items": "string", "system": "labels"},
"name": "Labels",
"autoCompleteUrl": "https://getsentry.atlassian.net/rest/api/1.0/labels/suggest?query=",
"hasDefaultValue": False,
"operations": ["add", "set", "remove"],
},
"attachment": {
"required": False,
"schema": {
"type": "array",
"items": "attachment",
"system": "attachment",
},
"name": "Attachment",
"hasDefaultValue": False,
"operations": [],
},
"assignee": {
"required": False,
"schema": {"type": "user", "system": "assignee"},
"name": "Assignee",
"autoCompleteUrl": "https://getsentry.atlassian.net/rest/api/latest/user/assignable/search?issueKey=null&username=",
"hasDefaultValue": False,
"operations": ["set"],
},
},
}
],
}
],
}
issue_response: dict[str, Any] = {
"key": "SEN-19",
"id": "10708",
"fields": {"summary": "TypeError: 'set' object has no attribute '__getitem__'"},
}
class JiraPluginTest(TestCase):
@cached_property
def plugin(self):
return JiraPlugin()
@cached_property
def request(self):
return RequestFactory()
def test_conf_key(self):
assert self.plugin.conf_key == "jira"
def test_get_issue_label(self):
group = self.create_group(message="Hello world", culprit="foo.bar")
assert self.plugin.get_issue_label(group, "SEN-1") == "SEN-1"
def test_get_issue_url(self):
self.plugin.set_option("instance_url", "https://getsentry.atlassian.net", self.project)
group = self.create_group(message="Hello world", culprit="foo.bar")
assert (
self.plugin.get_issue_url(group, "SEN-1")
== "https://getsentry.atlassian.net/browse/SEN-1"
)
def test_is_configured(self):
assert self.plugin.is_configured(None, self.project) is False
self.plugin.set_option("default_project", "SEN", self.project)
assert self.plugin.is_configured(None, self.project) is True
@responses.activate
def test_create_issue(self):
responses.add(
responses.GET,
"https://getsentry.atlassian.net/rest/api/2/issue/createmeta",
json=create_meta_response,
)
responses.add(
responses.POST,
"https://getsentry.atlassian.net/rest/api/2/issue",
json={"key": "SEN-1"},
)
self.plugin.set_option("instance_url", "https://getsentry.atlassian.net", self.project)
group = self.create_group(message="Hello world", culprit="foo.bar")
request = self.request.get("/")
request.user = AnonymousUser()
form_data = {
"title": "Hello",
"description": "Fix this.",
"issuetype": "bug",
"project": "SEN",
}
assert self.plugin.create_issue(request, group, form_data) == "SEN-1"
@responses.activate
def test_link_issue(self):
responses.add(
responses.GET,
"https://getsentry.atlassian.net/rest/api/2/issue/SEN-19",
json=issue_response,
)
self.plugin.set_option("instance_url", "https://getsentry.atlassian.net", self.project)
group = self.create_group(message="Hello world", culprit="foo.bar")
request = self.request.get("/")
request.user = AnonymousUser()
form_data = {"issue_id": "SEN-19"}
assert (
self.plugin.link_issue(request, group, form_data)["title"]
== issue_response["fields"]["summary"]
)
def test_no_secrets(self):
self.user = self.create_user("[email protected]")
self.org = self.create_organization(owner=self.user, name="Rowdy Tiger")
self.team = self.create_team(organization=self.org, name="Mariachi Band")
self.project = self.create_project(organization=self.org, teams=[self.team], name="Bengal")
self.login_as(self.user)
self.plugin.set_option("password", "abcdef", self.project)
url = reverse(
"sentry-api-0-project-plugin-details", args=[self.org.slug, self.project.slug, "jira"]
)
res = self.client.get(url)
config = json.loads(res.content)["config"]
password_config = [item for item in config if item["name"] == "password"][0]
assert password_config.get("type") == "secret"
assert password_config.get("value") is None
assert password_config.get("hasSavedValue") is True
assert password_config.get("prefix") == ""
def test_get_formatted_user(self):
assert self.plugin._get_formatted_user(
{"displayName": "Foo Bar", "emailAddress": "[email protected]", "name": "foobar"}
) == {"text": "Foo Bar - [email protected] (foobar)", "id": "foobar"}
# test weird addon users that don't have email addresses
assert self.plugin._get_formatted_user(
{
"name": "robot",
"avatarUrls": {
"16x16": "https://avatar-cdn.atlassian.com/someid",
"24x24": "https://avatar-cdn.atlassian.com/someotherid",
},
"self": "https://something.atlassian.net/rest/api/2/user?username=someaddon",
}
) == {"id": "robot", "text": "robot (robot)"}