Merge "[validation] Use jsonschema validator in Context plugins"

This commit is contained in:
Jenkins 2017-04-06 13:04:47 +00:00 committed by Gerrit Code Review
commit f29c5538a2
10 changed files with 205 additions and 282 deletions

View File

@ -12,13 +12,37 @@
import random import random
from rally.common.i18n import _, _LE from rally.common.i18n import _
from rally.common import validation
from rally import consts from rally import consts
from rally import exceptions from rally import exceptions
from rally import osclients from rally import osclients
from rally.task import context from rally.task import context
@validation.configure("check_api_versions")
class CheckOpenStackAPIVersionsValidator(validation.Validator):
"""Additional validation for api_versions context"""
def validate(self, credentials, config, plugin_cls, plugin_cfg):
for client in plugin_cfg:
client_cls = osclients.OSClient.get(client)
try:
if ("service_type" in plugin_cfg[client] or
"service_name" in plugin_cfg[client]):
client_cls.is_service_type_configurable()
if "version" in plugin_cfg[client]:
client_cls.validate_version(plugin_cfg[client]["version"])
except exceptions.RallyException as e:
return self.fail(
"Invalid settings for '%(client)s': %(error)s" % {
"client": client,
"error": e.format_message()})
@validation.add("check_api_versions")
@context.configure(name="api_versions", order=150) @context.configure(name="api_versions", order=150)
class OpenStackAPIVersions(context.Context): class OpenStackAPIVersions(context.Context):
"""Context for specifying OpenStack clients versions and service types. """Context for specifying OpenStack clients versions and service types.
@ -157,30 +181,49 @@ class OpenStackAPIVersions(context.Context):
} }
""" """
VERSION_SCHEMA = {
"anyOf": [
{"type": "string", "description": "a string-like version."},
{"type": "number", "description": "a number-like version."}
]
}
CONFIG_SCHEMA = { CONFIG_SCHEMA = {
"type": "object", "type": "object",
"$schema": consts.JSON_SCHEMA, "$schema": consts.JSON_SCHEMA,
"patternProperties": { "patternProperties": {
"^[a-z]+$": { "^[a-z]+$": {
"type": "object", "type": "object",
"properties": { "oneOf": [
"version": { {
"anyOf": [{"type": "string", "description": "version only",
"description": "a string-like version."}, "properties": {
{"type": "number", "version": VERSION_SCHEMA,
"description": "a number-like version."}] },
"required": ["version"],
"additionalProperties": False
}, },
"service_name": { {
"type": "string" "description": "version and service_name",
"properties": {
"version": VERSION_SCHEMA,
"service_name": {"type": "string"}
},
"required": ["service_name"],
"additionalProperties": False
}, },
"service_type": { {
"type": "string" "description": "version and service_type",
"properties": {
"version": VERSION_SCHEMA,
"service_type": {"type": "string"}
},
"required": ["service_type"],
"additionalProperties": False
} }
}, ],
"additionalProperties": False
} }
}, },
"minProperties": 1,
"additionalProperties": False "additionalProperties": False
} }
@ -219,27 +262,3 @@ class OpenStackAPIVersions(context.Context):
def cleanup(self): def cleanup(self):
# nothing to do here # nothing to do here
pass pass
@classmethod
def validate(cls, config):
super(OpenStackAPIVersions, cls).validate(config)
for client in config:
client_cls = osclients.OSClient.get(client)
if ("service_type" in config[client] and
"service_name" in config[client]):
raise exceptions.ValidationError(_LE(
"Setting both 'service_type' and 'service_name' properties"
" is restricted."))
try:
if ("service_type" in config[client] or
"service_name" in config[client]):
client_cls.is_service_type_configurable()
if "version" in config[client]:
client_cls.validate_version(config[client]["version"])
except exceptions.RallyException as e:
raise exceptions.ValidationError(
_LE("Invalid settings for '%(client)s': %(error)s") % {
"client": client,
"error": e.format_message()})

View File

@ -17,6 +17,7 @@ import sys
from rally.common.i18n import _ from rally.common.i18n import _
from rally.common import logging from rally.common import logging
from rally.common import validation
from rally.plugins.openstack.cleanup import manager from rally.plugins.openstack.cleanup import manager
from rally.plugins.openstack.context.cleanup import base from rally.plugins.openstack.context.cleanup import base
from rally.plugins.openstack import scenario from rally.plugins.openstack import scenario
@ -26,23 +27,12 @@ from rally.task import context
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@validation.add(name="check_cleanup_resources", admin_required=True)
# NOTE(amaretskiy): Set order to run this just before UserCleanup # NOTE(amaretskiy): Set order to run this just before UserCleanup
@context.configure(name="admin_cleanup", order=(sys.maxsize - 1), hidden=True) @context.configure(name="admin_cleanup", order=(sys.maxsize - 1), hidden=True)
class AdminCleanup(base.CleanupMixin, context.Context): class AdminCleanup(base.CleanupMixin, context.Context):
"""Context class for admin resources cleanup.""" """Context class for admin resources cleanup."""
@classmethod
def validate(cls, config):
super(AdminCleanup, cls).validate(config)
missing = set(config)
missing -= manager.list_resource_names(admin_required=True)
missing = ", ".join(missing)
if missing:
LOG.info(_("Couldn't find cleanup resource managers: %s")
% missing)
raise base.NoSuchCleanupResources(missing)
@logging.log_task_wrapper(LOG.info, _("admin resources cleanup")) @logging.log_task_wrapper(LOG.info, _("admin resources cleanup"))
def cleanup(self): def cleanup(self):
manager.cleanup( manager.cleanup(

View File

@ -13,13 +13,27 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from rally.common.i18n import _ from rally.common import validation
from rally import consts from rally import consts
from rally import exceptions from rally.plugins.openstack.cleanup import manager
class NoSuchCleanupResources(exceptions.RallyException): @validation.configure("check_cleanup_resources")
msg_fmt = _("Missing cleanup resource managers: %(message)s") class CheckCleanupResourcesValidator(validation.Validator):
"""Validates that openstack resource managers exist"""
def __init__(self, admin_required):
super(CheckCleanupResourcesValidator, self).__init__()
self.admin_required = admin_required
def validate(self, credentials, config, plugin_cls, plugin_cfg):
missing = set(plugin_cfg)
missing -= manager.list_resource_names(
admin_required=self.admin_required)
missing = ", ".join(missing)
if missing:
return self.fail(
"Couldn't find cleanup resource managers: %s" % missing)
class CleanupMixin(object): class CleanupMixin(object):

View File

@ -17,6 +17,7 @@ import sys
from rally.common.i18n import _ from rally.common.i18n import _
from rally.common import logging from rally.common import logging
from rally.common import validation
from rally.plugins.openstack.cleanup import manager from rally.plugins.openstack.cleanup import manager
from rally.plugins.openstack.context.cleanup import base from rally.plugins.openstack.context.cleanup import base
from rally.plugins.openstack import scenario from rally.plugins.openstack import scenario
@ -26,23 +27,12 @@ from rally.task import context
LOG = logging.getLogger(__name__) LOG = logging.getLogger(__name__)
@validation.add(name="check_cleanup_resources", admin_required=False)
# NOTE(amaretskiy): Set maximum order to run this last # NOTE(amaretskiy): Set maximum order to run this last
@context.configure(name="cleanup", order=sys.maxsize, hidden=True) @context.configure(name="cleanup", order=sys.maxsize, hidden=True)
class UserCleanup(base.CleanupMixin, context.Context): class UserCleanup(base.CleanupMixin, context.Context):
"""Context class for user resources cleanup.""" """Context class for user resources cleanup."""
@classmethod
def validate(cls, config):
super(UserCleanup, cls).validate(config)
missing = set(config)
missing -= manager.list_resource_names(admin_required=False)
missing = ", ".join(missing)
if missing:
LOG.info(_("Couldn't find cleanup resource managers: %s")
% missing)
raise base.NoSuchCleanupResources(missing)
@logging.log_task_wrapper(LOG.info, _("user resources cleanup")) @logging.log_task_wrapper(LOG.info, _("user resources cleanup"))
def cleanup(self): def cleanup(self):
manager.cleanup( manager.cleanup(

View File

@ -15,10 +15,10 @@
import copy import copy
import ddt import ddt
import jsonschema
import mock import mock
from rally.plugins.openstack.context.cinder import volumes from rally.plugins.openstack.context.cinder import volumes
from rally.task import context
from tests.unit import test from tests.unit import test
CTX = "rally.plugins.openstack.context" CTX = "rally.plugins.openstack.context"
@ -50,16 +50,15 @@ class VolumeGeneratorTestCase(test.ScenarioTestCase):
@ddt.data({"config": {"size": 1, "volumes_per_tenant": 5}}, @ddt.data({"config": {"size": 1, "volumes_per_tenant": 5}},
{"config": {"size": 1, "type": None, "volumes_per_tenant": 5}}, {"config": {"size": 1, "type": None, "volumes_per_tenant": 5}},
{"config": {"size": 1, "type": -1, "volumes_per_tenant": 5}, {"config": {"size": 1, "type": -1, "volumes_per_tenant": 5},
"validation_raises": jsonschema.exceptions.ValidationError}) "valid": False})
@ddt.unpack @ddt.unpack
@mock.patch("%s.block.BlockStorage" % SERVICE) @mock.patch("%s.block.BlockStorage" % SERVICE)
def test_setup(self, mock_block_storage, config, def test_setup(self, mock_block_storage, config, valid=True):
validation_raises=None): results = context.Context.validate("volumes", None, None, config)
try: if valid:
volumes.VolumeGenerator.validate(config) self.assertEqual([], results)
except Exception as e: else:
if not isinstance(e, validation_raises): self.assertEqual(1, len(results))
raise
from rally.plugins.openstack.services.storage import block from rally.plugins.openstack.services.storage import block
created_volume = block.Volume(id="uuid", size=config["size"], created_volume = block.Volume(id="uuid", size=config["size"],

View File

@ -13,44 +13,41 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import jsonschema import ddt
import mock import mock
from rally.common import utils from rally.common import utils
from rally.plugins.openstack.context.cleanup import admin from rally.plugins.openstack.context.cleanup import admin
from rally.plugins.openstack.context.cleanup import base
from rally.plugins.openstack import scenario from rally.plugins.openstack import scenario
from rally.task import context
from tests.unit import test from tests.unit import test
BASE = "rally.plugins.openstack.context.cleanup.admin" ADMIN = "rally.plugins.openstack.context.cleanup.admin"
BASE = "rally.plugins.openstack.context.cleanup.base"
@ddt.ddt
class AdminCleanupTestCase(test.TestCase): class AdminCleanupTestCase(test.TestCase):
@mock.patch("%s.manager" % BASE) @mock.patch("%s.manager" % BASE)
def test_validate(self, mock_manager): @ddt.data((["a", "b"], True),
mock_manager.list_resource_names.return_value = set(["a", "b", "c"]) (["a", "e"], False),
admin.AdminCleanup.validate(["a"]) (3, False))
mock_manager.list_resource_names.assert_called_once_with( @ddt.unpack
admin_required=True) def test_validate(self, config, valid, mock_manager):
mock_manager.list_resource_names.return_value = {"a", "b", "c"}
@mock.patch("%s.manager" % BASE) results = context.Context.validate(
def test_validate_no_such_cleanup(self, mock_manager): "admin_cleanup", None, None, config, allow_hidden=True)
mock_manager.list_resource_names.return_value = set(["a", "b", "c"]) if valid:
self.assertRaises(base.NoSuchCleanupResources, self.assertEqual([], results)
admin.AdminCleanup.validate, ["a", "d"]) else:
mock_manager.list_resource_names.assert_called_once_with( self.assertGreater(len(results), 0)
admin_required=True)
def test_validate_invalid_config(self):
self.assertRaises(jsonschema.ValidationError,
admin.AdminCleanup.validate, {})
@mock.patch("rally.common.plugin.discover.itersubclasses") @mock.patch("rally.common.plugin.discover.itersubclasses")
@mock.patch("%s.manager.find_resource_managers" % BASE, @mock.patch("%s.manager.find_resource_managers" % ADMIN,
return_value=[mock.MagicMock(), mock.MagicMock()]) return_value=[mock.MagicMock(), mock.MagicMock()])
@mock.patch("%s.manager.SeekAndDestroy" % BASE) @mock.patch("%s.manager.SeekAndDestroy" % ADMIN)
def test_cleanup(self, mock_seek_and_destroy, mock_find_resource_managers, def test_cleanup(self, mock_seek_and_destroy, mock_find_resource_managers,
mock_itersubclasses): mock_itersubclasses):
class ResourceClass(utils.RandomNameGeneratorMixin): class ResourceClass(utils.RandomNameGeneratorMixin):
@ -89,9 +86,9 @@ class AdminCleanupTestCase(test.TestCase):
]) ])
@mock.patch("rally.common.plugin.discover.itersubclasses") @mock.patch("rally.common.plugin.discover.itersubclasses")
@mock.patch("%s.manager.find_resource_managers" % BASE, @mock.patch("%s.manager.find_resource_managers" % ADMIN,
return_value=[mock.MagicMock(), mock.MagicMock()]) return_value=[mock.MagicMock(), mock.MagicMock()])
@mock.patch("%s.manager.SeekAndDestroy" % BASE) @mock.patch("%s.manager.SeekAndDestroy" % ADMIN)
def test_cleanup_admin_with_api_versions(self, def test_cleanup_admin_with_api_versions(self,
mock_seek_and_destroy, mock_seek_and_destroy,
mock_find_resource_managers, mock_find_resource_managers,

View File

@ -13,44 +13,41 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import jsonschema import ddt
import mock import mock
from rally.common import utils from rally.common import utils
from rally.plugins.openstack.context.cleanup import base
from rally.plugins.openstack.context.cleanup import user from rally.plugins.openstack.context.cleanup import user
from rally.plugins.openstack import scenario from rally.plugins.openstack import scenario
from rally.task import context
from tests.unit import test from tests.unit import test
BASE = "rally.plugins.openstack.context.cleanup.user" ADMIN = "rally.plugins.openstack.context.cleanup.admin"
BASE = "rally.plugins.openstack.context.cleanup.base"
@ddt.ddt
class UserCleanupTestCase(test.TestCase): class UserCleanupTestCase(test.TestCase):
@mock.patch("%s.manager" % BASE) @mock.patch("%s.manager" % BASE)
def test_validate(self, mock_manager): @ddt.data((["a", "b"], True),
mock_manager.list_resource_names.return_value = set(["a", "b", "c"]) (["a", "e"], False),
user.UserCleanup.validate(["a"]) (3, False))
mock_manager.list_resource_names.assert_called_once_with( @ddt.unpack
admin_required=False) def test_validate(self, config, valid, mock_manager):
mock_manager.list_resource_names.return_value = {"a", "b", "c"}
@mock.patch("%s.manager" % BASE) results = context.Context.validate(
def test_validate_no_such_cleanup(self, mock_manager): "cleanup", None, None, config, allow_hidden=True)
mock_manager.list_resource_names.return_value = set(["a", "b", "c"]) if valid:
self.assertRaises(base.NoSuchCleanupResources, self.assertEqual([], results)
user.UserCleanup.validate, ["a", "b", "d"]) else:
mock_manager.list_resource_names.assert_called_once_with( self.assertGreater(len(results), 0)
admin_required=False)
def test_validate_invalid_config(self):
self.assertRaises(jsonschema.ValidationError,
user.UserCleanup.validate, {})
@mock.patch("rally.common.plugin.discover.itersubclasses") @mock.patch("rally.common.plugin.discover.itersubclasses")
@mock.patch("%s.manager.find_resource_managers" % BASE, @mock.patch("%s.manager.find_resource_managers" % ADMIN,
return_value=[mock.MagicMock(), mock.MagicMock()]) return_value=[mock.MagicMock(), mock.MagicMock()])
@mock.patch("%s.manager.SeekAndDestroy" % BASE) @mock.patch("%s.manager.SeekAndDestroy" % ADMIN)
def test_cleanup(self, mock_seek_and_destroy, mock_find_resource_managers, def test_cleanup(self, mock_seek_and_destroy, mock_find_resource_managers,
mock_itersubclasses): mock_itersubclasses):
@ -83,9 +80,9 @@ class UserCleanupTestCase(test.TestCase):
]) ])
@mock.patch("rally.common.plugin.discover.itersubclasses") @mock.patch("rally.common.plugin.discover.itersubclasses")
@mock.patch("%s.manager.find_resource_managers" % BASE, @mock.patch("%s.manager.find_resource_managers" % ADMIN,
return_value=[mock.MagicMock(), mock.MagicMock()]) return_value=[mock.MagicMock(), mock.MagicMock()])
@mock.patch("%s.manager.SeekAndDestroy" % BASE) @mock.patch("%s.manager.SeekAndDestroy" % ADMIN)
def test_cleanup_user_with_api_versions( def test_cleanup_user_with_api_versions(
self, self,
mock_seek_and_destroy, mock_seek_and_destroy,

View File

@ -16,7 +16,6 @@
import copy import copy
import ddt import ddt
import jsonschema
import mock import mock
from rally.plugins.openstack.context.glance import images from rally.plugins.openstack.context.glance import images
@ -59,16 +58,6 @@ class ImageGeneratorTestCase(test.ScenarioTestCase):
tenants[str(id_)] = {"name": str(id_)} tenants[str(id_)] = {"name": str(id_)}
return tenants return tenants
def test_init_validation(self):
self.context["config"] = {
"images": {
"image_url": "mock_url"
}
}
self.assertRaises(jsonschema.ValidationError,
images.ImageGenerator.validate, self.context)
@ddt.data( @ddt.data(
{}, {},
{"min_disk": 1, "min_ram": 2}, {"min_disk": 1, "min_ram": 2},

View File

@ -14,14 +14,13 @@
# under the License. # under the License.
import copy import copy
import random
import ddt import ddt
import jsonschema
import mock import mock
from rally.common import logging from rally.common import logging
from rally.plugins.openstack.context.quotas import quotas from rally.plugins.openstack.context.quotas import quotas
from rally.task import context
from tests.unit import test from tests.unit import test
QUOTAS_PATH = "rally.plugins.openstack.context.quotas" QUOTAS_PATH = "rally.plugins.openstack.context.quotas"
@ -43,98 +42,56 @@ class QuotasTestCase(test.TestCase):
"task": mock.MagicMock() "task": mock.MagicMock()
} }
def test_quotas_schemas(self): @ddt.data(("cinder", "backup_gigabytes"),
ctx = copy.deepcopy(self.context) ("cinder", "backups"),
ctx["config"]["quotas"] = { ("cinder", "gigabytes"),
"cinder": { ("cinder", "snapshots"),
"volumes": self.unlimited, ("cinder", "volumes"),
"snapshots": self.unlimited, ("manila", "gigabytes"),
"gigabytes": self.unlimited ("manila", "share_networks"),
}, ("manila", "shares"),
"nova": { ("manila", "snapshot_gigabytes"),
"instances": self.unlimited, ("manila", "snapshots"),
"cores": self.unlimited, ("neutron", "floatingip"),
"ram": self.unlimited, ("neutron", "health_monitor"),
"floating_ips": self.unlimited, ("neutron", "network"),
"fixed_ips": self.unlimited, ("neutron", "pool"),
"metadata_items": self.unlimited, ("neutron", "port"),
"injected_files": self.unlimited, ("neutron", "router"),
"injected_file_content_bytes": self.unlimited, ("neutron", "security_group"),
"injected_file_path_bytes": self.unlimited, ("neutron", "security_group_rule"),
"key_pairs": self.unlimited, ("neutron", "subnet"),
"security_groups": self.unlimited, ("neutron", "vip"),
"security_group_rules": self.unlimited ("nova", "cores"),
}, ("nova", "fixed_ips"),
"neutron": { ("nova", "floating_ips"),
"network": self.unlimited, ("nova", "injected_file_content_bytes"),
"subnet": self.unlimited, ("nova", "injected_file_path_bytes"),
"port": self.unlimited, ("nova", "injected_files"),
"router": self.unlimited, ("nova", "instances"),
"floatingip": self.unlimited, ("nova", "key_pairs"),
"security_group": self.unlimited, ("nova", "metadata_items"),
"security_group_rule": self.unlimited ("nova", "ram"),
} ("nova", "security_group_rules"),
} ("nova", "security_groups"),
for service in ctx["config"]["quotas"]: ("nova", "server_group_members"),
for key in ctx["config"]["quotas"][service]: ("nova", "server_groups"))
# Test invalid values @ddt.unpack
ctx["config"]["quotas"][service][key] = self.unlimited - 1 def test_validate(self, group, parameter):
try: configs = [
quotas.Quotas.validate(ctx["config"]["quotas"]) ({group: {parameter: self.unlimited}}, True),
except jsonschema.ValidationError: ({group: {parameter: 0}}, True),
pass ({group: {parameter: 10000}}, True),
else: ({group: {parameter: 2.5}}, False),
self.fail("Invalid value %s must raise a validation error" ({group: {parameter: "-1"}}, False),
% ctx["config"]["quotas"][service][key]) ({group: {parameter: -2}}, False),
]
ctx["config"]["quotas"][service][key] = 2.5 for config, valid in configs:
try: results = context.Context.validate("quotas", None, None, config)
quotas.Quotas.validate(ctx["config"]["quotas"]) if valid:
except jsonschema.ValidationError: self.assertEqual([], results)
pass
else:
self.fail("Invalid value %s must raise a validation error"
% ctx["config"]["quotas"][service][key])
ctx["config"]["quotas"][service][key] = "-1"
try:
quotas.Quotas.validate(ctx["config"]["quotas"])
except jsonschema.ValidationError:
pass
else:
self.fail("Invalid value %s must raise a validation error"
% ctx["config"]["quotas"][service][key])
# Test valid values
ctx["config"]["quotas"][service][key] = random.randint(0,
1000000)
try:
quotas.Quotas.validate(ctx["config"]["quotas"])
except jsonschema.ValidationError:
self.fail("Positive integers are valid quota values")
ctx["config"]["quotas"][service][key] = self.unlimited
try:
quotas.Quotas.validate(ctx["config"]["quotas"])
except jsonschema.ValidationError:
self.fail("%d is a valid quota value" % self.unlimited)
# Test additional keys are refused
ctx["config"]["quotas"][service]["additional"] = self.unlimited
try:
quotas.Quotas.validate(ctx["config"]["quotas"])
except jsonschema.ValidationError:
pass
else: else:
self.fail("Additional keys must raise a validation error") self.assertGreater(len(results), 0)
del ctx["config"]["quotas"][service]["additional"]
# Test valid keys are optional
ctx["config"]["quotas"][service] = {}
try:
quotas.Quotas.validate(ctx["config"]["quotas"])
except jsonschema.ValidationError:
self.fail("Valid quota keys are optional")
@mock.patch("%s.quotas.osclients.Clients" % QUOTAS_PATH) @mock.patch("%s.quotas.osclients.Clients" % QUOTAS_PATH)
@mock.patch("%s.cinder_quotas.CinderQuotas" % QUOTAS_PATH) @mock.patch("%s.cinder_quotas.CinderQuotas" % QUOTAS_PATH)

View File

@ -10,15 +10,17 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import jsonschema import ddt
import mock import mock
from rally.common import utils from rally.common import utils
from rally import exceptions from rally import exceptions
from rally.plugins.openstack.context import api_versions from rally.plugins.openstack.context import api_versions
from rally.task import context
from tests.unit import test from tests.unit import test
@ddt.ddt
class OpenStackServicesTestCase(test.TestCase): class OpenStackServicesTestCase(test.TestCase):
def setUp(self): def setUp(self):
@ -30,82 +32,51 @@ class OpenStackServicesTestCase(test.TestCase):
self.service_catalog.get_endpoints.return_value = [] self.service_catalog.get_endpoints.return_value = []
self.mock_kc.services.list.return_value = [] self.mock_kc.services.list.return_value = []
def test_validate_correct_config(self): @ddt.data(({"nova": {"service_type": "compute", "version": 2},
api_versions.OpenStackAPIVersions.validate({ "cinder": {"service_name": "cinderv2", "version": 2},
"nova": {"service_type": "compute", "version": 2}, "neutron": {"service_type": "network"},
"cinder": {"service_name": "cinderv2", "version": 2}, "glance": {"service_name": "glance"},
"neutron": {"service_type": "network"}, "heat": {"version": 1}}, True),
"glance": {"service_name": "glance"}, ({"nova": {"service_type": "compute",
"heat": {"version": 1} "service_name": "nova"}}, False),
}) ({"keystone": {"service_type": "foo"}}, False),
({"nova": {"version": "foo"}}, False),
def test_validate_wrong_configs(self): ({}, False))
# Non-existing clients should be caught @ddt.unpack
self.assertRaises( def test_validate(self, config, valid):
exceptions.PluginNotFound, results = context.Context.validate("api_versions", None, None, config)
api_versions.OpenStackAPIVersions.validate, if valid:
{"invalid": {"service_type": "some_type"}}) self.assertEqual([], results)
else:
# Additional properties should be restricted self.assertGreater(len(results), 0)
self.assertRaises(
jsonschema.ValidationError,
api_versions.OpenStackAPIVersions.validate,
{"nova": {"some_key": "some_value"}})
# Setting service_type is allowed only
# for those clients, which support it
self.assertRaises(
exceptions.ValidationError,
api_versions.OpenStackAPIVersions.validate,
{"keystone": {"service_type": "identity"}})
# Setting service_name is allowed only
# for those clients, which support it
self.assertRaises(
exceptions.ValidationError,
api_versions.OpenStackAPIVersions.validate,
{"keystone": {"service_name": "keystone"}})
# Setting version is allowed only
# for those clients, which support it
self.assertRaises(
exceptions.ValidationError,
api_versions.OpenStackAPIVersions.validate,
{"keystone": {"version": 1}})
# Unsupported version should be caught
self.assertRaises(
exceptions.ValidationError,
api_versions.OpenStackAPIVersions.validate,
{"nova": {"version": 666}})
def test_setup_with_wrong_service_name(self): def test_setup_with_wrong_service_name(self):
context = { context_obj = {
"config": {api_versions.OpenStackAPIVersions.get_name(): { "config": {api_versions.OpenStackAPIVersions.get_name(): {
"nova": {"service_name": "service_name"}}}, "nova": {"service_name": "service_name"}}},
"admin": {"credential": mock.MagicMock()}, "admin": {"credential": mock.MagicMock()},
"users": [{"credential": mock.MagicMock()}]} "users": [{"credential": mock.MagicMock()}]}
ctx = api_versions.OpenStackAPIVersions(context) ctx = api_versions.OpenStackAPIVersions(context_obj)
self.assertRaises(exceptions.ValidationError, ctx.setup) self.assertRaises(exceptions.ValidationError, ctx.setup)
self.service_catalog.get_endpoints.assert_called_once_with() self.service_catalog.get_endpoints.assert_called_once_with()
self.mock_kc.services.list.assert_called_once_with() self.mock_kc.services.list.assert_called_once_with()
def test_setup_with_wrong_service_name_and_without_admin(self): def test_setup_with_wrong_service_name_and_without_admin(self):
context = { context_obj = {
"config": {api_versions.OpenStackAPIVersions.get_name(): { "config": {api_versions.OpenStackAPIVersions.get_name(): {
"nova": {"service_name": "service_name"}}}, "nova": {"service_name": "service_name"}}},
"users": [{"credential": mock.MagicMock()}]} "users": [{"credential": mock.MagicMock()}]}
ctx = api_versions.OpenStackAPIVersions(context) ctx = api_versions.OpenStackAPIVersions(context_obj)
self.assertRaises(exceptions.BenchmarkSetupFailure, ctx.setup) self.assertRaises(exceptions.BenchmarkSetupFailure, ctx.setup)
self.service_catalog.get_endpoints.assert_called_once_with() self.service_catalog.get_endpoints.assert_called_once_with()
self.assertFalse(self.mock_kc.services.list.called) self.assertFalse(self.mock_kc.services.list.called)
def test_setup_with_wrong_service_type(self): def test_setup_with_wrong_service_type(self):
context = { context_obj = {
"config": {api_versions.OpenStackAPIVersions.get_name(): { "config": {api_versions.OpenStackAPIVersions.get_name(): {
"nova": {"service_type": "service_type"}}}, "nova": {"service_type": "service_type"}}},
"users": [{"credential": mock.MagicMock()}]} "users": [{"credential": mock.MagicMock()}]}
ctx = api_versions.OpenStackAPIVersions(context) ctx = api_versions.OpenStackAPIVersions(context_obj)
self.assertRaises(exceptions.ValidationError, ctx.setup) self.assertRaises(exceptions.ValidationError, ctx.setup)
self.service_catalog.get_endpoints.assert_called_once_with() self.service_catalog.get_endpoints.assert_called_once_with()