From 3908d5d1a369bcfb26889f7a7f5f8eb4429ecc08 Mon Sep 17 00:00:00 2001 From: Giovanni M Guidini Date: Mon, 2 Nov 2026 15:53:37 +0100 Subject: [PATCH] ref(integrations): Remove duplicate search lifecycle Keep issue and repository search handlers as the authoritative SCM feature outcomes. Refs SCM-304 --- .../source_code_management/metrics.py | 7 +- .../source_code_management/search.py | 101 ++++++++--------- .../integrations/bitbucket/test_search.py | 34 ++---- .../sentry/integrations/github/test_search.py | 106 +++++------------- .../sentry/integrations/gitlab/test_search.py | 52 +++------ tests/sentry/integrations/vsts/test_search.py | 12 +- 6 files changed, 103 insertions(+), 209 deletions(-) diff --git a/src/sentry/integrations/source_code_management/metrics.py b/src/sentry/integrations/source_code_management/metrics.py index 8352407e2a15..490735462b96 100644 --- a/src/sentry/integrations/source_code_management/metrics.py +++ b/src/sentry/integrations/source_code_management/metrics.py @@ -36,7 +36,6 @@ class SCMIntegrationInteractionType(StrEnum): # SourceCodeSearchEndpoint HANDLE_SEARCH_ISSUES = "handle_search_issues" HANDLE_SEARCH_REPOSITORIES = "handle_search_repositories" - GET = "get" # CommitContextIntegration GET_BLAME_FOR_FILES = "get_blame_for_files" @@ -208,13 +207,9 @@ class LinkAllReposHaltReason(StrEnum): class SourceCodeSearchEndpointHaltReason(StrEnum): """ - Reasons why a SourceCodeSearchEndpoint method (handle_search_issues, - handle_search_repositories, or get) may halt without success/failure. + Reasons why a SourceCodeSearchEndpoint search handler may halt without success/failure. """ NO_ISSUE_TRACKER = "no_issue_tracker" RATE_LIMITED = "rate_limited" MISSING_REPOSITORY_OR_NO_ACCESS = "missing_repository_or_no_access" - MISSING_INTEGRATION = "missing_integration" - SERIALIZER_ERRORS = "serializer_errors" - MISSING_REPOSITORY_FIELD = "missing_repository_field" diff --git a/src/sentry/integrations/source_code_management/search.py b/src/sentry/integrations/source_code_management/search.py index 4a66a92a8a26..312d4d0edc2f 100644 --- a/src/sentry/integrations/source_code_management/search.py +++ b/src/sentry/integrations/source_code_management/search.py @@ -16,7 +16,6 @@ from sentry.integrations.source_code_management.metrics import ( SCMIntegrationInteractionEvent, SCMIntegrationInteractionType, - SourceCodeSearchEndpointHaltReason, ) from sentry.integrations.types import IntegrationProviderSlug from sentry.organizations.services.organization import RpcOrganization @@ -95,59 +94,47 @@ def handle_search_field( def get( self, request: Request, organization: RpcOrganization, integration_id: int, **kwds: Any ) -> Response: - with self.record_event( - SCMIntegrationInteractionType.GET, - organization_id=organization.id, - integration_id=integration_id, - ).capture() as lifecycle: - integration_query = Q( - organizationintegration__organization_id=organization.id, id=integration_id - ) - - if self.integration_provider: - integration_query &= Q(provider=self.integration_provider) - try: - integration: Integration = Integration.objects.get(integration_query) - except Integration.DoesNotExist: - lifecycle.record_halt(str(SourceCodeSearchEndpointHaltReason.MISSING_INTEGRATION)) - return Response(status=404) - - serializer = SourceCodeSearchSerializer(data=request.query_params) - if not serializer.is_valid(): - lifecycle.record_halt(str(SourceCodeSearchEndpointHaltReason.SERIALIZER_ERRORS)) - return self.respond(serializer.errors, status=400) - - field = serializer.validated_data["field"] - query = serializer.validated_data["query"] - - installation = integration.get_installation(organization.id) - if not isinstance(installation, self.installation_class): - raise NotFound( - f"Integration by that id is not of type {self.integration_provider}." - ) - - if field == self.issue_field: - repo = None - - if self.repository_field: # only fetch repository - repo = request.GET.get(self.repository_field) - if repo is None: - lifecycle.record_halt( - str(SourceCodeSearchEndpointHaltReason.MISSING_REPOSITORY_FIELD) - ) - return Response( - {"detail": f"{self.repository_field} is a required parameter"}, - status=400, - ) - - return self.handle_search_issues(installation, query, repo) - - if self.repository_field and field == self.repository_field: - return self.handle_search_repositories(integration, installation, query) - - repo = request.GET.get(self.repository_field) if self.repository_field else None - response = self.handle_search_field(installation, field, query, repo) - if response is not None: - return response - - return Response({"detail": "Invalid field"}, status=400) + integration_query = Q( + organizationintegration__organization_id=organization.id, id=integration_id + ) + + if self.integration_provider: + integration_query &= Q(provider=self.integration_provider) + try: + integration: Integration = Integration.objects.get(integration_query) + except Integration.DoesNotExist: + return Response(status=404) + + serializer = SourceCodeSearchSerializer(data=request.query_params) + if not serializer.is_valid(): + return self.respond(serializer.errors, status=400) + + field = serializer.validated_data["field"] + query = serializer.validated_data["query"] + + installation = integration.get_installation(organization.id) + if not isinstance(installation, self.installation_class): + raise NotFound(f"Integration by that id is not of type {self.integration_provider}.") + + if field == self.issue_field: + repo = None + + if self.repository_field: # only fetch repository + repo = request.GET.get(self.repository_field) + if repo is None: + return Response( + {"detail": f"{self.repository_field} is a required parameter"}, + status=400, + ) + + return self.handle_search_issues(installation, query, repo) + + if self.repository_field and field == self.repository_field: + return self.handle_search_repositories(integration, installation, query) + + repo = request.GET.get(self.repository_field) if self.repository_field else None + response = self.handle_search_field(installation, field, query, repo) + if response is not None: + return response + + return Response({"detail": "Invalid field"}, status=400) diff --git a/tests/sentry/integrations/bitbucket/test_search.py b/tests/sentry/integrations/bitbucket/test_search.py index c320e8ae141d..eddd8e24c70d 100644 --- a/tests/sentry/integrations/bitbucket/test_search.py +++ b/tests/sentry/integrations/bitbucket/test_search.py @@ -58,18 +58,15 @@ def test_search_issues(self, mock_record: MagicMock) -> None: {"label": "#456 Issue Title 456", "value": "456"}, ] - assert len(mock_record.mock_calls) == 8 + assert len(mock_record.mock_calls) == 6 # first 2 are middleware calls to ensure control silo, then the next one and the last one are also middleware calls for get_response_from_control_silo middleware_calls = mock_record.mock_calls[:3] + mock_record.mock_calls[-1:] assert_middleware_metrics(middleware_calls) - product_calls = mock_record.mock_calls[3:-1] - start1, start2, halt1, halt2 = product_calls - assert start1.args[0] == EventLifecycleOutcome.STARTED - assert start2.args[0] == EventLifecycleOutcome.STARTED - assert halt1.args[0] == EventLifecycleOutcome.SUCCESS - assert halt2.args[0] == EventLifecycleOutcome.SUCCESS + start, success = mock_record.mock_calls[3:-1] + assert start.args[0] == EventLifecycleOutcome.STARTED + assert success.args[0] == EventLifecycleOutcome.SUCCESS @responses.activate @patch("sentry.integrations.utils.metrics.EventLifecycle.record_event") @@ -87,14 +84,9 @@ def test_search_repositories(self, mock_record: MagicMock) -> None: middleware_calls = mock_record.mock_calls[:3] + mock_record.mock_calls[-1:] assert_middleware_metrics(middleware_calls) - product_calls = mock_record.mock_calls[3:-1] - start1, start2, halt1, halt2 = ( - product_calls # calls get, which calls handle_search_repositories - ) - assert start1.args[0] == EventLifecycleOutcome.STARTED - assert start2.args[0] == EventLifecycleOutcome.STARTED - assert halt1.args[0] == EventLifecycleOutcome.SUCCESS - assert halt2.args[0] == EventLifecycleOutcome.SUCCESS + start, success = mock_record.mock_calls[3:-1] + assert start.args[0] == EventLifecycleOutcome.STARTED + assert success.args[0] == EventLifecycleOutcome.SUCCESS @responses.activate @patch("sentry.integrations.utils.metrics.EventLifecycle.record_event") @@ -115,13 +107,7 @@ def test_search_repositories_no_issue_tracker(self, mock_record: MagicMock) -> N middleware_calls = mock_record.mock_calls[:3] + mock_record.mock_calls[-1:] assert_middleware_metrics(middleware_calls) - product_calls = mock_record.mock_calls[3:-1] - - start1, start2, halt1, halt2 = product_calls # calls get, which calls handle_search_issues - assert start1.args[0] == EventLifecycleOutcome.STARTED - assert start2.args[0] == EventLifecycleOutcome.STARTED - assert halt1.args[0] == EventLifecycleOutcome.HALTED + start, halt = mock_record.mock_calls[3:-1] + assert start.args[0] == EventLifecycleOutcome.STARTED + assert halt.args[0] == EventLifecycleOutcome.HALTED assert_halt_metric(mock_record, SourceCodeSearchEndpointHaltReason.NO_ISSUE_TRACKER.value) - # NOTE: handle_search_issues returns without raising an API error, so for the - # purposes of logging the GET request completes successfully - assert halt2.args[0] == EventLifecycleOutcome.SUCCESS diff --git a/tests/sentry/integrations/github/test_search.py b/tests/sentry/integrations/github/test_search.py index a877877e77d9..4b2c27a619c4 100644 --- a/tests/sentry/integrations/github/test_search.py +++ b/tests/sentry/integrations/github/test_search.py @@ -14,7 +14,6 @@ from sentry.testutils.asserts import ( assert_halt_metric, assert_middleware_metrics, - assert_slo_metric_calls, ) from sentry.testutils.cases import APITestCase from sentry.testutils.silo import control_silo_test @@ -98,16 +97,12 @@ def test_finds_external_issue_results(self, mock_record: MagicMock) -> None: {"value": 25, "label": "#25 AEIOU Error"}, {"value": 45, "label": "#45 AEIOU Error"}, ] - assert len(mock_record.mock_calls) == 8 + assert len(mock_record.mock_calls) == 6 middleware_calls = mock_record.mock_calls[:3] + mock_record.mock_calls[-1:] assert_middleware_metrics(middleware_calls) - product_calls = mock_record.mock_calls[3:-1] - start1, start2, halt1, halt2 = product_calls - assert start1.args[0] == EventLifecycleOutcome.STARTED - assert start1.args[0] == EventLifecycleOutcome.STARTED - assert start2.args[0] == EventLifecycleOutcome.STARTED - assert halt1.args[0] == EventLifecycleOutcome.SUCCESS - assert halt2.args[0] == EventLifecycleOutcome.SUCCESS + start, success = mock_record.mock_calls[3:-1] + assert start.args[0] == EventLifecycleOutcome.STARTED + assert success.args[0] == EventLifecycleOutcome.SUCCESS @responses.activate def test_finds_external_issue_results_with_id(self) -> None: @@ -143,17 +138,12 @@ def test_finds_repo_results(self, mock_record: MagicMock) -> None: {"value": "test/example", "label": "example"}, {"value": "test/exhaust", "label": "exhaust"}, ] - assert len(mock_record.mock_calls) == 8 + assert len(mock_record.mock_calls) == 6 middleware_calls = mock_record.mock_calls[:3] + mock_record.mock_calls[-1:] assert_middleware_metrics(middleware_calls) - product_calls = mock_record.mock_calls[3:-1] - start1, start2, halt1, halt2 = ( - product_calls # calls get, which calls handle_search_repositories - ) - assert start1.args[0] == EventLifecycleOutcome.STARTED - assert start2.args[0] == EventLifecycleOutcome.STARTED - assert halt1.args[0] == EventLifecycleOutcome.SUCCESS - assert halt2.args[0] == EventLifecycleOutcome.SUCCESS + start, success = mock_record.mock_calls[3:-1] + assert start.args[0] == EventLifecycleOutcome.STARTED + assert success.args[0] == EventLifecycleOutcome.SUCCESS @responses.activate def test_prefetches_repo_results_with_empty_query(self) -> None: @@ -380,20 +370,15 @@ def test_repo_search_validation_error(self, mock_record: MagicMock) -> None: resp = self.client.get(self.url, data={"field": "repo", "query": "nope", "repo": "example"}) assert resp.status_code == 404 assert "detail" in resp.data - assert len(mock_record.mock_calls) == 8 + assert len(mock_record.mock_calls) == 6 middleware_calls = mock_record.mock_calls[:3] + mock_record.mock_calls[-1:] assert_middleware_metrics(middleware_calls) - product_calls = mock_record.mock_calls[3:-1] - start1, start2, halt1, halt2 = product_calls - assert start1.args[0] == EventLifecycleOutcome.STARTED - assert start2.args[0] == EventLifecycleOutcome.STARTED - assert halt1.args[0] == EventLifecycleOutcome.HALTED + start, halt = mock_record.mock_calls[3:-1] + assert start.args[0] == EventLifecycleOutcome.STARTED + assert halt.args[0] == EventLifecycleOutcome.HALTED assert_halt_metric( mock_record, SourceCodeSearchEndpointHaltReason.MISSING_REPOSITORY_OR_NO_ACCESS.value ) - # NOTE: handle_search_repositories returns without raising an API error, so for the - # purposes of logging the GET request completes successfully - assert halt2.args[0] == EventLifecycleOutcome.SUCCESS @responses.activate def test_finds_no_external_issues_results(self) -> None: @@ -433,18 +418,13 @@ def test_search_issues_rate_limit(self, mock_record: MagicMock) -> None: self.url, data={"field": "externalIssue", "query": "ex", "repo": "example"} ) assert resp.status_code == 429 - assert len(mock_record.mock_calls) == 8 + assert len(mock_record.mock_calls) == 6 middleware_calls = mock_record.mock_calls[:3] + mock_record.mock_calls[-1:] assert_middleware_metrics(middleware_calls) - product_calls = mock_record.mock_calls[3:-1] - start1, start2, halt1, halt2 = product_calls - assert start1.args[0] == EventLifecycleOutcome.STARTED - assert start2.args[0] == EventLifecycleOutcome.STARTED - assert halt1.args[0] == EventLifecycleOutcome.HALTED + start, halt = mock_record.mock_calls[3:-1] + assert start.args[0] == EventLifecycleOutcome.STARTED + assert halt.args[0] == EventLifecycleOutcome.HALTED assert_halt_metric(mock_record, SourceCodeSearchEndpointHaltReason.RATE_LIMITED.value) - # NOTE: handle_search_issues returns without raising an API error, so for the - # purposes of logging the GET request completes successfully - assert halt2.args[0] == EventLifecycleOutcome.SUCCESS @responses.activate @patch("sentry.integrations.utils.metrics.EventLifecycle.record_event") @@ -460,18 +440,13 @@ def test_search_project_rate_limit(self, mock_record: MagicMock) -> None: ) resp = self.client.get(self.url, data={"field": "repo", "query": "ex"}) assert resp.status_code == 429 - assert len(mock_record.mock_calls) == 8 + assert len(mock_record.mock_calls) == 6 middleware_calls = mock_record.mock_calls[:3] + mock_record.mock_calls[-1:] assert_middleware_metrics(middleware_calls) - product_calls = mock_record.mock_calls[3:-1] - start1, start2, halt1, halt2 = product_calls - assert start1.args[0] == EventLifecycleOutcome.STARTED - assert start2.args[0] == EventLifecycleOutcome.STARTED - assert halt1.args[0] == EventLifecycleOutcome.HALTED + start, halt = mock_record.mock_calls[3:-1] + assert start.args[0] == EventLifecycleOutcome.STARTED + assert halt.args[0] == EventLifecycleOutcome.HALTED assert_halt_metric(mock_record, SourceCodeSearchEndpointHaltReason.RATE_LIMITED.value) - # NOTE: handle_search_repositories returns without raising an API error, so for the - # purposes of logging the GET request completes successfully - assert halt2.args[0] == EventLifecycleOutcome.SUCCESS # Request Validations # Test observability requests for GET requests failures here @@ -479,42 +454,24 @@ def test_search_project_rate_limit(self, mock_record: MagicMock) -> None: def test_missing_field(self, mock_record: MagicMock) -> None: resp = self.client.get(self.url, data={"query": "XYZ"}) assert resp.status_code == 400 - assert len(mock_record.mock_calls) == 6 - middleware_calls = mock_record.mock_calls[:3] + mock_record.mock_calls[-1:] - - assert_middleware_metrics(middleware_calls) - - product_calls = mock_record.mock_calls[3:-1] - assert_slo_metric_calls(product_calls, EventLifecycleOutcome.HALTED) - assert_halt_metric(mock_record, SourceCodeSearchEndpointHaltReason.SERIALIZER_ERRORS.value) + assert len(mock_record.mock_calls) == 4 + assert_middleware_metrics(mock_record.mock_calls) @patch("sentry.integrations.utils.metrics.EventLifecycle.record_event") def test_missing_query(self, mock_record: MagicMock) -> None: resp = self.client.get(self.url, data={"field": "externalIssue"}) assert resp.status_code == 400 - assert len(mock_record.mock_calls) == 6 - middleware_calls = mock_record.mock_calls[:3] + mock_record.mock_calls[-1:] - assert_middleware_metrics(middleware_calls) - - product_calls = mock_record.mock_calls[3:-1] - assert_slo_metric_calls(product_calls, EventLifecycleOutcome.HALTED) - assert_halt_metric(mock_record, SourceCodeSearchEndpointHaltReason.SERIALIZER_ERRORS.value) + assert len(mock_record.mock_calls) == 4 + assert_middleware_metrics(mock_record.mock_calls) @patch("sentry.integrations.utils.metrics.EventLifecycle.record_event") def test_missing_repository(self, mock_record: MagicMock) -> None: resp = self.client.get(self.url, data={"field": "externalIssue", "query": "XYZ"}) assert resp.status_code == 400 - assert len(mock_record.mock_calls) == 6 - middleware_calls = mock_record.mock_calls[:3] + mock_record.mock_calls[-1:] - assert_middleware_metrics(middleware_calls) - - product_calls = mock_record.mock_calls[3:-1] - assert_slo_metric_calls(product_calls, EventLifecycleOutcome.HALTED) - assert_halt_metric( - mock_record, SourceCodeSearchEndpointHaltReason.MISSING_REPOSITORY_FIELD.value - ) + assert len(mock_record.mock_calls) == 4 + assert_middleware_metrics(mock_record.mock_calls) def test_invalid_field(self) -> None: resp = self.client.get(self.url, data={"field": "invalid-field", "query": "nope"}) @@ -538,15 +495,8 @@ def test_missing_integration(self, mock_record: MagicMock) -> None: assert resp.status_code == 404 - assert len(mock_record.mock_calls) == 6 - middleware_calls = mock_record.mock_calls[:3] + mock_record.mock_calls[-1:] - assert_middleware_metrics(middleware_calls) - - product_calls = mock_record.mock_calls[3:-1] - assert_slo_metric_calls(product_calls, EventLifecycleOutcome.HALTED) - assert_halt_metric( - mock_record, SourceCodeSearchEndpointHaltReason.MISSING_INTEGRATION.value - ) + assert len(mock_record.mock_calls) == 4 + assert_middleware_metrics(mock_record.mock_calls) def test_missing_installation(self) -> None: # remove organization integration aka "uninstalling" installation diff --git a/tests/sentry/integrations/gitlab/test_search.py b/tests/sentry/integrations/gitlab/test_search.py index fd6407d3b933..dee7f52d4ac8 100644 --- a/tests/sentry/integrations/gitlab/test_search.py +++ b/tests/sentry/integrations/gitlab/test_search.py @@ -47,16 +47,12 @@ def test_finds_external_issue_results(self, mock_record: MagicMock) -> None: {"value": "5#25", "label": "(#25) AEIOU Error"}, {"value": "5#45", "label": "(#45) AEIOU Error"}, ] - assert len(mock_record.mock_calls) == 8 + assert len(mock_record.mock_calls) == 6 middleware_calls = mock_record.mock_calls[:3] + mock_record.mock_calls[-1:] assert_middleware_metrics(middleware_calls) - product_calls = mock_record.mock_calls[3:-1] - start1, start2, halt1, halt2 = product_calls # calls get, which calls handle_search_issues - assert start1.args[0] == EventLifecycleOutcome.STARTED - assert start1.args[0] == EventLifecycleOutcome.STARTED - assert start2.args[0] == EventLifecycleOutcome.STARTED - assert halt1.args[0] == EventLifecycleOutcome.SUCCESS - assert halt2.args[0] == EventLifecycleOutcome.SUCCESS + start, success = mock_record.mock_calls[3:-1] + assert start.args[0] == EventLifecycleOutcome.STARTED + assert success.args[0] == EventLifecycleOutcome.SUCCESS @responses.activate def test_finds_external_issue_results_with_iid(self) -> None: @@ -98,18 +94,12 @@ def test_finds_project_results(self, mock_record: MagicMock) -> None: {"value": "getsentry/sentry", "label": "GetSentry / Sentry"}, {"value": "getsentry2/sentry2", "label": "GetSentry2 / Sentry2"}, ] - assert len(mock_record.mock_calls) == 8 + assert len(mock_record.mock_calls) == 6 middleware_calls = mock_record.mock_calls[:3] + mock_record.mock_calls[-1:] assert_middleware_metrics(middleware_calls) - product_calls = mock_record.mock_calls[3:-1] - start1, start2, halt1, halt2 = ( - product_calls # calls get, which calls handle_search_repositories - ) - assert start1.args[0] == EventLifecycleOutcome.STARTED - assert start1.args[0] == EventLifecycleOutcome.STARTED - assert start2.args[0] == EventLifecycleOutcome.STARTED - assert halt1.args[0] == EventLifecycleOutcome.SUCCESS - assert halt2.args[0] == EventLifecycleOutcome.SUCCESS + start, success = mock_record.mock_calls[3:-1] + assert start.args[0] == EventLifecycleOutcome.STARTED + assert success.args[0] == EventLifecycleOutcome.SUCCESS @responses.activate def test_finds_project_results_with_pagination(self) -> None: @@ -248,17 +238,12 @@ def test_search_issues_request_fails(self, mock_record: MagicMock) -> None: self.url, data={"field": "externalIssue", "query": "GetSentry", "project": "5"} ) assert resp.status_code == 400 - assert len(mock_record.mock_calls) == 8 + assert len(mock_record.mock_calls) == 6 middleware_calls = mock_record.mock_calls[:3] + mock_record.mock_calls[-1:] assert_middleware_metrics(middleware_calls) - product_calls = mock_record.mock_calls[3:-1] - start1, start2, halt1, halt2 = product_calls - assert start1.args[0] == EventLifecycleOutcome.STARTED - assert start2.args[0] == EventLifecycleOutcome.STARTED - assert halt1.args[0] == EventLifecycleOutcome.FAILURE - # NOTE: handle_search_issues returns without raising an API error, so for the - # purposes of logging the GET request completes successfully - assert halt2.args[0] == EventLifecycleOutcome.SUCCESS + start, failure = mock_record.mock_calls[3:-1] + assert start.args[0] == EventLifecycleOutcome.STARTED + assert failure.args[0] == EventLifecycleOutcome.FAILURE @responses.activate @patch("sentry.integrations.utils.metrics.EventLifecycle.record_event") @@ -266,14 +251,9 @@ def test_projects_request_fails(self, mock_record: MagicMock) -> None: responses.add(responses.GET, "https://example.gitlab.com/api/v4/projects", status=503) resp = self.client.get(self.url, data={"field": "project", "query": "GetSentry"}) assert resp.status_code == 400 - assert len(mock_record.mock_calls) == 8 + assert len(mock_record.mock_calls) == 6 middleware_calls = mock_record.mock_calls[:3] + mock_record.mock_calls[-1:] assert_middleware_metrics(middleware_calls) - product_calls = mock_record.mock_calls[3:-1] - start1, start2, halt1, halt2 = product_calls - assert start1.args[0] == EventLifecycleOutcome.STARTED - assert start2.args[0] == EventLifecycleOutcome.STARTED - assert halt1.args[0] == EventLifecycleOutcome.FAILURE - # NOTE: handle_search_issues returns without raising an API error, so for the - # purposes of logging the GET request completes successfully - assert halt2.args[0] == EventLifecycleOutcome.SUCCESS + start, failure = mock_record.mock_calls[3:-1] + assert start.args[0] == EventLifecycleOutcome.STARTED + assert failure.args[0] == EventLifecycleOutcome.FAILURE diff --git a/tests/sentry/integrations/vsts/test_search.py b/tests/sentry/integrations/vsts/test_search.py index 97cb8f4dc59c..92532c87335a 100644 --- a/tests/sentry/integrations/vsts/test_search.py +++ b/tests/sentry/integrations/vsts/test_search.py @@ -88,13 +88,9 @@ def test_search_issues(self, mock_record: MagicMock) -> None: assert resp.data == [ {"label": "(2) Title", "value": "2"}, ] - assert len(mock_record.mock_calls) == 8 + assert len(mock_record.mock_calls) == 6 middleware_calls = mock_record.mock_calls[:3] + mock_record.mock_calls[-1:] assert_middleware_metrics(middleware_calls) - product_calls = mock_record.mock_calls[3:-1] - start1, start2, halt1, halt2 = product_calls # calls get, which calls handle_search_issues - assert start1.args[0] == EventLifecycleOutcome.STARTED - assert start1.args[0] == EventLifecycleOutcome.STARTED - assert start2.args[0] == EventLifecycleOutcome.STARTED - assert halt1.args[0] == EventLifecycleOutcome.SUCCESS - assert halt2.args[0] == EventLifecycleOutcome.SUCCESS + start, success = mock_record.mock_calls[3:-1] + assert start.args[0] == EventLifecycleOutcome.STARTED + assert success.args[0] == EventLifecycleOutcome.SUCCESS