示例#1
0
    def run(self, path_or_tests, dot_env_path=None, mapping=None):
        """ main interface.

        Args:
            path_or_tests:
                str: testcase/testsuite file/foler path
                dict: valid testcase/testsuite data
            dot_env_path (str): specified .env file path.
            mapping (dict): if mapping is specified, it will override variables in config block.

        Returns:
            dict: result summary

        """
        logger.log_info("HttpRunner version: {}".format(__version__))
        if loader.is_test_path(path_or_tests):
            return self.run_path(path_or_tests, dot_env_path, mapping)
        elif loader.is_test_content(path_or_tests):
            project_working_directory = path_or_tests.get(
                "project_mapping", {}).get("PWD", os.getcwd())
            loader.init_pwd(project_working_directory)
            return self.run_tests(path_or_tests)
        else:
            raise exceptions.ParamsError(
                "Invalid testcase path or testcases: {}".format(path_or_tests))
示例#2
0
def getTokenFromHodor(user, password):
    try:
        project_working_directory = os.getcwd()
        goFileToGetToken = os.path.join(project_working_directory, "aleo-go/src/aleo-e2e/cmd/hodor-auth")
        newGoEnvPATH = os.path.join(project_working_directory, "aleo-go")

        whole_cmd = 'go run {} --url {} --user {} --password {}'.format(
            goFileToGetToken, BASE_URL, user, password)
        s = subprocess.Popen(whole_cmd, stdout=subprocess.PIPE,
                             stderr=subprocess.PIPE, shell=True,
                             env={"GOPATH": newGoEnvPATH})

        error = s.stderr.read().decode('utf8')

        if error:
            logger.log_info(
                'cannot get the token, error message is {}'.format(error))
            raise Exception()

        result = s.stdout.read().decode('utf8')
        token = result.split('\n')[-2]
        logger.log_info('the token is {}'.format(token))

    except Exception as e:
            logger.log_error("cannot get hodor token")
            logger.logging.exception(e)

    return "Bearer " + token
示例#3
0
    def extract_response(self, extractors):
        """ extract value from requests.Response and store in OrderedDict.
        @param (list) extractors
            [
                {"resp_status_code": "status_code"},
                {"resp_headers_content_type": "headers.content-type"},
                {"resp_content": "content"},
                {"resp_content_person_first_name": "content.person.name.first_name"}
            ]
        @return (OrderDict) variable binds ordered dict
        """
        if not extractors:
            return {}

        logger.log_info("start to extract from response object.")
        extracted_variables_mapping = OrderedDict()
        extract_binds_order_dict = utils.convert_to_order_dict(extractors)

        for key, field in extract_binds_order_dict.items():
            if not isinstance(field, basestring):
                raise exception.ParamsError("invalid extractors in testcase!")

            extracted_variables_mapping[key] = self.extract_field(field)

        return extracted_variables_mapping
示例#4
0
    def __init__(self, failfast=False, save_tests=False, report_template=None, report_dir=None,
                 log_level="INFO", log_file=''):
        """ initialize HttpRunner.

        Args:
            failfast (bool): 在第一个错误或者失败时,停止测试运行.
            save_tests (bool): 将加载/解析的测试保存到json文件.
            report_template (str): 报表模板文件路径,模板应为jinja2格式.
            report_dir (str): html报告保存目录.
            log_level (str): 日志等级.
            log_file (str): 日志文件前缀名称.

        """
        log_name_timestamp = datetime.fromtimestamp(time.time()).strftime('%Y-%m-%d')
        log_path = os.path.join(os.getcwd(), 'logs')
        if not os.path.exists(log_path): os.mkdir(log_path)  # 创建logs目录
        log_file_path = os.path.join(log_path, (log_file + log_name_timestamp + ".log"))
        logger.setup_logger(log_level, log_file_path)  # 调用日志函数,参数 日志等级和日志文件路径
        logger.log_info("HttpRunner version: {}".format(__version__))

        self.exception_stage = "initialize HttpRunner()"
        kwargs = {
            "failfast": failfast,
            "resultclass": report.HtmlTestResult
        }
        self.unittest_runner = unittest.TextTestRunner(**kwargs)  # 实例化 TextTestRunner
        self.test_loader = unittest.TestLoader()  # 实例化 TestLoader
        self.save_tests = save_tests
        self.report_template = report_template
        self.report_dir = report_dir
        self._summary = None
示例#5
0
    def validate(self, validators, resp_obj):
        '''
        make validations
        '''

        evaluated_validators = []
        if not validators:
            return evaluated_validators

        logger.log_info('start to validate.')
        validate_pass = True

        for vaildator in validators:
            # evaluate validators with context variable mapping.
            evaluated_validator = self.__eval_check_item(
                parser.parse_validator(vaildator), resp_obj)

            try:
                self._do_validation(evaluated_validator)
            except exceptions.VaildationFailure:
                validate_pass = False

            evaluated_validators.append(evaluated_validator)

        if not validate_pass:
            raise exceptions.VaildationFailure
示例#6
0
    def __init__(self,
                 failfast=False,
                 save_tests=False,
                 report_template=None,
                 report_dir=None,
                 log_level="DEBUG",
                 log_file=None):
        """ initialize HttpRunner.

        Args:
            failfast (bool): stop the test run on the first error or failure.
            save_tests (bool): save loaded/parsed tests to JSON file.
            report_template (str): report template file path, template should be in Jinja2 format.
            report_dir (str): html report save directory.
            log_level (str): logging level.
            log_file (str): log file path.

        """
        logger.setup_logger(log_level, log_file)
        logger.log_info("HttpRunner version: {}".format(__version__))

        self.exception_stage = "initialize HttpRunner()"
        kwargs = {"failfast": failfast, "resultclass": report.HtmlTestResult}
        self.unittest_runner = unittest.TextTestRunner(**kwargs)
        self.test_loader = unittest.TestLoader()
        self.save_tests = save_tests
        self.report_template = report_template
        self.report_dir = report_dir
        self._summary = None
示例#7
0
    def extract_response(self, extractors):
        """ extract value from requests.Response and store in OrderedDict.
        @param (list) extractors
            [
                {"resp_status_code": "status_code"},
                {"resp_headers_content_type": "headers.content-type"},
                {"resp_content": "content"},
                {"resp_content_person_first_name": "content.person.name.first_name"}
            ]
        @return (OrderDict) variable binds ordered dict
        """
        if not extractors:
            return {}

        logger.log_info("start to extract from response object.")
        extracted_variables_mapping = OrderedDict()
        extract_binds_order_dict = utils.convert_to_order_dict(extractors)

        for key, field in extract_binds_order_dict.items():
            if not isinstance(field, basestring):
                raise exception.ParamsError("invalid extractors in testcase!")

            extracted_variables_mapping[key] = self.extract_field(field)

        return extracted_variables_mapping
示例#8
0
    def dbvalidate(self, dbvalidators):
        """ validate datebase item
        """

        evaluated_dbvalidators = []
        if not dbvalidators:
            return evaluated_dbvalidators

        logger.log_info("start to dbvalidate.")
        dbvalidate_pass = True
        failures = []

        for dbvalidator in dbvalidators:
            # evaluate dbvalidators with context variable mapping.
            evaluated_dbvalidator = self.eval_content(
                parser.parse_dbvalidator(dbvalidator))

            try:
                self._do_dbvalidation(evaluated_dbvalidator)
            except exceptions.DbValidationFailure as ex:
                dbvalidate_pass = False
                failures.append(str(ex))

            evaluated_dbvalidators.append(evaluated_dbvalidator)

            if not dbvalidate_pass:
                failures_string = "\n".join([failure for failure in failures])
                raise exceptions.DbValidationFailure(failures_string)
示例#9
0
    def extract_response(self, extractors):
        """ extract value from requests.Response and store in OrderedDict.
        @param (list) extractors
            [
                {"resp_status_code": "status_code"},
                {"resp_headers_content_type": "headers.content-type"},
                {"resp_content": "content"},
                {"resp_content_person_first_name": "content.person.name.first_name"}
            ]
        @return (OrderDict) variable binds ordered dict
        """
        if not extractors:
            return {}

        logger.log_info("start to extract from response object.")
        extracted_variables_mapping = OrderedDict()
        extract_binds_order_dict = utils.convert_to_order_dict(extractors)

        for key, field in extract_binds_order_dict.items():
            if not isinstance(field, basestring):
                raise exception.ParamsError("invalid extractors in testcase!")
            result = self.extract_field(field)
            extracted_variables_mapping[key] = result
            if not (isinstance(result, bool)
                    or bool(result)):  # False 可以return
                err_msg = u"extract data with delimiter can be None!\n"
                err_msg += u"response: {}\n".format(self.parsed_dict())
                err_msg += u"regex: {}\n".format(field)
                logger.log_error(err_msg)
                raise exception.ParamsError(err_msg)
        return extracted_variables_mapping
示例#10
0
    def validate(self, validators, resp_obj):
        """ make validations
        """
        if not validators:
            return

        logger.log_info("start to validate.")
        self.evaluated_validators = []
        validate_pass = True

        for validator in validators:
            # evaluate validators with context variable mapping.
            evaluated_validator = self.eval_check_item(
                testcase.parse_validator(validator),
                resp_obj
            )

            try:
                self.do_validation(evaluated_validator)
            except exceptions.ValidationFailure:
                validate_pass = False

            self.evaluated_validators.append(evaluated_validator)

        if not validate_pass:
            raise exceptions.ValidationFailure
示例#11
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
示例#12
0
    def validate(self, validators, resp_obj):
        """ make validations
        """
        evaluated_validators = []
        if not validators:
            return evaluated_validators

        logger.log_info("start to validate.")
        validate_pass = True
        failures = []

        for validator in validators:
            # evaluate validators with context variable mapping.
            evaluated_validator = self.__eval_check_item(
                parser.parse_validator(validator), resp_obj)

            try:
                self._do_validation(evaluated_validator)
            except exceptions.ValidationFailure as ex:
                validate_pass = False
                failures.append(str(ex))

            evaluated_validators.append(evaluated_validator)

        if not validate_pass:
            failures_string = "\n".join([failure for failure in failures])
            raise exceptions.ValidationFailure(failures_string)

        return evaluated_validators
示例#13
0
def render_html_report(summary,
                       html_report_name=None,
                       html_report_template=None,
                       data_or_report=False):
    """ render html report with specified report name and template
        if html_report_name is not specified, use current datetime
        if html_report_template is not specified, use default report template
    """
    if not html_report_template:
        html_report_template = os.path.join(
            os.path.abspath(os.path.dirname(__file__)), Path("templates"),
            Path("default_report_template.html"))
        logger.log_debug("No html report template specified, use default.")
    else:
        logger.log_info("render with html report template: {}".format(
            html_report_template))

    logger.log_info("Start to render Html report ...")
    logger.log_debug("render data: {}".format(summary))

    report_dir_path = os.path.join(os.path.abspath('.') + r'/reports')
    if html_report_name:
        summary["html_report_name"] = html_report_name
        # report_dir_path = os.path.join(report_dir_path, html_report_name)
        html_report_name += ".html"
    else:
        summary["html_report_name"] = ""

    if not os.path.isdir(report_dir_path):
        os.makedirs(report_dir_path)
    for index, suite_summary in enumerate(summary["details"]):
        if not suite_summary.get("name"):
            suite_summary["name"] = "test suite {}".format(index)
        for record in suite_summary.get("records"):
            meta_data = record['meta_data']
            stringify_data(meta_data, 'request')
            stringify_data(meta_data, 'response')
    with io.open(
            html_report_template,
            "r",
    ) as fp_r:
        template_content = fp_r.read()
        # rendered_content = Template(template_content).render(summary)
        report_path = os.path.join(report_dir_path, html_report_name)
        # report_path = r'E:\project\source/reports\aaa.html'
        rendered_content = Template(template_content,
                                    extensions=["jinja2.ext.loopcontrols"
                                                ]).render(summary)
        if data_or_report:
            return rendered_content
        with io.open(
                report_path,
                'w',
        ) as fp_w:
            fp_w.write(rendered_content)
        return report_path
示例#14
0
def request(self, method, url, name=None, **kwargs):

    self.init_meta_data()

    # record test name
    self.meta_data["name"] = name

    # record original request info
    self.meta_data["data"][0]["request"]["method"] = method
    self.meta_data["data"][0]["request"]["url"] = url
    kwargs.setdefault("timeout", 120)
    self.meta_data["data"][0]["request"].update(kwargs)

    # prepend url with hostname unless it's already an absolute URL
    url = build_url(self.base_url, url)

    start_timestamp = time.time()
    response = self._send_request_safe_mode(method, url, **kwargs)

    # requests包get响应内容中文乱码解决
    if response.apparent_encoding:
        response.encoding = response.apparent_encoding

    response_time_ms = round((time.time() - start_timestamp) * 1000, 2)

    # get the length of the content, but if the argument stream is set to True, we take
    # the size from the content-length header, in order to not trigger fetching of the body
    if kwargs.get("stream", False):
        content_size = int(dict(response.headers).get("content-length") or 0)
    else:
        content_size = len(response.content or "")

    # record the consumed time
    self.meta_data["stat"] = {
        "response_time_ms": response_time_ms,
        "elapsed_ms": response.elapsed.microseconds / 1000.0,
        "content_size": content_size
    }
    # record request and response histories, include 30X redirection
    response_list = response.history + [response]
    self.meta_data["data"] = [
        self.get_req_resp_record(resp_obj) for resp_obj in response_list
    ]
    self.meta_data["data"][0]["request"].update(kwargs)
    try:
        response.raise_for_status()
    except RequestException as e:
        logger.log_error(u"{exception}".format(exception=str(e)))
    else:
        logger.log_info(
            """status_code: {}, response_time(ms): {} ms, response_length: {} bytes\n"""
            .format(response.status_code, response_time_ms, content_size))

    return response
示例#15
0
def load_dot_env_file(path):
    """ load .env file and set to os.environ
    """
    if not os.path.isfile(path):
        return

    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("=")
            os.environ[variable] = value
            logger.log_debug("Loaded variable: {}".format(variable))
示例#16
0
def main_hrun(testset_path, executor=None, request_data=None):
    """
    用例运行
    :param testset_path: dict or list
    :param report_name: str
    :return:
    """
    logger.setup_logger('INFO')
    kwargs = {
        "failfast": False,
    }
    runner = HttpRunner(**kwargs)
    error_info = {
        'start_time': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    }
    report_type = 'test'
    report_name = '执行异常'

    try:
        id = request_data.pop('id')
        base_url = request_data.pop('env_name')
        type = request_data.pop('type')
        report_name = request_data.get('report_name', None)
        if type:
            report_type = type

        report_name2 = run_test_by_type(id, base_url, testset_path, type)

        if not report_name:
            report_name = report_name2

        runner.run2(testset_path)
        shutil.rmtree(testset_path)
        runner.summary = timestamp_to_datetime(runner.summary)
        report_path = add_test_reports(runner,
                                       report_name=report_name,
                                       report_type=report_type,
                                       executor=executor)
    except Exception as e:
        logger.log_info("出现异常: {0}".format(e))
        error_info['error_msg'] = "出现异常: {0}".format(e)
        add_error_reports(error_info,
                          report_name=report_name,
                          report_type=report_type,
                          executor=executor)
    except BaseException as e:
        logger.log_info("出现异常: {0}".format(e))
        error_info['error_msg'] = "出现异常: {0}".format(e)
        add_error_reports(error_info,
                          report_name=report_name,
                          report_type=report_type,
                          executor=executor)
示例#17
0
def print_info(info_mapping):
    """ print info in mapping.

    Args:
        info_mapping (dict): input(variables) or output mapping.

    Examples:
        >>> info_mapping = {
                "var_a": "hello",
                "var_b": "world"
            }
        >>> info_mapping = {
                "status_code": 500
            }
        >>> print_info(info_mapping)
        ==================== Output ====================
        Key              :  Value
        ---------------- :  ----------------------------
        var_a            :  hello
        var_b            :  world
        ------------------------------------------------

    """
    if not info_mapping:
        return

    content_format = "{:<16} : {:<}\n"
    content = "\n==================== Output ====================\n"
    content += content_format.format("Variable", "Value")
    content += content_format.format("-" * 16, "-" * 29)

    for key, value in info_mapping.items():
        if isinstance(value, (tuple, collections.deque)):
            continue
        elif isinstance(value, (dict, list)):
            value = json.dumps(value)
        elif value is None:
            value = "None"

        if is_py2:
            if isinstance(key, unicode):
                key = key.encode("utf-8")
            if isinstance(value, unicode):
                value = value.encode("utf-8")

        content += content_format.format(key, value)

    content += "-" * 48 + "\n"
    logger.log_info(content)
示例#18
0
    def run(self, path_or_tests, dot_env_path=None, mapping=None):
        """ main interface.

        Args:
            path_or_tests:
                str: testcase/testsuite file/foler path
                dict: valid testcase/testsuite data

        """
        logger.log_info("HttpRunner version: {}".format(__version__))
        if validator.is_testcase_path(path_or_tests):
            return self.run_path(path_or_tests, dot_env_path, mapping)
        elif validator.is_testcases(path_or_tests):
            return self.run_tests(path_or_tests)
        else:
            raise exceptions.ParamsError(
                "Invalid testcase path or testcases: {}".format(path_or_tests))
示例#19
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
示例#20
0
def write_data(res, json_path):
    """
    把处理后的参数写入json文件
    :param res:
    :param json_path:
    :return:
    """
    if isinstance(res, dict) or isinstance(res, list):
        with open(json_path, 'w', encoding='utf-8') as f:
            json.dump(res, f, ensure_ascii=False, sort_keys=True, indent=4)
            logger.log_info(
                'Interface Params Total:{} ,write to json file successfully! {}\n'.format(len(res), json_path))
    elif isinstance(res, str):
        with open(json_path, "w", encoding='utf-8') as f:
            f.write(res)
    else:
        logger.log_error('{} Params is not dict.\n'.format(write_data.__name__))
示例#21
0
def load_dot_env_file():
    """ load .env file, .env file should be located in project working directory by default.
        If dot_env_path is specified, it will be loaded instead.

    Returns:
        dict: environment variables mapping

            {
                "UserName": "******",
                "Password": "******",
                "PROJECT_KEY": "ABCDEFGH"
            }

    Raises:
        exceptions.FileFormatError: If env file format is invalid.

    """
    path = dot_env_path or os.path.join(project_working_directory, ".env")
    if not os.path.isfile(path):
        if dot_env_path:
            logger.log_error(".env file not exist: {}".format(dot_env_path))
            sys.exit(1)
        else:
            logger.log_debug(
                ".env file not exist in: {}".format(project_working_directory))
            return {}

    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:
            # 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()

    project_mapping["env"] = env_variables_mapping
    utils.set_os_environ(env_variables_mapping)

    return env_variables_mapping
示例#22
0
    def _run_suite(self, test_suite):
        """ run tests in test_suite

        Args:
            test_suite: unittest.TestSuite()

        Returns:
            list: tests_results

        """
        tests_results = []

        for testcase in test_suite:
            testcase_name = testcase.config.get("name")
            logger.log_info("Start to run testcase: {}".format(testcase_name))
            result = self.unittest_runner.run(testcase)
            tests_results.append((testcase, result))
        return tests_results
示例#23
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 exception.FileNotFoundError("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))
示例#24
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))
示例#25
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):
        return {}

    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)
            elif line.startswith("#") or line.startswith("\n"):
                pass
            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
示例#26
0
 def _send_request_safe_mode(self, host, port, service, method, params,
                             **kwargs):
     """
     Send a dubbo request
     TODO: 设计可选参数,设计ApiResponse使用例出现问题后处理不出错
     """
     meta_data = {
         "host": host,
         "port": port,
         "service": service,
         "method": method,
         "params": params,
     }
     try:
         msg = "processed request:\n"
         msg += "> {service}.{method}\n".format(service=service,
                                                method=method)
         msg += "> params: {params}".format(params=params)
         self._dubbo.set_host(host, port)
         response_data = self._dubbo.invoke(service, method, params)
         response = {
             "body": response_data,
             "request": {
                 "host": host,
                 "port": port,
                 "service": service,
                 "method": method
             }
         }
     except timeout as e:
         logger.log_error("{exception}".format(exception=str(e)))
         response = DubboApiResponse(**meta_data)
         response.error = e
     except Exception as e:
         logger.log_info(
             "something unknown happened while requesting {}.{}".format(
                 service, method))
         response = DubboApiResponse(**meta_data)
         response.error = e
     return response
示例#27
0
def render_html_report(summary,
                       html_report_name=None,
                       html_report_template=None):
    """ render html report with specified report name and template
        if html_report_name is not specified, use current datetime
        if html_report_template is not specified, use default report template
    """
    if not html_report_template:
        html_report_template = os.path.join(
            os.path.abspath(os.path.dirname(__file__)), "templates",
            "default_report_template.html")
        logger.log_debug("No html report template specified, use default.")
    else:
        logger.log_info("render with html report template: {}".format(
            html_report_template))

    logger.log_info("Start to render Html report ...")
    logger.log_debug("render data: {}".format(summary))

    report_dir_path = os.path.join(os.path.abspath('..') + r'/reports')
    start_datetime = summary["time"]["start_at"]
    if html_report_name:
        summary["html_report_name"] = html_report_name
        report_dir_path = os.path.join(report_dir_path, html_report_name)
        html_report_name += "-{}.html".format(start_datetime)
    else:
        summary["html_report_name"] = ""

    if not os.path.isdir(report_dir_path):
        os.makedirs(report_dir_path)

    for record in summary.get("records"):
        meta_data = record['meta_data']
        stringify_body(meta_data, 'request')
        stringify_body(meta_data, 'response')
    with io.open(html_report_template, "r", encoding='utf-8') as fp_r:
        template_content = fp_r.read()
        rendered_content = Template(template_content).render(summary)

    return rendered_content
示例#28
0
    def run_tests(self, unittest_runner, test_suite):
        """ run tests with unittest_runner and test_suite

        Args:
            unittest_runner: unittest.TextTestRunner()
            test_suite: unittest.TestSuite()

        Returns:
            list: tests_results

        """
        self.exception_stage = "running tests"
        tests_results = []

        for testcase in test_suite:
            testcase_name = testcase.config.get("name")
            logger.log_info("Start to run testcase: {}".format(testcase_name))

            result = unittest_runner.run(testcase)
            tests_results.append((testcase, result))

        return tests_results
示例#29
0
    def validate(self, validators, resp_obj):
        """ make validations
        """
        evaluated_validators = []
        if not validators:
            return evaluated_validators

        logger.log_info("start to validate.")
        failures = []

        for validator in validators:
            # evaluate validators with context variable mapping.
            evaluated_validator = self.__eval_check_item(
                parser.parse_validator(validator), resp_obj)

            try:
                self._do_validation(evaluated_validator)
            except exceptions.ValidationFailure as ex:
                failures.append(str(ex))

            evaluated_validators.append(evaluated_validator)

        return evaluated_validators
示例#30
0
    def _run_suite(self, test_suite):
        """ 运行测试套件

        Args:
            test_suite: unittest.TestSuite()

        Returns:
            list: tests_results测试结果

        """
        tests_results = []

        for testcase in test_suite:  # 遍历用例集中的每一个用例
            testcase_name = testcase.config.get("name")
            logger.log_info("Start to run testcase: {}".format(testcase_name))

            result = self.unittest_runner.run(testcase)
            if result.wasSuccessful():
                tests_results.append((testcase, result))
            else:
                tests_results.insert(0, (testcase, result))

        return tests_results
示例#31
0
def load_env_file():
    '''
    load .env file, .env file should be located in project working directory.
    Returns:
        dict: enviroment variables mapping
            {
                'username':'******',
                'password':'******',
                'PROJECT_KEY':'ABCDEFGH'
            }
    Raises:
        exceptions.FileFormatError: If env file format is invalid.
    '''

    path = os.path.join(project_working_directory, '.env')
    if not os.path.isfile(path):
        logger.log_debug(
            f'.env file not exist in: {project_working_directory}')
        return {}

    logger.log_info(f'Loading enviroment variables from {path}')
    env_variables_mapping = {}
    with 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
    utils.set_os_environ(env_variables_mapping)

    return env_variables_mapping
示例#32
0
def gen_html_report(summary,
                    report_template=None,
                    report_dir=None,
                    report_file=None):
    """ render html report with specified report name and template

    Args:
        summary (dict): test result summary data
        report_template (str): specify html report template path, template should be in Jinja2 format.
        report_dir (str): specify html report save directory
        report_file (str): specify html report file path, this has higher priority than specifying report dir.

    """
    if not summary["time"] or summary["stat"]["testcases"]["total"] == 0:
        logger.log_error("test result summary is empty ! {}".format(summary))
        raise SummaryEmpty

    if not report_template:
        report_template = os.path.join(
            os.path.abspath(os.path.dirname(__file__)), "template.html")
        logger.log_debug("No html report template specified, use default.")
    else:
        logger.log_info(
            "render with html report template: {}".format(report_template))

    logger.log_info("Start to render Html report ...")

    start_at_timestamp = summary["time"]["start_at"]
    utc_time_iso_8601_str = datetime.utcfromtimestamp(
        start_at_timestamp).isoformat()
    summary["time"]["start_datetime"] = utc_time_iso_8601_str

    if report_file:
        report_dir = os.path.dirname(report_file)
        report_file_name = os.path.basename(report_file)
    else:
        report_dir = report_dir or os.path.join(os.getcwd(), "reports")
        # fix #826: Windows does not support file name include ":"
        report_file_name = "{}.html".format(
            utc_time_iso_8601_str.replace(":", "").replace("-", ""))

    if not os.path.isdir(report_dir):
        os.makedirs(report_dir)

    report_path = os.path.join(report_dir, report_file_name)
    # custom: add filter, by zheng.zhang
    template_dir, template_file = os.path.split(report_template)
    env = Environment(loader=FileSystemLoader(template_dir),
                      extensions=["jinja2.ext.loopcontrols"])
    template = env.get_template(template_file)
    with io.open(report_path, 'w', encoding='utf-8') as fp_w:
        rendered_content = template.render(summary)
        fp_w.write(rendered_content)

    logger.log_info("Generated Html report: {}".format(report_path))

    return report_path
示例#33
0
def render_html_report(summary, html_report_name=None, html_report_template=None):
    """ render html report with specified report name and template
        if html_report_name is not specified, use current datetime
        if html_report_template is not specified, use default report template
    """
    if not html_report_template:
        html_report_template = os.path.join(
            os.path.abspath(os.path.dirname(__file__)),
            "templates",
            "default_report_template.html"
        )
        logger.log_debug("No html report template specified, use default.")
    else:
        logger.log_info("render with html report template: {}".format(html_report_template))

    logger.log_info("Start to render Html report ...")
    logger.log_debug("render data: {}".format(summary))

    report_dir_path = os.path.join(os.getcwd(), "reports")
    start_datetime = summary["time"]["start_at"].strftime('%Y-%m-%d-%H-%M-%S')
    if html_report_name:
        summary["html_report_name"] = html_report_name
        report_dir_path = os.path.join(report_dir_path, html_report_name)
        html_report_name += "-{}.html".format(start_datetime)
    else:
        summary["html_report_name"] = ""
        html_report_name = "{}.html".format(start_datetime)

    if not os.path.isdir(report_dir_path):
        os.makedirs(report_dir_path)

    for record in summary.get("records"):
        meta_data = record['meta_data']
        stringify_body(meta_data, 'request')
        stringify_body(meta_data, 'response')

    with io.open(html_report_template, "r", encoding='utf-8') as fp_r:
        template_content = fp_r.read()
        report_path = os.path.join(report_dir_path, html_report_name)
        with io.open(report_path, 'w', encoding='utf-8') as fp_w:
            rendered_content = Template(template_content).render(summary)
            fp_w.write(rendered_content)

    logger.log_info("Generated Html report: {}".format(report_path))

    return report_path
示例#34
0
    def request(self, method, url, name=None, **kwargs):
        """
        Constructs and sends a :py:class:`requests.Request`.
        Returns :py:class:`requests.Response` object.

        :param method:
            method for the new :class:`Request` object.
        :param url:
            URL for the new :class:`Request` object.
        :param name: (optional)
            Placeholder, make compatible with Locust's HttpSession
        :param params: (optional)
            Dictionary or bytes to be sent in the query string for the :class:`Request`.
        :param data: (optional)
            Dictionary or bytes to send in the body of the :class:`Request`.
        :param headers: (optional)
            Dictionary of HTTP Headers to send with the :class:`Request`.
        :param cookies: (optional)
            Dict or CookieJar object to send with the :class:`Request`.
        :param files: (optional)
            Dictionary of ``'filename': file-like-objects`` for multipart encoding upload.
        :param auth: (optional)
            Auth tuple or callable to enable Basic/Digest/Custom HTTP Auth.
        :param timeout: (optional)
            How long to wait for the server to send data before giving up, as a float, or \
            a (`connect timeout, read timeout <user/advanced.html#timeouts>`_) tuple.
            :type timeout: float or tuple
        :param allow_redirects: (optional)
            Set to True by default.
        :type allow_redirects: bool
        :param proxies: (optional)
            Dictionary mapping protocol to the URL of the proxy.
        :param stream: (optional)
            whether to immediately download the response content. Defaults to ``False``.
        :param verify: (optional)
            if ``True``, the SSL cert will be verified. A CA_BUNDLE path can also be provided.
        :param cert: (optional)
            if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair.
        """
        # store detail data of request and response
        self.meta_data = {}

        # prepend url with hostname unless it's already an absolute URL
        url = self._build_url(url)

        # set up pre_request hook for attaching meta data to the request object
        self.meta_data["method"] = method

        kwargs.setdefault("timeout", 120)

        self.meta_data["request_time"] = time.time()
        response = self._send_request_safe_mode(method, url, **kwargs)
        # record the consumed time
        self.meta_data["response_time_ms"] = round((time.time() - self.meta_data["request_time"]) * 1000, 2)
        self.meta_data["elapsed_ms"] = response.elapsed.microseconds / 1000.0

        self.meta_data["url"] = (response.history and response.history[0] or response)\
            .request.url

        self.meta_data["request_headers"] = response.request.headers
        self.meta_data["request_body"] = response.request.body
        self.meta_data["status_code"] = response.status_code
        self.meta_data["response_headers"] = response.headers

        try:
            self.meta_data["response_body"] = response.json()
        except ValueError:
            self.meta_data["response_body"] = response.content

        msg = "response details:\n"
        msg += "> status_code: {}\n".format(self.meta_data["status_code"])
        msg += "> headers: {}\n".format(self.meta_data["response_headers"])
        msg += "> body: {}".format(self.meta_data["response_body"])
        logger.log_debug(msg)

        # get the length of the content, but if the argument stream is set to True, we take
        # the size from the content-length header, in order to not trigger fetching of the body
        if kwargs.get("stream", False):
            self.meta_data["content_size"] = int(self.meta_data["response_headers"].get("content-length") or 0)
        else:
            self.meta_data["content_size"] = len(response.content or "")

        try:
            response.raise_for_status()
        except RequestException as e:
            logger.log_error(u"{exception}".format(exception=str(e)))
        else:
            logger.log_info(
                """status_code: {}, response_time(ms): {} ms, response_length: {} bytes""".format(
                    self.meta_data["status_code"],
                    self.meta_data["response_time_ms"],
                    self.meta_data["content_size"]
                )
            )

        return response
示例#35
0
    def run_test(self, testcase_dict):
        """ run single testcase.
        @param (dict) testcase_dict
            {
                "name": "testcase description",
                "skip": "skip this test unconditionally",
                "times": 3,
                "requires": [],         # optional, override
                "function_binds": {},   # optional, override
                "variables": [],        # optional, override
                "request": {
                    "url": "http://127.0.0.1:5000/api/users/1000",
                    "method": "POST",
                    "headers": {
                        "Content-Type": "application/json",
                        "authorization": "$authorization",
                        "random": "$random"
                    },
                    "body": '{"name": "user", "password": "******"}'
                },
                "extract": [],              # optional
                "validate": [],             # optional
                "setup_hooks": [],          # optional
                "teardown_hooks": []        # optional
            }
        @return True or raise exception during test
        """
        # check skip
        self._handle_skip_feature(testcase_dict)

        # prepare
        parsed_request = self.init_config(testcase_dict, level="testcase")
        self.context.bind_testcase_variable("request", parsed_request)

        # setup hooks
        setup_hooks = testcase_dict.get("setup_hooks", [])
        setup_hooks.insert(0, "${setup_hook_prepare_kwargs($request)}")
        self.do_hook_actions(setup_hooks)

        try:
            url = parsed_request.pop('url')
            method = parsed_request.pop('method')
            group_name = parsed_request.pop("group", None)
        except KeyError:
            raise exception.ParamsError("URL or METHOD missed!")

        logger.log_info("{method} {url}".format(method=method, url=url))
        logger.log_debug("request kwargs(raw): {kwargs}".format(kwargs=parsed_request))

        # request
        resp = self.http_client_session.request(
            method,
            url,
            name=group_name,
            **parsed_request
        )
        resp_obj = response.ResponseObject(resp)

        # teardown hooks
        teardown_hooks = testcase_dict.get("teardown_hooks", [])
        if teardown_hooks:
            self.context.bind_testcase_variable("response", resp_obj)
            self.do_hook_actions(teardown_hooks)

        # extract
        extractors = testcase_dict.get("extract", []) or testcase_dict.get("extractors", [])
        extracted_variables_mapping = resp_obj.extract_response(extractors)
        self.context.bind_extracted_variables(extracted_variables_mapping)
        
        # validate
        validators = testcase_dict.get("validate", []) or testcase_dict.get("validators", [])
        try:
            self.context.validate(validators, resp_obj)
        except (exception.ParamsError, exception.ResponseError, \
            exception.ValidationError, exception.ParseResponseError):
            # log request
            err_req_msg = "request: \n"
            err_req_msg += "headers: {}\n".format(parsed_request.pop("headers", {}))
            for k, v in parsed_request.items():
                err_req_msg += "{}: {}\n".format(k, v)
            logger.log_error(err_req_msg)

            # log response
            err_resp_msg = "response: \n"
            err_resp_msg += "status_code: {}\n".format(resp_obj.status_code)
            err_resp_msg += "headers: {}\n".format(resp_obj.headers)
            err_resp_msg += "content: {}\n".format(resp_obj.content)
            logger.log_error(err_resp_msg)

            raise