mirror of
https://github.com/httprunner/httprunner.git
synced 2026-05-12 11:29:48 +08:00
change: remove locust temporarily
This commit is contained in:
@@ -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)
|
||||
|
||||
|
||||
@@ -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
|
||||
```
|
||||
@@ -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()
|
||||
@@ -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]
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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",
|
||||
|
||||
@@ -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 = {}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user