1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-08 19:26:48 +00:00

test(instances): make the live libvirt suite runnable on real hosts

- Pick the test VM by name; .first() could select any VM already on
  the compute, and tearDownClass deletes the chosen VM's disks.
- Delete the test volume when setUpClass fails after creating it.
- test-vm.xml: no hard-coded emulator, machine alias q35 instead of
  pc-q35-5.1, so it defines on RHEL qemu-kvm hosts too.
- Follow current behavior: power actions are POST-only, the create
  form needs add_cdrom/add_input and VNC, cloning needs change
  permission on the source VM.
- README: the tests read TEST_LIBVIRT_HOST/TYPE/LOGIN/PASSWORD;
  WEBVIRTCLOUD_TEST_LIBVIRT_URI never existed.
This commit is contained in:
catborise 2026-10-03 13:27:47 +03:00
parent 964b58778d
commit 88ec3c5f6a
3 changed files with 25 additions and 15 deletions

View file

@ -445,9 +445,10 @@ ruff check .
```
> **Live Hypervisor Testing (Optional):**
> To run tests against a live libvirt host instead of standalone mocks, set the `WEBVIRTCLOUD_TEST_LIBVIRT_URI` environment variable before running tests:
> Without these variables the live tests use the local socket (`qemu:///system`) or are skipped. They create and delete `test*` VMs and volumes in the host's `default` pool.
> ```bash
> export WEBVIRTCLOUD_TEST_LIBVIRT_URI="qemu+ssh://root@compute1/system"
> export TEST_LIBVIRT_HOST=compute1 TEST_LIBVIRT_TYPE=2 # 1 TCP, 2 SSH, 3 TLS, 4 socket
> export TEST_LIBVIRT_LOGIN=root TEST_LIBVIRT_PASSWORD= # login/password for TCP and TLS
> python manage.py test
> ```

View file

@ -5,7 +5,7 @@
<currentMemory unit="KiB">131072</currentMemory>
<vcpu placement="static">1</vcpu>
<os>
<type arch="x86_64" machine="pc-q35-5.1">hvm</type>
<type arch="x86_64" machine="q35">hvm</type>
<boot dev="hd" />
<boot dev="cdrom" />
<bootmenu enable="yes" />
@ -20,7 +20,6 @@
<on_reboot>restart</on_reboot>
<on_crash>restart</on_crash>
<devices>
<emulator>/usr/bin/qemu-system-x86_64</emulator>
<disk type="file" device="disk">
<driver name="qemu" type="qcow2" cache="directsync" />
<source file="/var/lib/libvirt/images/test-volume.qcow2" />

View file

@ -61,7 +61,8 @@ class InstancesTestCase(TestCase):
)
# Add disks for testing
cls.connection.create_volume(
cls.volume_path = None
cls.volume_path = cls.connection.create_volume(
"default",
"test-volume",
1,
@ -77,9 +78,15 @@ class InstancesTestCase(TestCase):
# Create testing vm from XML
cls.connection._defineXML(cls.xml)
refr(cls.compute)
cls.instance: Instance = Instance.objects.filter(compute=cls.compute).first()
# The compute may hold other VMs; never pick one of them.
cls.instance: Instance = Instance.objects.get(compute=cls.compute, name="test-vm")
except Exception as e:
cls.instance = None
if getattr(cls, "volume_path", None):
try:
cls.connection.get_volume_by_path(cls.volume_path).delete(0)
except Exception:
pass
if getattr(cls, "compute", None):
try:
cls.compute.delete()
@ -174,12 +181,14 @@ class InstancesTestCase(TestCase):
"network-control": "default",
"cache_mode": "directsync",
"nwfilter": "",
"graphics": "spice",
"graphics": "vnc",
"video": "vga",
"listener_addr": "0.0.0.0",
"console_pass": "",
"qemu_ga": False,
"virtio": True,
"add_cdrom": "None",
"add_input": "None",
"create": True,
},
)
@ -687,7 +696,8 @@ class InstancesTestCase(TestCase):
# test for non admin user with quotas
instance_count = Instance.objects.count()
UserInstance.objects.create(user=self.test_user, instance=self.instance)
# Cloning needs change permission on the source VM
UserInstance.objects.create(user=self.test_user, instance=self.instance, is_change=True)
self.client.force_login(self.test_user)
@ -811,7 +821,7 @@ class InstancesTestCase(TestCase):
self.instance.is_template = True
self.instance.save()
response = self.client.get(
response = self.client.post(
reverse("instances:poweron", args=[self.instance.id]),
HTTP_REFERER=reverse("index"),
)
@ -827,7 +837,7 @@ class InstancesTestCase(TestCase):
# poweron
self.assertEqual(self.instance.status, 5)
response = self.client.get(
response = self.client.post(
reverse("instances:poweron", args=[self.instance.id]),
HTTP_REFERER=reverse("index"),
)
@ -838,7 +848,7 @@ class InstancesTestCase(TestCase):
self.assertEqual(self.instance.status, 1)
# suspend
response = self.client.get(
response = self.client.post(
reverse("instances:suspend", args=[self.instance.id]),
HTTP_REFERER=reverse("index"),
)
@ -848,7 +858,7 @@ class InstancesTestCase(TestCase):
self.assertEqual(self.instance.status, 3)
# resume
response = self.client.get(
response = self.client.post(
reverse("instances:resume", args=[self.instance.id]),
HTTP_REFERER=reverse("index"),
)
@ -858,7 +868,7 @@ class InstancesTestCase(TestCase):
self.assertEqual(self.instance.status, 1)
# poweroff
response = self.client.get(
response = self.client.post(
reverse("instances:poweroff", args=[self.instance.id]),
HTTP_REFERER=reverse("index"),
)
@ -869,7 +879,7 @@ class InstancesTestCase(TestCase):
self.assertEqual(self.instance.status, 1)
# powercycle
response = self.client.get(
response = self.client.post(
reverse("instances:powercycle", args=[self.instance.id]),
HTTP_REFERER=reverse("index"),
)
@ -879,7 +889,7 @@ class InstancesTestCase(TestCase):
self.assertEqual(self.instance.status, 1)
# force_off
response = self.client.get(
response = self.client.post(
reverse("instances:force_off", args=[self.instance.id]),
HTTP_REFERER=reverse("index"),
)