Example #1
0
 def test_return_docstring_and_user_classes(self):
     with mock_locustfile() as mocked:
         docstring, user_classes, shape_class = main.load_locustfile(mocked.file_path)
         self.assertEqual("This is a mock locust file for unit testing", docstring)
         self.assertIn("UserSubclass", user_classes)
         self.assertNotIn("NotUserSubclass", user_classes)
         self.assertNotIn("LoadTestShape", user_classes)
Example #2
0
 def test_load_locust_file_from_absolute_path(self):
     with mock_locustfile() as mocked:
         docstring, user_classes, shape_class = main.load_locustfile(
             mocked.file_path)
         self.assertIn('UserSubclass', user_classes)
         self.assertNotIn('NotUserSubclass', user_classes)
         self.assertNotIn('LoadTestShape', user_classes)
Example #3
0
 def test_return_docstring_and_locusts(self):
     with mock_locustfile() as mocked:
         docstring, locusts = main.load_locustfile(mocked.file_path)
         self.assertEqual("This is a mock locust file for unit testing",
                          docstring)
         self.assertIn('LocustSubclass', locusts)
         self.assertNotIn('NotLocustSubclass', locusts)
Example #4
0
 def test_with_shape_class(self):
     content = MOCK_LOUCSTFILE_CONTENT + '''class LoadTestShape(LoadTestShape):
 pass
     '''
     with mock_locustfile(content=content) as mocked:
         docstring, user_classes, shape_class = main.load_locustfile(
             mocked.file_path)
         self.assertEqual("This is a mock locust file for unit testing",
                          docstring)
         self.assertIn('UserSubclass', user_classes)
         self.assertNotIn('NotUserSubclass', user_classes)
         self.assertEqual(shape_class.__class__.__name__, 'LoadTestShape')
Example #5
0
 def test_with_shape_class(self):
     content = (
         MOCK_LOCUSTFILE_CONTENT
         + """class LoadTestShape(LoadTestShape):
 pass
     """
     )
     with mock_locustfile(content=content) as mocked:
         docstring, user_classes, shape_class = main.load_locustfile(mocked.file_path)
         self.assertEqual("This is a mock locust file for unit testing", docstring)
         self.assertIn("UserSubclass", user_classes)
         self.assertNotIn("NotUserSubclass", user_classes)
         self.assertEqual(shape_class.__class__.__name__, "LoadTestShape")
Example #6
0
def _run(master=False):
    if not os.path.exists('locust_file_by_web.py'):
        if generate() != 'success':
            return 'Fail to generate locust-file!'
    docstring, locusts = load_locustfile('locust_file_by_web.py')
    if not locusts:
        return 'No Locust class found in locust_file_by_web.py!'
    locust_classes = list(locusts.values())
    p = Process(target=_run_locust, args=(
        locust_classes,
        master,
    ))
    p.start()
    return 'success'
Example #7
0
    def prepare_test(self):
        logger = logging.getLogger(__name__)


        try:
            logger.debug("######## DEBUG: looking for a console object")
            ### DEBUG: enable/disable Console
            console = self.core.get_plugin_of_type(ConsolePlugin)
        except Exception as ex:
            logger.debug("######## DEBUG: Console not found: %s", ex)
            console = None

        if console:
            logger.debug("######## DEBUG: console found")
            widget = LocustInfoWidget(self)
            console.add_info_widget(widget)
            logger.debug("######## DEBUG: locust widget added to console")


        try:

            locustfile = lm.find_locustfile(self.locustfile)
            if not locustfile:
                logger.error("##### Locust plugin: Could not find any locustfile! Ensure file ends in '.py' and see --help for available options.")
                sys.exit(1)

            if locustfile == "locust.py":
                logger.error("##### Locust plugin: The locustfile must not be named `locust.py`. Please rename the file and try again.")
                sys.exit(1)

            docstring, locusts = lm.load_locustfile(locustfile)

            logger.info("##### Locust plugin: locustfile = {}".format(locustfile))

            if not locusts:
                logger.error("##### Locust plugin: No Locust class found!")
                sys.exit(1)
            else:
                logger.info("##### Locust plugin: Locust classes found in {} : {}".format(locustfile, locusts))

            self._locustclasses = list(locusts.values())
            options = Opts(**self.get_options())
            self._options = options
            logger.debug("##### Locust plugin: main() : options = {}".format(options))


        except Exception as e:
            logger.error("##### Locust plugin: prepare_test() CRITICAL ERROR : %s", e)
            sys.exit(1)
Example #8
0
def add_router():
    if request.method == "POST":
        name = request.form.get("name")
        if not name:
            name = uuid.uuid4()
        url = request.form.get("url")
        if not url:
            return "url 必填"
        data = request.form.get("data")
        if not data:
            data = {}
        path = os.path.join(PATH_BASE, "locustfile.py")
        with open(path, "a+", encoding="utf8") as f:
            f.write(
                f"    @task\n    def {name}(self):\n        self.client.get('{url}', data={data})\n"
            )
        docstring, locusts = load_locustfile(path)
        locust_classes = list(locusts.values())
        runners.locust_runner = runners.LocalLocustRunner(locust_classes, None)
        return redirect("/")
    return render_template("add_router.html")
Example #9
0
 def test_load_locust_file_with_a_dot_in_filename(self):
     self.__create_mock_locust_file("mock_locust_file.py")
     docstring, locusts = main.load_locustfile(self.file_path)
Example #10
0
 def test_load_locust_file_from_relative_path(self):
     with mock_locustfile() as mocked:
         docstring, user_classes, shape_class = main.load_locustfile(
             os.path.join(os.path.relpath(mocked.directory, os.getcwd()), mocked.filename)
         )
Example #11
0
def create_settings(from_environment=False, locustfile=None,
        classes=None, host=None, num_clients=None,
        hatch_rate=None, reset_stats=False, run_time="3m"):
    '''
    Returns a settings object to be used by a LocalLocustRunner.

    Arguments

        from_environment: get settings from environment variables
        locustfile: locustfile to use for loadtest
        classes: locust classes to use for load test
        host: host for load testing
        num_clients: number of clients to simulate in load test
        hatch_rate: number of clients per second to start
        reset_stats: Whether to reset stats after all clients are hatched
        run_time: The length of time to run the test for. Cannot exceed the duration limit set by lambda

    If from_environment is set to True then this function will attempt to set
    the attributes from environment variables. The environment variables are
    named LOCUST_ + attribute name in upper case.
    '''

    settings = type('', (), {})()

    settings.from_environment = from_environment
    settings.locustfile = locustfile
    settings.classes = classes
    settings.host = host
    settings.num_clients = num_clients
    settings.hatch_rate = hatch_rate
    settings.reset_stats = reset_stats
    settings.run_time = run_time

    # Default settings that are not to be changed
    settings.no_web = True
    settings.master = False
    settings.show_task_ratio_json = False
    settings.list_commands = False
    settings.loglevel = 'INFO'
    settings.slave = False
    settings.only_summary = True
    settings.logfile = None
    settings.show_task_ratio = False
    settings.print_stats = False
    settings.step_load = False
    settings.stop_timeout = None

    if from_environment:
        for attribute in ['locustfile', 'classes', 'host', 'run_time', 'num_clients', 'hatch_rate']:
            var_name = 'LOCUST_{0}'.format(attribute.upper())
            var_value = os.environ.get(var_name)
            if var_value:
                setattr(settings, attribute, var_value)

    if settings.locustfile is None and settings.classes is None:
        raise Exception('One of locustfile or classes must be specified')

    if settings.locustfile and settings.classes:
        raise Exception('Only one of locustfile or classes can be specified')

    if settings.locustfile:
        docstring, classes = load_locustfile(settings.locustfile)
        settings.classes = [classes[n] for n in classes]
    else:
        if isinstance(settings.classes, str):
            settings.classes = settings.classes.split(',')
            for idx, val in enumerate(settings.classes):
                # This needs fixing
                settings.classes[idx] = eval(val)

    for attribute in ['classes', 'host', 'num_clients', 'hatch_rate']:
        val = getattr(settings, attribute, None)
        if not val:
            raise Exception('configuration error, attribute not set: {0}'.format(attribute))

        if isinstance(val, str) and val.isdigit():
            setattr(settings, attribute, int(val))
    
    return settings
Example #12
0
 def test_load_locust_file_from_relative_path(self):
     self.__create_mock_locust_file('mock_locust_file.py')
     docstring, locusts = main.load_locustfile(os.path.join('./locust/test/', self.filename))
Example #13
0
 def test_load_locust_file_with_a_dot_in_filename(self):
     with mock_locustfile(filename_prefix="mocked.locust.file") as mocked:
         docstring, locusts = main.load_locustfile(mocked.file_path)
Example #14
0
 def test_load_locust_file_from_absolute_path(self):
     with mock_locustfile() as mocked:
         docstring, locusts = main.load_locustfile(mocked.file_path)
         self.assertIn('LocustSubclass', locusts)
         self.assertNotIn('NotLocustSubclass', locusts)
Example #15
0
def main(user_params=None, common_param=None):
    parser, options, arguments = parse_options()

    # setup logging
    setup_logging(options.loglevel, options.logfile)
    logger = logging.getLogger(__name__)

    if options.show_version:
        print("Locust %s" % (version, ))
        sys.exit(0)

    locustfile = find_locustfile(options.locustfile)

    if not locustfile:
        logger.error(
            "Could not find any locustfile! Ensure file ends in '.py' and see --help for available options."
        )
        sys.exit(1)

    if locustfile == "locust.py":
        logger.error(
            "The locustfile must not be named `locust.py`. Please rename the file and try again."
        )
        sys.exit(1)

    docstring, locusts = load_locustfile(locustfile)

    if options.list_commands:
        console_logger.info("Available Locusts:")
        for name in locusts:
            console_logger.info("    " + name)
        sys.exit(0)

    if not locusts:
        logger.error("No Locust class found!")
        sys.exit(1)

    # make sure specified Locust exists
    if arguments:
        missing = set(arguments) - set(locusts.keys())
        if missing:
            logger.error("Unknown Locust(s): %s\n" % (", ".join(missing)))
            sys.exit(1)
        else:
            names = set(arguments) & set(locusts.keys())
            locust_classes = [locusts[n] for n in names]
    else:
        # list() call is needed to consume the dict_view object in Python 3
        locust_classes = list(locusts.values())

    if options.show_task_ratio:
        console_logger.info("\n Task ratio per locust class")
        console_logger.info("-" * 80)
        print_task_ratio(locust_classes)
        console_logger.info("\n Total task ratio")
        console_logger.info("-" * 80)
        print_task_ratio(locust_classes, total=True)
        sys.exit(0)
    if options.show_task_ratio_json:
        from json import dumps
        task_data = {
            "per_class": get_task_ratio_dict(locust_classes),
            "total": get_task_ratio_dict(locust_classes, total=True)
        }
        console_logger.info(dumps(task_data))
        sys.exit(0)

    if not options.no_web and not options.slave:
        # spawn web greenlet
        logger.info("Starting web monitor at %s:%s" %
                    (options.web_host or "*", options.port))
        main_greenlet = gevent.spawn(web.start, locust_classes, options)

    if not options.master and not options.slave:
        if user_params:
            runners.locust_runner = ParameterizableLocustRunner(
                locust_classes, options, user_params, common_param)
        else:
            runners.locust_runner = LocalLocustRunner(locust_classes, options)
        # spawn client spawning/hatching greenlet
        if options.no_web:
            runners.locust_runner.start_hatching(wait=True)
            main_greenlet = runners.locust_runner.greenlet
    elif options.master:
        runners.locust_runner = MasterLocustRunner(locust_classes, options)
        if options.no_web:
            while len(runners.locust_runner.clients.ready
                      ) < options.expect_slaves:
                logging.info(
                    "Waiting for slaves to be ready, %s of %s connected",
                    len(runners.locust_runner.clients.ready),
                    options.expect_slaves)
                time.sleep(1)

            runners.locust_runner.start_hatching(options.num_clients,
                                                 options.hatch_rate)
            main_greenlet = runners.locust_runner.greenlet
    elif options.slave:
        try:
            runners.locust_runner = SlaveLocustRunner(locust_classes, options)
            main_greenlet = runners.locust_runner.greenlet
        except socket.error as e:
            logger.error("Failed to connect to the Locust master: %s", e)
            sys.exit(-1)

    if not options.only_summary and (options.print_stats or
                                     (options.no_web and not options.slave)):
        # spawn stats printing greenlet
        gevent.spawn(stats_printer)

    if options.csvfilebase:
        gevent.spawn(stats_writer, options.csvfilebase)

    def shutdown(code=0):
        """
        Shut down locust by firing quitting event, printing/writing stats and exiting
        """
        logger.info("Shutting down (exit code %s), bye." % code)

        events.quitting.fire()
        print_stats(runners.locust_runner.request_stats)
        print_percentile_stats(runners.locust_runner.request_stats)
        if options.csvfilebase:
            write_stat_csvs(options.csvfilebase)
        print_error_report()
        sys.exit(code)

    # install SIGTERM handler
    def sig_term_handler():
        logger.info("Got SIGTERM signal")
        shutdown(0)

    gevent.signal(gevent.signal.SIGTERM, sig_term_handler)

    try:
        logger.info("Starting Locust %s" % version)
        main_greenlet.join()
        code = 0
        if len(runners.locust_runner.errors):
            code = 1
        shutdown(code=code)
    except KeyboardInterrupt as e:
        shutdown(0)
Example #16
0
def parse_locustfile(locustfile):
    docstring, locusts = load_locustfile(locustfile)
    locust_classes = list(locusts.values())
    return locust_classes
#!/usr/local/bin/python

import os
from locust import events, TaskSet
from locust.main import load_locustfile

locustfile = os.getenv('FILE') or 'locustfile.py'
host = os.getenv('HOST')

if (host is None):
    print("HOST environment variable is not set")
    exit(1)

docstring, locusts = load_locustfile(locustfile)

total_result = True
request_result = None
request_exception = None


def request_success(request_type, name, response_time, response_length, **kw):
    global request_result
    print("Request succeeded: %s, %s" % (request_type, name))
    request_result = True


def request_failure(request_type, name, response_time, response_length,
                    exception, **kw):
    global request_result
    global request_exception
    print("Request failed: %s, %s" % (request_type, name))
Example #18
0
 def test_return_docstring_and_locusts(self):
     self.__create_mock_locust_file('mock_locust_file.py')
     docstring, locusts = main.load_locustfile(self.file_path)
     self.assertEqual(docstring, self.mock_docstring)
     self.assertIn('LocustSubclass', locusts)
     self.assertNotIn('NotLocustSubclass', locusts)
Example #19
0
 def test_load_locust_file_with_multiple_dots_in_filename(self):
     self.__create_mock_locust_file('mock_locust_file.test.py')
     docstring, locusts = main.load_locustfile(self.file_path)
Example #20
0
def create_settings(
    from_environment=False,
    locustfile=None,
    classes=None,
    host=None,
    num_users=None,
    spawn_rate=None,
    reset_stats=False,
    run_time="3m",
    loglevel="INFO",
):
    """
    Returns a settings object to configure the locust load test.

    Arguments

        from_environment: get settings from environment variables
        locustfile: locustfile to use for loadtest
        classes: locust classes to use for load test
        host: host for load testing
        num_users: number of users to simulate in load test
        spawn_rate: number of users per second to start
        reset_stats: Whether to reset stats after all users are hatched
        run_time: The length of time to run the test for. Cannot exceed the duration limit set by lambda

    If from_environment is set to True then this function will attempt to set
    the attributes from environment variables. The environment variables are
    named LOCUST_ + attribute name in upper case.
    """

    settings = type("", (), {})()

    settings.from_environment = from_environment
    settings.locustfile = locustfile

    # parameters needed to create the locust Environment object
    settings.classes = classes
    settings.host = host
    settings.tags = None
    settings.exclude_tags = None
    settings.reset_stats = reset_stats
    settings.step_load = False
    settings.stop_timeout = None

    # parameters to configure test
    settings.num_users = num_users
    settings.run_time = run_time
    settings.spawn_rate = spawn_rate

    if from_environment:
        for attribute in [
            "locustfile",
            "classes",
            "host",
            "run_time",
            "num_users",
            "spawn_rate",
            "loglevel",
        ]:
            var_name = "LOCUST_{0}".format(attribute.upper())
            var_value = os.environ.get(var_name)
            if var_value:
                setattr(settings, attribute, var_value)

    if settings.locustfile is None and settings.classes is None:
        raise Exception("One of locustfile or classes must be specified")

    if settings.locustfile and settings.classes:
        raise Exception("Only one of locustfile or classes can be specified")

    if settings.locustfile:
        docstring, classes, shape_class = load_locustfile(settings.locustfile)
        settings.classes = [classes[n] for n in classes]
    else:
        if isinstance(settings.classes, str):
            settings.classes = settings.classes.split(",")
            for idx, val in enumerate(settings.classes):
                # This needs fixing
                settings.classes[idx] = eval(val)

    for attribute in ["classes", "host", "num_users", "spawn_rate"]:
        val = getattr(settings, attribute, None)
        if not val:
            raise Exception(
                "configuration error, attribute not set: {0}".format(attribute)
            )

        if isinstance(val, str) and val.isdigit():
            setattr(settings, attribute, int(val))

    return settings
Example #21
0
 def test_load_locust_file_from_absolute_path(self):
     self.__create_mock_locust_file('mock_locust_file.py')
     docstring, locusts = main.load_locustfile(self.file_path)
Example #22
0
 def test_load_locust_file_from_relative_path(self):
     with mock_locustfile() as mocked:
         docstring, locusts = main.load_locustfile(
             os.path.join('./locust/test/', mocked.filename))
Example #23
0
 def test_load_locust_file_with_multiple_dots_in_filename(self):
     self.__create_mock_locust_file('mock_locust_file.test.py')
     docstring, locusts = main.load_locustfile(self.file_path)
Example #24
0
def main():
    parser, options = parse_options()

    # setup logging
    if not options.skip_log_setup:
        setup_logging(options.loglevel, options.logfile)

    logger = logging.getLogger(__name__)

    locust_path = get_locust_path()

    if options.web:
        web_port = options.web_port
        logger.info('Running easy-locust web: 0.0.0.0:{}'.format(web_port))
        init_app(port=web_port)
        sys.exit(0)

    if options.demo:
        if not locust_path:
            logger.error(
                '''Cannot locate Python path, make sure it is in right place. If windows add it to sys PATH,
            if linux make sure python is installed in /usr/local/lib/''')
            sys.exit(1)
        pt_demo_path = os.path.join(locust_path, 'demo',
                                    'demo_pressuretest.xls')
        pt_demo_path_json = os.path.join(locust_path, 'demo',
                                         'demo_locustfile.json')
        pt_new_demo = os.path.join(os.getcwd(), 'PtDemo.xls')
        pt_new_demo_json = os.path.join(os.getcwd(), 'demo.json')
        shutil.copyfile(pt_demo_path, pt_new_demo)
        shutil.copyfile(pt_demo_path_json, pt_new_demo_json)
        sys.exit(0)

    if options.xlsfile:
        pt_file = options.xlsfile
        if not (pt_file.endswith('.xls') or pt_file.endswith('.json')):
            logger.error(
                "PressureTest file must be end with '.xls' or '.json' and see --help for available options."
            )
            sys.exit(1)
        if not os.path.isfile(pt_file):
            logger.error('PressureTest file is not exist, please check it.')
            sys.exit(1)
        _status = generate_locust_file(pt_file)
        if not _status:
            sys.exit(1)
        sys.exit(0)

    locustfile = find_locustfile(options.locustfile)

    if not locustfile:
        logger.error(
            "Could not find any locustfile! Ensure file ends in '.py' and see --help for available options."
        )
        sys.exit(1)

    if locustfile == "locust.py" or locustfile == "locust.xls" or locustfile == "locust.json":
        logger.error(
            "The locustfile must not be named `locust.py` or `locust.xls` or `locust.json`. "
            "Please rename the file and try again.")
        sys.exit(1)

    docstring, locusts = load_locustfile(locustfile)

    if options.list_commands:
        console_logger.info("Available Locusts:")
        for name in locusts:
            console_logger.info("    " + name)
        sys.exit(0)

    if not locusts:
        logger.error("No Locust class found!")
        sys.exit(1)

    # make sure specified Locust exists
    if options.locust_classes:
        missing = set(options.locust_classes) - set(locusts.keys())
        if missing:
            logger.error("Unknown Locust(s): %s\n" % (", ".join(missing)))
            sys.exit(1)
        else:
            names = set(options.locust_classes) & set(locusts.keys())
            locust_classes = [locusts[n] for n in names]
    else:
        # list() call is needed to consume the dict_view object in Python 3
        locust_classes = list(locusts.values())

    if options.show_task_ratio:
        console_logger.info("\n Task ratio per locust class")
        console_logger.info("-" * 80)
        print_task_ratio(locust_classes)
        console_logger.info("\n Total task ratio")
        console_logger.info("-" * 80)
        print_task_ratio(locust_classes, total=True)
        sys.exit(0)
    if options.show_task_ratio_json:
        from json import dumps
        task_data = {
            "per_class": get_task_ratio_dict(locust_classes),
            "total": get_task_ratio_dict(locust_classes, total=True)
        }
        console_logger.info(dumps(task_data))
        sys.exit(0)

    if options.run_time:
        if not options.no_web:
            logger.error(
                "The --run-time argument can only be used together with --no-web"
            )
            sys.exit(1)
        try:
            options.run_time = parse_timespan(options.run_time)
        except ValueError:
            logger.error(
                "Valid --run-time formats are: 20, 20s, 3m, 2h, 1h20m, 3h30m10s, etc."
            )
            sys.exit(1)

        def spawn_run_time_limit_greenlet():
            logger.info("Run time limit set to %s seconds" % options.run_time)

            def timelimit_stop():
                logger.info("Time limit reached. Stopping Locust.")
                runners.locust_runner.quit()

            gevent.spawn_later(options.run_time, timelimit_stop)

    if options.step_time:
        if not options.step_load:
            logger.error(
                "The --step-time argument can only be used together with --step-load"
            )
            sys.exit(1)
        try:
            options.step_time = parse_timespan(options.step_time)
        except ValueError:
            logger.error(
                "Valid --step-time formats are: 20, 20s, 3m, 2h, 1h20m, 3h30m10s, etc."
            )
            sys.exit(1)

    if options.master:
        # Add -d for automatically run slaves
        if options.distribute:
            ptpy = locustfile
            if options.locustfile.endswith('.xls'):
                _type = 'xls'
                pt_s = PtExcel(options.locustfile)
                master_ip, pt_slave_info = pt_s.pt_slave()
            else:
                _type = 'dict'
                with open(options.locustfile, 'r') as f:
                    _d = json.load(f, encoding='utf-8')
                master_ip = _d.get('master_ip')
                pt_slave_info = _d.get('slaves')
            if master_ip == '':
                logger.error(
                    'master IP cannot be None if you use --distribute')
                sys.exit(1)
            if options.boomer:
                locust_cli_slave = 'nohup ./client_v1 --web --master-host={masteIP} > /dev/null 2>&1 &'.format(
                    masteIP=master_ip)
                targets_dict, file_list = gen_boomer_client_json(
                    options.locustfile)
                boomer_client_file = os.path.join(locust_path, 'boomer_client',
                                                  'client_v1')
                file_list.append(boomer_client_file)
                thread_pool = []
                try:
                    for slave in pt_slave_info:
                        if _type == 'xls':
                            slave_ip, slave_username, slave_password = slave
                        else:
                            slave_ip, slave_username, slave_password = slave[
                                'ip'], slave['username'], slave['password']
                        _t = Thread(target=pt_slave_boomer,
                                    args=(slave_ip, slave_username,
                                          slave_password, file_list,
                                          locust_cli_slave, targets_dict))
                        logger.info('Prepare slave {}'.format(slave_ip))
                        thread_pool.append(_t)
                        _t.start()
                    for each_t in thread_pool:
                        each_t.join()
                    file_list.pop()
                    for each in file_list:
                        os.remove(each)
                except KeyboardInterrupt:
                    pass
                except Exception as e:
                    logger.error(
                        'Something happened, collect Exceptions here: {}'.
                        format(e))
            else:
                try:
                    locust_cli_slave = 'nohup locust -f /root/locust_client.py --slave --master-host={masteIP} > /dev/null 2>&1 &'\
                        .format(masteIP=master_ip)
                    thread_pool = []
                    for slave in pt_slave_info:
                        if _type == 'xls':
                            slave_ip, slave_username, slave_password = slave
                        else:
                            slave_ip, slave_username, slave_password = slave[
                                'ip'], slave['username'], slave['password']
                        _t = Thread(target=pt_slave,
                                    args=(slave_ip, slave_username,
                                          slave_password, ptpy,
                                          locust_cli_slave))
                        logger.info('Prepare slave {}'.format(slave_ip))
                        thread_pool.append(_t)
                        _t.start()
                    for each_t in thread_pool:
                        each_t.join()
                except KeyboardInterrupt:
                    pass
                except Exception as e:
                    logger.error(
                        'Something happened, collect Exceptions here: {}'.
                        format(e))

        runners.locust_runner = MasterLocustRunner(locust_classes, options)
    else:
        runners.locust_runner = LocalLocustRunner(locust_classes, options)
    # main_greenlet is pointing to runners.locust_runner.greenlet by default, it will point the web greenlet later if in web mode
    main_greenlet = runners.locust_runner.greenlet

    if options.no_web:
        if options.master:
            while len(runners.locust_runner.clients.ready
                      ) < options.expect_slaves:
                logging.info(
                    "Waiting for slaves to be ready, %s of %s connected",
                    len(runners.locust_runner.clients.ready),
                    options.expect_slaves)
                time.sleep(1)
        if options.step_time:
            runners.locust_runner.start_stepload(options.num_clients,
                                                 options.hatch_rate,
                                                 options.step_clients,
                                                 options.step_time)
        else:
            runners.locust_runner.start_hatching(options.num_clients,
                                                 options.hatch_rate)
            # make locusts are spawned
            time.sleep(1)
    else:
        # spawn web greenlet
        logger.info("Starting web monitor at http://%s:%s" %
                    (options.web_host or "*", options.port))
        main_greenlet = gevent.spawn(web.start, locust_classes, options)

    if options.run_time:
        spawn_run_time_limit_greenlet()

    stats_printer_greenlet = None
    if not options.only_summary and (options.print_stats or options.no_web):
        # spawn stats printing greenlet
        stats_printer_greenlet = gevent.spawn(stats_printer)

    if options.csvfilebase:
        gevent.spawn(stats_writer, options.csvfilebase,
                     options.stats_history_enabled)

    def shutdown(code=0):
        """
        Shut down locust by firing quitting event, printing/writing stats and exiting
        """
        logger.info("Shutting down (exit code %s), bye." % code)
        if stats_printer_greenlet is not None:
            stats_printer_greenlet.kill(block=False)
        logger.info("Cleaning up runner...")
        if runners.locust_runner is not None:
            runners.locust_runner.quit()
        logger.info("Running teardowns...")
        events.quitting.fire(reverse=True)
        print_stats(runners.locust_runner.stats, current=False)
        print_percentile_stats(runners.locust_runner.stats)
        if options.csvfilebase:
            write_stat_csvs(options.csvfilebase, options.stats_history_enabled)
        print_error_report()
        sys.exit(code)

    # install SIGTERM handler
    def sig_term_handler():
        logger.info("Got SIGTERM signal")
        shutdown(0)

    gevent.signal(signal.SIGTERM, sig_term_handler)

    try:
        logger.info("Starting Locust %s" % version)
        main_greenlet.join()
        code = 0
        if len(runners.locust_runner.errors) or len(
                runners.locust_runner.exceptions):
            code = options.exit_code_on_error
        shutdown(code=code)
    except KeyboardInterrupt:
        shutdown(0)
Example #25
0
 def test_load_locust_file_from_absolute_path(self):
     self.__create_mock_locust_file('mock_locust_file.py')
     docstring, locusts = main.load_locustfile(self.file_path)
Example #26
0
 def test_load_locust_file_from_relative_path(self):
     self.__create_mock_locust_file('mock_locust_file.py')
     docstring, locusts = main.load_locustfile(
         os.path.join('./locust/test/', self.filename))
Example #27
0
 def test_load_locust_file_from_absolute_path(self):
     with mock_locustfile() as mocked:
         docstring, user_classes = main.load_locustfile(mocked.file_path)
         self.assertIn("UserSubclass", user_classes)
         self.assertNotIn("NotUserSubclass", user_classes)
Example #28
0
 def test_return_docstring_and_locusts(self):
     self.__create_mock_locust_file('mock_locust_file.py')
     docstring, locusts = main.load_locustfile(self.file_path)
     self.assertEqual(docstring, self.mock_docstring)
     self.assertIn('LocustSubclass', locusts)
     self.assertNotIn('NotLocustSubclass', locusts)
Example #29
0
 def test_load_locust_file_from_relative_path(self):
     with mock_locustfile() as mocked:
         docstring, user_classes = main.load_locustfile(
             os.path.join("./locust/test/", mocked.filename))