mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 19:26:48 +00:00
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.
86 lines
3.5 KiB
Python
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")
|