From 0e5ca838fb06f2208c1394aa31bc6a04383a96c0 Mon Sep 17 00:00:00 2001 From: debugtalk Date: Fri, 15 May 2020 22:48:59 +0800 Subject: [PATCH] change: remove locust temporarily --- httprunner/cli.py | 29 +---- httprunner/ext/locusts/README.md | 104 ------------------ httprunner/ext/locusts/__init__.py | 94 ---------------- httprunner/ext/locusts/core.py | 100 ----------------- httprunner/ext/locusts/data/demo_locusts.yml | 20 ---- httprunner/ext/locusts/locustfile_template.py | 43 -------- httprunner/ext/locusts/utils.py | 29 ----- httprunner/ext/locusts/utils_test.py | 17 --- httprunner/ext/make/make_test.py | 2 +- httprunner/response.py | 8 +- httprunner/runner.py | 2 +- 11 files changed, 13 insertions(+), 435 deletions(-) delete mode 100644 httprunner/ext/locusts/README.md delete mode 100644 httprunner/ext/locusts/__init__.py delete mode 100644 httprunner/ext/locusts/core.py delete mode 100644 httprunner/ext/locusts/data/demo_locusts.yml delete mode 100644 httprunner/ext/locusts/locustfile_template.py delete mode 100644 httprunner/ext/locusts/utils.py delete mode 100644 httprunner/ext/locusts/utils_test.py diff --git a/httprunner/cli.py b/httprunner/cli.py index abc2415c..f577e77a 100644 --- a/httprunner/cli.py +++ b/httprunner/cli.py @@ -2,29 +2,12 @@ import argparse import os import sys -if len(sys.argv) >= 2 and sys.argv[1] == "locusts": - # monkey patch ssl at beginning to avoid RecursionError when running locust. - try: - from gevent import monkey - - monkey.patch_ssl() - from locust.main import main as _ - except ImportError: - msg = """ -Locust is not installed, install first and try again. -install with pip: -$ pip install locustio -""" - print(msg) - sys.exit(1) - import pytest from httprunner import __description__, __version__, exceptions from httprunner.ext.har2case import init_har2case_parser, main_har2case -from httprunner.ext.scaffold import init_parser_scaffold, main_scaffold -from httprunner.ext.locusts import init_parser_locusts, main_locusts from httprunner.ext.make import init_make_parser, main_make, convert_testcase_path +from httprunner.ext.scaffold import init_parser_scaffold, main_scaffold def init_parser_run(subparsers): @@ -69,7 +52,6 @@ def main(): sub_parser_run = init_parser_run(subparsers) sub_parser_scaffold = init_parser_scaffold(subparsers) sub_parser_har2case = init_har2case_parser(subparsers) - sub_parser_locusts = init_parser_locusts(subparsers) sub_parser_make = init_make_parser(subparsers) if len(sys.argv) == 1: @@ -90,9 +72,6 @@ def main(): elif sys.argv[1] == "har2case": # httprunner har2case sub_parser_har2case.print_help() - elif sys.argv[1] == "locusts": - # httprunner locusts - sub_parser_locusts.print_help() elif sys.argv[1] == "run": # httprunner run pytest.main(["-h"]) @@ -100,7 +79,9 @@ def main(): # httprunner make sub_parser_make.print_help() sys.exit(0) - elif len(sys.argv) == 3 and sys.argv[1] == "run" and sys.argv[2] in ["-h", "--help"]: + elif ( + len(sys.argv) == 3 and sys.argv[1] == "run" and sys.argv[2] in ["-h", "--help"] + ): # httprunner run -h pytest.main(["-h"]) sys.exit(0) @@ -121,8 +102,6 @@ def main(): main_scaffold(args) elif sys.argv[1] == "har2case": main_har2case(args) - elif sys.argv[1] == "locusts": - main_locusts(args, extra_args) elif sys.argv[1] == "make": main_make(args.testcase_path) diff --git a/httprunner/ext/locusts/README.md b/httprunner/ext/locusts/README.md deleted file mode 100644 index 6b52620e..00000000 --- a/httprunner/ext/locusts/README.md +++ /dev/null @@ -1,104 +0,0 @@ -# locusts - -## Installation - -```shell script -$ pip install locustio -``` - -## Usage - -```shell script -$ locusts -f xxx.yml -``` - -```shell script -$ locusts -f xxx.yml --processes -``` - -```shell script -$ python3 -m httprunner.ext.locusts -h - -Usage: locust [options] [LocustClass [LocustClass2 ... ]] - -Options: - -h, --help show this help message and exit - -H HOST, --host=HOST Host to load test in the following format: - http://10.21.32.33 - --web-host=WEB_HOST Host to bind the web interface to. Defaults to '' (all - interfaces) - -P PORT, --port=PORT, --web-port=PORT - Port on which to run web host - -f LOCUSTFILE, --locustfile=LOCUSTFILE - Python module file to import, e.g. '../other.py'. - Default: locustfile - --csv=CSVFILEBASE, --csv-base-name=CSVFILEBASE - Store current request stats to files in CSV format. - --master Set locust to run in distributed mode with this - process as master - --slave Set locust to run in distributed mode with this - process as slave - --master-host=MASTER_HOST - Host or IP address of locust master for distributed - load testing. Only used when running with --slave. - Defaults to 127.0.0.1. - --master-port=MASTER_PORT - The port to connect to that is used by the locust - master for distributed load testing. Only used when - running with --slave. Defaults to 5557. Note that - slaves will also connect to the master node on this - port + 1. - --master-bind-host=MASTER_BIND_HOST - Interfaces (hostname, ip) that locust master should - bind to. Only used when running with --master. - Defaults to * (all available interfaces). - --master-bind-port=MASTER_BIND_PORT - Port that locust master should bind to. Only used when - running with --master. Defaults to 5557. Note that - Locust will also use this port + 1, so by default the - master node will bind to 5557 and 5558. - --heartbeat-liveness=HEARTBEAT_LIVENESS - set number of seconds before failed heartbeat from - slave - --heartbeat-interval=HEARTBEAT_INTERVAL - set number of seconds delay between slave heartbeats - to master - --expect-slaves=EXPECT_SLAVES - How many slaves master should expect to connect before - starting the test (only when --no-web used). - --no-web Disable the web interface, and instead start running - the test immediately. Requires -c and -r to be - specified. - -c NUM_CLIENTS, --clients=NUM_CLIENTS - Number of concurrent Locust users. Only used together - with --no-web - -r HATCH_RATE, --hatch-rate=HATCH_RATE - The rate per second in which clients are spawned. Only - used together with --no-web - -t RUN_TIME, --run-time=RUN_TIME - Stop after the specified amount of time, e.g. (300s, - 20m, 3h, 1h30m, etc.). Only used together with --no- - web - -L LOGLEVEL, --loglevel=LOGLEVEL - Choose between DEBUG/INFO/WARNING/ERROR/CRITICAL. - Default is INFO. - --logfile=LOGFILE Path to log file. If not set, log will go to - stdout/stderr - --print-stats Print stats in the console - --only-summary Only print the summary stats - --no-reset-stats [DEPRECATED] Do not reset statistics once hatching has - been completed. This is now the default behavior. See - --reset-stats to disable - --reset-stats Reset statistics once hatching has been completed. - Should be set on both master and slaves when running - in distributed mode - -l, --list Show list of possible locust classes and exit - --show-task-ratio print table of the locust classes' task execution - ratio - --show-task-ratio-json - print json data of the locust classes' task execution - ratio - -V, --version show program's version number and exit - --exit-code-on-error=EXIT_CODE_ON_ERROR - sets the exit code to post on error -``` diff --git a/httprunner/ext/locusts/__init__.py b/httprunner/ext/locusts/__init__.py deleted file mode 100644 index 1389dced..00000000 --- a/httprunner/ext/locusts/__init__.py +++ /dev/null @@ -1,94 +0,0 @@ -import multiprocessing -import sys - -from loguru import logger - -from httprunner import __version__ -from httprunner.ext.locusts.core import ( - start_locust_main, - parse_locustfile, - quick_run_locusts, - start_master, - start_slaves, -) - -CPU_COUNT = multiprocessing.cpu_count() - - -def init_parser_locusts(subparsers): - sub_parser_locusts = subparsers.add_parser( - "locusts", help="Run load test with locust." - ) - sub_parser_locusts.add_argument( - "--locust-help", action="store_true", default=False, help="Show locust help." - ) - sub_parser_locusts.add_argument( - "test_file", nargs="?", help="Specify YAML/JSON testcase file." - ) - sub_parser_locusts.add_argument( - "--master", action="store_true", default=False, help="Start locust master." - ) - sub_parser_locusts.add_argument( - "--slaves", type=int, help="Specify locust slave number." - ) - sub_parser_locusts.add_argument( - "--quickstart", - action="store_true", - default=False, - help=f"Start locust master with {CPU_COUNT} slaves.", - ) - return sub_parser_locusts - - -def main_locusts(args, extra_args): - """ Performance test with locust: parse command line options and run commands. - """ - logger.info(f"HttpRunner version: {__version__}") - sys.argv = ["locust", *extra_args] - - if args.locust_help: - sys.argv = ["locust", "-h"] - start_locust_main() - - def get_arg_index(*target_args): - for arg in target_args: - if arg not in sys.argv: - continue - - return sys.argv.index(arg) + 1 - - return None - - # set logging level - loglevel_index = get_arg_index("-L", "--loglevel") - if loglevel_index and loglevel_index < len(sys.argv): - loglevel = sys.argv[loglevel_index] - loglevel = loglevel.upper() - else: - # default - loglevel = "INFO" - - logger.remove() - logger.add(sys.stdout, level=loglevel) - - if not args.test_file: - logger.error("Testcase file is not specified, exit.") - sys.exit(1) - - # convert httprunner yaml/json case to locustfile.py - locustfile_path = parse_locustfile(args.test_file) - sys.argv.extend(["-f", locustfile_path]) - - manager = multiprocessing.Manager() - try: - if args.quickstart: - quick_run_locusts(CPU_COUNT) - elif args.master: - start_master(sys.argv) - elif args.slaves: - start_slaves(args.slaves) - else: - quick_run_locusts(CPU_COUNT) - - except KeyboardInterrupt: - manager.shutdown() diff --git a/httprunner/ext/locusts/core.py b/httprunner/ext/locusts/core.py deleted file mode 100644 index bef1ddf4..00000000 --- a/httprunner/ext/locusts/core.py +++ /dev/null @@ -1,100 +0,0 @@ -import io -import multiprocessing -import os -import sys - -from loguru import logger - - -def parse_locustfile(file_path): - """ parse testcase file and return locustfile path. - if file_path is a Python file, assume it is a locustfile - if file_path is a YAML/JSON file, convert it to locustfile - """ - if not os.path.isfile(file_path): - logger.error("file path invalid, exit.") - sys.exit(1) - - file_suffix = os.path.splitext(file_path)[1] - if file_suffix == ".py": - locustfile_path = file_path - elif file_suffix in [".yaml", ".yml", ".json"]: - locustfile_path = gen_locustfile(file_path) - else: - # '' or other suffix - logger.error("file type should be YAML/JSON/Python, exit.") - sys.exit(1) - - return locustfile_path - - -def gen_locustfile(testcase_file_path): - """ generate locustfile from template. - """ - locustfile_path = "locustfile.py" - template_path = os.path.join( - os.path.dirname(os.path.realpath(__file__)), "locustfile_template.py" - ) - - with io.open(template_path, encoding="utf-8") as template: - with io.open(locustfile_path, "w", encoding="utf-8") as locustfile: - template_content = template.read() - template_content = template_content.replace( - "$TESTCASE_FILE", testcase_file_path - ) - locustfile.write(template_content) - - return locustfile_path - - -def start_locust_main(): - logger.info(f"run command: {sys.argv}") - from locust.main import main - - main() - - -def start_master(sys_argv): - sys_argv.append("--master") - sys.argv = sys_argv - start_locust_main() - - -def start_slave(sys_argv): - if "--slave" not in sys_argv: - sys_argv.extend(["--slave"]) - - sys.argv = sys_argv - start_locust_main() - - -def init_slave_processes(slave_num): - """ init specified number of locust slave processes.""" - processes = [] - - for _ in range(slave_num): - p_slave = multiprocessing.Process(target=start_slave, args=(sys.argv,)) - p_slave.daemon = True - p_slave.start() - processes.append(p_slave) - - return processes - - -def start_slaves(slave_num): - logger.info(f"Start {slave_num} locust slaves ...") - processes = init_slave_processes(slave_num) - [process.join() for process in processes] - - -def quick_run_locusts(slave_num): - """ quick start locust master and multiple slaves. - - Args: - slave_num: locust slaves number - """ - logger.info(f"Start locust master with {slave_num} slaves ...") - - processes = init_slave_processes(slave_num) - processes.append(multiprocessing.Process(target=start_master, args=(sys.argv,))) - [process.join() for process in processes] diff --git a/httprunner/ext/locusts/data/demo_locusts.yml b/httprunner/ext/locusts/data/demo_locusts.yml deleted file mode 100644 index 2ec2d342..00000000 --- a/httprunner/ext/locusts/data/demo_locusts.yml +++ /dev/null @@ -1,20 +0,0 @@ -config: - name: create users with uid - variables: - device_sn: ${gen_random_string(15)} - base_url: "http://127.0.0.1:5000" - -testcases: -- - name: create user 1000 and check result. - testcase: testcases/create_user.yml - weight: 2 - variables: - uid: 1000 - -- - name: create user 1001 and check result. - testcase: testcases/create_user.yml - weight: 3 - variables: - uid: 1001 diff --git a/httprunner/ext/locusts/locustfile_template.py b/httprunner/ext/locusts/locustfile_template.py deleted file mode 100644 index 84a1c327..00000000 --- a/httprunner/ext/locusts/locustfile_template.py +++ /dev/null @@ -1,43 +0,0 @@ -import logging -import random - -from locust import HttpLocust, TaskSet, task -from locust.events import request_failure - -from httprunner.exceptions import MyBaseError, MyBaseFailure -from httprunner.ext.locusts.utils import prepare_locust_tests -from httprunner.runner import Runner - -logging.getLogger().setLevel(logging.CRITICAL) -logging.getLogger("locust.main").setLevel(logging.INFO) -logging.getLogger("locust.runners").setLevel(logging.INFO) - - -class WebPageTasks(TaskSet): - def on_start(self): - config = {} - self.test_runner = Runner(config, self.client) - - @task - def test_any(self): - test_dict = random.choice(self.locust.tests) - try: - self.test_runner.run_test(test_dict) - except (AssertionError, MyBaseError, MyBaseFailure) as ex: - request_failure.fire( - request_type=self.test_runner.exception_request_type, - name=self.test_runner.exception_name, - response_time=0, - exception=ex, - ) - - -class WebPageUser(HttpLocust): - host = "" - task_set = WebPageTasks - min_wait = 10 - max_wait = 30 - - # file_path is generated on locusts startup - file_path = "$TESTCASE_FILE" - tests = prepare_locust_tests(file_path) diff --git a/httprunner/ext/locusts/utils.py b/httprunner/ext/locusts/utils.py deleted file mode 100644 index e1d5d881..00000000 --- a/httprunner/ext/locusts/utils.py +++ /dev/null @@ -1,29 +0,0 @@ -from httprunner import loader, parser - - -def prepare_locust_tests(path): - """ prepare locust testcases - - Args: - path (str): testcase file path. - - Returns: - list: locust tests data - - [ - testcase1_dict, - testcase2_dict - ] - - """ - tests_mapping = loader.load_cases(path) - testcases = parser.parse_tests(tests_mapping) - - locust_tests = [] - - for testcase in testcases: - testcase_weight = testcase.get("config", {}).pop("weight", 1) - for _ in range(testcase_weight): - locust_tests.append(testcase) - - return locust_tests diff --git a/httprunner/ext/locusts/utils_test.py b/httprunner/ext/locusts/utils_test.py deleted file mode 100644 index e536386c..00000000 --- a/httprunner/ext/locusts/utils_test.py +++ /dev/null @@ -1,17 +0,0 @@ -import os -import unittest - -from httprunner.ext.locusts.utils import prepare_locust_tests - - -class TestLocust(unittest.TestCase): - def test_prepare_locust_tests(self): - path = os.path.join(os.path.dirname(__file__), "data", "demo_locusts.yml") - locust_tests = prepare_locust_tests(path) - self.assertEqual(len(locust_tests), 2 + 3) - name_list = [ - "create user 1000 and check result.", - "create user 1001 and check result.", - ] - self.assertIn(locust_tests[0]["config"]["name"], name_list) - self.assertIn(locust_tests[4]["config"]["name"], name_list) diff --git a/httprunner/ext/make/make_test.py b/httprunner/ext/make/make_test.py index eaba229c..14458bf0 100644 --- a/httprunner/ext/make/make_test.py +++ b/httprunner/ext/make/make_test.py @@ -12,7 +12,7 @@ class TestLoader(unittest.TestCase): ) def test_make_testcase_folder(self): - path = "examples/postman_echo/request_methods/" + path = ["examples/postman_echo/request_methods/"] testcase_python_list = main_make(path) self.assertIn( "examples/postman_echo/request_methods/request_with_functions_test.py", diff --git a/httprunner/response.py b/httprunner/response.py index b7a0fab0..b268d4b5 100644 --- a/httprunner/response.py +++ b/httprunner/response.py @@ -115,10 +115,16 @@ class ResponseObject(object): """ self.resp_obj = resp_obj + + try: + body = resp_obj.json() + except ValueError: + body = resp_obj.content + self.resp_obj_meta = { "status_code": resp_obj.status_code, "headers": resp_obj.headers, - "body": resp_obj.json(), + "body": body, } self.validation_results: Dict = {} diff --git a/httprunner/runner.py b/httprunner/runner.py index 3c540836..62db1cde 100644 --- a/httprunner/runner.py +++ b/httprunner/runner.py @@ -169,7 +169,7 @@ class HttpRunner(object): if self.config.path: self.project_meta = load_project_meta(self.config.path) - else: + elif not self.project_meta: self.project_meta = ProjectMeta() self.start_at = time.time()