mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 19:26:48 +00:00
0001_initial to 0024_log_retention_setting are mostly RunPython steps that added, renamed, re-chose and described setting rows since 2020. A squashed migration now creates the table in its final shape and inserts the 38 rows those steps leave; it replaces all 24, so a new database runs it alone. The 24 stay beside it, as Django's squashing expects until every installation has applied them: a database that applied them all records the squashed one without running anything, and one that stopped between them (an older release, or an upstream installation) applies the rest of them first. Checked: - on a new database its rows equal the old chain's (name, key, value, choices, description of every row); - on a copy of a running panel's database (all 24 applied) migrate plans nothing for appsettings; - a database migrated by the old code to 0023 applies 0024 and then records the squashed migration, with the same 38 rows; - makemigrations finds no change. It inserts its rows on the database being migrated, as the replaced steps do. The tests of the replaced steps stay, since an installation that stopped between them still runs them; the two that checked a few rows' columns became one that checks every row's columns and description, and a value is one of its choices.
122 lines
6.2 KiB
Python
122 lines
6.2 KiB
Python
"""The settings rows: those a new database gets fit their columns (PostgreSQL
|
|
refuses a longer value, SQLite does not), say what they do, and hold one of
|
|
their choices. The steps the squashed migration replaces still run on an
|
|
installation that stopped between them: they repair its rows, and their
|
|
inserts do not collide with the fixed ids of the first ones."""
|
|
|
|
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"))
|
|
|
|
|
|
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
|
|
removed = {"VIEW_INSTANCE_DETAIL_BOTTOM_BAR"} # by 0023
|
|
for key, text in descriptions.DESCRIPTIONS.items():
|
|
with self.subTest(key=key):
|
|
self.assertLessEqual(len(text), limit)
|
|
if key not in removed:
|
|
self.assertEqual(AppSettings.objects.get(key=key).description, text)
|
|
self.assertFalse(AppSettings.objects.filter(key__in=removed).exists())
|
|
|
|
|
|
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"))
|
|
|
|
|
|
class SettingsRowsTestCase(TestCase):
|
|
def test_every_row_fits_its_columns_and_has_a_description(self):
|
|
for setting in AppSettings.objects.all():
|
|
with self.subTest(key=setting.key):
|
|
self.assertTrue(setting.description)
|
|
for field in ("name", "key", "value", "choices", "description"):
|
|
limit = AppSettings._meta.get_field(field).max_length
|
|
self.assertLessEqual(len(getattr(setting, field)), limit, field)
|
|
|
|
def test_a_setting_with_choices_holds_one_of_them(self):
|
|
for setting in AppSettings.objects.exclude(choices=""):
|
|
with self.subTest(key=setting.key):
|
|
self.assertIn(setting.value, setting.choices_as_list())
|
|
|
|
def test_the_choices_offer_only_what_the_panel_uses(self):
|
|
rows = {s.key: (s.value, s.choices) for s in AppSettings.objects.all()}
|
|
self.assertEqual(rows["INSTANCE_NIC_DEFAULT_TYPE"][1], "default,e1000,e1000e,rtl8139,virtio")
|
|
self.assertEqual(rows["INSTANCE_CPU_DEFAULT_MODE"], ("host-model", "host-model,host-passthrough,maximum"))
|
|
self.assertEqual(rows["INSTANCE_MACHINE_DEFAULT_TYPE"], ("q35", "q35,pc,virt"))
|
|
self.assertEqual(rows["INSTANCE_CDROM_ADD"], ("sata", "None,ide,sata,scsi"))
|
|
self.assertEqual(rows["CLONE_INSTANCE_DEFAULT_PREFIX"][1], "")
|