123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773 |
- import datetime
- import logging
- from timeit import default_timer as timer
- from django.contrib.postgres.search import SearchVector
- from django.db.models import F, Value
- from django.urls import reverse
- from django.utils import timezone
- from freezegun import freeze_time
- from model_bakery import baker
- from apps.event_ingest.model_functions import PipeConcat
- from glitchtip.test_utils.test_case import (
- APIPermissionTestCase,
- GlitchTestCase,
- )
- from ..constants import EventStatus, LogLevel
- from ..models import Issue
- logger = logging.getLogger(__name__)
- def get_issue_url(issue_id: int) -> str:
- return reverse("api:get_issue", kwargs={"issue_id": issue_id})
- def get_organization_issue_url(organization_slug: str, issue_id: int) -> str:
- return reverse(
- "api:update_organization_issue",
- kwargs={"organization_slug": organization_slug, "issue_id": issue_id},
- )
- class IssueAPITestCase(GlitchTestCase):
- @classmethod
- def setUpTestData(cls):
- cls.create_user()
- cls.list_url = reverse(
- "api:list_issues", kwargs={"organization_slug": cls.organization.slug}
- )
- def setUp(self):
- self.client.force_login(self.user)
- def test_retrieve(self):
- issue = baker.make("issue_events.Issue", project=self.project, short_id=1)
- event = baker.make("issue_events.IssueEvent", issue=issue)
- baker.make(
- "issue_events.UserReport",
- project=self.project,
- issue=issue,
- event_id=event.pk.hex,
- _quantity=1,
- )
- baker.make("issue_events.Comment", issue=issue, _quantity=3)
- url = reverse(
- "api:get_issue",
- kwargs={"issue_id": issue.id},
- )
- res = self.client.get(url)
- data = res.json()
- self.assertEqual(
- data.get("shortId"), f"{self.project.slug.upper()}-{issue.short_id}"
- )
- self.assertEqual(data.get("count"), str(issue.count))
- self.assertEqual(data.get("userReportCount"), 1)
- self.assertEqual(data.get("numComments"), 3)
- def test_list(self):
- res = self.client.get(self.list_url)
- self.assertEqual(res.status_code, 200)
- not_my_issue = baker.make("issue_events.Issue")
- issue = baker.make("issue_events.Issue", project=self.project, short_id=1)
- baker.make("issue_events.IssueEvent", issue=issue)
- res = self.client.get(self.list_url)
- self.assertContains(res, issue.title)
- self.assertNotContains(res, not_my_issue.title)
- self.assertEqual(len(res.json()), 1)
- def test_project_issue_list(self):
- not_my_project = baker.make("projects.Project", organization=self.organization)
- not_my_issue = baker.make("issue_events.Issue", project=not_my_project)
- issue = baker.make("issue_events.Issue", project=self.project, short_id=1)
- baker.make("issue_events.IssueEvent", issue=issue)
- url = reverse(
- "api:list_project_issues",
- kwargs={
- "organization_slug": self.organization.slug,
- "project_slug": self.project.slug,
- },
- )
- res = self.client.get(url)
- self.assertContains(res, issue.title)
- self.assertNotContains(res, not_my_issue.title)
- self.assertEqual(len(res.json()), 1)
- def test_filter_by_date(self):
- """
- A user should be able to filter by start and end datetimes.
- In the future, this should filter events, not first_seen.
- """
- issue1 = baker.make(
- "issue_events.Issue",
- first_seen=timezone.make_aware(timezone.datetime(1999, 1, 1)),
- project=self.project,
- )
- issue2 = baker.make(
- "issue_events.Issue",
- first_seen=timezone.make_aware(timezone.datetime(2010, 1, 1)),
- project=self.project,
- )
- issue3 = baker.make(
- "issue_events.Issue",
- first_seen=timezone.make_aware(timezone.datetime(2020, 1, 1)),
- project=self.project,
- )
- res = self.client.get(
- self.list_url
- + "?start=2000-01-01T05:00:00.000Z&end=2019-01-01T05:00:00.000Z"
- )
- self.assertContains(res, issue2.title)
- self.assertNotContains(res, issue1.title)
- self.assertNotContains(res, issue3.title)
- def test_sort(self):
- issue1 = baker.make("issue_events.Issue", project=self.project)
- issue2 = baker.make("issue_events.Issue", project=self.project, count=2)
- issue3 = baker.make("issue_events.Issue", project=self.project)
- res = self.client.get(self.list_url)
- self.assertEqual(res.json()[0]["id"], str(issue3.id))
- res = self.client.get(self.list_url + "?sort=-count")
- self.assertEqual(res.json()[0]["id"], str(issue2.id))
- res = self.client.get(self.list_url + "?sort=priority")
- self.assertEqual(res.json()[0]["id"], str(issue1.id))
- res = self.client.get(self.list_url + "?sort=-priority")
- self.assertEqual(res.json()[0]["id"], str(issue2.id))
- def test_search(self):
- issue = baker.make(
- "issue_events.Issue",
- project=self.project,
- search_vector=SearchVector(Value("apple sauce")),
- )
- event = baker.make("issue_events.IssueEvent", issue=issue)
- other_issue = baker.make("issue_events.Issue", project=self.project)
- res = self.client.get(self.list_url + "?query=is:unresolved apple+sauce")
- self.assertContains(res, issue.title)
- self.assertNotContains(res, other_issue.title)
- # Not sure how to do this in Ninja without always removing None field values
- # self.assertNotContains(res, "matchingEventId")
- self.assertNotIn("X-Sentry-Direct-Hit", res.headers)
- res = self.client.get(self.list_url + "?query=is:unresolved apple sauce")
- self.assertContains(res, issue.title)
- self.assertNotContains(res, other_issue.title)
- res = self.client.get(self.list_url + '?query=is:unresolved "apple sauce"')
- self.assertContains(res, issue.title)
- self.assertNotContains(res, other_issue.title)
- res = self.client.get(self.list_url + "?query=" + event.id.hex)
- self.assertContains(res, issue.title)
- self.assertNotContains(res, other_issue.title)
- self.assertContains(res, "matchingEventId")
- self.assertContains(res, event.id.hex)
- self.assertEqual(res.headers.get("X-Sentry-Direct-Hit"), "1")
- event3 = baker.make(
- "issue_events.IssueEvent", issue=issue, data={"name": "plum sauce"}
- )
- Issue.objects.filter(id=issue.id).update(
- search_vector=SearchVector(
- PipeConcat(F("search_vector"), SearchVector(Value(event3.data["name"])))
- )
- )
- issue.search_vector = SearchVector(Value("apple sauce plum "))
- res = self.client.get(self.list_url + '?query=is:unresolved "plum sauce"')
- self.assertContains(res, event3.issue.title)
- res = self.client.get(self.list_url + '?query=is:unresolved "apple sauce"')
- self.assertContains(res, event.issue.title)
- def test_list_relative_datetime_filter(self):
- now = timezone.now()
- last_minute = now - datetime.timedelta(minutes=1)
- with freeze_time(last_minute):
- baker.make("issue_events.IssueEvent", issue__project=self.project)
- two_minutes_ago = now - datetime.timedelta(minutes=2)
- with freeze_time(two_minutes_ago):
- baker.make("issue_events.IssueEvent", issue__project=self.project)
- yesterday = now - datetime.timedelta(days=1)
- with freeze_time(yesterday):
- baker.make("issue_events.IssueEvent", issue__project=self.project)
- url = self.list_url
- with freeze_time(now):
- res = self.client.get(url, {"start": "now-1m"})
- self.assertEqual(res.status_code, 200)
- self.assertEqual(len(res.json()), 1)
- with freeze_time(now):
- res = self.client.get(url, {"start": "now-2m"})
- self.assertEqual(res.status_code, 200)
- self.assertEqual(len(res.json()), 2)
- with freeze_time(now):
- res = self.client.get(url, {"start": "now-24h", "end": "now"})
- self.assertEqual(res.status_code, 200)
- self.assertEqual(len(res.json()), 3)
- with freeze_time(now):
- res = self.client.get(url, {"end": "now-3m"})
- self.assertEqual(res.status_code, 200)
- self.assertEqual(len(res.json()), 1)
- def test_tag_space(self):
- tag_name = "os.name"
- tag_value = "Linux Vista"
- event = baker.make(
- "issue_events.IssueEvent",
- issue__project=self.project,
- tags={tag_name: tag_value, "foo": "bar"},
- )
- baker.make(
- "issue_events.IssueTag",
- issue=event.issue,
- tag_key__key=tag_name,
- tag_value__value=tag_value,
- )
- baker.make(
- "issue_events.IssueTag",
- issue=event.issue,
- tag_key__key="foo",
- tag_value__value="bar",
- )
- event2 = baker.make(
- "issue_events.IssueEvent",
- issue__project=self.project,
- tags={tag_name: "BananaOS 7"},
- )
- res = self.client.get(
- self.list_url + f'?query={tag_name}:"Linux+Vista" foo:bar'
- )
- self.assertContains(res, event.issue.title)
- self.assertNotContains(res, event2.issue.title)
- def test_filter_by_tag(self):
- tag_browser = "browser.name"
- tag_value_firefox = "Firefox"
- tag_value_chrome = "Chrome"
- tag_value_cthulhu = "Cthulhu"
- tag_mythic_animal = "mythic_animal"
- key_browser = baker.make("issue_events.TagKey", key=tag_browser)
- key_mythic_animal = baker.make("issue_events.TagKey", key=tag_mythic_animal)
- value_firefox = baker.make("issue_events.TagValue", value=tag_value_firefox)
- value_chrome = baker.make("issue_events.TagValue", value=tag_value_chrome)
- value_cthulhu = baker.make("issue_events.TagValue", value=tag_value_cthulhu)
- event_only_firefox = baker.make(
- "issue_events.IssueEvent",
- issue__project=self.project,
- tags={tag_browser: tag_value_firefox},
- )
- baker.make(
- "issue_events.IssueTag",
- issue=event_only_firefox.issue,
- tag_key=key_browser,
- tag_value=value_firefox,
- )
- event_only_firefox2 = baker.make(
- "issue_events.IssueEvent",
- issue=event_only_firefox.issue,
- tags={tag_mythic_animal: tag_value_cthulhu},
- )
- baker.make(
- "issue_events.IssueTag",
- issue=event_only_firefox2.issue,
- tag_key=key_mythic_animal,
- tag_value=value_cthulhu,
- )
- event_firefox_chrome = baker.make(
- "issue_events.IssueEvent",
- issue__project=self.project,
- tags={tag_browser: tag_value_firefox},
- )
- baker.make(
- "issue_events.IssueTag",
- issue=event_firefox_chrome.issue,
- tag_key=key_browser,
- tag_value=value_firefox,
- )
- event_firefox_chrome2 = baker.make(
- "issue_events.IssueEvent",
- issue=event_firefox_chrome.issue,
- tags={tag_browser: tag_value_chrome},
- )
- baker.make(
- "issue_events.IssueTag",
- issue=event_firefox_chrome2.issue,
- tag_key=key_browser,
- tag_value=value_chrome,
- )
- event_no_tags = baker.make(
- "issue_events.IssueEvent", issue__project=self.project
- )
- event_browser_chrome_mythic_animal_firefox = baker.make(
- "issue_events.IssueEvent",
- issue__project=self.project,
- tags={tag_mythic_animal: tag_value_firefox, tag_browser: tag_value_chrome},
- )
- baker.make(
- "issue_events.IssueTag",
- issue=event_browser_chrome_mythic_animal_firefox.issue,
- tag_key=key_mythic_animal,
- tag_value=value_firefox,
- )
- baker.make(
- "issue_events.IssueTag",
- issue=event_browser_chrome_mythic_animal_firefox.issue,
- tag_key=key_browser,
- tag_value=value_chrome,
- )
- url = self.list_url
- res = self.client.get(url + f'?query={tag_browser}:"{tag_value_firefox}"')
- self.assertContains(res, event_only_firefox.issue.title)
- self.assertContains(res, event_firefox_chrome.issue.title)
- self.assertNotContains(res, event_no_tags.issue.title)
- self.assertNotContains(
- res, event_browser_chrome_mythic_animal_firefox.issue.title
- )
- # Browser is Firefox AND Chrome
- res = self.client.get(
- url
- + f"?query={tag_browser}:{tag_value_firefox} {tag_browser}:{tag_value_chrome}"
- )
- self.assertNotContains(res, event_only_firefox.issue.title)
- self.assertContains(res, event_firefox_chrome.issue.title)
- self.assertNotContains(res, event_no_tags.issue.title)
- self.assertNotContains(
- res, event_browser_chrome_mythic_animal_firefox.issue.title
- )
- # Browser mythic_animal is Firefox
- res = self.client.get(url + f"?query={tag_mythic_animal}:{tag_value_firefox}")
- self.assertNotContains(res, event_only_firefox.issue.title)
- self.assertNotContains(res, event_firefox_chrome.issue.title)
- self.assertNotContains(res, event_no_tags.issue.title)
- self.assertContains(res, event_browser_chrome_mythic_animal_firefox.issue.title)
- # Browser is Chrome AND mythic_animal is Firefox
- res = self.client.get(
- url
- + f"?query={tag_browser}:{tag_value_chrome} {tag_mythic_animal}:{tag_value_firefox}"
- )
- self.assertNotContains(res, event_only_firefox.issue.title)
- self.assertNotContains(res, event_firefox_chrome.issue.title)
- self.assertNotContains(res, event_no_tags.issue.title)
- self.assertContains(res, event_browser_chrome_mythic_animal_firefox.issue.title)
- # Browser is Firefox AND mythic_animal is Firefox
- res = self.client.get(
- url
- + f"?query={tag_browser}:{tag_value_firefox} {tag_mythic_animal}:{tag_value_firefox}"
- )
- self.assertNotContains(res, event_only_firefox.issue.title)
- self.assertNotContains(res, event_firefox_chrome.issue.title)
- self.assertNotContains(res, event_no_tags.issue.title)
- self.assertNotContains(
- res, event_browser_chrome_mythic_animal_firefox.issue.title
- )
- def test_filter_by_tag_distinct(self):
- tag_browser = "browser.name"
- tag_value = "Firefox"
- tag_value2 = "Chrome"
- key_browser = baker.make("issue_events.TagKey", key=tag_browser)
- value = baker.make("issue_events.TagValue", value=tag_value)
- value2 = baker.make("issue_events.TagValue", value=tag_value2)
- event = baker.make(
- "issue_events.IssueEvent",
- issue__project=self.project,
- tags={tag_browser: tag_value},
- )
- baker.make(
- "issue_events.IssueTag",
- issue=event.issue,
- tag_key=key_browser,
- tag_value=value,
- )
- baker.make(
- "issue_events.IssueEvent",
- issue=event.issue,
- tags={tag_browser: tag_value},
- _quantity=2,
- )
- baker.make(
- "issue_events.IssueTag",
- issue=event.issue,
- tag_key=key_browser,
- tag_value=value,
- )
- baker.make(
- "issue_events.IssueEvent",
- issue=event.issue,
- tags={tag_browser: tag_value},
- _quantity=5,
- )
- baker.make(
- "issue_events.IssueTag",
- issue=event.issue,
- tag_key=key_browser,
- tag_value=value,
- )
- baker.make(
- "issue_events.IssueTag",
- issue=event.issue,
- tag_key=key_browser,
- tag_value=value2,
- )
- baker.make(
- "issue_events.IssueEvent",
- issue=event.issue,
- tags={tag_browser: tag_value2},
- _quantity=5,
- )
- baker.make(
- "issue_events.IssueTag",
- issue=event.issue,
- tag_key=key_browser,
- tag_value=value2,
- )
- res = self.client.get(self.list_url + f'?query={tag_browser}:"{tag_value}"')
- self.assertEqual(len(res.json()), 1)
- def test_filter_environment(self):
- environment1_name = "prod"
- environment2_name = "staging"
- key_environment = baker.make("issue_events.TagKey", key="environment")
- environment1_value = baker.make(
- "issue_events.TagValue", value=environment1_name
- )
- environment2_value = baker.make(
- "issue_events.TagValue", value=environment2_name
- )
- environment3_value = baker.make("issue_events.TagValue", value="dev")
- issue1 = baker.make(
- "issue_events.Issue",
- project=self.project,
- )
- baker.make(
- "issue_events.IssueTag",
- issue=issue1,
- tag_key=key_environment,
- tag_value=environment1_value,
- )
- issue2 = baker.make(
- "issue_events.Issue",
- project=self.project,
- )
- baker.make(
- "issue_events.IssueTag",
- issue=issue2,
- tag_key=key_environment,
- tag_value=environment2_value,
- )
- issue3 = baker.make("issue_events.Issue", project=self.project)
- baker.make(
- "issue_events.IssueTag",
- issue=issue3,
- tag_key=key_environment,
- tag_value=environment3_value,
- )
- res = self.client.get(
- self.list_url
- + f"?environment={environment1_name}&environment={environment2_name}"
- )
- data = res.json()
- self.assertEqual(len(data), 2)
- self.assertNotIn(str(issue3.id), [data[0]["id"], data[1]["id"]])
- def test_filter_by_level(self):
- """
- A user should be able to filter by issue levels.
- """
- level_warning = LogLevel.WARNING
- level_fatal = LogLevel.FATAL
- issue1 = baker.make(
- "issue_events.Issue", project=self.project, level=level_warning
- )
- issue2 = baker.make(
- "issue_events.Issue", project=self.project, level=level_fatal
- )
- baker.make("issue_events.Issue", project=self.project)
- res = self.client.get(self.list_url + f"?query=level:{level_warning.label}")
- data = res.json()
- self.assertEqual(len(data), 1)
- self.assertEqual(data[0]["id"], str(issue1.id))
- res = self.client.get(self.list_url + f"?query=level:{level_fatal.label}")
- data = res.json()
- self.assertEqual(len(data), 1)
- self.assertEqual(data[0]["id"], str(issue2.id))
- res = self.client.get(self.list_url)
- self.assertEqual(len(res.json()), 3)
- def test_issue_delete(self):
- issue = baker.make("issue_events.Issue", project=self.project)
- not_my_issue = baker.make("issue_events.Issue")
- res = self.client.delete(get_issue_url(issue.id))
- self.assertEqual(res.status_code, 204)
- res = self.client.delete(get_issue_url(not_my_issue.id))
- self.assertEqual(res.status_code, 404)
- def test_issue_update(self):
- issue = baker.make("issue_events.Issue", project=self.project)
- self.assertEqual(issue.status, EventStatus.UNRESOLVED)
- data = {"status": "resolved"}
- res = self.client.put(
- get_organization_issue_url(self.organization.slug, issue.pk),
- data,
- content_type="application/json",
- )
- self.assertEqual(res.status_code, 200)
- issue.refresh_from_db()
- self.assertEqual(issue.status, EventStatus.RESOLVED)
- def test_bulk_update(self):
- """Bulk update only supports Issue status"""
- issues = baker.make("issue_events.Issue", project=self.project, _quantity=2)
- url = f"{self.list_url}?id={issues[0].id}&id={issues[1].id}"
- status_to_set = EventStatus.RESOLVED
- data = {"status": status_to_set.label}
- res = self.client.put(url, data, content_type="application/json")
- self.assertContains(res, status_to_set.label)
- issues = Issue.objects.all()
- self.assertEqual(issues[0].status, status_to_set)
- self.assertEqual(issues[1].status, status_to_set)
- def test_bulk_delete_via_ids(self):
- """Bulk delete Issues with ids"""
- issues = baker.make("issue_events.Issue", project=self.project, _quantity=2)
- url = f"{self.list_url}?id={issues[0].id}&id={issues[1].id}"
- self.client.delete(url)
- issues = Issue.objects.all().count()
- self.assertEqual(issues, 0)
- def test_bulk_delete_via_search(self):
- """Bulk delete Issues via search string"""
- project2 = baker.make("projects.Project", organization=self.organization)
- project2.teams.add(self.team)
- issue1 = baker.make(Issue, project=self.project)
- issue2 = baker.make(Issue, project=project2)
- url = f"{self.list_url}?query=is:unresolved&project={self.project.id}"
- self.client.delete(url)
- self.assertFalse(Issue.objects.filter(id=issue1.id).exists())
- self.assertTrue(Issue.objects.filter(id=issue2.id).exists())
- def test_bulk_update_query(self):
- """Bulk update only supports Issue status"""
- project2 = baker.make("projects.Project", organization=self.organization)
- project2.teams.add(self.team)
- issue1 = baker.make(Issue, project=self.project)
- issue2 = baker.make(Issue, project=project2)
- url = f"{self.list_url}?query=is:unresolved&project={self.project.id}"
- status_to_set = EventStatus.RESOLVED
- data = {"status": status_to_set.label}
- res = self.client.put(url, data, content_type="application/json")
- self.assertContains(res, status_to_set.label)
- issue1.refresh_from_db()
- issue2.refresh_from_db()
- self.assertEqual(issue1.status, status_to_set)
- self.assertEqual(issue2.status, EventStatus.UNRESOLVED)
- class IssueEventAPIPermissionTestCase(APIPermissionTestCase):
- def setUp(self):
- self.create_org_team_project()
- self.set_client_credentials(self.auth_token.token)
- self.issue = baker.make("issue_events.Issue", project=self.project)
- self.list_url = reverse(
- "api:list_issues", kwargs={"organization_slug": self.organization.slug}
- )
- def test_list(self):
- self.assertGetReqStatusCode(self.list_url, 403)
- self.auth_token.add_permission("event:read")
- self.assertGetReqStatusCode(self.list_url, 200)
- class IssueEventTagsAPITestCase(GlitchTestCase):
- @classmethod
- def setUpTestData(cls):
- cls.create_user()
- def setUp(self):
- self.client.force_login(self.user)
- def get_url(self, issue_id: int) -> str:
- return reverse("api:list_issue_tags", kwargs={"issue_id": issue_id})
- def test_issue_tags(self):
- issue = baker.make("issue_events.Issue", project=self.project)
- key_foo = baker.make("issue_events.TagKey", key="foo")
- key_animal = baker.make("issue_events.TagKey", key="animal")
- value_bar = baker.make("issue_events.TagValue", value="bar")
- value_cat = baker.make("issue_events.TagValue", value="cat")
- value_dog = baker.make("issue_events.TagValue", value="dog")
- baker.make(
- "issue_events.IssueTag",
- issue=issue,
- tag_key=key_foo,
- tag_value=value_bar,
- count=2,
- )
- baker.make(
- "issue_events.IssueTag",
- issue=issue,
- tag_key=key_foo,
- tag_value=value_bar,
- count=1,
- )
- baker.make(
- "issue_events.IssueTag",
- issue=issue,
- tag_key=key_animal,
- tag_value=value_cat,
- )
- baker.make(
- "issue_events.IssueTag",
- issue=issue,
- tag_key=key_animal,
- tag_value=value_dog,
- count=4,
- )
- baker.make(
- "issue_events.IssueTag",
- issue=issue,
- tag_key=key_foo,
- tag_value=value_cat,
- count=4,
- )
- url = self.get_url(issue.id)
- res = self.client.get(url)
- data = res.json()
- # Order is random
- if data[0]["name"] == "animal":
- animal = data[0]
- foo = data[1]
- else:
- animal = data[1]
- foo = data[0]
- self.assertEqual(animal["totalValues"], 5)
- self.assertEqual(animal["topValues"][0]["value"], "dog")
- self.assertEqual(animal["topValues"][0]["count"], 4)
- self.assertEqual(animal["uniqueValues"], 2)
- self.assertEqual(foo["totalValues"], 7)
- self.assertEqual(foo["topValues"][0]["value"], "cat")
- self.assertEqual(foo["topValues"][0]["count"], 4)
- self.assertEqual(foo["uniqueValues"], 2)
- def test_issue_tags_filter(self):
- issue = baker.make("issue_events.Issue", project=self.project)
- value_bar = baker.make("issue_events.TagValue", value="bar")
- baker.make(
- "issue_events.IssueTag",
- issue=issue,
- tag_key__key="foo",
- tag_value=value_bar,
- )
- baker.make(
- "issue_events.IssueTag",
- issue=issue,
- tag_key__key="lol",
- tag_value=value_bar,
- )
- baker.make(
- "issue_events.IssueEvent", issue=issue, tags={"foo": "bar", "lol": "bar"}
- )
- url = self.get_url(issue.id)
- res = self.client.get(url + "?key=foo")
- self.assertEqual(len(res.json()), 1)
- def test_issue_tags_performance(self):
- issue = baker.make("issue_events.Issue", project=self.project)
- key_foo = baker.make("issue_events.TagKey", key="foo")
- key_animal = baker.make("issue_events.TagKey", key="animal")
- value_bar = baker.make("issue_events.TagValue", value="bar")
- value_cat = baker.make("issue_events.TagValue", value="cat")
- value_dog = baker.make("issue_events.TagValue", value="dog")
- quantity = 2
- baker.make(
- "issue_events.IssueTag",
- issue=issue,
- tag_key=key_foo,
- tag_value=value_bar,
- count=5,
- _quantity=quantity,
- _bulk_create=True,
- )
- baker.make(
- "issue_events.IssueTag",
- tag_key=key_foo,
- tag_value=value_bar,
- _quantity=quantity,
- _bulk_create=True,
- )
- baker.make(
- "issue_events.IssueTag",
- issue=issue,
- tag_key=key_animal,
- tag_value=value_cat,
- count=5,
- _quantity=quantity,
- _bulk_create=True,
- )
- baker.make(
- "issue_events.IssueTag",
- _quantity=quantity,
- _bulk_create=True,
- )
- baker.make(
- "issue_events.IssueTag",
- issue=issue,
- tag_key=key_animal,
- tag_value=value_dog,
- count=5,
- _quantity=quantity,
- _bulk_create=True,
- )
- url = self.get_url(issue.id)
- with self.assertNumQueries(2): # Includes many auth related queries
- start = timer()
- self.client.get(url)
- end = timer()
- logger.info(end - start)
|