1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-11 12:46:49 +00:00

test: test files named by their topic, one file per topic

- console settings were split over four files; who sees the form, the
  listen address, and the settings themselves are test_console_settings,
  and who may open a console is test_console_access;
- the three template files are test_templates;
- the quota lock test joins test_quota;
- accounts' test_security_fixes held two topics: the SSH key tests are
  test_ssh_keys, the owner-row delete redirect is in test_views;
- instances' test_security_mutations, who may change a VM, is
  test_permissions.
The suite runs the same 2097 tests.
This commit is contained in:
catborise 2026-11-06 11:36:16 +03:00
parent bdc8a6755c
commit f3003bb414
15 changed files with 541 additions and 606 deletions

View file

@ -18,6 +18,10 @@ from libvirt import VIR_DOMAIN_PAUSED, VIR_DOMAIN_RUNNING
from operations.models import Operation
from vrtManager.util import OperationError
import socket
import threading
import time
from django.db import connection
from django.test import Client, TransactionTestCase, override_settings
def vm_reader(vcpu=2, memory=1024, disk_gib=10, pending=None):
@ -292,3 +296,58 @@ class QuotaWithDownHostTestCase(TestCase):
get_settings() # app settings are normally loaded by middleware
self.assertEqual(check_user_quota(user, 1, 1, 128, 1), QUOTA_UNVERIFIED)
QUOTA_CPUS = 4
# Sessions and messages in cookies: concurrent writes to the in-memory test
# database would fail for reasons unrelated to the quota race.
@override_settings(
SESSION_ENGINE="django.contrib.sessions.backends.signed_cookies",
MESSAGE_STORAGE="django.contrib.messages.storage.cookie.CookieStorage",
)
class QuotaRaceTestCase(TransactionTestCase):
"""Two concurrent resizes of one user's VMs must not both pass the quota."""
def setUp(self):
self.user = get_user_model().objects.create_user("quota_user", password="pw")
compute = Compute.objects.create(name="quota-compute", hostname="127.0.0.1", login="", password="", type=4)
self.vms = [
Instance.objects.create(compute=compute, name=f"quota-vm-{i}", uuid=f"1111111{i}-2222-3333-4444-555555555555")
for i in range(2)
]
for vm in self.vms:
UserInstance.objects.create(user=self.user, instance=vm, is_change=True)
self.allocated = 2 # two VMs with one vCPU each
def fake_quota(self, user, instance, cpu, memory, disk):
seen = self.allocated
time.sleep(0.3) # widen the window between the check and the change
return "cpu" if seen + cpu > QUOTA_CPUS else ""
def fake_resize(self, cur_vcpu, vcpu):
self.allocated += int(vcpu) - 1
def resize(self, vm):
client = Client()
client.force_login(self.user)
client.post(reverse("instances:resizevm_cpu", args=[vm.id]), {"vcpu": 3, "cur_vcpu": 3})
connection.close()
def test_second_concurrent_resize_is_refused(self):
with patch("instances.views.utils.check_user_quota", self.fake_quota), patch(
"instances.models.wvmInstance"
) as wvm:
wvm.return_value.get_vcpu.return_value = 1
wvm.return_value.instance.isActive.return_value = False # vCPUs change on a shut-off VM
wvm.return_value.resize_cpu.side_effect = self.fake_resize
threads = [threading.Thread(target=self.resize, args=(vm,)) for vm in self.vms]
for t in threads:
t.start()
for t in threads:
t.join()
self.assertEqual(wvm.return_value.resize_cpu.call_count, 1)
self.assertLessEqual(self.allocated, QUOTA_CPUS)