# Copyright 2016 OpenStack Foundation # 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 jsonschema from glare.tests.functional import base fixture_base_props = { u'activated_at': { u'description': u'Datetime when artifact has became active.', u'filter_ops': [u'lt', u'gt'], u'format': u'date-time', u'glareType': u'DateTime', u'readOnly': True, u'required_on_activate': False, u'sortable': True, u'type': [u'string', u'null']}, u'created_at': { u'description': u'Datetime when artifact has been created.', u'filter_ops': [u'lt', u'gt'], u'format': u'date-time', u'glareType': u'DateTime', u'readOnly': True, u'sortable': True, u'type': u'string'}, u'description': {u'default': u'', u'description': u'Artifact description.', u'filter_ops': [], u'glareType': u'String', u'maxLength': 4096, u'mutable': True, u'required_on_activate': False, u'type': [u'string', u'null']}, u'id': {u'description': u'Artifact UUID.', u'filter_ops': [u'eq', u'neq', u'in'], u'glareType': u'String', u'maxLength': 255, u'pattern': u'^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F]){4}' u'-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$', u'readOnly': True, u'sortable': True, u'type': u'string'}, u'metadata': {u'additionalProperties': {u'maxLength': 255, u'minLength': 1, u'type': u'string'}, u'default': {}, u'description': u'Key-value dict with useful information ' u'about an artifact.', u'filter_ops': [u'eq', u'neq', u'in'], u'glareType': u'StringDict', u'maxProperties': 255, u'required_on_activate': False, u'type': [u'object', u'null']}, u'name': {u'description': u'Artifact Name.', u'filter_ops': [u'eq', u'neq', u'in'], u'glareType': u'String', u'maxLength': 255, u'minLength': 1, u'required_on_activate': False, u'sortable': True, u'type': u'string'}, u'owner': {u'description': u'ID of user/tenant who uploaded artifact.', u'filter_ops': [u'eq', u'neq', u'in'], u'glareType': u'String', u'maxLength': 255, u'readOnly': True, u'required_on_activate': False, u'sortable': True, u'type': u'string'}, u'status': {u'default': u'drafted', u'description': u'Artifact status.', u'enum': [u'drafted', u'active', u'deactivated', u'deleted'], u'filter_ops': [u'eq', u'neq', u'in'], u'glareType': u'String', u'mutable': True, u'sortable': True, u'type': u'string'}, u'tags': {u'default': [], u'description': u'List of tags added to Artifact.', u'filter_ops': [], u'glareType': u'StringList', u'items': {u'maxLength': 255, u'minLength': 1, u'pattern': u'^[^,/]+$', u'type': u'string'}, u'maxItems': 255, u'mutable': True, u'required_on_activate': False, u'type': [u'array', u'null'], u'uniqueItems': True}, u'updated_at': { u'description': u'Datetime when artifact has been updated last time.', u'filter_ops': [u'lt', u'gt'], u'format': u'date-time', u'glareType': u'DateTime', u'mutable': True, u'readOnly': True, u'sortable': True, u'type': u'string'}, u'version': {u'default': u'0.0.0', u'description': u'Artifact version(semver).', u'filter_ops': [u'eq', u'neq', u'in', u'gt', u'gte', u'lt', u'lte'], u'glareType': u'String', u'pattern': u'/^([0-9]+)\\.([0-9]+)\\.([0-9]+)(?:-' u'([0-9A-Za-z-]+(?:\\.[0-9A-Za-z-]+)*))?' u'(?:\\+[0-9A-Za-z-]+)?$/', u'required_on_activate': False, u'sortable': True, u'type': u'string'}, u'visibility': {u'default': u'private', u'description': u'Artifact visibility that defines if ' u'artifact can be available to other ' u'users.', u'enum': [u'private', u'public'], u'filter_ops': [u'eq', u'neq', u'in'], u'glareType': u'String', u'mutable': True, u'sortable': True, u'type': u'string'} } def generate_type_props(props): props.update(fixture_base_props) return props fixtures = { u'sample_artifact': { u'name': u'sample_artifact', u'properties': generate_type_props({ u'blob': {u'additionalProperties': False, u'description': u'I am Blob', u'filter_ops': [], u'glareType': u'Blob', u'mutable': True, u'properties': { u'md5': {u'type': [u'string', u'null']}, u'sha1': {u'type': [u'string', u'null']}, u'sha256': {u'type': [u'string', u'null']}, u'content_type': { u'type': u'string'}, u'external': { u'type': u'boolean'}, u'size': {u'type': [ u'number', u'null']}, u'status': { u'enum': [ u'saving', u'active'], u'type': u'string'}}, u'required': [u'size', u'md5', u'sha1', u'sha256', u'external', u'status', u'content_type'], u'required_on_activate': False, u'type': [u'object', u'null']}, u'bool1': {u'default': False, u'filter_ops': [u'eq'], u'glareType': u'Boolean', u'required_on_activate': False, u'type': [u'boolean', u'null']}, u'bool2': {u'default': False, u'filter_ops': [u'eq'], u'glareType': u'Boolean', u'required_on_activate': False, u'type': [u'boolean', u'null']}, u'link1': {u'filter_ops': [u'eq', u'neq'], u'glareType': u'Link', u'required_on_activate': False, u'type': [u'string', u'null']}, u'link2': {u'filter_ops': [u'eq', u'neq'], u'glareType': u'Link', u'required_on_activate': False, u'type': [u'string', u'null']}, u'dict_of_blobs': { u'additionalProperties': { u'additionalProperties': False, u'properties': { u'md5': {u'type': [u'string', u'null']}, u'sha1': {u'type': [u'string', u'null']}, u'sha256': {u'type': [u'string', u'null']}, u'content_type': { u'type': u'string'}, u'external': { u'type': u'boolean'}, u'size': { u'type': [ u'number', u'null']}, u'status': { u'enum': [ u'saving', u'active'], u'type': u'string'}}, u'required': [u'size', u'md5', u'sha1', u'sha256', u'external', u'status', u'content_type'], u'type': [u'object', u'null']}, u'default': {}, u'filter_ops': [], u'glareType': u'BlobDict', u'maxProperties': 255, u'required_on_activate': False, u'type': [u'object', u'null']}, u'dict_of_int': { u'additionalProperties': { u'type': u'integer'}, u'default': {}, u'filter_ops': [u'eq', u'in'], u'glareType': u'IntegerDict', u'maxProperties': 255, u'required_on_activate': False, u'type': [u'object', u'null']}, u'dict_of_links': {u'additionalProperties': {u'type': u'string'}, u'default': {}, u'filter_ops': [u'eq'], u'glareType': u'LinkDict', u'maxProperties': 255, u'mutable': True, u'required_on_activate': False, u'type': [u'object', u'null']}, u'list_of_links': {u'default': [], u'filter_ops': [u'eq'], u'glareType': u'LinkList', u'items': {u'type': u'string'}, u'maxItems': 255, u'mutable': True, u'required_on_activate': False, u'type': [u'array', u'null']}, u'dict_of_str': { u'additionalProperties': {u'maxLength': 255, u'type': u'string'}, u'default': {}, u'filter_ops': [u'eq', u'in'], u'glareType': u'StringDict', u'maxProperties': 255, u'required_on_activate': False, u'type': [u'object', u'null']}, u'dict_validators': { u'additionalProperties': False, u'filter_ops': [], u'glareType': u'StringDict', u'maxProperties': 3, u'properties': {u'abc': {u'maxLength': 255, u'type': [u'string', u'null']}, u'def': {u'maxLength': 255, u'type': [u'string', u'null']}, u'ghi': {u'maxLength': 255, u'type': [u'string', u'null']}, u'jkl': {u'maxLength': 255, u'type': [u'string', u'null']}}, u'required_on_activate': False, u'type': [u'object', u'null']}, u'float1': {u'filter_ops': [u'eq', u'neq', u'in', u'gt', u'gte', u'lt', u'lte'], u'glareType': u'Float', u'required_on_activate': False, u'sortable': True, u'type': [u'number', u'null']}, u'float2': {u'filter_ops': [u'eq', u'neq', u'in', u'gt', u'gte', u'lt', u'lte'], u'glareType': u'Float', u'required_on_activate': False, u'sortable': True, u'type': [u'number', u'null']}, u'int1': {u'filter_ops': [u'eq', u'neq', u'in', u'gt', u'gte', u'lt', u'lte'], u'glareType': u'Integer', u'required_on_activate': False, u'sortable': True, u'type': [u'integer', u'null']}, u'int2': {u'filter_ops': [u'eq', u'neq', u'in', u'gt', u'gte', u'lt', u'lte'], u'glareType': u'Integer', u'required_on_activate': False, u'sortable': True, u'type': [u'integer', u'null']}, u'int_validators': {u'filter_ops': [u'eq', u'neq', u'in', u'gt', u'gte', u'lt', u'lte'], u'glareType': u'Integer', u'maximum': 20, u'minimum': 10, u'required_on_activate': False, u'type': [u'integer', u'null']}, u'list_of_int': {u'default': [], u'filter_ops': [u'eq', u'in'], u'glareType': u'IntegerList', u'items': { u'type': u'integer'}, u'maxItems': 255, u'required_on_activate': False, u'type': [u'array', u'null']}, u'list_of_str': {u'default': [], u'filter_ops': [u'eq', u'in'], u'glareType': u'StringList', u'items': {u'maxLength': 255, u'type': u'string'}, u'maxItems': 255, u'required_on_activate': False, u'type': [u'array', u'null']}, u'list_validators': {u'default': [], u'filter_ops': [], u'glareType': u'StringList', u'items': {u'maxLength': 255, u'type': u'string'}, u'maxItems': 3, u'required_on_activate': False, u'type': [u'array', u'null'], u'uniqueItems': True}, u'small_blob': {u'additionalProperties': False, u'filter_ops': [], u'glareType': u'Blob', u'mutable': True, u'properties': { u'md5': {u'type': [u'string', u'null']}, u'sha1': {u'type': [u'string', u'null']}, u'sha256': {u'type': [u'string', u'null']}, u'content_type': { u'type': u'string'}, u'external': { u'type': u'boolean'}, u'size': { u'type': [ u'number', u'null']}, u'status': { u'enum': [ u'saving', u'active'], u'type': u'string'}}, u'required': [u'size', u'md5', u'sha1', u'sha256', u'external', u'status', u'content_type'], u'required_on_activate': False, u'type': [u'object', u'null']}, u'str1': {u'filter_ops': [u'like', u'eq', u'neq', u'in'], u'glareType': u'String', u'maxLength': 255, u'required_on_activate': False, u'sortable': True, u'type': [u'string', u'null']}, u'string_mutable': {u'filter_ops': [u'eq', u'neq', u'in'], u'glareType': u'String', u'maxLength': 255, u'mutable': True, u'required_on_activate': False, u'type': [u'string', u'null']}, u'string_regex': {u'filter_ops': [u'eq', u'neq', u'in'], u'glareType': u'String', u'maxLength': 255, u'pattern': u'^([0-9a-fA-F]){8}$', u'required_on_activate': False, u'type': [u'string', u'null']}, u'string_required': { u'filter_ops': [u'eq', u'neq', u'in'], u'glareType': u'String', u'maxLength': 255, u'type': [u'string', u'null']}, u'string_validators': { u'enum': [u'aa', u'bb', u'ccccccccccc'], u'filter_ops': [u'eq', u'neq', u'in'], u'glareType': u'String', u'maxLength': 10, u'required_on_activate': False, u'type': [u'string', u'null']}, u'system_attribute': {u'default': u'default', u'filter_ops': [u'eq', u'neq', u'in'], u'glareType': u'String', u'maxLength': 255, u'readOnly': True, u'sortable': True, u'type': [u'string', u'null']} }), u'required': [u'name'], u'title': u'Artifact type sample_artifact of version 1.0', u'version': u'1.0', u'type': u'object'}, u'tosca_templates': { u'name': u'tosca_templates', u'properties': generate_type_props({ u'template': { u'additionalProperties': False, u'description': u'TOSCA template body.', u'filter_ops': [], u'glareType': u'Blob', u'properties': { u'md5': {u'type': [u'string', u'null']}, u'sha1': {u'type': [u'string', u'null']}, u'sha256': {u'type': [u'string', u'null']}, u'content_type': { u'type': u'string'}, u'external': {u'type': u'boolean'}, u'size': {u'type': [u'number', u'null']}, u'status': {u'enum': [u'saving', u'active'], u'type': u'string'}}, u'required': [u'size', u'md5', u'sha1', u'sha256', u'external', u'status', u'content_type'], u'type': [u'object', u'null']}, u'template_format': {u'description': u'TOSCA template format.', u'filter_ops': [u'eq', u'neq', u'in'], u'glareType': u'String', u'maxLength': 255, u'type': [u'string', u'null']}, }), u'required': [u'name'], u'version': u'1.0', u'title': u'Artifact type tosca_templates of version 1.0', u'type': u'object'}, u'murano_packages': { u'name': u'murano_packages', u'properties': generate_type_props({ u'categories': { u'default': [], u'description': u'List of categories specified for ' u'the package.', u'filter_ops': [u'eq', u'neq', u'in'], u'glareType': u'StringList', u'items': {u'maxLength': 255, u'type': u'string'}, u'maxItems': 255, u'mutable': True, u'type': [u'array', u'null']}, u'class_definitions': { u'default': [], u'description': u'List of class definitions ' u'in the package.', u'filter_ops': [u'eq', u'neq', u'in'], u'glareType': u'StringList', u'items': {u'maxLength': 255, u'type': u'string'}, u'maxItems': 255, u'type': [u'array', u'null'], u'uniqueItems': True}, u'dependencies': { u'default': [], u'description': u'List of package dependencies for ' u'this package.', u'filter_ops': [u'eq', u'neq'], u'glareType': u'LinkList', u'items': {u'type': u'string'}, u'maxItems': 255, u'required_on_activate': False, u'type': [u'array', u'null']}, u'display_name': { u'description': u'Package name in human-readable format.', u'filter_ops': [u'eq', u'neq', u'in'], u'glareType': u'String', u'maxLength': 255, u'mutable': True, u'type': [u'string', u'null']}, u'inherits': { u'additionalProperties': {u'maxLength': 255, u'type': u'string'}, u'default': {}, u'filter_ops': [u'eq', u'neq', u'in'], u'glareType': u'StringDict', u'maxProperties': 255, u'type': [u'object', u'null']}, u'keywords': {u'default': [], u'filter_ops': [u'eq', u'neq', u'in'], u'glareType': u'StringList', u'items': {u'maxLength': 255, u'type': u'string'}, u'maxItems': 255, u'mutable': True, u'type': [u'array', u'null']}, u'package': { u'additionalProperties': False, u'description': u'Murano Package binary.', u'filter_ops': [], u'glareType': u'Blob', u'properties': {u'md5': {u'type': [u'string', u'null']}, u'sha1': {u'type': [u'string', u'null']}, u'sha256': {u'type': [u'string', u'null']}, u'content_type': {u'type': u'string'}, u'external': {u'type': u'boolean'}, u'size': {u'type': [u'number', u'null']}, u'status': {u'enum': [u'saving', u'active'], u'type': u'string'}}, u'required': [u'size', u'md5', u'sha1', u'sha256', u'external', u'status', u'content_type'], u'required_on_activate': False, u'type': [u'object', u'null']}, u'type': { u'default': u'Application', u'description': u'Package type.', u'enum': [u'Application', u'Library', ], u'filter_ops': [u'eq', u'neq', u'in'], u'glareType': u'String', u'type': [u'string', u'null']} }), u'required': [u'name'], u'version': u'1.0', u'title': u'Artifact type murano_packages of version 1.0', u'type': u'object'}, u'images': { u'name': u'images', u'properties': generate_type_props({ u'architecture': { u'description': u'Operating system architecture as specified ' u'in http://docs.openstack.org/trunk/' u'openstack-compute/admin/content/adding-' u'images.html', u'filter_ops': [u'eq', u'neq', u'in'], u'glareType': u'String', u'maxLength': 255, u'required_on_activate': False, u'type': [u'string', u'null']}, u'container_format': {u'description': u'Image container format.', u'enum': [u'ami', u'ari', u'aki', u'bare', u'ovf', u'ova', u'docker', ], u'filter_ops': [u'eq', u'neq', u'in'], u'glareType': u'String', u'type': [u'string', u'null']}, u'disk_format': {u'description': u'Image disk format.', u'enum': [u'ami', u'ari', u'aki', u'vhd', u'vhdx', u'vmdk', u'raw', u'qcow2', u'vdi', u'iso', ], u'filter_ops': [u'eq', u'neq', u'in'], u'glareType': u'String', u'type': [u'string', u'null']}, u'image': {u'additionalProperties': False, u'description': u'Image binary.', u'filter_ops': [], u'glareType': u'Blob', u'properties': { u'md5': {u'type': [u'string', u'null']}, u'sha1': {u'type': [u'string', u'null']}, u'sha256': {u'type': [u'string', u'null']}, u'content_type': {u'type': u'string'}, u'external': {u'type': u'boolean'}, u'size': {u'type': [u'number', u'null']}, u'status': {u'enum': [u'saving', u'active'], u'type': u'string'}}, u'required': [u'size', u'md5', u'sha1', u'sha256', u'external', u'status', u'content_type'], u'required_on_activate': False, u'type': [u'object', u'null']}, u'instance_uuid': { u'description': u'Metadata which can be used to record which ' u'instance this image is associated with. ' u'(Informational only, does not create an ' u'instance snapshot.)', u'filter_ops': [u'eq', u'neq', u'in'], u'glareType': u'String', u'maxLength': 255, u'required_on_activate': False, u'type': [u'string', u'null']}, u'kernel_id': { u'description': u'ID of image stored in Glare that should be ' u'used as the kernel when booting an ' u'AMI-style image.', u'filter_ops': [u'eq', u'neq', u'in'], u'glareType': u'String', u'maxLength': 255, u'pattern': u'^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-' u'([0-9a-fA-F]){4}-([0-9a-fA-F]){4}-' u'([0-9a-fA-F]){12}$', u'required_on_activate': False, u'type': [u'string', u'null']}, u'min_disk': { u'description': u'Minimal disk space required to boot image.', u'filter_ops': [u'eq', u'neq', u'in', u'gt', u'gte', u'lt', u'lte'], u'glareType': u'Integer', u'minimum': 0, u'required_on_activate': False, u'type': [u'integer', u'null']}, u'min_ram': { u'description': u'Minimal RAM required to boot image.', u'filter_ops': [u'eq', u'neq', u'in', u'gt', u'gte', u'lt', u'lte'], u'glareType': u'Integer', u'minimum': 0, u'required_on_activate': False, u'type': [u'integer', u'null']}, u'os_distro': { u'description': u'Common name of operating system distribution' u' as specified in http://docs.openstack.org/' u'trunk/openstack-compute/admin/content/' u'adding-images.html', u'filter_ops': [u'eq', u'neq', u'in'], u'glareType': u'String', u'maxLength': 255, u'required_on_activate': False, u'type': [u'string', u'null']}, u'os_version': { u'description': u'Operating system version as specified by the' u' distributor', u'filter_ops': [u'eq', u'neq', u'in'], u'glareType': u'String', u'maxLength': 255, u'required_on_activate': False, u'type': [u'string', u'null']}, u'ramdisk_id': { u'description': u'ID of image stored in Glare that should be ' u'used as the ramdisk when booting an ' u'AMI-style image.', u'filter_ops': [u'eq', u'neq', u'in'], u'glareType': u'String', u'maxLength': 255, u'pattern': u'^([0-9a-fA-F]){8}-([0-9a-fA-F]){4}-([0-9a-fA-F])' u'{4}-([0-9a-fA-F]){4}-([0-9a-fA-F]){12}$', u'required_on_activate': False, u'type': [u'string', u'null']}}), u'required': [u'name'], u'version': u'1.0', u'title': u'Artifact type images of version 1.0', u'type': u'object'}, u'heat_templates': { u'name': u'heat_templates', u'properties': generate_type_props({ u'default_envs': { u'additionalProperties': {u'maxLength': 255, u'type': u'string'}, u'default': {}, u'description': u'Default environments that can ' u'be applied to the template if no ' u'environments specified by user.', u'filter_ops': [u'eq', u'neq', u'in'], u'glareType': u'StringDict', u'maxProperties': 255, u'mutable': True, u'type': [u'object', u'null']}, u'environments': { u'additionalProperties': {u'type': u'string'}, u'default': {}, u'description': u'References to Heat Environments ' u'that can be used with current ' u'template.', u'filter_ops': [u'eq', u'neq'], u'glareType': u'LinkDict', u'maxProperties': 255, u'mutable': True, u'type': [u'object', u'null']}, u'nested_templates': { u'additionalProperties': {u'additionalProperties': False, u'properties': { u'md5': {u'type': [u'string', u'null']}, u'sha1': {u'type': [u'string', u'null']}, u'sha256': {u'type': [u'string', u'null']}, u'content_type': { u'type': u'string'}, u'external': {u'type': u'boolean'}, u'size': {u'type': [u'number', u'null']}, u'status': {u'enum': [u'saving', u'active'], u'type': u'string'}}, u'required': [u'size', u'md5', u'sha1', u'sha256', u'external', u'status', u'content_type'], u'type': [u'object', u'null']}, u'default': {}, u'description': u'Dict of nested templates where key is the ' u'name of template and value is nested ' u'template body.', u'filter_ops': [], u'glareType': u'BlobDict', u'maxProperties': 255, u'type': [u'object', u'null']}, u'template': { u'additionalProperties': False, u'description': u'Heat template body.', u'filter_ops': [], u'glareType': u'Blob', u'properties': { u'md5': {u'type': [u'string', u'null']}, u'sha1': {u'type': [u'string', u'null']}, u'sha256': {u'type': [u'string', u'null']}, u'content_type': { u'type': u'string'}, u'external': {u'type': u'boolean'}, u'size': {u'type': [u'number', u'null']}, u'status': {u'enum': [u'saving', u'active'], u'type': u'string'}}, u'required': [u'size', u'md5', u'sha1', u'sha256', u'external', u'status', u'content_type'], u'type': [u'object', u'null']}, }), u'version': u'1.0', u'required': [u'name'], u'title': u'Artifact type heat_templates of version 1.0', u'type': u'object'}, u'heat_environments': { u'name': u'heat_environments', u'properties': generate_type_props({ u'environment': { u'additionalProperties': False, u'description': u'Heat Environment text body.', u'filter_ops': [], u'glareType': u'Blob', u'properties': {u'md5': {u'type': [u'string', u'null']}, u'sha1': {u'type': [u'string', u'null']}, u'sha256': {u'type': [u'string', u'null']}, u'content_type': {u'type': u'string'}, u'external': {u'type': u'boolean'}, u'size': {u'type': [u'number', u'null']}, u'status': {u'enum': [u'saving', u'active'], u'type': u'string'}}, u'required': [u'size', u'md5', u'sha1', u'sha256', u'external', u'status', u'content_type'], u'type': [u'object', u'null']}, }), u'required': [u'name'], u'version': u'1.0', u'title': u'Artifact type heat_environments of version 1.0', u'type': u'object'}, u'all': { u'name': u'all', u'properties': generate_type_props({ u'type_name': {u'description': u'Name of artifact type.', u'filter_ops': [u'eq', u'neq', u'in'], u'glareType': u'String', u'maxLength': 255, u'sortable': True, u'type': [u'string', u'null']}, }), u'required': [u'name'], u'version': u'1.0', u'title': u'Artifact type all of version 1.0', u'type': u'object'} } class TestSchemas(base.TestArtifact): def test_schemas(self): # Get schemas for specific artifact type for at in self.enabled_types: result = self.get(url='/schemas/%s' % at) self.assertEqual(fixtures[at], result['schemas'][at]) # Get list schemas of artifacts result = self.get(url='/schemas') self.assertEqual(fixtures, result['schemas']) # Validation of schemas result = self.get(url='/schemas')['schemas'] for artifact_type, schema in result.items(): jsonschema.Draft4Validator.check_schema(schema)