mirror of
https://github.com/hanzoai/sentinel.git
synced 2026-09-29 22:34:33 +00:00
1185 lines
45 KiB
Python
1185 lines
45 KiB
Python
from datetime import datetime, timedelta
|
|
from unittest.mock import patch
|
|
|
|
import pytest
|
|
from django.http.request import QueryDict
|
|
from django.test import RequestFactory
|
|
from django.utils import timezone
|
|
|
|
from sentry.charts.types import ChartType
|
|
from sentry.discover.models import DiscoverSavedQuery
|
|
from sentry.incidents.logic import CRITICAL_TRIGGER_LABEL
|
|
from sentry.integrations.slack.message_builder.discover import SlackDiscoverMessageBuilder
|
|
from sentry.integrations.slack.message_builder.issues import SlackIssuesMessageBuilder
|
|
from sentry.integrations.slack.message_builder.metric_alerts import SlackMetricAlertMessageBuilder
|
|
from sentry.integrations.slack.unfurl import LinkType, UnfurlableUrl, link_handlers, match_link
|
|
from sentry.services.hybrid_cloud.integration.serial import serialize_integration
|
|
from sentry.snuba.dataset import Dataset
|
|
from sentry.testutils.cases import TestCase
|
|
from sentry.testutils.helpers import install_slack
|
|
from sentry.testutils.helpers.datetime import before_now, freeze_time, iso_format
|
|
from sentry.testutils.helpers.features import with_feature
|
|
from sentry.testutils.skips import requires_snuba
|
|
|
|
pytestmark = [requires_snuba]
|
|
|
|
INTERVAL_COUNT = 300
|
|
INTERVALS_PER_DAY = int(60 * 60 * 24 / INTERVAL_COUNT)
|
|
|
|
|
|
@pytest.mark.parametrize(
|
|
"url,expected",
|
|
[
|
|
("http://invalid_link", (None, None)),
|
|
(
|
|
"https://sentry.io/organizations/org1/issues/12345/",
|
|
(LinkType.ISSUES, {"issue_id": 12345, "event_id": None}),
|
|
),
|
|
(
|
|
"https://org1.sentry.io/issues/12345/",
|
|
(LinkType.ISSUES, {"issue_id": 12345, "event_id": None}),
|
|
),
|
|
(
|
|
"https://sentry.io/organizations/org1/alerts/rules/details/12345/",
|
|
(
|
|
LinkType.METRIC_ALERT,
|
|
{
|
|
"alert_rule_id": 12345,
|
|
"incident_id": None,
|
|
"org_slug": "org1",
|
|
"period": None,
|
|
"start": None,
|
|
"end": None,
|
|
},
|
|
),
|
|
),
|
|
(
|
|
"https://org1.sentry.io/alerts/rules/details/12345/",
|
|
(
|
|
LinkType.METRIC_ALERT,
|
|
{
|
|
"alert_rule_id": 12345,
|
|
"incident_id": None,
|
|
"org_slug": "org1",
|
|
"period": None,
|
|
"start": None,
|
|
"end": None,
|
|
},
|
|
),
|
|
),
|
|
(
|
|
"https://sentry.io/organizations/org1/alerts/rules/details/12345/?alert=1337",
|
|
(
|
|
LinkType.METRIC_ALERT,
|
|
{
|
|
"alert_rule_id": 12345,
|
|
"incident_id": 1337,
|
|
"org_slug": "org1",
|
|
"period": None,
|
|
"start": None,
|
|
"end": None,
|
|
},
|
|
),
|
|
),
|
|
(
|
|
"https://org1.sentry.io/alerts/rules/details/12345/?alert=1337",
|
|
(
|
|
LinkType.METRIC_ALERT,
|
|
{
|
|
"alert_rule_id": 12345,
|
|
"incident_id": 1337,
|
|
"org_slug": "org1",
|
|
"period": None,
|
|
"start": None,
|
|
"end": None,
|
|
},
|
|
),
|
|
),
|
|
(
|
|
"https://sentry.io/organizations/org1/alerts/rules/details/12345/?period=14d",
|
|
(
|
|
LinkType.METRIC_ALERT,
|
|
{
|
|
"alert_rule_id": 12345,
|
|
"incident_id": None,
|
|
"org_slug": "org1",
|
|
"period": "14d",
|
|
"start": None,
|
|
"end": None,
|
|
},
|
|
),
|
|
),
|
|
(
|
|
"https://org1.sentry.io/alerts/rules/details/12345/?period=14d",
|
|
(
|
|
LinkType.METRIC_ALERT,
|
|
{
|
|
"alert_rule_id": 12345,
|
|
"incident_id": None,
|
|
"org_slug": "org1",
|
|
"period": "14d",
|
|
"start": None,
|
|
"end": None,
|
|
},
|
|
),
|
|
),
|
|
(
|
|
"https://sentry.io/organizations/org1/alerts/rules/details/12345/?end=2022-05-05T06%3A05%3A52&start=2022-05-04T00%3A46%3A19",
|
|
(
|
|
LinkType.METRIC_ALERT,
|
|
{
|
|
"alert_rule_id": 12345,
|
|
"incident_id": None,
|
|
"org_slug": "org1",
|
|
"period": None,
|
|
"start": "2022-05-04T00:46:19",
|
|
"end": "2022-05-05T06:05:52",
|
|
},
|
|
),
|
|
),
|
|
(
|
|
"https://org1.sentry.io/alerts/rules/details/12345/?end=2022-05-05T06%3A05%3A52&start=2022-05-04T00%3A46%3A19",
|
|
(
|
|
LinkType.METRIC_ALERT,
|
|
{
|
|
"alert_rule_id": 12345,
|
|
"incident_id": None,
|
|
"org_slug": "org1",
|
|
"period": None,
|
|
"start": "2022-05-04T00:46:19",
|
|
"end": "2022-05-05T06:05:52",
|
|
},
|
|
),
|
|
),
|
|
(
|
|
"https://sentry.io/organizations/org1/discover/results/?project=1&yAxis=count()",
|
|
(
|
|
LinkType.DISCOVER,
|
|
{"org_slug": "org1", "query": QueryDict("project=1&yAxis=count()")},
|
|
),
|
|
),
|
|
(
|
|
"https://org1.sentry.io/discover/results/?project=1&yAxis=count()",
|
|
(
|
|
LinkType.DISCOVER,
|
|
{"org_slug": "org1", "query": QueryDict("project=1&yAxis=count()")},
|
|
),
|
|
),
|
|
],
|
|
)
|
|
def test_match_link(url, expected):
|
|
assert match_link(url) == expected
|
|
|
|
|
|
class UnfurlTest(TestCase):
|
|
def setUp(self):
|
|
super().setUp()
|
|
# We're redefining project to ensure that the individual tests have unique project ids.
|
|
# Sharing project ids across tests could result in some race conditions
|
|
self.project = self.create_project()
|
|
self._integration = install_slack(self.organization)
|
|
self.integration = serialize_integration(self._integration)
|
|
|
|
self.request = RequestFactory().get("slack/event")
|
|
self.frozen_time = freeze_time(datetime.now() - timedelta(days=1))
|
|
self.frozen_time.start()
|
|
|
|
def tearDown(self):
|
|
self.frozen_time.stop()
|
|
|
|
def test_unfurl_issues(self):
|
|
min_ago = iso_format(before_now(minutes=1))
|
|
event = self.store_event(
|
|
data={"fingerprint": ["group2"], "timestamp": min_ago}, project_id=self.project.id
|
|
)
|
|
assert event.group is not None
|
|
group2 = event.group
|
|
|
|
links = [
|
|
UnfurlableUrl(
|
|
url=f"https://sentry.io/organizations/{self.organization.slug}/issues/{self.group.id}/",
|
|
args={"issue_id": self.group.id, "event_id": None},
|
|
),
|
|
UnfurlableUrl(
|
|
url=f"https://sentry.io/organizations/{self.organization.slug}/issues/{group2.id}/{event.event_id}/",
|
|
args={"issue_id": group2.id, "event_id": event.event_id},
|
|
),
|
|
]
|
|
|
|
unfurls = link_handlers[LinkType.ISSUES].fn(self.request, self.integration, links)
|
|
|
|
assert unfurls[links[0].url] == SlackIssuesMessageBuilder(self.group).build()
|
|
assert (
|
|
unfurls[links[1].url]
|
|
== SlackIssuesMessageBuilder(
|
|
group2, next(iter(event.build_group_events())), link_to_event=True
|
|
).build()
|
|
)
|
|
|
|
@with_feature("organizations:slack-block-kit")
|
|
def test_unfurl_issues_block_kit(self):
|
|
min_ago = iso_format(before_now(minutes=1))
|
|
event = self.store_event(
|
|
data={"fingerprint": ["group2"], "timestamp": min_ago}, project_id=self.project.id
|
|
)
|
|
assert event.group is not None
|
|
group2 = event.group
|
|
|
|
links = [
|
|
UnfurlableUrl(
|
|
url=f"https://sentry.io/organizations/{self.organization.slug}/issues/{self.group.id}/",
|
|
args={"issue_id": self.group.id, "event_id": None},
|
|
),
|
|
UnfurlableUrl(
|
|
url=f"https://sentry.io/organizations/{self.organization.slug}/issues/{group2.id}/{event.event_id}/",
|
|
args={"issue_id": group2.id, "event_id": event.event_id},
|
|
),
|
|
]
|
|
|
|
unfurls = link_handlers[LinkType.ISSUES].fn(self.request, self.integration, links)
|
|
|
|
assert unfurls[links[0].url] == SlackIssuesMessageBuilder(self.group).build()
|
|
assert (
|
|
unfurls[links[1].url]
|
|
== SlackIssuesMessageBuilder(
|
|
group2, next(iter(event.build_group_events())), link_to_event=True
|
|
).build()
|
|
)
|
|
|
|
def test_escape_issue(self):
|
|
group = self.create_group(
|
|
project=self.project,
|
|
data={"type": "error", "metadata": {"value": "<https://example.com/|*Click Here*>"}},
|
|
)
|
|
|
|
links = [
|
|
UnfurlableUrl(
|
|
url=f"https://sentry.io/organizations/{self.organization.slug}/issues/{group.id}/",
|
|
args={"issue_id": group.id, "event_id": None},
|
|
),
|
|
]
|
|
|
|
unfurls = link_handlers[LinkType.ISSUES].fn(self.request, self.integration, links)
|
|
assert unfurls[links[0].url]["text"] == "&lt;https://example.com/|*Click Here*&gt;"
|
|
|
|
@with_feature("organizations:slack-block-kit")
|
|
def test_escape_issue_block_kit(self):
|
|
group = self.create_group(
|
|
project=self.project,
|
|
data={"type": "error", "metadata": {"value": "<https://example.com/|*Click Here*>"}},
|
|
)
|
|
|
|
links = [
|
|
UnfurlableUrl(
|
|
url=f"https://sentry.io/organizations/{self.organization.slug}/issues/{group.id}/",
|
|
args={"issue_id": group.id, "event_id": None},
|
|
),
|
|
]
|
|
|
|
unfurls = link_handlers[LinkType.ISSUES].fn(self.request, self.integration, links)
|
|
assert (
|
|
"&lt;https://example.com/|*Click Here*&gt;"
|
|
in unfurls[links[0].url]["blocks"][1]["elements"][0]["elements"][0]["text"]
|
|
)
|
|
|
|
def test_unfurl_metric_alert(self):
|
|
alert_rule = self.create_alert_rule()
|
|
|
|
incident = self.create_incident(
|
|
status=2, organization=self.organization, projects=[self.project], alert_rule=alert_rule
|
|
)
|
|
incident.update(identifier=123)
|
|
trigger = self.create_alert_rule_trigger(alert_rule, CRITICAL_TRIGGER_LABEL, 100)
|
|
self.create_alert_rule_trigger_action(
|
|
alert_rule_trigger=trigger, triggered_for_incident=incident
|
|
)
|
|
|
|
links = [
|
|
UnfurlableUrl(
|
|
url=f"https://sentry.io/organizations/{self.organization.slug}/alerts/rules/details/{incident.alert_rule.id}/?alert={incident.identifier}",
|
|
args={
|
|
"org_slug": self.organization.slug,
|
|
"alert_rule_id": incident.alert_rule.id,
|
|
"incident_id": incident.identifier,
|
|
"period": None,
|
|
"start": None,
|
|
"end": None,
|
|
},
|
|
),
|
|
]
|
|
unfurls = link_handlers[LinkType.METRIC_ALERT].fn(self.request, self.integration, links)
|
|
assert (
|
|
links[0].url
|
|
== f"https://sentry.io/organizations/{self.organization.slug}/alerts/rules/details/{incident.alert_rule.id}/?alert={incident.identifier}"
|
|
)
|
|
assert (
|
|
unfurls[links[0].url]
|
|
== SlackMetricAlertMessageBuilder(incident.alert_rule, incident).build()
|
|
)
|
|
|
|
@patch("sentry.charts.backend.generate_chart", return_value="chart-url")
|
|
def test_unfurl_metric_alerts_chart(self, mock_generate_chart):
|
|
alert_rule = self.create_alert_rule()
|
|
incident = self.create_incident(
|
|
status=2,
|
|
organization=self.organization,
|
|
projects=[self.project],
|
|
alert_rule=alert_rule,
|
|
date_started=timezone.now() - timedelta(minutes=2),
|
|
)
|
|
incident.update(identifier=123)
|
|
trigger = self.create_alert_rule_trigger(alert_rule, CRITICAL_TRIGGER_LABEL, 100)
|
|
self.create_alert_rule_trigger_action(
|
|
alert_rule_trigger=trigger, triggered_for_incident=incident
|
|
)
|
|
|
|
url = f"https://sentry.io/organizations/{self.organization.slug}/alerts/rules/details/{alert_rule.id}/?alert={incident.identifier}"
|
|
links = [
|
|
UnfurlableUrl(
|
|
url=url,
|
|
args={
|
|
"org_slug": self.organization.slug,
|
|
"alert_rule_id": alert_rule.id,
|
|
"incident_id": incident.identifier,
|
|
"period": None,
|
|
"start": None,
|
|
"end": None,
|
|
},
|
|
),
|
|
]
|
|
|
|
with self.feature(
|
|
[
|
|
"organizations:incidents",
|
|
"organizations:discover",
|
|
"organizations:discover-basic",
|
|
"organizations:metric-alert-chartcuterie",
|
|
]
|
|
):
|
|
unfurls = link_handlers[LinkType.METRIC_ALERT].fn(self.request, self.integration, links)
|
|
|
|
assert (
|
|
unfurls[links[0].url]
|
|
== SlackMetricAlertMessageBuilder(alert_rule, incident, chart_url="chart-url").build()
|
|
)
|
|
assert len(mock_generate_chart.mock_calls) == 1
|
|
chart_data = mock_generate_chart.call_args[0][1]
|
|
assert chart_data["rule"]["id"] == str(alert_rule.id)
|
|
assert chart_data["selectedIncident"]["identifier"] == str(incident.identifier)
|
|
series_data = chart_data["timeseriesData"][0]["data"]
|
|
assert len(series_data) > 0
|
|
# Validate format of timeseries
|
|
assert type(series_data[0]["name"]) is int
|
|
assert type(series_data[0]["value"]) is float
|
|
assert chart_data["incidents"][0]["id"] == str(incident.id)
|
|
|
|
@patch("sentry.charts.backend.generate_chart", return_value="chart-url")
|
|
def test_unfurl_metric_alerts_chart_transaction(self, mock_generate_chart):
|
|
# Using the transactions dataset
|
|
alert_rule = self.create_alert_rule(query="p95", dataset=Dataset.Transactions)
|
|
incident = self.create_incident(
|
|
status=2,
|
|
organization=self.organization,
|
|
projects=[self.project],
|
|
alert_rule=alert_rule,
|
|
date_started=timezone.now() - timedelta(minutes=2),
|
|
)
|
|
|
|
url = f"https://sentry.io/organizations/{self.organization.slug}/alerts/rules/details/{alert_rule.id}/?alert={incident.identifier}"
|
|
links = [
|
|
UnfurlableUrl(
|
|
url=url,
|
|
args={
|
|
"org_slug": self.organization.slug,
|
|
"alert_rule_id": alert_rule.id,
|
|
"incident_id": incident.identifier,
|
|
"period": None,
|
|
"start": None,
|
|
"end": None,
|
|
},
|
|
),
|
|
]
|
|
|
|
with self.feature(
|
|
[
|
|
"organizations:incidents",
|
|
"organizations:discover",
|
|
"organizations:performance-view",
|
|
"organizations:metric-alert-chartcuterie",
|
|
]
|
|
):
|
|
unfurls = link_handlers[LinkType.METRIC_ALERT].fn(self.request, self.integration, links)
|
|
|
|
assert (
|
|
unfurls[links[0].url]
|
|
== SlackMetricAlertMessageBuilder(alert_rule, incident, chart_url="chart-url").build()
|
|
)
|
|
assert len(mock_generate_chart.mock_calls) == 1
|
|
chart_data = mock_generate_chart.call_args[0][1]
|
|
assert chart_data["rule"]["id"] == str(alert_rule.id)
|
|
assert chart_data["selectedIncident"]["identifier"] == str(incident.identifier)
|
|
series_data = chart_data["timeseriesData"][0]["data"]
|
|
assert len(series_data) > 0
|
|
# Validate format of timeseries
|
|
assert type(series_data[0]["name"]) is int
|
|
assert type(series_data[0]["value"]) is float
|
|
assert chart_data["incidents"][0]["id"] == str(incident.id)
|
|
|
|
@patch("sentry.charts.backend.generate_chart", return_value="chart-url")
|
|
def test_unfurl_metric_alerts_chart_crash_free(self, mock_generate_chart):
|
|
alert_rule = self.create_alert_rule(
|
|
query="",
|
|
aggregate="percentage(sessions_crashed, sessions) AS _crash_rate_alert_aggregate",
|
|
dataset=Dataset.Sessions,
|
|
time_window=60,
|
|
resolve_threshold=10,
|
|
threshold_period=1,
|
|
)
|
|
|
|
url = f"https://sentry.io/organizations/{self.organization.slug}/alerts/rules/details/{alert_rule.id}/"
|
|
links = [
|
|
UnfurlableUrl(
|
|
url=url,
|
|
args={
|
|
"org_slug": self.organization.slug,
|
|
"alert_rule_id": alert_rule.id,
|
|
"incident_id": None,
|
|
"period": None,
|
|
"start": None,
|
|
"end": None,
|
|
},
|
|
),
|
|
]
|
|
|
|
with self.feature(
|
|
[
|
|
"organizations:incidents",
|
|
"organizations:discover",
|
|
"organizations:discover-basic",
|
|
"organizations:metric-alert-chartcuterie",
|
|
]
|
|
):
|
|
unfurls = link_handlers[LinkType.METRIC_ALERT].fn(self.request, self.integration, links)
|
|
|
|
assert (
|
|
unfurls[links[0].url]
|
|
== SlackMetricAlertMessageBuilder(alert_rule, chart_url="chart-url").build()
|
|
)
|
|
assert len(mock_generate_chart.mock_calls) == 1
|
|
chart_data = mock_generate_chart.call_args[0][1]
|
|
assert chart_data["rule"]["id"] == str(alert_rule.id)
|
|
assert chart_data["selectedIncident"] is None
|
|
assert len(chart_data["sessionResponse"]["groups"]) >= 1
|
|
assert len(chart_data["incidents"]) == 0
|
|
|
|
@patch(
|
|
"sentry.api.bases.organization_events.OrganizationEventsV2EndpointBase.get_event_stats_data",
|
|
return_value={
|
|
"data": [(i * INTERVAL_COUNT, [{"count": 0}]) for i in range(INTERVALS_PER_DAY)],
|
|
"end": 1652903400,
|
|
"isMetricsData": False,
|
|
"start": 1652817000,
|
|
},
|
|
)
|
|
@patch("sentry.charts.backend.generate_chart", return_value="chart-url")
|
|
def test_unfurl_discover(self, mock_generate_chart, _):
|
|
url = f"https://sentry.io/organizations/{self.organization.slug}/discover/results/?field=title&field=event.type&field=project&field=user.display&field=timestamp&name=All+Events&project={self.project.id}&query=&sort=-timestamp&statsPeriod=24h"
|
|
link_type, args = match_link(url)
|
|
|
|
if not args or not link_type:
|
|
raise Exception("Missing link_type/args")
|
|
|
|
links = [
|
|
UnfurlableUrl(url=url, args=args),
|
|
]
|
|
|
|
with self.feature(["organizations:discover-basic"]):
|
|
unfurls = link_handlers[link_type].fn(self.request, self.integration, links, self.user)
|
|
|
|
assert (
|
|
unfurls[url]
|
|
== SlackDiscoverMessageBuilder(
|
|
title=args["query"].get("name"), chart_url="chart-url"
|
|
).build()
|
|
)
|
|
assert len(mock_generate_chart.mock_calls) == 1
|
|
chart_data = mock_generate_chart.call_args[0][1]
|
|
assert chart_data["seriesName"] == "count()"
|
|
assert len(chart_data["stats"]["data"]) == INTERVALS_PER_DAY
|
|
|
|
@patch(
|
|
"sentry.api.bases.organization_events.OrganizationEventsV2EndpointBase.get_event_stats_data",
|
|
return_value={
|
|
"data": [
|
|
(i * INTERVAL_COUNT, [{"count": 0}]) for i in range(int(INTERVALS_PER_DAY / 6))
|
|
],
|
|
"end": 1652903400,
|
|
"isMetricsData": False,
|
|
"start": 1652817000,
|
|
},
|
|
)
|
|
@patch("sentry.charts.backend.generate_chart", return_value="chart-url")
|
|
def test_unfurl_discover_previous_period(self, mock_generate_chart, _):
|
|
url = f"https://sentry.io/organizations/{self.organization.slug}/discover/results/?display=previous&field=title&field=event.type&field=project&field=user.display&field=timestamp&name=All+Events&project={self.project.id}&query=&sort=-timestamp&statsPeriod=24h"
|
|
link_type, args = match_link(url)
|
|
|
|
if not args or not link_type:
|
|
raise Exception("Missing link_type/args")
|
|
|
|
links = [
|
|
UnfurlableUrl(url=url, args=args),
|
|
]
|
|
|
|
with self.feature(["organizations:discover-basic"]):
|
|
unfurls = link_handlers[link_type].fn(self.request, self.integration, links, self.user)
|
|
|
|
assert (
|
|
unfurls[url]
|
|
== SlackDiscoverMessageBuilder(
|
|
title=args["query"].get("name"), chart_url="chart-url"
|
|
).build()
|
|
)
|
|
assert len(mock_generate_chart.mock_calls) == 1
|
|
assert mock_generate_chart.call_args[0][0] == ChartType.SLACK_DISCOVER_PREVIOUS_PERIOD
|
|
chart_data = mock_generate_chart.call_args[0][1]
|
|
assert chart_data["seriesName"] == "count()"
|
|
assert len(chart_data["stats"]["data"]) == 48
|
|
|
|
@patch(
|
|
"sentry.api.bases.organization_events.OrganizationEventsV2EndpointBase.get_event_stats_data",
|
|
return_value={
|
|
"count()": {
|
|
"data": [(i * INTERVAL_COUNT, [{"count": 0}]) for i in range(INTERVALS_PER_DAY)],
|
|
"end": 1652903400,
|
|
"isMetricsData": False,
|
|
"order": 1,
|
|
"start": 1652817000,
|
|
},
|
|
"count_unique(user)": {
|
|
"data": [(i * INTERVAL_COUNT, [{"count": 0}]) for i in range(INTERVALS_PER_DAY)],
|
|
"end": 1652903400,
|
|
"isMetricsData": False,
|
|
"order": 1,
|
|
"start": 1652817000,
|
|
},
|
|
},
|
|
)
|
|
@patch("sentry.charts.backend.generate_chart", return_value="chart-url")
|
|
def test_unfurl_discover_multi_y_axis(self, mock_generate_chart, _):
|
|
url = f"https://sentry.io/organizations/{self.organization.slug}/discover/results/?field=title&field=event.type&field=project&field=user.display&field=timestamp&name=All+Events&project={self.project.id}&query=&sort=-timestamp&statsPeriod=24h&yAxis=count_unique%28user%29&yAxis=count%28%29"
|
|
link_type, args = match_link(url)
|
|
|
|
if not args or not link_type:
|
|
raise Exception("Missing link_type/args")
|
|
|
|
links = [
|
|
UnfurlableUrl(url=url, args=args),
|
|
]
|
|
|
|
with self.feature(["organizations:discover-basic"]):
|
|
unfurls = link_handlers[link_type].fn(self.request, self.integration, links, self.user)
|
|
|
|
assert (
|
|
unfurls[url]
|
|
== SlackDiscoverMessageBuilder(
|
|
title=args["query"].get("name"), chart_url="chart-url"
|
|
).build()
|
|
)
|
|
assert len(mock_generate_chart.mock_calls) == 1
|
|
chart_data = mock_generate_chart.call_args[0][1]
|
|
|
|
assert len(chart_data["stats"]["count()"]["data"]) == INTERVALS_PER_DAY
|
|
assert len(chart_data["stats"]["count_unique(user)"]["data"]) == INTERVALS_PER_DAY
|
|
|
|
@patch(
|
|
"sentry.api.bases.organization_events.OrganizationEventsV2EndpointBase.get_event_stats_data",
|
|
return_value={
|
|
"data": [(i * INTERVAL_COUNT, [{"count": 0}]) for i in range(INTERVALS_PER_DAY)],
|
|
"end": 1652903400,
|
|
"isMetricsData": False,
|
|
"order": 1,
|
|
"start": 1652817000,
|
|
},
|
|
)
|
|
@patch("sentry.charts.backend.generate_chart", return_value="chart-url")
|
|
def test_unfurl_discover_html_escaped(self, mock_generate_chart, _):
|
|
url = f"https://sentry.io/organizations/{self.organization.slug}/discover/results/?field=title&field=event.type&field=project&field=user.display&field=timestamp&name=All+Events&project={self.project.id}&query=&sort=-timestamp&statsPeriod=24h"
|
|
link_type, args = match_link(url)
|
|
|
|
if not args or not link_type:
|
|
raise Exception("Missing link_type/args")
|
|
|
|
links = [
|
|
UnfurlableUrl(url=url, args=args),
|
|
]
|
|
|
|
with self.feature(["organizations:discover-basic"]):
|
|
unfurls = link_handlers[link_type].fn(self.request, self.integration, links, self.user)
|
|
|
|
assert (
|
|
unfurls[url]
|
|
== SlackDiscoverMessageBuilder(
|
|
title=args["query"].get("name"), chart_url="chart-url"
|
|
).build()
|
|
)
|
|
assert len(mock_generate_chart.mock_calls) == 1
|
|
chart_data = mock_generate_chart.call_args[0][1]
|
|
assert chart_data["seriesName"] == "count()"
|
|
assert len(chart_data["stats"]["data"]) == INTERVALS_PER_DAY
|
|
|
|
@patch(
|
|
"sentry.api.bases.organization_events.OrganizationEventsV2EndpointBase.get_event_stats_data",
|
|
return_value={
|
|
"default,first,capable-hagfish,None": {
|
|
"data": [(i * INTERVAL_COUNT, [{"count": 0}]) for i in range(INTERVALS_PER_DAY)],
|
|
"end": 1652903400,
|
|
"isMetricsData": False,
|
|
"order": 1,
|
|
"start": 1652817000,
|
|
},
|
|
"default,second,capable-hagfish,None": {
|
|
"data": [(i * INTERVAL_COUNT, [{"count": 0}]) for i in range(INTERVALS_PER_DAY)],
|
|
"end": 1652903400,
|
|
"isMetricsData": False,
|
|
"order": 1,
|
|
"start": 1652817000,
|
|
},
|
|
},
|
|
)
|
|
@patch("sentry.charts.backend.generate_chart", return_value="chart-url")
|
|
def test_unfurl_discover_short_url(self, mock_generate_chart, _):
|
|
query = {
|
|
"fields": ["message", "event.type", "project", "user.display", "count_unique(user)"],
|
|
"query": "message:[first,second]",
|
|
"yAxis": "count_unique(user)",
|
|
"display": "top5",
|
|
"topEvents": 2,
|
|
}
|
|
saved_query = DiscoverSavedQuery.objects.create(
|
|
organization=self.organization,
|
|
created_by_id=self.user.id,
|
|
name="Test query",
|
|
query=query,
|
|
version=2,
|
|
)
|
|
saved_query.set_projects([self.project.id])
|
|
|
|
url = f"https://sentry.io/organizations/{self.organization.slug}/discover/results/?id={saved_query.id}&statsPeriod=24h&project={self.project.id}"
|
|
link_type, args = match_link(url)
|
|
|
|
if not args or not link_type:
|
|
raise Exception("Missing link_type/args")
|
|
|
|
links = [
|
|
UnfurlableUrl(url=url, args=args),
|
|
]
|
|
|
|
with self.feature(
|
|
[
|
|
"organizations:discover",
|
|
"organizations:discover-basic",
|
|
]
|
|
):
|
|
unfurls = link_handlers[link_type].fn(self.request, self.integration, links, self.user)
|
|
|
|
assert (
|
|
unfurls[url]
|
|
== SlackDiscoverMessageBuilder(
|
|
title=args["query"].get("name"), chart_url="chart-url"
|
|
).build()
|
|
)
|
|
assert len(mock_generate_chart.mock_calls) == 1
|
|
|
|
# Line chart expected since yAxis is count_unique(user)
|
|
assert mock_generate_chart.call_args[0][0] == ChartType.SLACK_DISCOVER_TOP5_PERIOD_LINE
|
|
chart_data = mock_generate_chart.call_args[0][1]
|
|
assert chart_data["seriesName"] == "count_unique(user)"
|
|
# 2 + 1 cause of Other
|
|
assert len(chart_data["stats"].keys()) == 2
|
|
first_key = list(chart_data["stats"].keys())[0]
|
|
assert len(chart_data["stats"][first_key]["data"]) == INTERVALS_PER_DAY
|
|
|
|
@patch(
|
|
"sentry.api.bases.organization_events.OrganizationEventsV2EndpointBase.get_event_stats_data",
|
|
return_value={
|
|
"data": [(i * INTERVAL_COUNT, [{"count": 0}]) for i in range(INTERVALS_PER_DAY)],
|
|
"end": 1652903400,
|
|
"isMetricsData": False,
|
|
"start": 1652817000,
|
|
},
|
|
)
|
|
@patch("sentry.charts.backend.generate_chart", return_value="chart-url")
|
|
def test_unfurl_correct_y_axis_for_saved_query(self, mock_generate_chart, _):
|
|
query = {
|
|
"fields": [
|
|
"message",
|
|
"event.type",
|
|
"project",
|
|
"user.display",
|
|
"p50(transaction.duration)",
|
|
],
|
|
}
|
|
saved_query = DiscoverSavedQuery.objects.create(
|
|
organization=self.organization,
|
|
created_by_id=self.user.id,
|
|
name="Test query",
|
|
query=query,
|
|
version=2,
|
|
)
|
|
saved_query.set_projects([self.project.id])
|
|
|
|
url = f"https://sentry.io/organizations/{self.organization.slug}/discover/results/?id={saved_query.id}&statsPeriod=24h&project={self.project.id}"
|
|
link_type, args = match_link(url)
|
|
|
|
if not args or not link_type:
|
|
raise Exception("Missing link_type/args")
|
|
|
|
links = [
|
|
UnfurlableUrl(url=url, args=args),
|
|
]
|
|
|
|
with self.feature(
|
|
[
|
|
"organizations:discover",
|
|
"organizations:discover-basic",
|
|
]
|
|
):
|
|
unfurls = link_handlers[link_type].fn(self.request, self.integration, links, self.user)
|
|
|
|
assert (
|
|
unfurls[url]
|
|
== SlackDiscoverMessageBuilder(
|
|
title=args["query"].get("name"), chart_url="chart-url"
|
|
).build()
|
|
)
|
|
assert len(mock_generate_chart.mock_calls) == 1
|
|
|
|
assert mock_generate_chart.call_args[0][0] == ChartType.SLACK_DISCOVER_TOTAL_PERIOD
|
|
chart_data = mock_generate_chart.call_args[0][1]
|
|
assert chart_data["seriesName"] == "p50(transaction.duration)"
|
|
assert len(chart_data["stats"]["data"]) == INTERVALS_PER_DAY
|
|
|
|
@patch(
|
|
"sentry.api.bases.organization_events.OrganizationEventsV2EndpointBase.get_event_stats_data",
|
|
return_value={
|
|
"default,first": {
|
|
"data": [(i * INTERVAL_COUNT, [{"count": 0}]) for i in range(INTERVALS_PER_DAY)],
|
|
"end": 1652903400,
|
|
"isMetricsData": False,
|
|
"order": 1,
|
|
"start": 1652817000,
|
|
},
|
|
"default,second": {
|
|
"data": [(i * INTERVAL_COUNT, [{"count": 0}]) for i in range(INTERVALS_PER_DAY)],
|
|
"end": 1652903400,
|
|
"isMetricsData": False,
|
|
"order": 1,
|
|
"start": 1652817000,
|
|
},
|
|
},
|
|
)
|
|
@patch("sentry.charts.backend.generate_chart", return_value="chart-url")
|
|
def test_top_events_url_param(self, mock_generate_chart, _):
|
|
url = f"https://sentry.io/organizations/{self.organization.slug}/discover/results/?field=message&field=event.type&field=count()&name=All+Events&query=message:[first,second]&sort=-count&statsPeriod=24h&display=top5&topEvents=2"
|
|
link_type, args = match_link(url)
|
|
|
|
if not args or not link_type:
|
|
raise Exception("Missing link_type/args")
|
|
|
|
links = [
|
|
UnfurlableUrl(url=url, args=args),
|
|
]
|
|
|
|
with self.feature(
|
|
[
|
|
"organizations:discover",
|
|
"organizations:discover-basic",
|
|
]
|
|
):
|
|
unfurls = link_handlers[link_type].fn(self.request, self.integration, links, self.user)
|
|
|
|
assert (
|
|
unfurls[url]
|
|
== SlackDiscoverMessageBuilder(
|
|
title=args["query"].get("name"), chart_url="chart-url"
|
|
).build()
|
|
)
|
|
assert len(mock_generate_chart.mock_calls) == 1
|
|
|
|
assert mock_generate_chart.call_args[0][0] == ChartType.SLACK_DISCOVER_TOP5_PERIOD
|
|
chart_data = mock_generate_chart.call_args[0][1]
|
|
assert chart_data["seriesName"] == "count()"
|
|
assert len(chart_data["stats"].keys()) == 2
|
|
first_key = list(chart_data["stats"].keys())[0]
|
|
assert len(chart_data["stats"][first_key]["data"]) == INTERVALS_PER_DAY
|
|
|
|
# patched return value determined by reading events stats output
|
|
@patch(
|
|
"sentry.api.bases.organization_events.OrganizationEventsV2EndpointBase.get_event_stats_data",
|
|
return_value={
|
|
"default,second": {
|
|
"data": [(1212121, [{"count": 15}]), (1652659200, [{"count": 12}])],
|
|
"order": 0,
|
|
"isMetricsData": False,
|
|
"start": 1652572800,
|
|
"end": 1652659201,
|
|
},
|
|
"default,first": {
|
|
"data": [(1652572800, [{"count": 15}]), (1652659200, [{"count": 11}])],
|
|
"order": 1,
|
|
"isMetricsData": False,
|
|
"start": 1652572800,
|
|
"end": 1652659201,
|
|
},
|
|
},
|
|
)
|
|
@patch("sentry.charts.backend.generate_chart", return_value="chart-url")
|
|
def test_top_daily_events_renders_bar_chart(self, mock_generate_chart, _):
|
|
url = (
|
|
f"https://sentry.io/organizations/{self.organization.slug}/discover/results/"
|
|
"?field=message"
|
|
"&field=event.type"
|
|
"&field=count()"
|
|
"&name=All+Events"
|
|
"&query=message:[first,second]"
|
|
"&sort=-count"
|
|
"&statsPeriod=24h"
|
|
"&display=dailytop5"
|
|
"&topEvents=2"
|
|
)
|
|
link_type, args = match_link(url)
|
|
|
|
if not args or not link_type:
|
|
raise Exception("Missing link_type/args")
|
|
|
|
links = [
|
|
UnfurlableUrl(url=url, args=args),
|
|
]
|
|
|
|
with self.feature(
|
|
[
|
|
"organizations:discover",
|
|
"organizations:discover-basic",
|
|
]
|
|
):
|
|
unfurls = link_handlers[link_type].fn(self.request, self.integration, links, self.user)
|
|
|
|
assert (
|
|
unfurls[url]
|
|
== SlackDiscoverMessageBuilder(
|
|
title=args["query"].get("name"), chart_url="chart-url"
|
|
).build()
|
|
)
|
|
assert len(mock_generate_chart.mock_calls) == 1
|
|
|
|
assert mock_generate_chart.call_args[0][0] == ChartType.SLACK_DISCOVER_TOP5_DAILY
|
|
chart_data = mock_generate_chart.call_args[0][1]
|
|
assert chart_data["seriesName"] == "count()"
|
|
assert len(chart_data["stats"].keys()) == 2
|
|
first_key = list(chart_data["stats"].keys())[0]
|
|
# Two buckets
|
|
assert len(chart_data["stats"][first_key]["data"]) == 2
|
|
|
|
@patch(
|
|
"sentry.api.bases.organization_events.OrganizationEventsV2EndpointBase.get_event_stats_data",
|
|
return_value={
|
|
"data": [(i * INTERVAL_COUNT, [{"count": 0}]) for i in range(INTERVALS_PER_DAY)],
|
|
"end": 1652903400,
|
|
"isMetricsData": False,
|
|
"start": 1652817000,
|
|
},
|
|
)
|
|
@patch("sentry.charts.backend.generate_chart", return_value="chart-url")
|
|
def test_unfurl_discover_short_url_without_project_ids(self, mock_generate_chart, _):
|
|
query = {
|
|
"fields": ["title", "event.type", "project", "user.display", "timestamp"],
|
|
"query": "",
|
|
"yAxis": "count_unique(users)",
|
|
}
|
|
saved_query = DiscoverSavedQuery.objects.create(
|
|
organization=self.organization,
|
|
created_by_id=self.user.id,
|
|
name="Test query",
|
|
query=query,
|
|
version=2,
|
|
)
|
|
saved_query.set_projects([self.project.id])
|
|
|
|
url = f"https://sentry.io/organizations/{self.organization.slug}/discover/results/?id={saved_query.id}&statsPeriod=24h"
|
|
link_type, args = match_link(url)
|
|
|
|
if not args or not link_type:
|
|
raise Exception("Missing link_type/args")
|
|
|
|
links = [
|
|
UnfurlableUrl(url=url, args=args),
|
|
]
|
|
|
|
with self.feature(
|
|
[
|
|
"organizations:discover",
|
|
"organizations:discover-basic",
|
|
]
|
|
):
|
|
unfurls = link_handlers[link_type].fn(self.request, self.integration, links, self.user)
|
|
|
|
assert (
|
|
unfurls[url]
|
|
== SlackDiscoverMessageBuilder(
|
|
title=args["query"].get("name"), chart_url="chart-url"
|
|
).build()
|
|
)
|
|
assert len(mock_generate_chart.mock_calls) == 1
|
|
|
|
assert mock_generate_chart.call_args[0][0] == ChartType.SLACK_DISCOVER_TOTAL_PERIOD
|
|
chart_data = mock_generate_chart.call_args[0][1]
|
|
assert chart_data["seriesName"] == "count_unique(users)"
|
|
assert len(chart_data["stats"]["data"]) == INTERVALS_PER_DAY
|
|
|
|
@patch(
|
|
"sentry.api.bases.organization_events.OrganizationEventsV2EndpointBase.get_event_stats_data",
|
|
return_value={
|
|
"data": [(i * INTERVAL_COUNT, [{"count": 0}]) for i in range(INTERVALS_PER_DAY)],
|
|
"end": 1652903400,
|
|
"isMetricsData": False,
|
|
"start": 1652817000,
|
|
},
|
|
)
|
|
@patch("sentry.charts.backend.generate_chart", return_value="chart-url")
|
|
def test_unfurl_discover_without_project_ids(self, mock_generate_chart, _):
|
|
url = f"https://sentry.io/organizations/{self.organization.slug}/discover/results/?field=title&field=event.type&field=project&field=user.display&field=timestamp&name=All+Events&query=&sort=-timestamp&statsPeriod=24h"
|
|
link_type, args = match_link(url)
|
|
|
|
if not args or not link_type:
|
|
raise Exception("Missing link_type/args")
|
|
|
|
links = [
|
|
UnfurlableUrl(url=url, args=args),
|
|
]
|
|
|
|
with self.feature(
|
|
[
|
|
"organizations:discover",
|
|
"organizations:discover-basic",
|
|
]
|
|
):
|
|
unfurls = link_handlers[link_type].fn(self.request, self.integration, links, self.user)
|
|
|
|
assert (
|
|
unfurls[url]
|
|
== SlackDiscoverMessageBuilder(
|
|
title=args["query"].get("name"), chart_url="chart-url"
|
|
).build()
|
|
)
|
|
assert len(mock_generate_chart.mock_calls) == 1
|
|
chart_data = mock_generate_chart.call_args[0][1]
|
|
assert chart_data["seriesName"] == "count()"
|
|
assert len(chart_data["stats"]["data"]) == INTERVALS_PER_DAY
|
|
|
|
# patched return value determined by reading events stats output
|
|
@patch(
|
|
"sentry.api.bases.organization_events.OrganizationEventsV2EndpointBase.get_event_stats_data",
|
|
return_value={
|
|
"default,second": {
|
|
"data": [(1212121, [{"count": 15}]), (1652659200, [{"count": 12}])],
|
|
"order": 0,
|
|
"isMetricsData": False,
|
|
"start": 1652572800,
|
|
"end": 1652659201,
|
|
},
|
|
"default,first": {
|
|
"data": [(1652572800, [{"count": 15}]), (1652659200, [{"count": 11}])],
|
|
"order": 1,
|
|
"isMetricsData": False,
|
|
"start": 1652572800,
|
|
"end": 1652659201,
|
|
},
|
|
},
|
|
)
|
|
@patch("sentry.charts.backend.generate_chart", return_value="chart-url")
|
|
def test_bar_chart_display_renders_bar_chart(self, mock_generate_chart, _):
|
|
url = f"https://sentry.io/organizations/{self.organization.slug}/discover/results/?display=bar&field=title&event.type%3Aerror&sort=-count&statsPeriod=24h&yAxis=count%28%29"
|
|
|
|
link_type, args = match_link(url)
|
|
|
|
if not args or not link_type:
|
|
raise Exception("Missing link_type/args")
|
|
|
|
links = [
|
|
UnfurlableUrl(url=url, args=args),
|
|
]
|
|
|
|
with self.feature(
|
|
[
|
|
"organizations:discover",
|
|
"organizations:discover-basic",
|
|
]
|
|
):
|
|
unfurls = link_handlers[link_type].fn(self.request, self.integration, links, self.user)
|
|
|
|
assert (
|
|
unfurls[url]
|
|
== SlackDiscoverMessageBuilder(
|
|
title=args["query"].get("name"), chart_url="chart-url"
|
|
).build()
|
|
)
|
|
assert len(mock_generate_chart.mock_calls) == 1
|
|
|
|
assert mock_generate_chart.call_args[0][0] == ChartType.SLACK_DISCOVER_TOTAL_DAILY
|
|
|
|
@patch("sentry.integrations.slack.unfurl.discover.client.get")
|
|
@patch("sentry.charts.backend.generate_chart", return_value="chart-url")
|
|
def test_bar_chart_interval_with_absolute_date(self, mock_generate_chart, api_mock):
|
|
url = f"https://sentry.io/organizations/{self.organization.slug}/discover/results/?display=bar&end=2022-09-16T23%3A59%3A59&field=title&field=event.type&field=project&field=user.display&field=timestamp&name=All+Events&query=&sort=-timestamp&start=2022-09-09T00%3A00%3A00&utc=true&yAxis=count%28%29"
|
|
|
|
link_type, args = match_link(url)
|
|
|
|
if not args or not link_type:
|
|
raise Exception("Missing link_type/args")
|
|
|
|
links = [
|
|
UnfurlableUrl(url=url, args=args),
|
|
]
|
|
|
|
with self.feature(
|
|
[
|
|
"organizations:discover",
|
|
"organizations:discover-basic",
|
|
]
|
|
):
|
|
unfurls = link_handlers[link_type].fn(self.request, self.integration, links, self.user)
|
|
|
|
assert (
|
|
unfurls[url]
|
|
== SlackDiscoverMessageBuilder(
|
|
title=args["query"].get("name"), chart_url="chart-url"
|
|
).build()
|
|
)
|
|
|
|
assert len(mock_generate_chart.mock_calls) == 1
|
|
assert len(api_mock.mock_calls) == 1
|
|
|
|
assert "interval" in api_mock.call_args[1]["params"]
|
|
assert api_mock.call_args[1]["params"]["interval"] == "1h"
|
|
|
|
@patch("sentry.integrations.slack.unfurl.discover.client.get")
|
|
@patch("sentry.charts.backend.generate_chart", return_value="chart-url")
|
|
def test_bar_chart_interval_with_periodic_date(self, mock_generate_chart, api_mock):
|
|
url = f"https://sentry.io/organizations/{self.organization.slug}/discover/results/?display=bar&field=title&field=event.type&field=project&field=user.display&field=timestamp&name=All+Events&query=&sort=-timestamp&statsPeriod=90d&utc=true&yAxis=count%28%29"
|
|
|
|
link_type, args = match_link(url)
|
|
|
|
if not args or not link_type:
|
|
raise Exception("Missing link_type/args")
|
|
|
|
links = [
|
|
UnfurlableUrl(url=url, args=args),
|
|
]
|
|
|
|
with self.feature(
|
|
[
|
|
"organizations:discover",
|
|
"organizations:discover-basic",
|
|
]
|
|
):
|
|
unfurls = link_handlers[link_type].fn(self.request, self.integration, links, self.user)
|
|
|
|
assert (
|
|
unfurls[url]
|
|
== SlackDiscoverMessageBuilder(
|
|
title=args["query"].get("name"), chart_url="chart-url"
|
|
).build()
|
|
)
|
|
|
|
assert len(mock_generate_chart.mock_calls) == 1
|
|
assert len(api_mock.mock_calls) == 1
|
|
|
|
assert "interval" in api_mock.call_args[1]["params"]
|
|
assert api_mock.call_args[1]["params"]["interval"] == "1d"
|
|
|
|
@patch("sentry.integrations.slack.unfurl.discover.client.get")
|
|
@patch("sentry.charts.backend.generate_chart", return_value="chart-url")
|
|
def test_saved_query_with_interval(self, mock_generate_chart, api_mock):
|
|
query = {
|
|
"fields": ["title", "event.type", "project", "user.display", "timestamp"],
|
|
"query": "",
|
|
"yAxis": "count()",
|
|
"interval": "10m",
|
|
"statsPeriod": "24h",
|
|
}
|
|
saved_query = DiscoverSavedQuery.objects.create(
|
|
organization=self.organization,
|
|
created_by_id=self.user.id,
|
|
name="Test query",
|
|
query=query,
|
|
version=2,
|
|
)
|
|
saved_query.set_projects([self.project.id])
|
|
api_mock.return_value.data = query
|
|
|
|
url = f"https://sentry.io/organizations/{self.organization.slug}/discover/results/?id={saved_query.id}&statsPeriod=24h"
|
|
link_type, args = match_link(url)
|
|
|
|
if not args or not link_type:
|
|
raise Exception("Missing link_type/args")
|
|
|
|
links = [
|
|
UnfurlableUrl(url=url, args=args),
|
|
]
|
|
|
|
with self.feature(
|
|
[
|
|
"organizations:discover",
|
|
"organizations:discover-basic",
|
|
]
|
|
):
|
|
unfurls = link_handlers[link_type].fn(self.request, self.integration, links, self.user)
|
|
|
|
assert (
|
|
unfurls[url]
|
|
== SlackDiscoverMessageBuilder(
|
|
title=args["query"].get("name"), chart_url="chart-url"
|
|
).build()
|
|
)
|
|
|
|
assert len(mock_generate_chart.mock_calls) == 1
|
|
assert len(api_mock.mock_calls) == 2
|
|
|
|
assert "interval" in api_mock.call_args[1]["params"]
|
|
assert api_mock.call_args[1]["params"]["interval"] == "10m"
|
|
|
|
@patch(
|
|
"sentry.api.bases.organization_events.OrganizationEventsV2EndpointBase.get_event_stats_data",
|
|
return_value={
|
|
"data": [(i * INTERVAL_COUNT, [{"count": 0}]) for i in range(INTERVALS_PER_DAY)],
|
|
"end": 1652903400,
|
|
"isMetricsData": False,
|
|
"start": 1652817000,
|
|
},
|
|
)
|
|
@patch("sentry.charts.backend.generate_chart", return_value="chart-url")
|
|
def test_unfurl_discover_homepage(self, mock_generate_chart, _):
|
|
url = f"https://sentry.io/organizations/{self.organization.slug}/discover/homepage/?field=title&field=event.type&field=project&field=user.display&field=timestamp&name=All+Events&project={self.project.id}&query=&sort=-timestamp&statsPeriod=24h"
|
|
link_type, args = match_link(url)
|
|
|
|
if not args or not link_type:
|
|
raise Exception("Missing link_type/args")
|
|
|
|
links = [
|
|
UnfurlableUrl(url=url, args=args),
|
|
]
|
|
|
|
with self.feature(["organizations:discover-basic"]):
|
|
unfurls = link_handlers[link_type].fn(self.request, self.integration, links, self.user)
|
|
|
|
assert (
|
|
unfurls[url]
|
|
== SlackDiscoverMessageBuilder(
|
|
title=args["query"].get("name"), chart_url="chart-url"
|
|
).build()
|
|
)
|
|
assert len(mock_generate_chart.mock_calls) == 1
|
|
chart_data = mock_generate_chart.call_args[0][1]
|
|
assert chart_data["seriesName"] == "count()"
|
|
assert len(chart_data["stats"]["data"]) == INTERVALS_PER_DAY
|