import io import json import os import platform import jsonschema from loguru import logger from httprunner import exceptions schemas_root_dir = os.path.join(os.path.dirname(__file__), "schemas") common_schema_path = os.path.join(schemas_root_dir, "common.schema.json") api_schema_path = os.path.join(schemas_root_dir, "api.schema.json") testcase_schema_v1_path = os.path.join(schemas_root_dir, "testcase.schema.v1.json") testcase_schema_v2_path = os.path.join(schemas_root_dir, "testcase.schema.v2.json") testsuite_schema_v1_path = os.path.join(schemas_root_dir, "testsuite.schema.v1.json") testsuite_schema_v2_path = os.path.join(schemas_root_dir, "testsuite.schema.v2.json") with io.open(api_schema_path, encoding='utf-8') as f: api_schema = json.load(f) with io.open(common_schema_path, encoding='utf-8') as f: if platform.system() == "Windows": absolute_base_path = 'file:///' + os.path.abspath(schemas_root_dir).replace("\\", "/") + '/' else: # Linux, Darwin absolute_base_path = "file://" + os.path.abspath(schemas_root_dir) + "/" common_schema = json.load(f) resolver = jsonschema.RefResolver(absolute_base_path, common_schema) with io.open(testcase_schema_v1_path, encoding='utf-8') as f: testcase_schema_v1 = json.load(f) with io.open(testcase_schema_v2_path, encoding='utf-8') as f: testcase_schema_v2 = json.load(f) with io.open(testsuite_schema_v1_path, encoding='utf-8') as f: testsuite_schema_v1 = json.load(f) with io.open(testsuite_schema_v2_path, encoding='utf-8') as f: testsuite_schema_v2 = json.load(f) class JsonSchemaChecker(object): @staticmethod def validate_format(content, scheme): """ check api/testcase/testsuite format if valid """ try: jsonschema.validate(content, scheme, resolver=resolver) except jsonschema.exceptions.ValidationError as ex: logger.error(str(ex)) raise exceptions.FileFormatError return True @staticmethod def validate_api_format(content): """ check api format if valid """ return JsonSchemaChecker.validate_format(content, api_schema) @staticmethod def validate_testcase_v1_format(content): """ check testcase format v1 if valid """ return JsonSchemaChecker.validate_format(content, testcase_schema_v1) @staticmethod def validate_testcase_v2_format(content): """ check testcase format v2 if valid """ return JsonSchemaChecker.validate_format(content, testcase_schema_v2) @staticmethod def validate_testsuite_v1_format(content): """ check testsuite format v1 if valid """ return JsonSchemaChecker.validate_format(content, testsuite_schema_v1) @staticmethod def validate_testsuite_v2_format(content): """ check testsuite format v2 if valid """ return JsonSchemaChecker.validate_format(content, testsuite_schema_v2) def is_test_path(path): """ check if path is valid json/yaml file path or a existed directory. Args: path (str/list/tuple): file path/directory or file path list. Returns: bool: True if path is valid file path or path list, otherwise False. """ if not isinstance(path, (str, list, tuple)): return False elif isinstance(path, (list, tuple)): for p in path: if not is_test_path(p): return False return True else: # path is string if not os.path.exists(path): return False # path exists if os.path.isfile(path): # path is a file file_suffix = os.path.splitext(path)[1].lower() if file_suffix not in ['.json', '.yaml', '.yml']: # path is not json/yaml file return False else: return True elif os.path.isdir(path): # path is a directory return True else: # path is neither a folder nor a file, maybe a symbol link or something else return False def is_test_content(data_structure): """ check if data_structure is apis/testcases/testsuites. Args: data_structure (dict): should include keys, apis or testcases or testsuites Returns: bool: True if data_structure is valid apis/testcases/testsuites, otherwise False. """ if not isinstance(data_structure, dict): return False if "apis" in data_structure: # maybe a group of api content apis = data_structure["apis"] if not isinstance(apis, list): return False for item in apis: is_testcase = False try: JsonSchemaChecker.validate_api_format(item) is_testcase = True except exceptions.FileFormatError: pass if not is_testcase: return False return True elif "testcases" in data_structure: # maybe a testsuite, containing a group of testcases testcases = data_structure["testcases"] if not isinstance(testcases, list): return False for item in testcases: is_testcase = False try: JsonSchemaChecker.validate_testcase_v2_format(item) is_testcase = True except exceptions.FileFormatError: pass try: JsonSchemaChecker.validate_testcase_v2_format(item) is_testcase = True except exceptions.FileFormatError: pass if not is_testcase: return False return True elif "testsuites" in data_structure: # maybe a group of testsuites testsuites = data_structure["testsuites"] if not isinstance(testsuites, list): return False for item in testsuites: is_testcase = False try: JsonSchemaChecker.validate_testsuite_v1_format(item) is_testcase = True except exceptions.FileFormatError: pass try: JsonSchemaChecker.validate_testsuite_v2_format(item) is_testcase = True except exceptions.FileFormatError: pass if not is_testcase: return False return True else: return False