Files
sentinel/tests/sentry/tasks/test_backfill_outboxes.py
2024-02-15 17:01:50 +00:00

183 lines
6.8 KiB
Python

from unittest.mock import patch
from django.apps import apps
from django.test.utils import override_settings
from sentry.db.models import BaseModel
from sentry.db.models.outboxes import run_outbox_replications_for_self_hosted
from sentry.models.authidentity import AuthIdentity
from sentry.models.authidentityreplica import AuthIdentityReplica
from sentry.models.authprovider import AuthProvider
from sentry.models.authproviderreplica import AuthProviderReplica
from sentry.models.organization import Organization
from sentry.models.organizationmapping import OrganizationMapping
from sentry.models.outbox import ControlOutbox, RegionOutbox, outbox_context
from sentry.silo import SiloMode
from sentry.tasks.backfill_outboxes import (
backfill_outboxes_for,
get_backfill_key,
get_processing_state,
process_outbox_backfill_batch,
)
from sentry.testutils.factories import Factories
from sentry.testutils.helpers import override_options
from sentry.testutils.outbox import outbox_runner
from sentry.testutils.pytest.fixtures import django_db_all
from sentry.testutils.silo import (
assume_test_silo_mode,
control_silo_test,
no_silo_test,
region_silo_test,
)
from sentry.utils import redis
def reset_processing_state():
with redis.clusters.get("default").get_local_client_for_key("backfill_outboxes") as client:
for app_models in apps.all_models.values():
for model in app_models.values():
client.delete(get_backfill_key(model._meta.db_table))
@django_db_all
@no_silo_test
def test_processing_awaits_options():
reset_processing_state()
org = Factories.create_organization()
with outbox_context(flush=False):
AuthProvider.objects.create(organization_id=org.id, provider="meethub", config={})
assert not backfill_outboxes_for(SiloMode.CONTROL, 0, 1)
with override_options(
{
"outbox_replication.sentry_authprovider.replication_version": AuthProvider.replication_version
}
):
assert backfill_outboxes_for(SiloMode.CONTROL, 0, 1)
assert not backfill_outboxes_for(SiloMode.REGION, 0, 1)
with override_options(
{
"outbox_replication.sentry_organization.replication_version": Organization.replication_version
}
):
assert backfill_outboxes_for(SiloMode.REGION, 0, 1)
@django_db_all
@region_silo_test
def test_region_processing(task_runner):
with outbox_context(flush=False):
for i in range(5):
Factories.create_organization()
RegionOutbox.objects.all().delete()
with outbox_runner(), task_runner():
while backfill_outboxes_for(SiloMode.REGION, 0, 1, force_synchronous=True):
pass
assert RegionOutbox.objects.all().count() == 5
assert RegionOutbox.objects.all().count() == 0
with assume_test_silo_mode(SiloMode.CONTROL):
assert OrganizationMapping.objects.all().count() == 5
@django_db_all
@control_silo_test
def test_control_processing(task_runner):
reset_processing_state()
org = Factories.create_organization()
with outbox_context(flush=False):
ap = AuthProvider.objects.create(organization_id=org.id, provider="meethub", config={})
for i in range(5):
user = Factories.create_user()
AuthIdentity.objects.create(user=user, auth_provider=ap, ident=str(i), data={})
# Clear existing outboxes, force replication by hand
ControlOutbox.objects.all().delete()
assert not ControlOutbox.objects.all().exists()
with assume_test_silo_mode(SiloMode.REGION):
assert not AuthProviderReplica.objects.filter(auth_provider_id=ap.id).exists()
assert not AuthIdentityReplica.objects.filter(auth_provider_id=ap.id).exists()
def run_for_model(model: type[BaseModel]):
while True:
if process_outbox_backfill_batch(model, 1, force_synchronous=True) is None:
break
with task_runner():
run_for_model(AuthIdentity)
run_for_model(AuthProvider)
assert (
get_processing_state(AuthIdentity._meta.db_table)[1] == AuthIdentity.replication_version + 1
)
with outbox_runner():
assert ControlOutbox.objects.all().count() == 6
with assume_test_silo_mode(SiloMode.REGION):
assert not AuthProviderReplica.objects.filter(auth_provider_id=ap.id).exists()
assert not AuthIdentityReplica.objects.filter(auth_provider_id=ap.id).exists()
with assume_test_silo_mode(SiloMode.REGION):
assert AuthProviderReplica.objects.filter(auth_provider_id=ap.id).exists()
assert AuthIdentityReplica.objects.filter(auth_provider_id=ap.id).count() == 5
with outbox_context(flush=False):
org2 = Factories.create_organization()
ap2 = AuthProvider.objects.create(organization_id=org2.id, provider="meethub", config={})
for i in range(5):
user = Factories.create_user()
AuthIdentity.objects.create(user=user, auth_provider=ap2, ident=str(i), data={})
# Clear again
ControlOutbox.objects.all().delete()
with assume_test_silo_mode(SiloMode.REGION):
assert AuthIdentityReplica.objects.filter(auth_provider_id=ap2.id).count() == 0
with outbox_runner(), task_runner():
while backfill_outboxes_for(SiloMode.CONTROL, 0, 1, force_synchronous=True):
pass
assert OrganizationMapping.objects.all().count() == 2
# Does not process these new objects since we already completed all available work for this version.
with assume_test_silo_mode(SiloMode.REGION):
assert AuthIdentityReplica.objects.filter(auth_provider_id=ap2.id).count() == 0
AuthIdentityReplica.objects.all().delete()
with patch("sentry.models.authidentity.AuthIdentity.replication_version", new=10000):
with outbox_runner(), task_runner():
while backfill_outboxes_for(SiloMode.CONTROL, 0, 1, force_synchronous=True):
pass
# Replicates it now that the version has bumped
with assume_test_silo_mode(SiloMode.REGION):
assert AuthIdentityReplica.objects.all().count() == 10
assert AuthIdentityReplica.objects.filter(auth_provider_id=ap2.id).count() == 5
assert AuthIdentityReplica.objects.filter(auth_provider_id=ap.id).count() == 5
assert get_processing_state(AuthIdentity._meta.db_table)[1] == 10001
@django_db_all
@no_silo_test
def test_run_outbox_replications_for_self_hosted():
reset_processing_state()
with outbox_context(flush=False):
org = Factories.create_organization()
AuthProvider.objects.create(organization_id=org.id, provider="meethub", config={})
ControlOutbox.objects.all().delete()
RegionOutbox.objects.all().delete()
with override_settings(SENTRY_SELF_HOSTED=True):
run_outbox_replications_for_self_hosted()
assert AuthProviderReplica.objects.count() == 1
assert OrganizationMapping.objects.count() == 1