Browse Source

test(backup): Improve backup tests (#54611)

This change contains a number of small improvements, including:

- Renaming some files for greater clarity
- Generalizing the `BackupTestCase` class, which creates an "exhaustive"
database state for testing backups. We'll be using this much more in the
future as we implement features like org-based filtering.
- Sped up `test_models` and `test_releases` considerably. These tests
both inherit from `TransactionTestCase`, which already does the heavy
lifting of rolling back any DB changes made during a test. However, we
were also manually flushing the database during the `setUp` phase,
resuling in a repeat of this super time consuming action. Removing it
makes the average test case in one of these files go from ~6 seconds to
less than 3!
- Because we are now running various tests with the `reset_pks` flag set
to `True` or `False` depending on the behavior we want to exercise, I've
added a check to `import_export_then_validate` to ensure that pks have
either all changes or all stayed the same, depending on the flag
setting.

Issue: getsentry/team-ospo#167
Alex Zaslavsky 1 year ago
parent
commit
458b615fdc

+ 304 - 0
src/sentry/testutils/helpers/backups.py

@@ -1,11 +1,15 @@
 from __future__ import annotations
 
 import tempfile
+from datetime import datetime, timedelta
 from pathlib import Path
+from uuid import uuid4
 
 from django.apps import apps
 from django.core.management import call_command
 from django.db import connections, router, transaction
+from django.utils import timezone
+from sentry_relay.auth import generate_key_pair
 
 from sentry.backup.comparators import ComparatorMap
 from sentry.backup.dependencies import sorted_dependencies
@@ -13,8 +17,59 @@ from sentry.backup.exports import OldExportConfig, exports
 from sentry.backup.findings import ComparatorFindings
 from sentry.backup.imports import OldImportConfig, imports
 from sentry.backup.validate import validate
+from sentry.incidents.models import (
+    IncidentActivity,
+    IncidentSnapshot,
+    IncidentSubscription,
+    IncidentTrigger,
+    PendingIncidentSnapshot,
+    TimeSeriesSnapshot,
+)
+from sentry.models.apiauthorization import ApiAuthorization
+from sentry.models.apikey import ApiKey
+from sentry.models.apitoken import ApiToken
+from sentry.models.authenticator import Authenticator
+from sentry.models.authidentity import AuthIdentity
+from sentry.models.authprovider import AuthProvider
+from sentry.models.counter import Counter
+from sentry.models.dashboard import Dashboard, DashboardTombstone
+from sentry.models.dashboard_widget import (
+    DashboardWidget,
+    DashboardWidgetQuery,
+    DashboardWidgetTypes,
+)
+from sentry.models.environment import EnvironmentProject
 from sentry.models.integrations.sentry_app import SentryApp
+from sentry.models.options.option import ControlOption, Option
+from sentry.models.options.organization_option import OrganizationOption
+from sentry.models.options.user_option import UserOption
+from sentry.models.organization import Organization
+from sentry.models.organizationaccessrequest import OrganizationAccessRequest
+from sentry.models.orgauthtoken import OrgAuthToken
+from sentry.models.project import Project
+from sentry.models.projectownership import ProjectOwnership
+from sentry.models.projectredirect import ProjectRedirect
+from sentry.models.recentsearch import RecentSearch
+from sentry.models.relay import Relay, RelayUsage
+from sentry.models.repository import Repository
+from sentry.models.rule import RuleActivity, RuleActivityType
+from sentry.models.savedsearch import SavedSearch, Visibility
+from sentry.models.search_common import SearchType
+from sentry.models.user import User
+from sentry.models.userip import UserIP
+from sentry.models.userrole import UserRole, UserRoleUser
+from sentry.monitors.models import (
+    CheckInStatus,
+    Monitor,
+    MonitorCheckIn,
+    MonitorEnvironment,
+    MonitorLocation,
+    MonitorType,
+    ScheduleType,
+)
+from sentry.sentry_apps.apps import SentryAppUpdater
 from sentry.silo import unguarded_write
+from sentry.testutils.cases import TransactionTestCase
 from sentry.testutils.factories import get_fixture_path
 from sentry.utils import json
 from sentry.utils.json import JSONData
@@ -99,6 +154,22 @@ def import_export_then_validate(method_name: str, *, reset_pks: bool = True) ->
         if res.findings:
             raise ValidationError(res)
 
+        # Ensure that the "reset" behavior was tested in the manner we expect.
+        for i, expect_entry in enumerate(expect):
+            model_name = expect_entry["model"]
+            expect_pk = expect_entry["pk"]
+            actual_pk = actual[i]["pk"]
+            if reset_pks and expect_pk != actual_pk:
+                expect_pk
+                AssertionError(
+                    f"At model `{model_name}`, the expected `pk` of `{expect_pk}` was not equal to the actual `pk` of `{actual_pk}`, even though `reset_pks = True`"
+                )
+            elif not reset_pks and expect_pk == actual_pk:
+                expect_pk
+                AssertionError(
+                    f"At model `{model_name}`, the expected `pk` of `{expect_pk}` was equal to the actual `pk` of `{actual_pk}`, even though `reset_pks = False`"
+                )
+
     return actual
 
 
@@ -124,3 +195,236 @@ def import_export_from_fixture_then_validate(
     res = validate(expect, export_to_file(tmp_path.joinpath("tmp_test_file.json")), map)
     if res.findings:
         raise ValidationError(res)
+
+
+class BackupTestCase(TransactionTestCase):
+    """Instruments a database state that includes an instance of every Sentry model with every field
+    set to a non-default, non-null value. This is useful for exhaustive conformance testing."""
+
+    def create_exhaustive_user(
+        self,
+        username: str,
+        *,
+        is_admin: bool = False,
+        is_staff: bool = False,
+        is_superuser: bool = False,
+    ) -> User:
+        user = self.create_user(username, is_staff=is_staff, is_superuser=is_superuser)
+        UserOption.objects.create(user=user, key="timezone", value="Europe/Vienna")
+        UserIP.objects.create(
+            user=user,
+            ip_address="127.0.0.2",
+            first_seen=datetime(2012, 4, 5, 3, 29, 45, tzinfo=timezone.utc),
+            last_seen=datetime(2012, 4, 5, 3, 29, 45, tzinfo=timezone.utc),
+        )
+
+        if is_admin:
+            self.add_user_permission(user, "users.admin")
+            role = UserRole.objects.create(name="test-admin-role")
+            UserRoleUser.objects.create(user=user, role=role)
+
+        return user
+
+    def create_exhaustive_organization(self, slug: str, owner: User, invitee: User) -> Organization:
+        org = self.create_organization(name=f"test_org_for_{slug}", owner=owner)
+        membership = self.create_member(organization=org, user=invitee, role="member")
+
+        OrganizationOption.objects.create(
+            organization=org, key="sentry:account-rate-limit", value=0
+        )
+
+        # Auth*
+        OrgAuthToken.objects.create(
+            organization_id=org.id,
+            name=f"token 1 for {slug}",
+            token_hashed=f"ABCDEF{slug}",
+            token_last_characters="xyz1",
+            scope_list=["org:ci"],
+            date_last_used=None,
+        )
+        ApiKey.objects.create(key=uuid4().hex, organization_id=org.id)
+        auth_provider = AuthProvider.objects.create(organization_id=org.id, provider="sentry")
+        Authenticator.objects.create(user=owner, type=1)
+        AuthIdentity.objects.create(
+            user=owner,
+            auth_provider=auth_provider,
+            ident=f"123456789{slug}",
+            data={
+                "key1": "value1",
+                "key2": 42,
+                "key3": [1, 2, 3],
+                "key4": {"nested_key": "nested_value"},
+            },
+        )
+
+        # Project*
+        project = self.create_project()
+        self.create_project_key(project)
+        self.create_project_bookmark(project=project, user=owner)
+        project = self.create_project()
+        ProjectOwnership.objects.create(
+            project=project, raw='{"hello":"hello"}', schema={"hello": "hello"}
+        )
+        ProjectRedirect.record(project, f"project_slug_in_{slug}")
+
+        # Team
+        team = self.create_team(name=f"test_team_in_{slug}", organization=org)
+        self.create_team_membership(user=owner, team=team)
+        OrganizationAccessRequest.objects.create(member=membership, team=team)
+
+        # Rule*
+        rule = self.create_project_rule(project=project)
+        RuleActivity.objects.create(rule=rule, type=RuleActivityType.CREATED.value)
+        self.snooze_rule(user_id=owner.id, owner_id=owner.id, rule=rule)
+
+        # Environment*
+        env = self.create_environment()
+        EnvironmentProject.objects.create(project=project, environment=env, is_hidden=False)
+
+        # Monitor*
+        monitor = Monitor.objects.create(
+            organization_id=project.organization.id,
+            project_id=project.id,
+            type=MonitorType.CRON_JOB,
+            config={"schedule": "* * * * *", "schedule_type": ScheduleType.CRONTAB},
+        )
+        mon_env = MonitorEnvironment.objects.create(
+            monitor=monitor,
+            environment=env,
+        )
+        location = MonitorLocation.objects.create(guid=uuid4(), name=f"test_location_in_{slug}")
+        MonitorCheckIn.objects.create(
+            monitor=monitor,
+            monitor_environment=mon_env,
+            location=location,
+            project_id=monitor.project_id,
+            status=CheckInStatus.IN_PROGRESS,
+        )
+
+        # AlertRule*
+        alert = self.create_alert_rule(include_all_projects=True, excluded_projects=[project])
+        trigger = self.create_alert_rule_trigger(alert_rule=alert, excluded_projects=[self.project])
+        self.create_alert_rule_trigger_action(alert_rule_trigger=trigger)
+
+        # Incident*
+        incident = self.create_incident()
+        IncidentActivity.objects.create(
+            incident=incident,
+            type=1,
+            comment=f"hello {slug}",
+        )
+        IncidentSnapshot.objects.create(
+            incident=incident,
+            event_stats_snapshot=TimeSeriesSnapshot.objects.create(
+                start=datetime.utcnow() - timedelta(hours=24),
+                end=datetime.utcnow(),
+                values=[[1.0, 2.0, 3.0], [1.5, 2.5, 3.5]],
+                period=1,
+            ),
+            unique_users=1,
+            total_events=1,
+        )
+        IncidentSubscription.objects.create(incident=incident, user_id=owner.id)
+        IncidentTrigger.objects.create(
+            incident=incident,
+            alert_rule_trigger=trigger,
+            status=1,
+        )
+
+        # *Snapshot
+        PendingIncidentSnapshot.objects.create(
+            incident=incident, target_run_date=datetime.utcnow() + timedelta(hours=4)
+        )
+
+        # Dashboard
+        dashboard = Dashboard.objects.create(
+            title=f"Dashboard 1 for {slug}", created_by_id=owner.id, organization=org
+        )
+        widget = DashboardWidget.objects.create(
+            dashboard=dashboard,
+            order=1,
+            title=f"Test Widget for {slug}",
+            display_type=0,
+            widget_type=DashboardWidgetTypes.DISCOVER,
+        )
+        DashboardWidgetQuery.objects.create(widget=widget, order=1, name=f"Test Query for {slug}")
+        DashboardTombstone.objects.create(organization=org, slug=f"test-tombstone-in-{slug}")
+
+        # *Search
+        RecentSearch.objects.create(
+            organization=org,
+            user_id=owner.id,
+            type=SearchType.ISSUE.value,
+            query=f"some query for {slug}",
+        )
+        SavedSearch.objects.create(
+            organization=org,
+            name=f"Saved query for {slug}",
+            query=f"saved query for {slug}",
+            visibility=Visibility.ORGANIZATION,
+        )
+
+        # misc
+        Counter.increment(project, 1)
+        Repository.objects.create(
+            name=f"test_repo_for_{slug}",
+            organization_id=org.id,
+            integration_id=self.integration.id,
+        )
+
+        return org
+
+    def create_exhaustive_sentry_app(self, name: str, owner: User, org: Organization) -> SentryApp:
+        # SentryApp*
+        app = self.create_sentry_app(name=name, organization=org)
+        install = self.create_sentry_app_installation(slug=app.slug, organization=org, user=owner)
+        updater = SentryAppUpdater(sentry_app=app)
+        updater.schema = {"elements": [self.create_alert_rule_action_schema()]}
+        updater.run(owner)
+
+        # Api*
+        ApiAuthorization.objects.create(application=app.application, user=owner)
+        ApiToken.objects.create(
+            application=app.application, user=owner, token=uuid4().hex, expires_at=None
+        )
+
+        # ServiceHook
+        self.create_service_hook(
+            application_id=app.application.id,
+            actor_id=app.proxy_user.id,
+            installation_id=install.id,
+            org=org,
+        )
+
+        # NotificationAction
+        project = Project.objects.filter(organization=org).first()
+        self.create_notification_action(organization=org, sentry_app_id=app.id, projects=[project])
+
+        return app
+
+    def create_exhaustive_globals(self):
+        # *Options
+        Option.objects.create(key="foo", value="a")
+        ControlOption.objects.create(key="bar", value="b")
+
+        # Relay*
+        _, public_key = generate_key_pair()
+        relay = str(uuid4())
+        Relay.objects.create(relay_id=relay, public_key=str(public_key), is_internal=True)
+        RelayUsage.objects.create(relay_id=relay, version="0.0.1", public_key=public_key)
+
+    def create_exhaustive_instance(self, *, is_superadmin: bool = False):
+        """
+        Takes an empty Sentry instance's database, and populates it with an "exhaustive" version of every model. The end result is two users, in one organization, with one full set of extensions, and all global flags set.
+        """
+
+        owner = self.create_exhaustive_user(
+            "owner", is_admin=is_superadmin, is_superuser=is_superadmin, is_staff=is_superadmin
+        )
+        invitee = self.create_exhaustive_user("invitee")
+        org = self.create_exhaustive_organization("test-org", owner, invitee)
+        self.create_exhaustive_sentry_app("test app", owner, org)
+        self.create_exhaustive_globals()
+
+    def import_export_then_validate(self, out_name, *, reset_pks: bool = True) -> JSONData:
+        return import_export_then_validate(out_name, reset_pks=reset_pks)

+ 1 - 1
tests/sentry/backup/test_coverage.py

@@ -3,7 +3,7 @@ from __future__ import annotations
 from sentry.backup.helpers import get_exportable_final_derivations_of
 from sentry.db.models import BaseModel
 from tests.sentry.backup.test_models import UNIT_TESTED_MODELS
-from tests.sentry.backup.test_releases import RELEASE_TESTED_MODELS
+from tests.sentry.backup.test_release import RELEASE_TESTED_MODELS
 
 ALL_EXPORTABLE_MODELS = {c.__name__ for c in get_exportable_final_derivations_of(BaseModel)}
 

+ 1 - 8
tests/sentry/backup/test_models.py

@@ -87,10 +87,7 @@ from sentry.monitors.models import (
 from sentry.sentry_apps.apps import SentryAppUpdater
 from sentry.snuba.models import QuerySubscription, SnubaQuery, SnubaQueryEventType
 from sentry.testutils.cases import TransactionTestCase
-from sentry.testutils.helpers.backups import (
-    clear_database_but_keep_sequences,
-    import_export_then_validate,
-)
+from sentry.testutils.helpers.backups import import_export_then_validate
 from sentry.utils.json import JSONData
 from tests.sentry.backup import run_backup_tests_only_on_single_db, targets
 
@@ -124,10 +121,6 @@ class ModelBackupTests(TransactionTestCase):
     the "actual" JSON file, and diffs the two to ensure that they match per the specified
     comparators."""
 
-    def setUp(self):
-        # Empty the database without resetting primary keys.
-        clear_database_but_keep_sequences()
-
     def import_export_then_validate(self) -> JSONData:
         return import_export_then_validate(self._testMethodName, reset_pks=False)
 

+ 42 - 0
tests/sentry/backup/test_release.py

@@ -0,0 +1,42 @@
+from __future__ import annotations
+
+from typing import Literal, Type
+
+from sentry.backup.helpers import get_exportable_final_derivations_of
+from sentry.db.models import BaseModel
+from sentry.testutils.helpers.backups import BackupTestCase
+from tests.sentry.backup import run_backup_tests_only_on_single_db, targets
+
+RELEASE_TESTED_MODELS = set()
+
+
+def mark(*marking: Type | Literal["__all__"]):
+    """A function that runs at module load time and marks all models that appear in
+    `test_at_head_...()` below.
+
+    Use the sentinel string "__all__" to indicate that all models are expected."""
+
+    all: Literal["__all__"] = "__all__"
+    for model in marking:
+        if model == all:
+            all_models = get_exportable_final_derivations_of(BaseModel)
+            RELEASE_TESTED_MODELS.update({c.__name__ for c in all_models})
+            return list(all_models)
+
+        RELEASE_TESTED_MODELS.add(model.__name__)
+    return marking
+
+
+@run_backup_tests_only_on_single_db
+class ReleaseTests(BackupTestCase):
+    """Ensure that the all Sentry models are still exportable."""
+
+    @targets(mark("__all__"))
+    def test_at_head_clean_pks(self):
+        self.create_exhaustive_instance(is_superadmin=True)
+        return self.import_export_then_validate(self._testMethodName, reset_pks=True)
+
+    @targets(mark("__all__"))
+    def test_at_head_dirty_pks(self):
+        self.create_exhaustive_instance(is_superadmin=True)
+        return self.import_export_then_validate(self._testMethodName, reset_pks=False)

+ 0 - 309
tests/sentry/backup/test_releases.py

@@ -1,309 +0,0 @@
-from __future__ import annotations
-
-from datetime import datetime, timedelta, timezone
-from typing import Literal, Type
-from uuid import uuid4
-
-from django.core.management import call_command
-from django.db import router
-from sentry_relay.auth import generate_key_pair
-
-from sentry.backup.helpers import get_exportable_final_derivations_of
-from sentry.db.models import BaseModel
-from sentry.incidents.models import (
-    IncidentActivity,
-    IncidentSnapshot,
-    IncidentSubscription,
-    IncidentTrigger,
-    PendingIncidentSnapshot,
-    TimeSeriesSnapshot,
-)
-from sentry.models.actor import ACTOR_TYPES, Actor
-from sentry.models.apiapplication import ApiApplication
-from sentry.models.apiauthorization import ApiAuthorization
-from sentry.models.apikey import ApiKey
-from sentry.models.apitoken import ApiToken
-from sentry.models.authenticator import Authenticator
-from sentry.models.authidentity import AuthIdentity
-from sentry.models.authprovider import AuthProvider
-from sentry.models.counter import Counter
-from sentry.models.dashboard import Dashboard, DashboardTombstone
-from sentry.models.dashboard_widget import (
-    DashboardWidget,
-    DashboardWidgetQuery,
-    DashboardWidgetTypes,
-)
-from sentry.models.email import Email
-from sentry.models.environment import EnvironmentProject
-from sentry.models.options.option import ControlOption, Option
-from sentry.models.options.organization_option import OrganizationOption
-from sentry.models.options.user_option import UserOption
-from sentry.models.organization import Organization
-from sentry.models.organizationaccessrequest import OrganizationAccessRequest
-from sentry.models.orgauthtoken import OrgAuthToken
-from sentry.models.projectownership import ProjectOwnership
-from sentry.models.projectredirect import ProjectRedirect
-from sentry.models.recentsearch import RecentSearch
-from sentry.models.relay import Relay, RelayUsage
-from sentry.models.repository import Repository
-from sentry.models.rule import RuleActivity, RuleActivityType
-from sentry.models.savedsearch import SavedSearch, Visibility
-from sentry.models.search_common import SearchType
-from sentry.models.servicehook import ServiceHook
-from sentry.models.userip import UserIP
-from sentry.models.userrole import UserRole, UserRoleUser
-from sentry.monitors.models import (
-    CheckInStatus,
-    Monitor,
-    MonitorCheckIn,
-    MonitorEnvironment,
-    MonitorLocation,
-    MonitorType,
-    ScheduleType,
-)
-from sentry.sentry_apps.apps import SentryAppUpdater
-from sentry.silo import unguarded_write
-from sentry.testutils.cases import TransactionTestCase
-from sentry.testutils.helpers.backups import import_export_then_validate
-from sentry.utils.json import JSONData
-from tests.sentry.backup import run_backup_tests_only_on_single_db, targets
-
-RELEASE_TESTED_MODELS = set()
-
-
-def mark(*marking: Type | Literal["__all__"]):
-    """A function that runs at module load time and marks all models that appear in
-    `test_at_head()` below.
-
-    Use the sentinel string "__all__" to indicate that all models are expected."""
-
-    all: Literal["__all__"] = "__all__"
-    for model in marking:
-        if model == all:
-            all_models = get_exportable_final_derivations_of(BaseModel)
-            RELEASE_TESTED_MODELS.update({c.__name__ for c in all_models})
-            return list(all_models)
-
-        RELEASE_TESTED_MODELS.add(model.__name__)
-    return marking
-
-
-@run_backup_tests_only_on_single_db
-class VersionCompatibilityTests(TransactionTestCase):
-    """Ensures that exports generated by prior releases can still be imported and re-exported by newer cuts of Sentry."""
-
-    def setUp(self):
-        with unguarded_write(using=router.db_for_write(Organization)):
-            # Reset the Django database.
-            call_command("flush", verbosity=0, interactive=False)
-
-    def import_export_then_validate(self) -> JSONData:
-        return import_export_then_validate(self._testMethodName)
-
-    @targets(mark("__all__"))
-    def test_at_head(self):
-        """Test that the currently checked in code passes a script that hits every `__include_in_export = True` model."""
-
-        # User*
-        user = self.create_user("user@example.com")
-        self.add_user_permission(user, "users.admin")
-        role = UserRole.objects.create(name="test-role")
-        UserRoleUser.objects.create(user=user, role=role)
-        UserOption.objects.create(user=user, key="timezone", value="Europe/Vienna")
-        UserIP.objects.create(
-            user=user,
-            ip_address="127.0.0.2",
-            first_seen=datetime(2012, 4, 5, 3, 29, 45, tzinfo=timezone.utc),
-            last_seen=datetime(2012, 4, 5, 3, 29, 45, tzinfo=timezone.utc),
-        )
-
-        # Organization*
-        org = self.create_organization(name="test_org", owner=user)
-        member = self.create_member(organization=org, user=self.user, role="member")
-        OrganizationOption.objects.create(
-            organization=org, key="sentry:account-rate-limit", value=0
-        )
-        OrgAuthToken.objects.create(
-            organization_id=org.id,
-            name="token 1",
-            token_hashed="ABCDEF",
-            token_last_characters="xyz1",
-            scope_list=["org:ci"],
-            date_last_used=None,
-        )
-
-        # SentryApp*
-        app = self.create_sentry_app(name="test_app", organization=org)
-        install = self.create_sentry_app_installation(slug=app.slug, organization=org, user=user)
-        updater = SentryAppUpdater(sentry_app=app)
-        updater.schema = {"elements": [self.create_alert_rule_action_schema()]}
-        updater.run(user)
-
-        # Api*
-        api_app = ApiApplication.objects.create(
-            name="test", owner=user, redirect_uris="http://example.com\nhttp://sub.example.com/path"
-        )
-        ApiAuthorization.objects.create(application=api_app, user=user)
-        ApiToken.objects.create(application=api_app, user=user, token=uuid4().hex, expires_at=None)
-        ApiKey.objects.create(key=uuid4().hex, organization_id=org.id)
-
-        # Auth*
-        Authenticator.objects.create(user=user, type=1)
-        AuthIdentity.objects.create(
-            user=user,
-            auth_provider=AuthProvider.objects.create(organization_id=1, provider="sentry"),
-            ident="123456789",
-            data={
-                "key1": "value1",
-                "key2": 42,
-                "key3": [1, 2, 3],
-                "key4": {"nested_key": "nested_value"},
-            },
-        )
-
-        # *Options
-        Option.objects.create(key="foo", value="a")
-        ControlOption.objects.create(key="bar", value="b")
-
-        # Team
-        team = self.create_team(name="test_team", organization=org)
-        self.create_team_membership(user=user, team=team)
-        OrganizationAccessRequest.objects.create(member=member, team=team)
-        actor = Actor.objects.create(type=ACTOR_TYPES["team"])
-
-        # Project*
-        project = self.create_project()
-        self.create_project_key(project)
-        self.create_project_bookmark(project=project, user=user)
-        project = self.create_project()
-        ProjectOwnership.objects.create(
-            project=project, raw='{"hello":"hello"}', schema={"hello": "hello"}
-        )
-        ProjectRedirect.record(project, "old_slug")
-
-        # ServiceHook
-        ServiceHook.objects.create(
-            application_id=app.id,
-            actor_id=actor.id,
-            project_id=project.id,
-            organization_id=org.id,
-            events=[],
-            installation_id=install.id,
-            url="https://example.com",
-        )
-
-        # Rule*
-        rule = self.create_project_rule(project=project)
-        RuleActivity.objects.create(rule=rule, type=RuleActivityType.CREATED.value)
-        self.snooze_rule(user_id=user.id, owner_id=user.id, rule=rule)
-
-        # Environment*
-        env = self.create_environment()
-        EnvironmentProject.objects.create(project=project, environment=env, is_hidden=False)
-
-        # Monitor*
-        monitor = Monitor.objects.create(
-            organization_id=project.organization.id,
-            project_id=project.id,
-            type=MonitorType.CRON_JOB,
-            config={"schedule": "* * * * *", "schedule_type": ScheduleType.CRONTAB},
-        )
-        mon_env = MonitorEnvironment.objects.create(
-            monitor=monitor,
-            environment=env,
-        )
-        location = MonitorLocation.objects.create(guid=uuid4(), name="test_location")
-        MonitorCheckIn.objects.create(
-            monitor=monitor,
-            monitor_environment=mon_env,
-            location=location,
-            project_id=monitor.project_id,
-            status=CheckInStatus.IN_PROGRESS,
-        )
-
-        # AlertRule*
-        alert = self.create_alert_rule(include_all_projects=True, excluded_projects=[project])
-        trigger = self.create_alert_rule_trigger(alert_rule=alert, excluded_projects=[self.project])
-        self.create_alert_rule_trigger_action(alert_rule_trigger=trigger)
-
-        # Incident*
-        incident = self.create_incident()
-        IncidentActivity.objects.create(
-            incident=incident,
-            type=1,
-            comment="hello",
-        )
-        IncidentSnapshot.objects.create(
-            incident=incident,
-            event_stats_snapshot=TimeSeriesSnapshot.objects.create(
-                start=datetime.utcnow() - timedelta(hours=24),
-                end=datetime.utcnow(),
-                values=[[1.0, 2.0, 3.0], [1.5, 2.5, 3.5]],
-                period=1,
-            ),
-            unique_users=1,
-            total_events=1,
-        )
-        IncidentSubscription.objects.create(incident=incident, user_id=user.id)
-        IncidentTrigger.objects.create(
-            incident=incident,
-            alert_rule_trigger=trigger,
-            status=1,
-        )
-
-        # *Snapshot
-        PendingIncidentSnapshot.objects.create(
-            incident=incident, target_run_date=datetime.utcnow() + timedelta(hours=4)
-        )
-        TimeSeriesSnapshot.objects.create(
-            start=datetime.utcnow() - timedelta(hours=24),
-            end=datetime.utcnow(),
-            values=[[1.0, 2.0, 3.0], [1.5, 2.5, 3.5]],
-            period=1,
-        )
-
-        # Relay*
-        _, public_key = generate_key_pair()
-        relay = str(uuid4())
-        Relay.objects.create(relay_id=relay, public_key=str(public_key), is_internal=True)
-        RelayUsage.objects.create(relay_id=relay, version="0.0.1", public_key=public_key)
-
-        # Dashboard
-        dashboard = Dashboard.objects.create(
-            title="Dashboard 1", created_by_id=user.id, organization=org
-        )
-        widget = DashboardWidget.objects.create(
-            dashboard=dashboard,
-            order=1,
-            title="Test Widget",
-            display_type=0,
-            widget_type=DashboardWidgetTypes.DISCOVER,
-        )
-        DashboardWidgetQuery.objects.create(widget=widget, order=1, name="Test Query")
-        DashboardTombstone.objects.create(organization=org, slug="test-tombstone")
-
-        # *Search
-        RecentSearch.objects.create(
-            organization=org,
-            user_id=user.id,
-            type=SearchType.ISSUE.value,
-            query="some query",
-        )
-        SavedSearch.objects.create(
-            organization=org,
-            name="Saved query",
-            query="saved query",
-            visibility=Visibility.ORGANIZATION,
-        )
-
-        # misc
-        Counter.increment(project, 1)
-        Email.objects.create(email="other@example.com")
-        self.create_notification_action(organization=org, projects=[project])
-        Repository.objects.create(
-            name="test_repo",
-            organization_id=org.id,
-            integration_id=self.integration.id,
-        )
-
-        return self.import_export_then_validate()

+ 0 - 0
tests/sentry/backup/test_correctness.py → tests/sentry/backup/test_validate.py