123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595 |
- from __future__ import absolute_import
- import six
- from six.moves.urllib.parse import urlencode
- from django.utils import timezone
- from django.core.urlresolvers import reverse
- from sentry.testutils import APITestCase, SnubaTestCase
- from sentry.testutils.helpers.datetime import before_now, iso_format
- from sentry.utils.compat import map
- class OrganizationEventsEndpointTest(APITestCase, SnubaTestCase):
- def setUp(self):
- super(OrganizationEventsEndpointTest, self).setUp()
- self.min_ago = iso_format(before_now(minutes=1))
- self.day_ago = iso_format(before_now(days=1))
- def assert_events_in_response(self, response, event_ids):
- assert sorted(map(lambda x: x["eventID"], response.data)) == sorted(event_ids)
- def test_simple(self):
- self.login_as(user=self.user)
- project = self.create_project()
- project2 = self.create_project()
- event_1 = self.store_event(
- data={"event_id": "a" * 32, "timestamp": self.min_ago}, project_id=project.id
- )
- event_2 = self.store_event(
- data={"event_id": "b" * 32, "timestamp": self.min_ago}, project_id=project2.id
- )
- url = reverse(
- "sentry-api-0-organization-events",
- kwargs={"organization_slug": project.organization.slug},
- )
- response = self.client.get(url, format="json")
- assert response.status_code == 200, response.content
- assert len(response.data) == 2
- self.assert_events_in_response(response, [event_1.event_id, event_2.event_id])
- def test_simple_superuser(self):
- user = self.create_user(is_superuser=True)
- self.login_as(user=user, superuser=True)
- project = self.create_project()
- project2 = self.create_project()
- event_1 = self.store_event(
- data={"event_id": "a" * 32, "timestamp": iso_format(before_now(seconds=1))},
- project_id=project.id,
- )
- event_2 = self.store_event(
- data={"event_id": "b" * 32, "timestamp": iso_format(before_now(seconds=1))},
- project_id=project2.id,
- )
- url = reverse(
- "sentry-api-0-organization-events",
- kwargs={"organization_slug": project.organization.slug},
- )
- response = self.client.get(url, format="json")
- assert response.status_code == 200, response.content
- assert len(response.data) == 2
- self.assert_events_in_response(response, [event_1.event_id, event_2.event_id])
- def test_message_search_raw_text(self):
- self.login_as(user=self.user)
- project = self.create_project()
- self.store_event(
- data={"message": "how to make fast", "timestamp": iso_format(before_now(seconds=1))},
- project_id=project.id,
- )
- event_2 = self.store_event(
- data={"message": "Delet the Data", "timestamp": iso_format(before_now(seconds=1))},
- project_id=project.id,
- )
- url = reverse(
- "sentry-api-0-organization-events",
- kwargs={"organization_slug": project.organization.slug},
- )
- response = self.client.get(url, {"query": "delet"}, format="json")
- assert response.status_code == 200, response.content
- assert len(response.data) == 1
- assert response.data[0]["eventID"] == event_2.event_id
- assert response.data[0]["message"] == "Delet the Data"
- def test_message_search_tags(self):
- self.login_as(user=self.user)
- project = self.create_project()
- event_1 = self.store_event(
- data={
- "event_id": "a" * 32,
- "message": "how to make fast",
- "timestamp": iso_format(before_now(seconds=1)),
- "fingerprint": ["group-1"],
- },
- project_id=project.id,
- )
- event_2 = self.store_event(
- data={
- "event_id": "b" * 32,
- "message": "Delet the Data",
- "timestamp": iso_format(before_now(seconds=1)),
- "fingerprint": ["group-1"],
- "user": {"email": "foo@example.com"},
- },
- project_id=project.id,
- )
- url = reverse(
- "sentry-api-0-organization-events",
- kwargs={"organization_slug": project.organization.slug},
- )
- response = self.client.get(url, {"query": "user.email:foo@example.com"}, format="json")
- assert response.status_code == 200, response.content
- assert len(response.data) == 1
- assert response.data[0]["eventID"] == event_2.event_id
- assert response.data[0]["message"] == "Delet the Data"
- response = self.client.get(url, {"query": "!user.email:foo@example.com"}, format="json")
- assert response.status_code == 200, response.content
- assert len(response.data) == 1
- assert response.data[0]["eventID"] == event_1.event_id
- assert response.data[0]["message"] == "how to make fast"
- def test_invalid_search_terms(self):
- self.login_as(user=self.user)
- project = self.create_project()
- self.store_event(
- data={"event_id": "a" * 32, "message": "how to make fast"}, project_id=project.id
- )
- url = reverse(
- "sentry-api-0-organization-events",
- kwargs={"organization_slug": project.organization.slug},
- )
- response = self.client.get(url, {"query": "hi \n there"}, format="json")
- assert response.status_code == 400, response.content
- assert (
- response.data["detail"]
- == "Parse error at 'hi \n ther' (column 4). This is commonly caused by unmatched parentheses. Enclose any text in double quotes."
- )
- def test_project_filtering(self):
- user = self.create_user(is_staff=False, is_superuser=False)
- org = self.create_organization()
- org.flags.allow_joinleave = False
- org.save()
- team = self.create_team(organization=org)
- self.create_member(organization=org, user=user, teams=[team])
- self.login_as(user=user)
- project = self.create_project(organization=org, teams=[team])
- project2 = self.create_project(organization=org, teams=[team])
- project3 = self.create_project(organization=org)
- event_1 = self.store_event(
- data={"event_id": "a" * 32, "timestamp": self.min_ago}, project_id=project.id
- )
- event_2 = self.store_event(
- data={"event_id": "b" * 32, "timestamp": self.min_ago}, project_id=project2.id
- )
- self.store_event(
- data={"event_id": "c" * 32, "timestamp": self.min_ago}, project_id=project3.id
- )
- base_url = reverse(
- "sentry-api-0-organization-events",
- kwargs={"organization_slug": project.organization.slug},
- )
- # test bad project id
- url = "%s?project=abc" % (base_url,)
- response = self.client.get(url, format="json")
- assert response.status_code == 400
- # test including project user doesn't have access to
- url = "%s?project=%s&project=%s" % (base_url, project.id, project3.id)
- response = self.client.get(url, format="json")
- assert response.status_code == 403
- # test filtering by project
- url = "%s?project=%s" % (base_url, project.id)
- response = self.client.get(url, format="json")
- assert response.status_code == 200, response.content
- assert len(response.data) == 1
- self.assert_events_in_response(response, [event_1.event_id])
- # test only returns events from project user has access to
- response = self.client.get(base_url, format="json")
- assert response.status_code == 200, response.content
- assert len(response.data) == 2
- self.assert_events_in_response(response, [event_1.event_id, event_2.event_id])
- def test_stats_period(self):
- self.login_as(user=self.user)
- project = self.create_project()
- project2 = self.create_project()
- event_1 = self.store_event(
- data={"event_id": "a" * 32, "timestamp": self.min_ago}, project_id=project.id
- )
- self.store_event(
- data={"event_id": "b" * 32, "timestamp": self.day_ago}, project_id=project2.id
- )
- url = reverse(
- "sentry-api-0-organization-events",
- kwargs={"organization_slug": project.organization.slug},
- )
- url = "%s?statsPeriod=2h" % (url,)
- response = self.client.get(url, format="json")
- assert response.status_code == 200, response.content
- assert len(response.data) == 1
- self.assert_events_in_response(response, [event_1.event_id])
- def test_time_range(self):
- self.login_as(user=self.user)
- project = self.create_project()
- project2 = self.create_project()
- event_1 = self.store_event(
- data={"event_id": "a" * 32, "timestamp": self.min_ago}, project_id=project.id
- )
- self.store_event(
- data={"event_id": "b" * 32, "timestamp": self.day_ago}, project_id=project2.id
- )
- now = timezone.now()
- base_url = reverse(
- "sentry-api-0-organization-events",
- kwargs={"organization_slug": project.organization.slug},
- )
- # test swapped order of start/end
- url = "%s?%s" % (
- base_url,
- urlencode({"end": iso_format(before_now(hours=2)), "start": iso_format(now)}),
- )
- response = self.client.get(url, format="json")
- assert response.status_code == 400
- url = "%s?%s" % (
- base_url,
- urlencode({"start": iso_format(before_now(hours=2)), "end": iso_format(now)}),
- )
- response = self.client.get(url, format="json")
- assert response.status_code == 200, response.content
- assert len(response.data) == 1
- self.assert_events_in_response(response, [event_1.event_id])
- def test_environment_filtering(self):
- user = self.create_user()
- org = self.create_organization()
- team = self.create_team(organization=org)
- self.create_member(organization=org, user=user, teams=[team])
- self.login_as(user=user)
- project = self.create_project(organization=org, teams=[team])
- environment = self.create_environment(project=project, name="production")
- environment2 = self.create_environment(project=project)
- null_env = self.create_environment(project=project, name="")
- events = []
- for event_id, env in [
- ("a" * 32, environment),
- ("b" * 32, environment),
- ("c" * 32, environment2),
- ("d" * 32, null_env),
- ]:
- events.append(
- self.store_event(
- data={
- "event_id": event_id,
- "timestamp": self.min_ago,
- "fingerprint": ["put-me-in-group1"],
- "environment": env.name or None,
- },
- project_id=project.id,
- )
- )
- event_1, event_2, event_3, event_4 = events
- base_url = reverse(
- "sentry-api-0-organization-events", kwargs={"organization_slug": org.slug}
- )
- # test as part of query param
- url = "%s?environment=%s" % (base_url, environment.name)
- response = self.client.get(url, format="json")
- assert response.status_code == 200, response.content
- assert len(response.data) == 2
- self.assert_events_in_response(response, [event_1.event_id, event_2.event_id])
- # test multiple as part of query param
- url = "%s?%s" % (
- base_url,
- urlencode((("environment", environment.name), ("environment", environment2.name))),
- )
- response = self.client.get(url, format="json")
- assert response.status_code == 200, response.content
- assert len(response.data) == 3
- self.assert_events_in_response(
- response, [event_1.event_id, event_2.event_id, event_3.event_id]
- )
- # test multiple as part of query param with no env
- url = "%s?%s" % (
- base_url,
- urlencode((("environment", environment.name), ("environment", null_env.name))),
- )
- response = self.client.get(url, format="json")
- assert response.status_code == 200, response.content
- assert len(response.data) == 3
- self.assert_events_in_response(
- response, [event_1.event_id, event_2.event_id, event_4.event_id]
- )
- # test as part of search
- url = "%s?query=environment:%s" % (base_url, environment.name)
- response = self.client.get(url, format="json")
- assert response.status_code == 200, response.content
- assert len(response.data) == 2
- self.assert_events_in_response(response, [event_1.event_id, event_2.event_id])
- # test as part of search - no environment
- url = '%s?query=environment:""' % (base_url,)
- response = self.client.get(url, format="json")
- assert response.status_code == 200, response.content
- assert len(response.data) == 1
- self.assert_events_in_response(response, [event_4.event_id])
- # test nonexistent environment
- url = "%s?environment=notanenvironment" % (base_url,)
- response = self.client.get(url, format="json")
- assert response.status_code == 404
- def test_custom_tags(self):
- user = self.create_user()
- org = self.create_organization()
- team = self.create_team(organization=org)
- self.create_member(organization=org, user=user, teams=[team])
- self.login_as(user=user)
- project = self.create_project(organization=org, teams=[team])
- event_1 = self.store_event(
- data={
- "event_id": "a" * 32,
- "tags": {"fruit": "apple"},
- "fingerprint": ["group-1"],
- "timestamp": iso_format(before_now(seconds=1)),
- },
- project_id=project.id,
- )
- event_2 = self.store_event(
- data={
- "event_id": "b" * 32,
- "tags": {"fruit": "orange"},
- "fingerprint": ["group-1"],
- "timestamp": iso_format(before_now(seconds=1)),
- },
- project_id=project.id,
- )
- base_url = reverse(
- "sentry-api-0-organization-events", kwargs={"organization_slug": org.slug}
- )
- response = self.client.get("%s?query=fruit:apple" % (base_url,), format="json")
- assert response.status_code == 200, response.content
- assert len(response.data) == 1
- self.assert_events_in_response(response, [event_1.event_id])
- response = self.client.get("%s?query=!fruit:apple" % (base_url,), format="json")
- assert response.status_code == 200, response.content
- assert len(response.data) == 1
- self.assert_events_in_response(response, [event_2.event_id])
- def test_wildcard_search(self):
- user = self.create_user()
- org = self.create_organization()
- team = self.create_team(organization=org)
- self.create_member(organization=org, user=user, teams=[team])
- self.login_as(user=user)
- project = self.create_project(organization=org, teams=[team])
- event_1 = self.store_event(
- data={
- "event_id": "a" * 32,
- "tags": {"sentry:release": "3.1.2"},
- "timestamp": self.min_ago,
- },
- project_id=project.id,
- )
- event_2 = self.store_event(
- data={
- "event_id": "b" * 32,
- "tags": {"sentry:release": "4.1.2"},
- "timestamp": self.min_ago,
- },
- project_id=project.id,
- )
- event_3 = self.store_event(
- data={
- "event_id": "c" * 32,
- "user": {"email": "foo@example.com"},
- "timestamp": self.min_ago,
- },
- project_id=project.id,
- )
- event_4 = self.store_event(
- data={
- "event_id": "d" * 32,
- "user": {"email": "foo@example.commmmmmmm"},
- "timestamp": self.min_ago,
- },
- project_id=project.id,
- )
- base_url = reverse(
- "sentry-api-0-organization-events", kwargs={"organization_slug": org.slug}
- )
- response = self.client.get("%s?query=release:3.1.*" % (base_url,), format="json")
- assert response.status_code == 200, response.content
- assert len(response.data) == 1
- self.assert_events_in_response(response, [event_1.event_id])
- response = self.client.get("%s?query=!release:3.1.*" % (base_url,), format="json")
- assert response.status_code == 200, response.content
- assert len(response.data) == 3
- self.assert_events_in_response(
- response, [event_2.event_id, event_3.event_id, event_4.event_id]
- )
- response = self.client.get("%s?query=user.email:*@example.com" % (base_url,), format="json")
- assert response.status_code == 200, response.content
- assert len(response.data) == 1
- self.assert_events_in_response(response, [event_3.event_id])
- response = self.client.get(
- "%s?query=!user.email:*@example.com" % (base_url,), format="json"
- )
- assert response.status_code == 200, response.content
- assert len(response.data) == 3
- self.assert_events_in_response(
- response, [event_1.event_id, event_2.event_id, event_4.event_id]
- )
- def test_has_tag(self):
- user = self.create_user()
- org = self.create_organization()
- team = self.create_team(organization=org)
- self.create_member(organization=org, user=user, teams=[team])
- self.login_as(user=user)
- project = self.create_project(organization=org, teams=[team])
- event_1 = self.store_event(
- data={
- "event_id": "a" * 32,
- "user": {"email": "foo@example.com"},
- "timestamp": self.min_ago,
- },
- project_id=project.id,
- )
- event_2 = self.store_event(
- data={
- "event_id": "b" * 32,
- "tags": {"example_tag": "example_value"},
- "timestamp": self.min_ago,
- },
- project_id=project.id,
- )
- base_url = reverse(
- "sentry-api-0-organization-events", kwargs={"organization_slug": org.slug}
- )
- response = self.client.get("%s?query=has:user.email" % (base_url,), format="json")
- assert response.status_code == 200, response.content
- assert len(response.data) == 1
- self.assert_events_in_response(response, [event_1.event_id])
- # test custom tag
- response = self.client.get("%s?query=has:example_tag" % (base_url,), format="json")
- assert response.status_code == 200, response.content
- assert len(response.data) == 1
- self.assert_events_in_response(response, [event_2.event_id])
- response = self.client.get("%s?query=!has:user.email" % (base_url,), format="json")
- assert response.status_code == 200, response.content
- assert len(response.data) == 1
- self.assert_events_in_response(response, [event_2.event_id])
- # test custom tag
- response = self.client.get("%s?query=!has:example_tag" % (base_url,), format="json")
- assert response.status_code == 200, response.content
- assert len(response.data) == 1
- self.assert_events_in_response(response, [event_1.event_id])
- def test_no_projects(self):
- org = self.create_organization(owner=self.user)
- self.login_as(user=self.user)
- url = reverse("sentry-api-0-organization-events", kwargs={"organization_slug": org.slug})
- response = self.client.get(url, format="json")
- assert response.status_code == 200, response.content
- assert len(response.data) == 0
- def test_event_id_direct_hit(self):
- user = self.create_user()
- org = self.create_organization()
- team = self.create_team(organization=org)
- self.create_member(organization=org, user=user, teams=[team])
- self.login_as(user=user)
- project = self.create_project(organization=org, teams=[team])
- self.store_event(
- data={"event_id": "a" * 32, "message": "best event", "timestamp": self.min_ago},
- project_id=project.id,
- )
- url = reverse("sentry-api-0-organization-events", kwargs={"organization_slug": org.slug})
- response = self.client.get(url, {"query": "a" * 32}, format="json")
- assert response.status_code == 200, response.content
- assert len(response.data) == 1
- assert response["X-Sentry-Direct-Hit"] == "1"
- def test_event_id_direct_hit_miss(self):
- user = self.create_user()
- org = self.create_organization()
- team = self.create_team(organization=org)
- self.create_member(organization=org, user=user, teams=[team])
- self.login_as(user=user)
- self.create_project(organization=org, teams=[team])
- url = reverse("sentry-api-0-organization-events", kwargs={"organization_slug": org.slug})
- response = self.client.get(url, {"query": "a" * 32}, format="json")
- assert response.status_code == 200, response.content
- assert len(response.data) == 0
- def test_project_id_filter(self):
- team = self.create_team(organization=self.organization, members=[self.user])
- project = self.create_project(organization=self.organization, teams=[team])
- self.store_event(
- data={"event_id": "a" * 32, "message": "best event", "timestamp": self.min_ago},
- project_id=project.id,
- )
- url = reverse(
- "sentry-api-0-organization-events", kwargs={"organization_slug": self.organization.slug}
- )
- self.login_as(user=self.user)
- response = self.client.get(
- url, {"query": "project_id:{}".format(project.id)}, format="json"
- )
- assert response.status_code == 200, response.content
- assert len(response.data) == 1
- assert response.data[0]["projectID"] == six.text_type(project.id)
- response = self.client.get(url, {"query": "project_id:9"}, format="json")
- # project_id filter should apply
- assert response.status_code == 200, response.content
- assert len(response.data) == 0
|