From 2d5ff04b46d02667de039705b1bc250aca9dc19e Mon Sep 17 00:00:00 2001 From: debugtalk Date: Mon, 29 Oct 2018 20:49:24 +0800 Subject: [PATCH] locusts support weight feature --- httprunner/__about__.py | 2 +- httprunner/__init__.py | 2 +- httprunner/api.py | 19 ---------- httprunner/context.py | 9 ++++- httprunner/loader.py | 47 ++++++++++++++++++++++++ httprunner/locusts.py | 3 -- httprunner/templates/locustfile_template | 44 ++++++++++++++++------ tests/data/demo_locust.yml | 34 +++++++++++++++++ tests/test_api.py | 14 +------ tests/test_loader.py | 9 +++++ 10 files changed, 133 insertions(+), 50 deletions(-) create mode 100644 tests/data/demo_locust.yml diff --git a/httprunner/__about__.py b/httprunner/__about__.py index 82a265d0..211c90c2 100644 --- a/httprunner/__about__.py +++ b/httprunner/__about__.py @@ -1,7 +1,7 @@ __title__ = 'HttpRunner' __description__ = 'One-stop solution for HTTP(S) testing.' __url__ = 'https://github.com/HttpRunner/HttpRunner' -__version__ = '1.5.14' +__version__ = '1.5.15' __author__ = 'debugtalk' __author_email__ = 'mail@debugtalk.com' __license__ = 'MIT' diff --git a/httprunner/__init__.py b/httprunner/__init__.py index 48724cf5..6942cf6c 100644 --- a/httprunner/__init__.py +++ b/httprunner/__init__.py @@ -6,4 +6,4 @@ try: except ImportError: pass -from httprunner.api import HttpRunner, LocustRunner +from httprunner.api import HttpRunner diff --git a/httprunner/api.py b/httprunner/api.py index feb791a1..e5e5e97d 100644 --- a/httprunner/api.py +++ b/httprunner/api.py @@ -255,22 +255,3 @@ class HttpRunner(object): html_report_name, html_report_template ) - - -class LocustRunner(object): - - def __init__(self, locust_client): - self.runner = HttpRunner(http_client_session=locust_client) - - def run(self, path): - try: - self.runner.run(path) - except exceptions.MyBaseError as ex: - # TODO: refactor - from locust.events import request_failure - request_failure.fire( - request_type=test.testcase_dict.get("request", {}).get("method"), - name=test.testcase_dict.get("request", {}).get("url"), - response_time=0, - exception=ex - ) diff --git a/httprunner/context.py b/httprunner/context.py index 98e7ebce..7484a503 100644 --- a/httprunner/context.py +++ b/httprunner/context.py @@ -14,8 +14,13 @@ class Context(object): """ init Context with testcase variables and functions. """ # testcase level context - ## TESTCASE_SHARED_VARIABLES_MAPPING and TESTCASE_SHARED_FUNCTIONS_MAPPING will not change. - self.TESTCASE_SHARED_VARIABLES_MAPPING = variables or OrderedDict() + ## TESTCASE_SHARED_VARIABLES_MAPPING and TESTCASE_SHARED_FUNCTIONS_MAPPING are unchangeable. + if isinstance(variables, list): + self.TESTCASE_SHARED_VARIABLES_MAPPING = utils.convert_mappinglist_to_orderdict(variables) + else: + # dict + self.TESTCASE_SHARED_VARIABLES_MAPPING = variables or OrderedDict() + self.TESTCASE_SHARED_FUNCTIONS_MAPPING = functions or OrderedDict() # testcase level request, will not change diff --git a/httprunner/loader.py b/httprunner/loader.py index fc0fbd33..d8294c40 100644 --- a/httprunner/loader.py +++ b/httprunner/loader.py @@ -987,3 +987,50 @@ def load_tests(path, dot_env_path=None): testcases_list = [] return testcases_list + + +def load_locust_tests(path, dot_env_path=None): + """ load locust testcases + + Args: + path (str): testcase/testsuite file path. + dot_env_path (str): specified .env file path + + Returns: + dict: locust testcases with weight + { + "config": {...}, + "tests": [ + # weight 3 + [teststep11], + [teststep11], + [teststep11], + # weight 2 + [teststep21, teststep22], + [teststep21, teststep22] + ] + } + + """ + raw_testcase = load_file(path) + project_mapping = load_project_tests(path, dot_env_path) + + config = { + "refs": project_mapping + } + tests = [] + for item in raw_testcase: + key, test_block = item.popitem() + + if key == "config": + config.update(test_block) + elif key == "test": + teststeps = _load_teststeps(test_block, project_mapping) + weight = test_block.pop("weight", 1) + for _ in range(weight): + tests.append(teststeps) + + return { + "config": config, + "tests": tests + } diff --git a/httprunner/locusts.py b/httprunner/locusts.py index b1532229..3411bfd5 100644 --- a/httprunner/locusts.py +++ b/httprunner/locusts.py @@ -40,13 +40,10 @@ def gen_locustfile(testcase_file_path): "templates", "locustfile_template" ) - testcases = loader.load_tests(testcase_file_path) - host = testcases[0].get("config", {}).get("request", {}).get("base_url", "") 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("$HOST", host) template_content = template_content.replace("$TESTCASE_FILE", testcase_file_path) locustfile.write(template_content) diff --git a/httprunner/templates/locustfile_template b/httprunner/templates/locustfile_template index 9b7c1924..84381083 100644 --- a/httprunner/templates/locustfile_template +++ b/httprunner/templates/locustfile_template @@ -1,24 +1,46 @@ -#coding: utf-8 +import logging +import random + import zmq +from httprunner.exceptions import MyBaseError, MyBaseFailure +from httprunner.loader import load_locust_tests +from httprunner.runner import Runner from locust import HttpLocust, TaskSet, task -from httprunner import LocustRunner -from httprunner.loader import load_tests +from locust.events import request_failure + +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): - self.test_runner = LocustRunner(self.client) - self.testcases = loader.load_tests(self.locust.file_path) + self.test_runner = Runner(self.locust.config, self.client) + self.testcases = load_locust_tests(self.locust.file_path) - @task - def test_specified_scenario(self): - self.test_runner.run(self.testcases) + @task(weight=1) + def test_any(self): + teststeps = random.choice(self.locust.tests) + for teststep in teststeps: + try: + self.test_runner.run_test(teststep) + except (MyBaseError, MyBaseFailure) as ex: + request_failure.fire( + request_type=teststep.get("request", {}).get("method"), + name=teststep.get("name"), + response_time=0, + exception=ex + ) class WebPageUser(HttpLocust): - host = "$HOST" task_set = WebPageTasks - min_wait = 1000 - max_wait = 5000 + min_wait = 10 + max_wait = 30 file_path = "$TESTCASE_FILE" + locust_tests = load_locust_tests(file_path) + config = locust_tests["config"] + tests = locust_tests["tests"] + + host = config.get('request', {}).get('base_url', '') diff --git a/tests/data/demo_locust.yml b/tests/data/demo_locust.yml new file mode 100644 index 00000000..8965689c --- /dev/null +++ b/tests/data/demo_locust.yml @@ -0,0 +1,34 @@ +- config: + name: basic test with httpbin + request: + base_url: https://httpbin.org/ + +- test: + name: index + weight: 5 + request: + url: / + method: GET + validate: + - eq: ["status_code", 200] + - contains: [content, "HTTP Request & Response Service"] + +- test: + name: headers + weight: 3 + request: + url: /headers + method: GET + validate: + - eq: ["status_code", 200] + - eq: [content.headers.Host, "httpbin.org"] + +- test: + name: user-agent + weight: 2 + request: + url: /user-agent + method: GET + validate: + - eq: ["status_code", 200] + - startswith: [content.user-agent, "python-requests"] diff --git a/tests/test_api.py b/tests/test_api.py index bd869938..7bf769a6 100644 --- a/tests/test_api.py +++ b/tests/test_api.py @@ -2,7 +2,7 @@ import os import shutil import time -from httprunner import HttpRunner, LocustRunner, api, loader, parser +from httprunner import HttpRunner, api, loader, parser from locust import HttpLocust from tests.api_server import HTTPBIN_SERVER from tests.base import ApiServerUnittest @@ -375,15 +375,3 @@ class TestHttpRunner(ApiServerUnittest): os.getcwd(), 'tests/httpbin/basic.yml') runner = HttpRunner().run(testcase_file_path) self.assertTrue(runner.summary["success"]) - - -class TestLocustRunner(ApiServerUnittest): - - def setUp(self): - WebPageUser = type('WebPageUser', (HttpLocust,), {}) - self.locust_client = WebPageUser.client - - def test_LocustRunner(self): - testcase_file = os.path.join(os.getcwd(), 'tests', 'httpbin', 'basic.yml') - locust_runner = LocustRunner(self.locust_client) - locust_runner.run(testcase_file) diff --git a/tests/test_loader.py b/tests/test_loader.py index 096b8511..5d0a2f08 100644 --- a/tests/test_loader.py +++ b/tests/test_loader.py @@ -553,3 +553,12 @@ class TestSuiteLoader(unittest.TestCase): self.assertIn("get_token", project_mapping["def-api"]) self.assertIn("setup_and_reset", project_mapping["def-testcase"]) self.assertEqual(project_mapping["env"]["PROJECT_KEY"], "ABCDEFGH") + + def test_load_locust_tests(self): + path = os.path.join( + os.getcwd(), 'tests/data/demo_locust.yml') + locust_tests = loader.load_locust_tests(path) + self.assertEqual(locust_tests["config"]["refs"]["env"]["UserName"], "debugtalk") + self.assertEqual(len(locust_tests["tests"]), 10) + self.assertEqual(locust_tests["tests"][0][0]["name"], "index") + self.assertEqual(locust_tests["tests"][9][0]["name"], "user-agent")