1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-10 04:06:47 +00:00
webvirtcloud/instances/tests/test_migration_bookkeeping.py
2026-10-16 07:57:02 +03:00

80 lines
3.9 KiB
Python

"""What migrate_instance does around the migration itself: it records a
finished migration even when autostart fails."""
import re
from pathlib import Path
from unittest.mock import MagicMock, patch
from accounts.models import UserInstance
from computes.models import Compute
from django.conf import settings
from django.contrib.auth import get_user_model
from django.db import DatabaseError
from django.test import TestCase
from logs.models import Logs
from instances.models import Instance
from instances.utils import MIGRATION_TIME_LIMIT, migrate_instance
from vrtManager import util
class MigrationBookkeepingTests(TestCase):
def setUp(self):
self.admin = get_user_model().objects.create_superuser("mb-admin", "mb@example.com", "pw")
self.source = Compute.objects.create(name="mb-src", hostname="198.51.100.8", login="root", password="", type=2)
self.dest = Compute.objects.create(name="mb-dst", hostname="198.51.100.9", login="root", password="", type=2)
self.vm = Instance.objects.create(compute=self.source, name="vm", uuid="u-mb", is_template=True)
def migrate(self, vm=None, up=True, autostart=False, autostart_error=None):
proxy = MagicMock()
proxy.get_autostart.return_value = autostart
with patch.object(Compute, "status", up), \
patch("instances.utils.wvmInstances") as instances, \
patch("instances.utils.wvmInstance") as instance, \
patch.object(Instance, "proxy", proxy):
instances.return_value.moveto.return_value = "live"
if autostart_error:
instance.return_value.set_autostart.side_effect = autostart_error
self.moveto = instances.return_value.moveto
self.set_autostart = instance.return_value.set_autostart
return migrate_instance(self.dest, vm or self.vm, self.admin, live=True)
def test_autostart_is_read_from_libvirt_and_restored_on_the_destination(self):
self.vm.__dict__["autostart"] = False # an earlier, cached read
self.migrate(autostart=True)
self.set_autostart.assert_called_once_with(1)
def test_a_failed_autostart_does_not_stop_the_records(self):
self.migrate(autostart=True, autostart_error=util.OperationError("no autostart"))
self.assertEqual(Instance.objects.get(id=self.vm.id).compute, self.dest)
self.assertEqual(
Logs.objects.get().message,
"Instance is migrated(live) to 198.51.100.9; setting its autostart there failed: no autostart",
)
def test_a_failed_record_is_logged_as_such(self):
with patch.object(Instance, "save", side_effect=DatabaseError("locked")), \
self.assertRaises(DatabaseError):
self.migrate()
self.assertEqual(
Logs.objects.get().message,
"Instance is migrated(live) to 198.51.100.9, but recording it failed: locked",
)
def test_a_record_the_destination_already_has_keeps_template_and_owners(self):
owner = get_user_model().objects.create_user("mb-owner")
UserInstance.objects.create(user=owner, instance=self.vm, is_change=True)
found = Instance.objects.create(compute=self.dest, name="vm", uuid="u-mb") # listed there meanwhile
old_id = self.vm.id
self.migrate()
self.assertFalse(Instance.objects.filter(id=old_id).exists())
found.refresh_from_db()
self.assertTrue(found.is_template)
self.assertEqual(UserInstance.objects.get(user=owner).instance_id, found.id)
def test_a_migration_is_cancelled_before_the_web_server_ends_the_request(self):
self.migrate()
self.assertEqual(self.moveto.call_args.kwargs["timeout"], MIGRATION_TIME_LIMIT)
gunicorn = (Path(settings.BASE_DIR) / "gunicorn.conf.py").read_text()
request_timeout = int(re.search(r"^timeout = (\d+)", gunicorn, re.M).group(1))
self.assertLess(MIGRATION_TIME_LIMIT, request_timeout - 30) # time to answer and log