mirror of
https://github.com/hanzoai/sentinel.git
synced 2026-09-29 22:34:33 +00:00
352 lines
15 KiB
Python
352 lines
15 KiB
Python
from unittest.mock import MagicMock, Mock, patch
|
|
from uuid import uuid4
|
|
|
|
import pytest
|
|
|
|
from sentry.models.relocation import Relocation
|
|
from sentry.testutils.cases import TestCase
|
|
from sentry.utils.relocation import (
|
|
OrderedTask,
|
|
fail_relocation,
|
|
retry_task_or_fail_relocation,
|
|
start_relocation_task,
|
|
)
|
|
|
|
|
|
class RelocationUtilsTestCase(TestCase):
|
|
def setUp(self):
|
|
super().setUp()
|
|
self.owner = self.create_user(
|
|
email="owner", is_superuser=False, is_staff=False, is_active=True
|
|
)
|
|
self.superuser = self.create_user(
|
|
"superuser", is_superuser=True, is_staff=True, is_active=True
|
|
)
|
|
self.relocation: Relocation = Relocation.objects.create(
|
|
creator_id=self.superuser.id,
|
|
owner_id=self.owner.id,
|
|
want_org_slugs=["testing"],
|
|
step=Relocation.Step.UPLOADING.value,
|
|
)
|
|
self.uuid = self.relocation.uuid
|
|
|
|
def mock_message_builder(self, fake_message_builder: Mock):
|
|
fake_message_builder.return_value.send_async.return_value = MagicMock()
|
|
|
|
|
|
@patch("sentry.utils.relocation.MessageBuilder")
|
|
class RelocationStartTestCase(RelocationUtilsTestCase):
|
|
def test_bad_relocation_not_found(self, fake_message_builder: Mock):
|
|
self.mock_message_builder(fake_message_builder)
|
|
|
|
uuid = uuid4().hex
|
|
(rel, attempts_left) = start_relocation_task(uuid, OrderedTask.UPLOADING_COMPLETE, 3)
|
|
|
|
assert fake_message_builder.call_count == 0
|
|
|
|
assert rel is None
|
|
assert not attempts_left
|
|
|
|
def test_bad_relocation_completed(self, fake_message_builder: Mock):
|
|
self.mock_message_builder(fake_message_builder)
|
|
|
|
self.relocation.status = Relocation.Status.FAILURE.value
|
|
self.relocation.save()
|
|
|
|
(rel, attempts_left) = start_relocation_task(self.uuid, OrderedTask.UPLOADING_COMPLETE, 3)
|
|
|
|
assert fake_message_builder.call_count == 0
|
|
|
|
assert rel is None
|
|
assert not attempts_left
|
|
assert Relocation.objects.get(uuid=self.uuid).status == Relocation.Status.FAILURE.value
|
|
|
|
def test_bad_unknown_task(self, fake_message_builder: Mock):
|
|
self.mock_message_builder(fake_message_builder)
|
|
|
|
(rel, attempts_left) = start_relocation_task(self.uuid, OrderedTask.NONE, 3)
|
|
|
|
assert fake_message_builder.call_count == 1
|
|
assert fake_message_builder.call_args.kwargs["type"] == "relocation.failed"
|
|
fake_message_builder.return_value.send_async.assert_called_once_with(
|
|
to=[self.owner.email, self.superuser.email]
|
|
)
|
|
|
|
assert rel is None
|
|
assert not attempts_left
|
|
assert Relocation.objects.get(uuid=self.uuid).status == Relocation.Status.FAILURE.value
|
|
|
|
def test_bad_task_out_of_order(self, fake_message_builder: Mock):
|
|
self.mock_message_builder(fake_message_builder)
|
|
|
|
self.relocation.latest_task = OrderedTask.PREPROCESSING_SCAN.name
|
|
self.relocation.save()
|
|
|
|
(rel, attempts_left) = start_relocation_task(self.uuid, OrderedTask.UPLOADING_COMPLETE, 3)
|
|
|
|
assert fake_message_builder.call_count == 1
|
|
assert fake_message_builder.call_args.kwargs["type"] == "relocation.failed"
|
|
fake_message_builder.return_value.send_async.assert_called_once_with(
|
|
to=[self.owner.email, self.superuser.email]
|
|
)
|
|
|
|
assert rel is None
|
|
assert not attempts_left
|
|
assert Relocation.objects.get(uuid=self.uuid).status == Relocation.Status.FAILURE.value
|
|
|
|
def test_good_first_task(self, fake_message_builder: Mock):
|
|
self.mock_message_builder(fake_message_builder)
|
|
|
|
(rel, attempts_left) = start_relocation_task(self.uuid, OrderedTask.UPLOADING_COMPLETE, 3)
|
|
|
|
assert fake_message_builder.call_count == 0
|
|
assert attempts_left == 2
|
|
|
|
relocation: Relocation = Relocation.objects.get(uuid=self.uuid)
|
|
assert relocation.step == Relocation.Step.UPLOADING.value
|
|
assert relocation.status != Relocation.Status.FAILURE.value
|
|
|
|
def test_good_next_task(self, fake_message_builder: Mock):
|
|
self.mock_message_builder(fake_message_builder)
|
|
|
|
self.relocation.latest_task = OrderedTask.UPLOADING_COMPLETE.name
|
|
self.relocation.save()
|
|
|
|
(rel, attempts_left) = start_relocation_task(self.uuid, OrderedTask.PREPROCESSING_SCAN, 3)
|
|
|
|
assert fake_message_builder.call_count == 0
|
|
assert attempts_left == 2
|
|
|
|
relocation: Relocation = Relocation.objects.get(uuid=self.uuid)
|
|
assert relocation.step == Relocation.Step.PREPROCESSING.value
|
|
assert relocation.status != Relocation.Status.FAILURE.value
|
|
|
|
def test_good_pause_at_scheduled_pause(self, fake_message_builder: Mock):
|
|
self.mock_message_builder(fake_message_builder)
|
|
|
|
self.relocation.latest_task = OrderedTask.UPLOADING_COMPLETE.name
|
|
self.relocation.scheduled_pause_at_step = Relocation.Step.PREPROCESSING.value
|
|
self.relocation.save()
|
|
|
|
(rel, attempts_left) = start_relocation_task(self.uuid, OrderedTask.PREPROCESSING_SCAN, 3)
|
|
|
|
assert fake_message_builder.call_count == 0
|
|
assert attempts_left == 0
|
|
|
|
relocation: Relocation = Relocation.objects.get(uuid=self.uuid)
|
|
assert relocation.step == Relocation.Step.PREPROCESSING.value
|
|
assert relocation.latest_task == OrderedTask.PREPROCESSING_SCAN.name
|
|
assert relocation.status == Relocation.Status.PAUSE.value
|
|
assert relocation.scheduled_pause_at_step is None
|
|
|
|
def test_good_already_paused(self, fake_message_builder: Mock):
|
|
self.mock_message_builder(fake_message_builder)
|
|
|
|
self.relocation.latest_task = OrderedTask.UPLOADING_COMPLETE.name
|
|
self.relocation.status = Relocation.Status.PAUSE.value
|
|
self.relocation.save()
|
|
|
|
(rel, attempts_left) = start_relocation_task(self.uuid, OrderedTask.UPLOADING_COMPLETE, 3)
|
|
|
|
assert fake_message_builder.call_count == 0
|
|
assert attempts_left == 0
|
|
|
|
relocation: Relocation = Relocation.objects.get(uuid=self.uuid)
|
|
assert relocation.step == Relocation.Step.UPLOADING.value
|
|
assert relocation.latest_task == OrderedTask.UPLOADING_COMPLETE.name
|
|
assert relocation.status == Relocation.Status.PAUSE.value
|
|
assert relocation.scheduled_pause_at_step is None
|
|
|
|
def test_good_cancel_at_scheduled_cancel(self, fake_message_builder: Mock):
|
|
self.mock_message_builder(fake_message_builder)
|
|
|
|
self.relocation.latest_task = OrderedTask.UPLOADING_COMPLETE.name
|
|
self.relocation.scheduled_cancel_at_step = Relocation.Step.PREPROCESSING.value
|
|
self.relocation.save()
|
|
|
|
(_, attempts_left) = start_relocation_task(self.uuid, OrderedTask.PREPROCESSING_SCAN, 3)
|
|
|
|
assert fake_message_builder.call_count == 0
|
|
assert attempts_left == 0
|
|
|
|
relocation: Relocation = Relocation.objects.get(uuid=self.uuid)
|
|
assert relocation.step == Relocation.Step.PREPROCESSING.value
|
|
assert relocation.latest_task == OrderedTask.PREPROCESSING_SCAN.name
|
|
assert relocation.status == Relocation.Status.FAILURE.value
|
|
assert relocation.scheduled_cancel_at_step is None
|
|
assert relocation.failure_reason == "This relocation was cancelled by an administrator."
|
|
|
|
def test_good_already_cancelled(self, fake_message_builder: Mock):
|
|
self.mock_message_builder(fake_message_builder)
|
|
|
|
self.relocation.step = Relocation.Step.POSTPROCESSING.value
|
|
self.relocation.latest_task = OrderedTask.POSTPROCESSING.name
|
|
self.relocation.status = Relocation.Status.FAILURE.value
|
|
self.relocation.failure_reason = "Cancelled"
|
|
self.relocation.save()
|
|
|
|
(_, attempts_left) = start_relocation_task(self.uuid, OrderedTask.POSTPROCESSING, 3)
|
|
|
|
assert fake_message_builder.call_count == 0
|
|
assert attempts_left == 0
|
|
|
|
relocation: Relocation = Relocation.objects.get(uuid=self.uuid)
|
|
assert relocation.step == Relocation.Step.POSTPROCESSING.value
|
|
assert relocation.latest_task == OrderedTask.POSTPROCESSING.name
|
|
assert relocation.status == Relocation.Status.FAILURE.value
|
|
assert relocation.scheduled_cancel_at_step is None
|
|
assert self.relocation.failure_reason == "Cancelled"
|
|
|
|
def test_good_cancel_before_pause(self, fake_message_builder: Mock):
|
|
self.mock_message_builder(fake_message_builder)
|
|
|
|
self.relocation.latest_task = OrderedTask.UPLOADING_COMPLETE.name
|
|
self.relocation.scheduled_cancel_at_step = Relocation.Step.PREPROCESSING.value
|
|
self.relocation.scheduled_pause_at_step = Relocation.Step.PREPROCESSING.value
|
|
self.relocation.save()
|
|
|
|
(_, attempts_left) = start_relocation_task(self.uuid, OrderedTask.PREPROCESSING_SCAN, 3)
|
|
|
|
assert fake_message_builder.call_count == 0
|
|
assert attempts_left == 0
|
|
|
|
relocation: Relocation = Relocation.objects.get(uuid=self.uuid)
|
|
assert relocation.step == Relocation.Step.PREPROCESSING.value
|
|
assert relocation.latest_task == OrderedTask.PREPROCESSING_SCAN.name
|
|
assert relocation.status == Relocation.Status.FAILURE.value
|
|
assert relocation.scheduled_pause_at_step is None
|
|
assert relocation.scheduled_cancel_at_step is None
|
|
assert relocation.failure_reason == "This relocation was cancelled by an administrator."
|
|
|
|
def test_good_pause_before_cancel(self, fake_message_builder: Mock):
|
|
self.mock_message_builder(fake_message_builder)
|
|
|
|
self.relocation.latest_task = OrderedTask.UPLOADING_COMPLETE.name
|
|
self.relocation.scheduled_cancel_at_step = Relocation.Step.POSTPROCESSING.value
|
|
self.relocation.scheduled_pause_at_step = Relocation.Step.PREPROCESSING.value
|
|
self.relocation.save()
|
|
|
|
(_, attempts_left) = start_relocation_task(self.uuid, OrderedTask.PREPROCESSING_SCAN, 3)
|
|
|
|
assert fake_message_builder.call_count == 0
|
|
assert attempts_left == 0
|
|
|
|
relocation: Relocation = Relocation.objects.get(uuid=self.uuid)
|
|
assert relocation.step == Relocation.Step.PREPROCESSING.value
|
|
assert relocation.latest_task == OrderedTask.PREPROCESSING_SCAN.name
|
|
assert relocation.status == Relocation.Status.PAUSE.value
|
|
assert relocation.scheduled_pause_at_step is None
|
|
assert relocation.scheduled_cancel_at_step == Relocation.Step.POSTPROCESSING.value
|
|
assert relocation.failure_reason is None
|
|
|
|
|
|
@patch("sentry.utils.relocation.MessageBuilder")
|
|
class RelocationFailTestCase(RelocationUtilsTestCase):
|
|
def test_no_reason(self, fake_message_builder: Mock):
|
|
self.mock_message_builder(fake_message_builder)
|
|
|
|
fail_relocation(self.relocation, OrderedTask.UPLOADING_COMPLETE)
|
|
|
|
assert fake_message_builder.call_count == 1
|
|
assert fake_message_builder.call_args.kwargs["type"] == "relocation.failed"
|
|
fake_message_builder.return_value.send_async.assert_called_once_with(
|
|
to=[self.owner.email, self.superuser.email]
|
|
)
|
|
|
|
relocation: Relocation = Relocation.objects.get(uuid=self.uuid)
|
|
assert relocation.status == Relocation.Status.FAILURE.value
|
|
assert relocation.latest_notified == Relocation.EmailKind.FAILED.value
|
|
assert not relocation.failure_reason
|
|
|
|
def test_with_reason(self, fake_message_builder: Mock):
|
|
self.mock_message_builder(fake_message_builder)
|
|
|
|
fail_relocation(self.relocation, OrderedTask.UPLOADING_COMPLETE, "foo")
|
|
|
|
assert fake_message_builder.call_count == 1
|
|
assert fake_message_builder.call_args.kwargs["type"] == "relocation.failed"
|
|
fake_message_builder.return_value.send_async.assert_called_once_with(
|
|
to=[self.owner.email, self.superuser.email]
|
|
)
|
|
|
|
relocation: Relocation = Relocation.objects.get(uuid=self.uuid)
|
|
assert relocation.status == Relocation.Status.FAILURE.value
|
|
assert relocation.latest_notified == Relocation.EmailKind.FAILED.value
|
|
assert relocation.failure_reason == "foo"
|
|
|
|
|
|
@patch("sentry.utils.relocation.MessageBuilder")
|
|
class RelocationRetryOrFailTestCase(RelocationUtilsTestCase):
|
|
def test_no_reason_attempts_left(self, fake_message_builder: Mock):
|
|
self.mock_message_builder(fake_message_builder)
|
|
|
|
with pytest.raises(ValueError):
|
|
with retry_task_or_fail_relocation(self.relocation, OrderedTask.UPLOADING_COMPLETE, 3):
|
|
raise ValueError("Some sort of failure")
|
|
|
|
assert fake_message_builder.call_count == 0
|
|
|
|
relocation: Relocation = Relocation.objects.get(uuid=self.uuid)
|
|
assert relocation.status == Relocation.Status.IN_PROGRESS.value
|
|
assert relocation.latest_notified != Relocation.EmailKind.FAILED.value
|
|
assert not relocation.failure_reason
|
|
|
|
def test_no_reason_last_attempt(self, fake_message_builder: Mock):
|
|
self.mock_message_builder(fake_message_builder)
|
|
|
|
# Wrap in `try/except` to make mypy happy.
|
|
try:
|
|
with retry_task_or_fail_relocation(self.relocation, OrderedTask.UPLOADING_COMPLETE, 0):
|
|
raise ValueError("Some sort of failure")
|
|
except Exception:
|
|
pass
|
|
|
|
assert fake_message_builder.call_count == 1
|
|
assert fake_message_builder.call_args.kwargs["type"] == "relocation.failed"
|
|
fake_message_builder.return_value.send_async.assert_called_once_with(
|
|
to=[self.owner.email, self.superuser.email]
|
|
)
|
|
|
|
relocation: Relocation = Relocation.objects.get(uuid=self.uuid)
|
|
assert relocation.status == Relocation.Status.FAILURE.value
|
|
assert relocation.latest_notified == Relocation.EmailKind.FAILED.value
|
|
|
|
def test_with_reason_attempts_left(self, fake_message_builder: Mock):
|
|
self.mock_message_builder(fake_message_builder)
|
|
|
|
with pytest.raises(ValueError):
|
|
with retry_task_or_fail_relocation(
|
|
self.relocation, OrderedTask.UPLOADING_COMPLETE, 3, "foo"
|
|
):
|
|
raise ValueError("Some sort of failure")
|
|
|
|
assert fake_message_builder.call_count == 0
|
|
|
|
relocation: Relocation = Relocation.objects.get(uuid=self.uuid)
|
|
assert relocation.status == Relocation.Status.IN_PROGRESS.value
|
|
assert relocation.latest_notified != Relocation.EmailKind.FAILED.value
|
|
assert not relocation.failure_reason
|
|
|
|
def test_with_reason_last_attempt(self, fake_message_builder: Mock):
|
|
self.mock_message_builder(fake_message_builder)
|
|
|
|
# Wrap in `try/except` to make mypy happy.
|
|
try:
|
|
with retry_task_or_fail_relocation(
|
|
self.relocation, OrderedTask.UPLOADING_COMPLETE, 0, "foo"
|
|
):
|
|
raise ValueError("Some sort of failure")
|
|
except Exception:
|
|
pass
|
|
|
|
assert fake_message_builder.call_count == 1
|
|
assert fake_message_builder.call_args.kwargs["type"] == "relocation.failed"
|
|
fake_message_builder.return_value.send_async.assert_called_once_with(
|
|
to=[self.owner.email, self.superuser.email]
|
|
)
|
|
|
|
relocation: Relocation = Relocation.objects.get(uuid=self.uuid)
|
|
assert relocation.status == Relocation.Status.FAILURE.value
|
|
assert relocation.latest_notified == Relocation.EmailKind.FAILED.value
|
|
assert relocation.failure_reason == "foo"
|