Files
sentinel/tests/sentry/snuba/test_entity_subscriptions.py
2024-02-15 17:01:50 +00:00

932 lines
38 KiB
Python

from unittest.mock import patch
import pytest
from snuba_sdk import And, Column, Condition, Entity, Function, Join, Op, Relationship
from sentry.exceptions import (
IncompatibleMetricsQuery,
InvalidQuerySubscription,
InvalidSearchQuery,
UnsupportedQuerySubscription,
)
from sentry.models.group import GroupStatus
from sentry.search.events.constants import METRICS_MAP
from sentry.sentry_metrics import indexer
from sentry.sentry_metrics.use_case_id_registry import UseCaseID
from sentry.sentry_metrics.utils import resolve, resolve_tag_key, resolve_tag_value
from sentry.snuba.dataset import Dataset, EntityKey
from sentry.snuba.entity_subscription import (
EventsEntitySubscription,
MetricsCountersEntitySubscription,
MetricsSetsEntitySubscription,
PerformanceMetricsEntitySubscription,
PerformanceTransactionsEntitySubscription,
SessionsEntitySubscription,
get_entity_key_from_snuba_query,
get_entity_subscription,
get_entity_subscription_from_snuba_query,
)
from sentry.snuba.metrics.naming_layer.mri import SessionMRI
from sentry.snuba.models import SnubaQuery
from sentry.testutils.cases import TestCase
from sentry.testutils.helpers import Feature
from sentry.testutils.skips import requires_snuba
pytestmark = [pytest.mark.sentry_metrics, requires_snuba]
@pytest.mark.snuba_ci
class EntitySubscriptionTestCase(TestCase):
def setUp(self) -> None:
super().setUp()
for tag in [
SessionMRI.RAW_SESSION.value,
SessionMRI.RAW_USER.value,
"session.status",
"init",
"crashed",
]:
indexer.record(use_case_id=UseCaseID.SESSIONS, org_id=self.organization.id, string=tag)
def test_get_entity_subscriptions_for_sessions_dataset_non_supported_aggregate(self) -> None:
aggregate = "count(sessions)"
with pytest.raises(UnsupportedQuerySubscription):
get_entity_subscription(
query_type=SnubaQuery.Type.CRASH_RATE,
dataset=Dataset.Sessions,
aggregate=aggregate,
time_window=3600,
extra_fields={"org_id": self.organization.id},
)
def test_get_entity_subscriptions_for_sessions_dataset_missing_organization(self) -> None:
aggregate = "percentage(sessions_crashed, sessions) AS _crash_rate_alert_aggregate"
with pytest.raises(InvalidQuerySubscription):
get_entity_subscription(
query_type=SnubaQuery.Type.CRASH_RATE,
dataset=Dataset.Sessions,
aggregate=aggregate,
time_window=3600,
)
def test_build_query_builder_invalid_fields_raise_error(self) -> None:
entities = [
get_entity_subscription(
query_type=SnubaQuery.Type.CRASH_RATE,
dataset=Dataset.Sessions,
aggregate="percentage(sessions_crashed, sessions) AS _crash_rate_alert_aggregate",
time_window=3600,
extra_fields={"org_id": self.organization.id},
),
get_entity_subscription(
query_type=SnubaQuery.Type.ERROR,
dataset=Dataset.Events,
aggregate="count_unique(user)",
time_window=3600,
),
]
for entity in entities:
with pytest.raises(InvalidSearchQuery, match="Invalid key for this search: timestamp"):
entity.build_query_builder("timestamp:-24h", [self.project.id], None)
def test_get_entity_subscriptions_for_sessions_dataset(self) -> None:
aggregate = "percentage(sessions_crashed, sessions) AS _crash_rate_alert_aggregate"
entity_subscription = get_entity_subscription(
query_type=SnubaQuery.Type.CRASH_RATE,
dataset=Dataset.Sessions,
aggregate=aggregate,
time_window=3600,
extra_fields={"org_id": self.organization.id},
)
assert isinstance(entity_subscription, SessionsEntitySubscription)
assert entity_subscription.aggregate == aggregate
assert entity_subscription.get_entity_extra_params() == {
"organization": self.organization.id
}
assert entity_subscription.dataset == Dataset.Sessions
snql_query = entity_subscription.build_query_builder(
"", [self.project.id], None
).get_snql_query()
snql_query.query.select.sort(key=lambda q: q.function)
assert snql_query.query.select == [
Function(
function="identity", parameters=[Column(name="sessions")], alias="_total_count"
),
Function(
function="if",
parameters=[
Function(function="greater", parameters=[Column(name="sessions"), 0]),
Function(
function="divide",
parameters=[Column(name="sessions_crashed"), Column(name="sessions")],
),
None,
],
alias="_crash_rate_alert_aggregate",
),
]
assert snql_query.query.where == [
Condition(Column(name="project_id"), Op.IN, [self.project.id]),
Condition(Column(name="org_id"), Op.EQ, self.organization.id),
]
def test_get_entity_subscription_for_metrics_dataset_non_supported_aggregate(self) -> None:
aggregate = "count(sessions)"
with pytest.raises(UnsupportedQuerySubscription):
get_entity_subscription(
query_type=SnubaQuery.Type.CRASH_RATE,
dataset=Dataset.Metrics,
aggregate=aggregate,
time_window=3600,
extra_fields={"org_id": self.organization.id},
)
def test_get_entity_subscription_for_metrics_dataset_missing_organization(self) -> None:
aggregate = "percentage(sessions_crashed, sessions) AS _crash_rate_alert_aggregate"
with pytest.raises(InvalidQuerySubscription):
get_entity_subscription(
query_type=SnubaQuery.Type.CRASH_RATE,
dataset=Dataset.Metrics,
aggregate=aggregate,
time_window=3600,
)
# This test has been kept in order to validate whether the old queries through metrics are supported, in the future
# this should be removed.
def test_get_entity_subscription_for_metrics_dataset_for_users(self) -> None:
org_id = self.organization.id
use_case_id = UseCaseID.SESSIONS
aggregate = "percentage(users_crashed, users) AS _crash_rate_alert_aggregate"
entity_subscription = get_entity_subscription(
query_type=SnubaQuery.Type.CRASH_RATE,
dataset=Dataset.Metrics,
aggregate=aggregate,
time_window=3600,
extra_fields={"org_id": self.organization.id},
)
assert isinstance(entity_subscription, MetricsSetsEntitySubscription)
assert entity_subscription.aggregate == aggregate
assert entity_subscription.get_entity_extra_params() == {
"organization": self.organization.id,
"granularity": 10,
}
assert entity_subscription.dataset == Dataset.Metrics
session_status = resolve_tag_key(use_case_id, org_id, "session.status")
session_status_crashed = resolve_tag_value(use_case_id, org_id, "crashed")
snql_query = entity_subscription.build_query_builder(
"", [self.project.id], None, {"organization_id": self.organization.id}
).get_snql_query()
key = lambda func: func.alias
assert sorted(snql_query.query.select, key=key) == sorted(
[
Function("uniq", parameters=[Column("value")], alias="count"),
Function(
"uniqIf",
parameters=[
Column(name="value"),
Function(
function="equals",
parameters=[
Column(session_status),
session_status_crashed,
],
),
],
alias="crashed",
),
],
key=key,
)
assert snql_query.query.where == [
Condition(Column("project_id"), Op.IN, [self.project.id]),
Condition(Column("org_id"), Op.EQ, self.organization.id),
Condition(
Column("metric_id"),
Op.EQ,
resolve(
UseCaseID.SESSIONS,
self.organization.id,
entity_subscription.metric_key.value,
),
),
]
def test_get_entity_subscription_for_metrics_dataset_for_users_with_metrics_layer(self) -> None:
with Feature("organizations:use-metrics-layer-in-alerts"):
org_id = self.organization.id
use_case_id = UseCaseID.SESSIONS
aggregate = "percentage(users_crashed, users) AS _crash_rate_alert_aggregate"
entity_subscription = get_entity_subscription(
query_type=SnubaQuery.Type.CRASH_RATE,
dataset=Dataset.Metrics,
aggregate=aggregate,
time_window=3600,
extra_fields={"org_id": self.organization.id},
)
assert isinstance(entity_subscription, MetricsSetsEntitySubscription)
assert entity_subscription.aggregate == aggregate
assert entity_subscription.get_entity_extra_params() == {
"organization": self.organization.id,
"granularity": 10,
}
assert entity_subscription.dataset == Dataset.Metrics
session_status = resolve_tag_key(use_case_id, org_id, "session.status")
session_status_crashed = resolve_tag_value(use_case_id, org_id, "crashed")
metric_id = resolve(use_case_id, org_id, entity_subscription.metric_key.value)
snql_query = entity_subscription.build_query_builder(
"", [self.project.id], None, {"organization_id": self.organization.id}
).get_snql_query()
key = lambda func: func.alias
assert sorted(snql_query.query.select, key=key) == sorted(
[
Function(
"uniqIf",
parameters=[
Column("value"),
Function("equals", [Column("metric_id"), metric_id]),
],
alias="count",
),
Function(
"uniqIf",
parameters=[
Column("value"),
Function(
"and",
parameters=[
Function("equals", [Column("metric_id"), metric_id]),
Function(
"equals", [Column(session_status), session_status_crashed]
),
],
),
],
alias="crashed",
),
],
key=key,
)
assert snql_query.query.where == [
Condition(Column("org_id"), Op.EQ, self.organization.id),
Condition(Column("project_id"), Op.IN, [self.project.id]),
Condition(Column("metric_id"), Op.IN, [metric_id]),
]
# This test has been kept in order to validate whether the old queries through metrics are supported, in the future
# this should be removed.
def test_get_entity_subscription_for_metrics_dataset_for_sessions(self) -> None:
org_id = self.organization.id
use_case_id = UseCaseID.SESSIONS
aggregate = "percentage(sessions_crashed, sessions) AS _crash_rate_alert_aggregate"
entity_subscription = get_entity_subscription(
query_type=SnubaQuery.Type.CRASH_RATE,
dataset=Dataset.Metrics,
aggregate=aggregate,
time_window=3600,
extra_fields={"org_id": self.organization.id},
)
assert isinstance(entity_subscription, MetricsCountersEntitySubscription)
assert entity_subscription.aggregate == aggregate
assert entity_subscription.get_entity_extra_params() == {
"organization": self.organization.id,
"granularity": 10,
}
assert entity_subscription.dataset == Dataset.Metrics
session_status = resolve_tag_key(use_case_id, org_id, "session.status")
session_status_crashed = resolve_tag_value(use_case_id, org_id, "crashed")
session_status_init = resolve_tag_value(use_case_id, org_id, "init")
snql_query = entity_subscription.build_query_builder(
"", [self.project.id], None, {"organization_id": self.organization.id}
).get_snql_query()
key = lambda func: func.alias
assert sorted(snql_query.query.select, key=key) == sorted(
[
Function(
function="sumIf",
parameters=[
Column("value"),
Function(
"equals", parameters=[Column(session_status), session_status_init]
),
],
alias="count",
),
Function(
"sumIf",
parameters=[
Column(name="value"),
Function(
"equals", parameters=[Column(session_status), session_status_crashed]
),
],
alias="crashed",
),
],
key=key,
)
assert snql_query.query.where == [
Condition(Column("project_id"), Op.IN, [self.project.id]),
Condition(Column("org_id"), Op.EQ, self.organization.id),
Condition(
Column("metric_id"),
Op.EQ,
resolve(use_case_id, self.organization.id, entity_subscription.metric_key.value),
),
Condition(
Column(session_status),
Op.IN,
[session_status_crashed, session_status_init],
),
]
def test_get_entity_subscription_for_metrics_dataset_for_sessions_with_metrics_layer(
self,
) -> None:
with Feature("organizations:use-metrics-layer-in-alerts"):
org_id = self.organization.id
use_case_id = UseCaseID.SESSIONS
aggregate = "percentage(sessions_crashed, sessions) AS _crash_rate_alert_aggregate"
entity_subscription = get_entity_subscription(
query_type=SnubaQuery.Type.CRASH_RATE,
dataset=Dataset.Metrics,
aggregate=aggregate,
time_window=3600,
extra_fields={"org_id": self.organization.id},
)
assert isinstance(entity_subscription, MetricsCountersEntitySubscription)
assert entity_subscription.aggregate == aggregate
assert entity_subscription.get_entity_extra_params() == {
"organization": self.organization.id,
"granularity": 10,
}
assert entity_subscription.dataset == Dataset.Metrics
session_status = resolve_tag_key(use_case_id, org_id, "session.status")
session_status_crashed = resolve_tag_value(use_case_id, org_id, "crashed")
session_status_init = resolve_tag_value(use_case_id, org_id, "init")
metric_id = resolve(use_case_id, org_id, entity_subscription.metric_key.value)
snql_query = entity_subscription.build_query_builder(
"", [self.project.id], None, {"organization_id": self.organization.id}
).get_snql_query()
key = lambda func: func.alias
assert sorted(snql_query.query.select, key=key) == sorted(
[
Function(
"sumIf",
parameters=[
Column("value"),
Function(
"and",
parameters=[
Function("equals", [Column("metric_id"), metric_id]),
Function(
"equals", [Column(session_status), session_status_init]
),
],
),
],
alias="count",
),
Function(
"sumIf",
parameters=[
Column("value"),
Function(
"and",
parameters=[
Function("equals", [Column("metric_id"), metric_id]),
Function(
"equals", [Column(session_status), session_status_crashed]
),
],
),
],
alias="crashed",
),
],
key=key,
)
assert snql_query.query.where == [
Condition(Column("org_id"), Op.EQ, self.organization.id),
Condition(Column("project_id"), Op.IN, [self.project.id]),
Condition(
Column(session_status),
Op.IN,
[session_status_crashed, session_status_init],
),
Condition(Column("metric_id"), Op.IN, [metric_id]),
]
def test_get_entity_subscription_for_performance_transactions_dataset(self) -> None:
aggregate = "percentile(transaction.duration,.95)"
entity_subscription = get_entity_subscription(
query_type=SnubaQuery.Type.PERFORMANCE,
dataset=Dataset.Transactions,
aggregate=aggregate,
time_window=3600,
)
assert isinstance(entity_subscription, PerformanceTransactionsEntitySubscription)
assert entity_subscription.aggregate == aggregate
assert entity_subscription.get_entity_extra_params() == {}
assert entity_subscription.dataset == Dataset.Transactions
snql_query = entity_subscription.build_query_builder(
"", [self.project.id], None
).get_snql_query()
assert snql_query.query.select == [
Function(
"quantile(0.95)",
parameters=[Column(name="duration")],
alias="percentile_transaction_duration__95",
)
]
assert snql_query.query.where == [Condition(Column("project_id"), Op.IN, [self.project.id])]
# This test has been kept in order to validate whether the old queries through metrics are supported, in the future
# this should be removed.
def test_get_entity_subscription_for_performance_metrics_dataset(self) -> None:
aggregate = "percentile(transaction.duration,.95)"
entity_subscription = get_entity_subscription(
query_type=SnubaQuery.Type.PERFORMANCE,
dataset=Dataset.PerformanceMetrics,
aggregate=aggregate,
time_window=3600,
extra_fields={"org_id": self.organization.id},
)
assert isinstance(entity_subscription, PerformanceMetricsEntitySubscription)
assert entity_subscription.aggregate == aggregate
assert entity_subscription.get_entity_extra_params() == {
"organization": self.organization.id,
"granularity": 60,
}
assert entity_subscription.dataset == Dataset.PerformanceMetrics
snql_query = entity_subscription.build_query_builder(
"",
[self.project.id],
None,
{
"organization_id": self.organization.id,
},
).get_snql_query()
metric_id = resolve(
UseCaseID.TRANSACTIONS, self.organization.id, METRICS_MAP["transaction.duration"]
)
assert snql_query.query.select == [
Function(
function="arrayElement",
parameters=[
Function(
function="quantilesIf(0.95)",
parameters=[
Column(name="value"),
Function(
function="equals",
parameters=[Column(name="metric_id"), metric_id],
),
],
),
1,
],
alias="percentile_transaction_duration__95",
)
]
assert snql_query.query.where == [
Condition(Column("project_id"), Op.IN, [self.project.id]),
Condition(Column("org_id"), Op.EQ, self.organization.id),
Condition(Column("metric_id"), Op.IN, [metric_id]),
]
def test_get_entity_subscription_for_performance_metrics_dataset_with_metrics_layer(
self,
) -> None:
with Feature("organizations:use-metrics-layer-in-alerts"):
aggregate = "percentile(transaction.duration,.95)"
entity_subscription = get_entity_subscription(
query_type=SnubaQuery.Type.PERFORMANCE,
dataset=Dataset.PerformanceMetrics,
aggregate=aggregate,
time_window=3600,
extra_fields={"org_id": self.organization.id},
)
assert isinstance(entity_subscription, PerformanceMetricsEntitySubscription)
assert entity_subscription.aggregate == aggregate
assert entity_subscription.get_entity_extra_params() == {
"organization": self.organization.id,
"granularity": 60,
}
assert entity_subscription.dataset == Dataset.PerformanceMetrics
snql_query = entity_subscription.build_query_builder(
"",
[self.project.id],
None,
{
"organization_id": self.organization.id,
},
).get_snql_query()
metric_id = resolve(
UseCaseID.TRANSACTIONS, self.organization.id, METRICS_MAP["transaction.duration"]
)
assert snql_query.query.select == [
Function(
"arrayElement",
parameters=[
Function(
"quantilesIf(0.95)",
parameters=[
Column("value"),
Function(
"equals",
parameters=[Column("metric_id"), metric_id],
),
],
),
1,
],
alias="percentile_transaction_duration__95",
)
]
assert snql_query.query.where == [
Condition(Column("org_id"), Op.EQ, self.organization.id),
Condition(Column("project_id"), Op.IN, [self.project.id]),
Condition(Column("metric_id"), Op.IN, [metric_id]),
]
def test_get_entity_subscription_for_performance_metrics_dataset_with_custom_metric_and_metrics_layer(
self,
) -> None:
mri = "d:custom/sentry.process_profile.track_outcome@second"
indexer.record(use_case_id=UseCaseID.CUSTOM, org_id=self.organization.id, string=mri)
with Feature("organizations:use-metrics-layer-in-alerts"):
aggregate = f"max({mri})"
entity_subscription = get_entity_subscription(
query_type=SnubaQuery.Type.PERFORMANCE,
dataset=Dataset.PerformanceMetrics,
aggregate=aggregate,
time_window=3600,
extra_fields={"org_id": self.organization.id},
)
assert isinstance(entity_subscription, PerformanceMetricsEntitySubscription)
assert entity_subscription.aggregate == aggregate
assert entity_subscription.get_entity_extra_params() == {
"organization": self.organization.id,
"granularity": 60,
}
assert entity_subscription.dataset == Dataset.PerformanceMetrics
snql_query = entity_subscription.build_query_builder(
"",
[self.project.id],
None,
{
"organization_id": self.organization.id,
},
).get_snql_query()
metric_id = resolve(UseCaseID.CUSTOM, self.organization.id, mri)
assert snql_query.query.select == [
Function(
"maxIf",
parameters=[
Column(
"value",
),
Function(
"equals",
parameters=[
Column("metric_id"),
10000,
],
alias=None,
),
],
alias="max_d_custom_sentry_process_profile_track_outcome_second",
)
]
assert snql_query.query.where == [
Condition(Column("org_id"), Op.EQ, self.organization.id),
Condition(Column("project_id"), Op.IN, [self.project.id]),
Condition(Column("metric_id"), Op.IN, [metric_id]),
]
def test_get_entity_subscription_with_multiple_entities_with_metrics_layer(
self,
) -> None:
with Feature("organizations:use-metrics-layer-in-alerts"):
aggregate = "percentile(transaction.duration,.95)"
entity_subscription = get_entity_subscription(
query_type=SnubaQuery.Type.PERFORMANCE,
dataset=Dataset.PerformanceMetrics,
aggregate=aggregate,
time_window=3600,
extra_fields={"org_id": self.organization.id},
)
with patch(
"sentry.snuba.entity_subscription.PerformanceMetricsEntitySubscription.get_snql_aggregations",
# We have two aggregates on the metrics dataset but one with generic_metrics_sets and the other with
# generic_metrics_distributions.
return_value=[aggregate, "count_unique(user)"],
):
with pytest.raises(IncompatibleMetricsQuery):
entity_subscription.build_query_builder(
"",
[self.project.id],
None,
{"organization_id": self.organization.id},
).get_snql_query()
def test_get_entity_subscription_for_events_dataset(self) -> None:
aggregate = "count_unique(user)"
entity_subscription = get_entity_subscription(
query_type=SnubaQuery.Type.ERROR,
dataset=Dataset.Events,
aggregate=aggregate,
time_window=3600,
)
assert isinstance(entity_subscription, EventsEntitySubscription)
assert entity_subscription.aggregate == aggregate
assert entity_subscription.get_entity_extra_params() == {}
assert entity_subscription.dataset == Dataset.Events
entity = Entity(Dataset.Events.value, alias=Dataset.Events.value)
with self.feature("organizations:metric-alert-ignore-archived"):
snql_query = entity_subscription.build_query_builder(
"release:latest", [self.project.id], None
).get_snql_query()
assert snql_query.query.select == [
Function(
function="uniq",
parameters=[Column(name="tags[sentry:user]", entity=entity)],
alias="count_unique_user",
)
]
assert snql_query.query.where == [
And(
[
Condition(Column("type", entity=entity), Op.EQ, "error"),
Condition(
Function(
function="ifNull",
parameters=[Column(name="tags[sentry:release]", entity=entity), ""],
),
Op.IN,
[""],
),
]
),
Condition(Column("project_id", entity=entity), Op.IN, [self.project.id]),
]
def test_get_entity_subscription_for_events_dataset_with_join(self) -> None:
aggregate = "count_unique(user)"
entity_subscription = get_entity_subscription(
query_type=SnubaQuery.Type.ERROR,
dataset=Dataset.Events,
aggregate=aggregate,
time_window=3600,
)
assert isinstance(entity_subscription, EventsEntitySubscription)
assert entity_subscription.aggregate == aggregate
assert entity_subscription.get_entity_extra_params() == {}
assert entity_subscription.dataset == Dataset.Events
e_entity = Entity(Dataset.Events.value, alias=Dataset.Events.value)
g_entity = Entity("group_attributes", alias="ga")
with self.feature("organizations:metric-alert-ignore-archived"):
snql_query = entity_subscription.build_query_builder(
"status:unresolved", [self.project.id], None
).get_snql_query()
assert snql_query.query.match == Join([Relationship(e_entity, "attributes", g_entity)])
assert snql_query.query.select == [
Function(
function="uniq",
parameters=[Column(name="tags[sentry:user]", entity=e_entity)],
alias="count_unique_user",
)
]
assert snql_query.query.where == [
And(
[
Condition(Column("type", entity=e_entity), Op.EQ, "error"),
Condition(
Column("group_status", entity=g_entity), Op.IN, [GroupStatus.UNRESOLVED]
),
]
),
Condition(Column("project_id", entity=e_entity), Op.IN, [self.project.id]),
Condition(Column("project_id", entity=g_entity), Op.IN, [self.project.id]),
]
class GetEntitySubscriptionFromSnubaQueryTest(TestCase):
def test(self):
cases = [
(EventsEntitySubscription, SnubaQuery.Type.ERROR, Dataset.Events, "count()"),
(
PerformanceTransactionsEntitySubscription,
SnubaQuery.Type.PERFORMANCE,
Dataset.Transactions,
"count()",
),
(
PerformanceMetricsEntitySubscription,
SnubaQuery.Type.PERFORMANCE,
Dataset.Metrics,
"count()",
),
(
PerformanceMetricsEntitySubscription,
SnubaQuery.Type.PERFORMANCE,
Dataset.PerformanceMetrics,
"count()",
),
(
PerformanceMetricsEntitySubscription,
SnubaQuery.Type.PERFORMANCE,
Dataset.Metrics,
"count_unique(user)",
),
(
PerformanceMetricsEntitySubscription,
SnubaQuery.Type.PERFORMANCE,
Dataset.PerformanceMetrics,
"count_unique(user)",
),
(
PerformanceMetricsEntitySubscription,
SnubaQuery.Type.PERFORMANCE,
Dataset.PerformanceMetrics,
"max(d:custom/sentry.process_profile.track_outcome@second)",
),
(
MetricsCountersEntitySubscription,
SnubaQuery.Type.CRASH_RATE,
Dataset.Metrics,
"percentage(sessions_crashed, sessions) AS _crash_rate_alert_aggregate",
),
(
MetricsSetsEntitySubscription,
SnubaQuery.Type.CRASH_RATE,
Dataset.Metrics,
"percentage(users_crashed, users) AS _crash_rate_alert_aggregate",
),
]
for expected_entity_subscription, query_type, dataset, aggregate in cases:
snuba_query = SnubaQuery.objects.create(
time_window=60,
type=query_type.value,
dataset=dataset.value,
aggregate=aggregate,
resolution=5,
)
assert isinstance(
get_entity_subscription_from_snuba_query(snuba_query, self.organization.id),
expected_entity_subscription,
)
class GetEntityKeyFromSnubaQueryTest(TestCase):
def test(self):
cases = [
(EntityKey.Events, SnubaQuery.Type.ERROR, Dataset.Events, "count()", "", True, True),
(
EntityKey.Transactions,
SnubaQuery.Type.PERFORMANCE,
Dataset.Transactions,
"count()",
"",
True,
True,
),
(
EntityKey.GenericMetricsDistributions,
SnubaQuery.Type.PERFORMANCE,
Dataset.Metrics,
"count()",
"",
True,
True,
),
(
EntityKey.GenericMetricsSets,
SnubaQuery.Type.PERFORMANCE,
Dataset.Metrics,
"count_unique(user)",
"",
True,
True,
),
(
EntityKey.GenericMetricsDistributions,
SnubaQuery.Type.PERFORMANCE,
Dataset.PerformanceMetrics,
"count()",
"",
True,
True,
),
(
EntityKey.GenericMetricsSets,
SnubaQuery.Type.PERFORMANCE,
Dataset.PerformanceMetrics,
"count_unique(user)",
"",
True,
True,
),
(
EntityKey.GenericMetricsCounters,
SnubaQuery.Type.PERFORMANCE,
Dataset.PerformanceMetrics,
"sum(c:custom/sentry.process_profile.track_outcome@second)",
"",
# Custom metrics are not supported when the metrics layer integration with mqb is disabled.
False,
True,
),
(
EntityKey.GenericMetricsDistributions,
SnubaQuery.Type.PERFORMANCE,
Dataset.PerformanceMetrics,
"max(d:custom/sentry.process_profile.track_outcome@second)",
"",
# Custom metrics are not supported when the metrics layer integration with mqb is disabled.
False,
True,
),
(
EntityKey.GenericMetricsSets,
SnubaQuery.Type.PERFORMANCE,
Dataset.PerformanceMetrics,
"count_unique(s:custom/sentry.process_profile.track_outcome@second)",
"",
# Custom metrics are not supported when the metrics layer integration with mqb is disabled.
False,
True,
),
(
EntityKey.GenericMetricsGauges,
SnubaQuery.Type.PERFORMANCE,
Dataset.PerformanceMetrics,
"last(g:custom/sentry.process_profile.track_outcome@second)",
"",
# Custom metrics are not supported when the metrics layer integration with mqb is disabled.
False,
True,
),
(
EntityKey.MetricsCounters,
SnubaQuery.Type.CRASH_RATE,
Dataset.Metrics,
"percentage(sessions_crashed, sessions) AS _crash_rate_alert_aggregate",
"",
True,
True,
),
(
EntityKey.MetricsSets,
SnubaQuery.Type.CRASH_RATE,
Dataset.Metrics,
"percentage(users_crashed, users) AS _crash_rate_alert_aggregate",
"",
True,
True,
),
]
for (
expected_entity_key,
query_type,
dataset,
aggregate,
query,
supported_with_no_metrics_layer,
supported_with_metrics_layer,
) in cases:
snuba_query = SnubaQuery.objects.create(
time_window=60,
type=query_type.value,
dataset=dataset.value,
aggregate=aggregate,
query=query,
resolution=5,
)
if supported_with_no_metrics_layer:
assert expected_entity_key == get_entity_key_from_snuba_query(
snuba_query, self.organization.id, self.project.id
)
if supported_with_metrics_layer:
with Feature("organizations:use-metrics-layer-in-alerts"):
assert expected_entity_key == get_entity_key_from_snuba_query(
snuba_query, self.organization.id, self.project.id
)