From d05c2350296d579a4ef737080412fe889450b6d8 Mon Sep 17 00:00:00 2001 From: debugtalk Date: Fri, 15 May 2020 22:23:16 +0800 Subject: [PATCH] refactor: remove unused code --- httprunner/report/__init__.py | 20 -- httprunner/report/html/__init__.py | 12 - httprunner/report/html/gen_report.py | 64 ----- httprunner/report/html/result.py | 65 ----- httprunner/report/html/template.html | 350 --------------------------- httprunner/report/report.py | 45 ---- httprunner/report/stringify.py | 170 ------------- httprunner/report/summarize.py | 76 ------ httprunner/runner.py | 2 +- httprunner/utils.py | 154 +----------- httprunner/utils_test.py | 69 ------ 11 files changed, 11 insertions(+), 1016 deletions(-) delete mode 100644 httprunner/report/__init__.py delete mode 100644 httprunner/report/html/__init__.py delete mode 100644 httprunner/report/html/gen_report.py delete mode 100644 httprunner/report/html/result.py delete mode 100644 httprunner/report/html/template.html delete mode 100644 httprunner/report/report.py delete mode 100644 httprunner/report/stringify.py delete mode 100644 httprunner/report/summarize.py diff --git a/httprunner/report/__init__.py b/httprunner/report/__init__.py deleted file mode 100644 index 9599cc3d..00000000 --- a/httprunner/report/__init__.py +++ /dev/null @@ -1,20 +0,0 @@ -""" -HttpRunner report - -- summarize: aggregate test stat data to summary -- stringify: stringify summary, in order to dump json file and generate html report. -- html: render html report -""" - -from httprunner.report.summarize import get_platform, aggregate_stat, get_summary -from httprunner.report.stringify import stringify_summary -from httprunner.report.html import HtmlTestResult, gen_html_report - -__all__ = [ - "get_platform", - "aggregate_stat", - "get_summary", - "stringify_summary", - "HtmlTestResult", - "gen_html_report", -] diff --git a/httprunner/report/html/__init__.py b/httprunner/report/html/__init__.py deleted file mode 100644 index 398adeea..00000000 --- a/httprunner/report/html/__init__.py +++ /dev/null @@ -1,12 +0,0 @@ -""" -HttpRunner html report - -- result: define resultclass for unittest TextTestRunner -- gen_report: render html report with jinja2 template - -""" - -from httprunner.report.html.result import HtmlTestResult -from httprunner.report.html.gen_report import gen_html_report - -__all__ = ["HtmlTestResult", "gen_html_report"] diff --git a/httprunner/report/html/gen_report.py b/httprunner/report/html/gen_report.py deleted file mode 100644 index 8d7364d9..00000000 --- a/httprunner/report/html/gen_report.py +++ /dev/null @@ -1,64 +0,0 @@ -import io -import os - -from jinja2 import Template -from loguru import logger - -from httprunner.exceptions import SummaryEmpty -from httprunner.schema import TestSuiteSummary - - -def gen_html_report( - testsuite_summary: TestSuiteSummary, - report_template=None, - report_dir=None, - report_file=None, -): - """ render html report with specified report name and template - - Args: - testsuite_summary (dict): testsuite 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 testsuite_summary.stat.total == 0: - logger.error(f"test result testsuite_summary is empty ! {testsuite_summary}") - raise SummaryEmpty - - if not report_template: - report_template = os.path.join( - os.path.abspath(os.path.dirname(__file__)), "template.html" - ) - logger.debug("No html report template specified, use default.") - else: - logger.info(f"render with html report template: {report_template}") - - logger.info("Start to render Html report ...") - - 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( - testsuite_summary.time.start_at_iso_format.replace(":", "").replace("-", "") - ) - - if not os.path.isdir(report_dir): - os.makedirs(report_dir) - - report_path = os.path.join(report_dir, report_file_name) - with io.open(report_template, "r", encoding="utf-8") as fp_r: - template_content = fp_r.read() - with io.open(report_path, "w", encoding="utf-8") as fp_w: - rendered_content = Template( - template_content, extensions=["jinja2.ext.loopcontrols"] - ).render(testsuite_summary.dict()) - fp_w.write(rendered_content) - - logger.info(f"Generated Html report: {report_path}") - - return report_path diff --git a/httprunner/report/html/result.py b/httprunner/report/html/result.py deleted file mode 100644 index 7d60f1e4..00000000 --- a/httprunner/report/html/result.py +++ /dev/null @@ -1,65 +0,0 @@ -import time -import unittest - -from loguru import logger - - -class HtmlTestResult(unittest.TextTestResult): - """ A html result class that can generate formatted html results, used by TextTestRunner. - Each testcase is corresponding to one HtmlTestResult instance - """ - - def __init__(self, stream, descriptions, verbosity): - super(HtmlTestResult, self).__init__(stream, descriptions, verbosity) - self.name = "" - self.status = "" - self.attachment = "" - self.step_datas = None - - def _record_test(self, test, status, attachment=""): - self.name = test.shortDescription() - self.status = status - self.attachment = attachment - self.step_datas = test.step_datas - - def startTestRun(self): - self.start_at = time.time() - - def startTest(self, test): - """ add start test time """ - super(HtmlTestResult, self).startTest(test) - logger.info(test.shortDescription()) - - def addSuccess(self, test): - super(HtmlTestResult, self).addSuccess(test) - self._record_test(test, "success") - print("") - - def addError(self, test, err): - super(HtmlTestResult, self).addError(test, err) - self._record_test(test, "error", self._exc_info_to_string(err, test)) - print("") - - def addFailure(self, test, err): - super(HtmlTestResult, self).addFailure(test, err) - self._record_test(test, "failure", self._exc_info_to_string(err, test)) - print("") - - def addSkip(self, test, reason): - super(HtmlTestResult, self).addSkip(test, reason) - self._record_test(test, "skipped", reason) - print("") - - def addExpectedFailure(self, test, err): - super(HtmlTestResult, self).addExpectedFailure(test, err) - self._record_test(test, "ExpectedFailure", self._exc_info_to_string(err, test)) - print("") - - def addUnexpectedSuccess(self, test): - super(HtmlTestResult, self).addUnexpectedSuccess(test) - self._record_test(test, "UnexpectedSuccess") - print("") - - @property - def duration(self): - return time.time() - self.start_at diff --git a/httprunner/report/html/template.html b/httprunner/report/html/template.html deleted file mode 100644 index 76baaa8b..00000000 --- a/httprunner/report/html/template.html +++ /dev/null @@ -1,350 +0,0 @@ - - - - {{html_report_name}} - TestReport - - - - -

Test Report: {{html_report_name}}

- -

Summary

- - - - - - - - - - - - - - - - - - - - - - - - - -
START AT{{time.start_at_iso_format}}
DURATION{{ '%0.3f'| format(time.duration|float) }} seconds
PLATFORMHttpRunner {{ platform.httprunner_version }} {{ platform.python_version }} {{ platform.platform }}
STATSUCCESSFAIL
total (details) =>{{stat.success}}{{stat.fail}}
- -

Details

- - {% for testcase_summary in testcases %} - {% set testcase_index = loop.index %} -

{{testcase_summary.name}}

- - - - - - - - - {% set testcase = testcase_summary %} - {% set step_datas = testcase_summary.step_datas %} - {% for session_data in step_datas %} - {% set step_index = "{}_{}".format(testcase_index, loop.index) %} - - - - - - - {% endfor %} -
StatusNameResponse TimeDetail
{{session_data.status}}{{session_data.name}}{{ session_data.stat.response_time_ms }} ms - log-{{loop.index}} - - - {% if session_data.status == "failed" %} - traceback - - {% endif %} - -
- {% endfor %} - \ No newline at end of file diff --git a/httprunner/report/report.py b/httprunner/report/report.py deleted file mode 100644 index b69f4be8..00000000 --- a/httprunner/report/report.py +++ /dev/null @@ -1,45 +0,0 @@ -import json -import platform -import time -import uuid - -import requests - -from httprunner import __version__ - - -def prepare_event_kwargs(event_name, params): - """ prepare report event kwargs""" - - kwargs = { - "headers": {"content-type": "application/json"}, - "json": { - "user": {"user_unique_id": str(uuid.getnode())}, - "header": { - "app_id": 173519, - "os_name": platform.system(), - "os_version": platform.release(), - "app_version": __version__, # HttpRunner version - }, - "events": [ - { - "event": event_name, - "params": json.dumps(params), - "time": int(time.time()), - } - ], - "verbose": 1, - }, - } - return kwargs - - -def report_event(event_name, success=True): - params = {"success": 1 if success else 0} - kwargs = prepare_event_kwargs(event_name, params) - resp = requests.post("http://mcs.snssdk.com/v1/json", **kwargs) - print("resp---", resp.json()) - - -if __name__ == "__main__": - report_event("loader") diff --git a/httprunner/report/stringify.py b/httprunner/report/stringify.py deleted file mode 100644 index 89e32801..00000000 --- a/httprunner/report/stringify.py +++ /dev/null @@ -1,170 +0,0 @@ -import json -from base64 import b64encode -from collections import Iterable -from typing import List - -from jinja2 import escape -from requests.cookies import RequestsCookieJar - -from httprunner.schema import TestSuiteSummary, SessionData - - -def dumps_json(value): - """ dumps json value to indented string - - Args: - value (dict): raw json data - - Returns: - str: indented json dump string - - """ - return json.dumps(value, indent=2, ensure_ascii=False) - - -def detect_encoding(value): - try: - return json.detect_encoding(value) - except AttributeError: - return "utf-8" - - -def __stringify_request(request_data): - """ stringfy HTTP request data - - Args: - request_data (dict): HTTP request data in dict. - - { - "url": "http://127.0.0.1:5000/api/get-token", - "method": "POST", - "headers": { - "User-Agent": "python-requests/2.20.0", - "Accept-Encoding": "gzip, deflate", - "Accept": "*/*", - "Connection": "keep-alive", - "user_agent": "iOS/10.3", - "device_sn": "TESTCASE_CREATE_XXX", - "os_platform": "ios", - "app_version": "2.8.6", - "Content-Type": "application/json", - "Content-Length": "52" - }, - "body": b'{"sign": "cb9d60acd09080ea66c8e63a1c78c6459ea00168"}', - "verify": false - } - - """ - for key, value in request_data.items(): - - if isinstance(value, (list, dict)): - value = dumps_json(value) - - elif isinstance(value, bytes): - try: - encoding = detect_encoding(value) - value = value.decode(encoding) - if key == "body": - try: - # request body is in json format - value = json.loads(value) - value = dumps_json(value) - except json.JSONDecodeError: - pass - value = escape(value) - except UnicodeDecodeError: - pass - - elif not isinstance(value, (str, bytes, int, float, Iterable)): - # class instance, e.g. MultipartEncoder() - value = repr(value) - - elif isinstance(value, RequestsCookieJar): - value = value.get_dict() - - request_data[key] = value - - -def __stringify_response(response_data): - """ stringfy HTTP response data - - Args: - response_data (dict): - - { - "status_code": 404, - "headers": { - "Content-Type": "application/json", - "Content-Length": "30", - "Server": "Werkzeug/0.14.1 Python/3.7.0", - "Date": "Tue, 27 Nov 2018 06:19:27 GMT" - }, - "encoding": "None", - "content_type": "application/json", - "ok": false, - "url": "http://127.0.0.1:5000/api/users/9001", - "reason": "NOT FOUND", - "cookies": {}, - "body": { - "success": false, - "data": {} - } - } - - """ - for key, value in response_data.items(): - - if isinstance(value, (list, dict)): - value = dumps_json(value) - - elif isinstance(value, bytes): - try: - encoding = response_data.get("encoding") - if not encoding or encoding == "None": - encoding = detect_encoding(value) - - if key == "body" and "image" in response_data["content_type"]: - # display image - value = "data:{};base64,{}".format( - response_data["content_type"], b64encode(value).decode(encoding) - ) - else: - value = escape(value.decode(encoding)) - except UnicodeDecodeError: - pass - - elif not isinstance(value, (str, bytes, int, float, Iterable)): - # class instance, e.g. MultipartEncoder() - value = repr(value) - - elif isinstance(value, RequestsCookieJar): - value = value.get_dict() - - response_data[key] = value - - -def stringify_summary(testsuite_summary: TestSuiteSummary): - """ stringify summary, in order to dump json file and generate html report. - """ - for index, testcase_summary in enumerate(testsuite_summary.testcases): - - if not testcase_summary.name: - testcase_summary.name = f"testcase {index}" - - step_datas = testcase_summary.step_datas - for step_data in step_datas: - if isinstance(step_data.data, list): - # List[SessionData] - session_data_list: List[SessionData] = step_data.data - for session_data in session_data_list: - req_resp_list = session_data.req_resps - for req_resp in req_resp_list: - __stringify_request(req_resp.request) - __stringify_response(req_resp.response) - else: - # SessionData - session_data: SessionData = step_data.data - req_resp_list = session_data.req_resps - for req_resp in req_resp_list: - __stringify_request(req_resp.request) - __stringify_response(req_resp.response) diff --git a/httprunner/report/summarize.py b/httprunner/report/summarize.py deleted file mode 100644 index 4819b7ea..00000000 --- a/httprunner/report/summarize.py +++ /dev/null @@ -1,76 +0,0 @@ -import platform -from datetime import datetime - -from httprunner import __version__ -from httprunner.report.html.result import HtmlTestResult -from httprunner.schema import TestCaseSummary, TestCaseTime, TestCaseInOut - - -def get_platform(): - return { - "httprunner_version": __version__, - "python_version": "{} {}".format( - platform.python_implementation(), platform.python_version() - ), - "platform": platform.platform(), - } - - -def aggregate_stat(origin_stat, new_stat): - """ aggregate new_stat to origin_stat. - - Args: - origin_stat (dict): origin stat dict, will be updated with new_stat dict. - new_stat (dict): new stat dict. - - """ - for key in new_stat: - if key not in origin_stat: - origin_stat[key] = new_stat[key] - elif key == "start_at": - # start datetime - origin_stat["start_at"] = min(origin_stat["start_at"], new_stat["start_at"]) - elif key == "duration": - # duration = max_end_time - min_start_time - max_end_time = max( - origin_stat["start_at"] + origin_stat["duration"], - new_stat["start_at"] + new_stat["duration"], - ) - min_start_time = min(origin_stat["start_at"], new_stat["start_at"]) - origin_stat["duration"] = max_end_time - min_start_time - else: - origin_stat[key] += new_stat[key] - - -def get_summary(result: HtmlTestResult) -> TestCaseSummary: - """ get summary from test result - - Args: - result (instance): HtmlTestResult() instance - - Returns: - dict: summary extracted from result. - - { - "success": True, - "stat": {}, - "time": {}, - "record": {} - } - - """ - start_at_timestamp = result.start_at - start_at_iso_format = datetime.utcfromtimestamp(start_at_timestamp).isoformat() - return TestCaseSummary( - success=result.wasSuccessful(), - time=TestCaseTime( - start_at=result.start_at, - start_at_iso_format=start_at_iso_format, - duration=result.duration, - ), - name=result.name, - status=result.status, - attachment=result.attachment, - in_out=TestCaseInOut(), - step_datas=result.step_datas, - ) diff --git a/httprunner/runner.py b/httprunner/runner.py index bcb8d9c4..3c540836 100644 --- a/httprunner/runner.py +++ b/httprunner/runner.py @@ -174,7 +174,7 @@ class HttpRunner(object): self.start_at = time.time() self.step_datas: List[StepData] = [] - self.session_variables.clear() + self.session_variables = {} for step in self.teststeps: # update with config variables step.variables.update(self.config.variables) diff --git a/httprunner/utils.py b/httprunner/utils.py index a7623385..a3c97651 100644 --- a/httprunner/utils.py +++ b/httprunner/utils.py @@ -1,15 +1,11 @@ -# encoding: utf-8 - import collections -import copy -import io -import itertools import json import os.path -from typing import Union +import platform from loguru import logger +from httprunner import __version__ from httprunner import exceptions @@ -83,42 +79,6 @@ def lower_dict_keys(origin_dict): return {key.lower(): value for key, value in origin_dict.items()} -def deepcopy_dict(data): - """ deepcopy dict data, ignore file object (_io.BufferedReader) - - Args: - data (dict): dict data structure - { - 'a': 1, - 'b': [2, 4], - 'c': lambda x: x+1, - 'd': open('LICENSE'), - 'f': { - 'f1': {'a1': 2}, - 'f2': io.open('LICENSE', 'rb'), - } - } - - Returns: - dict: deep copied dict data, with file object unchanged. - - """ - try: - return copy.deepcopy(data) - except TypeError: - copied_data = {} - for key, value in data.items(): - if isinstance(value, dict): - copied_data[key] = deepcopy_dict(value) - else: - try: - copied_data[key] = copy.deepcopy(value) - except TypeError: - copied_data[key] = value - - return copied_data - - def print_info(info_mapping): """ print info in mapping. @@ -164,47 +124,6 @@ def print_info(info_mapping): logger.info(content) -def gen_cartesian_product(*args): - """ generate cartesian product for lists - - Args: - args (list of list): lists to be generated with cartesian product - - Returns: - list: cartesian product in list - - Examples: - - >>> arg1 = [{"a": 1}, {"a": 2}] - >>> arg2 = [{"x": 111, "y": 112}, {"x": 121, "y": 122}] - >>> args = [arg1, arg2] - >>> gen_cartesian_product(*args) - >>> # same as below - >>> gen_cartesian_product(arg1, arg2) - [ - {'a': 1, 'x': 111, 'y': 112}, - {'a': 1, 'x': 121, 'y': 122}, - {'a': 2, 'x': 111, 'y': 112}, - {'a': 2, 'x': 121, 'y': 122} - ] - - """ - if not args: - return [] - elif len(args) == 1: - return args[0] - - product_list = [] - for product_item_tuple in itertools.product(*args): - product_item_dict = {} - for item in product_item_tuple: - product_item_dict.update(item) - - product_list.append(product_item_dict) - - return product_list - - def omit_long_data(body, omit_len=512): """ omit too long str/bytes """ @@ -224,64 +143,11 @@ def omit_long_data(body, omit_len=512): return omitted_body + appendix_str -def dump_json_file(json_data: Union[dict, list], json_file_abs_path: str) -> None: - """ dump json data to file - """ - - class PythonObjectEncoder(json.JSONEncoder): - def default(self, obj): - try: - return super().default(self, obj) - except TypeError: - return str(obj) - - file_foder_path = os.path.dirname(json_file_abs_path) - if not os.path.isdir(file_foder_path): - os.makedirs(file_foder_path) - - try: - with io.open(json_file_abs_path, "w", encoding="utf-8") as outfile: - json.dump( - json_data, - outfile, - indent=4, - separators=(",", ":"), - ensure_ascii=False, - cls=PythonObjectEncoder, - ) - - msg = f"dump file: {json_file_abs_path}" - logger.info(msg) - - except TypeError as ex: - msg = f"Failed to dump json file: {json_file_abs_path}\nReason: {ex}" - logger.error(msg) - - -def prepare_log_file_abs_path(test_path: str, file_name: str) -> str: - """ prepare dump json file absolute path. - """ - current_working_dir = os.getcwd() - - if not test_path: - # running passed in testcase/testsuite data structure - dump_file_name = f"tests_mapping.{file_name}" - dumped_json_file_abs_path = os.path.join( - current_working_dir, "logs", dump_file_name - ) - return dumped_json_file_abs_path - - # both test_path and pwd_dir_path are absolute path - logs_dir_path = os.path.join(current_working_dir, "logs") - - if os.path.isdir(test_path): - file_foder_path = os.path.join(logs_dir_path, test_path) - dump_file_name = f"all.{file_name}" - else: - file_relative_folder_path, test_file = os.path.split(test_path) - file_foder_path = os.path.join(logs_dir_path, file_relative_folder_path) - test_file_name, _file_suffix = os.path.splitext(test_file) - dump_file_name = f"{test_file_name}.{file_name}" - - dumped_json_file_abs_path = os.path.join(file_foder_path, dump_file_name) - return dumped_json_file_abs_path +def get_platform(): + return { + "httprunner_version": __version__, + "python_version": "{} {}".format( + platform.python_implementation(), platform.python_version() + ), + "platform": platform.platform(), + } diff --git a/httprunner/utils_test.py b/httprunner/utils_test.py index f5d33be0..252b33f0 100644 --- a/httprunner/utils_test.py +++ b/httprunner/utils_test.py @@ -86,75 +86,6 @@ class TestUtils(unittest.TestCase): new_request_dict = utils.lower_dict_keys(request_dict) self.assertEqual(None, request_dict) - def test_deepcopy_dict(self): - license_path = os.path.join( - os.path.dirname(os.path.dirname(__file__)), "LICENSE" - ) - data = { - "a": 1, - "b": [2, 4], - "c": lambda x: x + 1, - "d": open(license_path), - "f": {"f1": {"a1": 2}, "f2": io.open(license_path, "rb"),}, - } - new_data = utils.deepcopy_dict(data) - data["a"] = 0 - self.assertEqual(new_data["a"], 1) - data["f"]["f1"] = 123 - self.assertEqual(new_data["f"]["f1"], {"a1": 2}) - self.assertNotEqual(id(new_data["b"]), id(data["b"])) - self.assertEqual(id(new_data["c"]), id(data["c"])) - # self.assertEqual(id(new_data["d"]), id(data["d"])) - - def test_cartesian_product_one(self): - parameters_content_list = [[{"a": 1}, {"a": 2}]] - product_list = utils.gen_cartesian_product(*parameters_content_list) - self.assertEqual(product_list, [{"a": 1}, {"a": 2}]) - - def test_cartesian_product_multiple(self): - parameters_content_list = [ - [{"a": 1}, {"a": 2}], - [{"x": 111, "y": 112}, {"x": 121, "y": 122}], - ] - product_list = utils.gen_cartesian_product(*parameters_content_list) - self.assertEqual( - product_list, - [ - {"a": 1, "x": 111, "y": 112}, - {"a": 1, "x": 121, "y": 122}, - {"a": 2, "x": 111, "y": 112}, - {"a": 2, "x": 121, "y": 122}, - ], - ) - - def test_cartesian_product_empty(self): - parameters_content_list = [] - product_list = utils.gen_cartesian_product(*parameters_content_list) - self.assertEqual(product_list, []) - def test_print_info(self): info_mapping = {"a": 1, "t": (1, 2), "b": {"b1": 123}, "c": None, "d": [4, 5]} utils.print_info(info_mapping) - - def test_prepare_dump_json_file_path_for_folder(self): - # hrun tests/httpbin/a.b.c/ --save-tests - test_path = os.path.join("tests", "httpbin", "a.b.c") - self.assertEqual( - utils.prepare_log_file_abs_path(test_path, "loaded.json"), - os.path.join(os.getcwd(), "logs", "tests/httpbin/a.b.c/all.loaded.json"), - ) - - def test_prepare_dump_json_file_path_for_file(self): - # hrun tests/httpbin/a.b.c/rpc.yml --save-tests - test_path = os.path.join("tests", "httpbin", "a.b.c", "rpc.yml") - self.assertEqual( - utils.prepare_log_file_abs_path(test_path, "loaded.json"), - os.path.join(os.getcwd(), "logs", "tests/httpbin/a.b.c/rpc.loaded.json"), - ) - - def test_prepare_dump_json_file_path_for_passed_testcase(self): - test_path = "" - self.assertEqual( - utils.prepare_log_file_abs_path(test_path, "loaded.json"), - os.path.join(os.getcwd(), "logs", "tests_mapping.loaded.json"), - )