123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804 |
- from datetime import datetime, timedelta
- from datetime import timezone as datetime_timezone
- from unittest.mock import Mock, patch
- import pytest
- import responses
- from celery.exceptions import MaxRetriesExceededError
- from django.utils import timezone
- from sentry.integrations.github.integration import GitHubIntegrationProvider
- from sentry.models import PullRequest, PullRequestComment, Repository
- from sentry.models.commit import Commit
- from sentry.models.groupowner import GroupOwner, GroupOwnerType
- from sentry.models.options.organization_option import OrganizationOption
- from sentry.models.pullrequest import PullRequestCommit
- from sentry.shared_integrations.exceptions.base import ApiError
- from sentry.snuba.sessions_v2 import isoformat_z
- from sentry.tasks.commit_context import PR_COMMENT_WINDOW, process_commit_context
- from sentry.testutils.cases import IntegrationTestCase, TestCase
- from sentry.testutils.helpers.datetime import before_now, iso_format
- from sentry.testutils.silo import region_silo_test
- from sentry.utils.committers import get_frame_paths
- class TestCommitContextMixin(TestCase):
- def setUp(self):
- self.project = self.create_project()
- self.repo = Repository.objects.create(
- organization_id=self.organization.id,
- name="example",
- integration_id=self.integration.id,
- )
- self.code_mapping = self.create_code_mapping(
- repo=self.repo,
- project=self.project,
- )
- self.commit_author = self.create_commit_author(project=self.project, user=self.user)
- self.commit = self.create_commit(
- project=self.project,
- repo=self.repo,
- author=self.commit_author,
- key="asdfwreqr",
- message="placeholder commit message",
- )
- self.group = self.create_group(
- project=self.project, message="Kaboom!", first_release=self.release
- )
- self.event = self.store_event(
- data={
- "message": "Kaboom!",
- "platform": "python",
- "timestamp": iso_format(before_now(seconds=10)),
- "stacktrace": {
- "frames": [
- {
- "function": "handle_set_commits",
- "abs_path": "/usr/src/sentry/src/sentry/tasks.py",
- "module": "sentry.tasks",
- "in_app": False,
- "lineno": 30,
- "filename": "sentry/tasks.py",
- },
- {
- "function": "set_commits",
- "abs_path": "/usr/src/sentry/src/sentry/models/release.py",
- "module": "sentry.models.release",
- "in_app": True,
- "lineno": 39,
- "filename": "sentry/models/release.py",
- },
- ]
- },
- "tags": {"sentry:release": self.release.version},
- "fingerprint": ["put-me-in-the-control-group"],
- },
- project_id=self.project.id,
- )
- @region_silo_test(stable=True)
- class TestCommitContext(TestCommitContextMixin):
- @patch(
- "sentry.integrations.github.GitHubIntegration.get_commit_context",
- return_value={
- "commitId": "asdfwreqr",
- "committedDate": (datetime.now(tz=datetime_timezone.utc) - timedelta(days=7)),
- "commitMessage": "placeholder commit message",
- "commitAuthorName": "",
- "commitAuthorEmail": "admin@localhost",
- },
- )
- def test_simple(self, mock_get_commit_context):
- with self.tasks():
- assert not GroupOwner.objects.filter(group=self.event.group).exists()
- event_frames = get_frame_paths(self.event)
- process_commit_context(
- event_id=self.event.event_id,
- event_platform=self.event.platform,
- event_frames=event_frames,
- group_id=self.event.group_id,
- project_id=self.event.project_id,
- )
- assert GroupOwner.objects.get(
- group=self.event.group,
- project=self.event.project,
- organization=self.event.project.organization,
- type=GroupOwnerType.SUSPECT_COMMIT.value,
- )
- assert GroupOwner.objects.get(
- group=self.event.group,
- project=self.event.project,
- organization=self.event.project.organization,
- type=GroupOwnerType.SUSPECT_COMMIT.value,
- ).context == {"commitId": self.commit.id}
- @patch("sentry.analytics.record")
- @patch(
- "sentry.integrations.github.GitHubIntegration.get_commit_context",
- side_effect=ApiError(text="integration_failed"),
- )
- def test_failed_to_fetch_commit_context_record(self, mock_get_commit_context, mock_record):
- with self.tasks():
- assert not GroupOwner.objects.filter(group=self.event.group).exists()
- event_frames = get_frame_paths(self.event)
- process_commit_context(
- event_id=self.event.event_id,
- event_platform=self.event.platform,
- event_frames=event_frames,
- group_id=self.event.group_id,
- project_id=self.event.project_id,
- )
- mock_record.assert_called_with(
- "integrations.failed_to_fetch_commit_context",
- organization_id=self.organization.id,
- project_id=self.project.id,
- code_mapping_id=self.code_mapping.id,
- group_id=self.event.group_id,
- provider="github",
- error_message="integration_failed",
- )
- @patch("sentry.tasks.commit_context.logger")
- @patch(
- "sentry.integrations.github.GitHubIntegration.get_commit_context",
- return_value={
- "commitId": "asdfasdf",
- "committedDate": (datetime.now(tz=datetime_timezone.utc) - timedelta(days=370)),
- "commitMessage": "placeholder commit message",
- "commitAuthorName": "",
- "commitAuthorEmail": "admin@localhost",
- },
- )
- def test_found_commit_is_too_old(self, mock_get_commit_context, mock_logger):
- with self.tasks():
- assert not GroupOwner.objects.filter(group=self.event.group).exists()
- event_frames = get_frame_paths(self.event)
- process_commit_context(
- event_id=self.event.event_id,
- event_platform=self.event.platform,
- event_frames=event_frames,
- group_id=self.event.group_id,
- project_id=self.event.project_id,
- )
- assert mock_logger.info.call_count == 1
- mock_logger.info.assert_called_with(
- "process_commit_context.find_commit_context",
- extra={
- "event": self.event.event_id,
- "group": self.event.group_id,
- "organization": self.event.group.project.organization_id,
- "reason": "could_not_fetch_commit_context",
- "code_mappings_count": 1,
- "fallback": True,
- },
- )
- @patch(
- "sentry.integrations.github.GitHubIntegration.get_commit_context",
- return_value={
- "commitId": "asdfasdf",
- "committedDate": (datetime.now(tz=datetime_timezone.utc) - timedelta(days=7)),
- "commitMessage": "placeholder commit message",
- "commitAuthorName": "",
- "commitAuthorEmail": "admin@localhost",
- },
- )
- def test_no_matching_commit_in_db(self, mock_get_commit_context):
- with self.tasks():
- assert not GroupOwner.objects.filter(group=self.event.group).exists()
- assert not Commit.objects.filter(key="asdfasdf").exists()
- event_frames = get_frame_paths(self.event)
- process_commit_context(
- event_id=self.event.event_id,
- event_platform=self.event.platform,
- event_frames=event_frames,
- group_id=self.event.group_id,
- project_id=self.event.project_id,
- )
- assert Commit.objects.filter(key="asdfasdf").exists()
- assert GroupOwner.objects.filter(group=self.event.group).exists()
- @patch(
- "sentry.integrations.github.GitHubIntegration.get_commit_context",
- return_value={
- "commitId": "asdfwreqr",
- "committedDate": (datetime.now(tz=datetime_timezone.utc) - timedelta(days=7)),
- "commitMessage": "placeholder commit message",
- "commitAuthorName": "",
- "commitAuthorEmail": "admin@localhost",
- },
- )
- def test_delete_old_entries(self, mock_get_commit_context):
- # As new events come in associated with new owners, we should delete old ones.
- user_2 = self.create_user("another@user.com", is_superuser=True)
- self.create_member(teams=[self.team], user=user_2, organization=self.organization)
- owner = GroupOwner.objects.create(
- group=self.event.group,
- user_id=user_2.id,
- project=self.project,
- organization=self.organization,
- type=GroupOwnerType.SUSPECT_COMMIT.value,
- date_added=timezone.now() - timedelta(days=8),
- )
- with self.tasks():
- event_frames = get_frame_paths(self.event)
- process_commit_context(
- event_id=self.event.event_id,
- event_platform=self.event.platform,
- event_frames=event_frames,
- group_id=self.event.group_id,
- project_id=self.event.project_id,
- )
- assert not GroupOwner.objects.filter(id=owner.id).exists()
- assert GroupOwner.objects.filter(group=self.event.group).count() == 1
- assert GroupOwner.objects.filter(group=self.event.group, user_id=self.user.id).exists()
- @patch("sentry.tasks.groupowner.process_suspect_commits.delay")
- def test_no_inapp_frame_in_stacktrace(self, mock_process_suspect_commits):
- with self.tasks():
- assert not GroupOwner.objects.filter(group=self.event.group).exists()
- self.event_2 = self.store_event(
- data={
- "message": "Kaboom!",
- "platform": "python",
- "timestamp": iso_format(before_now(seconds=10)),
- "stacktrace": {
- "frames": [
- {
- "function": "handle_set_commits",
- "abs_path": "/usr/src/sentry/src/sentry/tasks.py",
- "module": "sentry.tasks",
- "in_app": False,
- "lineno": 30,
- "filename": "sentry/tasks.py",
- },
- {
- "function": "set_commits",
- "abs_path": "/usr/src/sentry/src/sentry/models/release.py",
- "module": "sentry.models.release",
- "in_app": False,
- "lineno": 39,
- "filename": "sentry/models/release.py",
- },
- ]
- },
- "tags": {"sentry:release": self.release.version},
- "fingerprint": ["put-me-in-the-control-group"],
- },
- project_id=self.project.id,
- )
- event_frames = get_frame_paths(self.event_2)
- process_commit_context(
- event_id=self.event.event_id,
- event_platform=self.event.platform,
- event_frames=event_frames,
- group_id=self.event.group_id,
- project_id=self.event.project_id,
- )
- assert mock_process_suspect_commits.call_count == 1
- assert not GroupOwner.objects.filter(
- group=self.event.group,
- project=self.event.project,
- organization=self.event.project.organization,
- type=GroupOwnerType.SUSPECT_COMMIT.value,
- ).exists()
- @patch(
- "sentry.integrations.github.GitHubIntegration.get_commit_context",
- return_value={
- "commitId": "somekey",
- "committedDate": (datetime.now(tz=datetime_timezone.utc) - timedelta(days=7)),
- "commitMessage": "placeholder commit message",
- "commitAuthorName": "",
- "commitAuthorEmail": "randomuser@sentry.io",
- },
- )
- def test_commit_author_not_in_sentry(self, mock_get_commit_context):
- self.commit_author_2 = self.create_commit_author(
- project=self.project,
- )
- self.commit_2 = self.create_commit(
- project=self.project,
- repo=self.repo,
- author=self.commit_author_2,
- key="somekey",
- message="placeholder commit message",
- )
- with self.tasks():
- assert not GroupOwner.objects.filter(group=self.event.group).exists()
- event_frames = get_frame_paths(self.event)
- process_commit_context(
- event_id=self.event.event_id,
- event_platform=self.event.platform,
- event_frames=event_frames,
- group_id=self.event.group_id,
- project_id=self.event.project_id,
- )
- assert GroupOwner.objects.filter(group=self.event.group).exists()
- assert len(GroupOwner.objects.filter(group=self.event.group)) == 1
- owner = GroupOwner.objects.get(group=self.event.group)
- assert owner.type == GroupOwnerType.SUSPECT_COMMIT.value
- assert owner.user_id is None
- assert owner.team is None
- assert owner.context == {"commitId": self.commit_2.id}
- @patch("sentry.tasks.commit_context.get_users_for_authors", return_value={})
- @patch(
- "sentry.integrations.github.GitHubIntegration.get_commit_context",
- return_value={
- "commitId": "somekey",
- "committedDate": (datetime.now(tz=datetime_timezone.utc) - timedelta(days=7)),
- "commitMessage": "placeholder commit message",
- "commitAuthorName": "",
- "commitAuthorEmail": "randomuser@sentry.io",
- },
- )
- def test_commit_author_no_user(self, mock_get_commit_context, mock_get_users_for_author):
- self.commit_author_2 = self.create_commit_author(
- project=self.project,
- )
- self.commit_2 = self.create_commit(
- project=self.project,
- repo=self.repo,
- author=self.commit_author_2,
- key="somekey",
- message="placeholder commit message",
- )
- with self.tasks(), patch(
- "sentry.tasks.commit_context.get_users_for_authors", return_value={}
- ):
- event_frames = get_frame_paths(self.event)
- process_commit_context(
- event_id=self.event.event_id,
- event_platform=self.event.platform,
- event_frames=event_frames,
- group_id=self.event.group_id,
- project_id=self.event.project_id,
- )
- assert GroupOwner.objects.filter(group=self.event.group).exists()
- assert len(GroupOwner.objects.filter(group=self.event.group)) == 1
- owner = GroupOwner.objects.get(group=self.event.group)
- assert owner.type == GroupOwnerType.SUSPECT_COMMIT.value
- assert owner.user_id is None
- assert owner.team is None
- assert owner.context == {"commitId": self.commit_2.id}
- @patch(
- "sentry.integrations.github.GitHubIntegration.get_commit_context",
- return_value={
- "commitId": "somekey",
- "committedDate": (datetime.now(tz=datetime_timezone.utc) - timedelta(days=7)),
- "commitMessage": "placeholder commit message",
- "commitAuthorName": "",
- "commitAuthorEmail": "randomuser@sentry.io",
- },
- )
- def test_multiple_matching_code_mappings_but_only_1_repository_has_the_commit_in_db(
- self, mock_get_commit_context
- ):
- self.integration_2 = self.create_integration(
- organization=self.organization,
- provider="github",
- name="GitHub",
- external_id="github:2",
- )
- self.repo_2 = Repository.objects.create(
- organization_id=self.organization.id,
- name="another/example",
- integration_id=self.integration_2.id,
- )
- self.code_mapping_2 = self.create_code_mapping(
- repo=self.repo_2, project=self.project, stack_root="src", source_root="src"
- )
- self.commit_author_2 = self.create_commit_author(
- project=self.project,
- )
- self.commit_2 = self.create_commit(
- project=self.project,
- repo=self.repo_2,
- author=self.commit_author_2,
- key="somekey",
- message="placeholder commit message",
- )
- with self.tasks():
- assert not GroupOwner.objects.filter(group=self.event.group).exists()
- event_frames = get_frame_paths(self.event)
- process_commit_context(
- event_id=self.event.event_id,
- event_platform=self.event.platform,
- event_frames=event_frames,
- group_id=self.event.group_id,
- project_id=self.event.project_id,
- )
- assert GroupOwner.objects.filter(group=self.event.group).exists()
- assert len(GroupOwner.objects.filter(group=self.event.group)) == 1
- owner = GroupOwner.objects.get(group=self.event.group)
- assert owner.type == GroupOwnerType.SUSPECT_COMMIT.value
- assert owner.user_id is None
- assert owner.team is None
- assert owner.context == {"commitId": self.commit_2.id}
- @patch(
- "sentry.integrations.github.GitHubIntegration.get_commit_context",
- side_effect=ApiError(text="integration_failed"),
- )
- @patch("sentry.tasks.groupowner.process_suspect_commits.delay")
- def test_fallback_if_max_retries_exceeded(self, mock_suspect_commits, mock_get_commit_context):
- def after_return(self, status, retval, task_id, args, kwargs, einfo):
- raise MaxRetriesExceededError()
- with self.tasks() and pytest.raises(MaxRetriesExceededError):
- with patch("celery.app.task.Task.after_return", after_return):
- process_commit_context.apply(
- kwargs={
- "event_id": self.event.event_id,
- "event_platform": self.event.platform,
- "event_frames": get_frame_paths(self.event),
- "group_id": self.event.group_id,
- "project_id": self.event.project_id,
- },
- retries=1,
- )
- assert mock_suspect_commits.called
- @region_silo_test(stable=True)
- @patch(
- "sentry.integrations.github.GitHubIntegration.get_commit_context",
- Mock(
- return_value={
- "commitId": "asdfwreqr",
- "committedDate": (datetime.now(tz=datetime_timezone.utc) - timedelta(days=7)),
- "commitMessage": "placeholder commit message",
- "commitAuthorName": "",
- "commitAuthorEmail": "admin@localhost",
- }
- ),
- )
- @patch("sentry.tasks.integrations.github.pr_comment.github_comment_workflow.delay")
- class TestGHCommentQueuing(IntegrationTestCase, TestCommitContextMixin):
- provider = GitHubIntegrationProvider
- base_url = "https://api.github.com"
- def setUp(self):
- super().setUp()
- self.pull_request = PullRequest.objects.create(
- organization_id=self.commit.organization_id,
- repository_id=self.repo.id,
- key="99",
- author=self.commit.author,
- message="foo",
- title="bar",
- merge_commit_sha=self.commit.key,
- date_added=iso_format(before_now(days=1)),
- )
- self.repo.provider = "integrations:github"
- self.repo.save()
- self.pull_request_comment = PullRequestComment.objects.create(
- pull_request=self.pull_request,
- external_id=1,
- created_at=iso_format(before_now(days=1)),
- updated_at=iso_format(before_now(days=1)),
- group_ids=[],
- )
- self.installation_id = "github:1"
- self.user_id = "user_1"
- self.app_id = "app_1"
- self.access_token = "xxxxx-xxxxxxxxx-xxxxxxxxxx-xxxxxxxxxxxx"
- self.expires_at = isoformat_z(timezone.now() + timedelta(days=365))
- def add_responses(self):
- responses.add(
- responses.POST,
- self.base_url + f"/app/installations/{self.installation_id}/access_tokens",
- json={"token": self.access_token, "expires_at": self.expires_at},
- )
- responses.add(
- responses.GET,
- self.base_url + f"/repos/example/commits/{self.commit.key}/pulls",
- status=200,
- json=[{"merge_commit_sha": self.pull_request.merge_commit_sha}],
- )
- def test_gh_comment_not_github(self, mock_comment_workflow):
- """Non github repos shouldn't be commented on"""
- self.repo.provider = "integrations:gitlab"
- self.repo.save()
- with self.tasks():
- event_frames = get_frame_paths(self.event)
- process_commit_context(
- event_id=self.event.event_id,
- event_platform=self.event.platform,
- event_frames=event_frames,
- group_id=self.event.group_id,
- project_id=self.event.project_id,
- )
- assert not mock_comment_workflow.called
- def test_gh_comment_org_option(self, mock_comment_workflow):
- """No comments on org with organization option disabled"""
- OrganizationOption.objects.set_value(
- organization=self.project.organization, key="sentry:github_pr_bot", value=False
- )
- with self.tasks():
- event_frames = get_frame_paths(self.event)
- process_commit_context(
- event_id=self.event.event_id,
- event_platform=self.event.platform,
- event_frames=event_frames,
- group_id=self.event.group_id,
- project_id=self.event.project_id,
- )
- assert not mock_comment_workflow.called
- @patch("sentry.integrations.github.client.get_jwt", return_value=b"jwt_token_1")
- @responses.activate
- def test_gh_comment_no_pr_from_api(self, get_jwt, mock_comment_workflow):
- """No comments on suspect commit with no pr returned from API response"""
- self.pull_request.delete()
- responses.add(
- responses.POST,
- self.base_url + f"/app/installations/{self.installation_id}/access_tokens",
- json={"token": self.access_token, "expires_at": self.expires_at},
- )
- responses.add(
- responses.GET,
- self.base_url + f"/repos/example/commits/{self.commit.key}/pulls",
- status=200,
- json={"message": "No commit found for SHA"},
- )
- with self.tasks():
- event_frames = get_frame_paths(self.event)
- process_commit_context(
- event_id=self.event.event_id,
- event_platform=self.event.platform,
- event_frames=event_frames,
- group_id=self.event.group_id,
- project_id=self.event.project_id,
- )
- assert not mock_comment_workflow.called
- @patch("sentry.integrations.github.client.get_jwt", return_value=b"jwt_token_1")
- @patch("sentry_sdk.capture_exception")
- @responses.activate
- def test_gh_comment_api_error(self, mock_capture_exception, get_jwt, mock_comment_workflow):
- """Captures exception if Github API call errors"""
- responses.add(
- responses.POST,
- self.base_url + f"/app/installations/{self.installation_id}/access_tokens",
- json={"token": self.access_token, "expires_at": self.expires_at},
- )
- responses.add(
- responses.GET,
- self.base_url + f"/repos/example/commits/{self.commit.key}/pulls",
- status=400,
- json={"message": "error"},
- )
- with self.tasks():
- event_frames = get_frame_paths(self.event)
- process_commit_context(
- event_id=self.event.event_id,
- event_platform=self.event.platform,
- event_frames=event_frames,
- group_id=self.event.group_id,
- project_id=self.event.project_id,
- )
- assert mock_capture_exception.called
- assert not mock_comment_workflow.called
- @patch("sentry.integrations.github.client.get_jwt", return_value=b"jwt_token_1")
- @responses.activate
- def test_gh_comment_commit_not_in_default_branch(self, get_jwt, mock_comment_workflow):
- """No comments on commit not in default branch"""
- responses.add(
- responses.POST,
- self.base_url + f"/app/installations/{self.installation_id}/access_tokens",
- json={"token": self.access_token, "expires_at": self.expires_at},
- )
- responses.add(
- responses.GET,
- self.base_url + f"/repos/example/commits/{self.commit.key}/pulls",
- status=200,
- json=[{"merge_commit_sha": "abcd"}, {"merge_commit_sha": "efgh"}],
- )
- with self.tasks():
- event_frames = get_frame_paths(self.event)
- process_commit_context(
- event_id=self.event.event_id,
- event_platform=self.event.platform,
- event_frames=event_frames,
- group_id=self.event.group_id,
- project_id=self.event.project_id,
- )
- assert not mock_comment_workflow.called
- @patch("sentry.integrations.github.client.get_jwt", return_value=b"jwt_token_1")
- @responses.activate
- def test_gh_comment_no_pr_from_query(self, get_jwt, mock_comment_workflow):
- """No comments on suspect commit with no pr row in table"""
- self.pull_request.delete()
- self.add_responses()
- with self.tasks():
- event_frames = get_frame_paths(self.event)
- process_commit_context(
- event_id=self.event.event_id,
- event_platform=self.event.platform,
- event_frames=event_frames,
- group_id=self.event.group_id,
- project_id=self.event.project_id,
- )
- assert not mock_comment_workflow.called
- @patch("sentry.integrations.github.client.get_jwt", return_value=b"jwt_token_1")
- @responses.activate
- def test_gh_comment_pr_too_old(self, get_jwt, mock_comment_workflow):
- """No comment on pr that's older than PR_COMMENT_WINDOW"""
- self.pull_request.date_added = iso_format(before_now(days=PR_COMMENT_WINDOW + 1))
- self.pull_request.save()
- self.add_responses()
- with self.tasks():
- event_frames = get_frame_paths(self.event)
- process_commit_context(
- event_id=self.event.event_id,
- event_platform=self.event.platform,
- event_frames=event_frames,
- group_id=self.event.group_id,
- project_id=self.event.project_id,
- )
- assert not mock_comment_workflow.called
- assert len(PullRequestCommit.objects.all()) == 0
- @patch("sentry.integrations.github.client.get_jwt", return_value=b"jwt_token_1")
- @responses.activate
- def test_gh_comment_repeat_issue(self, get_jwt, mock_comment_workflow):
- """No comment on a pr that has a comment with the issue in the same pr list"""
- self.pull_request_comment.group_ids.append(self.event.group_id)
- self.pull_request_comment.save()
- self.add_responses()
- with self.tasks():
- event_frames = get_frame_paths(self.event)
- process_commit_context(
- event_id=self.event.event_id,
- event_platform=self.event.platform,
- event_frames=event_frames,
- group_id=self.event.group_id,
- project_id=self.event.project_id,
- )
- assert not mock_comment_workflow.called
- assert len(PullRequestCommit.objects.all()) == 0
- @patch("sentry.integrations.github.client.get_jwt", return_value=b"jwt_token_1")
- @responses.activate
- def test_gh_comment_create_queued(self, get_jwt, mock_comment_workflow):
- """Task queued if no prior comment exists"""
- self.pull_request_comment.delete()
- self.add_responses()
- with self.tasks():
- event_frames = get_frame_paths(self.event)
- process_commit_context(
- event_id=self.event.event_id,
- event_platform=self.event.platform,
- event_frames=event_frames,
- group_id=self.event.group_id,
- project_id=self.event.project_id,
- )
- assert mock_comment_workflow.called
- pr_commits = PullRequestCommit.objects.all()
- assert len(pr_commits) == 1
- assert pr_commits[0].commit == self.commit
- @patch("sentry.integrations.github.client.get_jwt", return_value=b"jwt_token_1")
- @responses.activate
- def test_gh_comment_create_queued_existing_pr_commit(self, get_jwt, mock_comment_workflow):
- """Task queued if no prior comment exists"""
- pr_commit = PullRequestCommit.objects.create(
- commit=self.commit, pull_request=self.pull_request
- )
- self.pull_request_comment.delete()
- self.add_responses()
- with self.tasks():
- event_frames = get_frame_paths(self.event)
- process_commit_context(
- event_id=self.event.event_id,
- event_platform=self.event.platform,
- event_frames=event_frames,
- group_id=self.event.group_id,
- project_id=self.event.project_id,
- )
- assert mock_comment_workflow.called
- pr_commits = PullRequestCommit.objects.all()
- assert len(pr_commits) == 1
- assert pr_commits[0] == pr_commit
- @patch("sentry.integrations.github.client.get_jwt", return_value=b"jwt_token_1")
- @responses.activate
- def test_gh_comment_update_queue(self, get_jwt, mock_comment_workflow):
- """Task queued if new issue for prior comment"""
- self.add_responses()
- with self.tasks():
- assert not GroupOwner.objects.filter(group=self.event.group).exists()
- event_frames = get_frame_paths(self.event)
- process_commit_context(
- event_id=self.event.event_id,
- event_platform=self.event.platform,
- event_frames=event_frames,
- group_id=self.event.group_id,
- project_id=self.event.project_id,
- )
- assert mock_comment_workflow.called
- pr_commits = PullRequestCommit.objects.all()
- assert len(pr_commits) == 1
- assert pr_commits[0].commit == self.commit
- def test_gh_comment_no_repo(self, mock_comment_workflow):
- """No comments on suspect commit if no repo row exists"""
- self.repo.delete()
- with self.tasks():
- event_frames = get_frame_paths(self.event)
- process_commit_context(
- event_id=self.event.event_id,
- event_platform=self.event.platform,
- event_frames=event_frames,
- group_id=self.event.group_id,
- project_id=self.event.project_id,
- )
- assert not mock_comment_workflow.called
- assert len(PullRequestCommit.objects.all()) == 0
- @patch("sentry.integrations.github.client.get_jwt", return_value=b"jwt_token_1")
- @responses.activate
- def test_gh_comment_debounces(self, get_jwt, mock_comment_workflow):
- self.add_responses()
- with self.tasks():
- assert not GroupOwner.objects.filter(group=self.event.group).exists()
- event_frames = get_frame_paths(self.event)
- process_commit_context(
- event_id=self.event.event_id,
- event_platform=self.event.platform,
- event_frames=event_frames,
- group_id=self.event.group_id,
- project_id=self.event.project_id,
- )
- process_commit_context(
- event_id=self.event.event_id,
- event_platform=self.event.platform,
- event_frames=event_frames,
- group_id=self.event.group_id,
- project_id=self.event.project_id,
- )
- assert mock_comment_workflow.call_count == 1
|