From d76e774c5060d319004cc21a36f380023b81dc5a Mon Sep 17 00:00:00 2001 From: Javier Santacruz Date: Tue, 24 Jul 2012 12:35:49 +0200 Subject: [PATCH 1/9] Avoids calling min/max with an empty sequence Floqq innovation SL. www.floqq.com --- multimechanize/results.py | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/multimechanize/results.py b/multimechanize/results.py index dd95693..ae04a64 100644 --- a/multimechanize/results.py +++ b/multimechanize/results.py @@ -159,17 +159,19 @@ def output_results(results_dir, results_file, run_time, rampup, ts_interval, use report.write_line('

Timer Summary (secs)

') + custom_len = len(custom_timer_vals) + report.write_line('') report.write_line('') report.write_line('' % ( len(custom_timer_vals), - min(custom_timer_vals), - average(custom_timer_vals), - percentile(custom_timer_vals, 80), - percentile(custom_timer_vals, 90), - percentile(custom_timer_vals, 95), - max(custom_timer_vals), - standard_dev(custom_timer_vals) + min(custom_timer_vals) if custom_len else 0, + average(custom_timer_vals) if custom_len else 0, + percentile(custom_timer_vals, 80) if custom_len else 0, + percentile(custom_timer_vals, 90) if custom_len else 0, + percentile(custom_timer_vals, 95) if custom_len else 0, + max(custom_timer_vals) if custom_len else 0, + standard_dev(custom_timer_vals) if custom_len else 0 )) report.write_line('
countminavg80pct90pct95pctmaxstdev
%i%.3f%.3f%.3f%.3f%.3f%.3f%.3f
') From e313d2801814d0fe02ddfafe89982c6182fd5fc8 Mon Sep 17 00:00:00 2001 From: Javier Santacruz Date: Tue, 24 Jul 2012 12:36:55 +0200 Subject: [PATCH 2/9] Fixes IndexError when splitting empty points sets Floqq innovation SL. www.floqq.com --- multimechanize/results.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/multimechanize/results.py b/multimechanize/results.py index ae04a64..833757c 100644 --- a/multimechanize/results.py +++ b/multimechanize/results.py @@ -316,6 +316,9 @@ def __init__(self, request_num, elapsed_time, epoch_secs, user_group_name, trans def split_series(points, interval): + if not points: + return points + offset = points[0][0] maxval = int((points[-1][0] - offset) // interval) vals = defaultdict(list) From 7f9869c98d586025ab9e15ceafead034c70814ea Mon Sep 17 00:00:00 2001 From: Javier Santacruz Date: Tue, 24 Jul 2012 12:39:04 +0200 Subject: [PATCH 3/9] Ignore invalid scripts instead of firing an exception A message will be displayed showing the error with the script. This is useful if the user has extra code in the scripts directory, (like a settings.py file), that is not intended to be executed by multi-mechanize. Floqq innovation SL. www.floqq.com --- multimechanize/script_loader.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/multimechanize/script_loader.py b/multimechanize/script_loader.py index 105f79b..5d8907a 100644 --- a/multimechanize/script_loader.py +++ b/multimechanize/script_loader.py @@ -52,7 +52,8 @@ def ensure_module_valid(cls, module): """ problem = cls.check_module_invalid(module) if problem: - raise InvalidScriptError, problem + sys.stderr.write("Cannot import: {0}: {1}\n" + .format(module, problem)) class ScriptLoader(object): """Utility class to load scripts as python modules.""" From dd4ba3c3fb4455c57b751a58209ac39931a15228 Mon Sep 17 00:00:00 2001 From: Javier Santacruz Date: Tue, 24 Jul 2012 12:41:54 +0200 Subject: [PATCH 4/9] Changes string path composing with os.path.join string path composing is *dangerous* and should not be used: - Doesn't properly handle the 'separator' char in different OSs - Doesn't avoid repeated slashes (//) that might not be good in certain OSs - Doesn't handle absolute-relative paths well /root/ + /root/single = /root/root/single instead of /root + /root/single = /root/single Floqq innovation SL. www.floqq.com --- multimechanize/core.py | 4 ++-- multimechanize/results.py | 4 ++-- multimechanize/utilities/run.py | 11 +++++++---- 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/multimechanize/core.py b/multimechanize/core.py index 285c76a..1b32778 100644 --- a/multimechanize/core.py +++ b/multimechanize/core.py @@ -15,13 +15,13 @@ import time from multimechanize.script_loader import ScriptLoader -import os.path + def init(projects_dir, project_name): """ Sanity check that all test scripts can be loaded. """ - scripts_path = '%s/%s/test_scripts' % (projects_dir, project_name) + scripts_path = os.path.join(projects_dir, project_name, 'test_scripts') if not os.path.exists(scripts_path): sys.stderr.write('\nERROR: can not find project: %s\n\n' % project_name) sys.exit(1) diff --git a/multimechanize/results.py b/multimechanize/results.py index 833757c..7ad83de 100644 --- a/multimechanize/results.py +++ b/multimechanize/results.py @@ -6,7 +6,7 @@ # This file is part of Multi-Mechanize | Performance Test Framework # - +import os import time from collections import defaultdict import graph @@ -16,7 +16,7 @@ def output_results(results_dir, results_file, run_time, rampup, ts_interval, user_group_configs=None, xml_reports=False): - results = Results(results_dir + results_file, run_time) + results = Results(os.path.join(results_dir, results_file), run_time) report = reportwriter.Report(results_dir) diff --git a/multimechanize/utilities/run.py b/multimechanize/utilities/run.py index f667414..af6d7bd 100755 --- a/multimechanize/utilities/run.py +++ b/multimechanize/utilities/run.py @@ -77,7 +77,8 @@ def run_test(project_name, cmd_opts, remote_starter=None): run_time, rampup, results_ts_interval, console_logging, progress_bar, results_database, post_run_script, xml_report, user_group_configs = configure(project_name, cmd_opts) run_localtime = time.localtime() - output_dir = '%s/%s/results/results_%s' % (cmd_opts.projects_dir, project_name, time.strftime('%Y.%m.%d_%H.%M.%S/', run_localtime)) + output_dir = os.path.join(cmd_opts.projects_dir, project_name, 'results', + 'results_' + time.strftime('%Y.%m.%d_%H.%M.%S/', run_localtime)) # this queue is shared between all processes/threads queue = multiprocessing.Queue() @@ -168,8 +169,10 @@ def run_test(project_name, cmd_opts, remote_starter=None): def rerun_results(project_name, cmd_opts, results_dir): - output_dir = '%s/%s/results/%s/' % (cmd_opts.projects_dir, project_name, results_dir) + output_dir = os.path.join(cmd_opts.projects_dir, project_name, results_dir) + saved_config = '%s/config.cfg' % output_dir + saved_config = os.path.join(output_dir, 'config.cfg') run_time, rampup, results_ts_interval, console_logging, progress_bar, results_database, post_run_script, xml_report, user_group_configs = configure(project_name, cmd_opts, config_file=saved_config) print '\n\nanalyzing results...\n' results.output_results(output_dir, 'results.csv', run_time, rampup, results_ts_interval, user_group_configs, xml_report) @@ -183,8 +186,8 @@ def rerun_results(project_name, cmd_opts, results_dir): def configure(project_name, cmd_opts, config_file=None): user_group_configs = [] config = ConfigParser.ConfigParser() - if config_file is None: - config_file = '%s/%s/config.cfg' % (cmd_opts.projects_dir, project_name) + config_file = os.path.join(cmd_opts.projects_dir, + project_name, 'config.cfg') config.read(config_file) for section in config.sections(): if section == 'global': From ed71ea3193c2e10666ee5641b398ed59ec776ccd Mon Sep 17 00:00:00 2001 From: Javier Santacruz Date: Tue, 24 Jul 2012 12:45:41 +0200 Subject: [PATCH 5/9] Avoid repeated code in the progress bar Floqq innovation SL. www.floqq.com --- multimechanize/utilities/run.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/multimechanize/utilities/run.py b/multimechanize/utilities/run.py index af6d7bd..e84645b 100755 --- a/multimechanize/utilities/run.py +++ b/multimechanize/utilities/run.py @@ -124,10 +124,8 @@ def run_test(project_name, cmd_opts, remote_starter=None): while [user_group for user_group in user_groups if user_group.is_alive()] != []: if progress_bar: - if sys.platform.startswith('win'): - print 'waiting for all requests to finish...\r', - else: - print 'waiting for all requests to finish...\r' + print 'waiting for all requests to finish...\r', + if not sys.platform.startswith('win'): sys.stdout.write(chr(27) + '[A' ) time.sleep(.5) From 58984e150062d465e838cb82fd3b2046b5dbf3a5 Mon Sep 17 00:00:00 2001 From: pa_kt Date: Wed, 29 Aug 2012 13:54:50 +0200 Subject: [PATCH 6/9] Pass pid and tid to Transcation class --- multimechanize/core.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/multimechanize/core.py b/multimechanize/core.py index 1b32778..f1305bf 100644 --- a/multimechanize/core.py +++ b/multimechanize/core.py @@ -95,7 +95,10 @@ def __init__(self, queue, process_num, thread_num, start_time, run_time, def run(self): elapsed = 0 - trans = self.script_module.Transaction() + try: + trans = self.script_module.Transaction() + except TypeError, e: + trans = self.script_module.Transaction(self.process_num, self.thread_num) trans.custom_timers = {} # scripts have access to these vars, which can be useful for loading unique data From a61d1f816e0eb2d693bf39f435050a1af94d9edf Mon Sep 17 00:00:00 2001 From: pa_kt Date: Tue, 4 Sep 2012 11:58:03 +0200 Subject: [PATCH 7/9] don't validate all scripts --- multimechanize/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/multimechanize/core.py b/multimechanize/core.py index f1305bf..4c58354 100644 --- a/multimechanize/core.py +++ b/multimechanize/core.py @@ -26,7 +26,7 @@ def init(projects_dir, project_name): sys.stderr.write('\nERROR: can not find project: %s\n\n' % project_name) sys.exit(1) # -- NORMAL-CASE: Ensure that all scripts can be loaded (at program start). - ScriptLoader.load_all(scripts_path, validate=True) + ScriptLoader.load_all(scripts_path, validate=False) def load_script(script_file): """ From d0aac52dd4d4d490b5657297371531847c5aadbb Mon Sep 17 00:00:00 2001 From: pa_kt Date: Wed, 5 Sep 2012 12:46:55 +0200 Subject: [PATCH 8/9] good pip scripts --- Scripts/README | 3 +++ Scripts/multimech-gridgui-script.py | 10 ++++++++++ Scripts/multimech-newproject-script.py | 10 ++++++++++ Scripts/multimech-run-script.py | 10 ++++++++++ multimechanize/core.py | 2 +- 5 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 Scripts/README create mode 100644 Scripts/multimech-gridgui-script.py create mode 100644 Scripts/multimech-newproject-script.py create mode 100644 Scripts/multimech-run-script.py diff --git a/Scripts/README b/Scripts/README new file mode 100644 index 0000000..eb774b3 --- /dev/null +++ b/Scripts/README @@ -0,0 +1,3 @@ +pip installs these scripts without including +if __name__=="__main__": +which is bad. Copy these files to PYTHON_DIR\Scripts\ diff --git a/Scripts/multimech-gridgui-script.py b/Scripts/multimech-gridgui-script.py new file mode 100644 index 0000000..156e982 --- /dev/null +++ b/Scripts/multimech-gridgui-script.py @@ -0,0 +1,10 @@ +#!c:\python27\python.exe +# EASY-INSTALL-ENTRY-SCRIPT: 'multi-mechanize==1.2.0.1','console_scripts','multimech-gridgui' +__requires__ = 'multi-mechanize==1.2.0.1' +import sys +from pkg_resources import load_entry_point + +if __name__ == '__main__': + sys.exit( + load_entry_point('multi-mechanize==1.2.0.1', 'console_scripts', 'multimech-gridgui')() + ) diff --git a/Scripts/multimech-newproject-script.py b/Scripts/multimech-newproject-script.py new file mode 100644 index 0000000..8368503 --- /dev/null +++ b/Scripts/multimech-newproject-script.py @@ -0,0 +1,10 @@ +#!c:\python27\python.exe +# EASY-INSTALL-ENTRY-SCRIPT: 'multi-mechanize==1.2.0.1','console_scripts','multimech-newproject' +__requires__ = 'multi-mechanize==1.2.0.1' +import sys +from pkg_resources import load_entry_point + +if __name__ == '__main__': + sys.exit( + load_entry_point('multi-mechanize==1.2.0.1', 'console_scripts', 'multimech-newproject')() + ) diff --git a/Scripts/multimech-run-script.py b/Scripts/multimech-run-script.py new file mode 100644 index 0000000..987d2a1 --- /dev/null +++ b/Scripts/multimech-run-script.py @@ -0,0 +1,10 @@ +#!c:\python27\python.exe +# EASY-INSTALL-ENTRY-SCRIPT: 'multi-mechanize==1.2.0.1','console_scripts','multimech-run' +__requires__ = 'multi-mechanize==1.2.0.1' +import sys +from pkg_resources import load_entry_point + +if __name__ == '__main__': + sys.exit( + load_entry_point('multi-mechanize==1.2.0.1', 'console_scripts', 'multimech-run')() + ) diff --git a/multimechanize/core.py b/multimechanize/core.py index 4c58354..f1305bf 100644 --- a/multimechanize/core.py +++ b/multimechanize/core.py @@ -26,7 +26,7 @@ def init(projects_dir, project_name): sys.stderr.write('\nERROR: can not find project: %s\n\n' % project_name) sys.exit(1) # -- NORMAL-CASE: Ensure that all scripts can be loaded (at program start). - ScriptLoader.load_all(scripts_path, validate=False) + ScriptLoader.load_all(scripts_path, validate=True) def load_script(script_file): """ From 4d0666d11f239a67c383ef2bed26b5dfaacff104 Mon Sep 17 00:00:00 2001 From: pa_kt Date: Wed, 5 Sep 2012 13:07:01 +0200 Subject: [PATCH 9/9] no transactions in time (assert) --- multimechanize/results.py | 1 + 1 file changed, 1 insertion(+) diff --git a/multimechanize/results.py b/multimechanize/results.py index 7ad83de..bcaadd5 100644 --- a/multimechanize/results.py +++ b/multimechanize/results.py @@ -251,6 +251,7 @@ def __init__(self, results_file_name, run_time): self.uniq_user_group_names = set() self.resp_stats_list = self.__parse_file() + assert self.resp_stats_list, "no transactions completed in the specified time" self.epoch_start = self.resp_stats_list[0].epoch_secs self.epoch_finish = self.resp_stats_list[-1].epoch_secs