mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 11:16:47 +00:00
- The search read a row's whole text, so a word on a button or in a state label matched every row. VM rows now carry data-search (the name, title and owners, and the host in the flat list), and table_filter.js searches that text when a row has it; the state has its own filter. - Nothing matching left an empty table. table_filter.js shows the page's #no-match while no row does; the VM list's says so and offers "Clear the filters". A user with no VMs at all is told so instead of an empty table. - The grouped list's "#" toggled each host on its own: a host collapsed by hand opened while the others closed. It now collapses every host, or opens them all once all are collapsed. - One alert names every host the panel cannot reach, with why, in place of one dismissible alert per host; users who see no hosts keep their own message. - A host's VM list showed a VM's maximum memory, the Instances page its current memory: both show the current memory now. - The owners' users are prefetched with the VMs; the flat list's Bootstrap 4 font-italic is fst-italic.
87 lines
3.5 KiB
Python
87 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):
|
|
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, "2048 MiB", 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
|
|
# the VM's current memory, as on the Instances page, not its maximum
|
|
self.assert_one_info_per_vm(self.get(reverse("instances", args=[self.compute.id])))
|