diff --git a/importers/test/test_djornl_parser.py b/importers/test/test_djornl_parser.py index 763eea5d..4f95f645 100644 --- a/importers/test/test_djornl_parser.py +++ b/importers/test/test_djornl_parser.py @@ -3,6 +3,8 @@ At the present time, this just ensures that the files are parsed correctly; it does not check data loading into the db. + +These tests run within the re_api docker image. """ import json import unittest diff --git a/relation_engine_server/README.md b/relation_engine_server/README.md index 1689158d..e500b29a 100644 --- a/relation_engine_server/README.md +++ b/relation_engine_server/README.md @@ -271,7 +271,7 @@ Example response: Get the schema for a specific data source ```sh -GET "{root_url}/api/v1/specs/data_source?name=ncbi_taxonomy" +GET "{root_url}/api/v1/specs/data_sources?name=ncbi_taxonomy" ``` Example response: @@ -338,7 +338,7 @@ Example response: Get the schema for a specific stored query ```sh -GET "{root_url}/api/v1/specs/stored_query?name=ncbi_fetch_taxon" +GET "{root_url}/api/v1/specs/stored_queries?name=ncbi_fetch_taxon" ``` Example response: diff --git a/relation_engine_server/test/data/json_validation/fruit.yaml b/relation_engine_server/test/data/json_validation/fruit.yaml new file mode 100644 index 00000000..75e2acf7 --- /dev/null +++ b/relation_engine_server/test/data/json_validation/fruit.yaml @@ -0,0 +1,9 @@ +$schema: "http://json-schema.org/draft-07/schema#" +name: fruit +type: string +oneOf: + - const: peach + - const: plum + - const: dragonfruit + - const: strawberry + - const: pear diff --git a/relation_engine_server/test/data/json_validation/fruits_array.yaml b/relation_engine_server/test/data/json_validation/fruits_array.yaml new file mode 100644 index 00000000..ed6c710f --- /dev/null +++ b/relation_engine_server/test/data/json_validation/fruits_array.yaml @@ -0,0 +1,13 @@ +$schema: "http://json-schema.org/draft-07/schema#" +name: fruits_array +definitions: + fruits: + type: array + items: + $ref: fruit.yaml + default: [] + uniqueItems: true + examples: + - ['peach', 'plum'] + - ['strawberry'] + - [] diff --git a/relation_engine_server/test/data/json_validation/invalid_array.json b/relation_engine_server/test/data/json_validation/invalid_array.json deleted file mode 100644 index 438e32c0..00000000 --- a/relation_engine_server/test/data/json_validation/invalid_array.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "invalid_array", - "distance": 1, - "fruits": "pear" -} diff --git a/relation_engine_server/test/data/json_validation/invalid_array.yaml b/relation_engine_server/test/data/json_validation/invalid_array.yaml deleted file mode 100644 index 6471b4f4..00000000 --- a/relation_engine_server/test/data/json_validation/invalid_array.yaml +++ /dev/null @@ -1,3 +0,0 @@ -name: invalid_array -distance: 1 -fruits: pear diff --git a/relation_engine_server/test/data/json_validation/invalid_array_items.json b/relation_engine_server/test/data/json_validation/invalid_array_items.json deleted file mode 100644 index 2341cd7b..00000000 --- a/relation_engine_server/test/data/json_validation/invalid_array_items.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "invalid_array", - "distance": 1, - "fruits": ["pear", 1, "peach"] -} diff --git a/relation_engine_server/test/data/json_validation/invalid_array_items.yaml b/relation_engine_server/test/data/json_validation/invalid_array_items.yaml deleted file mode 100644 index 6a1be689..00000000 --- a/relation_engine_server/test/data/json_validation/invalid_array_items.yaml +++ /dev/null @@ -1,6 +0,0 @@ -name: invalid_array -distance: 1 -fruits: - - pear - - 1 - - peach diff --git a/relation_engine_server/test/data/json_validation/test_schema.json b/relation_engine_server/test/data/json_validation/test_schema.json index 465836d7..d0e93a98 100644 --- a/relation_engine_server/test/data/json_validation/test_schema.json +++ b/relation_engine_server/test/data/json_validation/test_schema.json @@ -33,8 +33,10 @@ "fruits": { "type": "array", "items": { - "type": "string" - } + "$ref": "fruit.yaml" + }, + "default": [], + "uniqueItems": "true" } } } diff --git a/relation_engine_server/test/data/json_validation/test_schema.yaml b/relation_engine_server/test/data/json_validation/test_schema.yaml index 164d5101..bbdc0707 100644 --- a/relation_engine_server/test/data/json_validation/test_schema.yaml +++ b/relation_engine_server/test/data/json_validation/test_schema.yaml @@ -27,4 +27,10 @@ properties: fruits: type: array items: - type: string + $ref: fruit.yaml + default: [] + uniqueItems: true + examples: + - ['peach', 'plum'] + - ['strawberry'] + - [] diff --git a/relation_engine_server/test/data/json_validation/valid_array.json b/relation_engine_server/test/data/json_validation/valid_array.json deleted file mode 100644 index 77d95f7f..00000000 --- a/relation_engine_server/test/data/json_validation/valid_array.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "name": "valid_array", - "distance": 3, - "fruits": ["pear", "plum"] -} diff --git a/relation_engine_server/test/data/json_validation/valid_array.yaml b/relation_engine_server/test/data/json_validation/valid_array.yaml deleted file mode 100644 index 79546e4b..00000000 --- a/relation_engine_server/test/data/json_validation/valid_array.yaml +++ /dev/null @@ -1,5 +0,0 @@ -name: valid_array -distance: 3 -fruits: - - pear - - plum diff --git a/relation_engine_server/test/data/json_validation/valid_uri.yaml b/relation_engine_server/test/data/json_validation/valid_uri.yaml index 2fe93df3..e31a0c49 100644 --- a/relation_engine_server/test/data/json_validation/valid_uri.yaml +++ b/relation_engine_server/test/data/json_validation/valid_uri.yaml @@ -1,3 +1,3 @@ name: valid_uri distance: 3 -home_page: "http://json-validation.com:5000/this/is/valid" +home_page: http://json-validation.com:5000/this/is/valid diff --git a/relation_engine_server/test/spec_release/README.md b/relation_engine_server/test/spec_release/README.md index a371c2e3..61d16dce 100644 --- a/relation_engine_server/test/spec_release/README.md +++ b/relation_engine_server/test/spec_release/README.md @@ -2,13 +2,27 @@ `sample_spec_release`, and the corresponding archive, `spec.tar.gz`, contain a set of sample schema files suitable for use in tests. -To create a new version of `spec.tar.gz`, you will need to exec into the `re_api` docker image to ensure that the new archive and its contents have the appropriate file owner and permissions (all files must have owner and group `root`/`root`). +To create a new version of `spec.tar.gz`, you will need to open a shell into the `re_api` docker image and create the new archive there to ensure that the new archive and its contents have the appropriate file owner and permissions (all files must have owner and group `root`/`root`). -Example commands: +Ensure that you have mounted your current working directory as `/app` in the docker `re_api` image by uncommenting the lines in `docker-compose.yaml`: +``` yaml + re_api: + ( ... ) +# uncomment to mount local directories + volumes: + - ${PWD}:/app ``` + +Run `make shell` to start up the docker container, and then get the ID of the current `re_api` image. Exec into the `re_api` image via the Docker Desktop client or the command line: + +``` sh $ docker exec -it relation_engine_re_api_run_1234567890 sh -# # in the docker image +``` + +Example commands for updating `spec.tar.gz`: + +``` sh # cd relation_engine_server/test/spec_release # # ... perform any edits ... # tar -czvf new_spec.tar.gz sample_spec_release/ diff --git a/relation_engine_server/test/test_api_v1.py b/relation_engine_server/test/test_api_v1.py index f5de696d..b309fe23 100644 --- a/relation_engine_server/test/test_api_v1.py +++ b/relation_engine_server/test/test_api_v1.py @@ -1,7 +1,7 @@ """ Simple integration tests on the API itself. -We make actual ajax requests to the running docker container. +These tests run within the re_api docker image, and require access to the ArangoDB, auth, and workspace images. """ import unittest import requests diff --git a/relation_engine_server/test/test_json_validation.py b/relation_engine_server/test/test_json_validation.py index e7dbc7ee..501b786f 100644 --- a/relation_engine_server/test/test_json_validation.py +++ b/relation_engine_server/test/test_json_validation.py @@ -12,6 +12,7 @@ Other validation tests are at the bottom of the file. +These tests run within the re_api docker image. """ import unittest import os.path as os_path @@ -21,6 +22,10 @@ from jsonschema.exceptions import ValidationError, RefResolutionError from jsonpointer import JsonPointerException +test_data_dirs = ['/app', 'relation_engine_server', 'test', 'data'] +json_validation_dir = os_path.join(*(test_data_dirs + ['json_validation'])) +schema_refs_dir = os_path.join(*(test_data_dirs + ['schema_refs'])) + test_schema = { 'properties': { @@ -50,22 +55,57 @@ 'format': 'date', }, 'fruits': { - 'title': 'Fruits', 'type': 'array', - 'uniqueItems': True, 'items': { - 'type': 'string' - } + 'name': 'fruit', + 'type': 'string', + 'oneOf': [ + {'const': 'peach'}, + {'const': 'plum'}, + {'const': 'pear'}, + {'const': 'strawberry'}, + ] + }, + 'default': [], + 'uniqueItems': True } } } } } +fruits_explicit = { + 'type': 'array', + 'items': { + 'name': 'fruit', + 'type': 'string', + 'oneOf': [ + {'const': 'peach'}, + {'const': 'plum'}, + {'const': 'pear'}, + {'const': 'strawberry'}, + ] + }, + 'default': [], + 'uniqueItems': True +} + +fruits_array_ref = { + '$ref': 'file://' + os_path.join(json_validation_dir, 'fruits_array.yaml') + + '#/definitions/fruits' +} + +fruit_ref = { + 'type': 'array', + 'items': { + '$ref': 'file://' + os_path.join(json_validation_dir, 'fruit.yaml') + }, + 'default': [], + 'uniqueItems': True +} + valid_json_loc = '/properties/params' -test_data_dirs = ['/app', 'relation_engine_server', 'test', 'data'] -json_validation_dir = os_path.join(*(test_data_dirs + ['json_validation'])) -schema_refs_dir = os_path.join(*(test_data_dirs + ['schema_refs'])) +schema_defaults = {'name': 'blank', 'distance': 1, 'fruits': []} test_schema_list = [ ['schema', test_schema], @@ -138,8 +178,11 @@ def test_non_validation_validator_errors(self): output = run_validator( schema=test_schema, data={'name': 'name', 'distance': 3}, - validate_at='/properties/params') - self.assertEqual(output, {'name': 'name', 'distance': 3}) + validate_at=valid_json_loc) + self.assertEqual( + output, + {**schema_defaults, **{'name': 'name', 'distance': 3}} + ) def test_json_validation(self): """ Generic JSON validation tests to ensure that all is working as expected """ @@ -161,8 +204,45 @@ def test_json_validation(self): else: schema_arg = None - for test in test_list: - test(schema_arg, schema_file_arg) + for test_name in test_list: + with self.subTest(test_name=test_name.__name__): + test_name(schema_arg, schema_file_arg) + + def execute_tests(self, schema_arg, schema_file_arg, tests, file_types=[None, 'json', 'yaml']): + + for t in tests: + for file_ext in file_types: + data = t['input'] + data_file = os_path.join(json_validation_dir, f"{t['file']}.{file_ext}") + if file_ext is None: + data_file = None + else: + data = None + + with self.subTest(input=t['input'], file_type=file_ext): + if 'err_str' in t: + with self.assertRaisesRegex(ValidationError, t['err_str']): + run_validator( + schema=schema_arg, + schema_file=schema_file_arg, + data=data, + data_file=data_file, + validate_at=valid_json_loc) + + else: + output = run_validator( + schema=schema_arg, + schema_file=schema_file_arg, + data=data, + data_file=data_file, + validate_at=valid_json_loc) + self.assertEqual( + output, + { + **schema_defaults, + **t['output'] + } + ) def test_add_defaults(self, schema_arg=None, schema_file_arg=None): """Test that the jsonschema validator sets default values.""" @@ -172,24 +252,15 @@ def test_add_defaults(self, schema_arg=None, schema_file_arg=None): self.assertTrue(True) return - test_data = run_validator( - schema=schema_arg, - schema_file=schema_file_arg, - data={}, - validate_at=valid_json_loc) - self.assertEqual(test_data, {'name': 'blank', 'distance': 1}) + tests = [ + { + 'input': {}, + 'file': 'defaults', + 'output': schema_defaults, + } + ] - for file_ext in ['json', 'yaml']: - file_path = os_path.join(json_validation_dir, 'defaults.' + file_ext) - self.assertEqual( - run_validator( - schema=schema_arg, - schema_file=schema_file_arg, - data_file=file_path, - validate_at=valid_json_loc - ), - {'name': 'blank', 'distance': 1} - ) + self.execute_tests(schema_arg, schema_file_arg, tests) def test_pattern_validation(self, schema_arg=None, schema_file_arg=None): '''Test pattern validation''' @@ -199,43 +270,22 @@ def test_pattern_validation(self, schema_arg=None, schema_file_arg=None): self.assertTrue(True) return - # validation error - string does not match regex - err_str = "'Mr Blobby' does not match .*?" - with self.assertRaisesRegex(ValidationError, err_str): - run_validator( - schema=schema_arg, - schema_file=schema_file_arg, - data={'name': 'Mr Blobby', 'distance': 3}, - validate_at=valid_json_loc) - - # this string is OK - output = run_validator( - schema=schema_arg, - schema_file=schema_file_arg, - data={'name': 'Mr_Blobby_666', 'distance': 3}, - validate_at=valid_json_loc) - self.assertEqual(output, {'name': 'Mr_Blobby_666', 'distance': 3}) - - for file_ext in ['json', 'yaml']: - # validation error - string does not match regex - err_str = '"what\'s-the-problem with-this-string\?" does not match .*?' - file_path = os_path.join(json_validation_dir, 'invalid_pattern.' + file_ext) - with self.assertRaisesRegex(ValidationError, err_str): - run_validator( - schema=schema_arg, - schema_file=schema_file_arg, - data_file=file_path, - validate_at=valid_json_loc) - - file_path = os_path.join(json_validation_dir, 'valid_pattern.' + file_ext) - self.assertEqual( - run_validator( - schema=schema_arg, - schema_file=schema_file_arg, - data_file=file_path, - validate_at=valid_json_loc), - {'name': 'No_problem_with_this_string', 'distance': 3} - ) + tests = [ + { + 'input': {"name": "what's-the-problem with-this-string?", "distance": 3}, + 'file': 'invalid_pattern', + 'err_str': '"what\'s-the-problem with-this-string\?" does not match .*?', + }, + { + 'input': {"name": "No_problem_with_this_string", "distance": 3}, + 'file': 'valid_pattern', + 'output': { + 'name': 'No_problem_with_this_string', + 'distance': 3, + } + } + ] + self.execute_tests(schema_arg, schema_file_arg, tests) def test_uri_validation(self, schema_arg=None, schema_file_arg=None): '''Test URI validation is operational''' @@ -245,47 +295,28 @@ def test_uri_validation(self, schema_arg=None, schema_file_arg=None): self.assertTrue(True) return - err_str = "'where is it\?' is not a 'uri'" - with self.assertRaisesRegex(ValidationError, err_str): - run_validator( - schema=schema_arg, - schema_file=schema_file_arg, - data={'name': 'blank', 'distance': 3, 'home_page': 'where is it?'}, - validate_at=valid_json_loc) - - # this string is OK - input = {'name': 'valid_uri', 'distance': 3, 'home_page': 'http://www.home.com'} - output = run_validator( - schema=schema_arg, - schema_file=schema_file_arg, - data=input, - validate_at=valid_json_loc) - self.assertEqual(output, input) - - # data files - for file_ext in ['json', 'yaml']: - file_path = os_path.join(json_validation_dir, 'invalid_uri.' + file_ext) - err_str = "'where is it\?' is not a 'uri'" - with self.assertRaisesRegex(ValidationError, err_str): - run_validator( - schema=schema_arg, - schema_file=schema_file_arg, - data_file=file_path, - validate_at=valid_json_loc) - - file_path = os_path.join(json_validation_dir, 'valid_uri.' + file_ext) - self.assertEqual( - run_validator( - schema=schema_arg, - schema_file=schema_file_arg, - data_file=file_path, - validate_at=valid_json_loc), - { - "name": "valid_uri", - "distance": 3, + tests = [ + { + 'input': { + 'name': 'valid_uri', + 'distance': 3, + "home_page": "http://json-validation.com:5000/this/is/valid" + }, + 'file': 'valid_uri', + 'output': { + 'name': 'valid_uri', + 'distance': 3, "home_page": "http://json-validation.com:5000/this/is/valid" } - ) + }, + { + 'input': {'name': 'invalid_uri', 'home_page': 'where is it?'}, + 'file': 'invalid_uri', + 'err_str': "'where is it\?' is not a 'uri'" + }, + ] + + self.execute_tests(schema_arg, schema_file_arg, tests) def test_date_format_validation(self, schema_arg=None, schema_file_arg=None): '''ensure that fancy date formats are correctly validated''' @@ -295,58 +326,30 @@ def test_date_format_validation(self, schema_arg=None, schema_file_arg=None): self.assertTrue(True) return - err_str = "'202001017' is not a 'date'" - with self.assertRaisesRegex(ValidationError, err_str): - input = {'name': 'whatever', 'distance': 1, 'date': '202001017'} - run_validator( - schema=schema_arg, - schema_file=schema_file_arg, - data=input, - validate_at=valid_json_loc) - - input = {'name': 'whatever', 'distance': 1, 'date': '2020-05-23'} - output = run_validator( - schema=schema_arg, - schema_file=schema_file_arg, - data=input, - validate_at=valid_json_loc) - self.assertEqual(input, output) - - # data files - for file_ext in ['json', 'yaml']: - # invalid type (number instead of string) - file_path = os_path.join(json_validation_dir, 'invalid_date_type.' + file_ext) - err_str = "20200606 is not of type 'string'" - with self.assertRaisesRegex(ValidationError, err_str): - run_validator( - schema=schema_arg, - schema_file=schema_file_arg, - data_file=file_path, - validate_at=valid_json_loc) - - # quoted string but not in the correct format - file_path = os_path.join(json_validation_dir, 'invalid_date.' + file_ext) - err_str = "'20200606' is not a 'date'" - with self.assertRaisesRegex(ValidationError, err_str): - run_validator( - schema=schema_arg, - schema_file=schema_file_arg, - data_file=file_path, - validate_at=valid_json_loc) - - file_path = os_path.join(json_validation_dir, 'valid_date.' + file_ext) - self.assertEqual( - run_validator( - schema=schema_arg, - schema_file=schema_file_arg, - data_file=file_path, - validate_at=valid_json_loc), - { + tests = [ + { + 'input': {'date': '20200606'}, + 'file': 'invalid_date', + 'err_str': "'20200606' is not a 'date'", + }, + { + 'input': {'date': 20200606}, + 'file': 'invalid_date_type', + 'err_str': "20200606 is not of type 'string'" + }, + { + 'input': {"name": "valid_date", "date": "2020-06-06", "distance": 3}, + 'file': 'valid_date', + 'output': { + **schema_defaults, "name": "valid_date", "date": "2020-06-06", "distance": 3, } - ) + } + ] + + self.execute_tests(schema_arg, schema_file_arg, tests) # pyyaml-specific issue: dates get automatically parsed into datetime objects (doh!) file_path = os_path.join(json_validation_dir, 'unquoted_date.yaml') @@ -359,72 +362,74 @@ def test_date_format_validation(self, schema_arg=None, schema_file_arg=None): validate_at=valid_json_loc) def test_array_validation(self, schema_arg=None, schema_file_arg=None): - """ check array validation works correctly """ + """ + check array validation and default population works correctly when refs are used + + The current implementation of the population of defaults does not allow defaults to be + populated if the property is a reference, i.e. + + 'properties': { + 'fruits': { + '$ref': '...' + } + } + + """ # skip if the test is not being called from test_json_validation if schema_arg is None and schema_file_arg is None: self.assertTrue(True) return - err_str = "'pear' is not of type 'array'" - with self.assertRaisesRegex(ValidationError, err_str): - run_validator( - schema=schema_arg, - schema_file=schema_file_arg, - data={'name': 'blank', 'distance': 3, 'fruits': 'pear'}, - validate_at=valid_json_loc) - - err_str = "1 is not of type 'string'" - with self.assertRaisesRegex(ValidationError, err_str): - run_validator( - schema=schema_arg, - schema_file=schema_file_arg, - data={'name': 'blank', 'distance': 3, 'fruits': ['pear', 1, 'peach']}, - validate_at=valid_json_loc) + # test the use of refs when populating defaults + tests = [ + { + 'fruits': fruit_ref, + 'name': 'using fruit.yaml -- array item is a ref', + 'output': { + 'params': { + 'name': 'name', + 'distance': 1, + 'fruits': [] + } + } + }, + { + # N.b. the default does not get populated in this case! + # This is a change from the expected functionality + 'fruits': fruits_array_ref, + 'name': 'using fruits_array.yaml -- the array is a ref', + 'output': { + 'params': { + 'name': 'name', + 'distance': 1, + } + } + }, + { + 'fruits': fruits_explicit, + 'name': 'with no references', + 'output': { + 'params': { + 'name': 'name', + 'distance': 1, + 'fruits': [] + } + } + } + ] - # this string is OK - input = {'name': 'valid_uri', 'distance': 3, 'fruits': ['pear', 'plum']} - output = run_validator( - schema=schema_arg, - schema_file=schema_file_arg, - data=input, - validate_at=valid_json_loc) - self.assertEqual(output, input) + for t in tests: + with self.subTest(desc=t['name']): + test_schema['properties']['params']['properties']['fruits'] = t['fruits'] + output = run_validator( + schema=test_schema, + data={'params': {'name': 'name'}} + ) + self.assertEqual(output, t['output']) - # data files - for file_ext in ['json', 'yaml']: - file_path = os_path.join(json_validation_dir, 'invalid_array.' + file_ext) - err_str = "'pear' is not of type 'array'" - with self.assertRaisesRegex(ValidationError, err_str): - run_validator( - schema=schema_arg, - schema_file=schema_file_arg, - data_file=file_path, - validate_at=valid_json_loc) - - for file_ext in ['json', 'yaml']: - file_path = os_path.join(json_validation_dir, 'invalid_array_items.' + file_ext) - err_str = "1 is not of type 'string'" - with self.assertRaisesRegex(ValidationError, err_str): - run_validator( - schema=schema_arg, - schema_file=schema_file_arg, - data_file=file_path, - validate_at=valid_json_loc) - - file_path = os_path.join(json_validation_dir, 'valid_array.' + file_ext) - self.assertEqual( - run_validator( - schema=schema_arg, - schema_file=schema_file_arg, - data_file=file_path, - validate_at=valid_json_loc), - { - "name": "valid_array", - "distance": 3, - 'fruits': ['pear', 'plum'], - } - ) + # restore the original value + test_schema['properties']['params']['properties']['fruits'] = fruits_explicit def test_schema_references(self): """Ensure referenced schemas, including those written in yaml, can be accessed.""" @@ -440,46 +445,47 @@ def test_schema_references(self): for path in path_list: for file_ext in ['json', 'yaml']: - file_path = os_path.join(*(test_data_dirs + ['schema_refs'] + path), 'edge.' + file_ext) - - # fails due to invalid data - with self.assertRaisesRegex(ValidationError, err_msg): - run_validator( - schema_file=file_path, - data=invalid_edge_data, + with self.subTest(file_ext=file_ext): + file_path = os_path.join(*(test_data_dirs + ['schema_refs'] + path), 'edge.' + file_ext) + + # fails due to invalid data + with self.assertRaisesRegex(ValidationError, err_msg): + run_validator( + schema_file=file_path, + data=invalid_edge_data, + ) + + # valid data + self.assertEqual( + run_validator( + schema_file=file_path, + data=valid_edge_data, + ), + valid_edge_data ) - # valid data - self.assertEqual( - run_validator( - schema_file=file_path, - data=valid_edge_data, - ), - valid_edge_data - ) - - # validate using the schema instead of the schema_file - with open(file_path) as fd: - contents = yaml.safe_load(fd) if file_ext == 'yaml' else json.load(fd) - - # if there is no $id in the schema, the ref resolver won't know - # where the schema file is located and will not resolve relative references - with self.assertRaisesRegex(RefResolutionError, 'No such file or directory'): - run_validator( - schema=contents, - data=valid_edge_data + # validate using the schema instead of the schema_file + with open(file_path) as fd: + contents = yaml.safe_load(fd) if file_ext == 'yaml' else json.load(fd) + + # if there is no $id in the schema, the ref resolver won't know + # where the schema file is located and will not resolve relative references + with self.assertRaisesRegex(RefResolutionError, 'No such file or directory'): + run_validator( + schema=contents, + data=valid_edge_data + ) + + # inject an $id with the current file path + contents['$id'] = file_path + self.assertEqual( + run_validator( + schema=contents, + data=valid_edge_data, + ), + valid_edge_data ) - # inject an $id with the current file path - contents['$id'] = file_path - self.assertEqual( - run_validator( - schema=contents, - data=valid_edge_data, - ), - valid_edge_data - ) - def test_complex_schema_references(self): """test validation with complex references that reference other references""" @@ -503,22 +509,23 @@ def test_complex_schema_references(self): err_msg = "'whatever' is not valid under any of the given schemas" for file_ext in ['json', 'yaml']: - file_path = os_path.join( - *(test_data_dirs + ['schema_refs', 'level_1']), - 'test_object.' + file_ext - ) - - # data fails validation - with self.assertRaisesRegex(ValidationError, err_msg): - run_validator( - schema_file=file_path, - data=invalid_data, + with self.subTest(file_ext=file_ext): + file_path = os_path.join( + *(test_data_dirs + ['schema_refs', 'level_1']), + 'test_object.' + file_ext ) - self.assertEqual( - run_validator( - schema_file=file_path, - data=valid_data, - ), - valid_data - ) + # data fails validation + with self.assertRaisesRegex(ValidationError, err_msg): + run_validator( + schema_file=file_path, + data=invalid_data, + ) + + self.assertEqual( + run_validator( + schema_file=file_path, + data=valid_data, + ), + valid_data + ) diff --git a/relation_engine_server/test/test_spec_loader.py b/relation_engine_server/test/test_spec_loader.py index 0833e5e9..fdefdea1 100644 --- a/relation_engine_server/test/test_spec_loader.py +++ b/relation_engine_server/test/test_spec_loader.py @@ -1,5 +1,7 @@ """ -Test JSON validation functions +Test spec_loader functions + +These tests run within the re_api docker image. """ import unittest import os.path as os_path @@ -16,15 +18,14 @@ def setUpClass(cls): cls.test_dir = os_path.join('/app', 'relation_engine_server', 'test') cls.test_spec_dir = os_path.join(cls.test_dir, 'spec_release', 'sample_spec_release') - config = get_config() - cls.repo_path = config['spec_paths']['repo'] - for key in config['spec_paths'].keys(): - if cls.repo_path in config['spec_paths'][key]: - config['spec_paths'][key] = config['spec_paths'][key].replace( + cls.config = get_config() + cls.repo_path = cls.config['spec_paths']['repo'] + for key in cls.config['spec_paths'].keys(): + if cls.repo_path in cls.config['spec_paths'][key]: + cls.config['spec_paths'][key] = cls.config['spec_paths'][key].replace( cls.repo_path, cls.test_spec_dir ) - cls.config = config @classmethod def tearDownClass(cls): @@ -151,9 +152,10 @@ def test_get_schemas_of_various_types(self): ] for schema in schema_type_list: - self.test_run_spec_loading_tests(schema['schema_type_names'], schema['example']) - if 'names' in schema: - self.test_get_names(schema['schema_type_names'], schema['names']) + with self.subTest(schema=schema['schema_type_names'][0]): + self.test_run_spec_loading_tests(schema['schema_type_names'], schema['example']) + if 'names' in schema: + self.test_get_names(schema['schema_type_names'], schema['names']) def test_non_existent_schema(self): diff --git a/spec/stored_queries/djornl/djornl_fetch_all.yaml b/spec/stored_queries/djornl/djornl_fetch_all.yaml index 90757835..88295928 100644 --- a/spec/stored_queries/djornl/djornl_fetch_all.yaml +++ b/spec/stored_queries/djornl/djornl_fetch_all.yaml @@ -5,7 +5,17 @@ params: additionalProperties: false properties: edge_types: - $ref: "../../datasets/djornl/edge_types_filter.yaml" + title: Edge Types + description: Edge types to filter on + type: array + items: + $ref: ../../datasets/djornl/edge_type.yaml + default: [] + uniqueItems: true + examples: + - ['AraNetv2-HT_high-throughput-ppi', 'AraNetv2-LC_lit-curated-ppi'] + - ['AraGWAS-Phenotype_Associations'] + - [] query: | LET nodes = ( FOR v IN djornl_node diff --git a/spec/stored_queries/djornl/djornl_fetch_clusters.yaml b/spec/stored_queries/djornl/djornl_fetch_clusters.yaml index 55222225..e39f82b4 100644 --- a/spec/stored_queries/djornl/djornl_fetch_clusters.yaml +++ b/spec/stored_queries/djornl/djornl_fetch_clusters.yaml @@ -10,14 +10,29 @@ params: title: Cluster IDs description: Cluster IDs, in the form "clustering_system_name:cluster_id" items: - $ref: "../../datasets/djornl/definitions.yaml#definitions/cluster_id" + $ref: ../../datasets/djornl/definitions.yaml#definitions/cluster_id minItems: 1 uniqueItems: true examples: [['markov_i2:5', 'markov_i6:2'],['markov_i6:1']] distance: - $ref: "../../datasets/distance.yaml" + type: integer + title: Traversal Distance + description: How many hops to find neighbors and neighbors-of-neighbors + default: 1 + minimum: 0 + maximum: 100 edge_types: - $ref: "../../datasets/djornl/edge_types_filter.yaml" + title: Edge Types + description: Edge types to filter on + type: array + items: + $ref: ../../datasets/djornl/edge_type.yaml + default: [] + uniqueItems: true + examples: + - ['AraNetv2-HT_high-throughput-ppi', 'AraNetv2-LC_lit-curated-ppi'] + - ['AraGWAS-Phenotype_Associations'] + - [] query: | LET node_ids = ( FOR n IN djornl_node diff --git a/spec/stored_queries/djornl/djornl_fetch_genes.yaml b/spec/stored_queries/djornl/djornl_fetch_genes.yaml index d8b1e008..87045a08 100644 --- a/spec/stored_queries/djornl/djornl_fetch_genes.yaml +++ b/spec/stored_queries/djornl/djornl_fetch_genes.yaml @@ -9,13 +9,29 @@ params: type: array title: Gene Keys items: - $ref: "../../datasets/djornl/definitions.yaml#definitions/djornl_node/_key" + $ref: ../../datasets/djornl/definitions.yaml#definitions/djornl_node/_key minItems: 1 + uniqueItems: true examples: [["AT1G01010"],["AT1G01020","AT1G01070"]] distance: - $ref: "../../datasets/distance.yaml" + type: integer + title: Traversal Distance + description: How many hops to find neighbors and neighbors-of-neighbors + default: 1 + minimum: 0 + maximum: 100 edge_types: - $ref: "../../datasets/djornl/edge_types_filter.yaml" + title: Edge Types + description: Edge types to filter on + type: array + items: + $ref: ../../datasets/djornl/edge_type.yaml + default: [] + uniqueItems: true + examples: + - ['AraNetv2-HT_high-throughput-ppi', 'AraNetv2-LC_lit-curated-ppi'] + - ['AraGWAS-Phenotype_Associations'] + - [] query: | LET node_ids = ( FOR n IN djornl_node diff --git a/spec/stored_queries/djornl/djornl_fetch_phenotypes.yaml b/spec/stored_queries/djornl/djornl_fetch_phenotypes.yaml index e1d2a426..8ae92892 100644 --- a/spec/stored_queries/djornl/djornl_fetch_phenotypes.yaml +++ b/spec/stored_queries/djornl/djornl_fetch_phenotypes.yaml @@ -9,13 +9,29 @@ params: type: array title: Phenotype Keys items: - $ref: "../../datasets/djornl/definitions.yaml#definitions/djornl_node/_key" + $ref: ../../datasets/djornl/definitions.yaml#definitions/djornl_node/_key minItems: 1 + uniqueItems: true examples: [["As2"],["As2", "Na23"]] distance: - $ref: "../../datasets/distance.yaml" + type: integer + title: Traversal Distance + description: How many hops to find neighbors and neighbors-of-neighbors + default: 1 + minimum: 0 + maximum: 100 edge_types: - $ref: "../../datasets/djornl/edge_types_filter.yaml" + title: Edge Types + description: Edge types to filter on + type: array + items: + $ref: ../../datasets/djornl/edge_type.yaml + default: [] + uniqueItems: true + examples: + - ['AraNetv2-HT_high-throughput-ppi', 'AraNetv2-LC_lit-curated-ppi'] + - ['AraGWAS-Phenotype_Associations'] + - [] query: | LET node_ids = ( FOR n IN djornl_node diff --git a/spec/stored_queries/djornl/djornl_search_nodes.yaml b/spec/stored_queries/djornl/djornl_search_nodes.yaml index 1279a4bb..d318781d 100644 --- a/spec/stored_queries/djornl/djornl_search_nodes.yaml +++ b/spec/stored_queries/djornl/djornl_search_nodes.yaml @@ -10,9 +10,24 @@ params: title: Search text examples: ['GO:0005515', 'organelle machinery'] distance: - $ref: "../../datasets/distance.yaml" + type: integer + title: Traversal Distance + description: How many hops to find neighbors and neighbors-of-neighbors + default: 1 + minimum: 0 + maximum: 100 edge_types: - $ref: "../../datasets/djornl/edge_types_filter.yaml" + title: Edge Types + description: Edge types to filter on + type: array + items: + $ref: ../../datasets/djornl/edge_type.yaml + default: [] + uniqueItems: true + examples: + - ['AraNetv2-HT_high-throughput-ppi', 'AraNetv2-LC_lit-curated-ppi'] + - ['AraGWAS-Phenotype_Associations'] + - [] query: | LET node_ids = ( FOR g IN djornl_node_view diff --git a/spec/test/collections/test_djornl.py b/spec/test/collections/test_djornl.py index 39008fbc..f2ea6511 100644 --- a/spec/test/collections/test_djornl.py +++ b/spec/test/collections/test_djornl.py @@ -1,23 +1,43 @@ """ Tests for the Dan Jacobson ORNL Arabidopsis collection schemas. -These tests ensure that specific elements of the collection schemas validate correctly. +Tests to ensure that specific elements of the collection schemas validate correctly. +These tests run within the re_api docker image. """ import unittest - -from spec.test.helpers import check_spec_test_env +from os.path import join as os_path_join +from relation_engine_server.utils.config import get_config from relation_engine_server.utils.spec_loader import get_schema from relation_engine_server.utils.json_validation import get_schema_validator from jsonschema.exceptions import ValidationError +_BASE_DIR = os_path_join('/app', 'spec') + class Test_DJORNL_Collections(unittest.TestCase): @classmethod def setUpClass(cls): cls.maxDiff = None - check_spec_test_env() + cls.config = get_config() + cls.repo_path = cls.config['spec_paths']['repo'] + for key in cls.config['spec_paths'].keys(): + if cls.repo_path in cls.config['spec_paths'][key]: + cls.config['spec_paths'][key] = cls.config['spec_paths'][key].replace( + cls.repo_path, + _BASE_DIR + ) + + @classmethod + def tearDownClass(cls): + # undo all the config changes + for key in cls.config['spec_paths'].keys(): + if _BASE_DIR in cls.config['spec_paths'][key]: + cls.config['spec_paths'][key] = cls.config['spec_paths'][key].replace( + _BASE_DIR, + cls.repo_path + ) def test_node(self, query_name=None, test_data=None): """ ensure node data validates correctly """ diff --git a/spec/test/djornl/results.json b/spec/test/djornl/results.json index 12f85bfb..9d397848 100644 --- a/spec/test/djornl/results.json +++ b/spec/test/djornl/results.json @@ -230,26 +230,26 @@ } }, { - "params": { "keys": ["Mary Poppins"], "distance": 0, "edge_types": [] }, + "params": { "keys": ["Mary Poppins"], "distance": 0 }, "results": {"nodes": [], "edges": []} }, { - "params": { "keys": ["Mary Poppins"], "distance": 1, "edge_types": [] }, + "params": { "keys": ["Mary Poppins"], "distance": 1 }, "results": {"nodes": [], "edges": []} }, { - "params": { "keys": ["Mary Poppins"], "distance": 5, "edge_types": [] }, + "params": { "keys": ["Mary Poppins"], "distance": 5 }, "results": {"nodes": [], "edges": []} }, { - "params": { "keys": ["AT1G01010"], "distance": 0, "edge_types": [] }, + "params": { "keys": ["AT1G01010"], "distance": 0 }, "results": { "nodes": ["AT1G01010"], "edges": [] } }, { - "params": { "keys": ["AT1G01010"], "distance": 1, "edge_types": [] }, + "params": { "keys": ["AT1G01010"], "distance": 1 }, "results": { "nodes": [ "AT1G01010", @@ -266,7 +266,7 @@ } }, { - "params": { "keys": ["AT1G01010"], "distance": 5, "edge_types": [] }, + "params": { "keys": ["AT1G01010"], "distance": 5 }, "results": { "nodes": ["As2", "As75", "AT1G01010", "AT1G01020", "AT1G01030", "AT1G01040", "AT1G01050", "AT1G01060"], "edges": [ @@ -283,7 +283,7 @@ } }, { - "params": { "keys": ["AT1G01010"], "distance": 5, "edge_types": [] }, + "params": { "keys": ["AT1G01010"], "distance": 5 }, "results": { "nodes": ["As2", "As75", "AT1G01010", "AT1G01020", "AT1G01030", "AT1G01040", "AT1G01050", "AT1G01060"], "edges": [ @@ -300,14 +300,14 @@ } }, { - "params": {"keys": ["AT1G01020", "AT1G01070"], "distance": 0, "edge_types": [] }, + "params": {"keys": ["AT1G01020", "AT1G01070"], "distance": 0 }, "results": { "nodes": ["AT1G01020", "AT1G01070"], "edges": [] } }, { - "params": {"keys": ["AT1G01020", "AT1G01070"], "distance": 1, "edge_types": [] }, + "params": {"keys": ["AT1G01020", "AT1G01070"], "distance": 1 }, "results": { "nodes": ["As2", "As75", "AT1G01010", "AT1G01020", "AT1G01070"], "edges": [ @@ -328,7 +328,7 @@ } }, { - "params": {"keys": ["AT1G01020", "AT1G01070"], "distance": 5, "edge_types": [] }, + "params": {"keys": ["AT1G01020", "AT1G01070"], "distance": 5 }, "results": { "nodes": ["As2", "As75", "AT1G01010", "AT1G01020", "AT1G01030", "AT1G01040", "AT1G01050", "AT1G01060", "AT1G01070"], "edges": [ @@ -372,26 +372,26 @@ } }, { - "params": {"keys": ["Mary Poppins"], "distance": 0, "edge_types": []}, + "params": {"keys": ["Mary Poppins"], "distance": 0}, "results": {"nodes": [], "edges": []} }, { - "params": {"keys": ["Mary Poppins"], "distance": 1, "edge_types": []}, + "params": {"keys": ["Mary Poppins"], "distance": 1}, "results": {"nodes": [], "edges": []} }, { - "params": {"keys": ["Mary Poppins"], "distance": 5, "edge_types": []}, + "params": {"keys": ["Mary Poppins"], "distance": 5}, "results": {"nodes": [], "edges": []} }, { - "params": {"keys": ["As2"], "distance": 0, "edge_types": []}, + "params": {"keys": ["As2"], "distance": 0}, "results": { "nodes": ["As2"], "edges": [] } }, { - "params": {"keys": ["As2"], "distance": 1, "edge_types": []}, + "params": {"keys": ["As2"], "distance": 1}, "results": { "nodes": ["As2", "AT1G01020", "AT1G01040"], "edges": [ @@ -401,7 +401,7 @@ } }, { - "params": {"keys": ["As2"], "distance": 5, "edge_types": []}, + "params": {"keys": ["As2"], "distance": 5}, "results": { "nodes": ["As2", "As75", "AT1G01010", "AT1G01020", "AT1G01030", "AT1G01040", "AT1G01050", "AT1G01060"], "edges": [ @@ -418,14 +418,14 @@ } }, { - "params": {"keys": ["As2", "Na23"], "distance": 0, "edge_types": []}, + "params": {"keys": ["As2", "Na23"], "distance": 0}, "results": { "nodes": ["As2", "Na23"], "edges": [] } }, { - "params": {"keys": ["As2", "Na23"], "distance": 1, "edge_types": []}, + "params": {"keys": ["As2", "Na23"], "distance": 1}, "results": { "nodes": ["As2", "Na23", "AT1G01020", "AT1G01040"], "edges": [ @@ -435,7 +435,7 @@ } }, { - "params": {"keys": ["As2", "Na23"], "distance": 5, "edge_types": []}, + "params": {"keys": ["As2", "Na23"], "distance": 5}, "results": { "nodes": ["As2", "As75", "AT1G01010", "AT1G01020", "AT1G01030", "AT1G01040", "AT1G01050", "AT1G01060", "Na23"], "edges": [ @@ -452,7 +452,7 @@ } }, { - "params": {"keys": ["As2", "Na23"], "distance": 0, "edge_types": []}, + "params": {"keys": ["As2", "Na23"], "distance": 0}, "results": { "nodes": ["As2", "Na23"], "edges": [] @@ -487,26 +487,26 @@ ], "djornl_search_nodes": [ { - "params": {"search_text": "Mary Poppins", "distance": 0, "edge_types": []}, + "params": {"search_text": "Mary Poppins", "distance": 0}, "results": {"nodes": [], "edges": []} }, { - "params": {"search_text": "Mary Poppins", "distance": 1, "edge_types": []}, + "params": {"search_text": "Mary Poppins", "distance": 1}, "results": {"nodes": [], "edges": []} }, { - "params": {"search_text": "Mary Poppins", "distance": 5, "edge_types": []}, + "params": {"search_text": "Mary Poppins", "distance": 5}, "results": {"nodes": [], "edges": []} }, { - "params": {"search_text": "GO:0005515", "distance": 0, "edge_types": []}, + "params": {"search_text": "GO:0005515", "distance": 0}, "results": { "nodes": ["AT1G01040", "AT1G01090"], "edges": [] } }, { - "params": {"search_text": "GO:0005515", "distance": 1, "edge_types": []}, + "params": {"search_text": "GO:0005515", "distance": 1}, "results": { "nodes": ["As2", "AT1G01010", "AT1G01040", "AT1G01080", "AT1G01090"], "edges": [ @@ -518,7 +518,7 @@ } }, { - "params": {"search_text": "GO:0005515", "distance": 5, "edge_types": []}, + "params": {"search_text": "GO:0005515", "distance": 5}, "results": { "nodes": ["As2", "As75", "AT1G01010", "AT1G01020", "AT1G01030", "AT1G01040", "AT1G01050", "AT1G01060", "AT1G01080", "AT1G01090"], "edges": [ @@ -592,26 +592,26 @@ } }, { - "params": {"cluster_ids": ["MaryPoppins:1"], "distance": 0, "edge_types": []}, + "params": {"cluster_ids": ["MaryPoppins:1"], "distance": 0}, "results": {"nodes": [], "edges": []} }, { - "params": {"cluster_ids": ["MaryPoppins:1"], "distance": 1, "edge_types": []}, + "params": {"cluster_ids": ["MaryPoppins:1"], "distance": 1}, "results": {"nodes": [], "edges": []} }, { - "params": {"cluster_ids": ["MaryPoppins:1"], "distance": 5, "edge_types": []}, + "params": {"cluster_ids": ["MaryPoppins:1"], "distance": 5}, "results": {"nodes": [], "edges": []} }, { - "params": {"cluster_ids": ["markov_i6:1"], "distance": 0, "edge_types": []}, + "params": {"cluster_ids": ["markov_i6:1"], "distance": 0}, "results": { "nodes": ["AT1G01040", "AT1G01090"], "edges": [] } }, { - "params": {"cluster_ids": ["markov_i6:1"], "distance": 1, "edge_types": []}, + "params": {"cluster_ids": ["markov_i6:1"], "distance": 1}, "results": { "nodes": ["As2", "AT1G01010", "AT1G01040", "AT1G01080", "AT1G01090"], "edges": [ @@ -623,7 +623,7 @@ } }, { - "params": {"cluster_ids": ["markov_i6:1"], "distance": 5, "edge_types": []}, + "params": {"cluster_ids": ["markov_i6:1"], "distance": 5}, "results": { "nodes": ["As2", "As75", "AT1G01010", "AT1G01020", "AT1G01030", "AT1G01040", "AT1G01050", "AT1G01060", "AT1G01080", "AT1G01090"], "edges": [ @@ -641,14 +641,14 @@ } }, { - "params": {"cluster_ids": ["markov_i2:5", "markov_i6:2"], "distance": 0, "edge_types": []}, + "params": {"cluster_ids": ["markov_i2:5", "markov_i6:2"], "distance": 0}, "results": { "nodes": ["AT1G01020", "AT1G01070"], "edges": [] } }, { - "params": {"cluster_ids": ["markov_i2:5", "markov_i6:2"], "distance": 1, "edge_types": []}, + "params": {"cluster_ids": ["markov_i2:5", "markov_i6:2"], "distance": 1}, "results": { "nodes": ["As2", "As75", "AT1G01010", "AT1G01020", "AT1G01070"], "edges": [ @@ -659,7 +659,7 @@ } }, { - "params": {"cluster_ids": ["markov_i2:5", "markov_i6:2"], "distance": 5, "edge_types": []}, + "params": {"cluster_ids": ["markov_i2:5", "markov_i6:2"], "distance": 5}, "results": { "nodes": ["As2", "As75", "AT1G01010", "AT1G01020", "AT1G01030", "AT1G01040", "AT1G01050", "AT1G01060", "AT1G01070"], "edges": [ diff --git a/spec/test/stored_queries/test_djornl.py b/spec/test/stored_queries/test_djornl.py index 8c27e719..94a57680 100644 --- a/spec/test/stored_queries/test_djornl.py +++ b/spec/test/stored_queries/test_djornl.py @@ -1,5 +1,7 @@ """ Tests for the Dan Jacobson ORNL Arabidopsis stored queries. + +These tests run within the re_api docker image, and require access to the ArangoDB, auth, and workspace images. """ import json import unittest diff --git a/spec/test/stored_queries/test_list_test_vertices.py b/spec/test/stored_queries/test_list_test_vertices.py index 086c2b2e..1644b600 100644 --- a/spec/test/stored_queries/test_list_test_vertices.py +++ b/spec/test/stored_queries/test_list_test_vertices.py @@ -1,3 +1,10 @@ +""" +Test the 'list_test_vertices' stored query (see +relation_engine_server/test/spec_release/sample_spec_release/stored_queries/test for the query). + +These tests run within the re_api docker image, and require access to the ArangoDB, auth, and workspace images. + +""" import unittest import requests diff --git a/spec/test/stored_queries/test_ncbi_tax.py b/spec/test/stored_queries/test_ncbi_tax.py index 6e3a0435..9daf5550 100644 --- a/spec/test/stored_queries/test_ncbi_tax.py +++ b/spec/test/stored_queries/test_ncbi_tax.py @@ -1,5 +1,7 @@ """ Tests for the ncbi taxonomy stored queries. + +These tests require access to the ArangoDB, auth, and workspace images. """ import json import time diff --git a/spec/test/stored_queries/test_taxonomy.py b/spec/test/stored_queries/test_taxonomy.py index a6075548..27025b18 100644 --- a/spec/test/stored_queries/test_taxonomy.py +++ b/spec/test/stored_queries/test_taxonomy.py @@ -1,5 +1,7 @@ """ Tests for the ncbi taxonomy stored queries. + +These tests run within the re_api docker image, and require access to the ArangoDB, auth, and workspace images. """ import json import time diff --git a/spec/test/stored_queries/test_ws.py b/spec/test/stored_queries/test_ws.py index c8796a94..15672cf7 100644 --- a/spec/test/stored_queries/test_ws.py +++ b/spec/test/stored_queries/test_ws.py @@ -1,5 +1,8 @@ """ -Tests for workspace workspace stored queries under the ws* namespace +Tests for workspace stored queries under the ws* namespace + + +These tests run within the re_api docker image, and require access to the ArangoDB, auth, and workspace images. """ import unittest import json diff --git a/spec/test/test_manifest_schema.py b/spec/test/test_manifest_schema.py index 4237624d..c00eeb77 100644 --- a/spec/test/test_manifest_schema.py +++ b/spec/test/test_manifest_schema.py @@ -1,7 +1,9 @@ """ Tests for manifest.schema.json -Ensure that the manifest schema correctly validates data +Ensure that the manifest schema correctly validates data. + +These tests run within the re_api docker image. """ import unittest import os.path as os_path diff --git a/spec/test/test_validate.py b/spec/test/test_validate.py index e104a6c5..4c6dacaf 100644 --- a/spec/test/test_validate.py +++ b/spec/test/test_validate.py @@ -1,5 +1,7 @@ """ Tests for the schema validation functions + +These tests run within the re_api docker image, and require access to the ArangoDB image for validation of AQL strings. """ import unittest import os.path as os_path