1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-08 11:16:47 +00:00
webvirtcloud/instances/tests/test_moved_while_waiting.py
2026-10-15 09:28:43 +03:00

71 lines
3.3 KiB
Python

"""
A migration may move a VM between a request reading it and taking its
compute's claim: the request then holds the old compute's claim, not the
new one's. It must not run on the new host but answer "moved, try again",
and the retry claims the right compute.
"""
from contextlib import contextmanager
from unittest.mock import PropertyMock, patch
from django.contrib.auth import get_user_model
from django.test import TestCase
from django.urls import reverse
from computes.models import Compute
from instances.models import Instance
class MovedWhileWaitingTestCase(TestCase):
def setUp(self):
self.admin = get_user_model().objects.create_superuser("moved_admin", "m@example.com", "x")
self.source = Compute.objects.create(name="src", hostname="192.0.2.1", login="root", password="", type=1)
self.target = Compute.objects.create(name="dst", hostname="192.0.2.2", login="root", password="", type=1)
self.vm = Instance.objects.create(
compute=self.source, name="moved-vm", uuid="eeeeeeee-ffff-0000-1111-222222222222"
)
self.client.force_login(self.admin)
def poweroff(self, lock):
with patch("instances.views.libvirt_instance_lock", lock), patch(
"instances.models.wvmInstance"
) as wvm, patch.object(Compute, "status", new_callable=PropertyMock, return_value=True):
response = self.client.post(reverse("instances:poweroff", args=[self.vm.id]))
return response, wvm.return_value.shutdown.called
def test_a_vm_moved_while_the_request_waited_is_not_touched(self):
@contextmanager
def lock_after_a_migration(instance):
# the migration that held the lock moved the VM before releasing it
Instance.objects.filter(pk=instance.pk).update(compute=self.target)
yield
response, touched = self.poweroff(lock_after_a_migration)
self.assertFalse(touched)
self.assertEqual(response.status_code, 302)
messages = [str(m) for m in response.wsgi_request._messages]
self.assertIn("The VM was moved meanwhile; try again.", messages)
def test_a_vm_that_stayed_is_changed(self):
@contextmanager
def plain_lock(instance):
yield
response, touched = self.poweroff(plain_lock)
self.assertTrue(touched)
def test_destroy_of_a_vm_moved_while_it_waited_is_not_run(self):
# destroy holds the whole compute; the migration moved the VM before
# releasing it
@contextmanager
def compute_lock_after_a_migration(compute, *, shared=False):
Instance.objects.filter(pk=self.vm.pk).update(compute=self.target)
yield
with patch("instances.views.libvirt_compute_lock", compute_lock_after_a_migration), patch(
"instances.models.wvmInstance"
) as wvm, patch.object(Compute, "status", new_callable=PropertyMock, return_value=True):
response = self.client.post(reverse("instances:destroy", args=[self.vm.id]), {"delete_disk": "on"})
self.assertFalse(wvm.return_value.delete.called)
self.assertTrue(Instance.objects.filter(pk=self.vm.pk).exists())
messages = [str(m) for m in response.wsgi_request._messages]
self.assertIn("The VM was moved meanwhile; try again.", messages)