class TagStorageTest(TestCase, SnubaTestCase): def setUp(self): super(TagStorageTest, self).setUp() self.ts = SnubaTagStorage() self.proj1 = self.create_project() self.proj1env1 = self.create_environment(project=self.proj1, name="test") self.proj1env2 = self.create_environment(project=self.proj1, name="test2") self.proj1group1 = self.create_group(self.proj1) self.proj1group2 = self.create_group(self.proj1) hash1 = "1" * 32 hash2 = "2" * 32 GroupHash.objects.create(project=self.proj1, group=self.proj1group1, hash=hash1) GroupHash.objects.create(project=self.proj1, group=self.proj1group2, hash=hash2) self.now = timezone.now().replace(microsecond=0) data = json.dumps([{ "event_id": six.text_type(r) * 32, "primary_hash": hash1, "group_id": self.proj1group1.id, "project_id": self.proj1.id, "message": "message 1", "platform": "python", "datetime": (self.now - timedelta(seconds=r) ).strftime("%Y-%m-%dT%H:%M:%S.%fZ"), "data": { "received": calendar.timegm(self.now.timetuple()) - r, "tags": { "foo": "bar", "baz": "quux", "environment": self.proj1env1.name, "sentry:release": 100 * r, "sentry:user": u"id:user{}".format(r), }, "user": { "id": u"user{}".format(r), "email": u"user{}@sentry.io".format(r) }, }, } for r in [1, 2]] + [{ "event_id": "3" * 32, "primary_hash": hash2, "group_id": self.proj1group2.id, "project_id": self.proj1.id, "message": "message 2", "platform": "python", "datetime": (self.now - timedelta(seconds=2) ).strftime("%Y-%m-%dT%H:%M:%S.%fZ"), "data": { "received": calendar.timegm(self.now.timetuple()) - 2, "tags": { "browser": "chrome", "environment": self.proj1env1.name, "sentry:user": "******", }, "user": { "id": "user1" }, }, }] + [{ "event_id": "4" * 32, "primary_hash": hash2, "group_id": self.proj1group1.id, "project_id": self.proj1.id, "message": "message 2", "platform": "python", "datetime": (self.now - timedelta(seconds=2) ).strftime("%Y-%m-%dT%H:%M:%S.%fZ"), "data": { "received": calendar.timegm(self.now.timetuple()) - 2, "tags": { "foo": "bar", "environment": self.proj1env2.name }, "user": { "id": "user1" }, }, }]) assert (requests.post(settings.SENTRY_SNUBA + "/tests/events/insert", data=data).status_code == 200) def test_get_group_tag_keys_and_top_values(self): result = list( self.ts.get_group_tag_keys_and_top_values(self.proj1.id, self.proj1group1.id, [self.proj1env1.id])) tags = [r.key for r in result] assert set(tags) == set( ["foo", "baz", "environment", "sentry:release", "sentry:user"]) result.sort(key=lambda r: r.key) assert result[0].key == "baz" assert result[0].top_values[0].value == "quux" assert result[0].count == 2 assert result[3].key == "sentry:release" assert result[3].count == 2 top_release_values = result[3].top_values assert len(top_release_values) == 2 assert set(v.value for v in top_release_values) == set(["100", "200"]) assert all(v.times_seen == 1 for v in top_release_values) # Now with only a specific set of keys, result = list( self.ts.get_group_tag_keys_and_top_values( self.proj1.id, self.proj1group1.id, [self.proj1env1.id], keys=["environment", "sentry:release"], )) tags = [r.key for r in result] assert set(tags) == set(["environment", "sentry:release"]) result.sort(key=lambda r: r.key) assert result[0].key == "environment" assert result[0].top_values[0].value == "test" assert result[1].key == "sentry:release" top_release_values = result[1].top_values assert len(top_release_values) == 2 assert set(v.value for v in top_release_values) == set(["100", "200"]) assert all(v.times_seen == 1 for v in top_release_values) def test_get_top_group_tag_values(self): resp = self.ts.get_top_group_tag_values(self.proj1.id, self.proj1group1.id, self.proj1env1.id, "foo", 1) assert len(resp) == 1 assert resp[0].times_seen == 2 assert resp[0].key == "foo" assert resp[0].value == "bar" assert resp[0].group_id == self.proj1group1.id def test_get_group_tag_value_count(self): assert (self.ts.get_group_tag_value_count(self.proj1.id, self.proj1group1.id, self.proj1env1.id, "foo") == 2) def test_get_tag_keys(self): expected_keys = set([ "baz", "browser", "environment", "foo", "sentry:release", "sentry:user" ]) keys = { k.key: k for k in self.ts.get_tag_keys(project_id=self.proj1.id, environment_id=self.proj1env1.id) } assert set(keys) == expected_keys keys = { k.key: k for k in self.ts.get_tag_keys(project_id=self.proj1.id, environment_id=self.proj1env1.id, include_values_seen=True) } assert set(keys) == expected_keys def test_get_group_tag_key(self): with pytest.raises(GroupTagKeyNotFound): self.ts.get_group_tag_key( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_id=self.proj1env1.id, key="notreal", ) assert (self.ts.get_group_tag_key( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_id=self.proj1env1.id, key="foo", ).key == "foo") keys = { k.key: k for k in self.ts.get_group_tag_keys( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_ids=[self.proj1env1.id], ) } assert set(keys) == set( ["baz", "environment", "foo", "sentry:release", "sentry:user"]) def test_get_group_tag_value(self): with pytest.raises(GroupTagValueNotFound): self.ts.get_group_tag_value( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_id=self.proj1env1.id, key="foo", value="notreal", ) assert self.ts.get_group_tag_values( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_id=self.proj1env1.id, key="notreal", ) == set([]) assert (list( self.ts.get_group_tag_values( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_id=self.proj1env1.id, key="foo", ))[0].value == "bar") assert (self.ts.get_group_tag_value( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_id=self.proj1env1.id, key="foo", value="bar", ).value == "bar") def test_get_tag_key(self): with pytest.raises(TagKeyNotFound): self.ts.get_tag_key(project_id=self.proj1.id, environment_id=self.proj1env1.id, key="notreal") def test_get_tag_value(self): with pytest.raises(TagValueNotFound): self.ts.get_tag_value( project_id=self.proj1.id, environment_id=self.proj1env1.id, key="foo", value="notreal", ) def test_get_groups_user_counts(self): assert self.ts.get_groups_user_counts( project_ids=[self.proj1.id], group_ids=[self.proj1group1.id, self.proj1group2.id], environment_ids=[self.proj1env1.id], ) == { self.proj1group1.id: 2, self.proj1group2.id: 1 } # test filtering by date range where there shouldn't be results assert (self.ts.get_groups_user_counts( project_ids=[self.proj1.id], group_ids=[self.proj1group1.id, self.proj1group2.id], environment_ids=[self.proj1env1.id], start=self.now - timedelta(days=5), end=self.now - timedelta(days=4), ) == {}) def test_get_releases(self): assert (self.ts.get_first_release( project_id=self.proj1.id, group_id=self.proj1group1.id) == "200") assert (self.ts.get_first_release( project_id=self.proj1.id, group_id=self.proj1group2.id) is None) assert (self.ts.get_last_release( project_id=self.proj1.id, group_id=self.proj1group1.id) == "100") assert (self.ts.get_last_release(project_id=self.proj1.id, group_id=self.proj1group2.id) is None) def test_get_group_ids_for_users(self): assert self.ts.get_group_ids_for_users( [self.proj1.id], [EventUser(project_id=self.proj1.id, ident="user1")]) == set( [self.proj1group1.id, self.proj1group2.id]) assert self.ts.get_group_ids_for_users( [self.proj1.id], [EventUser(project_id=self.proj1.id, ident="user2")]) == set( [self.proj1group1.id]) def test_get_group_tag_values_for_users(self): result = self.ts.get_group_tag_values_for_users( [EventUser(project_id=self.proj1.id, ident="user1")]) assert len(result) == 2 assert set(v.group_id for v in result) == set( [self.proj1group1.id, self.proj1group2.id]) assert set(v.last_seen for v in result) == set( [self.now - timedelta(seconds=1), self.now - timedelta(seconds=2)]) result.sort(key=lambda x: x.last_seen) assert result[0].last_seen == self.now - timedelta(seconds=2) assert result[1].last_seen == self.now - timedelta(seconds=1) for v in result: assert v.value == "user1" result = self.ts.get_group_tag_values_for_users( [EventUser(project_id=self.proj1.id, ident="user2")]) assert len(result) == 1 assert result[0].value == "user2" assert result[0].last_seen == self.now - timedelta(seconds=2) def test_get_release_tags(self): tags = list(self.ts.get_release_tags([self.proj1.id], None, ["100"])) assert len(tags) == 1 one_second_ago = self.now - timedelta(seconds=1) assert tags[0].last_seen == one_second_ago assert tags[0].first_seen == one_second_ago assert tags[0].times_seen == 1 assert tags[0].key == "sentry:release" def test_get_group_event_filter(self): assert self.ts.get_group_event_filter(self.proj1.id, self.proj1group1.id, [self.proj1env1.id], {"foo": "bar"}, None, None) == { "event_id__in": set(["1" * 32, "2" * 32]) } assert self.ts.get_group_event_filter( self.proj1.id, self.proj1group1.id, [self.proj1env1.id], {"foo": "bar"}, (self.now - timedelta(seconds=1)), None, ) == { "event_id__in": set(["1" * 32]) } assert self.ts.get_group_event_filter( self.proj1.id, self.proj1group1.id, [self.proj1env1.id], {"foo": "bar"}, None, (self.now - timedelta(seconds=1)), ) == { "event_id__in": set(["2" * 32]) } assert self.ts.get_group_event_filter( self.proj1.id, self.proj1group1.id, [self.proj1env1.id, self.proj1env2.id], {"foo": "bar"}, None, None, ) == { "event_id__in": set(["1" * 32, "2" * 32, "4" * 32]) } assert self.ts.get_group_event_filter( self.proj1.id, self.proj1group1.id, [self.proj1env1.id], { "foo": "bar", "sentry:release": "200" }, # AND None, None, ) == { "event_id__in": set(["2" * 32]) } assert self.ts.get_group_event_filter( self.proj1.id, self.proj1group2.id, [self.proj1env1.id], {"browser": "chrome"}, None, None, ) == { "event_id__in": set(["3" * 32]) } assert (self.ts.get_group_event_filter( self.proj1.id, self.proj1group2.id, [self.proj1env1.id], {"browser": "ie"}, None, None, ) is None) def test_get_tag_value_paginator(self): from sentry.tagstore.types import TagValue assert list( self.ts.get_tag_value_paginator( self.proj1.id, self.proj1env1.id, "sentry:user").get_result(10)) == [ TagValue( key="sentry:user", value="id:user1", times_seen=2, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=1), ), TagValue( key="sentry:user", value="id:user2", times_seen=1, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=2), ), ] assert list( self.ts.get_tag_value_paginator( self.proj1.id, self.proj1env1.id, "sentry:user", query="user1").get_result(10)) == [ TagValue( key="sentry:user", value="id:user1", times_seen=2, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=1), ) ] def test_get_group_tag_value_iter(self): from sentry.tagstore.types import GroupTagValue assert list( self.ts.get_group_tag_value_iter( self.proj1.id, self.proj1group1.id, self.proj1env1.id, "sentry:user")) == [ GroupTagValue( group_id=self.proj1group1.id, key="sentry:user", value="id:user1", times_seen=1, first_seen=self.now - timedelta(seconds=1), last_seen=self.now - timedelta(seconds=1), ), GroupTagValue( group_id=self.proj1group1.id, key="sentry:user", value="id:user2", times_seen=1, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=2), ), ] def test_get_group_tag_value_paginator(self): from sentry.tagstore.types import GroupTagValue assert list( self.ts.get_group_tag_value_paginator( self.proj1.id, self.proj1group1.id, self.proj1env1.id, "sentry:user").get_result(10)) == [ GroupTagValue( group_id=self.proj1group1.id, key="sentry:user", value="id:user1", times_seen=1, first_seen=self.now - timedelta(seconds=1), last_seen=self.now - timedelta(seconds=1), ), GroupTagValue( group_id=self.proj1group1.id, key="sentry:user", value="id:user2", times_seen=1, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=2), ), ] def test_get_group_seen_values_for_environments(self): assert self.ts.get_group_seen_values_for_environments( [self.proj1.id], [self.proj1group1.id], [self.proj1env1.id]) == { self.proj1group1.id: { "first_seen": self.now - timedelta(seconds=2), "last_seen": self.now - timedelta(seconds=1), "times_seen": 2, } } # test where there should be no results because of time filters assert (self.ts.get_group_seen_values_for_environments( [self.proj1.id], [self.proj1group1.id], [self.proj1env1.id], start=self.now - timedelta(hours=5), end=self.now - timedelta(hours=4), ) == {})
class TagStorageTest(TestCase, SnubaTestCase): def setUp(self): super(TagStorageTest, self).setUp() self.ts = SnubaTagStorage() self.proj1 = self.create_project() self.proj1env1 = self.create_environment(project=self.proj1, name="test") self.proj1env2 = self.create_environment(project=self.proj1, name="test2") self.proj1group1 = self.create_group(self.proj1) self.proj1group2 = self.create_group(self.proj1) hash1 = "1" * 32 hash2 = "2" * 32 GroupHash.objects.create(project=self.proj1, group=self.proj1group1, hash=hash1) GroupHash.objects.create(project=self.proj1, group=self.proj1group2, hash=hash2) self.now = timezone.now().replace(microsecond=0) data = json.dumps( [ { "event_id": six.text_type(r) * 32, "primary_hash": hash1, "group_id": self.proj1group1.id, "project_id": self.proj1.id, "message": "message 1", "platform": "python", "datetime": (self.now - timedelta(seconds=r)).strftime("%Y-%m-%dT%H:%M:%S.%fZ"), "data": { "received": calendar.timegm(self.now.timetuple()) - r, "tags": { "foo": "bar", "baz": "quux", "environment": self.proj1env1.name, "sentry:release": 100 * r, "sentry:user": u"id:user{}".format(r), }, "user": {"id": u"user{}".format(r), "email": u"user{}@sentry.io".format(r)}, "exception": {"values": [{"stacktrace": {"frames": [{"lineno": 29}]}}]}, }, } for r in [1, 2] ] + [ { "event_id": "3" * 32, "primary_hash": hash2, "group_id": self.proj1group2.id, "project_id": self.proj1.id, "message": "message 2", "platform": "python", "datetime": (self.now - timedelta(seconds=2)).strftime("%Y-%m-%dT%H:%M:%S.%fZ"), "data": { "received": calendar.timegm(self.now.timetuple()) - 2, "tags": { "browser": "chrome", "environment": self.proj1env1.name, "sentry:user": "******", }, "user": {"id": "user1"}, }, } ] + [ { "event_id": "4" * 32, "primary_hash": hash2, "group_id": self.proj1group1.id, "project_id": self.proj1.id, "message": "message 2", "platform": "python", "datetime": (self.now - timedelta(seconds=2)).strftime("%Y-%m-%dT%H:%M:%S.%fZ"), "data": { "received": calendar.timegm(self.now.timetuple()) - 2, "tags": {"foo": "bar", "environment": self.proj1env2.name}, "user": {"id": "user1"}, }, } ] ) assert ( requests.post(settings.SENTRY_SNUBA + "/tests/events/insert", data=data).status_code == 200 ) def test_get_group_tag_keys_and_top_values(self): result = list( self.ts.get_group_tag_keys_and_top_values( self.proj1.id, self.proj1group1.id, [self.proj1env1.id] ) ) tags = [r.key for r in result] assert set(tags) == set(["foo", "baz", "environment", "sentry:release", "sentry:user"]) result.sort(key=lambda r: r.key) assert result[0].key == "baz" assert result[0].top_values[0].value == "quux" assert result[0].count == 2 assert result[3].key == "sentry:release" assert result[3].count == 2 top_release_values = result[3].top_values assert len(top_release_values) == 2 assert set(v.value for v in top_release_values) == set(["100", "200"]) assert all(v.times_seen == 1 for v in top_release_values) # Now with only a specific set of keys, result = list( self.ts.get_group_tag_keys_and_top_values( self.proj1.id, self.proj1group1.id, [self.proj1env1.id], keys=["environment", "sentry:release"], ) ) tags = [r.key for r in result] assert set(tags) == set(["environment", "sentry:release"]) result.sort(key=lambda r: r.key) assert result[0].key == "environment" assert result[0].top_values[0].value == "test" assert result[1].key == "sentry:release" top_release_values = result[1].top_values assert len(top_release_values) == 2 assert set(v.value for v in top_release_values) == set(["100", "200"]) assert all(v.times_seen == 1 for v in top_release_values) def test_get_top_group_tag_values(self): resp = self.ts.get_top_group_tag_values( self.proj1.id, self.proj1group1.id, self.proj1env1.id, "foo", 1 ) assert len(resp) == 1 assert resp[0].times_seen == 2 assert resp[0].key == "foo" assert resp[0].value == "bar" assert resp[0].group_id == self.proj1group1.id def test_get_group_tag_value_count(self): assert ( self.ts.get_group_tag_value_count( self.proj1.id, self.proj1group1.id, self.proj1env1.id, "foo" ) == 2 ) def test_get_tag_keys(self): expected_keys = set( ["baz", "browser", "environment", "foo", "sentry:release", "sentry:user"] ) keys = { k.key: k for k in self.ts.get_tag_keys( project_id=self.proj1.id, environment_id=self.proj1env1.id ) } assert set(keys) == expected_keys keys = { k.key: k for k in self.ts.get_tag_keys( project_id=self.proj1.id, environment_id=self.proj1env1.id, include_values_seen=True ) } assert set(keys) == expected_keys def test_get_group_tag_key(self): with pytest.raises(GroupTagKeyNotFound): self.ts.get_group_tag_key( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_id=self.proj1env1.id, key="notreal", ) assert ( self.ts.get_group_tag_key( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_id=self.proj1env1.id, key="foo", ).key == "foo" ) keys = { k.key: k for k in self.ts.get_group_tag_keys( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_ids=[self.proj1env1.id], ) } assert set(keys) == set(["baz", "environment", "foo", "sentry:release", "sentry:user"]) def test_get_group_tag_value(self): with pytest.raises(GroupTagValueNotFound): self.ts.get_group_tag_value( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_id=self.proj1env1.id, key="foo", value="notreal", ) assert self.ts.get_group_tag_values( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_id=self.proj1env1.id, key="notreal", ) == set([]) assert ( list( self.ts.get_group_tag_values( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_id=self.proj1env1.id, key="foo", ) )[0].value == "bar" ) assert ( self.ts.get_group_tag_value( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_id=self.proj1env1.id, key="foo", value="bar", ).value == "bar" ) def test_get_tag_key(self): with pytest.raises(TagKeyNotFound): self.ts.get_tag_key( project_id=self.proj1.id, environment_id=self.proj1env1.id, key="notreal" ) def test_get_tag_value(self): with pytest.raises(TagValueNotFound): self.ts.get_tag_value( project_id=self.proj1.id, environment_id=self.proj1env1.id, key="foo", value="notreal", ) def test_get_tag_value_label(self): assert self.ts.get_tag_value_label("foo", "notreal") == "notreal" assert self.ts.get_tag_value_label("sentry:user", None) is None assert self.ts.get_tag_value_label("sentry:user", "id:stuff") == "stuff" assert self.ts.get_tag_value_label("sentry:user", "email:stuff") == "stuff" assert self.ts.get_tag_value_label("sentry:user", "username:stuff") == "stuff" assert self.ts.get_tag_value_label("sentry:user", "ip:stuff") == "stuff" def test_get_groups_user_counts(self): assert self.ts.get_groups_user_counts( project_ids=[self.proj1.id], group_ids=[self.proj1group1.id, self.proj1group2.id], environment_ids=[self.proj1env1.id], ) == {self.proj1group1.id: 2, self.proj1group2.id: 1} # test filtering by date range where there shouldn't be results assert ( self.ts.get_groups_user_counts( project_ids=[self.proj1.id], group_ids=[self.proj1group1.id, self.proj1group2.id], environment_ids=[self.proj1env1.id], start=self.now - timedelta(days=5), end=self.now - timedelta(days=4), ) == {} ) def test_get_releases(self): assert ( self.ts.get_first_release(project_id=self.proj1.id, group_id=self.proj1group1.id) == "200" ) assert ( self.ts.get_first_release(project_id=self.proj1.id, group_id=self.proj1group2.id) is None ) assert ( self.ts.get_last_release(project_id=self.proj1.id, group_id=self.proj1group1.id) == "100" ) assert ( self.ts.get_last_release(project_id=self.proj1.id, group_id=self.proj1group2.id) is None ) def test_get_group_ids_for_users(self): assert self.ts.get_group_ids_for_users( [self.proj1.id], [EventUser(project_id=self.proj1.id, ident="user1")] ) == set([self.proj1group1.id, self.proj1group2.id]) assert self.ts.get_group_ids_for_users( [self.proj1.id], [EventUser(project_id=self.proj1.id, ident="user2")] ) == set([self.proj1group1.id]) def test_get_group_tag_values_for_users(self): result = self.ts.get_group_tag_values_for_users( [EventUser(project_id=self.proj1.id, ident="user1")] ) assert len(result) == 2 assert set(v.group_id for v in result) == set([self.proj1group1.id, self.proj1group2.id]) assert set(v.last_seen for v in result) == set( [self.now - timedelta(seconds=1), self.now - timedelta(seconds=2)] ) result.sort(key=lambda x: x.last_seen) assert result[0].last_seen == self.now - timedelta(seconds=2) assert result[1].last_seen == self.now - timedelta(seconds=1) for v in result: assert v.value == "user1" result = self.ts.get_group_tag_values_for_users( [EventUser(project_id=self.proj1.id, ident="user2")] ) assert len(result) == 1 assert result[0].value == "user2" assert result[0].last_seen == self.now - timedelta(seconds=2) def test_get_release_tags(self): tags = list(self.ts.get_release_tags([self.proj1.id], None, ["100"])) assert len(tags) == 1 one_second_ago = self.now - timedelta(seconds=1) assert tags[0].last_seen == one_second_ago assert tags[0].first_seen == one_second_ago assert tags[0].times_seen == 1 assert tags[0].key == "sentry:release" def test_get_group_event_filter(self): assert self.ts.get_group_event_filter( self.proj1.id, self.proj1group1.id, [self.proj1env1.id], {"foo": "bar"}, None, None ) == {"event_id__in": set(["1" * 32, "2" * 32])} assert self.ts.get_group_event_filter( self.proj1.id, self.proj1group1.id, [self.proj1env1.id], {"foo": "bar"}, (self.now - timedelta(seconds=1)), None, ) == {"event_id__in": set(["1" * 32])} assert self.ts.get_group_event_filter( self.proj1.id, self.proj1group1.id, [self.proj1env1.id], {"foo": "bar"}, None, (self.now - timedelta(seconds=1)), ) == {"event_id__in": set(["2" * 32])} assert self.ts.get_group_event_filter( self.proj1.id, self.proj1group1.id, [self.proj1env1.id, self.proj1env2.id], {"foo": "bar"}, None, None, ) == {"event_id__in": set(["1" * 32, "2" * 32, "4" * 32])} assert self.ts.get_group_event_filter( self.proj1.id, self.proj1group1.id, [self.proj1env1.id], {"foo": "bar", "sentry:release": "200"}, # AND None, None, ) == {"event_id__in": set(["2" * 32])} assert self.ts.get_group_event_filter( self.proj1.id, self.proj1group2.id, [self.proj1env1.id], {"browser": "chrome"}, None, None, ) == {"event_id__in": set(["3" * 32])} assert ( self.ts.get_group_event_filter( self.proj1.id, self.proj1group2.id, [self.proj1env1.id], {"browser": "ie"}, None, None, ) is None ) def test_get_tag_value_paginator(self): from sentry.tagstore.types import TagValue assert list( self.ts.get_tag_value_paginator( self.proj1.id, self.proj1env1.id, "sentry:user" ).get_result(10) ) == [ TagValue( key="sentry:user", value="id:user1", times_seen=2, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=1), ), TagValue( key="sentry:user", value="id:user2", times_seen=1, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=2), ), ] assert list( self.ts.get_tag_value_paginator( self.proj1.id, self.proj1env1.id, "sentry:user", query="user1" ).get_result(10) ) == [ TagValue( key="sentry:user", value="id:user1", times_seen=2, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=1), ) ] def test_get_tag_value_paginator_with_dates(self): from sentry.tagstore.types import TagValue day_ago = self.now - timedelta(days=1) two_days_ago = self.now - timedelta(days=2) assert list( self.ts.get_tag_value_paginator( self.proj1.id, self.proj1env1.id, "sentry:user", start=day_ago, end=self.now ).get_result(10) ) == [ TagValue( key="sentry:user", value="id:user1", times_seen=2, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=1), ), TagValue( key="sentry:user", value="id:user2", times_seen=1, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=2), ), ] day_ago = self.now - timedelta(days=1) assert ( list( self.ts.get_tag_value_paginator( self.proj1.id, self.proj1env1.id, "sentry:user", start=two_days_ago, end=day_ago ).get_result(10) ) == [] ) def test_numeric_tag_value_paginator(self): from sentry.tagstore.types import TagValue assert list( self.ts.get_tag_value_paginator( self.proj1.id, self.proj1env1.id, "stack.lineno" ).get_result(10) ) == [ TagValue( key="stack.lineno", value="29", times_seen=2, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=1), ) ] assert list( self.ts.get_tag_value_paginator( self.proj1.id, self.proj1env1.id, "stack.lineno", query="30" ).get_result(10) ) == [ TagValue( key="stack.lineno", value="29", times_seen=2, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=1), ) ] def test_get_group_tag_value_iter(self): from sentry.tagstore.types import GroupTagValue assert list( self.ts.get_group_tag_value_iter( self.proj1.id, self.proj1group1.id, self.proj1env1.id, "sentry:user" ) ) == [ GroupTagValue( group_id=self.proj1group1.id, key="sentry:user", value="id:user1", times_seen=1, first_seen=self.now - timedelta(seconds=1), last_seen=self.now - timedelta(seconds=1), ), GroupTagValue( group_id=self.proj1group1.id, key="sentry:user", value="id:user2", times_seen=1, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=2), ), ] def test_get_group_tag_value_paginator(self): from sentry.tagstore.types import GroupTagValue assert list( self.ts.get_group_tag_value_paginator( self.proj1.id, self.proj1group1.id, self.proj1env1.id, "sentry:user" ).get_result(10) ) == [ GroupTagValue( group_id=self.proj1group1.id, key="sentry:user", value="id:user1", times_seen=1, first_seen=self.now - timedelta(seconds=1), last_seen=self.now - timedelta(seconds=1), ), GroupTagValue( group_id=self.proj1group1.id, key="sentry:user", value="id:user2", times_seen=1, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=2), ), ] def test_get_group_seen_values_for_environments(self): assert self.ts.get_group_seen_values_for_environments( [self.proj1.id], [self.proj1group1.id], [self.proj1env1.id] ) == { self.proj1group1.id: { "first_seen": self.now - timedelta(seconds=2), "last_seen": self.now - timedelta(seconds=1), "times_seen": 2, } } # test where there should be no results because of time filters assert ( self.ts.get_group_seen_values_for_environments( [self.proj1.id], [self.proj1group1.id], [self.proj1env1.id], start=self.now - timedelta(hours=5), end=self.now - timedelta(hours=4), ) == {} ) def test_cache_suffix_time(self): starting_key = cache_suffix_time(self.now, 0) finishing_key = cache_suffix_time(self.now + timedelta(seconds=300), 0) assert starting_key != finishing_key def test_cache_suffix_hour_edges(self): """ a suffix should still behave correctly around the end of the hour At a duration of 10 only one key between 0-10 should flip on the hour, the other 9 should flip at different times. """ before = datetime(2019, 9, 5, 17, 59, 59) on_hour = datetime(2019, 9, 5, 18, 0, 0) changed_on_hour = 0 # Check multiple keyhashes so that this test doesn't depend on implementation for key_hash in range(10): before_key = cache_suffix_time(before, key_hash, duration=10) on_key = cache_suffix_time(on_hour, key_hash, duration=10) if before_key != on_key: changed_on_hour += 1 assert changed_on_hour == 1 def test_cache_suffix_day_edges(self): """ a suffix should still behave correctly around the end of a day This test is nearly identical to test_cache_suffix_hour_edges, but is to confirm that date changes don't cause a different behaviour """ before = datetime(2019, 9, 5, 23, 59, 59) next_day = datetime(2019, 9, 6, 0, 0, 0) changed_on_hour = 0 for key_hash in range(10): before_key = cache_suffix_time(before, key_hash, duration=10) next_key = cache_suffix_time(next_day, key_hash, duration=10) if before_key != next_key: changed_on_hour += 1 assert changed_on_hour == 1 def test_cache_suffix_time_matches_duration(self): """ The number of seconds between keys changing should match duration """ previous_key = cache_suffix_time(self.now, 0, duration=10) changes = [] for i in range(21): current_time = self.now + timedelta(seconds=i) current_key = cache_suffix_time(current_time, 0, duration=10) if current_key != previous_key: changes.append(current_time) previous_key = current_key assert len(changes) == 2 assert (changes[1] - changes[0]).total_seconds() == 10 def test_cache_suffix_time_jitter(self): """ Different key hashes should change keys at different times While starting_key and other_key might begin as the same values they should change at different times """ starting_key = cache_suffix_time(self.now, 0, duration=10) for i in range(11): current_key = cache_suffix_time(self.now + timedelta(seconds=i), 0, duration=10) if current_key != starting_key: break other_key = cache_suffix_time(self.now, 5, duration=10) for j in range(11): current_key = cache_suffix_time(self.now + timedelta(seconds=j), 5, duration=10) if current_key != other_key: break assert i != j
class TagStorageTest(TestCase, SnubaTestCase): def setUp(self): super(TagStorageTest, self).setUp() self.ts = SnubaTagStorage() self.proj1 = self.create_project() self.proj1env1 = self.create_environment(project=self.proj1, name='test') self.proj1env2 = self.create_environment(project=self.proj1, name='test2') self.proj1group1 = self.create_group(self.proj1) self.proj1group2 = self.create_group(self.proj1) hash1 = '1' * 32 hash2 = '2' * 32 GroupHash.objects.create(project=self.proj1, group=self.proj1group1, hash=hash1) GroupHash.objects.create(project=self.proj1, group=self.proj1group2, hash=hash2) self.now = timezone.now().replace(microsecond=0) data = json.dumps([{ 'event_id': six.text_type(r) * 32, 'primary_hash': hash1, 'group_id': self.proj1group1.id, 'project_id': self.proj1.id, 'message': 'message 1', 'platform': 'python', 'datetime': (self.now - timedelta(seconds=r) ).strftime('%Y-%m-%dT%H:%M:%S.%fZ'), 'data': { 'received': calendar.timegm(self.now.timetuple()) - r, 'tags': { 'foo': 'bar', 'baz': 'quux', 'environment': self.proj1env1.name, 'sentry:release': 100 * r, 'sentry:user': u"id:user{}".format(r), }, 'user': { 'id': u"user{}".format(r), 'email': u"user{}@sentry.io".format(r) } }, } for r in [1, 2]] + [{ 'event_id': '3' * 32, 'primary_hash': hash2, 'group_id': self.proj1group2.id, 'project_id': self.proj1.id, 'message': 'message 2', 'platform': 'python', 'datetime': (self.now - timedelta(seconds=2) ).strftime('%Y-%m-%dT%H:%M:%S.%fZ'), 'data': { 'received': calendar.timegm(self.now.timetuple()) - 2, 'tags': { 'browser': 'chrome', 'environment': self.proj1env1.name, 'sentry:user': "******", }, 'user': { 'id': "user1" } }, }] + [{ 'event_id': '4' * 32, 'primary_hash': hash2, 'group_id': self.proj1group1.id, 'project_id': self.proj1.id, 'message': 'message 2', 'platform': 'python', 'datetime': (self.now - timedelta(seconds=2) ).strftime('%Y-%m-%dT%H:%M:%S.%fZ'), 'data': { 'received': calendar.timegm(self.now.timetuple()) - 2, 'tags': { 'foo': 'bar', 'environment': self.proj1env2.name, }, 'user': { 'id': "user1" } }, }]) assert requests.post(settings.SENTRY_SNUBA + '/tests/events/insert', data=data).status_code == 200 def test_get_group_tag_keys_and_top_values(self): result = list( self.ts.get_group_tag_keys_and_top_values( self.proj1.id, self.proj1group1.id, [self.proj1env1.id], )) tags = [r.key for r in result] assert set(tags) == set( ['foo', 'baz', 'environment', 'sentry:release', 'sentry:user']) result.sort(key=lambda r: r.key) assert result[0].key == 'baz' assert result[0].top_values[0].value == 'quux' assert result[0].count == 2 assert result[3].key == 'sentry:release' assert result[3].count == 2 top_release_values = result[3].top_values assert len(top_release_values) == 2 assert set(v.value for v in top_release_values) == set(['100', '200']) assert all(v.times_seen == 1 for v in top_release_values) # Now with only a specific set of keys, result = list( self.ts.get_group_tag_keys_and_top_values( self.proj1.id, self.proj1group1.id, [self.proj1env1.id], keys=['environment', 'sentry:release'], )) tags = [r.key for r in result] assert set(tags) == set(['environment', 'sentry:release']) result.sort(key=lambda r: r.key) assert result[0].key == 'environment' assert result[0].top_values[0].value == 'test' assert result[1].key == 'sentry:release' top_release_values = result[1].top_values assert len(top_release_values) == 2 assert set(v.value for v in top_release_values) == set(['100', '200']) assert all(v.times_seen == 1 for v in top_release_values) def test_get_top_group_tag_values(self): resp = self.ts.get_top_group_tag_values(self.proj1.id, self.proj1group1.id, self.proj1env1.id, 'foo', 1) assert len(resp) == 1 assert resp[0].times_seen == 2 assert resp[0].key == 'foo' assert resp[0].value == 'bar' assert resp[0].group_id == self.proj1group1.id def test_get_group_tag_value_count(self): assert self.ts.get_group_tag_value_count(self.proj1.id, self.proj1group1.id, self.proj1env1.id, 'foo') == 2 def test_get_tag_keys(self): expected_keys = set([ 'baz', 'browser', 'environment', 'foo', 'sentry:release', 'sentry:user', ]) keys = { k.key: k for k in self.ts.get_tag_keys( project_id=self.proj1.id, environment_id=self.proj1env1.id, ) } assert set(keys) == expected_keys keys = { k.key: k for k in self.ts.get_tag_keys( project_id=self.proj1.id, environment_id=self.proj1env1.id, include_values_seen=True, ) } assert set(keys) == expected_keys def test_get_group_tag_key(self): with pytest.raises(GroupTagKeyNotFound): self.ts.get_group_tag_key( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_id=self.proj1env1.id, key='notreal', ) assert self.ts.get_group_tag_key( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_id=self.proj1env1.id, key='foo', ).key == 'foo' keys = { k.key: k for k in self.ts.get_group_tag_keys( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_ids=[self.proj1env1.id], ) } assert set(keys) == set( ['baz', 'environment', 'foo', 'sentry:release', 'sentry:user']) def test_get_group_tag_value(self): with pytest.raises(GroupTagValueNotFound): self.ts.get_group_tag_value( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_id=self.proj1env1.id, key='foo', value='notreal', ) assert self.ts.get_group_tag_values( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_id=self.proj1env1.id, key='notreal', ) == set([]) assert list( self.ts.get_group_tag_values( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_id=self.proj1env1.id, key='foo', ))[0].value == 'bar' assert self.ts.get_group_tag_value( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_id=self.proj1env1.id, key='foo', value='bar', ).value == 'bar' def test_get_tag_key(self): with pytest.raises(TagKeyNotFound): self.ts.get_tag_key(project_id=self.proj1.id, environment_id=self.proj1env1.id, key='notreal') def test_get_tag_value(self): with pytest.raises(TagValueNotFound): self.ts.get_tag_value( project_id=self.proj1.id, environment_id=self.proj1env1.id, key='foo', value='notreal', ) def test_get_groups_user_counts(self): assert self.ts.get_groups_user_counts( project_ids=[self.proj1.id], group_ids=[self.proj1group1.id, self.proj1group2.id], environment_ids=[self.proj1env1.id]) == { self.proj1group1.id: 2, self.proj1group2.id: 1, } # test filtering by date range where there shouldn't be results assert self.ts.get_groups_user_counts( project_ids=[self.proj1.id], group_ids=[self.proj1group1.id, self.proj1group2.id], environment_ids=[self.proj1env1.id], start=self.now - timedelta(days=5), end=self.now - timedelta(days=4), ) == {} def test_get_releases(self): assert self.ts.get_first_release( project_id=self.proj1.id, group_id=self.proj1group1.id, ) == '200' assert self.ts.get_first_release( project_id=self.proj1.id, group_id=self.proj1group2.id, ) is None assert self.ts.get_last_release( project_id=self.proj1.id, group_id=self.proj1group1.id, ) == '100' assert self.ts.get_last_release( project_id=self.proj1.id, group_id=self.proj1group2.id, ) is None def test_get_group_ids_for_users(self): assert self.ts.get_group_ids_for_users( [self.proj1.id], [EventUser(project_id=self.proj1.id, ident='user1')]) == set( [self.proj1group1.id, self.proj1group2.id]) assert self.ts.get_group_ids_for_users( [self.proj1.id], [EventUser(project_id=self.proj1.id, ident='user2')]) == set( [self.proj1group1.id]) def test_get_group_tag_values_for_users(self): result = self.ts.get_group_tag_values_for_users( [EventUser(project_id=self.proj1.id, ident='user1')]) assert len(result) == 2 assert set(v.group_id for v in result) == set([ self.proj1group1.id, self.proj1group2.id, ]) assert set(v.last_seen for v in result) == \ set([self.now - timedelta(seconds=1), self.now - timedelta(seconds=2)]) result.sort(key=lambda x: x.last_seen) assert result[0].last_seen == self.now - timedelta(seconds=2) assert result[1].last_seen == self.now - timedelta(seconds=1) for v in result: assert v.value == 'user1' result = self.ts.get_group_tag_values_for_users( [EventUser(project_id=self.proj1.id, ident='user2')]) assert len(result) == 1 assert result[0].value == 'user2' assert result[0].last_seen == self.now - timedelta(seconds=2) def test_get_release_tags(self): tags = list(self.ts.get_release_tags([self.proj1.id], None, ['100'])) assert len(tags) == 1 one_second_ago = self.now - timedelta(seconds=1) assert tags[0].last_seen == one_second_ago assert tags[0].first_seen == one_second_ago assert tags[0].times_seen == 1 assert tags[0].key == 'sentry:release' def test_get_group_event_filter(self): assert self.ts.get_group_event_filter( self.proj1.id, self.proj1group1.id, [self.proj1env1.id], { 'foo': 'bar', }, None, None, ) == { 'event_id__in': set(["1" * 32, "2" * 32]) } assert self.ts.get_group_event_filter( self.proj1.id, self.proj1group1.id, [self.proj1env1.id], { 'foo': 'bar', }, (self.now - timedelta(seconds=1)), None, ) == { 'event_id__in': set(["1" * 32]) } assert self.ts.get_group_event_filter( self.proj1.id, self.proj1group1.id, [self.proj1env1.id], { 'foo': 'bar', }, None, (self.now - timedelta(seconds=1)), ) == { 'event_id__in': set(["2" * 32]) } assert self.ts.get_group_event_filter( self.proj1.id, self.proj1group1.id, [self.proj1env1.id, self.proj1env2.id], { 'foo': 'bar', }, None, None, ) == { 'event_id__in': set(["1" * 32, "2" * 32, "4" * 32]) } assert self.ts.get_group_event_filter( self.proj1.id, self.proj1group1.id, [self.proj1env1.id], { 'foo': 'bar', # AND 'sentry:release': '200' }, None, None, ) == { 'event_id__in': set(["2" * 32]) } assert self.ts.get_group_event_filter( self.proj1.id, self.proj1group2.id, [self.proj1env1.id], {'browser': 'chrome'}, None, None, ) == { 'event_id__in': set(["3" * 32]) } assert self.ts.get_group_event_filter( self.proj1.id, self.proj1group2.id, [self.proj1env1.id], {'browser': 'ie'}, None, None, ) is None def test_get_tag_value_paginator(self): from sentry.tagstore.types import TagValue assert list( self.ts.get_tag_value_paginator( self.proj1.id, self.proj1env1.id, 'sentry:user', ).get_result(10)) == [ TagValue(key='sentry:user', value='id:user1', times_seen=2, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=1)), TagValue(key='sentry:user', value='id:user2', times_seen=1, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=2)) ] assert list( self.ts.get_tag_value_paginator( self.proj1.id, self.proj1env1.id, 'sentry:user', query='user1', ).get_result(10)) == [ TagValue(key='sentry:user', value='id:user1', times_seen=2, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=1)), ] def test_get_group_tag_value_iter(self): from sentry.tagstore.types import GroupTagValue assert list( self.ts.get_group_tag_value_iter( self.proj1.id, self.proj1group1.id, self.proj1env1.id, 'sentry:user', )) == [ GroupTagValue(group_id=self.proj1group1.id, key='sentry:user', value='id:user1', times_seen=1, first_seen=self.now - timedelta(seconds=1), last_seen=self.now - timedelta(seconds=1)), GroupTagValue(group_id=self.proj1group1.id, key='sentry:user', value='id:user2', times_seen=1, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=2)) ] def test_get_group_tag_value_paginator(self): from sentry.tagstore.types import GroupTagValue assert list( self.ts.get_group_tag_value_paginator( self.proj1.id, self.proj1group1.id, self.proj1env1.id, 'sentry:user', ).get_result(10)) == [ GroupTagValue(group_id=self.proj1group1.id, key='sentry:user', value='id:user1', times_seen=1, first_seen=self.now - timedelta(seconds=1), last_seen=self.now - timedelta(seconds=1)), GroupTagValue(group_id=self.proj1group1.id, key='sentry:user', value='id:user2', times_seen=1, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=2)) ] def test_get_group_seen_values_for_environments(self): assert self.ts.get_group_seen_values_for_environments( [self.proj1.id], [self.proj1group1.id], [self.proj1env1.id]) == { self.proj1group1.id: { 'first_seen': self.now - timedelta(seconds=2), 'last_seen': self.now - timedelta(seconds=1), 'times_seen': 2, } } # test where there should be no results because of time filters assert self.ts.get_group_seen_values_for_environments( [self.proj1.id], [self.proj1group1.id], [self.proj1env1.id], start=self.now - timedelta(hours=5), end=self.now - timedelta(hours=4), ) == {}
class TagStorageTest(TestCase, SnubaTestCase): def setUp(self): super().setUp() self.ts = SnubaTagStorage() self.proj1 = self.create_project() env1 = "test" env2 = "test2" self.env3 = Environment.objects.create( organization_id=self.proj1.organization_id, name="test3") self.now = timezone.now().replace(microsecond=0) self.store_event( data={ "event_id": "1" * 32, "message": "message 1", "platform": "python", "environment": env1, "fingerprint": ["group-1"], "timestamp": iso_format(self.now - timedelta(seconds=1)), "tags": { "foo": "bar", "baz": "quux", "sentry:release": 100, "sentry:user": "******", }, "user": { "id": "user1" }, "exception": exception, }, project_id=self.proj1.id, ) self.proj1group1 = self.store_event( data={ "event_id": "2" * 32, "message": "message 1", "platform": "python", "environment": env1, "fingerprint": ["group-1"], "timestamp": iso_format(self.now - timedelta(seconds=2)), "tags": { "foo": "bar", "baz": "quux", "sentry:release": 200, "sentry:user": "******", }, "user": { "id": "user2" }, "exception": exception, }, project_id=self.proj1.id, ).group self.proj1group2 = self.store_event( data={ "event_id": "3" * 32, "message": "message 2", "platform": "python", "environment": env1, "fingerprint": ["group-2"], "timestamp": iso_format(self.now - timedelta(seconds=2)), "tags": { "browser": "chrome", "sentry:user": "******" }, "user": { "id": "user1" }, }, project_id=self.proj1.id, ).group self.store_event( data={ "event_id": "4" * 32, "message": "message2", "platform": "python", "environment": env2, "fingerprint": ["group-1"], "timestamp": iso_format(self.now - timedelta(seconds=2)), "tags": { "foo": "bar" }, }, project_id=self.proj1.id, ) self.proj1env1 = Environment.objects.get(name=env1) self.proj1env2 = Environment.objects.get(name=env2) def test_get_group_tag_keys_and_top_values(self): result = list( self.ts.get_group_tag_keys_and_top_values(self.proj1.id, self.proj1group1.id, [self.proj1env1.id])) tags = [r.key for r in result] assert set(tags) == { "foo", "baz", "environment", "sentry:release", "sentry:user", "level" } result.sort(key=lambda r: r.key) assert result[0].key == "baz" assert result[0].top_values[0].value == "quux" assert result[0].count == 2 assert result[4].key == "sentry:release" assert result[4].count == 2 top_release_values = result[4].top_values assert len(top_release_values) == 2 assert {v.value for v in top_release_values} == {"100", "200"} assert all(v.times_seen == 1 for v in top_release_values) # Now with only a specific set of keys, result = list( self.ts.get_group_tag_keys_and_top_values( self.proj1.id, self.proj1group1.id, [self.proj1env1.id], keys=["environment", "sentry:release"], )) tags = [r.key for r in result] assert set(tags) == {"environment", "sentry:release"} result.sort(key=lambda r: r.key) assert result[0].key == "environment" assert result[0].top_values[0].value == "test" assert result[1].key == "sentry:release" top_release_values = result[1].top_values assert len(top_release_values) == 2 assert {v.value for v in top_release_values} == {"100", "200"} assert all(v.times_seen == 1 for v in top_release_values) def test_get_top_group_tag_values(self): resp = self.ts.get_top_group_tag_values(self.proj1.id, self.proj1group1.id, self.proj1env1.id, "foo", 1) assert len(resp) == 1 assert resp[0].times_seen == 2 assert resp[0].key == "foo" assert resp[0].value == "bar" assert resp[0].group_id == self.proj1group1.id def test_get_group_tag_value_count(self): assert (self.ts.get_group_tag_value_count(self.proj1.id, self.proj1group1.id, self.proj1env1.id, "foo") == 2) def test_get_tag_keys(self): expected_keys = { "baz", "browser", "environment", "foo", "sentry:release", "sentry:user", "level", } keys = { k.key: k for k in self.ts.get_tag_keys(project_id=self.proj1.id, environment_id=self.proj1env1.id) } assert set(keys) == expected_keys keys = { k.key: k for k in self.ts.get_tag_keys(project_id=self.proj1.id, environment_id=self.proj1env1.id, include_values_seen=True) } assert set(keys) == expected_keys def test_get_group_tag_key(self): with pytest.raises(GroupTagKeyNotFound): self.ts.get_group_tag_key( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_id=self.proj1env1.id, key="notreal", ) assert (self.ts.get_group_tag_key( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_id=self.proj1env1.id, key="foo", ).key == "foo") keys = { k.key: k for k in self.ts.get_group_tag_keys( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_ids=[self.proj1env1.id], ) } assert set(keys) == { "baz", "environment", "foo", "sentry:release", "sentry:user", "level" } def test_get_group_tag_value(self): with pytest.raises(GroupTagValueNotFound): self.ts.get_group_tag_value( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_id=self.proj1env1.id, key="foo", value="notreal", ) assert (self.ts.get_group_tag_values( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_id=self.proj1env1.id, key="notreal", ) == set()) assert (list( self.ts.get_group_tag_values( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_id=self.proj1env1.id, key="foo", ))[0].value == "bar") assert (self.ts.get_group_tag_value( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_id=self.proj1env1.id, key="foo", value="bar", ).value == "bar") def test_get_tag_key(self): with pytest.raises(TagKeyNotFound): self.ts.get_tag_key(project_id=self.proj1.id, environment_id=self.proj1env1.id, key="notreal") def test_get_tag_value(self): with pytest.raises(TagValueNotFound): self.ts.get_tag_value( project_id=self.proj1.id, environment_id=self.proj1env1.id, key="foo", value="notreal", ) def test_get_tag_value_label(self): assert self.ts.get_tag_value_label("foo", "notreal") == "notreal" assert self.ts.get_tag_value_label("sentry:user", None) is None assert self.ts.get_tag_value_label("sentry:user", "id:stuff") == "stuff" assert self.ts.get_tag_value_label("sentry:user", "email:stuff") == "stuff" assert self.ts.get_tag_value_label("sentry:user", "username:stuff") == "stuff" assert self.ts.get_tag_value_label("sentry:user", "ip:stuff") == "stuff" def test_get_groups_user_counts(self): assert (self.ts.get_groups_user_counts( project_ids=[self.proj1.id], group_ids=[self.proj1group1.id, self.proj1group2.id], environment_ids=[self.proj1env1.id], ) == { self.proj1group1.id: 2, self.proj1group2.id: 1 }) # test filtering by date range where there shouldn't be results assert (self.ts.get_groups_user_counts( project_ids=[self.proj1.id], group_ids=[self.proj1group1.id, self.proj1group2.id], environment_ids=[self.proj1env1.id], start=self.now - timedelta(days=5), end=self.now - timedelta(days=4), ) == {}) def test_get_group_ids_for_users(self): assert self.ts.get_group_ids_for_users( [self.proj1.id], [EventUser(project_id=self.proj1.id, ident="user1")]) == { self.proj1group1.id, self.proj1group2.id } assert self.ts.get_group_ids_for_users( [self.proj1.id], [EventUser(project_id=self.proj1.id, ident="user2")]) == { self.proj1group1.id } def test_get_group_tag_values_for_users(self): result = self.ts.get_group_tag_values_for_users( [EventUser(project_id=self.proj1.id, ident="user1")]) assert len(result) == 2 assert {v.group_id for v in result} == {self.proj1group1.id, self.proj1group2.id} assert {v.last_seen for v in result} == { self.now - timedelta(seconds=1), self.now - timedelta(seconds=2), } result.sort(key=lambda x: x.last_seen) assert result[0].last_seen == self.now - timedelta(seconds=2) assert result[1].last_seen == self.now - timedelta(seconds=1) for v in result: assert v.value == "user1" result = self.ts.get_group_tag_values_for_users( [EventUser(project_id=self.proj1.id, ident="user2")]) assert len(result) == 1 assert result[0].value == "user2" assert result[0].last_seen == self.now - timedelta(seconds=2) def test_get_release_tags(self): tags = list( self.ts.get_release_tags(self.proj1.organization_id, [self.proj1.id], None, ["100"])) assert len(tags) == 1 one_second_ago = self.now - timedelta(seconds=1) assert tags[0].last_seen == one_second_ago assert tags[0].first_seen == one_second_ago assert tags[0].times_seen == 1 assert tags[0].key == "sentry:release" def test_get_release_tags_uses_release_project_environment(self): tags = list( self.ts.get_release_tags(self.proj1.organization_id, [self.proj1.id], None, ["100"])) assert len(tags) == 1 one_second_ago = self.now - timedelta(seconds=1) assert tags[0].last_seen == one_second_ago assert tags[0].first_seen == one_second_ago assert tags[0].times_seen == 1 one_day_ago = self.now - timedelta(days=1) two_days_ago = self.now - timedelta(days=2) self.store_event( data={ "event_id": "5" * 32, "message": "message3", "platform": "python", "environment": None, "fingerprint": ["group-1"], "timestamp": iso_format(one_day_ago), "tags": { "sentry:release": 100, }, }, project_id=self.proj1.id, ) release = Release.objects.create(version="100", organization=self.organization) ReleaseProjectEnvironment.objects.create( release_id=release.id, project_id=self.proj1.id, environment_id=self.env3.id, first_seen=one_day_ago, ) self.store_event( data={ "event_id": "6" * 32, "message": "message3", "platform": "python", "environment": None, "fingerprint": ["group-1"], "timestamp": iso_format(two_days_ago), "tags": { "sentry:release": 100, }, }, project_id=self.proj1.id, ) tags = list( self.ts.get_release_tags(self.proj1.organization_id, [self.proj1.id], None, ["100"])) assert tags[0].last_seen == one_second_ago assert tags[0].first_seen == one_day_ago assert ( tags[0].times_seen == 2 ) # Isn't 3 because start was limited by the ReleaseProjectEnvironment entry def test_get_group_event_filter(self): assert self.ts.get_group_event_filter(self.proj1.id, self.proj1group1.id, [self.proj1env1.id], {"foo": "bar"}, None, None) == { "event_id__in": {"1" * 32, "2" * 32} } assert (self.ts.get_group_event_filter( self.proj1.id, self.proj1group1.id, [self.proj1env1.id], {"foo": "bar"}, (self.now - timedelta(seconds=1)), None, ) == { "event_id__in": {"1" * 32} }) assert (self.ts.get_group_event_filter( self.proj1.id, self.proj1group1.id, [self.proj1env1.id], {"foo": "bar"}, None, (self.now - timedelta(seconds=1)), ) == { "event_id__in": {"2" * 32} }) assert (self.ts.get_group_event_filter( self.proj1.id, self.proj1group1.id, [self.proj1env1.id, self.proj1env2.id], {"foo": "bar"}, None, None, ) == { "event_id__in": {"1" * 32, "2" * 32, "4" * 32} }) assert (self.ts.get_group_event_filter( self.proj1.id, self.proj1group1.id, [self.proj1env1.id], { "foo": "bar", "sentry:release": "200" }, # AND None, None, ) == { "event_id__in": {"2" * 32} }) assert (self.ts.get_group_event_filter( self.proj1.id, self.proj1group2.id, [self.proj1env1.id], {"browser": "chrome"}, None, None, ) == { "event_id__in": {"3" * 32} }) assert (self.ts.get_group_event_filter( self.proj1.id, self.proj1group2.id, [self.proj1env1.id], {"browser": "ie"}, None, None, ) is None) def test_get_tag_value_paginator(self): from sentry.tagstore.types import TagValue assert list( self.ts.get_tag_value_paginator( self.proj1.id, self.proj1env1.id, "sentry:user").get_result(10)) == [ TagValue( key="sentry:user", value="id:user1", times_seen=2, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=1), ), TagValue( key="sentry:user", value="id:user2", times_seen=1, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=2), ), ] assert list( self.ts.get_tag_value_paginator( self.proj1.id, self.proj1env1.id, "sentry:user", query="user1").get_result(10)) == [ TagValue( key="sentry:user", value="id:user1", times_seen=2, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=1), ) ] def test_get_tag_value_paginator_with_dates(self): from sentry.tagstore.types import TagValue day_ago = self.now - timedelta(days=1) two_days_ago = self.now - timedelta(days=2) assert list( self.ts.get_tag_value_paginator( self.proj1.id, self.proj1env1.id, "sentry:user", start=day_ago, end=self.now).get_result(10)) == [ TagValue( key="sentry:user", value="id:user1", times_seen=2, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=1), ), TagValue( key="sentry:user", value="id:user2", times_seen=1, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=2), ), ] day_ago = self.now - timedelta(days=1) assert (list( self.ts.get_tag_value_paginator(self.proj1.id, self.proj1env1.id, "sentry:user", start=two_days_ago, end=day_ago).get_result(10)) == []) def test_numeric_tag_value_paginator(self): from sentry.tagstore.types import TagValue assert list( self.ts.get_tag_value_paginator( self.proj1.id, self.proj1env1.id, "stack.lineno").get_result(10)) == [ TagValue( key="stack.lineno", value="29", times_seen=2, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=1), ) ] assert list( self.ts.get_tag_value_paginator( self.proj1.id, self.proj1env1.id, "stack.lineno", query="30").get_result(10)) == [ TagValue( key="stack.lineno", value="29", times_seen=2, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=1), ) ] def test_get_group_tag_value_iter(self): from sentry.tagstore.types import GroupTagValue assert list( self.ts.get_group_tag_value_iter( self.proj1.id, self.proj1group1.id, [self.proj1env1.id], "sentry:user")) == [ GroupTagValue( group_id=self.proj1group1.id, key="sentry:user", value="id:user1", times_seen=1, first_seen=self.now - timedelta(seconds=1), last_seen=self.now - timedelta(seconds=1), ), GroupTagValue( group_id=self.proj1group1.id, key="sentry:user", value="id:user2", times_seen=1, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=2), ), ] def test_get_group_tag_value_paginator(self): from sentry.tagstore.types import GroupTagValue assert list( self.ts.get_group_tag_value_paginator( self.proj1.id, self.proj1group1.id, [self.proj1env1.id], "sentry:user").get_result(10)) == [ GroupTagValue( group_id=self.proj1group1.id, key="sentry:user", value="id:user1", times_seen=1, first_seen=self.now - timedelta(seconds=1), last_seen=self.now - timedelta(seconds=1), ), GroupTagValue( group_id=self.proj1group1.id, key="sentry:user", value="id:user2", times_seen=1, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=2), ), ] def test_get_group_tag_value_paginator_times_seen(self): from sentry.tagstore.types import GroupTagValue self.store_event( data={ "event_id": "5" * 32, "message": "message 1", "platform": "python", "environment": self.proj1env1.name, "fingerprint": ["group-1"], "timestamp": iso_format(self.now - timedelta(seconds=2)), "tags": { "foo": "bar", "baz": "quux", "sentry:release": 100, "sentry:user": "******", }, "user": { "id": "user2" }, "exception": exception, }, project_id=self.proj1.id, ) assert list( self.ts.get_group_tag_value_paginator( self.proj1.id, self.proj1group1.id, [self.proj1env1.id], "sentry:user", order_by="-times_seen", ).get_result(10)) == [ GroupTagValue( group_id=self.proj1group1.id, key="sentry:user", value="id:user2", times_seen=2, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=2), ), GroupTagValue( group_id=self.proj1group1.id, key="sentry:user", value="id:user1", times_seen=1, first_seen=self.now - timedelta(seconds=1), last_seen=self.now - timedelta(seconds=1), ), ] def test_get_group_seen_values_for_environments(self): assert self.ts.get_group_seen_values_for_environments( [self.proj1.id], [self.proj1group1.id], [self.proj1env1.id]) == { self.proj1group1.id: { "first_seen": self.now - timedelta(seconds=2), "last_seen": self.now - timedelta(seconds=1), "times_seen": 2, } } # test where there should be no results because of time filters assert (self.ts.get_group_seen_values_for_environments( [self.proj1.id], [self.proj1group1.id], [self.proj1env1.id], start=self.now - timedelta(hours=5), end=self.now - timedelta(hours=4), ) == {})
class TagStorageTest(TestCase, SnubaTestCase): def setUp(self): super(TagStorageTest, self).setUp() self.ts = SnubaTagStorage() self.proj1 = self.create_project() self.proj1env1 = self.create_environment(project=self.proj1, name='test') self.proj1env2 = self.create_environment(project=self.proj1, name='test2') self.proj1group1 = self.create_group(self.proj1) self.proj1group2 = self.create_group(self.proj1) hash1 = '1' * 32 hash2 = '2' * 32 GroupHash.objects.create(project=self.proj1, group=self.proj1group1, hash=hash1) GroupHash.objects.create(project=self.proj1, group=self.proj1group2, hash=hash2) self.now = timezone.now().replace(microsecond=0) data = json.dumps([{ 'event_id': six.text_type(r) * 32, 'primary_hash': hash1, 'group_id': self.proj1group1.id, 'project_id': self.proj1.id, 'message': 'message 1', 'platform': 'python', 'datetime': (self.now - timedelta(seconds=r)).strftime('%Y-%m-%dT%H:%M:%S.%fZ'), 'data': { 'received': calendar.timegm(self.now.timetuple()) - r, 'tags': { 'foo': 'bar', 'baz': 'quux', 'environment': self.proj1env1.name, 'sentry:release': 100 * r, 'sentry:user': u"id:user{}".format(r), }, 'user': { 'id': u"user{}".format(r), 'email': u"user{}@sentry.io".format(r) } }, } for r in [1, 2]] + [{ 'event_id': '3' * 32, 'primary_hash': hash2, 'group_id': self.proj1group2.id, 'project_id': self.proj1.id, 'message': 'message 2', 'platform': 'python', 'datetime': (self.now - timedelta(seconds=2)).strftime('%Y-%m-%dT%H:%M:%S.%fZ'), 'data': { 'received': calendar.timegm(self.now.timetuple()) - 2, 'tags': { 'browser': 'chrome', 'environment': self.proj1env1.name, 'sentry:user': "******", }, 'user': { 'id': "user1" } }, }] + [{ 'event_id': '4' * 32, 'primary_hash': hash2, 'group_id': self.proj1group1.id, 'project_id': self.proj1.id, 'message': 'message 2', 'platform': 'python', 'datetime': (self.now - timedelta(seconds=2)).strftime('%Y-%m-%dT%H:%M:%S.%fZ'), 'data': { 'received': calendar.timegm(self.now.timetuple()) - 2, 'tags': { 'foo': 'bar', 'environment': self.proj1env2.name, }, 'user': { 'id': "user1" } }, }]) assert requests.post(settings.SENTRY_SNUBA + '/tests/insert', data=data).status_code == 200 def test_get_group_tag_keys_and_top_values(self): result = list(self.ts.get_group_tag_keys_and_top_values( self.proj1.id, self.proj1group1.id, [self.proj1env1.id], )) tags = [r.key for r in result] assert set(tags) == set(['foo', 'baz', 'environment', 'sentry:release', 'sentry:user']) result.sort(key=lambda r: r.key) assert result[0].key == 'baz' assert result[0].top_values[0].value == 'quux' assert result[0].count == 2 assert result[3].key == 'sentry:release' assert result[3].count == 2 top_release_values = result[3].top_values assert len(top_release_values) == 2 assert set(v.value for v in top_release_values) == set(['100', '200']) assert all(v.times_seen == 1 for v in top_release_values) # Now with only a specific set of keys, result = list(self.ts.get_group_tag_keys_and_top_values( self.proj1.id, self.proj1group1.id, [self.proj1env1.id], keys=['environment', 'sentry:release'], )) tags = [r.key for r in result] assert set(tags) == set(['environment', 'sentry:release']) result.sort(key=lambda r: r.key) assert result[0].key == 'environment' assert result[0].top_values[0].value == 'test' assert result[1].key == 'sentry:release' top_release_values = result[1].top_values assert len(top_release_values) == 2 assert set(v.value for v in top_release_values) == set(['100', '200']) assert all(v.times_seen == 1 for v in top_release_values) def test_get_top_group_tag_values(self): resp = self.ts.get_top_group_tag_values( self.proj1.id, self.proj1group1.id, self.proj1env1.id, 'foo', 1 ) assert len(resp) == 1 assert resp[0].times_seen == 2 assert resp[0].key == 'foo' assert resp[0].value == 'bar' assert resp[0].group_id == self.proj1group1.id def test_get_group_tag_value_count(self): assert self.ts.get_group_tag_value_count( self.proj1.id, self.proj1group1.id, self.proj1env1.id, 'foo' ) == 2 def test_get_tag_keys(self): expected_keys = set([ 'baz', 'browser', 'environment', 'foo', 'sentry:release', 'sentry:user', ]) keys = { k.key: k for k in self.ts.get_tag_keys( project_id=self.proj1.id, environment_id=self.proj1env1.id, ) } assert set(keys) == expected_keys keys = { k.key: k for k in self.ts.get_tag_keys( project_id=self.proj1.id, environment_id=self.proj1env1.id, include_values_seen=True, ) } assert set(keys) == expected_keys def test_get_group_tag_key(self): with pytest.raises(GroupTagKeyNotFound): self.ts.get_group_tag_key( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_id=self.proj1env1.id, key='notreal', ) assert self.ts.get_group_tag_key( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_id=self.proj1env1.id, key='foo', ).key == 'foo' keys = { k.key: k for k in self.ts.get_group_tag_keys( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_ids=[self.proj1env1.id], ) } assert set(keys) == set(['baz', 'environment', 'foo', 'sentry:release', 'sentry:user']) def test_get_group_tag_value(self): with pytest.raises(GroupTagValueNotFound): self.ts.get_group_tag_value( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_id=self.proj1env1.id, key='foo', value='notreal', ) assert self.ts.get_group_tag_values( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_id=self.proj1env1.id, key='notreal', ) == set([]) assert list(self.ts.get_group_tag_values( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_id=self.proj1env1.id, key='foo', ))[0].value == 'bar' assert self.ts.get_group_tag_value( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_id=self.proj1env1.id, key='foo', value='bar', ).value == 'bar' def test_get_tag_key(self): with pytest.raises(TagKeyNotFound): self.ts.get_tag_key( project_id=self.proj1.id, environment_id=self.proj1env1.id, key='notreal' ) def test_get_tag_value(self): with pytest.raises(TagValueNotFound): self.ts.get_tag_value( project_id=self.proj1.id, environment_id=self.proj1env1.id, key='foo', value='notreal', ) def test_get_groups_user_counts(self): assert self.ts.get_groups_user_counts( project_ids=[self.proj1.id], group_ids=[self.proj1group1.id, self.proj1group2.id], environment_ids=[self.proj1env1.id] ) == { self.proj1group1.id: 2, self.proj1group2.id: 1, } # test filtering by date range where there shouldn't be results assert self.ts.get_groups_user_counts( project_ids=[self.proj1.id], group_ids=[self.proj1group1.id, self.proj1group2.id], environment_ids=[self.proj1env1.id], start=self.now - timedelta(days=5), end=self.now - timedelta(days=4), ) == {} def test_get_releases(self): assert self.ts.get_first_release( project_id=self.proj1.id, group_id=self.proj1group1.id, ) == '200' assert self.ts.get_first_release( project_id=self.proj1.id, group_id=self.proj1group2.id, ) is None assert self.ts.get_last_release( project_id=self.proj1.id, group_id=self.proj1group1.id, ) == '100' assert self.ts.get_last_release( project_id=self.proj1.id, group_id=self.proj1group2.id, ) is None def test_get_group_ids_for_users(self): assert self.ts.get_group_ids_for_users( [self.proj1.id], [EventUser(project_id=self.proj1.id, ident='user1')] ) == set([self.proj1group1.id, self.proj1group2.id]) assert self.ts.get_group_ids_for_users( [self.proj1.id], [EventUser(project_id=self.proj1.id, ident='user2')] ) == set([self.proj1group1.id]) def test_get_group_tag_values_for_users(self): result = self.ts.get_group_tag_values_for_users( [EventUser(project_id=self.proj1.id, ident='user1')] ) assert len(result) == 2 assert set(v.group_id for v in result) == set([ self.proj1group1.id, self.proj1group2.id, ]) assert set(v.last_seen for v in result) == \ set([self.now - timedelta(seconds=1), self.now - timedelta(seconds=2)]) result.sort(key=lambda x: x.last_seen) assert result[0].last_seen == self.now - timedelta(seconds=2) assert result[1].last_seen == self.now - timedelta(seconds=1) for v in result: assert v.value == 'user1' result = self.ts.get_group_tag_values_for_users( [EventUser(project_id=self.proj1.id, ident='user2')] ) assert len(result) == 1 assert result[0].value == 'user2' assert result[0].last_seen == self.now - timedelta(seconds=2) def test_get_release_tags(self): tags = list( self.ts.get_release_tags( [self.proj1.id], None, ['100'] ) ) assert len(tags) == 1 one_second_ago = self.now - timedelta(seconds=1) assert tags[0].last_seen == one_second_ago assert tags[0].first_seen == one_second_ago assert tags[0].times_seen == 1 assert tags[0].key == 'sentry:release' def test_get_group_event_filter(self): assert self.ts.get_group_event_filter( self.proj1.id, self.proj1group1.id, [self.proj1env1.id], { 'foo': 'bar', }, None, None, ) == {'event_id__in': set(["1" * 32, "2" * 32])} assert self.ts.get_group_event_filter( self.proj1.id, self.proj1group1.id, [self.proj1env1.id], { 'foo': 'bar', }, (self.now - timedelta(seconds=1)), None, ) == {'event_id__in': set(["1" * 32])} assert self.ts.get_group_event_filter( self.proj1.id, self.proj1group1.id, [self.proj1env1.id], { 'foo': 'bar', }, None, (self.now - timedelta(seconds=1)), ) == {'event_id__in': set(["2" * 32])} assert self.ts.get_group_event_filter( self.proj1.id, self.proj1group1.id, [self.proj1env1.id, self.proj1env2.id], { 'foo': 'bar', }, None, None, ) == {'event_id__in': set(["1" * 32, "2" * 32, "4" * 32])} assert self.ts.get_group_event_filter( self.proj1.id, self.proj1group1.id, [self.proj1env1.id], { 'foo': 'bar', # AND 'sentry:release': '200' }, None, None, ) == {'event_id__in': set(["2" * 32])} assert self.ts.get_group_event_filter( self.proj1.id, self.proj1group2.id, [self.proj1env1.id], { 'browser': 'chrome' }, None, None, ) == {'event_id__in': set(["3" * 32])} assert self.ts.get_group_event_filter( self.proj1.id, self.proj1group2.id, [self.proj1env1.id], { 'browser': 'ie' }, None, None, ) is None def test_get_tag_value_paginator(self): from sentry.tagstore.types import TagValue assert list(self.ts.get_tag_value_paginator( self.proj1.id, self.proj1env1.id, 'sentry:user', ).get_result(10)) == [ TagValue( key='sentry:user', value='id:user1', times_seen=2, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=1) ), TagValue( key='sentry:user', value='id:user2', times_seen=1, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=2) ) ] assert list(self.ts.get_tag_value_paginator( self.proj1.id, self.proj1env1.id, 'sentry:user', query='user1', ).get_result(10)) == [ TagValue( key='sentry:user', value='id:user1', times_seen=2, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=1) ), ] def test_get_group_tag_value_iter(self): from sentry.tagstore.types import GroupTagValue assert list(self.ts.get_group_tag_value_iter( self.proj1.id, self.proj1group1.id, self.proj1env1.id, 'sentry:user', )) == [ GroupTagValue( group_id=self.proj1group1.id, key='sentry:user', value='id:user1', times_seen=1, first_seen=self.now - timedelta(seconds=1), last_seen=self.now - timedelta(seconds=1) ), GroupTagValue( group_id=self.proj1group1.id, key='sentry:user', value='id:user2', times_seen=1, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=2) ) ] def test_get_group_tag_value_paginator(self): from sentry.tagstore.types import GroupTagValue assert list(self.ts.get_group_tag_value_paginator( self.proj1.id, self.proj1group1.id, self.proj1env1.id, 'sentry:user', ).get_result(10)) == [ GroupTagValue( group_id=self.proj1group1.id, key='sentry:user', value='id:user1', times_seen=1, first_seen=self.now - timedelta(seconds=1), last_seen=self.now - timedelta(seconds=1) ), GroupTagValue( group_id=self.proj1group1.id, key='sentry:user', value='id:user2', times_seen=1, first_seen=self.now - timedelta(seconds=2), last_seen=self.now - timedelta(seconds=2) ) ] def test_get_group_seen_values_for_environments(self): assert self.ts.get_group_seen_values_for_environments( [self.proj1.id], [self.proj1group1.id], [self.proj1env1.id] ) == {self.proj1group1.id: { 'first_seen': self.now - timedelta(seconds=2), 'last_seen': self.now - timedelta(seconds=1), 'times_seen': 2, }} # test where there should be no results because of time filters assert self.ts.get_group_seen_values_for_environments( [self.proj1.id], [self.proj1group1.id], [self.proj1env1.id], start=self.now - timedelta(hours=5), end=self.now - timedelta(hours=4), ) == {}