1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-08 19:26:48 +00:00
webvirtcloud/appsettings/tests/test_appsettings.py
catborise 07a2e09c2f docs(appsettings): each setting's description says what it does
The descriptions were tooltips, many only repeating the setting's name
("Cpu modes", "Debug for user quotas"). Now shown under each field, they
say what the setting changes: what a new VM or disk gets, how the
console starts, what a page shows. A migration writes them.
2026-10-25 22:02:53 +03:00

127 lines
6.9 KiB
Python

from django.contrib.messages import get_messages
from django.test import RequestFactory, TestCase
from django.urls import reverse
from appsettings.models import AppSettings
from appsettings.settings import app_settings, get_settings
class AppSettingsTestCase(TestCase):
def setUp(self):
self.client.login(request=RequestFactory().get("/"), username="admin", password="admin")
def test_get_settings_populates_singleton(self):
AppSettings.objects.update_or_create(
key="CUSTOM_TEST_SETTING",
defaults={"value": "test_value_123", "name": "Custom Test Setting"}
)
get_settings()
self.assertEqual(getattr(app_settings, "CUSTOM_TEST_SETTING", None), "test_value_123")
def test_appsettings_view_get(self):
response = self.client.get(reverse("appsettings"))
self.assertEqual(response.status_code, 200)
def test_appsettings_update_setting(self):
setting = AppSettings.objects.get(key="SHOW_ACCESS_ROOT_PASSWORD")
original_value = setting.value
new_val = "False" if original_value == "True" else "True"
response = self.client.post(
reverse("appsettings"),
{
"SHOW_ACCESS_ROOT_PASSWORD": new_val
}
)
self.assertRedirects(response, reverse("appsettings"))
setting.refresh_from_db()
self.assertEqual(setting.value, new_val)
def test_appsettings_non_superuser_forbidden(self):
from django.contrib.auth.models import User
regular_user = User.objects.create_user(username="regular", password="pwd")
self.client.force_login(regular_user)
response = self.client.get(reverse("appsettings"))
self.assertEqual(response.status_code, 403)
def test_clones_are_not_migrated_automatically(self):
# a clone stays on the host of the VM it was made from; the setting
# that sent it to a random host is removed by migration 0015
self.assertFalse(AppSettings.objects.filter(key="CLONE_INSTANCE_AUTO_MIGRATE").exists())
def test_worker_settings_refuse_values_out_of_bounds(self):
response = self.client.post(reverse("appsettings"), {"WORKER_CONCURRENCY": "0"})
self.assertEqual(AppSettings.objects.get(key="WORKER_CONCURRENCY").value, "4")
self.assertTrue(any("between 1 and 16" in str(m) for m in get_messages(response.wsgi_request)))
def post(self, key, value):
response = self.client.post(reverse("appsettings"), {key: value})
return [str(m) for m in get_messages(response.wsgi_request)]
def test_a_listed_setting_takes_only_its_choices(self):
messages = self.post("INSTANCE_FIRMWARE_DEFAULT_TYPE", "Coreboot")
self.assertEqual(AppSettings.objects.get(key="INSTANCE_FIRMWARE_DEFAULT_TYPE").value, "BIOS")
self.assertTrue(any("BIOS, UEFI" in m for m in messages), messages)
def test_number_settings_take_whole_numbers_in_their_range(self):
# read with int() elsewhere: a letter would break the logs page or VM create
for key, bad, good in (("LOGS_PER_PAGE", "abc", "50"), ("LOGS_PER_PAGE", "0", "1000"),
("INSTANCE_VOLUME_DEFAULT_OWNER_UID", "-1", "107"),
("INSTANCE_VOLUME_DEFAULT_OWNER_GID", "x", "4294967294"),
("LOGIN_FAILURE_LIMIT", "0", "10"), ("SNAPSHOT_FREE_SPACE_PERCENT", "101", "0")):
with self.subTest(key=key, bad=bad):
before = AppSettings.objects.get(key=key).value
self.assertTrue(any("whole number" in m for m in self.post(key, bad)))
self.assertEqual(AppSettings.objects.get(key=key).value, before)
self.post(key, good)
self.assertEqual(AppSettings.objects.get(key=key).value, good)
def test_the_clone_name_prefix_is_text(self):
self.post("CLONE_INSTANCE_DEFAULT_PREFIX", "web-")
self.assertEqual(AppSettings.objects.get(key="CLONE_INSTANCE_DEFAULT_PREFIX").value, "web-")
page = self.client.get(reverse("appsettings")).content.decode()
self.assertIn('name="CLONE_INSTANCE_DEFAULT_PREFIX" value="web-"', page)
def page(self):
from lxml import html
return html.fromstring(self.client.get(reverse("appsettings")).content)
def test_settings_are_grouped_with_their_descriptions_shown(self):
page = self.page()
titles = [h.text_content().strip() for h in page.xpath("//form//h2")]
self.assertEqual(titles[:3], ["New VM defaults", "Disks", "Clones"])
# every setting is in one group, with a label tied to its field and its description shown
keys = page.xpath("//form//*[self::input or self::select][@name and @name!='csrfmiddlewaretoken']/@name")
names = set(AppSettings.objects.exclude(key="BOOTSTRAP_THEME").values_list("key", flat=True))
self.assertEqual(sorted(k for k in keys if k not in ("BOOTSTRAP_THEME", "language")), sorted(names))
(field,) = page.xpath("//*[@name='LOGS_PER_PAGE']")
self.assertEqual((field.get("type"), field.get("min"), field.get("max")), ("number", "1", "1000"))
self.assertEqual(page.xpath(f"//label[@for='{field.get('id')}']/text()"), ["Logs per Page"])
self.assertEqual(page.xpath(f"//*[@id='{field.get('aria-describedby')}']/text()"), ["Rows per page on the Logs page"])
# a group is saved with its button, not on every change
self.assertEqual(page.xpath("//*[@onchange]"), [])
def test_a_group_saves_its_changed_settings_only(self):
from logs.models import Logs
Logs.objects.all().delete()
response = self.client.post(reverse("appsettings"), {
"CONSOLE_SCALE": "True", "CONSOLE_VIEW_ONLY": "False",
"CONSOLE_RESIZE_SESSION": "False", "CONSOLE_CLIP_VIEWPORT": "True"})
self.assertRedirects(response, reverse("appsettings"))
values = dict(AppSettings.objects.filter(key__startswith="CONSOLE_").values_list("key", "value"))
self.assertEqual(values, {"CONSOLE_SCALE": "True", "CONSOLE_VIEW_ONLY": "False",
"CONSOLE_RESIZE_SESSION": "False", "CONSOLE_CLIP_VIEWPORT": "True"})
self.assertEqual(sorted(Logs.objects.values_list("message", flat=True)),
["Setting Console Clip Viewport: change to True", "Setting Console Scale: change to True"])
self.assertEqual([str(m) for m in get_messages(response.wsgi_request)],
["Saved: Console Clip Viewport, Console Scale"])
def test_one_bad_value_saves_nothing_of_its_group(self):
response = self.client.post(reverse("appsettings"), {"LOGIN_FAILURE_LIMIT": "10", "LOGIN_LOCKOUT_MINUTES": "x"})
self.assertEqual(AppSettings.objects.get(key="LOGIN_FAILURE_LIMIT").value, "5")
self.assertEqual([str(m) for m in get_messages(response.wsgi_request)],
["Login Lockout Minutes must be a whole number between 1 and 10080"])