Files
nova/nova/tests/unit/api/openstack/compute/test_schemas.py
T
Stephen Finucane c382f036c3 tests: Ensure API schemas are valid
Validate the validation by validating our schemas against the JSON
Schema meta schema. This is an important first step in getting us
of JSON Schema Draft 4 and onto Draft 2019-09, which OpenAPI is a
superset of.

Change-Id: I3b5a05aa0aa058e92c6927c9e3bee3cdd4477f8f
Signed-off-by: Stephen Finucane <stephenfin@redhat.com>
2024-06-17 16:19:10 +00:00

123 lines
4.5 KiB
Python

# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import jsonschema.exceptions
from nova.api.openstack import compute
from nova.api.validation import validators
from nova import test
class SchemaTest(test.NoDBTestCase):
def setUp(self):
super().setUp()
self.router = compute.APIRouterV21()
self.meta_schema = validators._SchemaValidator.validator_org
def test_schemas(self):
missing_schemas = set()
invalid_schemas = set()
def _validate_func(func, method):
if method in ("POST", "PUT", "PATCH"):
# request body validation
if not hasattr(func, '_request_schema'):
missing_schemas.add(func.__qualname__)
else:
try:
self.meta_schema.check_schema(func._request_schema)
except jsonschema.exceptions.SchemaError:
invalid_schemas.add(func.__qualname__)
for route in self.router.map.matchlist:
if 'controller' not in route.defaults:
continue
controller = route.defaults['controller']
path = ""
for part in route.routelist:
if isinstance(part, dict):
path += "{" + part["name"] + "}"
else:
path += part
method = (
route.conditions.get("method", "GET")[0]
if route.conditions
else "GET"
)
action = route.defaults["action"]
if path.endswith('/action'):
# all actions should use POST
assert method == 'POST'
wsgi_actions = [
(k, v, controller.controller) for k, v in
controller.controller.wsgi_actions.items()
]
for sub_controller in controller.sub_controllers:
wsgi_actions += [
(k, v, sub_controller) for k, v in
sub_controller.wsgi_actions.items()
]
for (
wsgi_action, wsgi_method, action_controller
) in wsgi_actions:
func = controller.wsgi_actions[wsgi_action]
if hasattr(action_controller, 'versioned_methods'):
if wsgi_method in action_controller.versioned_methods:
# currently all our actions are unversioned and if
# this changes then we need to fix this
funcs = action_controller.versioned_methods[
wsgi_method
]
assert len(funcs) == 1
func = funcs[0].func
# method will always be POST for actions
_validate_func(func, method)
else:
# body validation
versioned_methods = getattr(
controller.controller, 'versioned_methods', {}
)
if action in versioned_methods:
# versioned method
for versioned_method in sorted(
versioned_methods[action],
key=lambda v: v.start_version
):
func = versioned_method.func
_validate_func(func, method)
else:
# unversioned method
func = getattr(controller.controller, action)
_validate_func(func, method)
if missing_schemas:
raise test.TestingException(
f"Found API resources without schemas: "
f"{sorted(missing_schemas)}"
)
if invalid_schemas:
raise test.TestingException(
f"Found API resources with invalid schemas: "
f"{sorted(invalid_schemas)}"
)