From 4f4ce0385ab1b6463dc8b1c9b57636e2fd82f819 Mon Sep 17 00:00:00 2001 From: Andrey Kurilin Date: Wed, 8 Feb 2017 18:21:58 +0200 Subject: [PATCH] Fix used jsonschemas We have a bunch of schemas with wrong format. This patch fixes them and adds unit test to avoid such mistakes in future. Change-Id: I8bafb4b62a38eca3a5d5ec8945d3d4f9f42674ab --- .../plugins/openstack/context/api_versions.py | 5 +- .../openstack/context/cinder/volume_types.py | 2 +- .../openstack/context/cinder/volumes.py | 7 +- .../plugins/openstack/context/cleanup/base.py | 3 +- .../openstack/context/dataplane/heat.py | 3 + .../openstack/context/keystone/roles.py | 3 +- .../context/magnum/cluster_templates.py | 2 +- .../openstack/context/magnum/clusters.py | 3 +- .../manila/manila_security_services.py | 33 ++-- .../openstack/context/nova/keypairs.py | 6 + .../plugins/openstack/context/nova/servers.py | 18 +- .../openstack/context/sahara/sahara_image.py | 6 +- .../context/vm/image_command_customizer.py | 8 +- .../context/watcher/audit_templates.py | 49 ++--- .../plugins/openstack/scenarios/vm/vmtasks.py | 12 +- .../openstack/scenarios/watcher/basic.py | 15 +- tests/unit/doc/test_jsonschemas.py | 168 ++++++++++++++++++ tests/unit/doc/test_task_samples.py | 8 +- .../manila/test_manila_security_services.py | 7 - 19 files changed, 278 insertions(+), 80 deletions(-) create mode 100644 tests/unit/doc/test_jsonschemas.py diff --git a/rally/plugins/openstack/context/api_versions.py b/rally/plugins/openstack/context/api_versions.py index df545301..207be447 100644 --- a/rally/plugins/openstack/context/api_versions.py +++ b/rally/plugins/openstack/context/api_versions.py @@ -166,7 +166,10 @@ class OpenStackAPIVersions(context.Context): "type": "object", "properties": { "version": { - "anyOf": [{"type": "string"}, {"type": "number"}] + "anyOf": [{"type": "string", + "description": "a string-like version."}, + {"type": "number", + "description": "a number-like version."}] }, "service_name": { "type": "string" diff --git a/rally/plugins/openstack/context/cinder/volume_types.py b/rally/plugins/openstack/context/cinder/volume_types.py index 72894e32..fe6bbc54 100644 --- a/rally/plugins/openstack/context/cinder/volume_types.py +++ b/rally/plugins/openstack/context/cinder/volume_types.py @@ -29,7 +29,7 @@ class VolumeTypeGenerator(context.Context): CONFIG_SCHEMA = { "type": "array", "$schema": consts.JSON_SCHEMA, - "additionalProperties": False + "items": {"type": "string"} } @logging.log_task_wrapper(LOG.info, _("Enter context: `volume_types`")) diff --git a/rally/plugins/openstack/context/cinder/volumes.py b/rally/plugins/openstack/context/cinder/volumes.py index a5380f09..1f939434 100755 --- a/rally/plugins/openstack/context/cinder/volumes.py +++ b/rally/plugins/openstack/context/cinder/volumes.py @@ -37,7 +37,12 @@ class VolumeGenerator(context.Context): "minimum": 1 }, "type": { - "type": ["string", "null"] + "oneOf": [{"type": "string", + "description": "a string-like type of volume to " + "create."}, + {"type": "null", + "description": "Use default type for volume to " + "create."}] }, "volumes_per_tenant": { "type": "integer", diff --git a/rally/plugins/openstack/context/cleanup/base.py b/rally/plugins/openstack/context/cleanup/base.py index 7d0b43bf..7d338b6c 100644 --- a/rally/plugins/openstack/context/cleanup/base.py +++ b/rally/plugins/openstack/context/cleanup/base.py @@ -29,8 +29,7 @@ class CleanupMixin(object): "$schema": consts.JSON_SCHEMA, "items": { "type": "string", - }, - "additionalProperties": False + } } def setup(self): diff --git a/rally/plugins/openstack/context/dataplane/heat.py b/rally/plugins/openstack/context/dataplane/heat.py index 08ef4445..8e879631 100644 --- a/rally/plugins/openstack/context/dataplane/heat.py +++ b/rally/plugins/openstack/context/dataplane/heat.py @@ -52,12 +52,15 @@ class HeatDataplane(context.Context): key_name: name of nova ssh keypair to use for "gate" node """ FILE_SCHEMA = { + "description": "", "type": "string", } RESOURCE_SCHEMA = { + "description": "", "type": "array", "minItems": 2, "maxItems": 2, + "items": {"type": "string"} } CONFIG_SCHEMA = { "type": "object", diff --git a/rally/plugins/openstack/context/keystone/roles.py b/rally/plugins/openstack/context/keystone/roles.py index 9c1d6730..2969ce49 100644 --- a/rally/plugins/openstack/context/keystone/roles.py +++ b/rally/plugins/openstack/context/keystone/roles.py @@ -49,8 +49,7 @@ class RoleGenerator(context.Context): "$schema": consts.JSON_SCHEMA, "items": { "type": "string", - }, - "additionalProperties": False + } } def __init__(self, ctx): diff --git a/rally/plugins/openstack/context/magnum/cluster_templates.py b/rally/plugins/openstack/context/magnum/cluster_templates.py index 2e20da9f..3bd6df0b 100644 --- a/rally/plugins/openstack/context/magnum/cluster_templates.py +++ b/rally/plugins/openstack/context/magnum/cluster_templates.py @@ -58,7 +58,7 @@ class ClusterTemplateGenerator(context.Context): "type": "integer" }, "labels": { - "type": ["string"] + "type": "string" }, "coe": { "type": "string" diff --git a/rally/plugins/openstack/context/magnum/clusters.py b/rally/plugins/openstack/context/magnum/clusters.py index b3461e1a..946ff294 100644 --- a/rally/plugins/openstack/context/magnum/clusters.py +++ b/rally/plugins/openstack/context/magnum/clusters.py @@ -38,12 +38,13 @@ class ClusterGenerator(context.Context): "node_count": { "type": "integer", "minimum": 1, - "default": 1 }, }, "additionalProperties": False } + DEFAULT_CONFIG = {"node_count": 1} + @logging.log_task_wrapper(LOG.info, _("Enter context: `Cluster`")) def setup(self): for user, tenant_id in rutils.iterate_per_tenants( diff --git a/rally/plugins/openstack/context/manila/manila_security_services.py b/rally/plugins/openstack/context/manila/manila_security_services.py index 951ac3e4..04e2bffa 100644 --- a/rally/plugins/openstack/context/manila/manila_security_services.py +++ b/rally/plugins/openstack/context/manila/manila_security_services.py @@ -38,19 +38,26 @@ class SecurityServices(context.Context): "type": "object", "$schema": rally_consts.JSON_SCHEMA, "properties": { - # NOTE(vponomaryov): context arg 'security_services' is expected - # to be list of dicts with data for creation of security services. - # Example: - # security_services = [ - # {'type': 'LDAP', 'dns_ip': 'foo_ip', 'server': 'bar_ip', - # 'domain': 'quuz_domain', 'user': 'ololo', - # 'password': 'fake_password'} - # ] - # Where 'type' is required key and should have one of following - # values: 'active_directory', 'kerberos' or 'ldap'. - # This context arg is used only if share networks are used and - # autocreated. - "security_services": {"type": "array"}, + "security_services": { + "type": "array", + "description": + "It is expected to be list of dicts with data for creation" + " of security services.", + "items": { + "type": "object", + "properties": {"type": {"enum": ["active_directory", + "kerberos", "ldap"]}}, + "required": ["type"], + "additionalProperties": True, + "description": + "Data for creation of security services. \n " + "Example:\n\n" + " .. code-block:: json\n\n" + " {'type': 'LDAP', 'dns_ip': 'foo_ip', \n" + " 'server': 'bar_ip', 'domain': 'quuz_domain',\n" + " 'user': 'ololo', 'password': 'fake_password'}\n" + } + }, }, "additionalProperties": False } diff --git a/rally/plugins/openstack/context/nova/keypairs.py b/rally/plugins/openstack/context/nova/keypairs.py index 5e723586..b6571e8b 100644 --- a/rally/plugins/openstack/context/nova/keypairs.py +++ b/rally/plugins/openstack/context/nova/keypairs.py @@ -26,6 +26,12 @@ LOG = logging.getLogger(__name__) @context.configure(name="keypair", order=310) class Keypair(context.Context): + # NOTE(andreykurilin): "type" != "null", since we need to support backward + # compatibility(previously empty dict was valid) and I hope in near + # future, we will extend this context to accept keys. + CONFIG_SCHEMA = {"type": "object", + "additionalProperties": False} + def _generate_keypair(self, credential): nova_client = osclients.Clients(credential).nova() # NOTE(hughsaunders): If keypair exists, it should re-generate name. diff --git a/rally/plugins/openstack/context/nova/servers.py b/rally/plugins/openstack/context/nova/servers.py index 8bac8417..bd5bea67 100755 --- a/rally/plugins/openstack/context/nova/servers.py +++ b/rally/plugins/openstack/context/nova/servers.py @@ -15,7 +15,6 @@ from rally.common.i18n import _ from rally.common import logging from rally.common import utils as rutils -from rally import consts from rally import osclients from rally.plugins.openstack.cleanup import manager as resource_manager from rally.plugins.openstack.scenarios.nova import utils as nova_utils @@ -35,9 +34,9 @@ class ServerGenerator(context.Context): CONFIG_SCHEMA = { "type": "object", - "$schema": consts.JSON_SCHEMA, "properties": { "image": { + "description": "Name of image to boot server(s) from.", "type": "object", "properties": { "name": { @@ -46,6 +45,7 @@ class ServerGenerator(context.Context): } }, "flavor": { + "description": "Name of flavor to boot server(s) with.", "type": "object", "properties": { "name": { @@ -54,19 +54,23 @@ class ServerGenerator(context.Context): } }, "servers_per_tenant": { + "description": "Number of servers to boot in each Tenant.", "type": "integer", "minimum": 1 }, "auto_assign_nic": { + "description": "True if NICs should be assigned.", "type": "boolean", }, "nics": { "type": "array", - "properties": { - "net-id": { - "type": "string" - } - } + "description": "List of networks to attach to server.", + "items": {"oneOf": [ + {"type": "object", + "properties": {"net-id": {"type": "string"}}, + "description": "Network ID in a format like OpenStack API" + " expects to see."}, + {"type": "string", "description": "Network ID."}]} } }, "required": ["image", "flavor"], diff --git a/rally/plugins/openstack/context/sahara/sahara_image.py b/rally/plugins/openstack/context/sahara/sahara_image.py index 1b7c8ad3..276792f6 100644 --- a/rally/plugins/openstack/context/sahara/sahara_image.py +++ b/rally/plugins/openstack/context/sahara/sahara_image.py @@ -52,9 +52,11 @@ class SaharaImage(context.Context): } }, "oneOf": [ - {"required": ["image_url", "username", "plugin_name", + {"description": "Create an image.", + "required": ["image_url", "username", "plugin_name", "hadoop_version"]}, - {"required": ["image_uuid"]} + {"description": "Use an existing image.", + "required": ["image_uuid"]} ], "additionalProperties": False } diff --git a/rally/plugins/openstack/context/vm/image_command_customizer.py b/rally/plugins/openstack/context/vm/image_command_customizer.py index e927cd8f..7a2af55f 100644 --- a/rally/plugins/openstack/context/vm/image_command_customizer.py +++ b/rally/plugins/openstack/context/vm/image_command_customizer.py @@ -35,14 +35,15 @@ class ImageCommandCustomizerContext(custom_image.BaseCustomImageGenerator): CONFIG_SCHEMA["definitions"] = { "stringOrStringList": { "anyOf": [ - {"type": "string"}, + {"type": "string", "description": "just a string"}, { - "type": "array", + "type": "array", "description": "just a list of strings", "items": {"type": "string"} } ] }, "scriptFile": { + "type": "object", "properties": { "script_file": {"$ref": "#/definitions/stringOrStringList"}, "interpreter": {"$ref": "#/definitions/stringOrStringList"}, @@ -52,6 +53,7 @@ class ImageCommandCustomizerContext(custom_image.BaseCustomImageGenerator): "additionalProperties": False, }, "scriptInline": { + "type": "object", "properties": { "script_inline": {"type": "string"}, "interpreter": {"$ref": "#/definitions/stringOrStringList"}, @@ -61,6 +63,7 @@ class ImageCommandCustomizerContext(custom_image.BaseCustomImageGenerator): "additionalProperties": False, }, "commandPath": { + "type": "object", "properties": { "remote_path": {"$ref": "#/definitions/stringOrStringList"}, "local_path": {"type": "string"}, @@ -70,7 +73,6 @@ class ImageCommandCustomizerContext(custom_image.BaseCustomImageGenerator): "additionalProperties": False, }, "commandDict": { - "type": "object", "oneOf": [ {"$ref": "#/definitions/scriptFile"}, {"$ref": "#/definitions/scriptInline"}, diff --git a/rally/plugins/openstack/context/watcher/audit_templates.py b/rally/plugins/openstack/context/watcher/audit_templates.py index 5cd26d29..3f7a7d28 100644 --- a/rally/plugins/openstack/context/watcher/audit_templates.py +++ b/rally/plugins/openstack/context/watcher/audit_templates.py @@ -36,34 +36,37 @@ class AuditTemplateGenerator(context.Context): CONFIG_SCHEMA = { "type": "object", "$schema": consts.JSON_SCHEMA, - "fill_strategy": {"enum": ["round_robin", "random", None]}, - "params": { - "type": "array", - "minItems": 1, - "uniqueItems": True, - "items": { - "type": "object", - "properties": { - "goal": { - "type": "object", - "properties": { - "name": { - "type": "string" + "properties": { + "audit_templates_per_admin": {"type": "integer", "minimum": 1}, + "fill_strategy": {"enum": ["round_robin", "random", None]}, + "params": { + "type": "array", + "minItems": 1, + "uniqueItems": True, + "items": { + "type": "object", + "properties": { + "goal": { + "type": "object", + "properties": { + "name": { + "type": "string" + } } - } - }, - "strategy": { - "type": "object", - "properties": { - "name": { - "type": "string" + }, + "strategy": { + "type": "object", + "properties": { + "name": { + "type": "string" + } } - } + }, }, }, - }, + } }, - "additionalProperties": True, + "additionalProperties": False, "required": ["params"] } diff --git a/rally/plugins/openstack/scenarios/vm/vmtasks.py b/rally/plugins/openstack/scenarios/vm/vmtasks.py index 021ca138..9847bd6c 100644 --- a/rally/plugins/openstack/scenarios/vm/vmtasks.py +++ b/rally/plugins/openstack/scenarios/vm/vmtasks.py @@ -46,7 +46,7 @@ LOG = logging.getLogger(__name__) @validation.required_services(consts.Service.NOVA, consts.Service.CINDER) @validation.required_openstack(users=True) @scenario.configure(context={"cleanup": ["nova", "cinder"], - "keypair": {}, "allow_ssh": {}}, + "keypair": {}, "allow_ssh": None}, name="VMTasks.boot_runcommand_delete") class BootRuncommandDelete(vm_utils.VMScenario): @@ -80,8 +80,9 @@ class BootRuncommandDelete(vm_utils.VMScenario): `local_path' is given). Uploading an interpreter is possible but requires that `remote_path' and `interpreter' path do match. + Examples: - Examples:: + .. code-block:: python # Run a `local_script.pl' file sending it to a remote # Perl interpreter @@ -228,11 +229,12 @@ class RuncommandHeat(vm_utils.VMScenario): Workload can be either file or resource: - .. code-block: json + .. code-block:: json {"file": "/path/to/file.sh"} {"resource": ["package.module", "workload.py"]} + Also it should contain "username" key. Given file will be uploaded to `gate_node` and started. This script @@ -415,7 +417,7 @@ EOF @validation.required_services(consts.Service.NOVA, consts.Service.CINDER) @validation.required_openstack(users=True) @scenario.configure(context={"cleanup": ["nova", "cinder"], - "keypair": {}, "allow_ssh": {}}, + "keypair": {}, "allow_ssh": None}, name="VMTasks.dd_load_test") class DDLoadTest(BootRuncommandDelete): @@ -425,4 +427,4 @@ class DDLoadTest(BootRuncommandDelete): Example Script in rally-jobs/extra/install_benchmark.sh """ command["script_inline"] = BASH_DD_LOAD_TEST - return super(DDLoadTest, self).run(command=command, **kwargs) \ No newline at end of file + return super(DDLoadTest, self).run(command=command, **kwargs) diff --git a/rally/plugins/openstack/scenarios/watcher/basic.py b/rally/plugins/openstack/scenarios/watcher/basic.py index 376a7263..aebcc116 100644 --- a/rally/plugins/openstack/scenarios/watcher/basic.py +++ b/rally/plugins/openstack/scenarios/watcher/basic.py @@ -37,7 +37,7 @@ class CreateAuditTemplateAndDelete(utils.WatcherScenario): :param goal: The goal audit template is based on :param strategy: The strategy used to provide resource optimization - algorithm + algorithm """ audit_template = self._create_audit_template(goal, strategy) @@ -59,12 +59,13 @@ class ListAuditTemplates(utils.WatcherScenario): :param goal: Name of the goal :param strategy: Name of the strategy :param limit: The maximum number of results to return per - request, if: - 1) limit > 0, the maximum number of audit templates to return. - 2) limit == 0, return the entire list of audit_templates. - 3) limit param is NOT specified (None), the number of items - returned respect the maximum imposed by the Watcher API - (see Watcher's api.max_limit option). + request, if: + + 1) limit > 0, the maximum number of audit templates to return. + 2) limit == 0, return the entire list of audit_templates. + 3) limit param is NOT specified (None), the number of items + returned respect the maximum imposed by the Watcher API + (see Watcher's api.max_limit option). :param sort_key: Optional, field used for sorting. :param sort_dir: Optional, direction of sorting, either 'asc' (the default) or 'desc'. diff --git a/tests/unit/doc/test_jsonschemas.py b/tests/unit/doc/test_jsonschemas.py new file mode 100644 index 00000000..9081766a --- /dev/null +++ b/tests/unit/doc/test_jsonschemas.py @@ -0,0 +1,168 @@ +# All Rights Reserved. +# +# 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 copy + +from rally.common.plugin import plugin +from rally import plugins +from tests.unit import test + + +class ConfigSchemasTestCase(test.TestCase): + + OBJECT_TYPE_KEYS = {"$schema", "type", "description", "required", + "properties", "patternProperties", + "additionalProperties", "oneOf", "anyOf"} + ARRAY_TYPE_KEYS = {"$schema", "type", "description", "items", + "uniqueItems", "minItems", "maxItems", + "additionalItems"} + NUMBER_TYPE_KEYS = {"$schema", "type", "description", "minimum", "maximum", + "exclusiveMinimum"} + STRING_TYPE_KEYS = {"$schema", "type", "description", "pattern"} + + def fail(self, p, schema, msg): + super(ConfigSchemasTestCase, self).fail( + "Config schema of plugin '%s' (%s) is invalid. %s " + "(Schema: %s)" % (p.get_name(), + "%s.%s" % (p.__module__, p.__name__), + msg, schema)) + + def _check_anyOf_or_oneOf(self, p, schema, definitions): + if "anyOf" in schema or "oneOf" in schema: + key = "anyOf" if "anyOf" in schema else "oneOf" + for case in schema[key]: + if "description" not in case and "$ref" not in case: + self.fail(p, schema, "Each case of '%s' should have " + "description." % key) + full_schema = copy.deepcopy(schema) + full_schema.pop(key) + for k, v in case.items(): + full_schema[k] = v + self._check_item(p, full_schema, definitions) + + def _check_object_type(self, p, schema, definitions): + unexpected_keys = set(schema.keys()) - self.OBJECT_TYPE_KEYS + if "definitions" in unexpected_keys: + # TODO(andreykurilin): do not use definitions since it is a hard + # task to parse and display them + unexpected_keys -= {"definitions"} + if unexpected_keys: + self.fail(p, schema, ("Found unexpected key(s) for object type: " + "%s." % ", ".join(unexpected_keys))) + + if "patternProperties" in schema: + if "properties" in schema: + self.fail(p, schema, "Usage both 'patternProperties' and " + "'properties' in one time is restricted.") + if not isinstance(schema["patternProperties"], dict): + self.fail(p, schema, "Field 'patternProperties' should be a " + "dict.") + for pattern, description in schema["patternProperties"].items(): + self._check_item(p, description, definitions) + + if "properties" in schema: + for property_name, description in schema["properties"].items(): + self._check_item(p, description, definitions) + + def _check_array_type(self, p, schema, definitions): + unexpected_keys = set(schema.keys()) - self.ARRAY_TYPE_KEYS + if "additionalProperties" in unexpected_keys: + self.fail(p, schema, "Array type doesn't support " + "'additionalProperties' field.") + + if unexpected_keys: + self.fail(p, schema, ("Found unexpected key(s) for array type: " + "%s." % ", ".join(unexpected_keys))) + + if "items" not in schema: + self.fail(p, schema, "Expected items of array type should be " + "described via 'items' field.") + + if isinstance(schema["items"], dict): + self._check_item(p, schema["items"], definitions) + if "additionalItems" in schema: + self.fail(p, schema, "When items is a single schema, the " + "`additionalItems` keyword is " + "meaningless, and it should not be used.") + elif isinstance(schema["items"], list): + for item in schema["items"]: + self._check_item(p, item, definitions) + else: + self.fail(p, schema, ("Field 'items' of array type should be a " + "list or a dict, but not '%s'" % + type(schema["items"]))) + + def _check_string_type(self, p, schema): + unexpected_keys = set(schema.keys()) - self.STRING_TYPE_KEYS + if unexpected_keys: + self.fail(p, schema, ("Found unexpected key(s) for string type: " + "%s." % ", ".join(unexpected_keys))) + + def _check_number_type(self, p, schema): + unexpected_keys = set(schema.keys()) - self.NUMBER_TYPE_KEYS + if unexpected_keys: + self.fail(p, schema, ("Found unexpected key(s) for integer/number " + "type: %s." % ", ".join(unexpected_keys))) + + def _check_simpliest_types(self, p, schema): + unexpected_keys = set(schema.keys()) - {"type", "description"} + if unexpected_keys: + self.fail(p, schema, ("Found unexpected key(s) for boolean type: " + "%s." % ", ".join(unexpected_keys))) + + def _check_item(self, p, schema, definitions): + if "type" in schema or "anyOf" in schema or "oneOf" in schema: + if "anyOf" in schema or "oneOf" in schema: + self._check_anyOf_or_oneOf(p, schema, definitions) + elif "type" in schema: + if schema["type"] == "object": + self._check_object_type(p, schema, definitions) + elif schema["type"] == "array": + self._check_array_type(p, schema, definitions) + elif schema["type"] == "string": + self._check_string_type(p, schema) + elif schema["type"] in ("number", "integer"): + self._check_number_type(p, schema) + elif schema["type"] in ("boolean", "null"): + self._check_simpliest_types(p, schema) + else: + self.fail(p, schema, + "Wrong type is used: %s" % schema["type"]) + elif "enum" in schema: + pass + elif schema == {}: + # NOTE(andreykurilin): an empty dict means that the user can + # transmit whatever he want in whatever he want format. It is + # not the case which we want to support. + self.fail(p, schema, "Empty schema is not allowed.") + elif "$ref" in schema: + definition_name = schema["$ref"].replace("#/definitions/", "") + if definition_name not in definitions: + self.fail(p, schema, + "Definition '%s' is not found." % definition_name) + else: + self.fail(p, schema, "Wrong format.") + + @plugins.ensure_plugins_are_loaded + def test_schema_is_valid(self): + for p in plugin.Plugin.get_all(): + if not hasattr(p, "CONFIG_SCHEMA"): + continue + # allow only top level definitions + definitions = p.CONFIG_SCHEMA.get("definitions", {}) + for definition in definitions.values(): + self._check_item(p, definition, definitions) + + # check schema itself + self._check_item(p, p.CONFIG_SCHEMA, definitions) diff --git a/tests/unit/doc/test_task_samples.py b/tests/unit/doc/test_task_samples.py index 010750b7..5e315f61 100644 --- a/tests/unit/doc/test_task_samples.py +++ b/tests/unit/doc/test_task_samples.py @@ -55,7 +55,7 @@ class TaskSampleTestCase(test.TestCase): with open(full_path) as task_file: try: - task_config = yaml.safe_load(api.Task.render_template + task_config = yaml.safe_load(api._Task.render_template (task_file.read())) eng = engine.TaskEngine(task_config, mock.MagicMock()) @@ -82,7 +82,7 @@ class TaskSampleTestCase(test.TestCase): full_path = os.path.join(dirname, filename) with open(full_path) as task_file: try: - json.loads(api.Task.render_template(task_file.read())) + json.loads(api._Task.render_template(task_file.read())) except Exception: print(traceback.format_exc()) self.fail("Invalid JSON file: %s" % full_path) @@ -122,10 +122,10 @@ class TaskSampleTestCase(test.TestCase): if os.path.exists(yaml_path) and os.path.exists(json_path): with open(json_path) as json_file: - json_config = yaml.safe_load(api.Task.render_template + json_config = yaml.safe_load(api._Task.render_template (json_file.read())) with open(yaml_path) as yaml_file: - yaml_config = yaml.safe_load(api.Task.render_template + yaml_config = yaml.safe_load(api._Task.render_template (yaml_file.read())) self.assertEqual(json_config, yaml_config, "Sample task configs are not equal:" diff --git a/tests/unit/plugins/openstack/context/manila/test_manila_security_services.py b/tests/unit/plugins/openstack/context/manila/test_manila_security_services.py index 228b0ff2..3e1a1a10 100644 --- a/tests/unit/plugins/openstack/context/manila/test_manila_security_services.py +++ b/tests/unit/plugins/openstack/context/manila/test_manila_security_services.py @@ -17,7 +17,6 @@ import ddt import mock import six -from rally import consts as rally_consts from rally.plugins.openstack.context.manila import consts from rally.plugins.openstack.context.manila import manila_security_services from tests.unit import test @@ -90,12 +89,6 @@ class SecurityServicesTestCase(test.ScenarioTestCase): self.assertEqual(inst.config.get("foo"), "bar") self.assertFalse(inst.config.get("security_services")) - self.assertIn( - rally_consts.JSON_SCHEMA, inst.CONFIG_SCHEMA.get("$schema")) - self.assertEqual(False, inst.CONFIG_SCHEMA.get("additionalProperties")) - self.assertEqual("object", inst.CONFIG_SCHEMA.get("type")) - props = inst.CONFIG_SCHEMA.get("properties", {}) - self.assertEqual({"type": "array"}, props.get("security_services")) self.assertEqual(445, inst.get_order()) self.assertEqual(CONTEXT_NAME, inst.get_name())