def add_spec(self, spec, transforms): info = spec.get('info', {}) LOG.debug('Adding API: %s %s', info.get('title', 'untitled'), info.get('version', '0.0.0')) self.spec = spec self.spec_resolver = jsonschema.RefResolver('', self.spec) validate(copy.deepcopy(self.spec)) for filter in transforms: for (path, methods) in six.iteritems(spec['paths']): if not re.search(filter, path): continue for (method, endpoint) in six.iteritems(methods): conditions = {'method': [method.upper()]} connect_kw = {} if 'x-requirements' in endpoint: connect_kw['requirements'] = endpoint['x-requirements'] m = self.routes.submapper(_api_path=path, _api_method=method, conditions=conditions) for transform in transforms[filter]: m.connect(None, re.sub(filter, transform, path), **connect_kw) module_name = endpoint['operationId'].split(':', 1)[0] __import__(module_name) for route in sorted(self.routes.matchlist, key=lambda r: r.routepath): LOG.debug('Route registered: %+6s %s', route.conditions['method'][0], route.routepath)
def _match_references(self, schema, body): if '$ref' in schema: pass elif schema['type'] == 'array' and 'items' in schema and len(body) > 0: # Recurse into arrays. schema['items'] = self._match_references(schema['items'], body[0]) elif schema['type'] == 'object' and 'properties' in schema: if body == {}: # Don't match the empty object against loose definitions. return schema # Try to match the current object against a definition. for name, definition in self.existing_schema.get('definitions', {}).iteritems(): try: validate(definition, body, context=self.existing_schema) except flex.exceptions.ValidationError: pass else: return {'$ref': "#/definitions/%s" % name} # No definition matched; recurse into subschemas. for prop, prop_schema in schema['properties'].iteritems(): if prop in body: schema['properties'][prop] = self._match_references(prop_schema, body[prop]) return schema
def _validate_flex(self): from flex.exceptions import ValidationError from flex.core import parse as validate try: validate(self.specification) except ValidationError as ex: raise SwaggerValidationError(str(ex))
def test_not_instantiated(self): service = Service("IceCream", "/icecream/{flavour}") class IceCream(object): """ Ice cream service """ # Use GetRequestSchema and ResponseSchemas classes instead of objects @service.get(validators=(colander_validator, ), schema=GetRequestSchema) def view_get(self, request): """Serve icecream""" return self.request.validated @service.put(validators=(colander_validator, ), schema=PutRequestSchema()) def view_put(self, request): """Add flavour""" return self.request.validated self.service = service self.swagger = CorniceSwagger([self.service]) self.spec = self.swagger.generate() validate(self.spec)
def add_spec(self, spec, transforms): info = spec.get('info', {}) LOG.debug('Adding API: %s %s', info.get('title', 'untitled'), info.get('version', '0.0.0')) self.spec = spec self.spec_resolver = jsonschema.RefResolver('', self.spec) validate(copy.deepcopy(self.spec)) for filter in transforms: for (path, methods) in six.iteritems(spec['paths']): if not re.search(filter, path): continue for (method, endpoint) in six.iteritems(methods): conditions = { 'method': [method.upper()] } connect_kw = {} if 'x-requirements' in endpoint: connect_kw['requirements'] = endpoint['x-requirements'] m = self.routes.submapper(_api_path=path, _api_method=method, conditions=conditions) for transform in transforms[filter]: m.connect(None, re.sub(filter, transform, path), **connect_kw) module_name = endpoint['operationId'].split(':', 1)[0] __import__(module_name) for route in sorted(self.routes.matchlist, key=lambda r: r.routepath): LOG.debug('Route registered: %+6s %s', route.conditions['method'][0], route.routepath)
def test_validate_example_specs(test_data): """ This test is generated by conftest.py for each app in examples app and `test_data` param is: mod, client, specs_data, opts = test_data mod: examples.example_name (the test module) client: Flask app test client specs_data: {'url': {swag_specs}} for every spec in app opts: a dictionary of test metadata defined in the example :expectedresults: validate specs dictionary using flex """ mod, client, specs_data, opts = test_data skip_full_validation = opts.get('skip_full_validation', False) for url, spec in specs_data.items(): if 'openapi' not in spec and not skip_full_validation: # Flex can do a sophisticated and thorough validatation of # Swagger 2.0 specs, before it was renamed to OpenAPI. validate_fully(spec) else: # OpenAPI specs are not yet supported by flex, so we should fall # back to a fairly simple structural validation. validate(spec)
def test_swagger_field_overrides_extracted_paths(self): swagger = CorniceSwagger([self.service], param_ref=True) swagger.swagger = {'parameters': {'BodySchema': {'required': False}}} spec = swagger.generate() validate(self.spec) expected = {'name': 'BodySchema', 'required': False} self.assertDictContainsSubset(expected, spec['parameters']['BodySchema'])
def _validate_flex(self, spec_version): from flex.exceptions import ValidationError as JSEValidationError from flex.core import parse as validate try: validate(self.specification) except JSEValidationError as ex: from .util.exceptions import raise_from raise_from(ValidationError, ex) self.__set_version(BaseParser.SPEC_VERSION_2_PREFIX, spec_version)
def _validate_flex(self, spec_version): # Set the version independently of whether validation succeeds self.__set_version(BaseParser.SPEC_VERSION_2_PREFIX, spec_version) from flex.exceptions import ValidationError as JSEValidationError from flex.core import parse as validate try: validate(self.specification) except JSEValidationError as ex: from .util.exceptions import raise_from raise_from(ValidationError, ex)
def test_swagger_field_updates_extracted_paths(self): self.swagger.swagger = { 'definitions': { 'OtherDef': { 'additionalProperties': {} } } } spec = self.swagger.generate() validate(spec) self.assertEquals(spec['definitions'], self.swagger.swagger['definitions'])
def test_view_defined_operation_id(self): service = Service("IceCream", "/icecream/{flavour}") @service.get(operation_id='serve_icecream') def view_get(self, request): return service swagger = CorniceSwagger([service]) spec = swagger.generate() validate(spec) op_id = spec['paths']['/icecream/{flavour}']['get']['operationId'] self.assertEquals(op_id, 'serve_icecream')
def test_view_defined_tags(self): service = Service("IceCream", "/icecream/{flavour}") class IceCream(object): @service.get(tags=['cold', 'foo']) def view_get(self, request): return service swagger = CorniceSwagger([service]) spec = swagger.generate() validate(spec) tags = spec['paths']['/icecream/{flavour}']['get']['tags'] self.assertEquals(tags, ['cold', 'foo'])
def test_summary_docstrings_with_klass(self): class TemperatureCooler(object): def put_view(self): """Put it.""" pass service = Service("TemperatureCooler", "/freshair", klass=TemperatureCooler) service.add_view("put", "put_view") CorniceSwagger.services = [service] self.swagger = CorniceSwagger() self.spec = self.swagger.generate() validate(self.spec)
def test_validate_example_specs(test_data): """ This test is generated by conftest.py for each app in examples app and `test_data` param is: mod, client, specs_data = test_data mod: examples.example_name (the test module) client: Flask app test client specs_data: {'url': {swag_specs}} for every spec in app :expectedresults: validate specs dictionary using flex """ mod, client, specs_data = test_data for url, spec in specs_data.items(): validate(spec) # validate using Flex
def test_callable_default_tags(self): service = Service("IceCream", "/icecream/{flavour}") class IceCream(object): @service.get() def view_get(self, request): return service def default_tag_callable(service, method): return ['cold'] swagger = CorniceSwagger([service]) swagger.default_tags = default_tag_callable spec = swagger.generate() validate(spec) tags = spec['paths']['/icecream/{flavour}']['get']['tags'] self.assertEquals(tags, ['cold'])
def test_provided_tags_override_sorting(self): service = Service("IceCream", "/icecream/{flavour}") class IceCream(object): @service.get(tags=['cold', 'foo']) def view_get(self, request): return service swagger = CorniceSwagger([service]) tags = [{'name': 'foo', 'description': 'bar'}] swagger.swagger = {'tags': tags} spec = swagger.generate() validate(spec) self.assertListEqual([{ 'name': 'foo', 'description': 'bar' }, { 'name': 'cold' }], spec['tags'])
def test_view_defined_security(self): service = Service("IceCream", "/icecream/{flavour}") @service.get(api_security=[{'basicAuth': []}]) def view_get(self, request): return service swagger = CorniceSwagger([service]) swagger.swagger = { 'securityDefinitions': { 'basicAuth': { 'type': 'basic' } } } spec = swagger.generate() validate(spec) security = spec['paths']['/icecream/{flavour}']['get']['security'] self.assertEquals(security, [{'basicAuth': []}])
def add_spec(self, spec, transforms): info = spec.get("info", {}) LOG.debug( "Adding API: %s %s", info.get("title", "untitled"), info.get("version", "0.0.0"), ) self.spec = spec self.spec_resolver = jsonschema.RefResolver("", self.spec) validate(fast_deepcopy_dict(self.spec)) for filter in transforms: for (path, methods) in six.iteritems(spec["paths"]): if not re.search(filter, path): continue for (method, endpoint) in six.iteritems(methods): conditions = {"method": [method.upper()]} connect_kw = {} if "x-requirements" in endpoint: connect_kw["requirements"] = endpoint["x-requirements"] m = self.routes.submapper(_api_path=path, _api_method=method, conditions=conditions) for transform in transforms[filter]: m.connect(None, re.sub(filter, transform, path), **connect_kw) module_name = endpoint["operationId"].split(":", 1)[0] __import__(module_name) for route in sorted(self.routes.matchlist, key=lambda r: r.routepath): LOG.debug( "Route registered: %+6s %s", route.conditions["method"][0], route.routepath, )
def test_callable_default_security(self): def get_security(service, method): definitions = service.definitions for definition in definitions: met, view, args = definition if met == method: break if 'security' in args: return [{'basicAuth': []}] else: return [] service = Service("IceCream", "/icecream/{flavour}") @service.get() def view_get(self, request): return service @service.post(security='foo') def view_post(self, request): return service swagger = CorniceSwagger([service]) swagger.swagger = { 'securityDefinitions': { 'basicAuth': { 'type': 'basic' } } } swagger.default_security = get_security spec = swagger.generate() validate(spec) security = spec['paths']['/icecream/{flavour}']['post']['security'] self.assertEquals(security, [{'basicAuth': []}]) security = spec['paths']['/icecream/{flavour}']['get']['security'] self.assertEquals(security, [])
def test_default_operation_ids(self): service = Service("IceCream", "/icecream/{flavour}") @service.get() def view_get(self, request): return service @service.put() def view_put(self, request): return service def op_id_generator(service, method): return '%s_%s' % (method.lower(), service.path.split('/')[-2]) swagger = CorniceSwagger([service]) swagger.default_op_ids = op_id_generator spec = swagger.generate() validate(spec) op_id = spec['paths']['/icecream/{flavour}']['get']['operationId'] self.assertEquals(op_id, 'get_icecream') op_id = spec['paths']['/icecream/{flavour}']['put']['operationId'] self.assertEquals(op_id, 'put_icecream')
def setUp(self): service = Service("IceCream", "/icecream/{flavour}") class IceCream(object): @service.get(validators=(colander_validator, ), schema=GetRequestSchema(), response_schemas=response_schemas) def view_get(self, request): """Serve ice cream""" return self.request.validated @service.put(validators=(colander_validator, ), schema=PutRequestSchema()) def view_put(self, request): """Add flavour""" return self.request.validated self.service = service CorniceSwagger.services = [self.service] CorniceSwagger.api_title = 'IceCreamAPI' CorniceSwagger.api_version = '4.2' self.swagger = CorniceSwagger() self.spec = self.swagger.generate() validate(self.spec)
import requests from flex.core import load, validate, validate_api_call from flex.exceptions import ValidationError dir_path = os.path.dirname(os.path.realpath(__file__)) platform = sys.argv[1] base_url = sys.argv[2] paths = glob.glob(os.path.join(dir_path, "../", "definitions", platform) + "/**/*.yml", recursive=True) exitcode = 0 for path in paths: schema = load(path) validate(schema) matches = re.match(".*/api(?P<path>.+)[.]yml$", path) if not matches: continue uri = "/api" + matches.group("path") print("testing endpoint %s... " % uri, end="", flush=True) response = requests.get(base_url + uri, verify=False) try: validate_api_call(schema, raw_request=response.request, raw_response=response) except ValidationError as ve: print("failed\n\n" + str(ve) + "\n") exitcode = 1
def test_openapis_schema(get, schema): validate(schema)
def validate_schema(): "validates the api schema" path = join(conf.PROJECT_DIR, 'schema', 'api.yaml') spec = flex.load(path) validate(spec) return True
def validate_schema(): "validates the api schema" path = join(conf.PROJECT_DIR, 'schema', 'api.yaml') spec = flex.load(path) validate(spec) return True
def test_with_resp_ref(self): swagger = CorniceSwagger([self.service], resp_ref=True) spec = swagger.generate() validate(spec) self.assertIn('responses', spec)
def test_with_param_ref(self): swagger = CorniceSwagger([self.service], param_ref=True) spec = swagger.generate() validate(spec) self.assertIn('parameters', spec)
def test_with_schema_ref(self): swagger = CorniceSwagger([self.service], def_ref_depth=1) spec = swagger.generate() validate(spec) self.assertIn('definitions', spec)
def test_validate_spec(self): spec = self.app.get('/api-explorer/swagger.json').json validate(spec)
def test_validate_spec(self): spec = self.app.get('/api').json validate(spec)
def test_summary_docstrings(self): self.swagger.summary_docstrings = True self.spec = self.swagger.generate() validate(self.spec) summary = self.spec['paths']['/icecream/{flavour}']['get']['summary'] self.assertEquals(summary, 'Serve ice cream')
def test_openapis_schema(get, schema): validate(schema)