fix #343: locate debugtalk.py and use as project working directory

This commit is contained in:
httprunner
2018-08-23 13:03:42 +08:00
parent 5e2159b097
commit 98ada8c84f
8 changed files with 70 additions and 68 deletions

View File

@@ -36,22 +36,6 @@ class HttpRunner(object):
self.kwargs = kwargs self.kwargs = kwargs
self.http_client_session = self.kwargs.pop("http_client_session", None) self.http_client_session = self.kwargs.pop("http_client_session", None)
self.__loader()
def __loader(self):
""" load project dependent files, including api/testcase definitions,
environment variables and builtin module.
"""
loader.reset_loader()
# load api/testcase definition and debugtalk.py module
project_folder_path = os.path.join(os.getcwd(), "tests") # TODO: remove tests
loader.load_project_tests(project_folder_path)
self.project_mapping = loader.project_mapping
utils.set_os_environ(self.project_mapping["env"])
def load_tests(self, path_or_testcases): def load_tests(self, path_or_testcases):
""" load testcases, extend and merge with api/testcase definitions. """ load testcases, extend and merge with api/testcase definitions.
@@ -94,14 +78,14 @@ class HttpRunner(object):
if isinstance(path_or_testcases, list): if isinstance(path_or_testcases, list):
for testcase in path_or_testcases: for testcase in path_or_testcases:
try: try:
dir_path = os.path.dirname(testcase["config"]["path"]) test_path = os.path.dirname(testcase["config"]["path"])
loader.load_debugtalk_module(dir_path) loader.load_project_tests(test_path)
except KeyError: except KeyError:
pass pass
else: else:
try: try:
dir_path = os.path.dirname(path_or_testcases["config"]["path"]) test_path = os.path.dirname(path_or_testcases["config"]["path"])
loader.load_debugtalk_module(dir_path) loader.load_project_tests(test_path)
except KeyError: except KeyError:
pass pass
@@ -109,6 +93,8 @@ class HttpRunner(object):
else: else:
testcases = loader.load_testcases(path_or_testcases) testcases = loader.load_testcases(path_or_testcases)
self.project_mapping = loader.project_mapping
if not testcases: if not testcases:
raise exceptions.TestcaseNotFound raise exceptions.TestcaseNotFound
@@ -245,8 +231,9 @@ class HttpRunner(object):
instance: HttpRunner() instance instance: HttpRunner() instance
""" """
# parser # loader
testcases_list = self.load_tests(path_or_testcases) testcases_list = self.load_tests(path_or_testcases)
# parser
parsed_testcases_list = self.parse_tests(testcases_list) parsed_testcases_list = self.parse_tests(testcases_list)
# initialize # initialize

View File

@@ -6,7 +6,7 @@ import json
import os import os
import yaml import yaml
from httprunner import built_in, exceptions, logger, parser, validator from httprunner import built_in, exceptions, logger, parser, utils, validator
from httprunner.compat import OrderedDict from httprunner.compat import OrderedDict
project_mapping = { project_mapping = {
@@ -192,6 +192,8 @@ def load_dot_env_file():
env_variables_mapping[variable.strip()] = value.strip() env_variables_mapping[variable.strip()] = value.strip()
project_mapping["env"] = env_variables_mapping project_mapping["env"] = env_variables_mapping
utils.set_os_environ(env_variables_mapping)
return env_variables_mapping return env_variables_mapping
@@ -231,6 +233,23 @@ def locate_file(start_path, file_name):
return locate_file(os.path.dirname(start_dir_path), file_name) return locate_file(os.path.dirname(start_dir_path), file_name)
def locate_pwd(start_path):
""" locate project working directory.
The folder contains debugtalk.py will be used as PWD.
If debugtalk.py is not found, use os.getcwd() as default PWD.
Args:
start_path (str): start locating path, maybe testcase file path or directory path
"""
global project_working_directory
try:
debugtalk_path = locate_file(start_path, "debugtalk.py")
project_working_directory = os.path.dirname(debugtalk_path)
except exceptions.FileNotFound:
project_working_directory = os.getcwd()
############################################################################### ###############################################################################
## debugtalk.py module loader ## debugtalk.py module loader
############################################################################### ###############################################################################
@@ -297,25 +316,18 @@ def load_builtin_module():
project_mapping["debugtalk"] = built_in_module project_mapping["debugtalk"] = built_in_module
def load_debugtalk_module(start_path=None): def load_debugtalk_module():
""" load project debugtalk.py module and merge with builtin module. """ load project debugtalk.py module and merge with builtin module.
debugtalk.py should be located in project working directory.
Args: variables and functions mapping for debugtalk.py
start_path (str, optional): start locating path, maybe file path or directory path.
Defaults to current working directory.
Returns:
dict: variables and functions mapping for debugtalk.py
{ {
"variables": {}, "variables": {},
"functions": {} "functions": {}
} }
""" """
start_path = start_path or os.getcwd()
try: try:
module_path = locate_file(start_path, "debugtalk.py") module_path = locate_file(project_working_directory, "debugtalk.py")
module_name = convert_module_name(module_path) module_name = convert_module_name(module_path)
except exceptions.FileNotFound: except exceptions.FileNotFound:
return return
@@ -734,7 +746,7 @@ def load_folder_content(folder_path):
return items_mapping return items_mapping
def load_api_folder(api_folder_path=None): def load_api_folder(api_folder_path):
""" load api definitions from api folder. """ load api definitions from api folder.
Args: Args:
@@ -775,7 +787,6 @@ def load_api_folder(api_folder_path=None):
""" """
api_definition_mapping = {} api_definition_mapping = {}
api_folder_path = api_folder_path or os.path.join(os.getcwd(), "api")
api_items_mapping = load_folder_content(api_folder_path) api_items_mapping = load_folder_content(api_folder_path)
for api_file_path, api_items in api_items_mapping.items(): for api_file_path, api_items in api_items_mapping.items():
@@ -797,7 +808,7 @@ def load_api_folder(api_folder_path=None):
return api_definition_mapping return api_definition_mapping
def load_test_folder(test_folder_path=None): def load_test_folder(test_folder_path):
""" load testcases definitions from folder. """ load testcases definitions from folder.
Args: Args:
@@ -839,8 +850,6 @@ def load_test_folder(test_folder_path=None):
""" """
test_definition_mapping = {} test_definition_mapping = {}
# TODO: replace suite with testcases
test_folder_path = test_folder_path or os.path.join(os.getcwd(), "suite")
test_items_mapping = load_folder_content(test_folder_path) test_items_mapping = load_folder_content(test_folder_path)
for test_file_path, items in test_items_mapping.items(): for test_file_path, items in test_items_mapping.items():
@@ -882,6 +891,9 @@ def load_test_folder(test_folder_path=None):
def reset_loader(): def reset_loader():
""" reset project mapping. """ reset project mapping.
""" """
global project_working_directory
project_working_directory = os.getcwd()
project_mapping["debugtalk"] = { project_mapping["debugtalk"] = {
"variables": {}, "variables": {},
"functions": {} "functions": {}
@@ -892,18 +904,22 @@ def reset_loader():
testcases_cache_mapping.clear() testcases_cache_mapping.clear()
def load_project_tests(folder_path): def load_project_tests(test_path):
""" load api, testcases and builtin module. """ load api, testcases, .env, builtin module and debugtalk.py.
api/testcases folder is relative to project_working_directory
Args: Args:
folder_path (str): folder path. test_path (str): test file/folder path, locate pwd from this path.
""" """
reset_loader()
locate_pwd(test_path)
load_builtin_module() load_builtin_module()
load_api_folder(os.path.join(folder_path, "api")) load_api_folder(os.path.join(project_working_directory, "api"))
load_test_folder(os.path.join(folder_path, "suite")) load_test_folder(os.path.join(project_working_directory, "suite"))
# load .env # load .env
load_dot_env_file() load_dot_env_file()
load_debugtalk_module()
def load_testcases(path): def load_testcases(path):
@@ -942,14 +958,13 @@ def load_testcases(path):
return testcases_cache_mapping[path] return testcases_cache_mapping[path]
if os.path.isdir(path): if os.path.isdir(path):
load_debugtalk_module(path) load_project_tests(path)
files_list = load_folder_files(path) files_list = load_folder_files(path)
testcases_list = load_testcases(files_list) testcases_list = load_testcases(files_list)
elif os.path.isfile(path): elif os.path.isfile(path):
try: try:
dir_path = os.path.dirname(path) load_project_tests(path)
load_debugtalk_module(dir_path)
testcase = _load_test_file(path) testcase = _load_test_file(path)
if testcase["teststeps"]: if testcase["teststeps"]:
testcases_list = [testcase] testcases_list = [testcase]

View File

@@ -9,7 +9,7 @@ from base64 import b64encode
from collections import Iterable from collections import Iterable
from datetime import datetime from datetime import datetime
from httprunner import logger from httprunner import loader, logger
from httprunner.__about__ import __version__ from httprunner.__about__ import __version__
from httprunner.compat import basestring, bytes, json, numeric_types from httprunner.compat import basestring, bytes, json, numeric_types
from jinja2 import Template, escape from jinja2 import Template, escape
@@ -95,7 +95,7 @@ def render_html_report(summary, html_report_name=None, html_report_template=None
logger.log_info("Start to render Html report ...") logger.log_info("Start to render Html report ...")
logger.log_debug("render data: {}".format(summary)) logger.log_debug("render data: {}".format(summary))
report_dir_path = os.path.join(os.getcwd(), "reports") report_dir_path = os.path.join(loader.project_working_directory, "reports")
start_at_timestamp = int(summary["time"]["start_at"]) start_at_timestamp = int(summary["time"]["start_at"])
summary["time"]["start_datetime"] = datetime.fromtimestamp(start_at_timestamp).strftime('%Y-%m-%d %H:%M:%S') summary["time"]["start_datetime"] = datetime.fromtimestamp(start_at_timestamp).strftime('%Y-%m-%d %H:%M:%S')
if html_report_name: if html_report_name:

View File

@@ -2,7 +2,7 @@ import os
import shutil import shutil
import time import time
from httprunner import HttpRunner, LocustRunner from httprunner import HttpRunner, LocustRunner, loader
from locust import HttpLocust from locust import HttpLocust
from tests.api_server import HTTPBIN_SERVER from tests.api_server import HTTPBIN_SERVER
from tests.base import ApiServerUnittest from tests.base import ApiServerUnittest
@@ -89,7 +89,7 @@ class TestHttpRunner(ApiServerUnittest):
self.assertEqual(summary["stat"]["skipped"], 4) self.assertEqual(summary["stat"]["skipped"], 4)
runner.gen_html_report(html_report_name=output_folder_name) runner.gen_html_report(html_report_name=output_folder_name)
report_save_dir = os.path.join(os.getcwd(), 'reports', output_folder_name) report_save_dir = os.path.join(loader.project_working_directory, 'reports', output_folder_name)
self.assertGreater(len(os.listdir(report_save_dir)), 0) self.assertGreater(len(os.listdir(report_save_dir)), 0)
shutil.rmtree(report_save_dir) shutil.rmtree(report_save_dir)
@@ -155,7 +155,7 @@ class TestHttpRunner(ApiServerUnittest):
output_folder_name = os.path.basename(os.path.splitext(testset_path)[0]) output_folder_name = os.path.basename(os.path.splitext(testset_path)[0])
report = runner.gen_html_report(html_report_name=output_folder_name) report = runner.gen_html_report(html_report_name=output_folder_name)
self.assertTrue(os.path.isfile(report)) self.assertTrue(os.path.isfile(report))
report_save_dir = os.path.join(os.getcwd(), 'reports', output_folder_name) report_save_dir = os.path.join(loader.project_working_directory, 'reports', output_folder_name)
shutil.rmtree(report_save_dir) shutil.rmtree(report_save_dir)
def test_testcase_layer(self): def test_testcase_layer(self):

View File

@@ -9,9 +9,7 @@ from tests.base import ApiServerUnittest
class TestContext(ApiServerUnittest): class TestContext(ApiServerUnittest):
def setUp(self): def setUp(self):
project_dir = os.path.join(os.getcwd(), "tests") loader.load_project_tests(os.path.join(os.getcwd(), "tests"))
loader.load_project_tests(project_dir)
loader.load_debugtalk_module(project_dir)
self.debugtalk_module = loader.project_mapping["debugtalk"] self.debugtalk_module = loader.project_mapping["debugtalk"]
self.context = context.Context( self.context = context.Context(

View File

@@ -185,15 +185,13 @@ class TestModuleLoader(unittest.TestCase):
self.assertNotIn("is_py3", functions_dict) self.assertNotIn("is_py3", functions_dict)
def test_load_debugtalk_module(self): def test_load_debugtalk_module(self):
project_dir = os.path.join(os.getcwd(), "tests") loader.load_project_tests(os.path.join(os.getcwd(), "httprunner"))
loader.load_project_tests(project_dir)
loader.load_debugtalk_module()
imported_module_items = loader.project_mapping["debugtalk"] imported_module_items = loader.project_mapping["debugtalk"]
self.assertIn("equals", imported_module_items["functions"]) self.assertIn("equals", imported_module_items["functions"])
self.assertNotIn("SECRET_KEY", imported_module_items["variables"]) self.assertNotIn("SECRET_KEY", imported_module_items["variables"])
self.assertNotIn("alter_response", imported_module_items["functions"]) self.assertNotIn("alter_response", imported_module_items["functions"])
loader.load_debugtalk_module("tests") loader.load_project_tests(os.path.join(os.getcwd(), "tests"))
imported_module_items = loader.project_mapping["debugtalk"] imported_module_items = loader.project_mapping["debugtalk"]
self.assertEqual( self.assertEqual(
imported_module_items["variables"]["SECRET_KEY"], imported_module_items["variables"]["SECRET_KEY"],
@@ -228,13 +226,22 @@ class TestModuleLoader(unittest.TestCase):
with self.assertRaises(exceptions.VariableNotFound): with self.assertRaises(exceptions.VariableNotFound):
loader.get_module_item(module_mapping, "variables", "SECRET_KEY2") loader.get_module_item(module_mapping, "variables", "SECRET_KEY2")
def test_locate_pwd(self):
loader.locate_pwd("tests/data/demo_testcase.yml")
self.assertEqual(loader.project_working_directory, "tests")
loader.locate_pwd("tests/base.py")
self.assertEqual(loader.project_working_directory, "tests")
loader.locate_pwd("httprunner/__init__.py")
self.assertEqual(loader.project_working_directory, os.getcwd())
class TestSuiteLoader(unittest.TestCase): class TestSuiteLoader(unittest.TestCase):
@classmethod @classmethod
def setUpClass(cls): def setUpClass(cls):
project_dir = os.path.join(os.getcwd(), "tests") loader.load_project_tests(os.path.join(os.getcwd(), "tests"))
loader.load_project_tests(project_dir)
def test_load_test_file_testcase(self): def test_load_test_file_testcase(self):
testcase = loader._load_test_file("tests/testcases/smoketest.yml") testcase = loader._load_test_file("tests/testcases/smoketest.yml")
@@ -483,9 +490,7 @@ class TestSuiteLoader(unittest.TestCase):
) )
def test_load_project_tests(self): def test_load_project_tests(self):
loader.project_working_directory = os.path.join(os.getcwd(), "tests") loader.load_project_tests(os.path.join(os.getcwd(), "tests"))
loader.load_project_tests(loader.project_working_directory)
loader.load_debugtalk_module(loader.project_working_directory)
project_mapping = loader.project_mapping project_mapping = loader.project_mapping
self.assertEqual(project_mapping["debugtalk"]["variables"]["SECRET_KEY"], "DebugTalk") self.assertEqual(project_mapping["debugtalk"]["variables"]["SECRET_KEY"], "DebugTalk")
self.assertIn("get_token", project_mapping["def-api"]) self.assertIn("get_token", project_mapping["def-api"])

View File

@@ -412,8 +412,7 @@ class TestParser(unittest.TestCase):
) )
def test_parse_parameters_mix(self): def test_parse_parameters_mix(self):
project_dir = os.path.join(os.getcwd(), "tests") loader.load_project_tests(os.path.join(os.getcwd(), "tests"))
loader.load_debugtalk_module(project_dir)
project_mapping = loader.project_mapping project_mapping = loader.project_mapping
parameters = [ parameters = [

View File

@@ -10,9 +10,7 @@ from tests.base import ApiServerUnittest
class TestRunner(ApiServerUnittest): class TestRunner(ApiServerUnittest):
def setUp(self): def setUp(self):
project_dir = os.path.join(os.getcwd(), "tests") loader.load_project_tests(os.path.join(os.getcwd(), "tests"))
loader.load_project_tests(project_dir)
loader.load_debugtalk_module(project_dir)
self.debugtalk_module = loader.project_mapping["debugtalk"] self.debugtalk_module = loader.project_mapping["debugtalk"]
config_dict = { config_dict = {
"variables": self.debugtalk_module["variables"], "variables": self.debugtalk_module["variables"],