def locate_file(start_path: Text, file_name: Text) -> Text: """ locate filename and return absolute file path. searching will be recursive upward until system root dir. Args: file_name (str): target locate file name start_path (str): start locating path, maybe file path or directory path Returns: str: located file path. None if file not found. Raises: exceptions.FileNotFound: If failed to locate file. """ if os.path.isfile(start_path): start_dir_path = os.path.dirname(start_path) elif os.path.isdir(start_path): start_dir_path = start_path else: raise exceptions.FileNotFound(f"invalid path: {start_path}") file_path = os.path.join(start_dir_path, file_name) if os.path.isfile(file_path): return os.path.abspath(file_path) # system root dir # Windows, e.g. 'E:\\' # Linux/Darwin, '/' parent_dir = os.path.dirname(start_dir_path) if parent_dir == start_dir_path: raise exceptions.FileNotFound(f"{file_name} not found in {start_path}") # locate recursive upward return locate_file(parent_dir, file_name)
def locate_file(start_path, file_name): ''' locate filename and return file path. searching will be recursive upward until current working directory. Args: start_path (str): start locating path, maybe file path or directory path. file_name (str): specified file name. Returns: str: located file path. None if file not found. Raises: exceptions.FileNotFound: If failed to locate file. ''' start_path = start_path.rstrip('/').rstrip('\\') if os.path.isfile(start_path): start_dir_path = os.path.dirname(start_path) elif os.path.isdir(start_path): start_dir_path = start_path else: raise exceptions.FileNotFound(f'invalid path:{start_path}') file_path = os.path.join(start_dir_path, file_name) if os.path.isfile(file_path): return file_path # current working directory if os.path.abspath(start_dir_path) in [ os.getcwd(), os.path.abspath(os.sep) ]: raise exceptions.FileNotFound(f'{file_name} not found in {start_path}') # locate recursive upward return locate_file(os.path.dirname(start_dir_path), file_name)
def locate_file(start_path, file_name): """ locate filename and return absolute file path. searching will be recursive upward until current working directory. Args: start_path (str): start locating path, maybe file path or directory path Returns: str: located file path. None if file not found. Raises: exceptions.FileNotFound: If failed to locate file. """ if os.path.isfile(start_path): start_dir_path = os.path.dirname(start_path) elif os.path.isdir(start_path): start_dir_path = start_path else: raise exceptions.FileNotFound("invalid path: {}".format(start_path)) file_path = os.path.join(start_dir_path, file_name) if os.path.isfile(file_path): return os.path.abspath(file_path) # current working directory if os.path.abspath(start_dir_path) in [ os.getcwd(), os.path.abspath(os.sep) ]: raise exceptions.FileNotFound("{} not found in {}".format( file_name, start_path)) # locate recursive upward return locate_file(os.path.dirname(start_dir_path), file_name)
def load_testcase_file(testcase_file: Text) -> Tuple[Dict, TestCase]: """load testcase file and validate with pydantic model""" if not os.path.isfile(testcase_file): raise exceptions.FileNotFound( f"testcase file not exists: {testcase_file}") file_suffix = os.path.splitext(testcase_file)[1].lower() if file_suffix == ".json": testcase_content = _load_json_file(testcase_file) elif file_suffix in [".yaml", ".yml"]: testcase_content = _load_yaml_file(testcase_file) else: # '' or other suffix raise exceptions.FileFormatError( f"testcase file should be YAML/JSON format, invalid testcase file: {testcase_file}" ) try: # validate with pydantic TestCase model testcase_obj = TestCase.parse_obj(testcase_content) except ValidationError as ex: err_msg = f"Invalid testcase format: {testcase_file}" logger.error(f"{err_msg}\n{ex}") raise exceptions.TestCaseFormatError(err_msg) testcase_content["config"]["path"] = testcase_file testcase_obj.config.path = testcase_file return testcase_content, testcase_obj
def load_dot_env_file(path): """ load .env file """ if not path: path = os.path.join(os.getcwd(), ".env") if not os.path.isfile(path): logger.log_debug(".env file not exist: {}".format(path)) return {} else: if not os.path.isfile(path): raise exceptions.FileNotFound( "env file not exist: {}".format(path)) logger.log_info("Loading environment variables from {}".format(path)) env_variables_mapping = {} with io.open(path, 'r', encoding='utf-8') as fp: for line in fp: if "=" in line: variable, value = line.split("=") elif ":" in line: variable, value = line.split(":") else: raise exceptions.FileFormatError(".env format error") env_variables_mapping[variable.strip()] = value.strip() return env_variables_mapping
def load_testcases(path): """ load testcases from file path, extend and merge with api/testcase definitions. Args: path (str): testcase file/foler path. path could be in several types: - absolute/relative file path - absolute/relative folder path - list/set container with file(s) and/or folder(s) Returns: list: testcases list, each testcase is corresponding to a file [ testcase_dict_1, testcase_dict_2 ] """ if isinstance(path, (list, set)): testcases_list = [] for file_path in set(path): testcases = load_testcases(file_path) if not testcases: continue testcases_list.extend(testcases) return testcases_list if not os.path.isabs(path): path = os.path.join(os.getcwd(), path) if path in testcases_cache_mapping: return testcases_cache_mapping[path] if os.path.isdir(path): load_project_tests(path) files_list = load_folder_files(path) testcases_list = load_testcases(files_list) elif os.path.isfile(path): try: load_project_tests(path) testcase = _load_test_file(path) if testcase["teststeps"]: testcases_list = [testcase] else: testcases_list = [] except exceptions.FileFormatError: testcases_list = [] else: err_msg = "path not exist: {}".format(path) logger.log_error(err_msg) raise exceptions.FileNotFound(err_msg) testcases_cache_mapping[path] = testcases_list return testcases_list
def prepare_path(path): if not os.path.exists(path): err_msg = "path not exist: {}".format(path) logger.log_error(err_msg) raise exceptions.FileNotFound(err_msg) if not os.path.isabs(path): path = os.path.join(os.getcwd(), path) return path
def load_file(file_path): if not os.path.isfile(file_path): raise exceptions.FileNotFound(f'{file_path} does not exist.') file_suffix = os.path.splitext(file_path)[1].lower() if file_suffix == '.json': return load_json_file(file_path) elif file_suffix in ['.yaml', '.yml']: return load_yaml_file(file_path) elif file_suffix == '.csv': return load_csv_file(file_path) else: err_msg = f'Unsupported file format: {file_path}' logger.log_error(err_msg) return []
def load_testcases(path): """ load testcases from file path @param path: path could be in several type - absolute/relative file path - absolute/relative folder path - list/set container with file(s) and/or folder(s) @return testcases list, each testcase is corresponding to a file [ testcase_dict_1, testcase_dict_2 ] """ if isinstance(path, (list, set)): testcases_list = [] for file_path in set(path): testcases = load_testcases(file_path) if not testcases: continue testcases_list.extend(testcases) return testcases_list if not os.path.isabs(path): path = os.path.join(os.getcwd(), path) if path in testcases_cache_mapping: return testcases_cache_mapping[path] if os.path.isdir(path): files_list = load_folder_files(path) testcases_list = load_testcases(files_list) elif os.path.isfile(path): try: testcase = load_test_file(path) if testcase["testcases"]: testcases_list = [testcase] else: testcases_list = [] except exceptions.FileFormatError: testcases_list = [] else: err_msg = "file not found: {}".format(path) logger.log_error(err_msg) raise exceptions.FileNotFound(err_msg) testcases_cache_mapping[path] = testcases_list return testcases_list
def load_file(file_path): if not os.path.isfile(file_path): raise exceptions.FileNotFound(f"{file_path} does not exist.") file_suffix = os.path.splitext(file_path)[1].lower() if file_suffix == '.json': return _load_json_file(file_path) elif file_suffix in ['.yaml', '.yml']: return _load_yaml_file(file_path) elif file_suffix == ".csv": return load_csv_file(file_path) else: # '' or other suffix logger.warning(f"Unsupported file format: {file_path}") return []
def load_file(file_path): if not os.path.isfile(file_path): raise exceptions.FileNotFound("{} does not exist.".format(file_path)) file_suffix = os.path.splitext(file_path)[1].lower() if file_suffix == '.json': return load_json_file(file_path) elif file_suffix in ['.yaml', '.yml']: return load_yaml_file(file_path) elif file_suffix == ".csv": return load_csv_file(file_path) else: # '' or other suffix err_msg = u"Unsupported file format: {}".format(file_path) logger.log_warning(err_msg) return []
def load_test_file(test_file: Text) -> Dict: """load testcase/testsuite file content""" if not os.path.isfile(test_file): raise exceptions.FileNotFound(f"test file not exists: {test_file}") file_suffix = os.path.splitext(test_file)[1].lower() if file_suffix == ".json": test_file_content = _load_json_file(test_file) elif file_suffix in [".yaml", ".yml"]: test_file_content = _load_yaml_file(test_file) else: # '' or other suffix raise exceptions.FileFormatError( f"testcase/testsuite file should be YAML/JSON format, invalid format file: {test_file}" ) return test_file_content
def load_dot_env_file(path): """ load .env file Args: path (str): .env file path. If path is None, it will find .env file in current working directory. Returns: dict: environment variables mapping { "UserName": "******", "Password": "******", "PROJECT_KEY": "ABCDEFGH" } Raises: exceptions.FileNotFound: If specified env file is not exist. exceptions.FileFormatError: If env file format is invalid. """ if not path: path = os.path.join(os.getcwd(), ".env") if not os.path.isfile(path): logger.log_debug(".env file not exist: {}".format(path)) return {} else: if not os.path.isfile(path): raise exceptions.FileNotFound( "env file not exist: {}".format(path)) logger.log_info("Loading environment variables from {}".format(path)) env_variables_mapping = {} with io.open(path, 'r', encoding='utf-8') as fp: for line in fp: if "=" in line: variable, value = line.split("=") elif ":" in line: variable, value = line.split(":") else: raise exceptions.FileFormatError(".env format error") env_variables_mapping[variable.strip()] = value.strip() project_mapping["env"] = env_variables_mapping return env_variables_mapping
def load_dot_env_file(path): """ load .env file and set to os.environ """ if not path: path = os.path.join(os.getcwd(), ".env") if not os.path.isfile(path): logger.log_debug(".env file not exist: {}".format(path)) return else: if not os.path.isfile(path): raise exceptions.FileNotFound("env file not exist: {}".format(path)) logger.log_info("Loading environment variables from {}".format(path)) with io.open(path, 'r', encoding='utf-8') as fp: for line in fp: variable, value = line.split("=") variable = variable.strip() os.environ[variable] = value.strip() logger.log_debug("Loaded variable: {}".format(variable))
def load_dot_env_file(dot_env_path): """ load .env file. Args: dot_env_path (str): .env file path Returns: dict: environment variables mapping { "UserName": "******", "Password": "******", "PROJECT_KEY": "ABCDEFGH" } Raises: exceptions.FileFormatError: If .env file format is invalid. """ if not os.path.isfile(dot_env_path): raise exceptions.FileNotFound(".env file path is not exist.") logger.log_info( "Loading environment variables from {}".format(dot_env_path)) env_variables_mapping = {} with io.open(dot_env_path, 'r', encoding='utf-8') as fp: for line in fp: # maxsplit=1 if "=" in line: variable, value = line.split("=", 1) elif ":" in line: variable, value = line.split(":", 1) else: raise exceptions.FileFormatError(".env format error") env_variables_mapping[variable.strip()] = value.strip() utils.set_os_environ(env_variables_mapping) return env_variables_mapping
def load_tests(path, dot_env_path=None): """ load testcases from file path, extend and merge with api/testcase definitions. Args: path (str): testcase/testsuite file/foler path. path could be in 2 types: - absolute/relative file path - absolute/relative folder path dot_env_path (str): specified .env file path Returns: dict: tests mapping, include project_mapping and testcases. each testcase is corresponding to a file. { "project_mapping": { "PWD": "XXXXX", "functions": {}, "env": {} }, "testcases": [ { # testcase data structure "config": { "name": "desc1", "path": "testcase1_path", "variables": [], # optional }, "teststeps": [ # test data structure { 'name': 'test desc1', 'variables': [], # optional 'extract': [], # optional 'validate': [], 'request': {} }, test_dict_2 # another test dict ] }, testcase_2_dict # another testcase dict ], "testsuites": [ { # testsuite data structure "config": {}, "testcases": { "testcase1": {}, "testcase2": {}, } }, testsuite_2_dict ] } """ if not os.path.exists(path): err_msg = "path not exist: {}".format(path) logger.log_error(err_msg) raise exceptions.FileNotFound(err_msg) if not os.path.isabs(path): path = os.path.join(os.getcwd(), path) load_project_tests(path, dot_env_path) tests_mapping = {"project_mapping": project_mapping} def __load_file_content(path): loaded_content = load_test_file(path) if not loaded_content: pass elif loaded_content["type"] == "testsuite": tests_mapping.setdefault("testsuites", []).append(loaded_content) elif loaded_content["type"] == "testcase": tests_mapping.setdefault("testcases", []).append(loaded_content) elif loaded_content["type"] == "api": tests_mapping.setdefault("apis", []).append(loaded_content) if os.path.isdir(path): files_list = load_folder_files(path) for path in files_list: __load_file_content(path) elif os.path.isfile(path): __load_file_content(path) return tests_mapping
def generate_conftest_for_summary(args: List): for arg in args: if os.path.exists(arg): test_path = arg # FIXME: several test paths maybe specified break else: raise exceptions.FileNotFound(f"No test path specified!") project_meta = load_project_meta(test_path) conftest_path = os.path.join(project_meta.PWD, "conftest.py") if os.path.isfile(conftest_path): return conftest_content = '''# NOTICE: Generated By HttpRunner. import json import os import time import pytest from loguru import logger from httprunner.utils import get_platform @pytest.fixture(scope="session", autouse=True) def session_fixture(request): """setup and teardown each task""" logger.info(f"start running testcases ...") start_at = time.time() yield logger.info(f"task finished, generate task summary for --save-tests") summary = { "success": True, "stat": { "testcases": {"total": 0, "success": 0, "fail": 0}, "teststeps": {"total": 0, "failures": 0, "successes": 0}, }, "time": {"start_at": start_at, "duration": time.time() - start_at}, "platform": get_platform(), "details": [], } for item in request.node.items: testcase_summary = item.instance.get_summary() summary["success"] &= testcase_summary.success summary["stat"]["testcases"]["total"] += 1 summary["stat"]["teststeps"]["total"] += len(testcase_summary.step_datas) if testcase_summary.success: summary["stat"]["testcases"]["success"] += 1 summary["stat"]["teststeps"]["successes"] += len( testcase_summary.step_datas ) else: summary["stat"]["testcases"]["fail"] += 1 summary["stat"]["teststeps"]["successes"] += ( len(testcase_summary.step_datas) - 1 ) summary["stat"]["teststeps"]["failures"] += 1 summary["details"].append(testcase_summary.dict()) summary_path = "{{SUMMARY_PATH_PLACEHOLDER}}" summary_dir = os.path.dirname(summary_path) os.makedirs(summary_dir, exist_ok=True) with open(summary_path, "w", encoding="utf-8") as f: json.dump(summary, f, indent=4) logger.info(f"generated task summary: {summary_path}") ''' test_path = os.path.abspath(test_path) logs_dir_path = os.path.join(project_meta.PWD, "logs") test_path_relative_path = test_path[len(project_meta.PWD) + 1 :] if os.path.isdir(test_path): file_foder_path = os.path.join(logs_dir_path, test_path_relative_path) dump_file_name = "all.summary.json" else: file_relative_folder_path, test_file = os.path.split(test_path_relative_path) file_foder_path = os.path.join(logs_dir_path, file_relative_folder_path) test_file_name, _ = os.path.splitext(test_file) dump_file_name = f"{test_file_name}.summary.json" summary_path = os.path.join(file_foder_path, dump_file_name) conftest_content = conftest_content.replace( "{{SUMMARY_PATH_PLACEHOLDER}}", summary_path ) with open(conftest_path, "w", encoding="utf-8") as f: f.write(conftest_content) logger.info("generated conftest.py to generate summary.json")
def load_tests(path, dot_env_path=None): """ load testcases from file path, extend and merge with api/testcase definitions. Args: path (str/list): testcase file/foler path. path could be in several types: - absolute/relative file path - absolute/relative folder path - list/set container with file(s) and/or folder(s) dot_env_path (str): specified .env file path Returns: list: testcases list, each testcase is corresponding to a file [ { # testcase data structure "config": { "name": "desc1", "path": "testcase1_path", "variables": [], # optional "request": {} # optional "refs": { "debugtalk": { "variables": {}, "functions": {} }, "env": {}, "def-api": {}, "def-testcase": {} } }, "teststeps": [ # teststep data structure { 'name': 'test step desc2', 'variables': [], # optional 'extract': [], # optional 'validate': [], 'request': {}, 'function_meta': {} }, teststep2 # another teststep dict ] }, testcase_dict_2 # another testcase dict ] """ if isinstance(path, (list, set)): testcases_list = [] for file_path in set(path): testcases = load_tests(file_path, dot_env_path) if not testcases: continue testcases_list.extend(testcases) return testcases_list if not os.path.exists(path): err_msg = "path not exist: {}".format(path) logger.log_error(err_msg) raise exceptions.FileNotFound(err_msg) if not os.path.isabs(path): path = os.path.join(os.getcwd(), path) if os.path.isdir(path): files_list = load_folder_files(path) testcases_list = load_tests(files_list, dot_env_path) elif os.path.isfile(path): try: project_mapping = load_project_tests(path, dot_env_path) testcase = _load_test_file(path, project_mapping) testcase["config"]["path"] = path testcase["config"]["refs"] = project_mapping testcases_list = [testcase] except exceptions.FileFormatError: testcases_list = [] return testcases_list