class TagStorage(TestCase): def setUp(self): 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='prod') self.proj1group1 = self.create_group(self.proj1) self.proj1group2 = self.create_group(self.proj1) GroupHash.objects.create(project=self.proj1, group=self.proj1group1, hash='1' * 32) GroupHash.objects.create(project=self.proj1, group=self.proj1group2, hash='2' * 32) @responses.activate def test_get_group_ids_for_search_filter(self): from sentry.search.base import ANY tags = { 'foo': 'bar', 'baz': 'quux', } with responses.RequestsMock() as rsps: def snuba_response(request): body = json.loads(request.body) assert body['project'] == [self.proj1.id] assert body['groupby'] == ['issue'] assert body['issues'] assert ['tags[foo]', '=', 'bar'] in body['conditions'] assert ['tags[baz]', '=', 'quux'] in body['conditions'] return (200, {}, json.dumps({ 'meta': [{'name': 'issue'}, {'name': 'aggregate'}], 'data': [{'issue': self.proj1group1.id, 'aggregate': 1}], })) rsps.add_callback(responses.POST, snuba.SNUBA + '/query', callback=snuba_response) result = self.ts.get_group_ids_for_search_filter(self.proj1.id, self.proj1env1.id, tags) assert result == [self.proj1group1.id] tags = { 'foo': ANY, } with responses.RequestsMock() as rsps: def snuba_response_2(request): body = json.loads(request.body) assert body['project'] == [self.proj1.id] assert body['groupby'] == ['issue'] assert body['issues'] assert ['tags[foo]', 'IS NOT NULL', None] in body['conditions'] return (200, {}, json.dumps({ 'meta': [{'name': 'issue'}, {'name': 'aggregate'}], 'data': [{'issue': self.proj1group2.id, 'aggregate': 1}], })) rsps.add_callback(responses.POST, snuba.SNUBA + '/query', callback=snuba_response_2) result = self.ts.get_group_ids_for_search_filter(self.proj1.id, self.proj1env1.id, tags) assert result == [self.proj1group2.id]
class TagStorage(TestCase): def setUp(self): assert requests.post(snuba.SNUBA + '/tests/drop').status_code == 200 self.ts = SnubaTagStorage() self.proj1 = self.create_project() self.proj1env1 = self.create_environment(project=self.proj1, name='test') 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 = datetime.utcnow().replace(microsecond=0) data = json.dumps([{ 'event_id': six.text_type(r) * 32, 'primary_hash': hash1, '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.interfaces.User': { 'id': "user{}".format(r), 'email': "user{}@sentry.io".format(r) } }, } for r in range(1, 3)] + [{ 'event_id': '3' * 32, 'primary_hash': hash2, 'project_id': self.proj1.id, 'message': 'message 2', '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': { 'browser': 'chrome', 'environment': self.proj1env1.name, }, 'sentry.interfaces.User': { 'id': "user1" } }, }]) assert requests.post(snuba.SNUBA + '/tests/insert', data=data).status_code == 200 @responses.activate def test_get_group_ids_for_search_filter(self): from sentry.search.base import ANY tags = { 'foo': 'bar', 'baz': 'quux', } with responses.RequestsMock() as rsps: def snuba_response(request): body = json.loads(request.body) assert body['project'] == [self.proj1.id] assert body['groupby'] == ['issue'] assert body['issues'] assert ['tags[foo]', '=', 'bar'] in body['conditions'] assert ['tags[baz]', '=', 'quux'] in body['conditions'] return (200, {}, json.dumps({ 'meta': [{ 'name': 'issue' }, { 'name': 'aggregate' }], 'data': [{ 'issue': self.proj1group1.id, 'aggregate': 1 }], })) rsps.add_callback(responses.POST, snuba.SNUBA + '/query', callback=snuba_response) result = self.ts.get_group_ids_for_search_filter( self.proj1.id, self.proj1env1.id, tags) assert result == [self.proj1group1.id] tags = { 'foo': ANY, } with responses.RequestsMock() as rsps: def snuba_response_2(request): body = json.loads(request.body) assert body['project'] == [self.proj1.id] assert body['groupby'] == ['issue'] assert body['issues'] assert ['tags[foo]', 'IS NOT NULL', None] in body['conditions'] return (200, {}, json.dumps({ 'meta': [{ 'name': 'issue' }, { 'name': 'aggregate' }], 'data': [{ 'issue': self.proj1group2.id, 'aggregate': 1 }], })) rsps.add_callback(responses.POST, snuba.SNUBA + '/query', callback=snuba_response_2) result = self.ts.get_group_ids_for_search_filter( self.proj1.id, self.proj1env1.id, tags) assert result == [self.proj1group2.id] def test_get_group_tag_keys_and_top_values(self): result = self.ts.get_group_tag_keys_and_top_values( self.proj1.id, self.proj1group1.id, self.proj1env1.id, ) result.sort(key=lambda r: r['id']) assert result[0]['key'] == 'baz' assert result[1]['key'] == 'foo' assert result[0]['uniqueValues'] == 1 assert result[0]['totalValues'] == 2 assert result[0]['topValues'][0]['value'] == 'quux' assert result[1]['topValues'][0]['value'] == 'bar' 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_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 = self.ts.get_group_tag_keys( project_id=self.proj1.id, group_id=self.proj1group1.id, environment_id=self.proj1env1.id, ) keys.sort(key=lambda x: x.key) assert len(keys) == 2 assert keys[0].key == 'baz' assert keys[0].times_seen == 2 assert keys[1].key == 'foo' assert keys[1].times_seen == 2 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', ) == [] assert 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_id=self.proj1.id, group_ids=[self.proj1group1.id, self.proj1group2.id], environment_id=self.proj1env1.id) == { self.proj1group1.id: 2, self.proj1group2.id: 1, } 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 set( 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 set( 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')]) one_second_ago = ( self.now - timedelta(seconds=1)).strftime('%Y-%m-%dT%H:%M:%S+00:00') assert len(result) == 1 assert result[0].value == 'user1' assert result[0].last_seen == one_second_ago result = self.ts.get_group_tag_values_for_users( [EventUser(project_id=self.proj1.id, ident='user2')]) two_seconds_ago = ( self.now - timedelta(seconds=2)).strftime('%Y-%m-%dT%H:%M:%S+00:00') assert len(result) == 1 assert result[0].value == 'user2' assert result[0].last_seen == two_seconds_ago # Test that users identified by different means are collected. # (effectively tests OR conditions in snuba API) result = self.ts.get_group_tag_values_for_users([ EventUser(project_id=self.proj1.id, email='*****@*****.**'), EventUser(project_id=self.proj1.id, ident='user2') ]) two_seconds_ago = ( self.now - timedelta(seconds=2)).strftime('%Y-%m-%dT%H:%M:%S+00:00') assert len(result) == 2 result.sort(key=lambda x: x.value) assert result[0].value == 'user1' assert result[0].last_seen == one_second_ago assert result[1].value == 'user2' assert result[1].last_seen == two_seconds_ago def test_get_release_tags(self): tags = self.ts.get_release_tags([self.proj1.id], None, ['100']) assert len(tags) == 1 one_second_ago = ( self.now - timedelta(seconds=1)).strftime('%Y-%m-%dT%H:%M:%S+00:00') assert tags[0].last_seen == one_second_ago assert tags[0].first_seen == one_second_ago assert tags[0].times_seen == 1 def test_get_group_event_ids(self): assert sorted( self.ts.get_group_event_ids(self.proj1.id, self.proj1group1.id, self.proj1env1.id, { 'foo': 'bar', })) == ["1" * 32, "2" * 32] assert sorted( self.ts.get_group_event_ids( self.proj1.id, self.proj1group1.id, self.proj1env1.id, { 'foo': 'bar', # OR 'release': '200' })) == ["1" * 32, "2" * 32] assert self.ts.get_group_event_ids( self.proj1.id, self.proj1group2.id, self.proj1env1.id, {'browser': 'chrome'}) == ["3" * 32] assert self.ts.get_group_event_ids(self.proj1.id, self.proj1group2.id, self.proj1env1.id, {'browser': 'ie'}) == []