diff --git a/src/sentry/models/group.py b/src/sentry/models/group.py index 0ed5c85fc3d070..fabc3f1942e3a0 100644 --- a/src/sentry/models/group.py +++ b/src/sentry/models/group.py @@ -22,9 +22,7 @@ from django.utils.translation import ugettext_lazy as _ from sentry import eventtypes, tagstore -from sentry.constants import ( - DEFAULT_LOGGER_NAME, EVENT_ORDERING_KEY, LOG_LEVELS, MAX_CULPRIT_LENGTH -) +from sentry.constants import DEFAULT_LOGGER_NAME, LOG_LEVELS, MAX_CULPRIT_LENGTH from sentry.db.models import ( BaseManager, BoundedBigIntegerField, BoundedIntegerField, BoundedPositiveIntegerField, FlexibleForeignKey, GzippedDictField, Model, sane_repr @@ -407,20 +405,9 @@ def get_score(self): return type(self).calculate_score(self.times_seen, self.last_seen) def get_latest_event(self): - from sentry.models import Event - if not hasattr(self, '_latest_event'): - latest_events = sorted( - Event.objects.filter( - group_id=self.id, - ).order_by('-datetime')[0:5], - key=EVENT_ORDERING_KEY, - reverse=True, - ) - try: - self._latest_event = latest_events[0] - except IndexError: - self._latest_event = None + self._latest_event = self.get_latest_event_for_environments() + return self._latest_event def get_latest_event_for_environments(self, environments=()): diff --git a/tests/sentry/api/endpoints/test_group_integration_details.py b/tests/sentry/api/endpoints/test_group_integration_details.py index 751d9fc1e7d33a..aeb0980c33f942 100644 --- a/tests/sentry/api/endpoints/test_group_integration_details.py +++ b/tests/sentry/api/endpoints/test_group_integration_details.py @@ -2,26 +2,44 @@ import six import mock +from datetime import timedelta +from django.utils import timezone +import copy from sentry.integrations.example.integration import ExampleIntegration from sentry.integrations.exceptions import IntegrationError from sentry.models import Activity, ExternalIssue, GroupLink, Integration from sentry.testutils import APITestCase from sentry.utils.http import absolute_uri +from sentry.testutils.factories import DEFAULT_EVENT_DATA class GroupIntegrationDetailsTest(APITestCase): + def setUp(self): + super(GroupIntegrationDetailsTest, self).setUp() + self.min_ago = timezone.now() - timedelta(minutes=1) + self.event = self.store_event( + data={ + 'event_id': 'a' * 32, + 'timestamp': self.min_ago.isoformat()[:19], + 'message': 'message', + 'stacktrace': copy.deepcopy(DEFAULT_EVENT_DATA['stacktrace']), + }, + project_id=self.project.id + ) + self.group = self.event.group + def test_simple_get_link(self): self.login_as(user=self.user) org = self.organization - group = self.create_group() integration = Integration.objects.create( provider='example', name='Example', ) integration.add_organization(org, self.user) - path = u'/api/0/issues/{}/integrations/{}/?action=link'.format(group.id, integration.id) + path = u'/api/0/issues/{}/integrations/{}/?action=link'.format( + self.group.id, integration.id) with self.feature('organizations:integrations-issue-basic'): response = self.client.get(path) @@ -61,13 +79,12 @@ def test_simple_get_link(self): def test_simple_get_create(self): self.login_as(user=self.user) org = self.organization - group = self.create_group() - self.create_event(group=group) integration = Integration.objects.create( provider='example', name='Example', ) integration.add_organization(org, self.user) + group = self.group path = u'/api/0/issues/{}/integrations/{}/?action=create'.format(group.id, integration.id) @@ -99,7 +116,7 @@ def test_simple_get_create(self): 'required': True, }, { 'default': ('Sentry Issue: [%s](%s)\n\n```\n' - 'Stacktrace (most recent call last):\n\n ' + 'Stacktrace (most recent call first):\n\n ' 'File "sentry/models/foo.py", line 29, in build_msg\n ' 'string_max_length=self.string_max_length)\n\nmessage\n```' ) % (group.qualified_short_id, absolute_uri(group.get_absolute_url(params={'referrer': 'example_integration'}))), @@ -121,15 +138,14 @@ def test_simple_get_create(self): def test_get_create_with_error(self): self.login_as(user=self.user) org = self.organization - group = self.create_group() - self.create_event(group=group) integration = Integration.objects.create( provider='example', name='Example', ) integration.add_organization(org, self.user) - path = u'/api/0/issues/{}/integrations/{}/?action=create'.format(group.id, integration.id) + path = u'/api/0/issues/{}/integrations/{}/?action=create'.format( + self.group.id, integration.id) with self.feature('organizations:integrations-issue-basic'): with mock.patch.object(ExampleIntegration, 'get_create_issue_config', side_effect=IntegrationError('oops')): @@ -141,15 +157,14 @@ def test_get_create_with_error(self): def test_get_feature_disabled(self): self.login_as(user=self.user) org = self.organization - group = self.create_group() - self.create_event(group=group) integration = Integration.objects.create( provider='example', name='Example', ) integration.add_organization(org, self.user) - path = u'/api/0/issues/{}/integrations/{}/?action=create'.format(group.id, integration.id) + path = u'/api/0/issues/{}/integrations/{}/?action=create'.format( + self.group.id, integration.id) with self.feature({'organizations:integrations-issue-basic': False}): response = self.client.get(path) @@ -167,7 +182,6 @@ def test_simple_put(self): integration.add_organization(org, self.user) path = u'/api/0/issues/{}/integrations/{}/'.format(group.id, integration.id) - with self.feature('organizations:integrations-issue-basic'): response = self.client.put(path, data={ 'externalIssue': 'APP-123' @@ -367,8 +381,14 @@ def assert_default_project(path, action, expected_project_field): self.login_as(user=self.user) org = self.organization - group = self.create_group() - self.create_event(group=group) + event = self.store_event( + data={ + 'event_id': 'a' * 32, + 'timestamp': self.min_ago.isoformat()[:19], + }, + project_id=self.project.id + ) + group = event.group integration = Integration.objects.create( provider='example', name='Example', diff --git a/tests/sentry/api/endpoints/test_shared_group_details.py b/tests/sentry/api/endpoints/test_shared_group_details.py index ba6c8785f10e2e..2bcb539f06051e 100644 --- a/tests/sentry/api/endpoints/test_shared_group_details.py +++ b/tests/sentry/api/endpoints/test_shared_group_details.py @@ -1,6 +1,8 @@ from __future__ import absolute_import, print_function import six +from datetime import timedelta +from django.utils import timezone from sentry.testutils import APITestCase from sentry.models import GroupShare @@ -10,8 +12,14 @@ class SharedGroupDetailsTest(APITestCase): def test_simple(self): self.login_as(user=self.user) - group = self.create_group() - event = self.create_event(group=group) + min_ago = (timezone.now() - timedelta(minutes=1)).isoformat()[:19] + event = self.store_event( + data={ + 'timestamp': min_ago, + }, + project_id=self.project.id, + ) + group = event.group share_id = group.get_share_id() assert share_id is None @@ -29,7 +37,7 @@ def test_simple(self): assert response.status_code == 200, response.content assert response.data['id'] == six.text_type(group.id) - assert response.data['latestEvent']['id'] == six.text_type(event.id) + assert response.data['latestEvent']['id'] == six.text_type(event.event_id) assert response.data['project']['slug'] == group.project.slug assert response.data['project']['organization']['slug'] == group.organization.slug diff --git a/tests/sentry/integrations/bitbucket/test_issues.py b/tests/sentry/integrations/bitbucket/test_issues.py index ec8f1c686bdd3f..cf20c9576ba829 100644 --- a/tests/sentry/integrations/bitbucket/test_issues.py +++ b/tests/sentry/integrations/bitbucket/test_issues.py @@ -1,8 +1,14 @@ from __future__ import absolute_import +from datetime import timedelta +import copy + +from django.utils import timezone + from sentry.integrations.bitbucket.issues import ISSUE_TYPES, PRIORITIES from sentry.models import ExternalIssue, Integration from sentry.testutils import APITestCase +from sentry.testutils.factories import DEFAULT_EVENT_DATA import json import responses @@ -24,8 +30,18 @@ def setUp(self): 'subject': self.subject, } ) - self.group = self.create_group() - self.create_event(group=self.group) + min_ago = (timezone.now() - timedelta(minutes=1)).isoformat()[:19] + event = self.store_event( + data={ + 'event_id': 'a' * 32, + 'message': 'message', + 'timestamp': min_ago, + 'stacktrace': copy.deepcopy(DEFAULT_EVENT_DATA['stacktrace']), + + }, + project_id=self.project.id, + ) + self.group = event.group self.repo_choices = [('myaccount/repo1', 'myaccount/repo1'), ('myaccount/repo2', 'myaccount/repo2')] self.org_integration = self.integration.add_organization(self.organization) @@ -203,7 +219,7 @@ def test_get_create_issue_config(self): }, { 'name': 'description', 'label': 'Description', - 'default': u'Sentry Issue: [BAR-1](http://testserver/organizations/baz/issues/%d/?referrer=bitbucket_integration)\n\n```\nStacktrace (most recent call last):\n\n File "sentry/models/foo.py", line 29, in build_msg\n string_max_length=self.string_max_length)\n\nmessage\n```' % self.group.id, + 'default': u'Sentry Issue: [BAR-1](http://testserver/organizations/baz/issues/%d/?referrer=bitbucket_integration)\n\n```\nStacktrace (most recent call first):\n\n File "sentry/models/foo.py", line 29, in build_msg\n string_max_length=self.string_max_length)\n\nmessage\n```' % self.group.id, 'type': 'textarea', 'autosize': True, 'maxRows': 10, diff --git a/tests/sentry/integrations/github/test_issues.py b/tests/sentry/integrations/github/test_issues.py index 98ab1f2bf09b57..b6ca0fb53052e6 100644 --- a/tests/sentry/integrations/github/test_issues.py +++ b/tests/sentry/integrations/github/test_issues.py @@ -2,10 +2,12 @@ import responses import six +from datetime import timedelta from mock import patch from exam import fixture from django.test import RequestFactory +from django.utils import timezone from sentry.integrations.github.integration import GitHubIntegration from sentry.models import Integration, ExternalIssue @@ -28,6 +30,7 @@ def setUp(self): ) self.model.add_organization(self.organization, self.user) self.integration = GitHubIntegration(self.model, self.organization.id) + self.min_ago = (timezone.now() - timedelta(minutes=1)).isoformat()[:19] @responses.activate @patch('sentry.integrations.github.client.get_jwt', return_value='jwt_token_1') @@ -155,8 +158,13 @@ def test_link_issue(self, mock_get_jwt): @responses.activate @patch('sentry.integrations.github.client.get_jwt', return_value='jwt_token_1') def test_repo_dropdown_choices(self, mock_get_jwt): - group = self.create_group() - self.create_event(group) + event = self.store_event( + data={ + 'event_id': 'a' * 32, + 'timestamp': self.min_ago, + }, + project_id=self.project.id, + ) responses.add( responses.POST, @@ -176,7 +184,7 @@ def test_repo_dropdown_choices(self, mock_get_jwt): json={'repositories': [{'full_name': 'getsentry/sentry', 'name': 'sentry'}]} ) - resp = self.integration.get_create_issue_config(group=self.group) + resp = self.integration.get_create_issue_config(group=event.group) assert resp[0]['choices'] == [(u'getsentry/sentry', u'sentry')] responses.add( @@ -187,12 +195,12 @@ def test_repo_dropdown_choices(self, mock_get_jwt): # create an issue data = {'params': {'repo': 'getsentry/hello'}} - resp = self.integration.get_create_issue_config(group=self.group, **data) + resp = self.integration.get_create_issue_config(group=event.group, **data) assert resp[0]['choices'] == [(u'getsentry/hello', u'hello'), (u'getsentry/sentry', u'sentry')] # link an issue data = {'params': {'repo': 'getsentry/hello'}} - resp = self.integration.get_link_issue_config(group=self.group, **data) + resp = self.integration.get_link_issue_config(group=event.group, **data) assert resp[0]['choices'] == [(u'getsentry/hello', u'hello'), (u'getsentry/sentry', u'sentry')] @@ -240,8 +248,15 @@ def test_default_repo_link_fields(self, mock_get_jwt): ] }, ) - group = self.create_group() - self.create_event(group=group) + event = self.store_event( + data={ + 'event_id': 'a' * 32, + 'timestamp': self.min_ago, + }, + project_id=self.project.id, + ) + group = event.group + org_integration = self.integration.org_integration org_integration.config = { 'project_issue_defaults': { @@ -278,8 +293,14 @@ def test_default_repo_create_fields(self, mock_get_jwt): 'https://api.github.com/installations/github_external_id/access_tokens', json={'token': 'token_1', 'expires_at': '2018-10-11T22:14:10Z'} ) - group = self.create_group() - self.create_event(group=group) + event = self.store_event( + data={ + 'event_id': 'a' * 32, + 'timestamp': self.min_ago, + }, + project_id=self.project.id, + ) + group = event.group org_integration = self.integration.org_integration org_integration.config = { 'project_issue_defaults': { @@ -304,10 +325,14 @@ def test_default_repo_link_fields_no_repos(self, mock_get_jwt): 'repositories': [] }, ) - group = self.create_group() - self.create_event(group=group) - - fields = self.integration.get_link_issue_config(group) + event = self.store_event( + data={ + 'event_id': 'a' * 32, + 'timestamp': self.min_ago, + }, + project_id=self.project.id, + ) + fields = self.integration.get_link_issue_config(event.group) repo_field = [field for field in fields if field['name'] == 'repo'][0] assert repo_field['default'] is '' assert repo_field['choices'] == [] @@ -327,11 +352,14 @@ def test_default_repo_create_fields_no_repos(self, mock_get_jwt): 'https://api.github.com/installations/github_external_id/access_tokens', json={'token': 'token_1', 'expires_at': '2018-10-11T22:14:10Z'} ) - - group = self.create_group() - self.create_event(group=group) - - fields = self.integration.get_create_issue_config(group) + event = self.store_event( + data={ + 'event_id': 'a' * 32, + 'timestamp': self.min_ago, + }, + project_id=self.project.id, + ) + fields = self.integration.get_create_issue_config(event.group) repo_field = [field for field in fields if field['name'] == 'repo'][0] assignee_field = [field for field in fields if field['name'] == 'assignee'][0] diff --git a/tests/sentry/integrations/gitlab/test_issues.py b/tests/sentry/integrations/gitlab/test_issues.py index 4da18714d76db7..235d8afd6efb3b 100644 --- a/tests/sentry/integrations/gitlab/test_issues.py +++ b/tests/sentry/integrations/gitlab/test_issues.py @@ -2,10 +2,15 @@ import responses import six +from datetime import timedelta +import copy + +from django.utils import timezone from sentry.integrations.exceptions import IntegrationError from sentry.models import ExternalIssue from sentry.utils.http import absolute_uri +from sentry.testutils.factories import DEFAULT_EVENT_DATA from .testutils import GitLabTestCase @@ -13,8 +18,17 @@ class GitlabIssuesTest(GitLabTestCase): def setUp(self): super(GitlabIssuesTest, self).setUp() - self.group = self.create_group() - self.create_event(group=self.group) + min_ago = (timezone.now() - timedelta(minutes=1)).isoformat()[:19] + event = self.store_event( + data={ + 'event_id': 'a' * 32, + 'message': 'message', + 'timestamp': min_ago, + 'stacktrace': copy.deepcopy(DEFAULT_EVENT_DATA['stacktrace']), + }, + project_id=self.project.id, + ) + self.group = event.group def test_make_external_key(self): project_name = 'getsentry/sentry' @@ -35,7 +49,7 @@ def test_get_issue_url(self): def test_get_create_issue_config(self): group_description = ( u'Sentry Issue: [%s](%s)\n\n' - '```\nStacktrace (most recent call last):\n\n' + '```\nStacktrace (most recent call first):\n\n' ' File "sentry/models/foo.py", line 29, in build_msg\n' ' string_max_length=self.string_max_length)\n\nmessage\n```' ) % ( @@ -190,7 +204,7 @@ def test_get_issue(self): def test_create_issue_default_project_in_group_api_call(self): group_description = ( u'Sentry Issue: [%s](%s)\n\n' - '```\nStacktrace (most recent call last):\n\n' + '```\nStacktrace (most recent call first):\n\n' ' File "sentry/models/foo.py", line 29, in build_msg\n' ' string_max_length=self.string_max_length)\n\nmessage\n```' ) % ( @@ -254,7 +268,7 @@ def test_create_issue_default_project_in_group_api_call(self): def test_create_issue_default_project_not_in_api_call(self): group_description = ( u'Sentry Issue: [%s](%s)\n\n' - '```\nStacktrace (most recent call last):\n\n' + '```\nStacktrace (most recent call first):\n\n' ' File "sentry/models/foo.py", line 29, in build_msg\n' ' string_max_length=self.string_max_length)\n\nmessage\n```' ) % ( @@ -317,7 +331,7 @@ def test_create_issue_default_project_not_in_api_call(self): def test_create_issue_no_projects(self): group_description = ( u'Sentry Issue: [%s](%s)\n\n' - '```\nStacktrace (most recent call last):\n\n' + '```\nStacktrace (most recent call first):\n\n' ' File "sentry/models/foo.py", line 29, in build_msg\n' ' string_max_length=self.string_max_length)\n\nmessage\n```' ) % ( diff --git a/tests/sentry/integrations/jira/test_integration.py b/tests/sentry/integrations/jira/test_integration.py index d200b054fac6f7..58b7bf69703b33 100644 --- a/tests/sentry/integrations/jira/test_integration.py +++ b/tests/sentry/integrations/jira/test_integration.py @@ -5,6 +5,8 @@ import responses import six import pytest +import copy +from datetime import timedelta from django.core.urlresolvers import reverse from django.utils import timezone @@ -17,6 +19,7 @@ ) from sentry.testutils import APITestCase from sentry.utils.http import absolute_uri +from sentry.testutils.factories import DEFAULT_EVENT_DATA SAMPLE_CREATE_META_RESPONSE = """ @@ -435,11 +438,23 @@ def integration(self): self.user) return integration + def setUp(self): + super(JiraIntegrationTest, self).setUp() + self.min_ago = (timezone.now() - timedelta(minutes=1)).isoformat()[:19] + def test_get_create_issue_config(self): org = self.organization self.login_as(self.user) - group = self.create_group() - self.create_event(group=group) + event = self.store_event( + data={ + 'event_id': 'a' * 32, + 'message': 'message', + 'timestamp': self.min_ago, + 'stacktrace': copy.deepcopy(DEFAULT_EVENT_DATA['stacktrace']), + }, + project_id=self.project.id, + ) + group = event.group installation = self.integration.get_installation(org.id) @@ -462,7 +477,7 @@ def get_client(): 'required': True, }, { 'default': ('Sentry Issue: [%s|%s]\n\n{code}\n' - 'Stacktrace (most recent call last):\n\n ' + 'Stacktrace (most recent call first):\n\n ' 'File "sentry/models/foo.py", line 29, in build_msg\n ' 'string_max_length=self.string_max_length)\n\nmessage\n{code}' ) % ( @@ -510,9 +525,16 @@ def get_client(): def test_get_create_issue_config_with_default_and_param(self): org = self.organization self.login_as(self.user) - group = self.create_group() - self.create_event(group=group) - + event = self.store_event( + data={ + 'event_id': 'a' * 32, + 'message': 'message', + 'timestamp': self.min_ago, + 'stacktrace': copy.deepcopy(DEFAULT_EVENT_DATA['stacktrace']), + }, + project_id=self.project.id, + ) + group = event.group installation = self.integration.get_installation(org.id) installation.org_integration.config = { 'project_issue_defaults': { @@ -540,9 +562,16 @@ def get_client(): def test_get_create_issue_config_with_default(self): org = self.organization self.login_as(self.user) - group = self.create_group() - self.create_event(group=group) - + event = self.store_event( + data={ + 'event_id': 'a' * 32, + 'message': 'message', + 'timestamp': self.min_ago, + 'stacktrace': copy.deepcopy(DEFAULT_EVENT_DATA['stacktrace']), + }, + project_id=self.project.id, + ) + group = event.group installation = self.integration.get_installation(org.id) installation.org_integration.config = { 'project_issue_defaults': { @@ -570,9 +599,16 @@ def get_client(): def test_get_create_issue_config_with_label_default(self): org = self.organization self.login_as(self.user) - group = self.create_group() - self.create_event(group=group) - + event = self.store_event( + data={ + 'event_id': 'a' * 32, + 'message': 'message', + 'timestamp': self.min_ago, + 'stacktrace': copy.deepcopy(DEFAULT_EVENT_DATA['stacktrace']), + }, + project_id=self.project.id, + ) + group = event.group label_default = 'hi' installation = self.integration.get_installation(org.id) @@ -606,7 +642,7 @@ def test_get_create_issue_config__no_projects(self): event = self.store_event( data={ 'message': 'oh no', - 'timestamp': timezone.now().isoformat() + 'timestamp': self.min_ago, }, project_id=self.project.id ) @@ -632,7 +668,7 @@ def test_get_create_issue_config__no_issue_config(self): event = self.store_event( data={ 'message': 'oh no', - 'timestamp': timezone.now().isoformat() + 'timestamp': self.min_ago, }, project_id=self.project.id ) diff --git a/tests/sentry/integrations/vsts/test_issues.py b/tests/sentry/integrations/vsts/test_issues.py index a9989c67ca2450..b1fadf5c88fdc7 100644 --- a/tests/sentry/integrations/vsts/test_issues.py +++ b/tests/sentry/integrations/vsts/test_issues.py @@ -7,6 +7,8 @@ from exam import fixture from django.test import RequestFactory from time import time +from datetime import timedelta +from django.utils import timezone from sentry.integrations.exceptions import IntegrationError from sentry.integrations.vsts.integration import VstsIntegration @@ -349,8 +351,15 @@ def setUp(self): ] }, ) - self.group = self.create_group() - self.create_event(group=self.group) + min_ago = (timezone.now() - timedelta(minutes=1)).isoformat()[:19] + event = self.store_event( + data={ + 'fingerprint': ['group1'], + 'timestamp': min_ago, + }, + project_id=self.project.id, + ) + self.group = event.group def tearDown(self): responses.reset() diff --git a/tests/sentry/plugins/bases/test_issue2.py b/tests/sentry/plugins/bases/test_issue2.py index 3cda7000d1e6e4..77ed32bc8eed1a 100644 --- a/tests/sentry/plugins/bases/test_issue2.py +++ b/tests/sentry/plugins/bases/test_issue2.py @@ -4,7 +4,9 @@ import json import mock +from datetime import timedelta +from django.utils import timezone from social_auth.models import UserSocialAuth from sentry.models import GroupMeta, User @@ -80,12 +82,16 @@ class IssuePlugin2GroupActionTest(TestCase): def setUp(self): super(IssuePlugin2GroupActionTest, self).setUp() self.project = self.create_project() - self.group = self.create_group(project=self.project) self.plugin_instance = plugins.get(slug='issuetrackingplugin2') - self.event = self.create_event( - event_id='a', - group=self.group, + min_ago = (timezone.now() - timedelta(minutes=1)).isoformat()[:19] + self.event = self.store_event( + data={ + 'timestamp': min_ago, + 'fingerprint': ['group-1'] + }, + project_id=self.project.id ) + self.group = self.event.group @mock.patch('sentry.plugins.IssueTrackingPlugin2.is_configured', return_value=True) def test_get_create(self, *args):