mirror of
https://github.com/httprunner/httprunner.git
synced 2026-07-12 16:01:27 +08:00
logging with colors
This commit is contained in:
@@ -1,18 +1,18 @@
|
|||||||
import argparse
|
import argparse
|
||||||
import logging
|
|
||||||
import multiprocessing
|
import multiprocessing
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
import unittest
|
import unittest
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
from httprunner import __version__ as hrun_version
|
|
||||||
from httprunner.utils import create_scaffold, print_output, string_type
|
|
||||||
from pyunitreport import __version__ as pyu_version
|
from pyunitreport import __version__ as pyu_version
|
||||||
from pyunitreport import HTMLTestRunner
|
from pyunitreport import HTMLTestRunner
|
||||||
|
|
||||||
|
from . import __version__ as hrun_version
|
||||||
|
from . import logger
|
||||||
from .exception import TestcaseNotFound
|
from .exception import TestcaseNotFound
|
||||||
from .task import Result, TaskSuite
|
from .task import Result, TaskSuite
|
||||||
|
from .utils import create_scaffold, print_output, string_type
|
||||||
|
|
||||||
|
|
||||||
def run_suite_path(path, mapping=None, runner=None):
|
def run_suite_path(path, mapping=None, runner=None):
|
||||||
@@ -59,21 +59,13 @@ def main_hrun():
|
|||||||
help="Specify new project name.")
|
help="Specify new project name.")
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
logger.setup_logger(args.log_level)
|
||||||
|
|
||||||
if args.version:
|
if args.version:
|
||||||
print("HttpRunner version: {}".format(hrun_version))
|
logger.color_print("HttpRunner version: {}".format(hrun_version), "GREEN")
|
||||||
print("PyUnitReport version: {}".format(pyu_version))
|
logger.color_print("PyUnitReport version: {}".format(pyu_version), "GREEN")
|
||||||
exit(0)
|
exit(0)
|
||||||
|
|
||||||
log_level = getattr(logging, args.log_level.upper(), None)
|
|
||||||
if not log_level:
|
|
||||||
raise ValueError('Invalid log level: %s' % args.log_level)
|
|
||||||
logging.basicConfig(level=log_level)
|
|
||||||
|
|
||||||
if log_level >= 20:
|
|
||||||
# hide traceback when log level is INFO/WARNING/ERROR/CRITICAL
|
|
||||||
sys.tracebacklimit = 0
|
|
||||||
|
|
||||||
project_name = args.startproject
|
project_name = args.startproject
|
||||||
if project_name:
|
if project_name:
|
||||||
project_path = os.path.join(os.getcwd(), project_name)
|
project_path = os.path.join(os.getcwd(), project_name)
|
||||||
@@ -93,14 +85,14 @@ def main_hrun():
|
|||||||
def main_locust():
|
def main_locust():
|
||||||
""" Performance test with locust: parse command line options and run commands.
|
""" Performance test with locust: parse command line options and run commands.
|
||||||
"""
|
"""
|
||||||
logging.basicConfig(level="INFO")
|
logger.setup_logger("INFO")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from httprunner import locusts
|
from httprunner import locusts
|
||||||
except ImportError:
|
except ImportError:
|
||||||
msg = "Locust is not installed, install first and try again.\n"
|
msg = "Locust is not installed, install first and try again.\n"
|
||||||
msg += "install command: pip install locustio"
|
msg += "install command: pip install locustio"
|
||||||
logging.info(msg)
|
logger.log_warning(msg)
|
||||||
exit(1)
|
exit(1)
|
||||||
|
|
||||||
sys.argv[0] = 'locust'
|
sys.argv[0] = 'locust'
|
||||||
@@ -115,7 +107,7 @@ def main_locust():
|
|||||||
testcase_index = sys.argv.index('-f') + 1
|
testcase_index = sys.argv.index('-f') + 1
|
||||||
assert testcase_index < len(sys.argv)
|
assert testcase_index < len(sys.argv)
|
||||||
except (ValueError, AssertionError):
|
except (ValueError, AssertionError):
|
||||||
logging.error("Testcase file is not specified, exit.")
|
logger.log_error("Testcase file is not specified, exit.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
testcase_file_path = sys.argv[testcase_index]
|
testcase_file_path = sys.argv[testcase_index]
|
||||||
@@ -125,7 +117,7 @@ def main_locust():
|
|||||||
""" locusts -f locustfile.py --cpu-cores 4
|
""" locusts -f locustfile.py --cpu-cores 4
|
||||||
"""
|
"""
|
||||||
if "--no-web" in sys.argv:
|
if "--no-web" in sys.argv:
|
||||||
logging.error("conflict parameter args: --cpu-cores & --no-web. \nexit.")
|
logger.log_error("conflict parameter args: --cpu-cores & --no-web. \nexit.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
cpu_cores_index = sys.argv.index('--cpu-cores')
|
cpu_cores_index = sys.argv.index('--cpu-cores')
|
||||||
@@ -137,7 +129,7 @@ def main_locust():
|
|||||||
locusts -f locustfile.py --cpu-cores
|
locusts -f locustfile.py --cpu-cores
|
||||||
"""
|
"""
|
||||||
cpu_cores_num_value = multiprocessing.cpu_count()
|
cpu_cores_num_value = multiprocessing.cpu_count()
|
||||||
logging.warning("cpu cores number not specified, use {} by default.".format(cpu_cores_num_value))
|
logger.log_warning("cpu cores number not specified, use {} by default.".format(cpu_cores_num_value))
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
""" locusts -f locustfile.py --cpu-cores 4 """
|
""" locusts -f locustfile.py --cpu-cores 4 """
|
||||||
@@ -146,7 +138,7 @@ def main_locust():
|
|||||||
except ValueError:
|
except ValueError:
|
||||||
""" locusts -f locustfile.py --cpu-cores -P 8888 """
|
""" locusts -f locustfile.py --cpu-cores -P 8888 """
|
||||||
cpu_cores_num_value = multiprocessing.cpu_count()
|
cpu_cores_num_value = multiprocessing.cpu_count()
|
||||||
logging.warning("cpu cores number not specified, use {} by default.".format(cpu_cores_num_value))
|
logger.log_warning("cpu cores number not specified, use {} by default.".format(cpu_cores_num_value))
|
||||||
|
|
||||||
sys.argv.pop(cpu_cores_index)
|
sys.argv.pop(cpu_cores_index)
|
||||||
locusts.run_locusts_on_cpu_cores(sys.argv, cpu_cores_num_value)
|
locusts.run_locusts_on_cpu_cores(sys.argv, cpu_cores_num_value)
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
import json
|
import json
|
||||||
import logging
|
|
||||||
import re
|
import re
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import requests
|
import requests
|
||||||
import urllib3
|
import urllib3
|
||||||
from httprunner.exception import ParamsError
|
|
||||||
from requests import Request, Response
|
from requests import Request, Response
|
||||||
from requests.exceptions import (InvalidSchema, InvalidURL, MissingSchema,
|
from requests.exceptions import (InvalidSchema, InvalidURL, MissingSchema,
|
||||||
RequestException)
|
RequestException)
|
||||||
|
|
||||||
|
from . import logger
|
||||||
|
from .exception import ParamsError
|
||||||
|
|
||||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||||
|
|
||||||
absolute_http_url_regexp = re.compile(r"^https?://", re.I)
|
absolute_http_url_regexp = re.compile(r"^https?://", re.I)
|
||||||
@@ -99,8 +100,8 @@ class HttpSession(requests.Session):
|
|||||||
|
|
||||||
# prepend url with hostname unless it's already an absolute URL
|
# prepend url with hostname unless it's already an absolute URL
|
||||||
url = self._build_url(url)
|
url = self._build_url(url)
|
||||||
logging.info(" Start to {method} {url}".format(method=method, url=url))
|
logger.log_info("{method} {url}".format(method=method, url=url))
|
||||||
logging.debug(" kwargs: {kwargs}".format(kwargs=kwargs))
|
logger.log_debug("request kwargs: {kwargs}".format(kwargs=kwargs))
|
||||||
# store meta data that is used when reporting the request to locust's statistics
|
# store meta data that is used when reporting the request to locust's statistics
|
||||||
request_meta = {}
|
request_meta = {}
|
||||||
|
|
||||||
@@ -136,16 +137,17 @@ class HttpSession(requests.Session):
|
|||||||
request_meta["response_headers"] = response.headers
|
request_meta["response_headers"] = response.headers
|
||||||
request_meta["response_content"] = response.content
|
request_meta["response_content"] = response.content
|
||||||
|
|
||||||
logging.debug(" response: {response}".format(response=request_meta))
|
logger.log_debug("response status_code: {}".format(response.status_code))
|
||||||
|
logger.log_debug("response headers: {}".format(response.headers))
|
||||||
|
logger.log_debug("response body: {}".format(response.text))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
except RequestException as e:
|
except RequestException as e:
|
||||||
logging.error(u" Failed to {method} {url}! exception msg: {exception}".format(
|
logger.log_error(u"{exception}".format(exception=str(e)))
|
||||||
method=method, url=url, exception=str(e)))
|
|
||||||
else:
|
else:
|
||||||
logging.info(
|
logger.log_info(
|
||||||
""" status_code: {}, response_time: {} ms, response_length: {} bytes"""\
|
"""status_code: {}, response_time: {} ms, response_length: {} bytes"""\
|
||||||
.format(request_meta["status_code"], request_meta["response_time"], \
|
.format(request_meta["status_code"], request_meta["response_time"], \
|
||||||
request_meta["content_size"]))
|
request_meta["content_size"]))
|
||||||
|
|
||||||
|
|||||||
@@ -3,9 +3,11 @@ import multiprocessing
|
|||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from httprunner.testcase import load_test_file
|
|
||||||
from locust.main import main
|
from locust.main import main
|
||||||
|
|
||||||
|
from .logger import color_print
|
||||||
|
from .testcase import load_test_file
|
||||||
|
|
||||||
|
|
||||||
def parse_locustfile(file_path):
|
def parse_locustfile(file_path):
|
||||||
""" parse testcase file and return locustfile path.
|
""" parse testcase file and return locustfile path.
|
||||||
@@ -13,7 +15,7 @@ def parse_locustfile(file_path):
|
|||||||
if file_path is a YAML/JSON file, convert it to locustfile
|
if file_path is a YAML/JSON file, convert it to locustfile
|
||||||
"""
|
"""
|
||||||
if not os.path.isfile(file_path):
|
if not os.path.isfile(file_path):
|
||||||
print("file path invalid, exit.")
|
color_print("file path invalid, exit.", "RED")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
file_suffix = os.path.splitext(file_path)[1]
|
file_suffix = os.path.splitext(file_path)[1]
|
||||||
@@ -23,7 +25,7 @@ def parse_locustfile(file_path):
|
|||||||
locustfile_path = gen_locustfile(file_path)
|
locustfile_path = gen_locustfile(file_path)
|
||||||
else:
|
else:
|
||||||
# '' or other suffix
|
# '' or other suffix
|
||||||
print("file type should be YAML/JSON/Python, exit.")
|
color_print("file type should be YAML/JSON/Python, exit.", "RED")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
return locustfile_path
|
return locustfile_path
|
||||||
|
|||||||
63
httprunner/logger.py
Normal file
63
httprunner/logger.py
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
import logging
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from colorama import Back, Fore, Style, init
|
||||||
|
from colorlog import ColoredFormatter
|
||||||
|
|
||||||
|
init(autoreset=True)
|
||||||
|
|
||||||
|
log_colors_config = {
|
||||||
|
'DEBUG': 'cyan',
|
||||||
|
'INFO': 'green',
|
||||||
|
'WARNING': 'yellow',
|
||||||
|
'ERROR': 'red',
|
||||||
|
'CRITICAL': 'red',
|
||||||
|
}
|
||||||
|
|
||||||
|
def setup_logger(log_level):
|
||||||
|
"""setup root logger with ColoredFormatter."""
|
||||||
|
level = getattr(logging, log_level.upper(), None)
|
||||||
|
if not level:
|
||||||
|
color_print("Invalid log level: %s" % log_level, "RED")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
# hide traceback when log level is INFO/WARNING/ERROR/CRITICAL
|
||||||
|
if level >= logging.INFO:
|
||||||
|
sys.tracebacklimit = 0
|
||||||
|
|
||||||
|
formatter = ColoredFormatter(
|
||||||
|
"%(log_color)s%(bg_white)s%(levelname)-8s%(reset)s %(message)s",
|
||||||
|
datefmt=None,
|
||||||
|
reset=True,
|
||||||
|
log_colors=log_colors_config
|
||||||
|
)
|
||||||
|
|
||||||
|
handler = logging.StreamHandler()
|
||||||
|
handler.setFormatter(formatter)
|
||||||
|
logging.root.addHandler(handler)
|
||||||
|
logging.root.setLevel(level)
|
||||||
|
|
||||||
|
|
||||||
|
def coloring(text, color="WHITE"):
|
||||||
|
fore_color = getattr(Fore, color.upper())
|
||||||
|
return fore_color + text
|
||||||
|
|
||||||
|
def color_print(msg, color="WHITE"):
|
||||||
|
fore_color = getattr(Fore, color.upper())
|
||||||
|
print(fore_color + msg)
|
||||||
|
|
||||||
|
def log_with_color(level):
|
||||||
|
""" log with color by different level
|
||||||
|
"""
|
||||||
|
def wrapper(text):
|
||||||
|
color = log_colors_config[level.upper()]
|
||||||
|
getattr(logging, level.lower())(coloring(text, color))
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
log_debug = log_with_color("debug")
|
||||||
|
log_info = log_with_color("info")
|
||||||
|
log_warning = log_with_color("warning")
|
||||||
|
log_error = log_with_color("error")
|
||||||
|
log_critical = log_with_color("critical")
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
import logging
|
|
||||||
import re
|
import re
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
from httprunner import exception, utils, testcase
|
|
||||||
from requests.structures import CaseInsensitiveDict
|
from requests.structures import CaseInsensitiveDict
|
||||||
|
|
||||||
|
from . import exception, logger, testcase, utils
|
||||||
|
|
||||||
text_extractor_regexp_compile = re.compile(r".*\(.*\).*")
|
text_extractor_regexp_compile = re.compile(r".*\(.*\).*")
|
||||||
|
|
||||||
|
|
||||||
@@ -42,10 +42,10 @@ class ResponseObject(object):
|
|||||||
"""
|
"""
|
||||||
matched = re.search(field, self.resp_text)
|
matched = re.search(field, self.resp_text)
|
||||||
if not matched:
|
if not matched:
|
||||||
err_msg = u"Extractor error: failed to extract data with regex!\n"
|
err_msg = u"Failed to extract data with regex!\n"
|
||||||
err_msg += u"response body: {}\n".format(self.resp_text)
|
err_msg += u"response body: {}\n".format(self.resp_text)
|
||||||
err_msg += u"regex: {}\n".format(field)
|
err_msg += u"regex: {}\n".format(field)
|
||||||
logging.error(err_msg)
|
logger.log_error(err_msg)
|
||||||
raise exception.ParamsError(err_msg)
|
raise exception.ParamsError(err_msg)
|
||||||
|
|
||||||
return matched.group(1)
|
return matched.group(1)
|
||||||
@@ -75,10 +75,10 @@ class ResponseObject(object):
|
|||||||
|
|
||||||
if sub_query:
|
if sub_query:
|
||||||
if not isinstance(top_query_content, (dict, CaseInsensitiveDict, list)):
|
if not isinstance(top_query_content, (dict, CaseInsensitiveDict, list)):
|
||||||
err_msg = u"Extractor error: failed to extract data with regex!\n"
|
err_msg = u"Failed to extract data with regex!\n"
|
||||||
err_msg += u"response: {}\n".format(self.parsed_dict())
|
err_msg += u"response: {}\n".format(self.parsed_dict())
|
||||||
err_msg += u"regex: {}\n".format(field)
|
err_msg += u"regex: {}\n".format(field)
|
||||||
logging.error(err_msg)
|
logger.log_error(err_msg)
|
||||||
raise exception.ParamsError(err_msg)
|
raise exception.ParamsError(err_msg)
|
||||||
|
|
||||||
# e.g. key: resp_headers_content_type, sub_query = "content-type"
|
# e.g. key: resp_headers_content_type, sub_query = "content-type"
|
||||||
@@ -91,7 +91,7 @@ class ResponseObject(object):
|
|||||||
err_msg = u"Failed to extract value from response!\n"
|
err_msg = u"Failed to extract value from response!\n"
|
||||||
err_msg += u"response: {}\n".format(self.parsed_dict())
|
err_msg += u"response: {}\n".format(self.parsed_dict())
|
||||||
err_msg += u"extract field: {}\n".format(field)
|
err_msg += u"extract field: {}\n".format(field)
|
||||||
logging.error(err_msg)
|
logger.log_error(err_msg)
|
||||||
raise exception.ParamsError(err_msg)
|
raise exception.ParamsError(err_msg)
|
||||||
|
|
||||||
def extract_field(self, field):
|
def extract_field(self, field):
|
||||||
|
|||||||
@@ -1,9 +1,8 @@
|
|||||||
import logging
|
|
||||||
from unittest.case import SkipTest
|
from unittest.case import SkipTest
|
||||||
|
|
||||||
from httprunner import exception, response, testcase, utils
|
from . import exception, logger, response, testcase, utils
|
||||||
from httprunner.client import HttpSession
|
from .client import HttpSession
|
||||||
from httprunner.context import Context
|
from .context import Context
|
||||||
|
|
||||||
|
|
||||||
class Runner(object):
|
class Runner(object):
|
||||||
@@ -156,12 +155,20 @@ class Runner(object):
|
|||||||
try:
|
try:
|
||||||
self.context.validate(validators, resp_obj)
|
self.context.validate(validators, resp_obj)
|
||||||
except (exception.ParamsError, exception.ResponseError, exception.ValidationError):
|
except (exception.ParamsError, exception.ResponseError, exception.ValidationError):
|
||||||
err_msg = u"Exception occured.\n"
|
# log request
|
||||||
err_msg += u"HTTP request url: {}\n".format(url)
|
err_req_msg = "request: \n"
|
||||||
err_msg += u"HTTP request kwargs: {}\n".format(parsed_request)
|
err_req_msg += "headers: {}\n".format(parsed_request.pop("headers", {}))
|
||||||
err_msg += u"HTTP response status_code: {}\n".format(resp.status_code)
|
for k, v in parsed_request.items():
|
||||||
err_msg += u"HTTP response content: \n{}".format(resp.text)
|
err_req_msg += "{}: {}\n".format(k, v)
|
||||||
logging.error(err_msg)
|
logger.log_error(err_req_msg)
|
||||||
|
|
||||||
|
# log response
|
||||||
|
err_resp_msg = "response: \n"
|
||||||
|
err_resp_msg += "status_code: {}\n".format(resp.status_code)
|
||||||
|
err_resp_msg += "headers: {}\n".format(resp.headers)
|
||||||
|
err_resp_msg += "body: {}\n".format(resp.text)
|
||||||
|
logger.log_error(err_resp_msg)
|
||||||
|
|
||||||
raise
|
raise
|
||||||
finally:
|
finally:
|
||||||
setup_teardown(teardown_actions)
|
setup_teardown(teardown_actions)
|
||||||
@@ -174,7 +181,7 @@ class Runner(object):
|
|||||||
output = {}
|
output = {}
|
||||||
for variable in output_variables_list:
|
for variable in output_variables_list:
|
||||||
if variable not in variables_mapping:
|
if variable not in variables_mapping:
|
||||||
logging.warning(
|
logger.log_warning(
|
||||||
"variable '{}' can not be found in variables mapping, failed to ouput!"\
|
"variable '{}' can not be found in variables mapping, failed to ouput!"\
|
||||||
.format(variable)
|
.format(variable)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
import logging
|
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
from httprunner import exception, runner, testcase, utils
|
from . import exception, logger, runner, testcase, utils
|
||||||
|
|
||||||
|
|
||||||
class ApiTestCase(unittest.TestCase):
|
class ApiTestCase(unittest.TestCase):
|
||||||
@@ -73,10 +72,11 @@ class ApiTestSuite(unittest.TestSuite):
|
|||||||
def _add_tests_to_suite(self, testcases):
|
def _add_tests_to_suite(self, testcases):
|
||||||
for testcase_dict in testcases:
|
for testcase_dict in testcases:
|
||||||
testcase_name = self.test_runner.context.eval_content(testcase_dict["name"])
|
testcase_name = self.test_runner.context.eval_content(testcase_dict["name"])
|
||||||
|
testcase_name_with_color = logger.coloring(testcase_name, "yellow")
|
||||||
if utils.PYTHON_VERSION == 3:
|
if utils.PYTHON_VERSION == 3:
|
||||||
ApiTestCase.runTest.__doc__ = testcase_name
|
ApiTestCase.runTest.__doc__ = testcase_name_with_color
|
||||||
else:
|
else:
|
||||||
ApiTestCase.runTest.__func__.__doc__ = testcase_name
|
ApiTestCase.runTest.__func__.__doc__ = testcase_name_with_color
|
||||||
|
|
||||||
test = ApiTestCase(self.test_runner, testcase_dict)
|
test = ApiTestCase(self.test_runner, testcase_dict)
|
||||||
[self.addTest(test) for _ in range(int(testcase_dict.get("times", 1)))]
|
[self.addTest(test) for _ in range(int(testcase_dict.get("times", 1)))]
|
||||||
@@ -165,14 +165,10 @@ class LocustTask(object):
|
|||||||
try:
|
try:
|
||||||
test.runTest()
|
test.runTest()
|
||||||
except exception.MyBaseError as ex:
|
except exception.MyBaseError as ex:
|
||||||
try:
|
from locust.events import request_failure
|
||||||
from locust.events import request_failure
|
request_failure.fire(
|
||||||
request_failure.fire(
|
request_type=test.testcase_dict.get("request", {}).get("method"),
|
||||||
request_type=test.testcase_dict.get("request", {}).get("method"),
|
name=test.testcase_dict.get("request", {}).get("url"),
|
||||||
name=test.testcase_dict.get("request", {}).get("url"),
|
response_time=0,
|
||||||
response_time=0,
|
exception=ex
|
||||||
exception=ex
|
)
|
||||||
)
|
|
||||||
except ImportError:
|
|
||||||
logging.exception(
|
|
||||||
"Exception occured in testcase: {}".format(test.testcase_dict.get("name")))
|
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ import ast
|
|||||||
import io
|
import io
|
||||||
import itertools
|
import itertools
|
||||||
import json
|
import json
|
||||||
import logging
|
|
||||||
import os
|
import os
|
||||||
import random
|
import random
|
||||||
import re
|
import re
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
from httprunner import exception, utils
|
|
||||||
|
from . import exception, logger, utils
|
||||||
|
|
||||||
variable_regexp = r"\$([\w_]+)"
|
variable_regexp = r"\$([\w_]+)"
|
||||||
function_regexp = r"\$\{([\w_]+\([\$\w_ =,]*\))\}"
|
function_regexp = r"\$\{([\w_]+\([\$\w_ =,]*\))\}"
|
||||||
@@ -38,7 +38,7 @@ def _load_json_file(json_file):
|
|||||||
json_content = json.load(data_file)
|
json_content = json.load(data_file)
|
||||||
except exception.JSONDecodeError:
|
except exception.JSONDecodeError:
|
||||||
err_msg = u"JSONDecodeError: JSON file format error: {}".format(json_file)
|
err_msg = u"JSONDecodeError: JSON file format error: {}".format(json_file)
|
||||||
logging.error(err_msg)
|
logger.log_error(err_msg)
|
||||||
raise exception.FileFormatError(err_msg)
|
raise exception.FileFormatError(err_msg)
|
||||||
|
|
||||||
check_format(json_file, json_content)
|
check_format(json_file, json_content)
|
||||||
@@ -110,8 +110,8 @@ def load_file(file_path):
|
|||||||
return _load_csv_file(file_path)
|
return _load_csv_file(file_path)
|
||||||
else:
|
else:
|
||||||
# '' or other suffix
|
# '' or other suffix
|
||||||
err_msg = u"file is not in YAML/JSON format: {}".format(file_path)
|
err_msg = u"Unsupported file format: {}".format(file_path)
|
||||||
logging.warning(err_msg)
|
logger.log_warning(err_msg)
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def extract_variables(content):
|
def extract_variables(content):
|
||||||
@@ -267,7 +267,7 @@ def load_testcases_by_path(path):
|
|||||||
testcases_list = []
|
testcases_list = []
|
||||||
|
|
||||||
else:
|
else:
|
||||||
logging.error(u"file not found: {}".format(path))
|
logger.log_error(u"file not found: {}".format(path))
|
||||||
testcases_list = []
|
testcases_list = []
|
||||||
|
|
||||||
testcases_cache_mapping[path] = testcases_list
|
testcases_cache_mapping[path] = testcases_list
|
||||||
@@ -380,7 +380,7 @@ def merge_extractor(api_extrators, test_extracors):
|
|||||||
extractor_dict = OrderedDict()
|
extractor_dict = OrderedDict()
|
||||||
for api_extrator in api_extrators:
|
for api_extrator in api_extrators:
|
||||||
if len(api_extrator) != 1:
|
if len(api_extrator) != 1:
|
||||||
logging.warning("incorrect extractor: {}".format(api_extrator))
|
logger.log_warning("incorrect extractor: {}".format(api_extrator))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
var_name = list(api_extrator.keys())[0]
|
var_name = list(api_extrator.keys())[0]
|
||||||
@@ -388,7 +388,7 @@ def merge_extractor(api_extrators, test_extracors):
|
|||||||
|
|
||||||
for test_extrator in test_extracors:
|
for test_extrator in test_extracors:
|
||||||
if len(test_extrator) != 1:
|
if len(test_extrator) != 1:
|
||||||
logging.warning("incorrect extractor: {}".format(test_extrator))
|
logger.log_warning("incorrect extractor: {}".format(test_extrator))
|
||||||
continue
|
continue
|
||||||
|
|
||||||
var_name = list(test_extrator.keys())[0]
|
var_name = list(test_extrator.keys())[0]
|
||||||
@@ -601,13 +601,13 @@ def check_format(file_path, content):
|
|||||||
if not content:
|
if not content:
|
||||||
# testcase file content is empty
|
# testcase file content is empty
|
||||||
err_msg = u"Testcase file content is empty: {}".format(file_path)
|
err_msg = u"Testcase file content is empty: {}".format(file_path)
|
||||||
logging.error(err_msg)
|
logger.log_error(err_msg)
|
||||||
raise exception.FileFormatError(err_msg)
|
raise exception.FileFormatError(err_msg)
|
||||||
|
|
||||||
elif not isinstance(content, (list, dict)):
|
elif not isinstance(content, (list, dict)):
|
||||||
# testcase file content does not match testcase format
|
# testcase file content does not match testcase format
|
||||||
err_msg = u"Testcase file content format invalid: {}".format(file_path)
|
err_msg = u"Testcase file content format invalid: {}".format(file_path)
|
||||||
logging.error(err_msg)
|
logger.log_error(err_msg)
|
||||||
raise exception.FileFormatError(err_msg)
|
raise exception.FileFormatError(err_msg)
|
||||||
|
|
||||||
def gen_cartesian_product(*args):
|
def gen_cartesian_product(*args):
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ import hashlib
|
|||||||
import hmac
|
import hmac
|
||||||
import imp
|
import imp
|
||||||
import importlib
|
import importlib
|
||||||
import logging
|
|
||||||
import os.path
|
import os.path
|
||||||
import random
|
import random
|
||||||
import re
|
import re
|
||||||
@@ -10,9 +9,10 @@ import string
|
|||||||
import types
|
import types
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
|
|
||||||
from httprunner import exception
|
|
||||||
from requests.structures import CaseInsensitiveDict
|
from requests.structures import CaseInsensitiveDict
|
||||||
|
|
||||||
|
from . import exception, logger
|
||||||
|
|
||||||
try:
|
try:
|
||||||
string_type = basestring
|
string_type = basestring
|
||||||
long_type = long
|
long_type = long
|
||||||
@@ -351,23 +351,23 @@ def print_output(output):
|
|||||||
|
|
||||||
content += "============================================\n"
|
content += "============================================\n"
|
||||||
|
|
||||||
logging.debug(content)
|
logger.log_debug(content)
|
||||||
|
|
||||||
def create_scaffold(project_path):
|
def create_scaffold(project_path):
|
||||||
logging.info(" Start to create new project: {}".format(project_path))
|
|
||||||
|
|
||||||
if os.path.isdir(project_path):
|
if os.path.isdir(project_path):
|
||||||
folder_name = os.path.basename(project_path)
|
folder_name = os.path.basename(project_path)
|
||||||
logging.warning(u" Folder {} exists, please specify a new folder name.".format(folder_name))
|
logger.log_warning(u"Folder {} exists, please specify a new folder name.".format(folder_name))
|
||||||
return
|
return
|
||||||
|
|
||||||
|
logger.color_print("Start to create new project: {}\n".format(project_path), "GREEN")
|
||||||
|
|
||||||
def create_path(path, ptype):
|
def create_path(path, ptype):
|
||||||
if ptype == "folder":
|
if ptype == "folder":
|
||||||
os.makedirs(path)
|
os.makedirs(path)
|
||||||
elif ptype == "file":
|
elif ptype == "file":
|
||||||
open(path, 'w').close()
|
open(path, 'w').close()
|
||||||
|
|
||||||
logging.info("\tcreated {}: {}".format(ptype, path))
|
return "created {}: {}\n".format(ptype, path)
|
||||||
|
|
||||||
path_list = [
|
path_list = [
|
||||||
(project_path, "folder"),
|
(project_path, "folder"),
|
||||||
@@ -377,4 +377,9 @@ def create_scaffold(project_path):
|
|||||||
(os.path.join(project_path, "tests", "testcases"), "folder"),
|
(os.path.join(project_path, "tests", "testcases"), "folder"),
|
||||||
(os.path.join(project_path, "tests", "debugtalk.py"), "file")
|
(os.path.join(project_path, "tests", "debugtalk.py"), "file")
|
||||||
]
|
]
|
||||||
[create_path(p[0], p[1]) for p in path_list]
|
|
||||||
|
msg = ""
|
||||||
|
for p in path_list:
|
||||||
|
msg += create_path(p[0], p[1])
|
||||||
|
|
||||||
|
logger.color_print(msg, "BLUE")
|
||||||
|
|||||||
@@ -2,4 +2,6 @@ requests[security]
|
|||||||
flask
|
flask
|
||||||
PyYAML
|
PyYAML
|
||||||
PyUnitReport
|
PyUnitReport
|
||||||
har2case
|
har2case
|
||||||
|
colorama
|
||||||
|
colorlog
|
||||||
Reference in New Issue
Block a user