added saving of history and results and function to load and print stats about them
authorChristian Herdtweck <christian.herdtweck@intra2net.com>
Thu, 22 Jan 2015 16:21:24 +0000 (17:21 +0100)
committerChristian Herdtweck <christian.herdtweck@intra2net.com>
Thu, 22 Jan 2015 16:21:24 +0000 (17:21 +0100)
test/long_term_test.py
test/strftimedelta.py [new file with mode: 0644]

index 989a1ed..98146eb 100755 (executable)
@@ -28,6 +28,8 @@ from os.path import expanduser, dirname, isdir
 from os import mkdir, EX_OK
 from connd_state import ConndState
 #import signal
+import pickle
+from strftimedelta import strftimedelta
 
 logger_base = logging.getLogger('long_term_test')
 
@@ -655,6 +657,11 @@ def parse_args():
                                       + "using tell-connd and checks log for correct output", \
                             epilog="(c) Christian Herdtweck, Intra2net AG, 2015")
 
+    # option to show saved data
+    parser.add_argument('--show-saved-data', '-s', metavar='SAVE_FILE.pickle', \
+            default='', type=str, \
+            help='Do not run test but instead print info saved by earlier test run')
+
     # binaries
     parser.add_argument('--pingcheck-binary', '-p', metavar='PATH', \
             default=default_pingcheck_bin, \
@@ -755,15 +762,14 @@ def setup_logging(opts):
 #end: setup_logging
 
 
-def handle_sigchild(log, pinger, tester, signum, curr_frame):
-    print("\n!received sigchild!\n")
+def handle_sigchild(signum, curr_frame, log, cleanup_args):
     log.error('Received SIGCHLD')
     log.info('with args {0} and {1}'.format(signum, curr_frame))
 
-    cleanup(log, pinger, tester)
+    cleanup(*cleanup_args)
 
 
-def cleanup(log, pinger, tester, line_iter):
+def cleanup(log, pinger, tester, line_iter, save_file):
     """ the stuff from finally clause in main loop; also called from handle_sigchild """
 
     return_code = 255
@@ -838,6 +844,9 @@ def main():
 
     opts = parse_args()
 
+    if opts.show_saved_data:
+        return Tester.show_saved_data(opts.show_saved_data)
+
     base_dir = dirname(opts.output_prefix + "_test")
     if not isdir(base_dir):
         mkdir(base_dir)
@@ -853,10 +862,12 @@ def main():
         #test_version(opts.pingcheck_binary, log)
 
         config_file, n_hosts = create_conf_file(opts.output_prefix)
+        save_file = opts.output_prefix + '_save.pickle'
         log.info('created config file {0}'.format(config_file))
 
         #signal.signal(signal.SIGCHLD, \
-        #        lambda signum, curr_frame: handle_sigchild(log, pinger, tester, signum, curr_frame))
+        #        lambda signum, curr_frame: handle_sigchild(signum, curr_frame, log, \
+        #           (log, pinger, tester, line_iter, save_file) )
 
         # pingcheck subprocess
         pinger = subprocess.Popen([opts.pingcheck_binary, '--log-level', opts.pinger_log_level, \
diff --git a/test/strftimedelta.py b/test/strftimedelta.py
new file mode 100644 (file)
index 0000000..4596c2a
--- /dev/null
@@ -0,0 +1,105 @@
+#!/usr/bin/env python3
+
+""" give a nice string representation for a duration
+
+Christian Herdtweck, Intra2net, November 2014
+Licensed under GPL
+"""
+
+from datetime import timedelta
+
+# Version History
+# 24/11/14 Christian Herdtweck: started creation by copying strftimedelta
+
+
+def strftimedelta(delta, max_parts=2, only_up_to_hours=False):
+    """ nice and length-adjustable text representation of a timespan 
+
+    will output the most significant non-zero time units, e.g.
+    '2h23m50s' or '3d50s12ms' (skipping 0 minutes), or '3y63d12h'
+    or for max_parts=2: '2h23m' / '3d50s' / '3y63d'
+
+    Assumes that each year has 365 days, every day 24h, every hour 60 mins, ...
+      not accounting for leap years / leap days, changes of timezones, etc
+    
+    @delta:timedelta or anything that can be converted to float;
+       if numeric, this is interpreted as number of seconds
+    @param max_parts: precision (i.e., length) of output (default: 2)
+       set to None if always want precision down to microseconds
+    @param only_up_to_hours: set to True to never give number of days/years
+      (e.g. to get '40h' instead of '1d16h')
+      default: False
+
+    returns a string
+    """
+
+    units = '\u00B5s', 'ms', 's', 'm', 'h', 'd', 'y'
+
+    if (max_parts is None) or (max_parts < 1):
+        max_parts = 100
+
+    # get number of seconds and sign
+    if isinstance(delta, timedelta):
+        seconds = delta.total_seconds()
+    else:
+        seconds = float(delta)
+    negative = False
+    if seconds < 0:
+        negative = True
+        seconds = abs(seconds)
+
+    # split sub-second part
+    seconds, second_part = divmod(seconds, 1)
+    milliseconds, milli_part = divmod(second_part*1000, 1)
+    microseconds = int(round(milli_part*1000))
+    seconds = int(seconds)   # convert to int here --> all other variables will be int
+    vals = [microseconds, int(milliseconds), ]
+
+    # split longer units
+    minutes = hours = days = years = 0
+    if seconds > 0:
+        minutes, seconds = divmod(seconds, 60)
+    if minutes > 0:
+        hours, minutes = divmod(minutes, 60)
+    if hours > 0 and not only_up_to_hours:
+        days, hours = divmod(hours, 24)
+    if days > 0:
+        years, days = divmod(days, 365)
+    vals.append(seconds)
+    vals.append(minutes)
+    vals.append(hours)
+    vals.append(days)
+    vals.append(years)
+
+    # build string
+    str_parts = []
+    if negative:
+        str_parts.append('-')
+
+    n_used = 0
+    for val,unit in zip( reversed(vals), reversed(units) ):
+        if val == 0:
+            continue
+        str_parts.append(str(val))
+        str_parts.append(unit)
+        n_used += 1
+        if n_used >= max_parts:
+            break
+    return ''.join(str_parts)
+
+#end: strftimedelta
+
+
+
+def main():
+    """ Main function, called when running file as script; currently raises a NotImplementedError 
+    """
+    raise NotImplementedError('nothing to run here -- only a lib!')
+#end: function main
+
+
+if __name__ == '__main__':
+    main()
+
+# (created using vim -- the world's best text editor)
+