1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-08 19:26:48 +00:00
webvirtcloud/instances/test_list_rpc.py
catborise a57290cdf2 fix(instances): the new-VM dialog shows each host's current CPU load
The CPU bar showed the average since the host booted, read for every
compute on every load of the VM list. The dialog now reads each compute's
graph endpoint (load over one second) when it opens, two computes at a
time so the reads hold at most two workers, and ignores answers of an
earlier opening. A host that cannot be read shows a dash. The since-boot
reading had no other caller and is removed.
2026-10-10 20:54:19 +03:00

86 lines
3.5 KiB
Python

"""Instance lists ask libvirt for a VM's info once per row."""
from types import SimpleNamespace
from unittest.mock import PropertyMock, patch
from appsettings.models import AppSettings
from computes.models import Compute
from django.contrib.auth import get_user_model
from django.test import TestCase
from django.urls import reverse
from instances.models import Instance
# virDomainGetInfo: state, max memory KiB, memory KiB, vCPUs, CPU time
INFO = [1, 4194304, 2097152, 3, 0]
class FakeDomain:
# a plain class: Django templates do not call MagicMock attributes
def __init__(self):
self.info_calls = 0
self.xml_calls = 0
def info(self):
self.info_calls += 1
return INFO
def XMLDesc(self, flags=0):
self.xml_calls += 1
return "<domain><title></title><currentMemory>2097152</currentMemory></domain>"
class ListInfoCallTests(TestCase):
def setUp(self):
self.client.force_login(
get_user_model().objects.create_superuser(username="rpc-admin", password="pwd", email="rpc@example.com")
)
self.compute = Compute.objects.create(name="rpc-compute", hostname="localhost", type=4, login="", password="")
Instance.objects.create(compute=self.compute, name="vm-a", uuid="11111111-1111-1111-1111-111111111111")
Instance.objects.create(compute=self.compute, name="vm-b", uuid="22222222-2222-2222-2222-222222222222")
self.domains = []
def proxy(self, *args, **kwargs):
domain = FakeDomain()
self.domains.append(domain)
return SimpleNamespace(
instance=domain,
get_uuid=lambda: "uuid",
get_title=lambda: domain.XMLDesc() and "",
get_cur_memory=lambda: int(domain.XMLDesc().split(">")[4].split("<")[0]) // 1024,
)
def get(self, url):
compute_patches = {"status": True, "cpu_count": 1, "ram_size": 1024, "ram_usage": 0}
with patch("instances.views.utils.refr"), patch("computes.views.utils.refresh_instance_database"), patch(
"instances.models.wvmInstance", side_effect=self.proxy
):
patches = [patch.object(Compute, k, new_callable=PropertyMock, return_value=v) for k, v in compute_patches.items()]
for p in patches:
p.start()
try:
response = self.client.get(url)
finally:
for p in patches:
p.stop()
self.assertEqual(response.status_code, 200)
return response
def assert_one_info_per_vm(self, response, memory="2048 MB"):
self.assertEqual(len(self.domains), 2, "one proxy per VM row")
for domain in self.domains:
self.assertEqual(domain.info_calls, 1)
self.assertEqual(domain.xml_calls, 1, "only the title reads the XML")
self.assertContains(response, memory, count=2)
self.assertContains(response, "Active")
def test_nongrouped_index(self):
AppSettings.objects.filter(key="VIEW_INSTANCES_LIST_STYLE").update(value="nongrouped")
self.assert_one_info_per_vm(self.get(reverse("instances:index")))
def test_grouped_index(self):
AppSettings.objects.filter(key="VIEW_INSTANCES_LIST_STYLE").update(value="grouped")
self.assert_one_info_per_vm(self.get(reverse("instances:index")))
def test_compute_instances(self):
# this page shows the maximum memory, as before
self.assert_one_info_per_vm(self.get(reverse("instances", args=[self.compute.id])), memory="4096 MiB")