예제 #1
0
 def setUp(self) -> None:
     resp = requests.post(
         "https://httpbin.org/anything",
         json={
             "locations": [
                 {
                     "name": "Seattle",
                     "state": "WA"
                 },
                 {
                     "name": "New York",
                     "state": "NY"
                 },
                 {
                     "name": "Bellevue",
                     "state": "WA"
                 },
                 {
                     "name": "Olympia",
                     "state": "WA"
                 },
             ]
         },
     )
     parser = Parser(functions_mapping={
         "get_name": lambda: "name",
         "get_num": lambda x: x
     })
     self.resp_obj = ResponseObject(resp, parser)
예제 #2
0
 def setUp(self) -> None:
     resp = requests.post(
         "https://httpbin.org/anything",
         json={
             "locations": [
                 {
                     "name": "Seattle",
                     "state": "WA"
                 },
                 {
                     "name": "New York",
                     "state": "NY"
                 },
                 {
                     "name": "Bellevue",
                     "state": "WA"
                 },
                 {
                     "name": "Olympia",
                     "state": "WA"
                 },
             ]
         },
     )
     self.resp_obj = ResponseObject(resp)
예제 #3
0
def match_event_with_reports(
        response: ResponseObject,
        platform: PlatformEnum,
        event: Event,
        happen_after_seconds: int
) -> None:
    """
    Match event with report records in database, matched records will be appended to response.

    When an event happens, corresponding report will be sent.
    """
    # 1. filter
    filter_result: List[ReportLog] = crud.report_log.filter(db, event, platform, happen_after_seconds)

    filter_result_ids = [_.id for _ in filter_result]
    response.body["filter"] = filter_result_ids

    # 2. match
    matched_report_logs = match(filter_result, event)
    for report_log in matched_report_logs:
        update_data = {"matched": True}
        crud.report_log.update(db, db_obj=report_log, obj_in=update_data)

    matched_report_log_ids = [_.id for _ in matched_report_logs]
    response.body["match"] = matched_report_log_ids
예제 #4
0
    def __run_step_request(self, step: TStep):
        """run teststep: request"""
        step_data = StepData(name=step.name)

        # parse
        prepare_upload_step(step, self.__project_meta.functions)
        request_dict = step.request.dict()
        request_dict.pop("upload", None)
        parsed_request_dict = parse_data(request_dict, step.variables,
                                         self.__project_meta.functions)

        # prepare arguments
        method = parsed_request_dict.pop("method")
        url_path = parsed_request_dict.pop("url")
        url = build_url(self.config.base_url, url_path)

        parsed_request_dict["json"] = parsed_request_dict.pop("req_json", {})

        logger.info(f"{method} {url}")
        logger.debug(f"request kwargs(raw): {parsed_request_dict}")

        # request
        self.__session = self.__session or HttpSession()
        resp = self.__session.request(method, url, **parsed_request_dict)
        resp_obj = ResponseObject(resp)

        def log_req_resp_details():
            err_msg = "\n{} DETAILED REQUEST & RESPONSE {}\n".format(
                "*" * 32, "*" * 32)

            # log request
            err_msg += "====== request details ======\n"
            err_msg += f"url: {url}\n"
            err_msg += f"method: {method}\n"
            headers = parsed_request_dict.pop("headers", {})
            err_msg += f"headers: {headers}\n"
            for k, v in parsed_request_dict.items():
                v = utils.omit_long_data(v)
                err_msg += f"{k}: {repr(v)}\n"

            err_msg += "\n"

            # log response
            err_msg += "====== response details ======\n"
            err_msg += f"status_code: {resp.status_code}\n"
            err_msg += f"headers: {resp.headers}\n"
            err_msg += f"body: {repr(resp.text)}\n"
            logger.error(err_msg)

        # extract
        extractors = step.extract
        extract_mapping = resp_obj.extract(extractors)
        step_data.export = extract_mapping

        variables_mapping = step.variables
        variables_mapping.update(extract_mapping)

        # validate
        validators = step.validators
        try:
            resp_obj.validate(validators, variables_mapping,
                              self.__project_meta.functions)
            self.__session.data.success = True
        except ValidationFailure:
            self.__session.data.success = False
            log_req_resp_details()
            raise
        finally:
            # save request & response meta data
            self.__session.data.validators = resp_obj.validation_results
            self.success &= self.__session.data.success
            # save step data
            step_data.success = self.__session.data.success
            step_data.data = self.__session.data

        return step_data
예제 #5
0
    def __run_step_request(self, step: TStep) -> StepData:
        """run teststep: request"""
        step_data = StepData(name=step.name)

        # parse
        prepare_upload_step(step, self.__project_meta.functions)
        request_dict = step.request.dict()
        request_dict.pop("upload", None)
        parsed_request_dict = parse_data(request_dict, step.variables,
                                         self.__project_meta.functions)
        parsed_request_dict["headers"].setdefault(
            "HRUN-Request-ID",
            f"HRUN-{self.__case_id}-{str(int(time.time() * 1000))[-6:]}",
        )
        step.variables["request"] = parsed_request_dict

        # setup hooks
        if step.setup_hooks:
            self.__call_hooks(step.setup_hooks, step.variables, "setup")

        # prepare arguments
        method = parsed_request_dict.pop("method")
        url_path = parsed_request_dict.pop("url")
        url = build_url(self.__config.base_url, url_path)
        parsed_request_dict["verify"] = self.__config.verify
        parsed_request_dict["json"] = parsed_request_dict.pop("req_json", {})

        # request
        resp = self.__session.request(method, url, **parsed_request_dict)
        resp_obj = ResponseObject(resp)
        step.variables["response"] = resp_obj

        # teardown hooks
        if step.teardown_hooks:
            self.__call_hooks(step.teardown_hooks, step.variables, "teardown")

        def log_req_resp_details():
            err_msg = "\n{} DETAILED REQUEST & RESPONSE {}\n".format(
                "*" * 32, "*" * 32)

            # log request
            err_msg += "====== request details ======\n"
            err_msg += f"url: {url}\n"
            err_msg += f"method: {method}\n"
            headers = parsed_request_dict.pop("headers", {})
            err_msg += f"headers: {headers}\n"
            for k, v in parsed_request_dict.items():
                v = utils.omit_long_data(v)
                err_msg += f"{k}: {repr(v)}\n"

            err_msg += "\n"

            # log response
            err_msg += "====== response details ======\n"
            err_msg += f"status_code: {resp.status_code}\n"
            err_msg += f"headers: {resp.headers}\n"
            err_msg += f"body: {repr(resp.text)}\n"
            logger.error(err_msg)

        # extract
        extractors = step.extract
        extract_mapping = resp_obj.extract(extractors)
        step_data.export_vars = extract_mapping

        variables_mapping = step.variables
        variables_mapping.update(extract_mapping)

        # validate
        validators = step.validators
        try:
            resp_obj.validate(validators, variables_mapping,
                              self.__project_meta.functions)
            self.__session.data.success = True
        except ValidationFailure:
            self.__session.data.success = False
            log_req_resp_details()
            # log testcase duration before raise ValidationFailure
            self.__duration = time.time() - self.__start_at
            raise
        finally:
            # save request & response meta data
            self.__session.data.validators = resp_obj.validation_results
            self.success = self.__session.data.success
            # save step data
            step_data.success = self.__session.data.success
            step_data.data = self.__session.data

        return step_data
예제 #6
0
class TestResponse(unittest.TestCase):
    def setUp(self) -> None:
        resp = requests.post(
            "https://httpbin.org/anything",
            json={
                "locations": [
                    {
                        "name": "Seattle",
                        "state": "WA"
                    },
                    {
                        "name": "New York",
                        "state": "NY"
                    },
                    {
                        "name": "Bellevue",
                        "state": "WA"
                    },
                    {
                        "name": "Olympia",
                        "state": "WA"
                    },
                ]
            },
        )
        self.resp_obj = ResponseObject(resp)

    def test_extract(self):
        extract_mapping = self.resp_obj.extract({
            "var_1":
            "body.json.locations[0]",
            "var_2":
            "body.json.locations[3].name"
        })
        self.assertEqual(extract_mapping["var_1"], {
            "name": "Seattle",
            "state": "WA"
        })
        self.assertEqual(extract_mapping["var_2"], "Olympia")

    def test_validate(self):
        variables_mapping = {"index": 1}
        self.resp_obj.validate(
            [
                {
                    "eq": ["body.json.locations[0].name", "Seattle"]
                },
                {
                    "eq": [
                        "body.json.locations[0]", {
                            "name": "Seattle",
                            "state": "WA"
                        }
                    ]
                },
                {
                    "eq": ["body.json.locations[$index].name", "New York"]
                },
            ],
            variables_mapping=variables_mapping,
        )
예제 #7
0
class TestResponse(unittest.TestCase):
    def setUp(self) -> None:
        resp = requests.post(
            "https://httpbin.org/anything",
            json={
                "locations": [
                    {
                        "name": "Seattle",
                        "state": "WA"
                    },
                    {
                        "name": "New York",
                        "state": "NY"
                    },
                    {
                        "name": "Bellevue",
                        "state": "WA"
                    },
                    {
                        "name": "Olympia",
                        "state": "WA"
                    },
                ]
            },
        )
        parser = Parser(functions_mapping={
            "get_name": lambda: "name",
            "get_num": lambda x: x
        })
        self.resp_obj = ResponseObject(resp, parser)

    def test_extract(self):
        variables_mapping = {"body": "body"}
        extract_mapping = self.resp_obj.extract(
            {
                "var_1": "body.json.locations[0]",
                "var_2": "body.json.locations[3].name",
                "var_3": "$body.json.locations[3].name",
                "var_4": "$body.json.locations[3].${get_name()}",
            },
            variables_mapping=variables_mapping,
        )
        self.assertEqual(extract_mapping["var_1"], {
            "name": "Seattle",
            "state": "WA"
        })
        self.assertEqual(extract_mapping["var_2"], "Olympia")
        self.assertEqual(extract_mapping["var_3"], "Olympia")
        self.assertEqual(extract_mapping["var_4"], "Olympia")

    def test_validate(self):
        self.resp_obj.validate([
            {
                "eq": ["body.json.locations[0].name", "Seattle"]
            },
            {
                "eq":
                ["body.json.locations[0]", {
                    "name": "Seattle",
                    "state": "WA"
                }]
            },
        ], )

    def test_validate_variables(self):
        variables_mapping = {"index": 1, "var_empty": ""}
        self.resp_obj.validate(
            [
                {
                    "eq": ["body.json.locations[$index].name", "New York"]
                },
                {
                    "eq": ["$var_empty", ""]
                },
            ],
            variables_mapping=variables_mapping,
        )

    def test_validate_functions(self):
        variables_mapping = {"index": 1}
        self.resp_obj.validate(
            [
                {
                    "eq": ["${get_num(0)}", 0]
                },
                {
                    "eq": ["${get_num($index)}", 1]
                },
            ],
            variables_mapping=variables_mapping,
        )
예제 #8
0
    def run_testcase(self, testcase: TestCase) -> "HttpRunner":
        """run specified testcase

        Examples:
            >>> testcase_obj = TestCase(config=TConfig(...), teststeps=[TStep(...)])
            >>> HttpRunner().with_project_meta(project_meta).run_testcase(testcase_obj)

        """
        self.__config = testcase.config
        self.__teststeps = testcase.teststeps

        # prepare
        self.__project_meta = self.__project_meta or load_project_meta(
            self.__config.path)
        self.__parse_config(self.__config)
        self.__start_at = time.time()
        self.__step_datas: List[StepData] = []
        self.__session = self.__session or HttpSession()
        # save extracted variables of teststeps
        extracted_variables: VariablesMapping = {}

        # run teststeps
        for step in self.__teststeps:
            # override variables
            # step variables > extracted variables from previous steps
            step.variables = merge_variables(step.variables,
                                             extracted_variables)
            # step variables > testcase config variables
            step.variables = merge_variables(step.variables,
                                             self.__config.variables)

            # parse variables
            step.variables = parse_variables_mapping(
                step.variables, self.__project_meta.functions)

            while True:
                # run step
                if USE_ALLURE:
                    with allure.step(f"step: {step.name}"):
                        extract_mapping = self.__run_step(step)
                else:
                    extract_mapping = self.__run_step(step)

                if step.retry_whens:
                    variables_mapping = step.variables
                    variables_mapping.update(extract_mapping)

                    try:
                        response = step.variables.get(
                            'response') or ResponseObject(requests.Response())
                        if isinstance(response, ResponseObject):
                            response.validate(step.retry_whens,
                                              variables_mapping,
                                              self.__project_meta.functions)
                        else:
                            break
                    except ValidationFailure:
                        break
                else:
                    break

            # save extracted variables to session variables
            extracted_variables.update(extract_mapping)

        self.__session_variables.update(extracted_variables)
        self.__duration = time.time() - self.__start_at
        return self
예제 #9
0
def run_step_request(runner: HttpRunner, step: TStep) -> StepResult:
    """run teststep: request"""
    step_result = StepResult(
        name=step.name,
        success=False,
    )
    start_time = time.time()

    step.variables = runner.merge_step_variables(step.variables)

    # parse
    functions = runner.parser.functions_mapping
    prepare_upload_step(step, functions)
    request_dict = step.request.dict()
    request_dict.pop("upload", None)
    parsed_request_dict = runner.parser.parse_data(request_dict,
                                                   step.variables)
    parsed_request_dict["headers"].setdefault(
        "HRUN-Request-ID",
        f"HRUN-{runner.case_id}-{str(int(time.time() * 1000))[-6:]}",
    )
    step.variables["request"] = parsed_request_dict

    # setup hooks
    if step.setup_hooks:
        call_hooks(runner, step.setup_hooks, step.variables, "setup request")

    # prepare arguments
    config = runner.get_config()
    method = parsed_request_dict.pop("method")
    url_path = parsed_request_dict.pop("url")
    url = build_url(config.base_url, url_path)
    parsed_request_dict["verify"] = config.verify
    parsed_request_dict["json"] = parsed_request_dict.pop("req_json", {})

    # request
    resp = runner.session.request(method, url, **parsed_request_dict)
    resp_obj = ResponseObject(resp, runner.parser)
    step.variables["response"] = resp_obj

    # teardown hooks
    if step.teardown_hooks:
        call_hooks(runner, step.teardown_hooks, step.variables,
                   "teardown request")

    def log_req_resp_details():
        err_msg = "\n{} DETAILED REQUEST & RESPONSE {}\n".format(
            "*" * 32, "*" * 32)

        # log request
        err_msg += "====== request details ======\n"
        err_msg += f"url: {url}\n"
        err_msg += f"method: {method}\n"
        headers = parsed_request_dict.pop("headers", {})
        err_msg += f"headers: {headers}\n"
        for k, v in parsed_request_dict.items():
            v = utils.omit_long_data(v)
            err_msg += f"{k}: {repr(v)}\n"

        err_msg += "\n"

        # log response
        err_msg += "====== response details ======\n"
        err_msg += f"status_code: {resp.status_code}\n"
        err_msg += f"headers: {resp.headers}\n"
        err_msg += f"body: {repr(resp.text)}\n"
        logger.error(err_msg)

    # extract
    extractors = step.extract
    extract_mapping = resp_obj.extract(extractors, step.variables)
    step_result.export_vars = extract_mapping

    variables_mapping = step.variables
    variables_mapping.update(extract_mapping)

    # validate
    validators = step.validators
    try:
        resp_obj.validate(validators, variables_mapping)
        step_result.success = True
    except ValidationFailure:
        log_req_resp_details()
        raise
    finally:
        session_data = runner.session.data
        session_data.success = step_result.success
        session_data.validators = resp_obj.validation_results

        # save step data
        step_result.data = session_data
        step_result.elapsed = time.time() - start_time

    return step_result