123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962 |
- from __future__ import annotations
- from typing import Any, Protocol
- from django.http.response import HttpResponse
- from django.urls import reverse
- from sentry.discover.models import MAX_TEAM_KEY_TRANSACTIONS, TeamKeyTransaction
- from sentry.models.projectteam import ProjectTeam
- from sentry.testutils.cases import APITestCase, SnubaTestCase
- from sentry.testutils.helpers import parse_link_header
- from sentry.testutils.helpers.pagination import override_pagination_limit
- from sentry.testutils.silo import region_silo_test
- from sentry.utils.samples import load_data
- class TeamKeyTransactionTestBase(APITestCase, SnubaTestCase):
- def setUp(self):
- super().setUp()
- self.login_as(user=self.user, superuser=False)
- self.org = self.create_organization(owner=self.user, name="foo")
- self.project = self.create_project(name="baz", organization=self.org)
- self.event_data = load_data("transaction")
- self.features = ["organizations:performance-view"]
- class ClientCallable(Protocol):
- def __call__(self, url: str, data: dict[str, Any], format: str, **kwargs: Any) -> HttpResponse:
- ...
- @region_silo_test
- class TeamKeyTransactionTest(TeamKeyTransactionTestBase):
- def setUp(self):
- super().setUp()
- self.url = reverse("sentry-api-0-organization-key-transactions", args=[self.org.slug])
- def test_key_transaction_without_feature(self):
- project = self.create_project(name="qux", organization=self.org)
- data = {
- "project": [self.project.id, project.id],
- "transaction": self.event_data["transaction"],
- "team": "myteams",
- }
- for response in (
- self.client.get(self.url, data=data, format="json"),
- self.client.post(self.url, data=data, format="json"),
- self.client.delete(self.url, data=data, format="json"),
- ):
- assert response.status_code == 404, response.content
- def test_get_key_transaction_multiple_projects(self):
- project = self.create_project(name="qux", organization=self.org)
- with self.feature(self.features):
- response = self.client.get(
- self.url,
- data={
- "project": [self.project.id, project.id],
- "transaction": self.event_data["transaction"],
- },
- format="json",
- )
- assert response.status_code == 400, response.content
- assert response.data == {"detail": "Only 1 project per Key Transaction"}
- def test_get_key_transaction_no_transaction_name(self):
- with self.feature(self.features):
- response = self.client.get(
- self.url,
- data={
- "project": [self.project.id],
- },
- format="json",
- )
- assert response.status_code == 400, response.content
- assert response.data == {"detail": "A transaction name is required"}
- def test_get_no_key_transaction(self):
- with self.feature(self.features):
- response = self.client.get(
- self.url,
- data={
- "project": [self.project.id],
- "transaction": self.event_data["transaction"],
- },
- format="json",
- )
- assert response.status_code == 200, response.content
- assert response.data == []
- def test_get_key_transaction_my_teams(self):
- team1 = self.create_team(organization=self.org, name="Team A")
- team2 = self.create_team(organization=self.org, name="Team B")
- team3 = self.create_team(organization=self.org, name="Team C")
- # should not be in response because we never joined this team
- self.create_team(organization=self.org, name="Team D")
- # only join teams 1,2,3
- for team in [team1, team2, team3]:
- self.create_team_membership(team, user=self.user)
- self.project.add_team(team)
- TeamKeyTransaction.objects.bulk_create(
- [
- TeamKeyTransaction(
- organization=self.org,
- project_team=project_team,
- transaction=self.event_data["transaction"],
- )
- for project_team in ProjectTeam.objects.filter(
- project=self.project, team__in=[team1, team2]
- )
- ]
- + [
- TeamKeyTransaction(
- organization=self.org,
- project_team=project_team,
- transaction="other-transaction",
- )
- for project_team in ProjectTeam.objects.filter(
- project=self.project, team__in=[team2, team3]
- )
- ]
- )
- with self.feature(self.features):
- response = self.client.get(
- self.url,
- data={
- "project": [self.project.id],
- "transaction": self.event_data["transaction"],
- "team": "myteams",
- },
- format="json",
- )
- assert response.status_code == 200, response.content
- assert response.data == [
- {
- "team": str(team1.id),
- },
- {
- "team": str(team2.id),
- },
- ]
- def test_post_key_transaction_more_than_1_project(self):
- team = self.create_team(organization=self.org, name="Team Foo")
- self.create_team_membership(team, user=self.user)
- self.project.add_team(team)
- project = self.create_project(name="bar", organization=self.org)
- project.add_team(team)
- with self.feature(self.features):
- response = self.client.post(
- self.url,
- data={
- "project": [self.project.id, project.id],
- "transaction": self.event_data["transaction"],
- "team": [team.id],
- },
- format="json",
- )
- assert response.status_code == 400, response.content
- assert response.data == {"detail": "Only 1 project per Key Transaction"}
- def test_post_key_transaction_no_team(self):
- team = self.create_team(organization=self.org, name="Team Foo")
- self.create_team_membership(team, user=self.user)
- self.project.add_team(team)
- with self.feature(self.features):
- response = self.client.post(
- self.url,
- data={
- "project": [self.project.id],
- "transaction": self.event_data["transaction"],
- },
- format="json",
- )
- assert response.status_code == 400, response.content
- assert response.data == {"team": ["This field is required."]}
- def test_post_key_transaction_no_transaction_name(self):
- team = self.create_team(organization=self.org, name="Team Foo")
- self.create_team_membership(team, user=self.user)
- self.project.add_team(team)
- with self.feature(self.features):
- response = self.client.post(
- self.url,
- data={
- "project": [self.project.id],
- "team": [team.id],
- },
- format="json",
- )
- assert response.status_code == 400, response.content
- assert response.data == {"transaction": ["This field is required."]}
- def test_post_key_transaction_no_access_team(self):
- org = self.create_organization(
- owner=self.user, # use other user as owner
- name="foo",
- flags=0, # disable default allow_joinleave
- )
- project = self.create_project(name="baz", organization=org)
- user = self.create_user()
- self.login_as(user=user, superuser=False)
- team = self.create_team(organization=org, name="Team Foo")
- self.create_team_membership(team, user=user)
- project.add_team(team)
- other_team = self.create_team(organization=org, name="Team Bar")
- project.add_team(other_team)
- with self.feature(self.features):
- response = self.client.post(
- reverse("sentry-api-0-organization-key-transactions", args=[org.slug]),
- data={
- "project": [project.id],
- "transaction": self.event_data["transaction"],
- "team": [other_team.id],
- },
- format="json",
- )
- assert response.status_code == 400, response.content
- assert response.data == {
- "team": [f"You do not have permission to access {other_team.name}"]
- }
- def test_post_key_transaction_no_access_project(self):
- team1 = self.create_team(organization=self.org, name="Team Foo")
- self.create_team_membership(team1, user=self.user)
- self.project.add_team(team1)
- team2 = self.create_team(organization=self.org, name="Team Bar")
- self.create_team_membership(team2, user=self.user)
- with self.feature(self.features):
- response = self.client.post(
- self.url,
- data={
- "project": [self.project.id],
- "transaction": self.event_data["transaction"],
- "team": [team2.id],
- },
- format="json",
- )
- assert response.status_code == 400, response.content
- assert response.data == {"detail": "Team does not have access to project"}
- def test_post_key_transactions_exceed_limit(self):
- team = self.create_team(organization=self.org, name="Team Foo")
- self.create_team_membership(team, user=self.user)
- self.project.add_team(team)
- project_team = ProjectTeam.objects.get(project=self.project, team=team)
- TeamKeyTransaction.objects.bulk_create(
- [
- TeamKeyTransaction(
- organization=self.org,
- project_team=project_team,
- transaction=f"{self.event_data['transaction']}-{i}",
- )
- for i in range(MAX_TEAM_KEY_TRANSACTIONS)
- ]
- )
- with self.feature(self.features):
- response = self.client.post(
- self.url,
- data={
- "project": [self.project.id],
- "transaction": self.event_data["transaction"],
- "team": [team.id],
- },
- format="json",
- )
- assert response.status_code == 400, response.content
- assert response.data == {
- "non_field_errors": [
- f"At most {MAX_TEAM_KEY_TRANSACTIONS} Key Transactions can be added for a team"
- ]
- }
- def test_post_key_transaction_limit_is_per_team(self):
- team1 = self.create_team(organization=self.org, name="Team Foo")
- self.create_team_membership(team1, user=self.user)
- self.project.add_team(team1)
- team2 = self.create_team(organization=self.org, name="Team Bar")
- self.create_team_membership(team2, user=self.user)
- self.project.add_team(team2)
- project_teams = ProjectTeam.objects.filter(project=self.project, team__in=[team1, team2])
- TeamKeyTransaction.objects.bulk_create(
- [
- TeamKeyTransaction(
- organization=self.org,
- project_team=project_team,
- transaction=f"{self.event_data['transaction']}-{i}",
- )
- for project_team in project_teams
- for i in range(MAX_TEAM_KEY_TRANSACTIONS - 1)
- ]
- )
- with self.feature(self.features):
- response = self.client.post(
- self.url,
- data={
- "project": [self.project.id],
- "transaction": self.event_data["transaction"],
- "team": [team1.id, team2.id],
- },
- format="json",
- )
- assert response.status_code == 201, response.content
- key_transactions = TeamKeyTransaction.objects.filter(project_team__team__in=[team1, team2])
- assert len(key_transactions) == 2 * MAX_TEAM_KEY_TRANSACTIONS
- def test_post_key_transactions(self):
- team = self.create_team(organization=self.org, name="Team Foo")
- self.create_team_membership(team, user=self.user)
- self.project.add_team(team)
- with self.feature(self.features):
- response = self.client.post(
- self.url,
- data={
- "project": [self.project.id],
- "transaction": self.event_data["transaction"],
- "team": [team.id],
- },
- format="json",
- )
- assert response.status_code == 201, response.content
- key_transactions = TeamKeyTransaction.objects.filter(project_team__team=team)
- assert len(key_transactions) == 1
- def test_post_key_transactions_duplicate(self):
- team = self.create_team(organization=self.org, name="Team Foo")
- self.create_team_membership(team, user=self.user)
- self.project.add_team(team)
- project_team = ProjectTeam.objects.get(project=self.project, team=team)
- TeamKeyTransaction.objects.create(
- organization=self.org,
- project_team=project_team,
- transaction=self.event_data["transaction"],
- )
- with self.feature(self.features):
- response = self.client.post(
- self.url,
- data={
- "project": [self.project.id],
- "transaction": self.event_data["transaction"],
- "team": [team.id],
- },
- format="json",
- )
- assert response.status_code == 204, response.content
- key_transactions = TeamKeyTransaction.objects.filter(
- project_team=project_team, transaction=self.event_data["transaction"]
- )
- assert len(key_transactions) == 1
- def test_post_key_transaction_multiple_team(self):
- team1 = self.create_team(organization=self.org, name="Team Foo")
- self.create_team_membership(team1, user=self.user)
- self.project.add_team(team1)
- team2 = self.create_team(organization=self.org, name="Team Bar")
- self.create_team_membership(team2, user=self.user)
- self.project.add_team(team2)
- with self.feature(self.features):
- response = self.client.post(
- self.url,
- data={
- "project": [self.project.id],
- "transaction": self.event_data["transaction"],
- "team": [team1.id, team2.id],
- },
- format="json",
- )
- assert response.status_code == 201, response.content
- key_transactions = TeamKeyTransaction.objects.filter(
- project_team__in=ProjectTeam.objects.filter(
- project=self.project, team__in=[team1, team2]
- ),
- transaction=self.event_data["transaction"],
- )
- assert len(key_transactions) == 2
- def test_post_key_transaction_partially_existing_teams(self):
- team1 = self.create_team(organization=self.org, name="Team Foo")
- self.create_team_membership(team1, user=self.user)
- self.project.add_team(team1)
- team2 = self.create_team(organization=self.org, name="Team Bar")
- self.create_team_membership(team2, user=self.user)
- self.project.add_team(team2)
- TeamKeyTransaction.objects.create(
- organization=self.org,
- project_team=ProjectTeam.objects.get(project=self.project, team=team1),
- transaction=self.event_data["transaction"],
- )
- with self.feature(self.features):
- response = self.client.post(
- self.url,
- data={
- "project": [self.project.id],
- "transaction": self.event_data["transaction"],
- "team": [team1.id, team2.id],
- },
- format="json",
- )
- assert response.status_code == 201, response.content
- key_transactions = TeamKeyTransaction.objects.filter(
- project_team__in=ProjectTeam.objects.filter(
- project=self.project, team__in=[team1, team2]
- ),
- transaction=self.event_data["transaction"],
- )
- assert len(key_transactions) == 2
- def test_post_key_transaction_multiple_users(self):
- team = self.create_team(organization=self.org, name="Team Foo")
- self.create_team_membership(team, user=self.user)
- self.project.add_team(team)
- with self.feature(self.features):
- response = self.client.post(
- self.url,
- data={
- "project": [self.project.id],
- "transaction": self.event_data["transaction"],
- "team": [team.id],
- },
- format="json",
- )
- assert response.status_code == 201, response.content
- with self.feature(self.features):
- response = self.client.post(
- self.url,
- data={
- "project": [self.project.id],
- "transaction": self.event_data["transaction"],
- "team": [team.id],
- },
- format="json",
- )
- # already created by this user, so it's 204 this time
- assert response.status_code == 204, response.content
- user = self.create_user()
- self.create_member(user=user, organization=self.org, role="member")
- self.create_team_membership(team, user=user)
- self.login_as(user=user, superuser=False)
- with self.feature(self.features):
- response = self.client.post(
- self.url,
- data={
- "project": [self.project.id],
- "transaction": self.event_data["transaction"],
- "team": [team.id],
- },
- format="json",
- )
- # already created by another user, so it's 204 this time
- assert response.status_code == 204, response.content
- # should only create 1 team key transaction
- key_transactions = TeamKeyTransaction.objects.filter(project_team__team=team)
- assert len(key_transactions) == 1
- def test_post_key_transaction_overly_long_transaction(self):
- team = self.create_team(organization=self.org, name="Team Foo")
- self.create_team_membership(team, user=self.user)
- self.project.add_team(team)
- with self.feature(self.features):
- response = self.client.post(
- self.url,
- data={
- "project": [self.project.id],
- "transaction": "a" * 500,
- "team": [team.id],
- },
- format="json",
- )
- assert response.status_code == 400, response.content
- assert response.data == {
- "transaction": ["Ensure this field has no more than 200 characters."]
- }
- def test_delete_key_transaction_no_transaction_name(self):
- team = self.create_team(organization=self.org, name="Team Foo")
- self.create_team_membership(team, user=self.user)
- self.project.add_team(team)
- with self.feature(self.features):
- response = self.client.delete(
- self.url,
- data={
- "project": [self.project.id],
- "team": [team.id],
- },
- format="json",
- )
- assert response.status_code == 400, response.content
- assert response.data == {"transaction": ["This field is required."]}
- def test_delete_key_transaction_no_team(self):
- team = self.create_team(organization=self.org, name="Team Foo")
- self.create_team_membership(team, user=self.user)
- self.project.add_team(team)
- with self.feature(self.features):
- response = self.client.delete(
- self.url,
- data={
- "project": [self.project.id],
- "transaction": self.event_data["transaction"],
- },
- format="json",
- )
- assert response.status_code == 400, response.content
- assert response.data == {"team": ["This field is required."]}
- def test_delete_key_transactions_no_exist(self):
- team = self.create_team(organization=self.org, name="Team Foo")
- self.create_team_membership(team, user=self.user)
- self.project.add_team(team)
- with self.feature(self.features):
- response = self.client.delete(
- self.url,
- data={
- "project": [self.project.id],
- "transaction": self.event_data["transaction"],
- "team": [team.id],
- },
- format="json",
- )
- assert response.status_code == 204, response.content
- key_transactions = TeamKeyTransaction.objects.filter(project_team__team=team)
- assert len(key_transactions) == 0
- def test_delete_key_transaction_no_access_team(self):
- org = self.create_organization(
- owner=self.user, # use other user as owner
- name="foo",
- flags=0, # disable default allow_joinleave
- )
- project = self.create_project(name="baz", organization=org)
- user = self.create_user()
- self.login_as(user=user, superuser=False)
- team = self.create_team(organization=org, name="Team Foo")
- self.create_team_membership(team, user=user)
- project.add_team(team)
- other_team = self.create_team(organization=org, name="Team Bar")
- project.add_team(other_team)
- TeamKeyTransaction.objects.create(
- organization=org,
- project_team=ProjectTeam.objects.get(project=project, team=team),
- transaction=self.event_data["transaction"],
- )
- with self.feature(self.features):
- response = self.client.delete(
- reverse("sentry-api-0-organization-key-transactions", args=[org.slug]),
- data={
- "project": [project.id],
- "transaction": self.event_data["transaction"],
- "team": [other_team.id],
- },
- format="json",
- )
- assert response.status_code == 400, response.content
- assert response.data == {
- "team": [f"You do not have permission to access {other_team.name}"]
- }
- def test_delete_key_transactions(self):
- team = self.create_team(organization=self.org, name="Team Foo")
- self.create_team_membership(team, user=self.user)
- self.project.add_team(team)
- TeamKeyTransaction.objects.create(
- organization=self.org,
- project_team=ProjectTeam.objects.get(project=self.project, team=team),
- transaction=self.event_data["transaction"],
- )
- with self.feature(self.features):
- response = self.client.delete(
- self.url,
- data={
- "project": [self.project.id],
- "transaction": self.event_data["transaction"],
- "team": [team.id],
- },
- format="json",
- )
- assert response.status_code == 204, response.content
- key_transactions = TeamKeyTransaction.objects.filter(project_team__team=team)
- assert len(key_transactions) == 0
- def test_delete_key_transaction_partially_existing_teams(self):
- team1 = self.create_team(organization=self.org, name="Team Foo")
- self.create_team_membership(team1, user=self.user)
- self.project.add_team(team1)
- team2 = self.create_team(organization=self.org, name="Team Bar")
- self.create_team_membership(team2, user=self.user)
- self.project.add_team(team2)
- TeamKeyTransaction.objects.create(
- organization=self.org,
- project_team=ProjectTeam.objects.get(project=self.project, team=team1),
- transaction=self.event_data["transaction"],
- )
- with self.feature(self.features):
- response = self.client.delete(
- self.url,
- data={
- "project": [self.project.id],
- "transaction": self.event_data["transaction"],
- "team": [team1.id, team2.id],
- },
- format="json",
- )
- assert response.status_code == 204, response.content
- @region_silo_test
- class TeamKeyTransactionListTest(TeamKeyTransactionTestBase):
- def setUp(self):
- super().setUp()
- self.url = reverse("sentry-api-0-organization-key-transactions-list", args=[self.org.slug])
- self.team1 = self.create_team(organization=self.org, name="Team A")
- self.team2 = self.create_team(organization=self.org, name="Team B")
- self.team3 = self.create_team(organization=self.org, name="Team C")
- self.team4 = self.create_team(organization=self.org, name="Team D")
- self.team5 = self.create_team(organization=self.org, name="Team E")
- for team in [self.team1, self.team2, self.team3, self.team4, self.team5]:
- self.project.add_team(team)
- # only join teams 1,2,3
- for team in [self.team1, self.team2, self.team3]:
- self.create_team_membership(team, user=self.user)
- TeamKeyTransaction.objects.bulk_create(
- [
- TeamKeyTransaction(
- organization=self.org,
- project_team=project_team,
- transaction=self.event_data["transaction"],
- )
- for project_team in ProjectTeam.objects.filter(
- project=self.project, team__in=[self.team2, self.team3]
- )
- ]
- + [
- TeamKeyTransaction(
- organization=self.org,
- project_team=project_team,
- transaction="other-transaction",
- )
- for project_team in ProjectTeam.objects.filter(
- project=self.project, team__in=[self.team3, self.team4]
- )
- ]
- )
- def test_get_key_transaction_list_no_permissions(self):
- org = self.create_organization(
- owner=self.user, # use other user as owner
- name="foo",
- flags=0, # disable default allow_joinleave
- )
- project = self.create_project(name="baz", organization=org)
- user = self.create_user()
- self.login_as(user=user, superuser=False)
- team = self.create_team(organization=org, name="Team Foo")
- self.create_team_membership(team, user=user)
- project.add_team(team)
- other_team = self.create_team(organization=org, name="Team Bar")
- project.add_team(other_team)
- with self.feature(self.features):
- response = self.client.get(
- reverse("sentry-api-0-organization-key-transactions-list", args=[org.slug]),
- data={
- "project": [self.project.id],
- "team": ["myteams", other_team.id],
- },
- format="json",
- )
- assert response.status_code == 403, response.content
- assert response.data == {
- "detail": f"Error: You do not have permission to access {other_team.name}"
- }
- def test_get_key_transaction_list_my_teams(self):
- with self.feature(self.features):
- response = self.client.get(
- self.url,
- data={
- "project": [self.project.id],
- "team": ["myteams"],
- },
- format="json",
- )
- assert response.status_code == 200, response.content
- assert response.data == [
- {
- "team": str(self.team1.id),
- "count": 0,
- "keyed": [],
- },
- {
- "team": str(self.team2.id),
- "count": 1,
- "keyed": [
- {
- "project_id": str(self.project.id),
- "transaction": self.event_data["transaction"],
- },
- ],
- },
- {
- "team": str(self.team3.id),
- "count": 2,
- "keyed": [
- {
- "project_id": str(self.project.id),
- "transaction": self.event_data["transaction"],
- },
- {"project_id": str(self.project.id), "transaction": "other-transaction"},
- ],
- },
- ]
- def test_get_key_transaction_list_other_teams(self):
- with self.feature(self.features):
- response = self.client.get(
- self.url,
- data={
- "project": [self.project.id],
- "team": [self.team4.id, self.team5.id],
- },
- format="json",
- )
- assert response.status_code == 200, response.content
- assert response.data == [
- {
- "team": str(self.team4.id),
- "count": 1,
- "keyed": [
- {"project_id": str(self.project.id), "transaction": "other-transaction"},
- ],
- },
- {
- "team": str(self.team5.id),
- "count": 0,
- "keyed": [],
- },
- ]
- def test_get_key_transaction_list_mixed_my_and_other_teams(self):
- with self.feature(self.features):
- response = self.client.get(
- self.url,
- data={
- "project": [self.project.id],
- "team": ["myteams", self.team4.id, self.team5.id],
- },
- format="json",
- )
- assert response.status_code == 200, response.content
- assert response.data == [
- {
- "team": str(self.team1.id),
- "count": 0,
- "keyed": [],
- },
- {
- "team": str(self.team2.id),
- "count": 1,
- "keyed": [
- {
- "project_id": str(self.project.id),
- "transaction": self.event_data["transaction"],
- },
- ],
- },
- {
- "team": str(self.team3.id),
- "count": 2,
- "keyed": [
- {
- "project_id": str(self.project.id),
- "transaction": self.event_data["transaction"],
- },
- {"project_id": str(self.project.id), "transaction": "other-transaction"},
- ],
- },
- {
- "team": str(self.team4.id),
- "count": 1,
- "keyed": [
- {"project_id": str(self.project.id), "transaction": "other-transaction"},
- ],
- },
- {
- "team": str(self.team5.id),
- "count": 0,
- "keyed": [],
- },
- ]
- @override_pagination_limit(5)
- def test_get_key_transaction_list_pagination(self):
- user = self.create_user()
- self.login_as(user=user)
- org = self.create_organization(owner=user, name="foo")
- project = self.create_project(name="baz", organization=org)
- teams = []
- for i in range(8):
- team = self.create_team(organization=org, name=f"Team {i:02d}")
- self.create_team_membership(team, user=user)
- project.add_team(team)
- teams.append(team)
- # get the first page
- with self.feature(self.features):
- response = self.client.get(
- reverse("sentry-api-0-organization-key-transactions-list", args=[org.slug]),
- data={
- "project": [project.id],
- "team": ["myteams"],
- },
- format="json",
- )
- assert response.status_code == 200, response.content
- assert len(response.data) == 5
- links = {
- link["rel"]: {"url": url, **link}
- for url, link in parse_link_header(response["Link"]).items()
- }
- assert links["previous"]["results"] == "false"
- assert links["next"]["results"] == "true"
- # get the second page
- with self.feature(self.features):
- assert links["next"]["cursor"] is not None
- response = self.client.get(
- reverse("sentry-api-0-organization-key-transactions-list", args=[org.slug]),
- data={
- "project": [project.id],
- "team": ["myteams"],
- "cursor": links["next"]["cursor"],
- },
- format="json",
- )
- assert response.status_code == 200, response.content
- assert len(response.data) == 3
- links = {
- link["rel"]: {"url": url, **link}
- for url, link in parse_link_header(response["Link"]).items()
- }
- assert links["previous"]["results"] == "true"
- assert links["next"]["results"] == "false"
- def test_get_key_transaction_list_partial_project(self):
- another_project = self.create_project(organization=self.org)
- another_project.add_team(self.team2)
- TeamKeyTransaction.objects.create(
- organization=self.org,
- project_team=ProjectTeam.objects.get(project=another_project, team=self.team2),
- transaction="another-transaction",
- )
- with self.feature(self.features):
- response = self.client.get(
- self.url,
- data={
- "project": [another_project.id],
- "team": [self.team2.id],
- },
- format="json",
- )
- assert response.status_code == 200, response.content
- assert response.data == [
- {
- "team": str(self.team2.id),
- # the key transaction in self.project is counted but not in
- # the list because self.project is not in the project param
- "count": 2,
- "keyed": [
- {
- "project_id": str(another_project.id),
- "transaction": "another-transaction",
- },
- ],
- },
- ]
|