diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 93eba206..8a95a93d 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,5 +1,18 @@ # Release History +## 3.0.12 (2020-06-14) + +**Fixed** + +- fix: compatibility with different path separators of Linux and Windows +- fix: IndexError in ensure_file_path_valid when file_path=os.getcwd() +- fix: ensure step referenced api, convert to v3 testcase +- fix: several other compatibility issues + +**Changed** + +- change: skip reporting sentry for errors occurred in debugtalk.py + ## 3.0.11 (2020-06-08) **Changed** diff --git a/httprunner/__init__.py b/httprunner/__init__.py index 61b95cf3..b082aed8 100644 --- a/httprunner/__init__.py +++ b/httprunner/__init__.py @@ -1,4 +1,4 @@ -__version__ = "3.0.11" +__version__ = "3.0.12" __description__ = "One-stop solution for HTTP(S) testing." from httprunner.runner import HttpRunner diff --git a/httprunner/compat.py b/httprunner/compat.py index 20c442f4..e899e3cc 100644 --- a/httprunner/compat.py +++ b/httprunner/compat.py @@ -47,6 +47,9 @@ def convert_variables( def convert_jmespath(raw: Text) -> Text: + if not isinstance(raw, Text): + raise exceptions.TestCaseFormatError(f"Invalid jmespath extractor: {raw}") + # content.xx/json.xx => body.xx if raw.startswith("content"): raw = f"body{raw[len('content'):]}" @@ -90,6 +93,9 @@ def convert_extractors(extractors: Union[List, Dict]) -> Dict: if isinstance(extractors, List): # [{"varA": "content.varA"}, {"varB": "json.varB"}] for extractor in extractors: + if not isinstance(extractor, Dict): + logger.error(f"Invalid extractor: {extractors}") + sys.exit(1) for k, v in extractor.items(): v3_extractors[k] = v elif isinstance(extractors, Dict): @@ -348,3 +354,15 @@ def session_fixture(request): f.write(conftest_content) logger.info("generated conftest.py to generate summary.json") + + +def ensure_path_sep(path: Text) -> Text: + """ ensure compatibility with different path separators of Linux and Windows + """ + if "/" in path: + path = os.sep.join(path.split("/")) + + if "\\" in path: + path = os.sep.join(path.split("\\")) + + return path diff --git a/httprunner/ext/har2case/__init__.py b/httprunner/ext/har2case/__init__.py index 3e5c21c4..c1a074b4 100644 --- a/httprunner/ext/har2case/__init__.py +++ b/httprunner/ext/har2case/__init__.py @@ -14,6 +14,7 @@ import sys from loguru import logger from sentry_sdk import capture_message +from httprunner.compat import ensure_path_sep from httprunner.ext.har2case.core import HarParser @@ -59,6 +60,7 @@ def main_har2case(args): logger.error("HAR file not specified.") sys.exit(1) + har_source_file = ensure_path_sep(har_source_file) if not os.path.isfile(har_source_file): logger.error(f"HAR file not exists: {har_source_file}") sys.exit(1) diff --git a/httprunner/loader.py b/httprunner/loader.py index 9592e5bf..cc6799c0 100644 --- a/httprunner/loader.py +++ b/httprunner/loader.py @@ -370,7 +370,12 @@ def load_debugtalk_functions() -> Dict[Text, Callable]: """ # load debugtalk.py module - imported_module = importlib.import_module("debugtalk") + try: + imported_module = importlib.import_module("debugtalk") + except Exception as ex: + logger.error(f"error occurred in debugtalk.py: {ex}") + sys.exit(1) + # reload to refresh previously loaded module imported_module = importlib.reload(imported_module) return load_module_functions(imported_module) diff --git a/httprunner/make.py b/httprunner/make.py index 2e842213..55ee1070 100644 --- a/httprunner/make.py +++ b/httprunner/make.py @@ -13,6 +13,7 @@ from httprunner.compat import ( ensure_testcase_v3_api, ensure_testcase_v3, convert_variables, + ensure_path_sep, ) from httprunner.loader import ( load_folder_files, @@ -63,6 +64,7 @@ if __name__ == "__main__": def __ensure_absolute(path: Text) -> Text: + path = ensure_path_sep(path) project_meta = load_project_meta(path) if os.path.isabs(path): @@ -148,6 +150,15 @@ def format_pytest_with_black(*python_paths: Text) -> NoReturn: except subprocess.CalledProcessError as ex: capture_exception(ex) logger.error(ex) + sys.exit(1) + except FileNotFoundError: + err_msg = """ +missing dependency tool: black +install black manually and try again: +$ pip install black +""" + logger.error(err_msg) + sys.exit(1) def make_config_chain_style(config: Dict) -> Text: @@ -324,6 +335,11 @@ def make_testcase(testcase: Dict, dir_path: Text = None) -> Text: # make ref testcase pytest file ref_testcase_path = __ensure_absolute(teststep["testcase"]) test_content = load_test_file(ref_testcase_path) + + # api in v2 format, convert to v3 testcase + if "request" in test_content and "name" in test_content: + test_content = ensure_testcase_v3_api(test_content) + test_content.setdefault("config", {})["path"] = ref_testcase_path ref_testcase_python_path = make_testcase(test_content) @@ -493,6 +509,7 @@ def main_make(tests_paths: List[Text]) -> List[Text]: return [] for tests_path in tests_paths: + tests_path = ensure_path_sep(tests_path) if not os.path.isabs(tests_path): tests_path = os.path.join(os.getcwd(), tests_path) diff --git a/httprunner/utils.py b/httprunner/utils.py index 7ba3b147..48da026a 100644 --- a/httprunner/utils.py +++ b/httprunner/utils.py @@ -199,6 +199,9 @@ def ensure_file_path_valid(file_path: Text) -> Text: else: raw_file_relative_name = raw_file_name + if raw_file_relative_name == "": + return file_path + path_names = [] for name in raw_file_relative_name.rstrip(os.sep).split(os.sep): diff --git a/pyproject.toml b/pyproject.toml index 9eb460f6..e21f7182 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "httprunner" -version = "3.0.11" +version = "3.0.12" description = "One-stop solution for HTTP(S) testing." license = "Apache-2.0" readme = "README.md" diff --git a/tests/compat_test.py b/tests/compat_test.py index 49e78500..b5d45250 100644 --- a/tests/compat_test.py +++ b/tests/compat_test.py @@ -2,7 +2,7 @@ import os import unittest from httprunner import compat, exceptions, loader -from httprunner.compat import convert_variables +from httprunner.compat import convert_variables, ensure_path_sep class TestCompat(unittest.TestCase): @@ -213,3 +213,19 @@ class TestCompat(unittest.TestCase): "--self-contained-html", ], ) + + def test_ensure_file_path(self): + self.assertEqual( + ensure_path_sep("demo\\test.yml"), os.sep.join(["demo", "test.yml"]) + ) + self.assertEqual( + ensure_path_sep(os.path.join(os.getcwd(), "demo\\test.yml")), + os.path.join(os.getcwd(), os.sep.join(["demo", "test.yml"])), + ) + self.assertEqual( + ensure_path_sep("demo/test.yml"), os.sep.join(["demo", "test.yml"]) + ) + self.assertEqual( + ensure_path_sep(os.path.join(os.getcwd(), "demo/test.yml")), + os.path.join(os.getcwd(), os.sep.join(["demo", "test.yml"])), + ) diff --git a/tests/ext/har2case/core_test.py b/tests/ext/har2case/core_test.py index 21e818ad..f696e5c0 100644 --- a/tests/ext/har2case/core_test.py +++ b/tests/ext/har2case/core_test.py @@ -2,7 +2,7 @@ import os from httprunner.ext.har2case.core import HarParser from httprunner.ext.har2case.utils import load_har_log_entries -from tests.ext.har2case.utils_test import TestHar2CaseUtils +from tests.ext.har2case.har_utils_test import TestHar2CaseUtils class TestHar(TestHar2CaseUtils): diff --git a/tests/ext/har2case/utils_test.py b/tests/ext/har2case/har_utils_test.py similarity index 100% rename from tests/ext/har2case/utils_test.py rename to tests/ext/har2case/har_utils_test.py diff --git a/tests/utils_test.py b/tests/utils_test.py index d301587b..df213a54 100644 --- a/tests/utils_test.py +++ b/tests/utils_test.py @@ -122,6 +122,16 @@ class TestUtils(unittest.TestCase): ensure_file_path_valid("examples/postman_echo/request_methods/"), os.path.join(os.getcwd(), "examples/postman_echo/request_methods"), ) + self.assertEqual( + ensure_file_path_valid(os.path.join(os.getcwd(), "test.yml")), + os.path.join(os.getcwd(), "test.yml"), + ) + self.assertEqual( + ensure_file_path_valid(os.getcwd()), os.getcwd(), + ) + self.assertEqual( + ensure_file_path_valid(os.getcwd() + ".csv"), os.getcwd() + ".csv", + ) def test_safe_dump_json(self): class A(object):