Configuration schema are checked against jsonschema draft 4 meta-schema (#10247)

fixes #10246
This commit is contained in:
Massimiliano Culpo 2019-08-27 17:31:18 +02:00 committed by Todd Gamblin
parent dce9fc4d63
commit 2e8aa6cb24
3 changed files with 197 additions and 3 deletions

View File

@ -0,0 +1,149 @@
{
"id": "http://json-schema.org/draft-04/schema#",
"$schema": "http://json-schema.org/draft-04/schema#",
"description": "Core schema meta-schema",
"definitions": {
"schemaArray": {
"type": "array",
"minItems": 1,
"items": { "$ref": "#" }
},
"positiveInteger": {
"type": "integer",
"minimum": 0
},
"positiveIntegerDefault0": {
"allOf": [ { "$ref": "#/definitions/positiveInteger" }, { "default": 0 } ]
},
"simpleTypes": {
"enum": [ "array", "boolean", "integer", "null", "number", "object", "string" ]
},
"stringArray": {
"type": "array",
"items": { "type": "string" },
"minItems": 1,
"uniqueItems": true
}
},
"type": "object",
"properties": {
"id": {
"type": "string"
},
"$schema": {
"type": "string"
},
"title": {
"type": "string"
},
"description": {
"type": "string"
},
"default": {},
"multipleOf": {
"type": "number",
"minimum": 0,
"exclusiveMinimum": true
},
"maximum": {
"type": "number"
},
"exclusiveMaximum": {
"type": "boolean",
"default": false
},
"minimum": {
"type": "number"
},
"exclusiveMinimum": {
"type": "boolean",
"default": false
},
"maxLength": { "$ref": "#/definitions/positiveInteger" },
"minLength": { "$ref": "#/definitions/positiveIntegerDefault0" },
"pattern": {
"type": "string",
"format": "regex"
},
"additionalItems": {
"anyOf": [
{ "type": "boolean" },
{ "$ref": "#" }
],
"default": {}
},
"items": {
"anyOf": [
{ "$ref": "#" },
{ "$ref": "#/definitions/schemaArray" }
],
"default": {}
},
"maxItems": { "$ref": "#/definitions/positiveInteger" },
"minItems": { "$ref": "#/definitions/positiveIntegerDefault0" },
"uniqueItems": {
"type": "boolean",
"default": false
},
"maxProperties": { "$ref": "#/definitions/positiveInteger" },
"minProperties": { "$ref": "#/definitions/positiveIntegerDefault0" },
"required": { "$ref": "#/definitions/stringArray" },
"additionalProperties": {
"anyOf": [
{ "type": "boolean" },
{ "$ref": "#" }
],
"default": {}
},
"definitions": {
"type": "object",
"additionalProperties": { "$ref": "#" },
"default": {}
},
"properties": {
"type": "object",
"additionalProperties": { "$ref": "#" },
"default": {}
},
"patternProperties": {
"type": "object",
"additionalProperties": { "$ref": "#" },
"default": {}
},
"dependencies": {
"type": "object",
"additionalProperties": {
"anyOf": [
{ "$ref": "#" },
{ "$ref": "#/definitions/stringArray" }
]
}
},
"enum": {
"type": "array",
"minItems": 1,
"uniqueItems": true
},
"type": {
"anyOf": [
{ "$ref": "#/definitions/simpleTypes" },
{
"type": "array",
"items": { "$ref": "#/definitions/simpleTypes" },
"minItems": 1,
"uniqueItems": true
}
]
},
"format": { "type": "string" },
"allOf": { "$ref": "#/definitions/schemaArray" },
"anyOf": { "$ref": "#/definitions/schemaArray" },
"oneOf": { "$ref": "#/definitions/schemaArray" },
"not": { "$ref": "#" }
},
"dependencies": {
"exclusiveMaximum": [ "maximum" ],
"exclusiveMinimum": [ "minimum" ]
},
"default": {}
}

View File

@ -42,7 +42,10 @@
os.path.join(spack_lib_path, 'external', 'jinja2', 'asyncfilters.py'),
os.path.join(spack_lib_path, 'external', 'jinja2', 'asyncsupport.py'),
os.path.join(spack_lib_path, 'external', 'yaml', 'lib3'),
os.path.join(spack_lib_path, 'external', 'pyqver3.py')]
os.path.join(spack_lib_path, 'external', 'pyqver3.py'),
# Uses importlib
os.path.join(spack_lib_path, 'spack', 'test', 'schema.py')
]
else:
import pyqver3 as pyqver
@ -55,7 +58,10 @@
os.path.join(spack_lib_path, 'external', 'jinja2', 'asyncfilters.py'),
os.path.join(spack_lib_path, 'external', 'jinja2', 'asyncsupport.py'),
os.path.join(spack_lib_path, 'external', 'yaml', 'lib'),
os.path.join(spack_lib_path, 'external', 'pyqver2.py')]
os.path.join(spack_lib_path, 'external', 'pyqver2.py'),
# Uses importlib
os.path.join(spack_lib_path, 'spack', 'test', 'schema.py')
]
def pyfiles(search_paths, exclude=()):

View File

@ -3,10 +3,14 @@
#
# SPDX-License-Identifier: (Apache-2.0 OR MIT)
import json
import os.path
import sys
import jsonschema
import pytest
import spack.paths
import spack.schema
@ -50,6 +54,17 @@ def module_suffixes_schema():
}
@pytest.fixture(scope='module')
def meta_schema():
"""Meta schema for JSON schema validation (Draft 4)"""
meta_schema_file = os.path.join(
spack.paths.test_path, 'data', 'jsonschema_meta.json'
)
with open(meta_schema_file) as f:
ms = json.load(f)
return ms
@pytest.mark.regression('9857')
def test_validate_spec(validate_spec_schema):
v = spack.schema.Validator(validate_spec_schema)
@ -75,3 +90,27 @@ def test_module_suffixes(module_suffixes_schema):
v.validate(data)
assert 'is an invalid spec' in str(exc_err.value)
@pytest.mark.regression('10246')
@pytest.mark.skipif(
sys.version_info < (2, 7),
reason='requires python2.7 or higher because of importlib')
@pytest.mark.parametrize('config_name', [
'compilers',
'config',
'env',
'merged',
'mirrors',
'modules',
'packages',
'repos'
])
def test_schema_validation(meta_schema, config_name):
import importlib
module_name = 'spack.schema.{0}'.format(config_name)
module = importlib.import_module(module_name)
schema = getattr(module, 'schema')
# If this validation throws the test won't pass
jsonschema.validate(schema, meta_schema)