Beispiel #1
0
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)
Beispiel #2
0
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)
Beispiel #3
0
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)
Beispiel #4
0
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
Beispiel #5
0
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
Beispiel #6
0
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
Beispiel #7
0
    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
Beispiel #8
0
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 []
Beispiel #9
0
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
Beispiel #10
0
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 []
Beispiel #11
0
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 []
Beispiel #12
0
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
Beispiel #13
0
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
Beispiel #14
0
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))
Beispiel #15
0
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
Beispiel #16
0
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
Beispiel #17
0
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")
Beispiel #18
0
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