From 22eb592eec7898a277e0a081d3a9488d91f336a6 Mon Sep 17 00:00:00 2001 From: debugtalk Date: Fri, 25 Oct 2019 16:40:47 +0800 Subject: [PATCH] feat: make locusts as httprunner plugin --- httprunner/api.py | 28 ----- httprunner/plugins/__init__.py | 0 httprunner/plugins/locusts/README.md | 100 ++++++++++++++++++ .../locusts/__init__.py} | 31 +++++- httprunner/plugins/locusts/__main__.py | 6 ++ .../locusts}/locustfile_template | 8 +- pyproject.toml | 2 +- tests/test_api.py | 18 +--- tests/test_plugins/__init__.py | 0 tests/test_plugins/test_locusts.py | 19 ++++ 10 files changed, 158 insertions(+), 54 deletions(-) create mode 100644 httprunner/plugins/__init__.py create mode 100644 httprunner/plugins/locusts/README.md rename httprunner/{locusts.py => plugins/locusts/__init__.py} (88%) create mode 100644 httprunner/plugins/locusts/__main__.py rename httprunner/{templates => plugins/locusts}/locustfile_template (94%) create mode 100644 tests/test_plugins/__init__.py create mode 100644 tests/test_plugins/test_locusts.py diff --git a/httprunner/api.py b/httprunner/api.py index cfcd9145..a8c6f140 100644 --- a/httprunner/api.py +++ b/httprunner/api.py @@ -283,31 +283,3 @@ class HttpRunner(object): """ get test reuslt summary. """ return self._summary - - -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_tests(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/plugins/__init__.py b/httprunner/plugins/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/httprunner/plugins/locusts/README.md b/httprunner/plugins/locusts/README.md new file mode 100644 index 00000000..514ea9bb --- /dev/null +++ b/httprunner/plugins/locusts/README.md @@ -0,0 +1,100 @@ +# locusts + +## Usage + +```shell script +$ locusts -f xxx.yml +``` + +```shell script +$ python3 -m plugins.locusts + +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 +``` + +## tests + +```shell script +$ python -m plugins.locusts.test_main +``` diff --git a/httprunner/locusts.py b/httprunner/plugins/locusts/__init__.py similarity index 88% rename from httprunner/locusts.py rename to httprunner/plugins/locusts/__init__.py index c079c504..d16c3673 100644 --- a/httprunner/locusts.py +++ b/httprunner/plugins/locusts/__init__.py @@ -15,7 +15,7 @@ import multiprocessing import os import sys -from httprunner import logger +from httprunner import logger, loader, parser def parse_locustfile(file_path): @@ -46,7 +46,6 @@ def gen_locustfile(testcase_file_path): locustfile_path = 'locustfile.py' template_path = os.path.join( os.path.dirname(os.path.realpath(__file__)), - "templates", "locustfile_template" ) @@ -168,5 +167,29 @@ def main(): start_locust_main() -if __name__ == '__main__': - main() +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_tests(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/plugins/locusts/__main__.py b/httprunner/plugins/locusts/__main__.py new file mode 100644 index 00000000..488e253d --- /dev/null +++ b/httprunner/plugins/locusts/__main__.py @@ -0,0 +1,6 @@ +import sys + +from httprunner.plugins.locusts import main + +if __name__ == "__main__": + main() diff --git a/httprunner/templates/locustfile_template b/httprunner/plugins/locusts/locustfile_template similarity index 94% rename from httprunner/templates/locustfile_template rename to httprunner/plugins/locusts/locustfile_template index 410a6fe5..b3389b62 100644 --- a/httprunner/templates/locustfile_template +++ b/httprunner/plugins/locusts/locustfile_template @@ -1,13 +1,13 @@ import logging import random -import zmq -from httprunner.exceptions import MyBaseError, MyBaseFailure -from httprunner.api import prepare_locust_tests -from httprunner.runner import Runner from locust import HttpLocust, TaskSet, task from locust.events import request_failure +from httprunner.exceptions import MyBaseError, MyBaseFailure +from httprunner.runner import Runner +from httprunner.plugins.locusts import prepare_locust_tests + logging.getLogger().setLevel(logging.CRITICAL) logging.getLogger('locust.main').setLevel(logging.INFO) logging.getLogger('locust.runners').setLevel(logging.INFO) diff --git a/pyproject.toml b/pyproject.toml index 0f4534ef..8280e744 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -42,7 +42,7 @@ contextlib2 = "^0.5.5" hrun = "httprunner.cli:main" ate = "httprunner.cli:main" httprunner = "httprunner.cli:main" -locusts = "httprunner.locusts:main" +locusts = "httprunner.plugins.locusts:main" [build-system] requires = ["poetry>=0.12"] diff --git a/tests/test_api.py b/tests/test_api.py index 9cf176f3..1f84a8b8 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -2,10 +2,9 @@ import os import re import shutil import time -import unittest from httprunner import exceptions, loader, parser -from httprunner.api import HttpRunner, prepare_locust_tests +from httprunner.api import HttpRunner from tests.api_server import HTTPBIN_SERVER from tests.base import ApiServerUnittest @@ -788,18 +787,3 @@ class TestApi(ApiServerUnittest): results.records[1]["name"], "create user and check result." ) - - -class TestLocust(unittest.TestCase): - - def test_prepare_locust_tests(self): - path = os.path.join( - os.getcwd(), 'tests/locust_tests/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/tests/test_plugins/__init__.py b/tests/test_plugins/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/tests/test_plugins/test_locusts.py b/tests/test_plugins/test_locusts.py new file mode 100644 index 00000000..10bc736a --- /dev/null +++ b/tests/test_plugins/test_locusts.py @@ -0,0 +1,19 @@ +import os +import unittest + +from httprunner.plugins.locusts import prepare_locust_tests + + +class TestLocust(unittest.TestCase): + + def test_prepare_locust_tests(self): + path = os.path.join( + os.getcwd(), 'tests/locust_tests/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)