1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-08 19:26:48 +00:00
webvirtcloud/appsettings/tests/test_migrations.py
catborise 2e1f29961c fix(instances): a new VM's CPU is a mode or a model the host offers, checked by libvirt
- A named CPU model is written without check='none' and with
  fallback='forbid': libvirt checks before the start that the host runs
  it, and it is not swapped for another model.
- Mode maximum is written as that mode; it was written as a model named
  maximum.
- Model names up to 64 characters: the -noTSX and -IBRS models, the ones a
  mixed set of hosts needs, were refused at 20.
- The mode or model is checked against the host's capabilities when the VM
  is defined, from the page and the API alike; no CPU element (QEMU's
  oldest default CPU) is no longer offered.
- The default CPU mode setting offers the modes the new VM dialog has;
  no-model and custom, which matched none of them, become host-model.
2026-10-29 11:17:38 +03:00

115 lines
5.5 KiB
Python

"""The default settings rows of the first migrations carry fixed ids, which a
PostgreSQL id sequence does not see. A later migration that inserts without
an id must not collide with them."""
import importlib
import unittest
from types import SimpleNamespace
from django.apps import apps
from django.db import connection
from django.test import TestCase, TransactionTestCase
from appsettings.models import AppSettings
login_lockout = importlib.import_module("appsettings.migrations.0014_login_lockout_settings")
@unittest.skipUnless(connection.vendor == "postgresql", "id sequences are a PostgreSQL concern")
class SequenceAfterFixedIdsTestCase(TransactionTestCase):
serialized_rollback = True
def test_login_lockout_settings_insert_after_fixed_ids(self):
with connection.schema_editor() as schema_editor:
login_lockout.del_settings(apps, schema_editor)
# the state after the fixed-id inserts: rows exist, the sequence starts at 1
with connection.cursor() as cursor:
cursor.execute("SELECT setval(pg_get_serial_sequence('appsettings_appsettings', 'id'), 1, false)")
login_lockout.add_settings(apps, schema_editor)
self.assertEqual(AppSettings.objects.filter(key__startswith="LOGIN_").count(), 2)
nic_type = importlib.import_module("appsettings.migrations.0016_nic_type_rtl8139")
class NicTypeTestCase(TestCase):
def test_the_misspelt_nic_type_becomes_rtl8139(self):
setting = AppSettings.objects.get(key="INSTANCE_NIC_DEFAULT_TYPE")
self.assertEqual(setting.choices, "default,e1000,e1000e,rtl8139,virtio")
AppSettings.objects.filter(pk=setting.pk).update(value="rt18139", choices="default,e1000,e1000e,rt18139,virtio")
nic_type.fix_rtl8139(apps, SimpleNamespace(connection=connection))
setting.refresh_from_db()
self.assertEqual((setting.value, setting.choices), ("rtl8139", "default,e1000,e1000e,rtl8139,virtio"))
class SnapshotFreeSpaceSettingsTestCase(TestCase):
def test_the_rows_fit_their_columns(self):
# PostgreSQL refuses a value longer than the column, sqlite does not
for key in ("SNAPSHOT_FREE_SPACE_PERCENT", "SNAPSHOT_FREE_SPACE_MIN_GIB"):
setting = AppSettings.objects.get(key=key)
for field in ("name", "key", "value", "description"):
limit = AppSettings._meta.get_field(field).max_length
if limit:
self.assertLessEqual(len(getattr(setting, field)), limit, f"{key} {field}")
class WorkerSettingsTestCase(TestCase):
def test_the_rows_fit_their_columns(self):
for key in ("WORKER_CONCURRENCY", "JOB_RETENTION_DAYS"):
setting = AppSettings.objects.get(key=key)
for field in ("name", "key", "value", "description"):
limit = AppSettings._meta.get_field(field).max_length
if limit:
self.assertLessEqual(len(getattr(setting, field)), limit, f"{key} {field}")
choices_fix = importlib.import_module("appsettings.migrations.0020_fix_setting_choices")
class ChoicesFixTestCase(TestCase):
"""Choices that offered values the panel cannot use, and a text setting
that showed as a True/False list."""
def test_the_broken_choices_are_fixed_and_their_values_moved(self):
broken = {
"CLONE_INSTANCE_DEFAULT_PREFIX": ("instance", "True,False"),
"INSTANCE_VOLUME_DEFAULT_SCSI_CONTROLLER": ("virtio-blk", "virtio-scsi, lsilogic, virtio-blk"),
"INSTANCE_MACHINE_DEFAULT_TYPE": ("x86_64", "q35,x86_64,virt"),
"INSTANCE_CDROM_ADD": ("virtio", "None,ide,sata,scsi,virtio"),
}
for key, (value, choices) in broken.items():
AppSettings.objects.filter(key=key).update(value=value, choices=choices)
choices_fix.fix_choices(apps, SimpleNamespace(connection=connection))
fixed = {s.key: (s.value, s.choices) for s in AppSettings.objects.filter(key__in=broken)}
self.assertEqual(fixed, {
"CLONE_INSTANCE_DEFAULT_PREFIX": ("instance", ""),
"INSTANCE_VOLUME_DEFAULT_SCSI_CONTROLLER": ("virtio-scsi", "virtio-scsi,lsilogic"),
"INSTANCE_MACHINE_DEFAULT_TYPE": ("q35", "q35,pc,virt"),
"INSTANCE_CDROM_ADD": ("sata", "None,ide,sata,scsi"),
})
descriptions = importlib.import_module("appsettings.migrations.0021_setting_descriptions")
class DescriptionsTestCase(TestCase):
def test_every_setting_says_what_it_does_within_its_column(self):
limit = AppSettings._meta.get_field("description").max_length
for key, text in descriptions.DESCRIPTIONS.items():
with self.subTest(key=key):
self.assertLessEqual(len(text), limit)
self.assertEqual(AppSettings.objects.get(key=key).description, text)
cpu_mode = importlib.import_module("appsettings.migrations.0022_cpu_mode_choices")
class CpuModeChoicesTestCase(TestCase):
def test_the_default_cpu_mode_is_one_the_new_vm_dialog_offers(self):
for old, new in (("no-model", "host-model"), ("custom", "host-model"), ("host-passthrough", "host-passthrough")):
with self.subTest(old=old):
AppSettings.objects.filter(key="INSTANCE_CPU_DEFAULT_MODE").update(
value=old, choices="no-model,host-model,host-passthrough,custom")
cpu_mode.fix_cpu_mode(apps, SimpleNamespace(connection=connection))
setting = AppSettings.objects.get(key="INSTANCE_CPU_DEFAULT_MODE")
self.assertEqual((setting.value, setting.choices), (new, "host-model,host-passthrough,maximum"))