From 24e5e4d4ce5931550cd36e0e55d5dd4678953320 Mon Sep 17 00:00:00 2001 From: Andrew Liu <159852527+aliu39@users.noreply.github.com> Date: Fri, 11 Jul 2025 15:12:02 -0700 Subject: [PATCH 01/10] Move endpoints --- src/sentry/api/urls.py | 8 ++++--- src/sentry/feedback/endpoints/__init__.py | 0 .../organization_feedback_summary.py | 0 .../endpoints/organization_user_reports.py | 0 .../endpoints/project_user_reports.py | 0 .../test_organization_feedback_summary.py | 24 +++++++++---------- .../test_organization_user_reports.py | 0 .../test_project_user_reports.py | 0 8 files changed, 17 insertions(+), 15 deletions(-) create mode 100644 src/sentry/feedback/endpoints/__init__.py rename src/sentry/{api => feedback}/endpoints/organization_feedback_summary.py (100%) rename src/sentry/{api => feedback}/endpoints/organization_user_reports.py (100%) rename src/sentry/{api => feedback}/endpoints/project_user_reports.py (100%) rename tests/sentry/{api/endpoints => feedback}/test_organization_feedback_summary.py (90%) rename tests/sentry/{api/endpoints => feedback}/test_organization_user_reports.py (100%) rename tests/sentry/{api/endpoints => feedback}/test_project_user_reports.py (100%) diff --git a/src/sentry/api/urls.py b/src/sentry/api/urls.py index 30036a43d86ea1..b9427731d2a19f 100644 --- a/src/sentry/api/urls.py +++ b/src/sentry/api/urls.py @@ -20,7 +20,6 @@ from sentry.api.endpoints.organization_events_root_cause_analysis import ( OrganizationEventsRootCauseAnalysisEndpoint, ) -from sentry.api.endpoints.organization_feedback_summary import OrganizationFeedbackSummaryEndpoint from sentry.api.endpoints.organization_fork import OrganizationForkEndpoint from sentry.api.endpoints.organization_insights_tree import OrganizationInsightsTreeEndpoint from sentry.api.endpoints.organization_member_invite.details import ( @@ -100,6 +99,11 @@ from sentry.explore.endpoints.explore_saved_query_starred_order import ( ExploreSavedQueryStarredOrderEndpoint, ) +from sentry.feedback.endpoints.organization_feedback_summary import ( + OrganizationFeedbackSummaryEndpoint, +) +from sentry.feedback.endpoints.organization_user_reports import OrganizationUserReportsEndpoint +from sentry.feedback.endpoints.project_user_reports import ProjectUserReportsEndpoint from sentry.flags.endpoints.hooks import OrganizationFlagsHooksEndpoint from sentry.flags.endpoints.logs import ( OrganizationFlagLogDetailsEndpoint, @@ -643,7 +647,6 @@ OrganizationTraceSpansEndpoint, ) from .endpoints.organization_user_details import OrganizationUserDetailsEndpoint -from .endpoints.organization_user_reports import OrganizationUserReportsEndpoint from .endpoints.organization_user_teams import OrganizationUserTeamsEndpoint from .endpoints.organization_users import OrganizationUsersEndpoint from .endpoints.project_artifact_bundle_file_details import ProjectArtifactBundleFileDetailsEndpoint @@ -710,7 +713,6 @@ ProjectTransactionThresholdOverrideEndpoint, ) from .endpoints.project_transfer import ProjectTransferEndpoint -from .endpoints.project_user_reports import ProjectUserReportsEndpoint from .endpoints.project_user_stats import ProjectUserStatsEndpoint from .endpoints.project_users import ProjectUsersEndpoint from .endpoints.prompts_activity import PromptsActivityEndpoint diff --git a/src/sentry/feedback/endpoints/__init__.py b/src/sentry/feedback/endpoints/__init__.py new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/src/sentry/api/endpoints/organization_feedback_summary.py b/src/sentry/feedback/endpoints/organization_feedback_summary.py similarity index 100% rename from src/sentry/api/endpoints/organization_feedback_summary.py rename to src/sentry/feedback/endpoints/organization_feedback_summary.py diff --git a/src/sentry/api/endpoints/organization_user_reports.py b/src/sentry/feedback/endpoints/organization_user_reports.py similarity index 100% rename from src/sentry/api/endpoints/organization_user_reports.py rename to src/sentry/feedback/endpoints/organization_user_reports.py diff --git a/src/sentry/api/endpoints/project_user_reports.py b/src/sentry/feedback/endpoints/project_user_reports.py similarity index 100% rename from src/sentry/api/endpoints/project_user_reports.py rename to src/sentry/feedback/endpoints/project_user_reports.py diff --git a/tests/sentry/api/endpoints/test_organization_feedback_summary.py b/tests/sentry/feedback/test_organization_feedback_summary.py similarity index 90% rename from tests/sentry/api/endpoints/test_organization_feedback_summary.py rename to tests/sentry/feedback/test_organization_feedback_summary.py index 61b16c8a571b55..f4cf4cd96344a1 100644 --- a/tests/sentry/api/endpoints/test_organization_feedback_summary.py +++ b/tests/sentry/feedback/test_organization_feedback_summary.py @@ -39,7 +39,7 @@ def test_get_feedback_summary_without_feature_flag(self): @django_db_all @patch( - "sentry.api.endpoints.organization_feedback_summary.generate_summary", + "sentry.feedback.endpoints.organization_feedback_summary.generate_summary", return_value="Test summary of feedback", ) def test_get_feedback_summary_basic(self, mock_generate_summary): @@ -58,7 +58,7 @@ def test_get_feedback_summary_basic(self, mock_generate_summary): @django_db_all @patch( - "sentry.api.endpoints.organization_feedback_summary.generate_summary", + "sentry.feedback.endpoints.organization_feedback_summary.generate_summary", return_value="Test summary of feedback", ) def test_get_feedback_summary_with_date_filter(self, mock_generate_summary): @@ -89,7 +89,7 @@ def test_get_feedback_summary_with_date_filter(self, mock_generate_summary): @django_db_all @patch( - "sentry.api.endpoints.organization_feedback_summary.generate_summary", + "sentry.feedback.endpoints.organization_feedback_summary.generate_summary", return_value="Test summary of feedback", ) def test_get_feedback_summary_with_project_filter(self, mock_generate_summary): @@ -118,7 +118,7 @@ def test_get_feedback_summary_with_project_filter(self, mock_generate_summary): @django_db_all @patch( - "sentry.api.endpoints.organization_feedback_summary.generate_summary", + "sentry.feedback.endpoints.organization_feedback_summary.generate_summary", return_value="Test summary of feedback", ) def test_get_feedback_summary_with_many_project_filter_as_list(self, mock_generate_summary): @@ -147,7 +147,7 @@ def test_get_feedback_summary_with_many_project_filter_as_list(self, mock_genera @django_db_all @patch( - "sentry.api.endpoints.organization_feedback_summary.generate_summary", + "sentry.feedback.endpoints.organization_feedback_summary.generate_summary", return_value="Test summary of feedback", ) def test_get_feedback_summary_with_many_project_filter_separate(self, mock_generate_summary): @@ -175,7 +175,7 @@ def test_get_feedback_summary_with_many_project_filter_separate(self, mock_gener @django_db_all @patch( - "sentry.api.endpoints.organization_feedback_summary.generate_summary", + "sentry.feedback.endpoints.organization_feedback_summary.generate_summary", return_value="Test summary of feedback", ) def test_get_feedback_summary_too_few_feedbacks(self, mock_generate_summary): @@ -192,11 +192,11 @@ def test_get_feedback_summary_too_few_feedbacks(self, mock_generate_summary): @django_db_all @patch( - "sentry.api.endpoints.organization_feedback_summary.generate_summary", + "sentry.feedback.endpoints.organization_feedback_summary.generate_summary", return_value="Test summary of feedback", ) @patch( - "sentry.api.endpoints.organization_feedback_summary.MAX_FEEDBACKS_TO_SUMMARIZE_CHARS", + "sentry.feedback.endpoints.organization_feedback_summary.MAX_FEEDBACKS_TO_SUMMARIZE_CHARS", 1000, ) def test_get_feedback_summary_character_limit(self, mock_generate_summary): @@ -226,10 +226,10 @@ def test_get_feedback_summary_character_limit(self, mock_generate_summary): @django_db_all @patch( - "sentry.api.endpoints.organization_feedback_summary.generate_summary", + "sentry.feedback.endpoints.organization_feedback_summary.generate_summary", return_value="Test summary of feedback", ) - @patch("sentry.api.endpoints.organization_feedback_summary.cache") + @patch("sentry.feedback.endpoints.organization_feedback_summary.cache") def test_get_feedback_summary_cache_hit(self, mock_cache, mock_generate_summary): mock_cache.get.return_value = { "summary": "Test cached summary of feedback", @@ -254,10 +254,10 @@ def test_get_feedback_summary_cache_hit(self, mock_cache, mock_generate_summary) @django_db_all @patch( - "sentry.api.endpoints.organization_feedback_summary.generate_summary", + "sentry.feedback.endpoints.organization_feedback_summary.generate_summary", return_value="Test summary of feedback", ) - @patch("sentry.api.endpoints.organization_feedback_summary.cache") + @patch("sentry.feedback.endpoints.organization_feedback_summary.cache") def test_get_feedback_summary_cache_miss(self, mock_cache, mock_generate_summary): mock_cache.get.return_value = None diff --git a/tests/sentry/api/endpoints/test_organization_user_reports.py b/tests/sentry/feedback/test_organization_user_reports.py similarity index 100% rename from tests/sentry/api/endpoints/test_organization_user_reports.py rename to tests/sentry/feedback/test_organization_user_reports.py diff --git a/tests/sentry/api/endpoints/test_project_user_reports.py b/tests/sentry/feedback/test_project_user_reports.py similarity index 100% rename from tests/sentry/api/endpoints/test_project_user_reports.py rename to tests/sentry/feedback/test_project_user_reports.py From 6eb22607de3231cdd3289332c48492ef56872df7 Mon Sep 17 00:00:00 2001 From: Andrew Liu <159852527+aliu39@users.noreply.github.com> Date: Fri, 11 Jul 2025 15:45:03 -0700 Subject: [PATCH 02/10] save_event_feedback renaming and commenting for upcoming pr --- ...edback_event.py => save_event_feedback.py} | 9 +++++---- src/sentry/tasks/store.py | 6 ++++-- ...k_event.py => test_save_event_feedback.py} | 20 +++++++++---------- 3 files changed, 19 insertions(+), 16 deletions(-) rename src/sentry/feedback/usecases/{save_feedback_event.py => save_event_feedback.py} (81%) rename tests/sentry/feedback/{test_save_feedback_event.py => test_save_event_feedback.py} (88%) diff --git a/src/sentry/feedback/usecases/save_feedback_event.py b/src/sentry/feedback/usecases/save_event_feedback.py similarity index 81% rename from src/sentry/feedback/usecases/save_feedback_event.py rename to src/sentry/feedback/usecases/save_event_feedback.py index 7e678a40deada8..3b1c116687279a 100644 --- a/src/sentry/feedback/usecases/save_feedback_event.py +++ b/src/sentry/feedback/usecases/save_event_feedback.py @@ -13,12 +13,12 @@ logger = logging.getLogger(__name__) -def save_feedback_event(event_data: Mapping[str, Any], project_id: int): - """Saves a feedback from a feedback event envelope. +def save_event_feedback(event_data: Mapping[str, Any], project_id: int): + """Saves feedback given data in an event format. This function should only be called by the new feedback consumer's ingest strategy, to process feedback envelopes (feedback v2). + It is currently instrumented as a task in sentry.tasks.store. If the save is successful and the `associated_event_id` field is present, this will - also save a UserReport in Postgres. This is to ensure the feedback can be queried by - group_id, which is hard to associate in clickhouse. + also save a UserReport in Postgres (shim to v1). This is to allow queries by the group_id relation, which we don't have in clickhouse. """ if not isinstance(event_data, dict): event_data = dict(event_data) @@ -32,6 +32,7 @@ def save_feedback_event(event_data: Mapping[str, Any], project_id: int): try: # Shim to UserReport + # TODO: this logic should be extracted to a shim_to_userreport function which returns a report dict. After that this function can be removed and the store task can directly call feedback ingest functions. feedback_context = fixed_event_data["contexts"]["feedback"] associated_event_id = feedback_context.get("associated_event_id") diff --git a/src/sentry/tasks/store.py b/src/sentry/tasks/store.py index d688edcb4ce45c..b0c276c90cafee 100644 --- a/src/sentry/tasks/store.py +++ b/src/sentry/tasks/store.py @@ -16,7 +16,9 @@ from sentry.constants import DEFAULT_STORE_NORMALIZER_ARGS from sentry.datascrubbing import scrub_data from sentry.eventstore import processing -from sentry.feedback.usecases.save_feedback_event import save_feedback_event +from sentry.feedback.usecases.save_event_feedback import ( + save_event_feedback as save_event_feedback_impl, +) from sentry.ingest.types import ConsumerType from sentry.killswitches import killswitch_matches_context from sentry.lang.native.symbolicator import SymbolicatorTaskKind @@ -703,7 +705,7 @@ def save_event_feedback( project_id: int, **kwargs: Any, ) -> None: - save_feedback_event(data, project_id) + save_event_feedback_impl(data, project_id) @instrumented_task( diff --git a/tests/sentry/feedback/test_save_feedback_event.py b/tests/sentry/feedback/test_save_event_feedback.py similarity index 88% rename from tests/sentry/feedback/test_save_feedback_event.py rename to tests/sentry/feedback/test_save_event_feedback.py index 6495b7c577288e..877d43357cdabd 100644 --- a/tests/sentry/feedback/test_save_feedback_event.py +++ b/tests/sentry/feedback/test_save_event_feedback.py @@ -5,7 +5,7 @@ from sentry.eventstore.models import Event from sentry.feedback.lib.utils import FeedbackCreationSource -from sentry.feedback.usecases.save_feedback_event import save_feedback_event +from sentry.feedback.usecases.save_event_feedback import save_event_feedback from sentry.models.environment import Environment from sentry.models.userreport import UserReport from sentry.testutils.factories import Factories @@ -15,7 +15,7 @@ @pytest.fixture def mock_create_feedback_issue(): - with mock.patch("sentry.feedback.usecases.save_feedback_event.create_feedback_issue") as m: + with mock.patch("sentry.feedback.usecases.save_event_feedback.create_feedback_issue") as m: yield m @@ -30,11 +30,11 @@ def create_test_event(project_id: int, environment: Environment) -> Event: @django_db_all -def test_save_feedback_event_no_associated_event(default_project, mock_create_feedback_issue): +def test_save_event_feedback_no_associated_event(default_project, mock_create_feedback_issue): event_data = mock_feedback_event(default_project.id) mock_create_feedback_issue.return_value = None - save_feedback_event(event_data, default_project.id) + save_event_feedback(event_data, default_project.id) mock_create_feedback_issue.assert_called_once_with( event_data, default_project.id, FeedbackCreationSource.NEW_FEEDBACK_ENVELOPE @@ -47,7 +47,7 @@ def test_save_feedback_event_no_associated_event(default_project, mock_create_fe "timestamp_format", ["number", "iso"], ) -def test_save_feedback_event_with_associated_event( +def test_save_event_feedback_with_associated_event( default_project, mock_create_feedback_issue, timestamp_format ): environment = Factories.create_environment(default_project, name="production") @@ -63,7 +63,7 @@ def test_save_feedback_event_with_associated_event( event_data["environment"] = "production" mock_create_feedback_issue.return_value = event_data - save_feedback_event(event_data, default_project.id) + save_event_feedback(event_data, default_project.id) mock_create_feedback_issue.assert_called_once_with( event_data, default_project.id, FeedbackCreationSource.NEW_FEEDBACK_ENVELOPE @@ -83,7 +83,7 @@ def test_save_feedback_event_with_associated_event( @django_db_all -def test_save_feedback_event_with_unprocessed_associated_event( +def test_save_event_feedback_with_unprocessed_associated_event( default_project, mock_create_feedback_issue, ): @@ -95,7 +95,7 @@ def test_save_feedback_event_with_unprocessed_associated_event( event_data["environment"] = "production" mock_create_feedback_issue.return_value = event_data - save_feedback_event(event_data, default_project.id) + save_event_feedback(event_data, default_project.id) mock_create_feedback_issue.assert_called_once_with( event_data, default_project.id, FeedbackCreationSource.NEW_FEEDBACK_ENVELOPE @@ -116,7 +116,7 @@ def test_save_feedback_event_with_unprocessed_associated_event( @django_db_all -def test_save_feedback_event_with_missing_fields(default_project, mock_create_feedback_issue): +def test_save_event_feedback_with_missing_fields(default_project, mock_create_feedback_issue): environment = Factories.create_environment(default_project, name="production") event_data = mock_feedback_event(default_project.id) @@ -130,7 +130,7 @@ def test_save_feedback_event_with_missing_fields(default_project, mock_create_fe mock_create_feedback_issue.return_value = event_data - save_feedback_event(event_data, default_project.id) + save_event_feedback(event_data, default_project.id) mock_create_feedback_issue.assert_called_once_with( event_data, default_project.id, FeedbackCreationSource.NEW_FEEDBACK_ENVELOPE From 927b6767922cbfe59a593d63983bd03d2cbe5b07 Mon Sep 17 00:00:00 2001 From: Andrew Liu <159852527+aliu39@users.noreply.github.com> Date: Fri, 11 Jul 2025 15:46:33 -0700 Subject: [PATCH 03/10] Line length --- .../feedback/usecases/save_event_feedback.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/src/sentry/feedback/usecases/save_event_feedback.py b/src/sentry/feedback/usecases/save_event_feedback.py index 3b1c116687279a..4dce45ad48a4b9 100644 --- a/src/sentry/feedback/usecases/save_event_feedback.py +++ b/src/sentry/feedback/usecases/save_event_feedback.py @@ -14,11 +14,14 @@ def save_event_feedback(event_data: Mapping[str, Any], project_id: int): - """Saves feedback given data in an event format. This function should only be called by the new feedback consumer's ingest strategy, to process feedback envelopes (feedback v2). - It is currently instrumented as a task in sentry.tasks.store. + """Saves feedback given data in an event format. This function should only + be called by the new feedback consumer's ingest strategy, to process + feedback envelopes (feedback v2). It is currently instrumented as a task in + sentry.tasks.store. - If the save is successful and the `associated_event_id` field is present, this will - also save a UserReport in Postgres (shim to v1). This is to allow queries by the group_id relation, which we don't have in clickhouse. + If the save is successful and the `associated_event_id` field is present, + this will also save a UserReport in Postgres (shim to v1). This is to allow + queries by the group_id relation, which we don't have in clickhouse. """ if not isinstance(event_data, dict): event_data = dict(event_data) @@ -32,7 +35,9 @@ def save_event_feedback(event_data: Mapping[str, Any], project_id: int): try: # Shim to UserReport - # TODO: this logic should be extracted to a shim_to_userreport function which returns a report dict. After that this function can be removed and the store task can directly call feedback ingest functions. + # TODO: this logic should be extracted to a shim_to_userreport function + # which returns a report dict. After that this function can be removed + # and the store task can directly call feedback ingest functions. feedback_context = fixed_event_data["contexts"]["feedback"] associated_event_id = feedback_context.get("associated_event_id") From ef511ea7e83feb887333107f9434a6a4820df2c4 Mon Sep 17 00:00:00 2001 From: Andrew Liu <159852527+aliu39@users.noreply.github.com> Date: Fri, 11 Jul 2025 15:49:10 -0700 Subject: [PATCH 04/10] Nest endpoint tests --- .../{ => endpoints}/test_organization_feedback_summary.py | 0 .../feedback/{ => endpoints}/test_organization_user_reports.py | 0 .../sentry/feedback/{ => endpoints}/test_project_user_reports.py | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename tests/sentry/feedback/{ => endpoints}/test_organization_feedback_summary.py (100%) rename tests/sentry/feedback/{ => endpoints}/test_organization_user_reports.py (100%) rename tests/sentry/feedback/{ => endpoints}/test_project_user_reports.py (100%) diff --git a/tests/sentry/feedback/test_organization_feedback_summary.py b/tests/sentry/feedback/endpoints/test_organization_feedback_summary.py similarity index 100% rename from tests/sentry/feedback/test_organization_feedback_summary.py rename to tests/sentry/feedback/endpoints/test_organization_feedback_summary.py diff --git a/tests/sentry/feedback/test_organization_user_reports.py b/tests/sentry/feedback/endpoints/test_organization_user_reports.py similarity index 100% rename from tests/sentry/feedback/test_organization_user_reports.py rename to tests/sentry/feedback/endpoints/test_organization_user_reports.py diff --git a/tests/sentry/feedback/test_project_user_reports.py b/tests/sentry/feedback/endpoints/test_project_user_reports.py similarity index 100% rename from tests/sentry/feedback/test_project_user_reports.py rename to tests/sentry/feedback/endpoints/test_project_user_reports.py From 9a729303c7a6cbb4924cc1b7142e925697d81e3d Mon Sep 17 00:00:00 2001 From: Andrew Liu <159852527+aliu39@users.noreply.github.com> Date: Fri, 11 Jul 2025 15:56:32 -0700 Subject: [PATCH 05/10] Move userreport ingest file under feedback --- .../endpoints/project_user_reports.py | 2 +- .../feedback/usecases/save_event_feedback.py | 2 +- .../usecases}/userreport.py | 0 src/sentry/ingest/consumer/processors.py | 2 +- .../test_organization_user_reports.py | 0 .../feedback/test_project_user_reports.py | 0 .../{ingest => feedback}/test_userreport.py | 20 +++++++++++++------ 7 files changed, 17 insertions(+), 9 deletions(-) rename src/sentry/{ingest => feedback/usecases}/userreport.py (100%) create mode 100644 tests/sentry/feedback/test_organization_user_reports.py create mode 100644 tests/sentry/feedback/test_project_user_reports.py rename tests/sentry/{ingest => feedback}/test_userreport.py (93%) diff --git a/src/sentry/feedback/endpoints/project_user_reports.py b/src/sentry/feedback/endpoints/project_user_reports.py index c8f06673ef6516..0d80f661b12116 100644 --- a/src/sentry/feedback/endpoints/project_user_reports.py +++ b/src/sentry/feedback/endpoints/project_user_reports.py @@ -16,7 +16,7 @@ from sentry.api.paginator import DateTimePaginator from sentry.api.serializers import UserReportWithGroupSerializer, serialize from sentry.feedback.lib.utils import FeedbackCreationSource -from sentry.ingest.userreport import Conflict, save_userreport +from sentry.feedback.usecases.userreport import Conflict, save_userreport from sentry.models.environment import Environment from sentry.models.userreport import UserReport from sentry.utils.dates import epoch diff --git a/src/sentry/feedback/usecases/save_event_feedback.py b/src/sentry/feedback/usecases/save_event_feedback.py index 4dce45ad48a4b9..6a07dc911d72cc 100644 --- a/src/sentry/feedback/usecases/save_event_feedback.py +++ b/src/sentry/feedback/usecases/save_event_feedback.py @@ -5,7 +5,7 @@ from sentry.feedback.lib.utils import FeedbackCreationSource from sentry.feedback.usecases.create_feedback import create_feedback_issue -from sentry.ingest.userreport import Conflict, save_userreport +from sentry.feedback.usecases.userreport import Conflict, save_userreport from sentry.models.environment import Environment from sentry.models.project import Project from sentry.utils import metrics diff --git a/src/sentry/ingest/userreport.py b/src/sentry/feedback/usecases/userreport.py similarity index 100% rename from src/sentry/ingest/userreport.py rename to src/sentry/feedback/usecases/userreport.py diff --git a/src/sentry/ingest/consumer/processors.py b/src/sentry/ingest/consumer/processors.py index 56e8041cede3b8..2146a69bb5a046 100644 --- a/src/sentry/ingest/consumer/processors.py +++ b/src/sentry/ingest/consumer/processors.py @@ -15,8 +15,8 @@ from sentry.event_manager import EventManager, save_attachment from sentry.eventstore.processing import event_processing_store, transaction_processing_store from sentry.feedback.lib.utils import FeedbackCreationSource, is_in_feedback_denylist +from sentry.feedback.usecases.userreport import Conflict, save_userreport from sentry.ingest.types import ConsumerType -from sentry.ingest.userreport import Conflict, save_userreport from sentry.killswitches import killswitch_matches_context from sentry.models.organization import Organization from sentry.models.project import Project diff --git a/tests/sentry/feedback/test_organization_user_reports.py b/tests/sentry/feedback/test_organization_user_reports.py new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/tests/sentry/feedback/test_project_user_reports.py b/tests/sentry/feedback/test_project_user_reports.py new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/tests/sentry/ingest/test_userreport.py b/tests/sentry/feedback/test_userreport.py similarity index 93% rename from tests/sentry/ingest/test_userreport.py rename to tests/sentry/feedback/test_userreport.py index f5611ee99b4f23..23032f707cadf6 100644 --- a/tests/sentry/ingest/test_userreport.py +++ b/tests/sentry/feedback/test_userreport.py @@ -5,7 +5,7 @@ from sentry.feedback.lib.types import UserReportDict from sentry.feedback.lib.utils import UNREAL_FEEDBACK_UNATTENDED_MESSAGE, FeedbackCreationSource -from sentry.ingest.userreport import save_userreport, validate_user_report +from sentry.feedback.usecases.userreport import save_userreport, validate_user_report from sentry.models.userreport import UserReport from sentry.testutils.factories import Factories from sentry.testutils.pytest.fixtures import django_db_all @@ -30,13 +30,15 @@ def mock_report_dict() -> UserReportDict: @pytest.fixture def skip_denylist(monkeypatch): - monkeypatch.setattr("sentry.ingest.userreport.is_in_feedback_denylist", lambda org: False) + monkeypatch.setattr( + "sentry.feedback.usecases.userreport.is_in_feedback_denylist", lambda org: False + ) @pytest.fixture def skip_filters(monkeypatch): monkeypatch.setattr( - "sentry.ingest.userreport.validate_user_report", + "sentry.feedback.usecases.userreport.validate_user_report", Mock(return_value=(False, None, None)), ) @@ -219,7 +221,9 @@ def test_save_user_report_basic( def test_save_user_report_filters_denylist( default_project, monkeypatch, skip_filters, mock_report_dict ): - monkeypatch.setattr("sentry.ingest.userreport.is_in_feedback_denylist", lambda org: True) + monkeypatch.setattr( + "sentry.feedback.usecases.userreport.is_in_feedback_denylist", lambda org: True + ) result = save_userreport( default_project, mock_report_dict, FeedbackCreationSource.USER_REPORT_ENVELOPE ) @@ -286,7 +290,9 @@ def test_save_user_report_shims_if_event_found( ) mock_shim_to_feedback = Mock() - monkeypatch.setattr("sentry.ingest.userreport.shim_to_feedback", mock_shim_to_feedback) + monkeypatch.setattr( + "sentry.feedback.usecases.userreport.shim_to_feedback", mock_shim_to_feedback + ) mock_report_dict["event_id"] = event.event_id @@ -305,7 +311,9 @@ def test_save_user_report_does_not_shim_if_event_found_but_source_is_new_feedbac ) mock_shim_to_feedback = Mock() - monkeypatch.setattr("sentry.ingest.userreport.shim_to_feedback", mock_shim_to_feedback) + monkeypatch.setattr( + "sentry.feedback.usecases.userreport.shim_to_feedback", mock_shim_to_feedback + ) # Source is new feedback, so no shim save_userreport( default_project, From 8f9be9722e7cb7ec8a88e83692d44b24bb38f444 Mon Sep 17 00:00:00 2001 From: Andrew Liu <159852527+aliu39@users.noreply.github.com> Date: Fri, 11 Jul 2025 16:05:25 -0700 Subject: [PATCH 06/10] Create nested ingest module --- src/sentry/feedback/endpoints/project_user_reports.py | 2 +- src/sentry/feedback/usecases/ingest/__init__.py | 0 src/sentry/feedback/usecases/{ => ingest}/create_feedback.py | 0 .../feedback/usecases/{ => ingest}/save_event_feedback.py | 0 src/sentry/feedback/usecases/{ => ingest}/shim_to_feedback.py | 0 src/sentry/feedback/usecases/{ => ingest}/userreport.py | 0 src/sentry/ingest/consumer/processors.py | 2 +- src/sentry/ingest/userreport.py | 0 src/sentry/tasks/post_process.py | 2 +- src/sentry/tasks/store.py | 2 +- src/sentry/tasks/update_user_reports.py | 2 +- src/sentry/utils/mockdata/core.py | 2 +- src/sentry/web/frontend/error_page_embed.py | 2 +- .../feedback/endpoints/test_organization_feedback_summary.py | 2 +- tests/sentry/feedback/test_create_feedback.py | 2 +- tests/sentry/feedback/test_save_event_feedback.py | 2 +- tests/sentry/feedback/test_shim_to_feedback.py | 2 +- tests/sentry/feedback/test_userreport.py | 2 +- tests/sentry/issues/endpoints/test_organization_group_index.py | 2 +- tests/sentry/tasks/test_post_process.py | 2 +- 20 files changed, 14 insertions(+), 14 deletions(-) create mode 100644 src/sentry/feedback/usecases/ingest/__init__.py rename src/sentry/feedback/usecases/{ => ingest}/create_feedback.py (100%) rename src/sentry/feedback/usecases/{ => ingest}/save_event_feedback.py (100%) rename src/sentry/feedback/usecases/{ => ingest}/shim_to_feedback.py (100%) rename src/sentry/feedback/usecases/{ => ingest}/userreport.py (100%) create mode 100644 src/sentry/ingest/userreport.py diff --git a/src/sentry/feedback/endpoints/project_user_reports.py b/src/sentry/feedback/endpoints/project_user_reports.py index 0d80f661b12116..8d0dabb2952e79 100644 --- a/src/sentry/feedback/endpoints/project_user_reports.py +++ b/src/sentry/feedback/endpoints/project_user_reports.py @@ -16,7 +16,7 @@ from sentry.api.paginator import DateTimePaginator from sentry.api.serializers import UserReportWithGroupSerializer, serialize from sentry.feedback.lib.utils import FeedbackCreationSource -from sentry.feedback.usecases.userreport import Conflict, save_userreport +from sentry.feedback.usecases.ingest.userreport import Conflict, save_userreport from sentry.models.environment import Environment from sentry.models.userreport import UserReport from sentry.utils.dates import epoch diff --git a/src/sentry/feedback/usecases/ingest/__init__.py b/src/sentry/feedback/usecases/ingest/__init__.py new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/src/sentry/feedback/usecases/create_feedback.py b/src/sentry/feedback/usecases/ingest/create_feedback.py similarity index 100% rename from src/sentry/feedback/usecases/create_feedback.py rename to src/sentry/feedback/usecases/ingest/create_feedback.py diff --git a/src/sentry/feedback/usecases/save_event_feedback.py b/src/sentry/feedback/usecases/ingest/save_event_feedback.py similarity index 100% rename from src/sentry/feedback/usecases/save_event_feedback.py rename to src/sentry/feedback/usecases/ingest/save_event_feedback.py diff --git a/src/sentry/feedback/usecases/shim_to_feedback.py b/src/sentry/feedback/usecases/ingest/shim_to_feedback.py similarity index 100% rename from src/sentry/feedback/usecases/shim_to_feedback.py rename to src/sentry/feedback/usecases/ingest/shim_to_feedback.py diff --git a/src/sentry/feedback/usecases/userreport.py b/src/sentry/feedback/usecases/ingest/userreport.py similarity index 100% rename from src/sentry/feedback/usecases/userreport.py rename to src/sentry/feedback/usecases/ingest/userreport.py diff --git a/src/sentry/ingest/consumer/processors.py b/src/sentry/ingest/consumer/processors.py index 2146a69bb5a046..a6099bc9a4696c 100644 --- a/src/sentry/ingest/consumer/processors.py +++ b/src/sentry/ingest/consumer/processors.py @@ -15,7 +15,7 @@ from sentry.event_manager import EventManager, save_attachment from sentry.eventstore.processing import event_processing_store, transaction_processing_store from sentry.feedback.lib.utils import FeedbackCreationSource, is_in_feedback_denylist -from sentry.feedback.usecases.userreport import Conflict, save_userreport +from sentry.feedback.usecases.ingest.userreport import Conflict, save_userreport from sentry.ingest.types import ConsumerType from sentry.killswitches import killswitch_matches_context from sentry.models.organization import Organization diff --git a/src/sentry/ingest/userreport.py b/src/sentry/ingest/userreport.py new file mode 100644 index 00000000000000..e69de29bb2d1d6 diff --git a/src/sentry/tasks/post_process.py b/src/sentry/tasks/post_process.py index 80779a5074f5bb..e39f3eda256b1e 100644 --- a/src/sentry/tasks/post_process.py +++ b/src/sentry/tasks/post_process.py @@ -1428,7 +1428,7 @@ def check_has_high_priority_alerts(job: PostProcessJob) -> None: def link_event_to_user_report(job: PostProcessJob) -> None: from sentry.feedback.lib.utils import FeedbackCreationSource - from sentry.feedback.usecases.shim_to_feedback import shim_to_feedback + from sentry.feedback.usecases.ingest.shim_to_feedback import shim_to_feedback from sentry.models.userreport import UserReport event = job["event"] diff --git a/src/sentry/tasks/store.py b/src/sentry/tasks/store.py index b0c276c90cafee..6cb7a245787a48 100644 --- a/src/sentry/tasks/store.py +++ b/src/sentry/tasks/store.py @@ -16,7 +16,7 @@ from sentry.constants import DEFAULT_STORE_NORMALIZER_ARGS from sentry.datascrubbing import scrub_data from sentry.eventstore import processing -from sentry.feedback.usecases.save_event_feedback import ( +from sentry.feedback.usecases.ingest.save_event_feedback import ( save_event_feedback as save_event_feedback_impl, ) from sentry.ingest.types import ConsumerType diff --git a/src/sentry/tasks/update_user_reports.py b/src/sentry/tasks/update_user_reports.py index fe9eeb047e3696..5db1ca0e8cbedb 100644 --- a/src/sentry/tasks/update_user_reports.py +++ b/src/sentry/tasks/update_user_reports.py @@ -6,7 +6,7 @@ from sentry import eventstore, quotas from sentry.feedback.lib.utils import FeedbackCreationSource, is_in_feedback_denylist -from sentry.feedback.usecases.shim_to_feedback import shim_to_feedback +from sentry.feedback.usecases.ingest.shim_to_feedback import shim_to_feedback from sentry.models.project import Project from sentry.models.userreport import UserReport from sentry.silo.base import SiloMode diff --git a/src/sentry/utils/mockdata/core.py b/src/sentry/utils/mockdata/core.py index 405ea1f7157ae0..5fd4c3c322ede8 100644 --- a/src/sentry/utils/mockdata/core.py +++ b/src/sentry/utils/mockdata/core.py @@ -22,7 +22,7 @@ from sentry.constants import ObjectStatus from sentry.exceptions import HashDiscarded from sentry.feedback.lib.utils import FeedbackCreationSource -from sentry.feedback.usecases.create_feedback import create_feedback_issue +from sentry.feedback.usecases.ingest.create_feedback import create_feedback_issue from sentry.incidents.logic import create_alert_rule, create_alert_rule_trigger, create_incident from sentry.incidents.models.alert_rule import AlertRuleThresholdType from sentry.incidents.models.incident import IncidentType diff --git a/src/sentry/web/frontend/error_page_embed.py b/src/sentry/web/frontend/error_page_embed.py index 2f91a7b87ba3b1..08eec8d13854b2 100644 --- a/src/sentry/web/frontend/error_page_embed.py +++ b/src/sentry/web/frontend/error_page_embed.py @@ -13,7 +13,7 @@ from sentry import eventstore from sentry.feedback.lib.utils import FeedbackCreationSource -from sentry.feedback.usecases.shim_to_feedback import shim_to_feedback +from sentry.feedback.usecases.ingest.shim_to_feedback import shim_to_feedback from sentry.models.options.project_option import ProjectOption from sentry.models.project import Project from sentry.models.projectkey import ProjectKey diff --git a/tests/sentry/feedback/endpoints/test_organization_feedback_summary.py b/tests/sentry/feedback/endpoints/test_organization_feedback_summary.py index f4cf4cd96344a1..6f8f91fe8384fa 100644 --- a/tests/sentry/feedback/endpoints/test_organization_feedback_summary.py +++ b/tests/sentry/feedback/endpoints/test_organization_feedback_summary.py @@ -4,7 +4,7 @@ from django.urls import reverse from sentry.feedback.lib.utils import FeedbackCreationSource -from sentry.feedback.usecases.create_feedback import create_feedback_issue +from sentry.feedback.usecases.ingest.create_feedback import create_feedback_issue from sentry.testutils.cases import APITestCase from sentry.testutils.pytest.fixtures import django_db_all from sentry.testutils.silo import region_silo_test diff --git a/tests/sentry/feedback/test_create_feedback.py b/tests/sentry/feedback/test_create_feedback.py index 88d06cc6bded4a..050105806d9bd8 100644 --- a/tests/sentry/feedback/test_create_feedback.py +++ b/tests/sentry/feedback/test_create_feedback.py @@ -7,7 +7,7 @@ import pytest from sentry.feedback.lib.utils import FeedbackCreationSource -from sentry.feedback.usecases.create_feedback import ( +from sentry.feedback.usecases.ingest.create_feedback import ( create_feedback_issue, fix_for_issue_platform, get_feedback_title, diff --git a/tests/sentry/feedback/test_save_event_feedback.py b/tests/sentry/feedback/test_save_event_feedback.py index 877d43357cdabd..13c7179a34d323 100644 --- a/tests/sentry/feedback/test_save_event_feedback.py +++ b/tests/sentry/feedback/test_save_event_feedback.py @@ -5,7 +5,7 @@ from sentry.eventstore.models import Event from sentry.feedback.lib.utils import FeedbackCreationSource -from sentry.feedback.usecases.save_event_feedback import save_event_feedback +from sentry.feedback.usecases.ingest.save_event_feedback import save_event_feedback from sentry.models.environment import Environment from sentry.models.userreport import UserReport from sentry.testutils.factories import Factories diff --git a/tests/sentry/feedback/test_shim_to_feedback.py b/tests/sentry/feedback/test_shim_to_feedback.py index bf526141f4b469..748b176726bfd1 100644 --- a/tests/sentry/feedback/test_shim_to_feedback.py +++ b/tests/sentry/feedback/test_shim_to_feedback.py @@ -8,7 +8,7 @@ from sentry.eventstore.models import Event from sentry.feedback.lib.utils import FeedbackCreationSource -from sentry.feedback.usecases.shim_to_feedback import shim_to_feedback +from sentry.feedback.usecases.ingest.shim_to_feedback import shim_to_feedback from sentry.testutils.factories import Factories from sentry.testutils.pytest.fixtures import django_db_all diff --git a/tests/sentry/feedback/test_userreport.py b/tests/sentry/feedback/test_userreport.py index 23032f707cadf6..dd0e6d94dd04fb 100644 --- a/tests/sentry/feedback/test_userreport.py +++ b/tests/sentry/feedback/test_userreport.py @@ -5,7 +5,7 @@ from sentry.feedback.lib.types import UserReportDict from sentry.feedback.lib.utils import UNREAL_FEEDBACK_UNATTENDED_MESSAGE, FeedbackCreationSource -from sentry.feedback.usecases.userreport import save_userreport, validate_user_report +from sentry.feedback.usecases.ingest.userreport import save_userreport, validate_user_report from sentry.models.userreport import UserReport from sentry.testutils.factories import Factories from sentry.testutils.pytest.fixtures import django_db_all diff --git a/tests/sentry/issues/endpoints/test_organization_group_index.py b/tests/sentry/issues/endpoints/test_organization_group_index.py index 70008e7dab68b4..9f361a9ff1891c 100644 --- a/tests/sentry/issues/endpoints/test_organization_group_index.py +++ b/tests/sentry/issues/endpoints/test_organization_group_index.py @@ -13,7 +13,7 @@ from sentry import options from sentry.feedback.lib.utils import FeedbackCreationSource -from sentry.feedback.usecases.create_feedback import create_feedback_issue +from sentry.feedback.usecases.ingest.create_feedback import create_feedback_issue from sentry.integrations.models.external_issue import ExternalIssue from sentry.integrations.models.organization_integration import OrganizationIntegration from sentry.issues.grouptype import ( diff --git a/tests/sentry/tasks/test_post_process.py b/tests/sentry/tasks/test_post_process.py index 86fe02cffcaf83..4ae7ee3a5826b5 100644 --- a/tests/sentry/tasks/test_post_process.py +++ b/tests/sentry/tasks/test_post_process.py @@ -19,7 +19,7 @@ from sentry.eventstore.processing import event_processing_store from sentry.eventstream.types import EventStreamEventType from sentry.feedback.lib.utils import FeedbackCreationSource -from sentry.feedback.usecases.create_feedback import get_feedback_title +from sentry.feedback.usecases.ingest.create_feedback import get_feedback_title from sentry.integrations.models.integration import Integration from sentry.integrations.source_code_management.commit_context import CommitInfo, FileBlameInfo from sentry.issues.auto_source_code_config.utils.platform import get_supported_platforms From 9be2e69d482574b3a9ad393956effa5c44b7f736 Mon Sep 17 00:00:00 2001 From: Andrew Liu <159852527+aliu39@users.noreply.github.com> Date: Fri, 11 Jul 2025 16:33:45 -0700 Subject: [PATCH 07/10] Fix imports and tests --- .../feedback/usecases/ingest/save_event_feedback.py | 4 ++-- .../feedback/usecases/ingest/shim_to_feedback.py | 2 +- src/sentry/feedback/usecases/ingest/userreport.py | 4 ++-- tests/sentry/feedback/conftest.py | 2 +- .../endpoints/test_organization_user_reports.py | 2 +- .../feedback/endpoints/test_project_user_reports.py | 8 ++++---- tests/sentry/feedback/test_create_feedback.py | 2 +- .../sentry/feedback/test_organization_user_reports.py | 0 tests/sentry/feedback/test_project_user_reports.py | 0 tests/sentry/feedback/test_save_event_feedback.py | 4 +++- tests/sentry/feedback/test_shim_to_feedback.py | 2 +- tests/sentry/feedback/test_userreport.py | 10 +++++----- 12 files changed, 21 insertions(+), 19 deletions(-) delete mode 100644 tests/sentry/feedback/test_organization_user_reports.py delete mode 100644 tests/sentry/feedback/test_project_user_reports.py diff --git a/src/sentry/feedback/usecases/ingest/save_event_feedback.py b/src/sentry/feedback/usecases/ingest/save_event_feedback.py index 6a07dc911d72cc..d45cb84085b0e4 100644 --- a/src/sentry/feedback/usecases/ingest/save_event_feedback.py +++ b/src/sentry/feedback/usecases/ingest/save_event_feedback.py @@ -4,8 +4,8 @@ from typing import Any from sentry.feedback.lib.utils import FeedbackCreationSource -from sentry.feedback.usecases.create_feedback import create_feedback_issue -from sentry.feedback.usecases.userreport import Conflict, save_userreport +from sentry.feedback.usecases.ingest.create_feedback import create_feedback_issue +from sentry.feedback.usecases.ingest.userreport import Conflict, save_userreport from sentry.models.environment import Environment from sentry.models.project import Project from sentry.utils import metrics diff --git a/src/sentry/feedback/usecases/ingest/shim_to_feedback.py b/src/sentry/feedback/usecases/ingest/shim_to_feedback.py index 844a471398c24a..ff35413867681e 100644 --- a/src/sentry/feedback/usecases/ingest/shim_to_feedback.py +++ b/src/sentry/feedback/usecases/ingest/shim_to_feedback.py @@ -8,7 +8,7 @@ from sentry.eventstore.models import Event, GroupEvent from sentry.feedback.lib.types import UserReportDict from sentry.feedback.lib.utils import FeedbackCreationSource, is_in_feedback_denylist -from sentry.feedback.usecases.create_feedback import create_feedback_issue +from sentry.feedback.usecases.ingest.create_feedback import create_feedback_issue from sentry.models.project import Project from sentry.utils import metrics from sentry.utils.outcomes import Outcome, track_outcome diff --git a/src/sentry/feedback/usecases/ingest/userreport.py b/src/sentry/feedback/usecases/ingest/userreport.py index ffc5cc9d24f01f..e891d441765e83 100644 --- a/src/sentry/feedback/usecases/ingest/userreport.py +++ b/src/sentry/feedback/usecases/ingest/userreport.py @@ -19,7 +19,7 @@ FeedbackCreationSource, is_in_feedback_denylist, ) -from sentry.feedback.usecases.shim_to_feedback import shim_to_feedback +from sentry.feedback.usecases.ingest.shim_to_feedback import shim_to_feedback from sentry.models.project import Project from sentry.models.userreport import UserReport from sentry.signals import user_feedback_received @@ -40,7 +40,7 @@ def save_userreport( source: FeedbackCreationSource, start_time: datetime | None = None, ) -> UserReport | None: - with metrics.timer("sentry.ingest.userreport.save_userreport", tags={"referrer": source.value}): + with metrics.timer("userreport.create_user_report", tags={"referrer": source.value}): if start_time is None: start_time = timezone.now() diff --git a/tests/sentry/feedback/conftest.py b/tests/sentry/feedback/conftest.py index 56a4ccac16c26d..8409bf866f99d4 100644 --- a/tests/sentry/feedback/conftest.py +++ b/tests/sentry/feedback/conftest.py @@ -7,7 +7,7 @@ def mock_produce_occurrence_to_kafka(monkeypatch): mock = Mock() monkeypatch.setattr( - "sentry.feedback.usecases.create_feedback.produce_occurrence_to_kafka", mock + "sentry.feedback.usecases.ingest.create_feedback.produce_occurrence_to_kafka", mock ) return mock diff --git a/tests/sentry/feedback/endpoints/test_organization_user_reports.py b/tests/sentry/feedback/endpoints/test_organization_user_reports.py index 59bf2fb93e54af..328671dd782ad6 100644 --- a/tests/sentry/feedback/endpoints/test_organization_user_reports.py +++ b/tests/sentry/feedback/endpoints/test_organization_user_reports.py @@ -3,7 +3,7 @@ from sentry.feedback.lib.types import UserReportDict from sentry.feedback.lib.utils import FeedbackCreationSource -from sentry.ingest.userreport import save_userreport +from sentry.feedback.usecases.ingest.userreport import save_userreport from sentry.models.group import GroupStatus from sentry.models.userreport import UserReport from sentry.testutils.cases import APITestCase, SnubaTestCase diff --git a/tests/sentry/feedback/endpoints/test_project_user_reports.py b/tests/sentry/feedback/endpoints/test_project_user_reports.py index 1bb405823f8c96..0911bd525beeab 100644 --- a/tests/sentry/feedback/endpoints/test_project_user_reports.py +++ b/tests/sentry/feedback/endpoints/test_project_user_reports.py @@ -415,7 +415,7 @@ def test_environments(self): == self.environment.id ) - @patch("sentry.feedback.usecases.create_feedback.produce_occurrence_to_kafka") + @patch("sentry.feedback.usecases.ingest.create_feedback.produce_occurrence_to_kafka") def test_simple_shim_to_feedback(self, mock_produce_occurrence_to_kafka): replay_id = "b" * 32 event_with_replay = self.store_event( @@ -471,7 +471,7 @@ def test_simple_shim_to_feedback(self, mock_produce_occurrence_to_kafka): ) assert mock_event_data["level"] == "error" - @patch("sentry.feedback.usecases.create_feedback.produce_occurrence_to_kafka") + @patch("sentry.feedback.usecases.ingest.create_feedback.produce_occurrence_to_kafka") def test_simple_shim_to_feedback_no_event_should_not_call( self, mock_produce_occurrence_to_kafka ): @@ -499,7 +499,7 @@ def test_simple_shim_to_feedback_no_event_should_not_call( assert len(mock_produce_occurrence_to_kafka.mock_calls) == 0 - @patch("sentry.ingest.userreport.validate_user_report") + @patch("sentry.feedback.usecases.ingest.userreport.validate_user_report") def test_validation_error(self, mock_validate_user_report): mock_validate_user_report.return_value = (True, "data_invalid", "Data invalid") self.login_as(user=self.user) @@ -518,7 +518,7 @@ def test_validation_error(self, mock_validate_user_report): assert response.status_code == 400, response.content assert UserReport.objects.count() == 0 - @patch("sentry.ingest.userreport.is_in_feedback_denylist") + @patch("sentry.feedback.usecases.ingest.userreport.is_in_feedback_denylist") def test_denylist(self, mock_is_in_feedback_denylist): mock_is_in_feedback_denylist.return_value = True self.login_as(user=self.user) diff --git a/tests/sentry/feedback/test_create_feedback.py b/tests/sentry/feedback/test_create_feedback.py index 050105806d9bd8..80beccbbea75a8 100644 --- a/tests/sentry/feedback/test_create_feedback.py +++ b/tests/sentry/feedback/test_create_feedback.py @@ -845,7 +845,7 @@ def test_create_feedback_evidence_has_spam( default_project, mock_produce_occurrence_to_kafka, monkeypatch ): """We need this evidence field in post process, to determine if we should send alerts.""" - monkeypatch.setattr("sentry.feedback.usecases.create_feedback.is_spam", lambda _: True) + monkeypatch.setattr("sentry.feedback.usecases.ingest.create_feedback.is_spam", lambda _: True) default_project.update_option("sentry:feedback_ai_spam_detection", True) with Feature({"organizations:user-feedback-spam-ingest": True}): diff --git a/tests/sentry/feedback/test_organization_user_reports.py b/tests/sentry/feedback/test_organization_user_reports.py deleted file mode 100644 index e69de29bb2d1d6..00000000000000 diff --git a/tests/sentry/feedback/test_project_user_reports.py b/tests/sentry/feedback/test_project_user_reports.py deleted file mode 100644 index e69de29bb2d1d6..00000000000000 diff --git a/tests/sentry/feedback/test_save_event_feedback.py b/tests/sentry/feedback/test_save_event_feedback.py index 13c7179a34d323..28e8b23adf34cb 100644 --- a/tests/sentry/feedback/test_save_event_feedback.py +++ b/tests/sentry/feedback/test_save_event_feedback.py @@ -15,7 +15,9 @@ @pytest.fixture def mock_create_feedback_issue(): - with mock.patch("sentry.feedback.usecases.save_event_feedback.create_feedback_issue") as m: + with mock.patch( + "sentry.feedback.usecases.ingest.save_event_feedback.create_feedback_issue" + ) as m: yield m diff --git a/tests/sentry/feedback/test_shim_to_feedback.py b/tests/sentry/feedback/test_shim_to_feedback.py index 748b176726bfd1..18085a65800f83 100644 --- a/tests/sentry/feedback/test_shim_to_feedback.py +++ b/tests/sentry/feedback/test_shim_to_feedback.py @@ -111,7 +111,7 @@ def test_shim_to_feedback_fails_if_required_fields_missing(default_project, monk # Email and comments are required to shim. Tests key errors are handled. mock_create_feedback_issue = Mock() monkeypatch.setattr( - "sentry.feedback.usecases.shim_to_feedback.create_feedback_issue", + "sentry.feedback.usecases.ingest.shim_to_feedback.create_feedback_issue", mock_create_feedback_issue, ) report_dict = { diff --git a/tests/sentry/feedback/test_userreport.py b/tests/sentry/feedback/test_userreport.py index dd0e6d94dd04fb..b39c3a0fd1356e 100644 --- a/tests/sentry/feedback/test_userreport.py +++ b/tests/sentry/feedback/test_userreport.py @@ -31,14 +31,14 @@ def mock_report_dict() -> UserReportDict: @pytest.fixture def skip_denylist(monkeypatch): monkeypatch.setattr( - "sentry.feedback.usecases.userreport.is_in_feedback_denylist", lambda org: False + "sentry.feedback.usecases.ingest.userreport.is_in_feedback_denylist", lambda org: False ) @pytest.fixture def skip_filters(monkeypatch): monkeypatch.setattr( - "sentry.feedback.usecases.userreport.validate_user_report", + "sentry.feedback.usecases.ingest.userreport.validate_user_report", Mock(return_value=(False, None, None)), ) @@ -222,7 +222,7 @@ def test_save_user_report_filters_denylist( default_project, monkeypatch, skip_filters, mock_report_dict ): monkeypatch.setattr( - "sentry.feedback.usecases.userreport.is_in_feedback_denylist", lambda org: True + "sentry.feedback.usecases.ingest.userreport.is_in_feedback_denylist", lambda org: True ) result = save_userreport( default_project, mock_report_dict, FeedbackCreationSource.USER_REPORT_ENVELOPE @@ -291,7 +291,7 @@ def test_save_user_report_shims_if_event_found( mock_shim_to_feedback = Mock() monkeypatch.setattr( - "sentry.feedback.usecases.userreport.shim_to_feedback", mock_shim_to_feedback + "sentry.feedback.usecases.ingest.userreport.shim_to_feedback", mock_shim_to_feedback ) mock_report_dict["event_id"] = event.event_id @@ -312,7 +312,7 @@ def test_save_user_report_does_not_shim_if_event_found_but_source_is_new_feedbac mock_shim_to_feedback = Mock() monkeypatch.setattr( - "sentry.feedback.usecases.userreport.shim_to_feedback", mock_shim_to_feedback + "sentry.feedback.usecases.ingest.userreport.shim_to_feedback", mock_shim_to_feedback ) # Source is new feedback, so no shim save_userreport( From 2cbb14f2d0d4c22b5b2f70a94c68e98c67e9103e Mon Sep 17 00:00:00 2001 From: Andrew Liu <159852527+aliu39@users.noreply.github.com> Date: Fri, 11 Jul 2025 16:43:02 -0700 Subject: [PATCH 08/10] Nest tests w same file structure --- tests/sentry/feedback/{ => lib}/test_utils.py | 0 tests/sentry/feedback/{ => usecases}/conftest.py | 0 .../sentry/feedback/{ => usecases/ingest}/test_create_feedback.py | 0 .../feedback/{ => usecases/ingest}/test_save_event_feedback.py | 0 .../feedback/{ => usecases/ingest}/test_shim_to_feedback.py | 0 tests/sentry/feedback/{ => usecases/ingest}/test_userreport.py | 0 tests/sentry/feedback/{ => usecases}/test_feedback_summaries.py | 0 tests/sentry/feedback/{ => usecases}/test_spam_detection.py | 0 8 files changed, 0 insertions(+), 0 deletions(-) rename tests/sentry/feedback/{ => lib}/test_utils.py (100%) rename tests/sentry/feedback/{ => usecases}/conftest.py (100%) rename tests/sentry/feedback/{ => usecases/ingest}/test_create_feedback.py (100%) rename tests/sentry/feedback/{ => usecases/ingest}/test_save_event_feedback.py (100%) rename tests/sentry/feedback/{ => usecases/ingest}/test_shim_to_feedback.py (100%) rename tests/sentry/feedback/{ => usecases/ingest}/test_userreport.py (100%) rename tests/sentry/feedback/{ => usecases}/test_feedback_summaries.py (100%) rename tests/sentry/feedback/{ => usecases}/test_spam_detection.py (100%) diff --git a/tests/sentry/feedback/test_utils.py b/tests/sentry/feedback/lib/test_utils.py similarity index 100% rename from tests/sentry/feedback/test_utils.py rename to tests/sentry/feedback/lib/test_utils.py diff --git a/tests/sentry/feedback/conftest.py b/tests/sentry/feedback/usecases/conftest.py similarity index 100% rename from tests/sentry/feedback/conftest.py rename to tests/sentry/feedback/usecases/conftest.py diff --git a/tests/sentry/feedback/test_create_feedback.py b/tests/sentry/feedback/usecases/ingest/test_create_feedback.py similarity index 100% rename from tests/sentry/feedback/test_create_feedback.py rename to tests/sentry/feedback/usecases/ingest/test_create_feedback.py diff --git a/tests/sentry/feedback/test_save_event_feedback.py b/tests/sentry/feedback/usecases/ingest/test_save_event_feedback.py similarity index 100% rename from tests/sentry/feedback/test_save_event_feedback.py rename to tests/sentry/feedback/usecases/ingest/test_save_event_feedback.py diff --git a/tests/sentry/feedback/test_shim_to_feedback.py b/tests/sentry/feedback/usecases/ingest/test_shim_to_feedback.py similarity index 100% rename from tests/sentry/feedback/test_shim_to_feedback.py rename to tests/sentry/feedback/usecases/ingest/test_shim_to_feedback.py diff --git a/tests/sentry/feedback/test_userreport.py b/tests/sentry/feedback/usecases/ingest/test_userreport.py similarity index 100% rename from tests/sentry/feedback/test_userreport.py rename to tests/sentry/feedback/usecases/ingest/test_userreport.py diff --git a/tests/sentry/feedback/test_feedback_summaries.py b/tests/sentry/feedback/usecases/test_feedback_summaries.py similarity index 100% rename from tests/sentry/feedback/test_feedback_summaries.py rename to tests/sentry/feedback/usecases/test_feedback_summaries.py diff --git a/tests/sentry/feedback/test_spam_detection.py b/tests/sentry/feedback/usecases/test_spam_detection.py similarity index 100% rename from tests/sentry/feedback/test_spam_detection.py rename to tests/sentry/feedback/usecases/test_spam_detection.py From 4dbdcf37138ae583d0d97299295b8a4dae4f0c26 Mon Sep 17 00:00:00 2001 From: Andrew Liu <159852527+aliu39@users.noreply.github.com> Date: Fri, 11 Jul 2025 16:49:52 -0700 Subject: [PATCH 09/10] Rename test_utils to avoid pytest conflict --- .../sentry/feedback/lib/{test_utils.py => test_feedback_utils.py} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/sentry/feedback/lib/{test_utils.py => test_feedback_utils.py} (100%) diff --git a/tests/sentry/feedback/lib/test_utils.py b/tests/sentry/feedback/lib/test_feedback_utils.py similarity index 100% rename from tests/sentry/feedback/lib/test_utils.py rename to tests/sentry/feedback/lib/test_feedback_utils.py From ba60b4748cd250748c0bbcb2f99e5f30ecce77a6 Mon Sep 17 00:00:00 2001 From: Andrew Liu <159852527+aliu39@users.noreply.github.com> Date: Fri, 11 Jul 2025 17:24:24 -0700 Subject: [PATCH 10/10] Fix more patches --- tests/sentry/tasks/test_post_process.py | 4 ++-- tests/sentry/tasks/test_update_user_reports.py | 4 ++-- tests/sentry/web/frontend/test_error_page_embed.py | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/sentry/tasks/test_post_process.py b/tests/sentry/tasks/test_post_process.py index 4ae7ee3a5826b5..6de8ef750841a9 100644 --- a/tests/sentry/tasks/test_post_process.py +++ b/tests/sentry/tasks/test_post_process.py @@ -2026,7 +2026,7 @@ def test_user_report_gets_environment_with_new_link_features(self): assert UserReport.objects.get(event_id=event_id).environment_id == environment.id - @patch("sentry.feedback.usecases.create_feedback.produce_occurrence_to_kafka") + @patch("sentry.feedback.usecases.ingest.create_feedback.produce_occurrence_to_kafka") def test_user_report_shims_to_feedback(self, mock_produce_occurrence_to_kafka): project = self.create_project() environment = Environment.objects.create( @@ -2080,7 +2080,7 @@ def test_user_report_shims_to_feedback(self, mock_produce_occurrence_to_kafka): mock_event_data["contexts"]["feedback"]["message"] ) - @patch("sentry.feedback.usecases.create_feedback.produce_occurrence_to_kafka") + @patch("sentry.feedback.usecases.ingest.create_feedback.produce_occurrence_to_kafka") def test_user_reports_no_shim_if_group_exists_on_report(self, mock_produce_occurrence_to_kafka): project = self.create_project() environment = Environment.objects.create( diff --git a/tests/sentry/tasks/test_update_user_reports.py b/tests/sentry/tasks/test_update_user_reports.py index 794f7f9e5e8265..11a5bd0ce97485 100644 --- a/tests/sentry/tasks/test_update_user_reports.py +++ b/tests/sentry/tasks/test_update_user_reports.py @@ -126,7 +126,7 @@ def test_event_timerange(self): assert report4.group_id is None assert report4.environment_id is None - @patch("sentry.feedback.usecases.create_feedback.produce_occurrence_to_kafka") + @patch("sentry.feedback.usecases.ingest.create_feedback.produce_occurrence_to_kafka") def test_calls_feedback_shim_if_ff_enabled(self, mock_produce_occurrence_to_kafka): project = self.create_project() event1 = self.store_event( @@ -166,7 +166,7 @@ def test_calls_feedback_shim_if_ff_enabled(self, mock_produce_occurrence_to_kafk assert mock_event_data["contexts"]["feedback"]["associated_event_id"] == event1.event_id assert mock_event_data["level"] == "error" - @patch("sentry.feedback.usecases.create_feedback.produce_occurrence_to_kafka") + @patch("sentry.feedback.usecases.ingest.create_feedback.produce_occurrence_to_kafka") def test_does_not_call_feedback_shim_if_environment_is_set( self, mock_produce_occurrence_to_kafka ): diff --git a/tests/sentry/web/frontend/test_error_page_embed.py b/tests/sentry/web/frontend/test_error_page_embed.py index 79b5be23dc4a64..3cefcb406e276a 100644 --- a/tests/sentry/web/frontend/test_error_page_embed.py +++ b/tests/sentry/web/frontend/test_error_page_embed.py @@ -242,7 +242,7 @@ def test_environment_gets_user_report(self): assert response.status_code == 200, response.content assert UserReport.objects.get(event_id=self.event_id).environment_id == self.environment.id - @mock.patch("sentry.feedback.usecases.create_feedback.produce_occurrence_to_kafka") + @mock.patch("sentry.feedback.usecases.ingest.create_feedback.produce_occurrence_to_kafka") def test_calls_feedback_shim_if_ff_enabled(self, mock_produce_occurrence_to_kafka): self.make_event(environment=self.environment.name, event_id=self.event_id) self.client.post( @@ -264,7 +264,7 @@ def test_calls_feedback_shim_if_ff_enabled(self, mock_produce_occurrence_to_kafk assert mock_event_data["contexts"]["feedback"]["associated_event_id"] == self.event_id assert mock_event_data["level"] == "error" - @mock.patch("sentry.feedback.usecases.create_feedback.produce_occurrence_to_kafka") + @mock.patch("sentry.feedback.usecases.ingest.create_feedback.produce_occurrence_to_kafka") def test_does_not_call_feedback_shim_no_event_if_ff_enabled( self, mock_produce_occurrence_to_kafka ):