1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-08 11:16:47 +00:00
webvirtcloud/instances/tests/test_api_parity.py
catborise 8d7f28482f fix(api): VM API answers as the VM pages do
- A VM delete reads delete_disk and delete_nvram as booleans from a JSON
  or form body. The view read them as HTML checkboxes from the form body
  only: JSON {"delete_disk": true} kept the disks while reporting success,
  and a form "delete_disk=false" deleted them. Refused options stop
  nothing; the API schema names both options.
- Power on and power cycle of a template answer 409 instead of reporting a
  start that did not happen.
- The VM details leave out the host's ISO images for non-superusers, as
  the VM page does; reading them also refreshed every pool of the host.
- Flavors take values of at least 1, as the web form does, and show their
  id for later changes; a migration needs neither live nor offline; a VM
  create on an unknown compute answers 404 instead of 500.
2026-10-26 17:47:18 +03:00

62 lines
3.2 KiB
Python

"""The VM API answers as its web pages do: a template is not started, the
host's ISO images are a superuser's, flavors and migrations take what the
web forms take."""
from unittest.mock import patch
from accounts.models import UserInstance
from computes.models import Compute
from django.contrib.auth import get_user_model
from django.test import TestCase
from instances.api.serializers import InstanceDetailsSerializer, MigrateSerializer
from instances.models import Flavor, Instance
class ApiParityTests(TestCase):
def setUp(self):
self.user = get_user_model().objects.create_user("api-owner", password="pw")
self.admin = get_user_model().objects.create_superuser("api-admin", "api@example.com", "pw")
self.compute = Compute.objects.create(name="api-host", hostname="192.0.2.30", login="u", password="p", type=1)
self.vm = Instance.objects.create(compute=self.compute, name="api-vm", uuid="31313131-0000-0000-0000-000000000000",
is_template=True)
UserInstance.objects.create(user=self.user, instance=self.vm)
self.url = f"/api/v1/computes/{self.compute.id}/instances/{self.vm.id}/"
def test_a_template_is_not_started(self):
self.client.force_login(self.user)
with patch("instances.models.wvmInstance") as wvm:
for action in ("poweron", "powercycle"):
with self.subTest(action=action):
self.assertEqual(self.client.post(self.url + f"{action}/").status_code, 409)
wvm.return_value.start.assert_not_called()
def test_the_hosts_iso_images_are_a_superusers(self):
class Request:
def __init__(self, user):
self.user = user
for user, shown in ((self.user, False), (self.admin, True)):
fields = InstanceDetailsSerializer(self.vm, context={"request": Request(user)}).fields
self.assertEqual("media_iso" in fields, shown, user)
def test_a_flavor_is_at_least_one_of_each_and_has_its_id(self):
self.client.force_login(self.admin)
response = self.client.post("/api/v1/flavor/", {"label": "zero", "memory": 0, "vcpu": -1, "disk": 0},
content_type="application/json")
self.assertEqual(set(response.json()), {"memory", "vcpu", "disk"})
flavor = Flavor.objects.create(label="one", memory=1024, vcpu=1, disk=10)
self.assertEqual(self.client.get(f"/api/v1/flavor/{flavor.id}/").json()["id"], flavor.id)
def test_a_migration_needs_neither_live_nor_offline(self):
other = Compute.objects.create(name="api-host-2", hostname="192.0.2.31", login="u", password="p", type=1)
data = {"instance": self.vm.id, "target_compute": other.id, "submission_key": "k" * 12}
serializer = MigrateSerializer(data=data)
self.assertTrue(serializer.is_valid(), serializer.errors)
self.assertEqual((serializer.validated_data["live"], serializer.validated_data["offline"]), (True, False))
def test_a_vm_on_an_unknown_compute_is_not_found(self):
from django.http import Http404
from instances.jobs import CreateInstance
with self.assertRaises(Http404):
CreateInstance().validate(self.admin, {"compute": 999999})