From 3a7db96e78cb8556600b72821d66f9513619061b Mon Sep 17 00:00:00 2001 From: Ondrej Mular Date: Wed, 20 Apr 2016 15:42:11 +0200 Subject: [PATCH] regression testing: code cleanup --- fence/agents/lib/fencing_pycurl.py.py | 63 ++++-- tests/actions.d/sleep.cfg | 2 - tests/actions.d/status.cfg | 2 +- tests/binmitm.py | 111 ++++++---- tests/create_test_data.py | 230 +++++++++++--------- tests/fence_tests_lib.py | 266 ++++++++++++++++++------ tests/run_tests.py | 289 ++++++++++++++++---------- 7 files changed, 627 insertions(+), 336 deletions(-) delete mode 100644 tests/actions.d/sleep.cfg diff --git a/fence/agents/lib/fencing_pycurl.py.py b/fence/agents/lib/fencing_pycurl.py.py index 23d7a51c6..a3f237705 100644 --- a/fence/agents/lib/fencing_pycurl.py.py +++ b/fence/agents/lib/fencing_pycurl.py.py @@ -1,6 +1,3 @@ -__author__ = 'Ondrej Mular ' -__all__ = ["FencingPyCurl"] - import pycurl import sys import atexit @@ -10,6 +7,8 @@ import logging import pprint +__all__ = ["FencingPyCurl"] + ## do not add code here. #BEGIN_VERSION_GENERATION RELEASE_VERSION = "" @@ -17,7 +16,8 @@ BUILD_DATE = "" #END_VERSION_GENERATION -class FencingPyCurl(): + +class FencingPyCurl: active = False input_file = None output_file = None @@ -29,7 +29,10 @@ class FencingPyCurl(): pycurl_obj = None def __init__(self): - if not FencingPyCurl.active and (FencingPyCurl.input_file or FencingPyCurl.output_file): + if ( + not FencingPyCurl.active and + (FencingPyCurl.input_file or FencingPyCurl.output_file) + ): FencingPyCurl.active = True logging.debug("FencingPyCurl is active now") if FencingPyCurl.active: @@ -48,7 +51,11 @@ def __init__(self): with open(FencingPyCurl.input_file, "r") as f: FencingPyCurl.actions = json.load(f) except Exception as e: - logging.debug("Reading input file (%s) failed: %s" % (FencingPyCurl.input_file, e.message)) + logging.debug( + "Reading input file '{file}' failed: {msg}".format( + file=FencingPyCurl.input_file, msg=e.message + ) + ) if FencingPyCurl.output_file: logging.debug("output file detected") @@ -68,14 +75,17 @@ def setopt(self, opt, value): return self.pycurl_obj.setopt(opt, value) def perform(self): + req_ind = FencingPyCurl.request_index + actions = FencingPyCurl.actions if FencingPyCurl.active: if FencingPyCurl.input_file: perform_start = time.time() - if self.options["request"] == FencingPyCurl.actions[FencingPyCurl.request_index]["request"]: - self.options["response"] = FencingPyCurl.actions[FencingPyCurl.request_index]["response"] + if self.options["request"] == actions[req_ind]["request"]: + self.options["response"] = actions[req_ind]["response"] if self.write_function: self.write_function(self.options["response"]["output"]) - diff = FencingPyCurl.actions[FencingPyCurl.request_index]["time"]["perform_duration"] - (time.time() - perform_start) + duration = actions[req_ind]["time"]["perform_duration"] + diff = duration - (time.time() - perform_start) if diff > 0: logging.debug("sleeping for: %s" % str(diff)) time.sleep(diff) @@ -84,15 +94,17 @@ def perform(self): print "Request:" pprint.pprint(self.options["request"]) print "Expected:" - pprint.pprint(FencingPyCurl.actions[FencingPyCurl.request_index]["request"]) + pprint.pprint(actions[req_ind]["request"]) raise Exception("Invalid request") else: + response = self.options["response"] start_time = time.time() self.pycurl_obj.perform() - self.options["time"]["perform_duration"] = FencingPyCurl.last_request_time - start_time - self.options["response"]["output"] = self.output_buffer.getvalue() + duration = FencingPyCurl.last_request_time - start_time + self.options["time"]["perform_duration"] = duration + response["output"] = self.output_buffer.getvalue() if self.write_function: - self.write_function(self.options["response"]["output"]) + self.write_function(response["output"]) if FencingPyCurl.output_file: FencingPyCurl.actions.append(self.options) FencingPyCurl.request_index += 1 @@ -124,20 +136,32 @@ def close(self): @staticmethod def save_log_to_file(): if FencingPyCurl.output_file and FencingPyCurl.actions: - logging.debug("Writing log to file: %s" % FencingPyCurl.output_file) + logging.debug( + "Writing log to file: {0}".format(FencingPyCurl.output_file) + ) try: with open(FencingPyCurl.output_file, "w") as f: - json.dump(FencingPyCurl.actions, f, sort_keys=True, indent=4, separators=(',', ': ')) + json.dump( + FencingPyCurl.actions, + f, + sort_keys=True, + indent=4, + separators=(',', ': ') + ) except Exception as e: - logging.debug("Writing log to file (%s) failed: %s" % (FencingPyCurl.output_file, e.message)) + logging.debug( + "Writing log to file '{file}' failed: {msg}".format( + file=FencingPyCurl.output_file, msg=e.message + ) + ) def get_and_remove_arg(arg, has_value=True): - logging.debug("Getting arg: %s (has_value: %s)" % (arg, str(has_value))) + logging.debug("Getting arg: '{0}'".format(arg)) if not has_value: if arg in sys.argv: sys.argv.remove(arg) - logging.debug("%s: True" % arg) + logging.debug(arg + ": True") return True if arg in sys.argv: index = sys.argv.index(arg) @@ -145,10 +169,11 @@ def get_and_remove_arg(arg, has_value=True): if len(sys.argv) > index: value = sys.argv[index] sys.argv.remove(value) - logging.debug("%s: %s" % (arg, value)) + logging.debug("{arg}: {val}".format(arg=arg, val=value)) return value return None + FencingPyCurl.input_file = get_and_remove_arg("--fencing_pycurl-log-in") FencingPyCurl.output_file = get_and_remove_arg("--fencing_pycurl-log-out") diff --git a/tests/actions.d/sleep.cfg b/tests/actions.d/sleep.cfg deleted file mode 100644 index c0fad72ca..000000000 --- a/tests/actions.d/sleep.cfg +++ /dev/null @@ -1,2 +0,0 @@ -name = "Pure Sleep" -actions = [ { "command" : "sleep(1)", "return_code" : "^0$" }, { "command" : "sleep(3)", "return_code" : "^0$" }, { "command" : "sleep(5)", "return_code" : "^0$" } ] diff --git a/tests/actions.d/status.cfg b/tests/actions.d/status.cfg index 760f94bd5..e2701a6f5 100644 --- a/tests/actions.d/status.cfg +++ b/tests/actions.d/status.cfg @@ -1,2 +1,2 @@ name = "Simple Status" -actions = [ { "command" : "status", "return_code" : "^[02]$" }, { "command" : "sleep(1)", "return_code" : "^0$" } ] +actions = [ { "command" : "status", "return_code" : "^[02]$" }] diff --git a/tests/binmitm.py b/tests/binmitm.py index e4fb7026a..c1c80e38c 100755 --- a/tests/binmitm.py +++ b/tests/binmitm.py @@ -1,7 +1,5 @@ #!/usr/bin/python -__author__ = 'Ondrej Mular ' - import sys import os import subprocess @@ -9,10 +7,14 @@ import json import time -INPUT_FILE = os.environ["BINMITM_INPUT"] if "BINMITM_INPUT" in os.environ else None -OUTPUT_FILE = os.environ["BINMITM_OUTPUT"] if "BINMITM_OUTPUT" in os.environ else None -COUNTER_FILE = os.environ["BINMITM_COUNTER_FILE"] if "BINMITM_COUNTER_FILE" in os.environ else ".binmitm_counter" -ENV_VARS = os.environ["BINMITM_ENV"].split(",") if "BINMITM_ENV" in os.environ else [] +INPUT_FILE = os.environ["BINMITM_INPUT"]\ + if "BINMITM_INPUT" in os.environ else None +OUTPUT_FILE = os.environ["BINMITM_OUTPUT"]\ + if "BINMITM_OUTPUT" in os.environ else None +COUNTER_FILE = os.environ["BINMITM_COUNTER_FILE"]\ + if "BINMITM_COUNTER_FILE" in os.environ else ".binmitm_counter" +ENV_VARS = os.environ["BINMITM_ENV"].split(",")\ + if "BINMITM_ENV" in os.environ else [] IGNORE_TIMING = "BINMITM_IGNORE_TIMING" in os.environ DEBUG = "BINMITM_DEBUG" in os.environ @@ -22,18 +24,24 @@ def log_debug(msg): logging.error(msg) -def exit(ret): +def _exit(ret): if COUNTER_FILE and os.path.isfile(COUNTER_FILE): try: os.remove(COUNTER_FILE) except Exception as e: - log_debug("Unable to delete counter file (%s): %s" % (COUNTER_FILE, e.message)) + log_debug("Unable to delete counter file ({0}): {1}".format( + COUNTER_FILE, e.message + )) try: with open(COUNTER_FILE, "w") as f: f.write("0\n") - log_debug("0 written into counter file (%s)" % COUNTER_FILE) + log_debug( + "0 written into counter file ({0})".format(COUNTER_FILE) + ) except Exception as e: - log_debug("Unable to write 0 to counter file (%s): %s" % (COUNTER_FILE, e.message)) + log_debug("Unable to write 0 to counter file ({0}): {1}".format( + COUNTER_FILE, e.message + )) sys.exit(ret) @@ -45,16 +53,20 @@ def get_count(max_count): count = int(f.readline().strip()) f.seek(0) f.truncate() - f.write("%d\n" % ((count+1)%max_count)) + f.write("{0}\n".format((count+1) % max_count)) except Exception as e: - log_debug("Unable to read/write from/to '%s': %s" % (COUNTER_FILE, e.message)) + log_debug("Unable to read/write from/to '{0}': {1}".format( + COUNTER_FILE, e.message + )) else: if max_count != 1: try: with open(COUNTER_FILE, "w") as f: f.write("1\n") except Exception as e: - log_debug("Unable to write to '%s': %s" % (COUNTER_FILE, e.message)) + log_debug("Unable to write to '{0}': {1}".format( + COUNTER_FILE, e.message + )) return count @@ -62,24 +74,31 @@ def record(argv): output = OUTPUT_FILE and not INPUT_FILE env = os.environ.copy() - cur_output = {} - cur_output["request"] = {} - cur_output["response"] = {} - cur_output["time"] = {} - cur_output["request"]["argv"] = argv - cur_output["request"]["env"] = {} + cur_output = { + "request": { + "argv": argv, + "env": {} + }, + "response": {}, + "time": {} + } for e in ENV_VARS: if e in env: cur_output["request"]["env"][e] = env[e] proc_start_time = time.time() + process = None try: - process = subprocess.Popen(argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) + process = subprocess.Popen( + argv, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env + ) except OSError as e: - log_debug("Unable to run command '%s': %s" % (" ".join(argv), e.message)) - exit(127) + log_debug("Unable to run command '{0}': {1}".format( + " ".join(argv), e.message + )) + _exit(127) status = process.wait() cur_output["time"]["perform_duration"] = time.time() - proc_start_time @@ -104,7 +123,10 @@ def record(argv): try: output_values = json.load(f) except: - log_debug("Parsing output file '%s' failed. It is considered as empty." % OUTPUT_FILE) + log_debug( + "Parsing output file '{0}' failed. It is " + "considered as empty.".format(OUTPUT_FILE) + ) output_values.append(cur_output) f.truncate() @@ -113,11 +135,10 @@ def record(argv): else: with open(OUTPUT_FILE, "w") as f: json.dump([cur_output], f, indent=4) - except ValueError as e: - log_debug("Unable to parse output file: %s" % e.message) - except IOError as e: - log_debug("Unable to open output file '%s': %s" % (OUTPUT_FILE, e.message)) - + except (IOError, ValueError) as e: + log_debug("Unable to store data to file '{0}': {1}".format( + OUTPUT_FILE, e.message + )) sys.exit(status) @@ -129,37 +150,46 @@ def replay(argv): try: with open(INPUT_FILE) as f: input_values = json.load(f) - except ValueError as e: - log_debug("Unable to parse input file: %s" % e.message) - except IOError as e: - log_debug("Unable to open input file '%s': %s" % (INPUT_FILE, e.message)) + except (ValueError, IOError) as e: + log_debug("Unable to parse input file '{0}': {1}".format( + OUTPUT_FILE, e.message + )) if not input_values: log_debug("Empty input") - exit(127) + _exit(127) input_number = get_count(len(input_values)) if input_number >= len(input_values): log_debug("Unable to get current input") - exit(127) + _exit(127) cur_input = input_values[input_number] if cur_input["request"]["argv"] != argv: - log_debug("Expected different command (Expected: '%s', Given: '%s')" % (" ".join(cur_input["request"]["argv"]), " ".join(argv))) - exit(127) + log_debug( + "Expected different command (Expected: '{0}', Given: '{1}')".format( + " ".join(cur_input["request"]["argv"]), + " ".join(argv) + ) + ) + _exit(127) env.update(cur_input["request"]["env"]) sys.stderr.write(cur_input["response"]["stderr"]) sys.stdout.write(cur_input["response"]["stdout"]) if not IGNORE_TIMING: - time_left = cur_input["time"]["perform_duration"] - (time.time() - start_time) + time_left = cur_input["time"]["perform_duration"] - ( + time.time() - start_time + ) if time_left > 0: - log_debug("Sleeping for %f s" % time_left) + log_debug("Sleeping for {0} s".format(time_left)) time.sleep(time_left) else: - log_debug("Uooops! We are runnig %f s longer." % abs(time_left)) + log_debug("Uooops! We are running {0} s longer.".format( + abs(time_left) + )) sys.exit(cur_input["response"]["return_code"]) @@ -167,7 +197,7 @@ def replay(argv): def main(argv): if not argv: print "No command to run" - exit(127) + _exit(127) if INPUT_FILE: replay(argv) else: @@ -176,4 +206,3 @@ def main(argv): if __name__ == "__main__": main(sys.argv[1:]) - diff --git a/tests/create_test_data.py b/tests/create_test_data.py index f579a5103..d3993410d 100755 --- a/tests/create_test_data.py +++ b/tests/create_test_data.py @@ -1,17 +1,18 @@ #!/usr/bin/python -tt -__author__ = 'Ondrej Mular ' - -from configobj import ConfigObj -from time import sleep import sys -import subprocess -import shlex import logging import os import re +from configobj import ConfigObj + import fence_tests_lib as ftl + +class RecordException(Exception): + pass + + VERBOSE = not set(["-v", "--verbose"]).isdisjoint(sys.argv) avail_opt = { @@ -48,68 +49,71 @@ "longopt": "force", "description": "force rewrite existing log file", "default": False + }, + "port": { + "getopt": "p:", + "longopt": "port", + "description": + "Local port for communication between agent and mitmproxy", + "default": "4242" } } class RecordTestData(object): - - def __init__(self, device_cfg, action_cfg, force=False): + def __init__( + self, device_cfg, action_cfg, local_port, force=False + ): + self.local_port = local_port self.device_cfg = device_cfg self.action_cfg = action_cfg - self.device_config = ConfigObj(device_cfg, unrepr=True) - self.action_config = ConfigObj(action_cfg, unrepr=True) - logs_path = os.path.join(ftl.MITM_LOGS_PATH, self.device_config["agent"][6:]) - if "subdir" in self.device_config: - logs_path = os.path.join(logs_path, self.device_config["subdir"]) - self.log = os.path.join(logs_path, "%s.log" % ftl.get_basename(action_cfg)) + self.device_cfg_obj = ConfigObj(device_cfg, unrepr=True) + self.action_cfg_obj = ConfigObj(action_cfg, unrepr=True) + logs_path = os.path.join( + ftl.MITM_LOGS_PATH, self.device_cfg_obj["agent"][6:] + ) + if "subdir" in self.device_cfg_obj: + logs_path = os.path.join(logs_path, self.device_cfg_obj["subdir"]) + self.log = os.path.join( + logs_path, "{name}.log".format(name=ftl.get_basename(action_cfg)) + ) + logging.debug("Log file: {log}".format(log=self.log)) + if os.path.isfile(self.log) and not force: - raise Exception("Log file already exists. Use --force option to overwrite it.") - elif os.path.isfile(self.log): - os.remove(self.log) + if force: + os.remove(self.log) + else: + raise RecordException( + "Log file already exists. Use --force to overwrite it." + ) + self.mitm_process = None self.params = "" self.env = {} - self.type = self.device_config["agent_type"].lower() - - - def setUp_MITM(self): - cmd, env = ftl.get_MITM_record_cmd(self.device_cfg, self.log) - if cmd: - logging.debug("Executing: %s", cmd) - try: - # Try to start replay server - process = subprocess.Popen(shlex.split(cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) - except OSError as e: - logging.error("Unable to start record server: %s" % e.message) - raise - sleep(1) # wait for replay server - if process.poll() is not None: # check if replay server is running correctly - raise Exception("Replay server is not running correctly.") - self.mitm_process = process - - def tearDown_MITM(self): - if self.mitm_process: - process = self.mitm_process - # if server is still alive after test, kill it - if process.poll() is None: - try: - # race condition, process can exit between checking and killing process - process.kill() - except Exception: - pass - pipe_stdout, pipe_stderr = process.communicate() - process.stdout.close() - process.stderr.close() - logging.debug("Record server STDOUT:\n%s\nRecord server STDERR:\n%s", str(pipe_stdout), str(pipe_stderr)) - - def setUp_pycurl(self): - self.params = "--fencing_pycurl-log-out %s" % self.log - - def tearDown_pycurl(self): + self.type = self.device_cfg_obj["agent_type"].lower() + + def set_up_mitm(self): + self.mitm_process = ftl.start_mitm_server( + *ftl.get_mitm_record_cmd( + self.device_cfg_obj, self.log, self.local_port + ) + ) + + if "ipaddr" in self.device_cfg_obj["options"]: + self.device_cfg_obj["options"]["ipaddr"][0] = "localhost" + if "ipport" in self.device_cfg_obj["options"]: + self.device_cfg_obj["options"]["ipport"][0] = self.local_port + + def tear_down_mitm(self): + ftl.stop_mitm_server(self.mitm_process) + + def set_up_pycurl(self): + self.params = "--fencing_pycurl-log-out {log}".format(log=self.log) + + def tear_down_pycurl(self): pass - def setUp_binmitm(self): + def set_up_binmitm(self): cf = os.path.abspath(ftl.BINMITM_COUNTERFILE) if os.path.exists(cf): os.remove(cf) @@ -117,71 +121,88 @@ def setUp_binmitm(self): del os.environ["BINMITM_INPUT"] if "BINMITM_DEBUG" in os.environ: del os.environ["BINMITM_DEBUG"] - self.env = {} - self.env["BINMITM_COUNTER_FILE"] = ftl.BINMITM_COUNTERFILE - self.env["BINMITM_OUTPUT"] = self.log + self.env = { + "BINMITM_COUNTER_FILE": ftl.BINMITM_COUNTERFILE, + "BINMITM_OUTPUT": self.log + } - def tearDown_binmitm(self): + def tear_down_binmitm(self): cf = os.path.abspath(ftl.BINMITM_COUNTERFILE) if os.path.exists(cf): os.remove(cf) - def setUp(self): - type = self.type - if type == "mitmproxy": - self.setUp_MITM() - elif type =="pycurl": - self.setUp_pycurl() - elif type == "binmitm": - self.setUp_binmitm() - - def tearDown(self): - type = self.type - if type == "mitmproxy": - self.tearDown_MITM() - elif type =="pycurl": - self.tearDown_pycurl() - elif type == "binmitm": - self.tearDown_binmitm() + def set_up(self): + if self.type == "mitmproxy": + self.set_up_mitm() + elif self.type == "pycurl": + self.set_up_pycurl() + elif self.type == "binmitm": + self.set_up_binmitm() + + def tear_down(self): + if self.type == "mitmproxy": + self.tear_down_mitm() + elif self.type == "pycurl": + self.tear_down_pycurl() + elif self.type == "binmitm": + self.tear_down_binmitm() def record(self): - self.setUp() + self.set_up() success = True - actions = self.action_config + actions = self.action_cfg_obj for action in actions["actions"]: if not success: break - cmd, stdin, env = ftl._prepare_command(self.device_config, self.params) + cmd, stdin, env = ftl.prepare_command( + self.device_cfg_obj, self.params + ) + env.update(self.env) - cmd += " -o %s"% (action["command"]) + cmd += " -o {action}".format(action=(action["command"])) status, stdout, stderr = ftl.run_agent(cmd, stdin, env) - logging.debug("AGENT EXITCODE: %s" % str(status)) - logging.debug("AGENT STDOUT: %s" % stdout) - logging.debug("AGENT STDERRT: %s" % stderr) + logging.debug("AGENT EXITCODE: {0}".format(str(status))) + logging.debug("AGENT STDOUT: {0}".format(stdout)) + logging.debug("AGENT STDERR: {0}".format(stderr)) - success = success and bool(re.search(action["return_code"], str(status), re.IGNORECASE)) + success = success and bool( + re.search(action["return_code"], str(status), re.IGNORECASE) + ) if not success: - logging.error("EXITCODE: %s (expected: %s)" % (str(status), re.search(action["return_code"]))) - - self.tearDown() + logging.error( + "EXITCODE: {actual} (expected: {expected})".format( + actual=str(status), + expected=action["return_code"] + ) + ) + + self.tear_down() return success def get_device_cfg_path(device): - device_cfg = os.path.join(ftl.DEVICES_PATH, "%s.cfg" % device) + device_cfg = os.path.join( + ftl.DEVICES_PATH, "{name}.cfg".format(name=device) + ) if not os.path.isfile(device_cfg): - raise Exception("Device config '%s' not found." % device_cfg) + raise RecordException( + "Device config '{cfg}' not found.".format(cfg=device_cfg) + ) return device_cfg def get_action_cfg_path(action): - action_cfg = os.path.join(ftl.ACTIONS_PATH, "%s.cfg" % action) + action_cfg = os.path.join( + ftl.ACTIONS_PATH, "{name}.cfg".format(name=action) + ) if not os.path.isfile(action_cfg): - raise Exception("Action config '%s' not found." % action_cfg) + raise RecordException( + "Action config '{cfg}' not found.".format(cfg=action_cfg) + ) return action_cfg @@ -194,7 +215,11 @@ def main(): opt = ftl.get_options(avail_opt) if "--help" in opt: - ftl.show_help(avail_opt, "This program can create testing data for MITM tests of fence-agents.") + ftl.show_help( + avail_opt, + "This program can create testing data for MITM tests of " + "fence-agents." + ) sys.exit(0) if opt["--device"] is None: @@ -212,12 +237,15 @@ def main(): if opt["--test-config"]: config = ConfigObj(device_cfg, unrepr=True) - cmd, stdin, env = ftl._prepare_command(config) + cmd, stdin, env = ftl.prepare_command(config) cmd += " -o status" status, stdout, stderr = ftl.run_agent(cmd, stdin, env) if status != 0 and status != 2: - logging.error("Cannot obtain status:\nRETURNCODE: %s\nSTDOUT:\n%s\nSTDERR:\n%s\n" % (str(status), stdout, stderr)) + logging.error("Cannot obtain status)") + logging.error("Agent RETURNCODE: {0}".format(str(status))) + logging.error("Agent STDOUT: {0}".format(stdout)) + logging.error("Agent STDERR: {0}".format(stdout)) sys.exit(1) print stdout, @@ -226,9 +254,14 @@ def main(): action_cfg = get_action_cfg_path(opt["--action"]) try: - status = RecordTestData(device_cfg, action_cfg, opt["--force"]).record() - except Exception as e: - logging.error(e.message) + status = RecordTestData( + device_cfg, + action_cfg, + opt["--port"], + opt["--force"] + ).record() + except (ftl.LibException, RecordException) as e: + logging.error(str(e)) logging.error("Obtaining testing data failed.") sys.exit(1) @@ -237,5 +270,6 @@ def main(): sys.exit(1) print "Obtaining log file was successful." + if __name__ == "__main__": - main() \ No newline at end of file + main() diff --git a/tests/fence_tests_lib.py b/tests/fence_tests_lib.py index 039fe62d2..7d9c562ff 100644 --- a/tests/fence_tests_lib.py +++ b/tests/fence_tests_lib.py @@ -1,85 +1,136 @@ -__author__ = 'Ondrej Mular ' -__all__ = ["get_MITM_replay_cmd", "get_agent_path", "_prepare_command", "run_agent", - "get_basename", "METHODS", "ACTIONS_PATH", "BINMITM_COUNTERFILE", - "FENCING_LIB_PATH", "DEVICES_PATH", "MITM_LOGS_PATH", "MITM_PROXY_PATH" - "show_help", "get_options", "get_MITM_record_cmd","get_and_remove_arg"] - - -from pipes import quote import sys import subprocess import shlex import logging import os import getopt +from pipes import quote +from time import sleep + + +__all__ = [ + "get_mitm_replay_cmd", "get_agent_path", "prepare_command", + "run_agent", "get_basename", "METHODS", "ACTIONS_PATH", + "BINMITM_COUNTERFILE", "FENCING_LIB_PATH", "DEVICES_PATH", "MITM_LOGS_PATH", + "MITM_PROXY_PATH", "show_help", "get_options", "get_mitm_record_cmd", + "get_and_remove_arg" +] + + +METHODS = ["getopt", "longopt", "stdin"] # all available methods to test +FENCING_LIB_PATH = "../fence/agents/lib" # path to fencing libs +DEVICES_PATH = "./devices.d" # path to device directory +ACTIONS_PATH = "./actions.d" # path to actions directory +MITM_LOGS_PATH = "./data/mitm-logs" # path to mitm logs +MITM_PROXY_PATH = "../mitm/mitmproxy-0.1/build" # path to mitm_proxy servers +BINMITM_COUNTERFILE = "./.counterfile" # path to counter file for BINMITM +MITMPROXY_STARTUP_TIMEOUT = 1 + +class LibException(Exception): + pass -METHODS = ["getopt", "longopt", "stdin"] # all available methods to test -FENCING_LIB_PATH = "../fence/agents/lib" # apth to fencing libs -DEVICES_PATH = "./devices.d" # path to device directory -ACTIONS_PATH = "./actions.d" # path to actions directory -MITM_LOGS_PATH = "./data/mitm-logs" # path to mitm logs -MITM_PROXY_PATH = "../mitm/mitmproxy-0.1/build" # path to mitm_proxy servers -BINMITM_COUNTERFILE = "./.counterfile" # path to counter file for BINMITM # returns command for MITM_PROXY replay server -def get_MITM_replay_cmd(agent_config, log): +def get_mitm_replay_cmd(agent_config, log): if "replay_server_type" not in agent_config: - return None, None + raise LibException( + "Option 'replay_server_type' is not defined in device config. " + "It is required when agent_type = 'mitmproxy'" + ) + + script_path = os.path.join( + MITM_PROXY_PATH, + "scripts-2.7/mitmreplay_" + agent_config["replay_server_type"] + ) + + port = "" + if "ipport" in agent_config["options"]: + port = "-p " + agent_config["options"]["ipport"][0] + + cmd = "{script} -f {log} {port} {args}".format( + script=script_path, + log=log, + port=port, + args=agent_config.get("replay_server_args", "") + ) - replay = "%s/scripts-2.7/mitmreplay_%s" % (MITM_PROXY_PATH, agent_config["replay_server_type"]) - - port = ("-p %s" % agent_config["options"]["ipport"][0]) if "ipport" in agent_config["options"] else "" - cmd = "%s -f %s %s %s" % (replay, log, port, agent_config.get("replay_server_args", "")) env = os.environ.copy() - env["PYTHONPATH"] = "%s/lib" % MITM_PROXY_PATH + env["PYTHONPATH"] = os.path.join(MITM_PROXY_PATH, "lib/") return cmd, env -def get_MITM_record_cmd(agent_config, log): - if "replay_server_type" not in agent_config: - return None, None - record = "%s/scripts-2.7/mitmproxy_%s" % (MITM_PROXY_PATH, agent_config["replay_server_type"]) +def get_mitm_record_cmd(agent_config, log, local_port): + if "replay_server_type" not in agent_config: + raise LibException( + "Option 'replay_server_type' is not defined in device config. " + "It is required when agent_type = 'mitmproxy'" + ) + + script_path = os.path.join( + MITM_PROXY_PATH, + "scripts-2.7/mitmproxy_" + agent_config["replay_server_type"] + ) + + host = "" + if "ipport" in agent_config["options"]: + host = "-H " + agent_config["options"]["ipaddr"][0] + + port = "" + if "ipport" in agent_config["options"]: + port = "-P " + agent_config["options"]["ipport"][0] + + cmd = "{script} -o {log} -p {local_port} {host} {port} {a1} {a2}".format( + script=script_path, + log=log, + local_port=local_port, + host=host, + port=port, + a1=agent_config.get("record_server_args", ""), + a2=agent_config.get("replay_server_args", "") + ) - port = ("-P %s" % agent_config["options"]["ipport"][0]) if "ipport" in agent_config["options"] else "" - cmd = "%s -o %s %s %s %s" % (record, log, port, agent_config.get("replay_server_args", ""), agent_config.get("record_server_args", "")) env = os.environ.copy() - env["PYTHONPATH"] = "%s/lib" % MITM_PROXY_PATH + env["PYTHONPATH"] = os.path.join(MITM_PROXY_PATH, "lib/") return cmd, env + # returns path to fence agent def get_agent_path(agent): - return "../fence/agents/%s/%s" % (agent[6:], agent) - + return os.path.join("../fence/agents/", agent[6:], agent) # prepare agent command to run -def _prepare_command(config, params="", method="getopt"): - env = {} - env["PYTHONPATH"] = FENCING_LIB_PATH +def prepare_command(config, params="", method="getopt"): + env = {"PYTHONPATH": FENCING_LIB_PATH} final_command = "python " - if config.has_key("agent_path"): + if "agent_path" in config: final_command += config["agent_path"] else: final_command += get_agent_path(config["agent"]) if params: - final_command += " %s " % params + final_command += " " + params + " " stdin_values = None for opt in config["options"]: - if not isinstance(config["options"][opt], list) or not len(config["options"][opt]) >= 2: - raise Exception("Option %s have to have at least value and longopt"% opt) + if not isinstance(config["options"][opt], list) or not len( + config["options"][opt]) >= 2: + raise LibException( + "Option '{0}' have to have at least value and longopt".format( + opt + ) + ) value = config["options"][opt][0] - has_value = value is not None + has_value = value is not None if opt == "action": - ## ignore action as it is not part of fence device definition + # ignore action as it is not part of fence device definition continue if method == "stdin": @@ -109,21 +160,29 @@ def _prepare_command(config, params="", method="getopt"): if has_value: final_command += " " + quote(value) - return (final_command, stdin_values, env) + return final_command, stdin_values, env -def run_agent(command, stdin="", env_vars={}): +def run_agent(command, stdin="", env_vars=None): + if env_vars is None: + env_vars = {} env = os.environ.copy() env.update(env_vars) - logging.debug("Running: %s" % command) + logging.debug("Running: {cmd}".format(cmd=command)) if stdin: - logging.debug("STDIN: %s" % stdin) + logging.debug("STDIN: {0}".format(stdin)) if env_vars: - logging.debug("ENV: %s" % str(env_vars)) + logging.debug("ENV: {0}".format(str(env_vars))) - process = subprocess.Popen(shlex.split(command), stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) + process = subprocess.Popen( + shlex.split(command), + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + env=env + ) if stdin: process.stdin.write(stdin) @@ -148,19 +207,28 @@ def show_help(avail_opt, description=None): if description: print description print "Options:" - max = 30 + space = 30 for o in avail_opt: - args = "-%s, --%s%s" % (avail_opt[o]["getopt"].strip(":"), avail_opt[o]["longopt"], " " if avail_opt[o]["getopt"].endswith(":") else "") - line = "\t%s%s%s" % (args, (' ' * (max-len(args)) if max-len(args) > 0 else ' ' * 5), avail_opt[o]["description"]) + args = "-{short}, --{long}{val}".format( + short=avail_opt[o]["getopt"].strip(":"), + long=avail_opt[o]["longopt"], + val=(" " if avail_opt[o]["getopt"].endswith(":") else "") + ) + line = "\t{args}{spaces}{description}".format( + args=args, + spaces=( + ' ' * (space - len(args)) if space - len(args) > 0 else ' ' * 5 + ), + description=avail_opt[o]["description"]) print line # get options from command line parameters def get_options(avail_opt): opt = {} - for o in avail_opt.itervalues(): # set default values + for o in avail_opt.itervalues(): # set default values if "default" in o: - opt["--%s" % o["longopt"]] = o["default"] + opt["--" + o["longopt"]] = o["default"] if len(sys.argv) > 1: os.putenv("LANG", "C") @@ -170,21 +238,29 @@ def get_options(avail_opt): longopt_list = [] for k in avail_opt: getopt_string += avail_opt[k]["getopt"] - longopt_list.append("%s%s" % (avail_opt[k]["longopt"], "=" if avail_opt[k]["getopt"].endswith(":") else "")) + long_opt = avail_opt[k]["longopt"] + ( + "=" if avail_opt[k]["getopt"].endswith(":") else "" + ) + longopt_list.append(long_opt) try: - old_opt, _ = getopt.gnu_getopt(sys.argv[1:], getopt_string, longopt_list) - except getopt.GetoptError, error: - logging.error("Parse error: " + error.msg) + old_opt, _ = getopt.gnu_getopt( + sys.argv[1:], getopt_string, longopt_list + ) + except getopt.GetoptError as error: + logging.error("Parse error: " + str(error)) show_help(avail_opt) sys.exit(1) - ## Transform short getopt to long one + # Transform short getopt to long one ##### for o in dict(old_opt).keys(): if o.startswith("--"): for x in avail_opt.keys(): - if avail_opt[x].has_key("longopt") and "--" + avail_opt[x]["longopt"] == o: + if ( + "longopt" in avail_opt[x] and + "--" + avail_opt[x]["longopt"] == o + ): if avail_opt[x]["getopt"].endswith(":"): opt[o] = dict(old_opt)[o] if "list" in avail_opt[x]: @@ -193,26 +269,86 @@ def get_options(avail_opt): opt[o] = True else: for x in avail_opt.keys(): - if x in avail_opt and avail_opt[x].has_key("getopt") and avail_opt[x].has_key("longopt") and \ - ("-" + avail_opt[x]["getopt"] == o or "-" + avail_opt[x]["getopt"].rstrip(":") == o): + if ( + x in avail_opt and + "getopt" in avail_opt[x] and + "longopt" in avail_opt[x] and + ( + "-" + avail_opt[x]["getopt"] == o or + "-" + avail_opt[x]["getopt"].rstrip(":") == o + ) + ): + key = "--" + avail_opt[x]["longopt"] if avail_opt[x]["getopt"].endswith(":"): - opt["--" + avail_opt[x]["longopt"]] = dict(old_opt)[o] + opt[key] = dict(old_opt)[o] if "list" in avail_opt[x]: - opt["--" + avail_opt[x]["longopt"]] = opt["--" + avail_opt[x]["longopt"]].split(avail_opt[x]["list"]) + opt[key] = opt[key].split(avail_opt[x]["list"]) else: - opt["--" + avail_opt[x]["longopt"]] = True - + opt[key] = True return opt def get_and_remove_arg(arg): - logging.debug("Getting arg: %s" % arg) + logging.debug("Getting arg: {0}".format(arg)) if arg in sys.argv: index = sys.argv.index(arg) sys.argv.remove(arg) if len(sys.argv) > index: value = sys.argv[index] sys.argv.remove(value) - logging.debug("%s: %s" % (arg, value)) + logging.debug("{arg}: {val}".format(arg=arg, val=value)) return value return None + + +def start_mitm_server(cmd, env): + logging.debug("Executing: {cmd}".format(cmd=cmd)) + try: + # Try to start replay server + process = subprocess.Popen( + shlex.split(cmd), + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + env=env + ) + except OSError as e: + raise LibException( + "Unable to start replay server: {0}".format(str(e)) + ) + + # wait for replay server + sleep(MITMPROXY_STARTUP_TIMEOUT) + # check if replay server is running correctly + if process.poll() is not None: + pipe_stdout, pipe_stderr = process.communicate() + process.stdout.close() + process.stderr.close() + logging.debug( + "MITM server STDOUT:\n{out}".format(out=str(pipe_stdout)) + ) + logging.debug( + "MITM server STDERR:\n{err}".format(err=str(pipe_stderr)) + ) + raise LibException("MITM server is not running correctly.") + return process + + +def stop_mitm_server(process): + if process: + # if server is still alive after test, kill it + if process.poll() is None: + try: + # race condition, process can exit between checking and + # killing process + process.kill() + except Exception: + pass + pipe_stdout, pipe_stderr = process.communicate() + process.stdout.close() + process.stderr.close() + logging.debug( + "MITM server STDOUT:\n{out}".format(out=str(pipe_stdout)) + ) + logging.debug( + "MITM server STDERR:\n{err}".format(err=str(pipe_stderr)) + ) diff --git a/tests/run_tests.py b/tests/run_tests.py index b1e4affb6..1b29f2b06 100755 --- a/tests/run_tests.py +++ b/tests/run_tests.py @@ -1,26 +1,28 @@ #!/usr/bin/python -tt -__author__ = 'Ondrej Mular ' - -from configobj import ConfigObj -from time import sleep import sys -import subprocess -import shlex import logging import os import unittest import re import pprint +from configobj import ConfigObj + import fence_tests_lib as ftl VERBOSE = not set(["-v", "--verbose"]).isdisjoint(sys.argv) PARAM_FORCE = ftl.get_and_remove_arg("--param") methods = ftl.get_and_remove_arg("--method") or ftl.get_and_remove_arg("-m") METHODS_TO_TEST = methods.split(",") if methods else ftl.METHODS +LOCAL_PORT = ( + ftl.get_and_remove_arg("--port") or + ftl.get_and_remove_arg("-p") or + "4242" +) + # define tests which cannot be autodetected -#(device_config, action_config, log_file) +# (device_config, action_config, log_file) TESTS = [ ] @@ -68,80 +70,68 @@ "longopt": "show-tests", "description": "Prints all found tests and exit", "default": False + }, + "port": { + "getopt": "p:", + "longopt": "port", + "description": + "Local port for communication between agent and mitmproxy", + "default": "4242" } } # TestCase class which adds posibility to add param into tests class ParametrizedTestCase(unittest.TestCase): - """ TestCase classes that want to be parametrized should - inherit from this class. """ - def __init__(self, methodName='runTest', param=None): - super(ParametrizedTestCase, self).__init__(methodName) + TestCase classes that want to be parametrized should + inherit from this class. + """ + + def __init__(self, method_name='runTest', param=None): + super(ParametrizedTestCase, self).__init__(method_name) self.param = param @staticmethod - def parametrize(testcase_klass, param=None): - """ Create a suite containing all tests taken from the given - subclass, passing them the parameter 'param'. + def parametrize(test_case_klass, param=None): """ - testloader = unittest.TestLoader() - testnames = testloader.getTestCaseNames(testcase_klass) + Create a suite containing all tests taken from the given + subclass, passing them the parameter 'param'. + """ + test_loader = unittest.TestLoader() + test_names = test_loader.getTestCaseNames(test_case_klass) suite = unittest.TestSuite() - for name in testnames: - suite.addTest(testcase_klass(name, param=param)) + for name in test_names: + suite.addTest(test_case_klass(name, param=param)) return suite # TestCase for testing of one agent class FenceAgentTestCase(ParametrizedTestCase): - def __getattr__(self, key): return None - - # prepate enviroment for running test with MITM_PROXY + # prepare environment for running test with MITM_PROXY def setUp_MITMPROXY(self): - (replay_cmd, replay_env) = ftl.get_MITM_replay_cmd(self.device_config, self.action_log) - if replay_cmd: - logging.debug("Executing: %s", replay_cmd) - try: - # Try to start replay server - process = subprocess.Popen(shlex.split(replay_cmd), stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=replay_env) - except OSError as e: - logging.error("Unable to start replay server: %s" % e.message) - raise - sleep(1) # wait for replay server - if process.poll() is not None: # check if replay server is running correctly - raise Exception("Replay server is not running correctly.") - self.mitm_process = process + if "ipport" in self.device_config["options"]: + self.device_config["options"]["ipport"][0] = LOCAL_PORT + self.mitm_process = ftl.start_mitm_server( + *ftl.get_mitm_replay_cmd(self.device_config, self.action_log) + ) - def tearDown_MITMPROXY(self): - if self.mitm_process: - process = self.mitm_process - # if server is still alive after test, kill it - if process.poll() is None: - try: - # race condition, process can exit between checking and killing process - process.kill() - except Exception: - pass - pipe_stdout, pipe_stderr = process.communicate() - process.stdout.close() - process.stderr.close() - logging.debug("Replay server STDOUT:\n%s\nReplay server STDERR:\n%s", str(pipe_stdout), str(pipe_stderr)) + if "ipaddr" in self.device_config["options"]: + self.device_config["options"]["ipaddr"][0] = "localhost" + def tearDown_MITMPROXY(self): + ftl.stop_mitm_server(self.mitm_process) def setUp_pycurl(self): self.params = "--fencing_pycurl-log-in %s" % self.action_log - def tearDown_pycurl(self): pass - def setUp_BINMITM(self): cf = os.path.abspath(ftl.BINMITM_COUNTERFILE) if os.path.exists(cf): @@ -150,67 +140,72 @@ def setUp_BINMITM(self): del os.environ["BINMITM_OUTPUT"] if "BINMITM_DEBUG" in os.environ: del os.environ["BINMITM_DEBUG"] - self.env = {} - self.env["BINMITM_COUNTER_FILE"] = ftl.BINMITM_COUNTERFILE - self.env["BINMITM_INPUT"] = self.action_log - + self.env = { + "BINMITM_COUNTER_FILE": ftl.BINMITM_COUNTERFILE, + "BINMITM_INPUT": self.action_log + } def tearDown_BINMITM(self): cf = os.path.abspath(ftl.BINMITM_COUNTERFILE) if os.path.exists(cf): os.remove(cf) - def setUp(self): - if PARAM_FORCE: - force_param, force_param_val = PARAM_FORCE.split("=", 1) self.device_cfg, self.action_cfg, self.action_log = self.param self.device_config = ConfigObj(self.device_cfg, unrepr=True) - if PARAM_FORCE and force_param in self.device_config["options"]: - self.device_config["options"][force_param][0] = force_param_val + if PARAM_FORCE: + force_param, force_param_val = PARAM_FORCE.split("=", 1) + if force_param in self.device_config["options"]: + self.device_config["options"][force_param][0] = force_param_val self.action_config = ConfigObj(self.action_cfg, unrepr=True) self.type = self.device_config["agent_type"].lower() self.params = "" self.mitm_process = None self.env = {} - type = self.type - if type == "mitmproxy": + agent_type = self.type + if agent_type == "mitmproxy": self.setUp_MITMPROXY() - elif type =="pycurl": + elif agent_type == "pycurl": self.setUp_pycurl() - elif type == "binmitm": + elif agent_type == "binmitm": self.setUp_BINMITM() - def tearDown(self): - type = self.type - if type == "mitmproxy": + agent_type = self.type + if agent_type == "mitmproxy": self.tearDown_MITMPROXY() - elif type =="pycurl": + elif agent_type == "pycurl": self.tearDown_pycurl() - elif type == "binmitm": + elif agent_type == "binmitm": self.tearDown_BINMITM() - - @unittest.skipIf("getopt" not in METHODS_TO_TEST, "Not testing getopt method") + @unittest.skipIf( + "getopt" not in METHODS_TO_TEST, "Not testing getopt method" + ) def test_getopt(self): self.agent_test("getopt") - - @unittest.skipIf("longopt" not in METHODS_TO_TEST, "Not testing longopt method") + @unittest.skipIf( + "longopt" not in METHODS_TO_TEST, "Not testing longopt method" + ) def test_longopt(self): self.agent_test("longopt") - @unittest.skipIf("stdin" not in METHODS_TO_TEST, "Not testing stdin method") def test_stdin(self): self.agent_test("stdin") - - def get_failure_message(self, expected_status, status, stdout="", stderr="", long=False): - msg = "Return code was %s (expected: %s)" % (str(status), str(expected_status)) - if long: - msg += "\nSTDOUT:\n%s\nSTDERR:\n%s\n" % (stdout, stderr) + def get_failure_message( + self, expected_status, status, stdout="", stderr="", longer=False + ): + msg = "Return code was {actual} (expected: {expected})".format( + actual=status, expected=expected_status + ) + if longer: + msg += "\nSTDOUT:\n{stdout}\nSTDERR:\n{stderr}\n".format( + stdout=stdout, + stderr=stderr + ) return msg # run test of agent with specific method @@ -218,40 +213,69 @@ def agent_test(self, method): action_file = self.action_cfg actions = self.action_config for action in actions["actions"]: - self.assertTrue(action.has_key("command"), "Action %s need to have defined 'command'"% (action_file)) - self.assertTrue(action.has_key("return_code"), "Command %s (in %s) need to have 'return_code' defined"% (action_file, action["command"])) - cmd, stdin, env = ftl._prepare_command(self.device_config, self.params, method) + self.assertTrue( + "command" in action, + "Action {action} need to have defined 'command'".format( + action=action_file + ) + ) + self.assertTrue( + "return_code" in action, + "Command '{command}' (in {file}) need to have 'return_code' " + "defined".format( + command=action["command"], file=action_file + ) + ) + + cmd, stdin, env = ftl.prepare_command( + self.device_config, self.params, method + ) env.update(self.env) if method == "stdin": if stdin is None: stdin = "" - stdin += "action=%s"% (action["command"]) + stdin += "action=" + action["command"] elif method == "longopt": - cmd += " --action=%s"% (action["command"]) + cmd += " --action=" + action["command"] elif method == "getopt": - cmd += " -o %s"% (action["command"]) + cmd += " -o " + action["command"] status, stdout, stderr = ftl.run_agent(cmd, stdin, env) - logging.debug("AGENT EXITCODE: %s" % str(status)) - - self.assertTrue(bool(re.search(action["return_code"], str(status), re.IGNORECASE)), self.get_failure_message(action["return_code"], status, stdout, stderr, VERBOSE)) + logging.debug("AGENT EXITCODE: {0}".format(status)) + logging.debug("AGENT STDOUT: {0}".format(stdout)) + logging.debug("AGENT STDERR: {0}".format(stderr)) + self.assertTrue( + bool(re.search( + action["return_code"], str(status), re.IGNORECASE) + ), + self.get_failure_message( + action["return_code"], status, stdout, stderr, VERBOSE + ) + ) def shortDescription(self): self.device_cfg, self.action_cfg, self.action_log = self.param return self.get_test_identificator(True) - def get_test_identificator(self, short=False): if short: if not self.short_test_identificator: - self.short_test_identificator = "%s => %s" % (ftl.get_basename(self.device_cfg), ftl.get_basename(self.action_cfg)) + self.short_test_identificator = "{0} => {0}".format( + ftl.get_basename(self.device_cfg), + ftl.get_basename(self.action_cfg) + ) return self.short_test_identificator if not self.test_identificator: - self.test_identificator = "AGENT: %s (%s)\nACTION: %s" % (self.device_config["name"], self.device_cfg, self.action_cfg) + self.test_identificator =\ + "AGENT: {agent} ({config})\nACTION: {action}".format( + agent=self.device_config["name"], + config=self.device_cfg, + action=self.action_cfg + ) return self.test_identificator @@ -259,26 +283,52 @@ def get_test_identificator(self, short=False): # returns list of (agent_cfg_path, action_cfg_path, log_path) def find_tests(opt): tests = [] - agents = [os.path.join(ftl.DEVICES_PATH, f) for f in os.listdir(ftl.DEVICES_PATH) - if os.path.isfile(os.path.join(ftl.DEVICES_PATH, f)) and f.endswith(".cfg") and (not opt["--device"] or f[:-4] in opt["--device"])] - actions = [f for f in os.listdir(ftl.ACTIONS_PATH) - if os.path.isfile(os.path.join(ftl.ACTIONS_PATH, f)) and f.endswith(".cfg") and (not opt["--action"] or f[:-4] in opt["--action"])] + agents = [] + for f in os.listdir(ftl.DEVICES_PATH): + if ( + os.path.isfile(os.path.join(ftl.DEVICES_PATH, f)) and + f.endswith(".cfg") and + (not opt["--device"] or f[:-4] in opt["--device"]) + ): + agents.append(os.path.join(ftl.DEVICES_PATH, f)) + + actions = [] + for f in os.listdir(ftl.ACTIONS_PATH): + if ( + os.path.isfile(os.path.join(ftl.ACTIONS_PATH, f)) and + f.endswith(".cfg") and + (not opt["--action"] or f[:-4] in opt["--action"]) + ): + actions.append(f) for agent_cfg in agents: logging.debug("Opening device config '%s'" % agent_cfg) - config = ConfigObj(agent_cfg, unrepr = True) - logs_path = os.path.join(ftl.MITM_LOGS_PATH, config["agent"][6:]) # remove prefix 'fence_' from agent name + config = ConfigObj(agent_cfg, unrepr=True) + logs_path = os.path.join( + ftl.MITM_LOGS_PATH, config["agent"][6:] # remove prefix 'fence_' + ) if "subdir" in config: logs_path = os.path.join(logs_path, config["subdir"]) if not os.path.exists(logs_path): - logging.info("Logs directory '%s' not exists." % logs_path) + logging.info("Logs directory '{0}' not exists.".format(logs_path)) continue - logs = [f for f in os.listdir(logs_path) if os.path.isfile(os.path.join(logs_path, f)) and f.endswith(".log")] + logs = [] + for f in os.listdir(logs_path): + if ( + os.path.isfile(os.path.join(logs_path, f)) and + f.endswith(".log") + ): + logs.append(f) + for log in logs: action = "%scfg" % log[:-3] # replace suffix 'log' with 'cfg' if action in actions: - test = (agent_cfg, os.path.join(ftl.ACTIONS_PATH, action), os.path.join(logs_path, log)) - logging.debug("Found test: %s" % str(test)) + test = ( + agent_cfg, + os.path.join(ftl.ACTIONS_PATH, action), + os.path.join(logs_path, log) + ) + logging.debug("Found test: {0}".format(test)) tests.append(test) return tests @@ -292,7 +342,9 @@ def main(): opt = ftl.get_options(avail_opt) if "--help" in opt: - ftl.show_help(avail_opt, "This program can run MITM tests of fence-agents.") + ftl.show_help( + avail_opt, "This program can run MITM tests of fence-agents." + ) sys.exit(0) valid_tests = find_tests(opt) @@ -304,21 +356,38 @@ def main(): return for test in TESTS: - if test not in valid_tests \ - and (opt["--device"] is None or os.path.basename(test[0])[:-4] in opt["--device"]) \ - and (opt["--action"] is None or os.path.basename(test[1])[:-4] in opt["--action"]) \ - and os.path.exists(test[0]) \ - and os.path.exists(test[1]) \ - and os.path.exists(test[2]): + if ( + test not in valid_tests and + ( + opt["--device"] is None or + os.path.basename(test[0])[:-4] in opt["--device"] + ) and + ( + opt["--action"] is None or + os.path.basename(test[1])[:-4] in opt["--action"] + ) and + os.path.exists(test[0]) and + os.path.exists(test[1]) and + os.path.exists(test[2]) + ): valid_tests.append(test) suite = unittest.TestSuite() for test in valid_tests: - #agent, action, log = test - suite.addTest(ParametrizedTestCase.parametrize(FenceAgentTestCase, param=test)) + # agent, action, log = test + suite.addTest( + ParametrizedTestCase.parametrize(FenceAgentTestCase, param=test) + ) + + try: + unittest.TextTestRunner( + verbosity=2, failfast=opt["--failfast"] + ).run(suite) + except ftl.LibException as e: + logging.error(str(e)) + sys.exit(1) - unittest.TextTestRunner(verbosity=2, failfast=opt["--failfast"]).run(suite) if __name__ == "__main__": main()