Beispiel #1
0
    def test_spawn_zero_locusts(self):
        class MyTaskSet(TaskSet):
            @task
            def my_task(self):
                pass

        class MyTestLocust(Locust):
            tasks = [MyTaskSet]
            wait_time = constant(0.1)

        environment = Environment(options=mocked_options())
        runner = LocalLocustRunner(environment, [MyTestLocust])

        timeout = gevent.Timeout(2.0)
        timeout.start()

        try:
            runner.start(0, 1, wait=True)
            runner.hatching_greenlet.join()
        except gevent.Timeout:
            self.fail(
                "Got Timeout exception. A locust seems to have been spawned, even though 0 was specified."
            )
        finally:
            timeout.cancel()
Beispiel #2
0
    def test_spawn_zero_locusts(self):
        class MyTaskSet(TaskSet):
            @task
            def my_task(self):
                pass

        class MyTestLocust(Locust):
            task_set = MyTaskSet
            min_wait = 100
            max_wait = 100

        runner = LocalLocustRunner([MyTestLocust], self.options)

        timeout = gevent.Timeout(2.0)
        timeout.start()

        try:
            runner.start_hatching(0, 1, wait=True)
            runner.greenlet.join()
        except gevent.Timeout:
            self.fail(
                "Got Timeout exception. A locust seems to have been spawned, even though 0 was specified."
            )
        finally:
            timeout.cancel()
Beispiel #3
0
    def test_taskset_setup_method_exception(self):
        class User(Locust):
            setup_run_count = 0
            task_run_count = 0
            locust_error_count = 0
            wait_time = constant(1)

            @task
            class task_set(TaskSet):
                def setup(self):
                    User.setup_run_count += 1
                    raise Exception("some exception")

                @task
                def my_task(self):
                    User.task_run_count += 1

        environment = Environment(options=mocked_options())

        def on_locust_error(*args, **kwargs):
            User.locust_error_count += 1

        environment.events.locust_error.add_listener(on_locust_error)

        runner = LocalLocustRunner(environment, locust_classes=[User])
        runner.start(locust_count=3, hatch_rate=3, wait=False)
        runner.hatching_greenlet.get(timeout=3)

        self.assertEqual(1, User.setup_run_count)
        self.assertEqual(1, User.locust_error_count)
        self.assertEqual(3, User.task_run_count)
Beispiel #4
0
 def test_taskset_setup_method_exception(self):
     class User(Locust):
         setup_run_count = 0
         task_run_count = 0
         locust_error_count = 0
         wait_time = constant(1)
         class task_set(TaskSet):
             def setup(self):
                 User.setup_run_count += 1
                 raise Exception("some exception")
             @task
             def my_task(self):
                 User.task_run_count += 1
     
     def on_locust_error(*args, **kwargs):
         User.locust_error_count += 1
     events.locust_error += on_locust_error
     
     runner = LocalLocustRunner([User], mocked_options())
     runner.start_hatching(locust_count=3, hatch_rate=3, wait=False)
     runner.hatching_greenlet.get(timeout=3)
     
     self.assertEqual(1, User.setup_run_count)
     self.assertEqual(1, User.locust_error_count)
     self.assertEqual(3, User.task_run_count)
Beispiel #5
0
    def test_exception_is_catched(self):
        """ Test that exceptions are stored, and execution continues """
        class HeyAnException(Exception):
            pass

        class MyTaskSet(TaskSet):
            def __init__(self, *a, **kw):
                super(MyTaskSet, self).__init__(*a, **kw)
                self._task_queue = [
                    {
                        "callable": self.will_error,
                        "args": [],
                        "kwargs": {}
                    },
                    {
                        "callable": self.will_stop,
                        "args": [],
                        "kwargs": {}
                    },
                ]

            @task(1)
            def will_error(self):
                raise HeyAnException(":(")

            @task(1)
            def will_stop(self):
                self.interrupt()

        class MyLocust(Locust):
            min_wait = 10
            max_wait = 10
            task_set = MyTaskSet

        runner = LocalLocustRunner([MyLocust], self.options)
        l = MyLocust()

        # supress stderr
        with mock.patch("sys.stderr") as mocked:
            l.task_set._task_queue = [
                l.task_set.will_error, l.task_set.will_stop
            ]
            self.assertRaises(LocustError,
                              l.run)  # make sure HeyAnException isn't raised
            l.task_set._task_queue = [
                l.task_set.will_error, l.task_set.will_stop
            ]
            self.assertRaises(LocustError,
                              l.run)  # make sure HeyAnException isn't raised
        self.assertEqual(2, len(mocked.method_calls))

        # make sure exception was stored
        self.assertEqual(1, len(runner.exceptions))
        hash_key, exception = runner.exceptions.popitem()
        self.assertTrue("traceback" in exception)
        self.assertTrue("HeyAnException" in exception["traceback"])
        self.assertEqual(2, exception["count"])
Beispiel #6
0
 def test_start_event(self):
     class User(Locust):
         wait_time = constant(1)
         task_run_count = 0
         @task
         def my_task(self):
             User.task_run_count += 1
     
     test_start_run = [0]
     
     environment = Environment(options=mocked_options())
     def on_test_start(*args, **kwargs):
         test_start_run[0] += 1
     environment.events.test_start.add_listener(on_test_start)
     
     runner = LocalLocustRunner(environment, locust_classes=[User])
     runner.start(locust_count=3, hatch_rate=3, wait=False)
     runner.hatching_greenlet.get(timeout=3)
     
     self.assertEqual(1, test_start_run[0])
     self.assertEqual(3, User.task_run_count)
Beispiel #7
0
    def test_stop_timeout_with_interrupt_no_reschedule(self):
        state = [0]

        class MySubTaskSet(TaskSet):
            @task
            def a_task(self):
                gevent.sleep(0.1)
                state[0] = 1
                self.interrupt(reschedule=False)

        class MyTestLocust(Locust):
            tasks = [MySubTaskSet]
            wait_time = constant(3)

        environment = create_environment(mocked_options())
        environment.stop_timeout = 0.3
        runner = LocalLocustRunner(environment, [MyTestLocust])
        runner.start(1, 1, wait=True)
        gevent.sleep(0)
        timeout = gevent.Timeout(0.11)
        timeout.start()
        try:
            runner.quit()
            runner.greenlet.join()
        except gevent.Timeout:
            self.fail(
                "Got Timeout exception. Interrupted locusts should exit immediately during stop_timeout."
            )
        finally:
            timeout.cancel()
        self.assertEqual(1, state[0])
Beispiel #8
0
    def test_stop_timeout_during_on_start(self):
        short_time = 0.05

        class MyTaskSet(TaskSet):
            finished_on_start = False
            my_task_run = False

            def on_start(self):
                gevent.sleep(short_time)
                MyTaskSet.finished_on_start = True

            @task
            def my_task(self):
                MyTaskSet.my_task_run = True

        class MyTestLocust(Locust):
            tasks = [MyTaskSet]
            wait_time = constant(0)

        environment = create_environment(mocked_options())
        environment.stop_timeout = short_time
        runner = LocalLocustRunner(environment, [MyTestLocust])
        runner.start(1, 1)
        gevent.sleep(short_time / 2)
        runner.quit()

        self.assertTrue(MyTaskSet.finished_on_start)
        self.assertFalse(MyTaskSet.my_task_run)
Beispiel #9
0
 def test_user_count_in_csv_history_stats(self):
     start_time = int(time.time())
     class TestUser(Locust):
         wait_time = constant(10)
         @task
         def t(self):
             self.environment.runner.stats.log_request("GET", "/", 10, 10)
     runner = LocalLocustRunner(self.environment, [TestUser])
     runner.start(3, 5) # spawn a user every 0.2 second
     gevent.sleep(0.1)
     
     greenlet = gevent.spawn(stats_writer, self.environment, self.STATS_BASE_NAME, full_history=True)
     gevent.sleep(0.6)
     gevent.kill(greenlet)
     
     runner.stop()
     
     with open(self.STATS_HISTORY_FILENAME) as f:
         reader = csv.DictReader(f)
         rows = [r for r in reader]
     
     self.assertEqual(6, len(rows))
     for i in range(3):
         row = rows.pop(0)
         self.assertEqual("%i" % (i + 1), row["User count"])
         self.assertEqual("/", row["Name"])
         self.assertEqual("%i" % (i + 1), row["# requests"])
         self.assertGreaterEqual(int(row["Timestamp"]), start_time)
         row = rows.pop(0)
         self.assertEqual("%i" % (i + 1), row["User count"])
         self.assertEqual("Aggregated", row["Name"])
         self.assertEqual("%i" % (i + 1), row["# requests"])
         self.assertGreaterEqual(int(row["Timestamp"]), start_time)
Beispiel #10
0
    def test_no_reset_stats(self):
        class User(Locust):
            wait_time = constant(0)

            @task
            class task_set(TaskSet):
                @task
                def my_task(self):
                    self.locust.environment.events.request_success.fire(
                        request_type="GET",
                        name="/test",
                        response_time=666,
                        response_length=1337,
                    )
                    sleep(2)

        environment = Environment(reset_stats=False, options=mocked_options())
        runner = LocalLocustRunner(environment, locust_classes=[User])
        runner.start(locust_count=6, hatch_rate=12, wait=False)
        sleep(0.25)
        self.assertGreaterEqual(
            runner.stats.get("/test", "GET").num_requests, 3)
        sleep(0.3)
        self.assertEqual(6, runner.stats.get("/test", "GET").num_requests)
        runner.quit()
Beispiel #11
0
    def test_stop_timeout_during_on_start(self):
        short_time = 0.05
        class MyTaskSet(TaskSet):
            finished_on_start = False
            my_task_run = False
            def on_start(self):
                gevent.sleep(short_time)
                MyTaskSet.finished_on_start = True

            @task
            def my_task(self):
                MyTaskSet.my_task_run = True

        class MyTestLocust(Locust):
            task_set = MyTaskSet
            min_wait = 0
            max_wait = 0
        
        options = mocked_options()
        options.stop_timeout = short_time
        runner = LocalLocustRunner([MyTestLocust], options)
        runner.start_hatching(1, 1)
        gevent.sleep(short_time / 2)
        runner.quit()

        self.assertTrue(MyTaskSet.finished_on_start)
        self.assertFalse(MyTaskSet.my_task_run)
Beispiel #12
0
    def test_stop_timeout_exit_during_wait(self):
        short_time = 0.05
        class MyTaskSet(TaskSet):
            @task
            def my_task(self):
                pass

        class MyTestLocust(Locust):
            task_set = MyTaskSet
            wait_time = between(1, 1)

        options = mocked_options()
        options.stop_timeout = short_time
        runner = LocalLocustRunner([MyTestLocust], options)
        runner.start_hatching(1, 1)
        gevent.sleep(short_time) # sleep to make sure locust has had time to start waiting
        timeout = gevent.Timeout(short_time)
        timeout.start()
        try:
            runner.quit()
            runner.greenlet.join()
        except gevent.Timeout:
            self.fail("Got Timeout exception. Waiting locusts should stop immediately, even when using stop_timeout.")
        finally:
            timeout.cancel()
Beispiel #13
0
    def test_stop_timeout_with_interrupt(self):
        short_time = 0.05
        class MySubTaskSet(TaskSet):
            @task
            def a_task(self):
                gevent.sleep(0)
                self.interrupt(reschedule=True)

        class MyTaskSet(TaskSet):
            tasks = [MySubTaskSet]
        
        class MyTestLocust(Locust):
            task_set = MyTaskSet

        options = mocked_options()
        options.stop_timeout = short_time
        runner = LocalLocustRunner([MyTestLocust], options)
        runner.start_hatching(1, 1)
        gevent.sleep(0)
        timeout = gevent.Timeout(short_time)
        timeout.start()
        try:
            runner.quit()
            runner.greenlet.join()
        except gevent.Timeout:
            self.fail("Got Timeout exception. Interrupted locusts should exit immediately during stop_timeout.")
        finally:
            timeout.cancel()
Beispiel #14
0
 def test_change_user_count_during_hatching(self):
     class User(Locust):
         wait_time = constant(1)
         @task
         def my_task(self):
             pass
     
     environment = Environment(options=mocked_options())
     runner = LocalLocustRunner(environment, [User])
     runner.start(locust_count=10, hatch_rate=5, wait=False)
     sleep(0.6)
     runner.start(locust_count=5, hatch_rate=5, wait=False)
     runner.hatching_greenlet.join()
     self.assertEqual(5, len(runner.locusts))
     runner.quit()
Beispiel #15
0
 def test_change_user_count_during_hatching(self):
         class User(Locust):
             wait_time = constant(1)
             class task_set(TaskSet):
                 @task
                 def my_task(self):
                     pass
         
         runner = LocalLocustRunner([User], mocked_options())
         runner.start_hatching(locust_count=10, hatch_rate=5, wait=False)
         sleep(0.6)
         runner.start_hatching(locust_count=5, hatch_rate=5, wait=False)
         runner.hatching_greenlet.join()
         self.assertEqual(5, len(runner.locusts))
         runner.quit()
Beispiel #16
0
    def test_exception_is_catched(self):
        """ Test that exceptions are stored, and execution continues """
        class HeyAnException(Exception):
            pass

        class MyTaskSet(TaskSet):
            def __init__(self, *a, **kw):
                super(MyTaskSet, self).__init__(*a, **kw)
                self._task_queue = [
                    {
                        "callable": self.will_error,
                        "args": [],
                        "kwargs": {}
                    },
                    {
                        "callable": self.will_stop,
                        "args": [],
                        "kwargs": {}
                    },
                ]

            @task(1)
            def will_error(self):
                raise HeyAnException(":(")

            @task(1)
            def will_stop(self):
                self.interrupt()

        class MyLocust(Locust):
            wait_time = constant(0.01)
            task_set = MyTaskSet

        runner = LocalLocustRunner(self.environment, [MyLocust])
        l = MyLocust(self.environment)

        l.task_set._task_queue = [l.task_set.will_error, l.task_set.will_stop]
        self.assertRaises(LocustError,
                          l.run)  # make sure HeyAnException isn't raised
        l.task_set._task_queue = [l.task_set.will_error, l.task_set.will_stop]
        self.assertRaises(LocustError,
                          l.run)  # make sure HeyAnException isn't raised
        # make sure we got two entries in the error log
        self.assertEqual(2, len(self.mocked_log.error))

        # make sure exception was stored
        self.assertEqual(1, len(runner.exceptions))
        hash_key, exception = runner.exceptions.popitem()
        self.assertTrue("traceback" in exception)
        self.assertTrue("HeyAnException" in exception["traceback"])
        self.assertEqual(2, exception["count"])
 def test_spawn_zero_locusts(self):
     class MyTaskSet(TaskSet):
         @task
         def my_task(self):
             pass
         
     class MyTestLocust(Locust):
         task_set = MyTaskSet
         min_wait = 100
         max_wait = 100
     
     runner = LocalLocustRunner([MyTestLocust], self.options)
     
     timeout = gevent.Timeout(2.0)
     timeout.start()
     
     try:
         runner.start_hatching(0, 1, wait=True)
         runner.greenlet.join()
     except gevent.Timeout:
         self.fail("Got Timeout exception. A locust seems to have been spawned, even though 0 was specified.")
     finally:
         timeout.cancel()
Beispiel #18
0
def _run_locust(locust_classes, master):
    config_options(master=master)
    print('*** Starting locust: {}:{} ***'.format(options.web_host,
                                                  options.port))
    if options.master:
        runners.locust_runner = MasterLocustRunner(locust_classes, options)
    else:
        runners.locust_runner = LocalLocustRunner(locust_classes, options)
    logging.info("Starting web monitor at http://%s:%s" %
                 (options.web_host or "0.0.0.0", options.port))
    main_greenlet = gevent.spawn(locust_web.start, locust_classes, options)
    stats_printer_greenlet = None

    def shutdown(code=0):
        """
        Shut down locust by firing quitting event, printing/writing stats and exiting
        """
        logging.info("Shutting down (exit code %s), bye." % code)
        if stats_printer_greenlet is not None:
            stats_printer_greenlet.kill(block=False)
        logging.info("Cleaning up runner...")
        if runners.locust_runner is not None:
            runners.locust_runner.quit()
        logging.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():
        logging.info("Got SIGTERM signal")
        shutdown(0)

    gevent.signal_handler(signal.SIGTERM, sig_term_handler)

    try:
        logging.info("Starting Locust...")
        main_greenlet.join()
        code = 0
        lr = runners.locust_runner
        if len(lr.errors) or len(lr.exceptions) or lr.cpu_log_warning():
            code = options.exit_code_on_error
        shutdown(code=code)
    except KeyboardInterrupt:
        shutdown(0)
Beispiel #19
0
def bootstrap(test_id):
    test_runner = get_runner(test_id)
    if test_runner is None:
        parser, options, arguments = parse_options()
        tests_in_locust_folder = find_all_test_in_folder(
            '/Users/jaumepinyol/Documents/locust/locust/tests')
        for test_in_folder in tests_in_locust_folder:
            docstring, locusts = tests_in_locust_folder[test_in_folder][
                "locust"]
            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())
                    tests_in_locust_folder[test_in_folder]["locust"] = [
                        locusts[n] for n in names
                    ]
            else:
                tests_in_locust_folder[test_in_folder][
                    "locust"] = locusts.values()
        runners.locust_runner = LocalLocustRunner(tests_in_locust_folder,
                                                  options)
        test_runner = get_runner(test_id)

    changed = False
    if test_runner.selected_locust != test_id:
        changed = test_runner.set_selected_locust(test_id)

    is_distributed = isinstance(test_runner, MasterLocustRunner)
    if is_distributed:
        slave_count = test_runner.slave_count
    else:
        slave_count = 0

    files = runners.locust_runner.files

    return render_template("test.html",
                           state=test_runner.state,
                           is_distributed=is_distributed,
                           slave_count=slave_count,
                           user_count=test_runner.user_count,
                           version=version,
                           files=files,
                           selected=test_runner.selected_locust,
                           changed=changed)
Beispiel #20
0
def start_pressure_test(test_data):
    global locust_runner_id, host
    locust_runner_id = test_data["test_id"]
    host = test_data["host"]
    locust_count = test_data["locust_count"]
    hatch_rate = test_data["hatch_rate"]
    arser, options, arguments = parse_options()

    WebsiteUser = decorator(test_data=test_data)

    runners.locust_runner = LocalLocustRunner([WebsiteUser], options)
    runners.locust_runner.start_hatching(locust_count=locust_count,
                                         hatch_rate=hatch_rate)
    update_running_status(DJANGO_GET_UPDATE_RUNNING_STATUS_URL,
                          locust_runner_id)
    gevent.spawn_later(test_data["run_time"], time_limit_stop,
                       locust_runner_id)
Beispiel #21
0
    def test_stop_event_stop_and_quit(self):
        class User(Locust):
            wait_time = constant(1)
            @task
            def my_task(self):
                pass

        test_stop_run = [0]
        environment = Environment(options=mocked_options())
        def on_test_stop(*args, **kwargs):
            test_stop_run[0] += 1
        environment.events.test_stop.add_listener(on_test_stop)

        runner = LocalLocustRunner(environment, locust_classes=[User])
        runner.start(locust_count=3, hatch_rate=3, wait=False)
        self.assertEqual(0, test_stop_run[0])
        runner.stop()
        runner.quit()
        self.assertEqual(1, test_stop_run[0])
Beispiel #22
0
    def test_exception_in_task(self):
        class MyLocust(Locust):
            @task
            def will_error(self):
                raise HeyAnException(":(")

        runner = LocalLocustRunner(self.environment, [MyLocust])

        l = MyLocust(self.environment)

        self.assertRaises(HeyAnException, l.run)
        self.assertRaises(HeyAnException, l.run)
        self.assertEqual(1, len(runner.exceptions))

        hash_key, exception = runner.exceptions.popitem()
        self.assertTrue("traceback" in exception)
        self.assertTrue("HeyAnException" in exception["traceback"])
        self.assertEqual(2, exception["count"])
Beispiel #23
0
def launch(classname, base_url, n_clients, rate, n_requests=None, timeout=600):
    """
    Launches the tests
    :param: classname: class inherited from HttpLocust defining the test
    :param: base_url: server and port of the url to request
    :param: n_clients: Number of concurrent users
    :param: rate: The rate per second in which clients are spawned
    :param: n_requests: Total number of requests to be done
    :param: timeout: Stop testing after the specified amount of seconds
    """
    options = Namespace(**{
        'host': base_url,
        'num_clients': n_clients,
        'hatch_rate': rate,
        'num_requests': n_requests if n_requests else n_clients * 10,
        'run_time': timeout,
        'no_web': True,
        'no_reset_stats': True,
        'csvfilebase': os.path.join(get_or_create_output_dir(), get_test_calling())
    })

    setup_logging('INFO', None)
    runners.locust_runner = LocalLocustRunner([classname], options)

    # spawn client spawning/hatching greenlets:
    runners.locust_runner.start_hatching(wait=True)
    main_greenlet = runners.locust_runner.greenlet
    spawn_run_time_limit_greenlet(options)

    if options.csvfilebase:
        gevent.spawn(stats_writer, options.csvfilebase)
    try:
        main_greenlet.join()
        code = 0
        if len(runners.locust_runner.errors):
            code = 1
        shutdown(options, code=code)
    except KeyboardInterrupt:
        shutdown(options, 0)
Beispiel #24
0
 def test_exception_in_task(self):
     class HeyAnException(Exception):
         pass
     
     class MyLocust(Locust):
         class task_set(TaskSet):
             @task
             def will_error(self):
                 raise HeyAnException(":(")
     
     runner = LocalLocustRunner([MyLocust], self.options)
     
     l = MyLocust()
     l._catch_exceptions = False
     
     self.assertRaises(HeyAnException, l.run)
     self.assertRaises(HeyAnException, l.run)
     self.assertEqual(1, len(runner.exceptions))
     
     hash_key, exception = runner.exceptions.popitem()
     self.assertTrue("traceback" in exception)
     self.assertTrue("HeyAnException" in exception["traceback"])
     self.assertEqual(2, exception["count"])
Beispiel #25
0
 def test_cpu_warning(self):
     _monitor_interval = runners.CPU_MONITOR_INTERVAL
     runners.CPU_MONITOR_INTERVAL = 2.0
     try:
         class CpuLocust(Locust):
             wait_time = constant(0)
             class task_set(TaskSet):
                 @task
                 def cpu_task(self):
                     for i in range(1000000):
                         _ = 3 / 2
         runner = LocalLocustRunner([CpuLocust], mocked_options())
         self.assertFalse(runner.cpu_warning_emitted)
         runner.spawn_locusts(1, wait=False)
         sleep(2.5)
         runner.quit()
         self.assertTrue(runner.cpu_warning_emitted)
     finally:
         runners.CPU_MONITOR_INTERVAL = _monitor_interval
Beispiel #26
0
 def test_cpu_warning(self):
     _monitor_interval = runners.CPU_MONITOR_INTERVAL
     runners.CPU_MONITOR_INTERVAL = 2.0
     try:
         class CpuLocust(Locust):
             wait_time = constant(0.001)
             @task
             def cpu_task(self):
                 for i in range(1000000):
                     _ = 3 / 2
         environment = Environment(
             options=mocked_options(),
         )
         runner = LocalLocustRunner(environment, [CpuLocust])
         self.assertFalse(runner.cpu_warning_emitted)
         runner.spawn_locusts(1, 1, wait=False)
         sleep(2.5)
         runner.quit()
         self.assertTrue(runner.cpu_warning_emitted)
     finally:
         runners.CPU_MONITOR_INTERVAL = _monitor_interval
Beispiel #27
0
    wait_time = between(1, 3)
    host = "https://docs.locust.io"

    class task_set(TaskSet):
        @task
        def my_task(self):
            self.client.get("/")

        @task
        def task_404(self):
            self.client.get("/non-existing-path")


# setup Environment and Runner
env = Environment()
runner = LocalLocustRunner(environment=env, locust_classes=[User])
# start a WebUI instance
web_ui = WebUI(environment=env)
gevent.spawn(lambda: web_ui.start("127.0.0.1", 8089))

# TODO: fix
#def on_request_success(request_type, name, response_time, response_length, **kwargs):
#    report_to_grafana("%_%s" % (request_type, name), response_time)
#env.events.request_succes.add_listener(on_request_success)

# start a greenlet that periodically outputs the current stats
gevent.spawn(stats_printer(runner.stats))

# start the test
runner.start(1, hatch_rate=10)
# wait for the greenlets (indefinitely)
Beispiel #28
0
    def test_kill_locusts_with_stop_timeout(self):
        short_time = 0.05
        class MyTaskSet(TaskSet):
            @task
            def my_task(self):
                MyTaskSet.state = "first"
                gevent.sleep(short_time)
                MyTaskSet.state = "second" # should only run when run time + stop_timeout is > short_time
                gevent.sleep(short_time)
                MyTaskSet.state = "third" # should only run when run time + stop_timeout is > short_time * 2

        class MyTestLocust(Locust):
            task_set = MyTaskSet
            wait_time = constant(0)
        
        options = mocked_options()
        runner = LocalLocustRunner([MyTestLocust], options)
        runner.start_hatching(1, 1)
        gevent.sleep(short_time / 2)
        runner.kill_locusts(1)
        self.assertEqual("first", MyTaskSet.state)
        runner.quit()

        options.stop_timeout = short_time / 2 # exit with timeout
        runner = LocalLocustRunner([MyTestLocust], options)
        runner.start_hatching(1, 1)
        gevent.sleep(short_time)
        runner.kill_locusts(1)
        self.assertEqual("second", MyTaskSet.state)
        runner.quit()
        
        options.stop_timeout = short_time * 3 # allow task iteration to complete, with some margin
        runner = LocalLocustRunner([MyTestLocust], options)
        runner.start_hatching(1, 1)
        gevent.sleep(short_time)
        timeout = gevent.Timeout(short_time * 2)
        timeout.start()
        try:
            runner.kill_locusts(1)
            runner.locusts.join()
        except gevent.Timeout:
            self.fail("Got Timeout exception. Some locusts must have kept runnining after iteration finish")
        finally:
            timeout.cancel()
        self.assertEqual("third", MyTaskSet.state)
Beispiel #29
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)
Beispiel #30
0
def main():
    parser, options, arguments = parse_options()

    # setup logging
    
    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)

    docstring, locusts = load_locustfile(locustfile)

    if options.list_commands:
        logger.info("Available Locusts:")
        for name in locusts:
            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:
        locust_classes = locusts.values()
    
    if options.show_task_ratio:
        logger.info("\n Task ratio per locust class")
        logger.info( "-" * 80)
        print_task_ratio(locust_classes)
        logger.info("\n Total task ratio")
        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)
        }
        logger.info(dumps(task_data))
        sys.exit(0)
    
    # if --master is set, make sure --no-web isn't set
    if options.master and options.no_web:
        logger.error("Locust can not run distributed with the web interface disabled (do not use --no-web and --master together)")
        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:
        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)
    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)
    
    def shutdown(code=0):
        """
        Shut down locust by firing quitting event, printing 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)

        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):
            code = 1
        shutdown(code=code)
    except KeyboardInterrupt as e:
        shutdown(0)
Beispiel #31
0
 def test_runner_reference_on_environment(self):
     env = Environment()
     runner = LocalLocustRunner(environment=env, locust_classes=[])
     self.assertEqual(env, runner.environment)