示例#1
0
def print_io(in_out):
    """ print input(variables) and output.

    Args:
        in_out (dict): input(variables) and output mapping.

    Examples:
        >>> in_out = {
                "in": {
                    "var_a": "hello",
                    "var_b": "world"
                },
                "out": {
                    "status_code": 500
                }
            }
        >>> print_io(in_out)
        ================== Variables & Output ==================
        Type   | Variable         :  Value
        ------ | ---------------- :  ---------------------------
        Var    | var_a            :  hello
        Var    | var_b            :  world

        Out    | status_code      :  500
        --------------------------------------------------------

    """
    content_format = "{:<6} | {:<16} :  {:<}\n"
    content = "\n================== Variables & Output ==================\n"
    content += content_format.format("Type", "Variable", "Value")
    content += content_format.format("-" * 6, "-" * 16, "-" * 27)

    def prepare_content(var_type, in_out):
        content = ""
        for variable, value in in_out.items():
            if isinstance(value, tuple):
                continue
            elif isinstance(value, (dict, list)):
                value = json.dumps(value)

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

            content += content_format.format(var_type, variable, value)

        return content

    _in = in_out["in"]
    _out = in_out["out"]

    content += prepare_content("Var", _in)
    content += "\n"
    content += prepare_content("Out", _out)
    content += "-" * 56 + "\n"

    logger.log_debug(content)
示例#2
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",
            "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_at_timestamp = int(summary["time"]["start_at"])
    summary["time"]["start_datetime"] = datetime.fromtimestamp(
        start_at_timestamp).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_at_timestamp)
    else:
        summary["html_report_name"] = ""
        html_report_name = "{}.html".format(start_at_timestamp)

    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", 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,
                                        extensions=["jinja2.ext.loopcontrols"
                                                    ]).render(summary)
            fp_w.write(rendered_content)

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

    return report_path
示例#3
0
    def _do_validation(self, validator_dict):
        """ validate with functions

        Args:
            validator_dict (dict): validator dict
                {
                    "check": "status_code",
                    "check_value": 200,
                    "expect": 201,
                    "comparator": "eq"
                }

        """
        # TODO: move comparator uniform to init_test_suites
        comparator = utils.get_uniform_comparator(validator_dict["comparator"])
        validate_func = parser.get_mapping_function(
            comparator, self.TESTCASE_SHARED_FUNCTIONS_MAPPING)

        check_item = validator_dict["check"]
        check_value = validator_dict["check_value"]
        expect_value = validator_dict["expect"]

        if (check_value is None or expect_value is None) \
            and comparator not in ["is", "eq", "equals", "=="]:
            raise exceptions.ParamsError(
                "Null value can only be compared with comparator: eq/equals/=="
            )

        validate_msg = "validate: {} {} {}({})".format(
            check_item, comparator, expect_value,
            type(expect_value).__name__)

        try:
            validator_dict["check_result"] = "pass"
            validate_func(check_value, expect_value)
            validate_msg += "\t==> pass"
            logger.log_debug(validate_msg)
        except (AssertionError, TypeError):
            validate_msg += "\t==> fail"
            validate_msg += "\n{}({}) {} {}({})".format(
                check_value,
                type(check_value).__name__, comparator, expect_value,
                type(expect_value).__name__)
            logger.log_error(validate_msg)
            validator_dict["check_result"] = "fail"
            raise exceptions.ValidationFailure(validate_msg)
示例#4
0
 def _send_request_safe_mode(self, method, url, **kwargs):
     """
     Send a HTTP request, and catch any exception that might occur due to connection problems.
     Safe mode has been removed from requests 1.x.
     """
     try:
         msg = "processed request:\n"
         msg += "> {method} {url}\n".format(method=method, url=url)
         msg += "> kwargs: {kwargs}".format(kwargs=kwargs)
         logger.log_debug(msg)
         return requests.Session.request(self, method, url, **kwargs)
     except (MissingSchema, InvalidSchema, InvalidURL):
         raise
     except RequestException as ex:
         resp = ApiResponse()
         resp.error = ex
         resp.status_code = 0  # with this status_code, content returns None
         resp.request = Request(method, url).prepare()
         return resp
    def extract_field(self, field):
        """ extract value from requests.Response.
        """
        if not isinstance(field, basestring):
            err_msg = u"Invalid extractor! => {}\n".format(field)
            logger.log_error(err_msg)
            raise exceptions.ParamsError(err_msg)

        msg = "extract: {}".format(field)

        if text_extractor_regexp_compile.match(field):
            value = self._extract_field_with_regex(field)
        else:
            value = self._extract_field_with_delimiter(field)

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

        msg += "\t=> {}".format(value)
        logger.log_debug(msg)

        return value
示例#6
0
 def log_print(request_response):
     msg = "\n================== {} details ==================\n".format(
         request_response)
     for key, value in self.meta_data[request_response].items():
         msg += "{:<16} : {}\n".format(key, repr(value))
     logger.log_debug(msg)
示例#7
0
    def run_test(self, teststep_dict):
        """ run single teststep.

        Args:
            teststep_dict (dict): teststep info
                {
                    "name": "teststep description",
                    "skip": "skip this test unconditionally",
                    "times": 3,
                    "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
                }

        Raises:
            exceptions.ParamsError
            exceptions.ValidationFailure
            exceptions.ExtractFailure

        """
        # check skip
        self._handle_skip_feature(teststep_dict)

        # prepare
        extractors = teststep_dict.get("extract", []) or teststep_dict.get(
            "extractors", [])
        validators = teststep_dict.get("validate", []) or teststep_dict.get(
            "validators", [])
        parsed_request = self.init_test(teststep_dict, level="teststep")
        self.context.update_teststep_variables_mapping("request",
                                                       parsed_request)

        # setup hooks
        setup_hooks = teststep_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 exceptions.ParamsError("URL or METHOD missed!")

        # TODO: move method validation to json schema
        valid_methods = [
            "GET", "HEAD", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"
        ]
        if method.upper() not in valid_methods:
            err_msg = u"Invalid HTTP method! => {}\n".format(method)
            err_msg += "Available HTTP methods: {}".format(
                "/".join(valid_methods))
            logger.log_error(err_msg)
            raise exceptions.ParamsError(err_msg)

        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 = teststep_dict.get("teardown_hooks", [])
        if teardown_hooks:
            logger.log_info("start to run teardown hooks")
            self.context.update_teststep_variables_mapping(
                "response", resp_obj)
            self.do_hook_actions(teardown_hooks)

        # extract
        extracted_variables_mapping = resp_obj.extract_response(extractors)
        self.context.update_testcase_runtime_variables_mapping(
            extracted_variables_mapping)

        # validate
        try:
            self.evaluated_validators = self.context.validate(
                validators, resp_obj)
        except (exceptions.ParamsError, exceptions.ValidationFailure,
                exceptions.ExtractFailure):
            # 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, repr(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 += "body: {}\n".format(repr(resp_obj.text))
            logger.log_error(err_resp_msg)

            raise
示例#8
0
 def do_hook_actions(self, actions):
     for action in actions:
         logger.log_debug("call hook: {}".format(action))
         # TODO: check hook function if valid
         self.context.eval_content(action)
示例#9
0
def set_os_environ(variables_mapping):
    """ set variables mapping to os.environ
    """
    for variable in variables_mapping:
        os.environ[variable] = variables_mapping[variable]
        logger.log_debug("Loaded variable: {}".format(variable))
示例#10
0
    def render_html_report(self, **kwargs):
        """ 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
        """
        # 获取所需参数 -------------------------------------------------------------------------------------------------
        summary = self.summary
        result_stastic= {
            "testsRun": summary["stat"]["testsRun"],
            "successes": summary["stat"]["successes"],
            "errors": summary["stat"]["errors"],
            "failures": summary["stat"]["failures"],
            "skipped": summary["stat"]["skipped"]}
        report_name = kwargs.get("report_name", None)
        file_name = kwargs.get("file_name", None)
        dir_name = kwargs.get("dir_name", None)
        html_report_template = kwargs.get("html_report_template", None)

        # 选择模板------------------------------------------------------------------------------------------------------
        if not html_report_template:
            html_report_template = os.path.join(
                os.path.abspath(os.path.dirname(__file__)),
                "templates",
                "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))

        # 在reports文件夹下建立dir_name文件夹,如果没有就创建 ----------------------------------------------------------
        report_dir_path = os.path.join(os.getcwd(), "reports")
        report_dir_path = os.path.join(report_dir_path, dir_name)
        if not os.path.isdir(report_dir_path):
            os.makedirs(report_dir_path)

        #  在dir_name文件夹下建立file_name报告 -------------------------------------------------------------------------
        start_at_timestamp = int(summary["time"]["start_at"])
        summary["time"]["start_datetime"] = datetime.fromtimestamp(start_at_timestamp).strftime('%Y-%m-%d %H_%M_%S')
        start_time = summary["time"]["start_datetime"]
        if file_name:
            summary["html_report_name"] = report_name
            file_name += "-{}.html".format(start_time)
        else:
            summary["html_report_name"] = ""
            file_name = "{}.html".format(start_time)

        # 准备报告的Details部分数据 ------------------------------------------------------------------------------------
        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']
                report.stringify_data(meta_data, 'request')
                report.stringify_data(meta_data, 'response')

        # 模板渲染 -----------------------------------------------------------------------------------------------------
        with open(html_report_template, "r", encoding='utf-8') as fp_r:
            template_content = fp_r.read()
            # report_path = os.path.join(report_dir_path, file_name)  # 报告完整路径
            rendered_content = Template(template_content).render(summary)
            # with 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 rendered_content, result_stastic