diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 9fcb2272..e387cb76 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -1,5 +1,11 @@ # Release History +## 2.3.3 (2019-12-04) + +**Fixed** + +- fix #768: dump json file path error when folder name contains dot, such as `a.b.c` + ## 2.3.2 (2019-11-01) **Added** diff --git a/httprunner/__init__.py b/httprunner/__init__.py index 5b67afa6..4d5c880e 100644 --- a/httprunner/__init__.py +++ b/httprunner/__init__.py @@ -1,4 +1,4 @@ -__version__ = "2.3.2" +__version__ = "2.3.3" __description__ = "One-stop solution for HTTP(S) testing." __all__ = ["__version__", "__description__"] diff --git a/httprunner/api.py b/httprunner/api.py index 8608a189..d8cf9941 100644 --- a/httprunner/api.py +++ b/httprunner/api.py @@ -257,6 +257,7 @@ class HttpRunner(object): """ # load tests self.exception_stage = "load tests" + path = loader.prepare_path(path) tests_mapping = loader.load_tests(path, dot_env_path) tests_mapping["project_mapping"]["test_path"] = path diff --git a/httprunner/loader.py b/httprunner/loader.py index b4735ad1..27bd9f56 100644 --- a/httprunner/loader.py +++ b/httprunner/loader.py @@ -816,6 +816,18 @@ def load_project_tests(test_path, dot_env_path=None): tests_def_mapping["PWD"] = project_working_directory +def prepare_path(path): + if not os.path.exists(path): + err_msg = "path not exist: {}".format(path) + logger.log_error(err_msg) + raise exceptions.FileNotFound(err_msg) + + if not os.path.isabs(path): + path = os.path.join(os.getcwd(), path) + + return path + + def load_tests(path, dot_env_path=None): """ load testcases from file path, extend and merge with api/testcase definitions. @@ -869,14 +881,6 @@ def load_tests(path, dot_env_path=None): } """ - if not os.path.exists(path): - err_msg = "path not exist: {}".format(path) - logger.log_error(err_msg) - raise exceptions.FileNotFound(err_msg) - - if not os.path.isabs(path): - path = os.path.join(os.getcwd(), path) - load_project_tests(path, dot_env_path) tests_mapping = { "project_mapping": project_mapping diff --git a/httprunner/utils.py b/httprunner/utils.py index 133329f3..5f24b396 100644 --- a/httprunner/utils.py +++ b/httprunner/utils.py @@ -607,7 +607,7 @@ def omit_long_data(body, omit_len=512): return omitted_body + appendix_str -def dump_json_file(json_data, pwd_dir_path, dump_file_name): +def dump_json_file(json_data, json_file_abs_path): """ dump json data to file """ class PythonObjectEncoder(json.JSONEncoder): @@ -617,14 +617,8 @@ def dump_json_file(json_data, pwd_dir_path, dump_file_name): except TypeError: return str(obj) - logs_dir_path = os.path.join(pwd_dir_path, "logs") - if not os.path.isdir(logs_dir_path): - os.makedirs(logs_dir_path) - - dump_file_path = os.path.join(logs_dir_path, dump_file_name) - try: - with io.open(dump_file_path, 'w', encoding='utf-8') as outfile: + with io.open(json_file_abs_path, 'w', encoding='utf-8') as outfile: if is_py2: outfile.write( unicode(json.dumps( @@ -645,23 +639,44 @@ def dump_json_file(json_data, pwd_dir_path, dump_file_name): cls=PythonObjectEncoder ) - msg = "dump file: {}".format(dump_file_path) + msg = "dump file: {}".format(json_file_abs_path) logger.color_print(msg, "BLUE") except TypeError as ex: - msg = "Failed to dump json file: {}\nReason: {}".format(dump_file_path, ex) + msg = "Failed to dump json file: {}\nReason: {}".format(json_file_abs_path, ex) logger.color_print(msg, "RED") -def _prepare_dump_info(project_mapping, tag_name): - """ prepare dump file info. +def prepare_dump_json_file_abs_path(project_mapping, tag_name): + """ prepare dump json file absolute path. """ - test_path = project_mapping.get("test_path") or "tests_mapping" pwd_dir_path = project_mapping.get("PWD") or os.getcwd() - file_name, file_suffix = os.path.splitext(os.path.basename(test_path.rstrip("/"))) - dump_file_name = "{}.{}.json".format(file_name, tag_name) + test_path = project_mapping.get("test_path") - return pwd_dir_path, dump_file_name + if not test_path: + # running passed in testcase/testsuite data structure + dump_file_name = "tests_mapping.{}.json".format(tag_name) + dumped_json_file_abs_path = os.path.join(pwd_dir_path, "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(pwd_dir_path, "logs") + test_path_relative_path = test_path[len(pwd_dir_path)+1:] + + if os.path.isdir(test_path): + file_foder_path = os.path.join(logs_dir_path, test_path_relative_path) + dump_file_name = "all.{}.json".format(tag_name) + else: + file_relative_folder_path, test_file = os.path.split(test_path_relative_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 = "{}.{}.json".format(test_file_name, tag_name) + + if not os.path.isdir(file_foder_path): + os.makedirs(file_foder_path, exist_ok=True) + + dumped_json_file_abs_path = os.path.join(file_foder_path, dump_file_name) + return dumped_json_file_abs_path def dump_logs(json_data, project_mapping, tag_name): @@ -674,8 +689,8 @@ def dump_logs(json_data, project_mapping, tag_name): tag_name (str): tag name, loaded/parsed/summary """ - pwd_dir_path, dump_file_name = _prepare_dump_info(project_mapping, tag_name) - dump_json_file(json_data, pwd_dir_path, dump_file_name) + json_file_abs_path = prepare_dump_json_file_abs_path(project_mapping, tag_name) + dump_json_file(json_data, json_file_abs_path) def get_python2_retire_msg(): diff --git a/pyproject.toml b/pyproject.toml index 08c8742c..29385917 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "httprunner" -version = "2.3.2" +version = "2.3.3" description = "One-stop solution for HTTP(S) testing." license = "Apache-2.0" readme = "README.md" diff --git a/tests/httpbin/a.b.c/rpc.yml b/tests/httpbin/a.b.c/rpc.yml new file mode 100644 index 00000000..ef31c546 --- /dev/null +++ b/tests/httpbin/a.b.c/rpc.yml @@ -0,0 +1,10 @@ +name: rpc api +base_url: http://httpbin.org +variables: + expected_status_code: 200 +request: + url: /headers + method: GET +validate: + - eq: ["status_code", $expected_status_code] + - eq: [content.headers.Host, "httpbin.org"] diff --git a/tests/test_utils.py b/tests/test_utils.py index 5a32588f..7952a5ac 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -275,3 +275,37 @@ class TestUtils(ApiServerUnittest): "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 + project_working_directory = os.path.join(os.getcwd(), "tests") + project_mapping = { + "PWD": project_working_directory, + "test_path": os.path.join(os.getcwd(), "tests", "httpbin", "a.b.c") + } + self.assertEqual( + utils.prepare_dump_json_file_abs_path(project_mapping, "loaded"), + os.path.join(project_working_directory, "logs", "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 + project_working_directory = os.path.join(os.getcwd(), "tests") + project_mapping = { + "PWD": project_working_directory, + "test_path": os.path.join(os.getcwd(), "tests", "httpbin", "a.b.c", "rpc.yml") + } + self.assertEqual( + utils.prepare_dump_json_file_abs_path(project_mapping, "loaded"), + os.path.join(project_working_directory, "logs", "httpbin/a.b.c/rpc.loaded.json") + ) + + def test_prepare_dump_json_file_path_for_passed_testcase(self): + project_working_directory = os.path.join(os.getcwd(), "tests") + project_mapping = { + "PWD": project_working_directory + } + self.assertEqual( + utils.prepare_dump_json_file_abs_path(project_mapping, "loaded"), + os.path.join(project_working_directory, "logs", "tests_mapping.loaded.json") + )