diff --git a/requirements.txt b/requirements.txt index a63e7d7..577d2be 100644 --- a/requirements.txt +++ b/requirements.txt @@ -15,3 +15,4 @@ eventlet oslo.config>=2.4.0,<3.0.0 oslo.messaging>=2.5.0,<3.0.0 python-dateutil +tabulate>=0.7.2,<0.8.0 diff --git a/setup.cfg b/setup.cfg index 589ea03..5bafd79 100644 --- a/setup.cfg +++ b/setup.cfg @@ -26,13 +26,10 @@ scripts = [entry_points] synergy.managers = - timer = synergy.examples.timer_manager:TimerManager + TimerManager = synergy.examples.timer_manager:TimerManager synergy.commands = - list = synergy.client.command:List - status = synergy.client.command:Status - start = synergy.client.command:Start - stop = synergy.client.command:Stop + manager = synergy.client.command:ManagerCommand [build_sphinx] source-dir = doc/source diff --git a/synergy/client/command.py b/synergy/client/command.py index a4a7d44..4e2fb35 100644 --- a/synergy/client/command.py +++ b/synergy/client/command.py @@ -1,6 +1,10 @@ import json import requests +from synergy.common import utils +from tabulate import tabulate + + __author__ = "Lisa Zangrando" __email__ = "lisa.zangrando[AT]pd.infn.it" __copyright__ = """Copyright (c) 2015 INFN - INDIGO-DataCloud @@ -31,10 +35,21 @@ class HTTPCommand(object): def configureParser(self, subparser): raise NotImplementedError("not implemented!") - def log(self): - raise NotImplementedError("not implemented!") + def objectHookHandler(self, parsed_dict): + if "synergy_object" in parsed_dict: + synergy_object = parsed_dict["synergy_object"] + try: + objClass = utils.import_class(synergy_object["name"]) - def sendRequest(self, synergy_url, payload=None): + objInstance = objClass() + return objInstance.deserialize(parsed_dict) + except Exception as ex: + print(ex) + raise ex + else: + return parsed_dict + + def execute(self, synergy_url, payload=None): request = requests.get(synergy_url, params=payload) if request.status_code != requests.codes.ok: @@ -44,180 +59,98 @@ class HTTPCommand(object): self.results = request.json() - return request + try: + return json.loads(request.text, object_hook=self.objectHookHandler) + except Exception: + return request.json() def getResults(self): return self.results -class List(HTTPCommand): +class ManagerCommand(HTTPCommand): def __init__(self): - super(List, self).__init__("list") + super(ManagerCommand, self).__init__("Manager") def configureParser(self, subparser): - subparser.add_parser("list", add_help=True, help="list the managers") + manager_parser = subparser.add_parser('manager') + manager_parsers = manager_parser.add_subparsers(dest="command") - def sendRequest(self, synergy_url, args=None): - super(List, self).sendRequest(synergy_url + "/synergy/list") + manager_parsers.add_parser( + "list", add_help=True, help="list the managers") - def log(self): - results = self.getResults() + status_parser = manager_parsers.add_parser( + "status", add_help=True, help="show the managers status") - max_project_id = max(len(max(results, key=len)), len("manager")) - separator_str = "-" * (max_project_id + 4) + "\n" - format_str = "| {0:%ss} |\n" % (max_project_id) + status_parser.add_argument( + "manager", nargs='*', help="the managers list") - msg = separator_str - msg += format_str.format("manager") - msg += separator_str + start_parser = manager_parsers.add_parser( + "start", add_help=True, help="start the manager") - for manager in results: - msg += format_str.format(manager) + start_parser.add_argument( + "manager", nargs='+', help="the managers list") - msg += separator_str - print(msg) + stop_parser = manager_parsers.add_parser( + "stop", add_help=True, help="stop the manager") + + stop_parser.add_argument( + "manager", nargs='+', help="the managers list") + + def execute(self, synergy_url, args=None): + table = [] + headers = [] + url = synergy_url + + if args.command == "list": + headers.append("manager") + url += "/synergy/list" + + managers = super(ManagerCommand, self).execute(url) + + for manager in managers: + table.append([manager.getName()]) + else: + headers.append("manager") + headers.append("status") + headers.append("rate (min)") + url += "/synergy/" + args.command + + managers = super(ManagerCommand, self).execute( + url, {"manager": args.manager}) + + if args.command == "status": + for manager in managers: + table.append([manager.getName(), + manager.getStatus(), + manager.getRate()]) + else: + headers.append("details") + + for manager in managers: + msg = manager.get("message") + + table.append([manager.getName(), + manager.getStatus() + " (%s)" % msg, + manager.getRate()]) + + print(tabulate(table, headers, tablefmt="fancy_grid")) -class Start(HTTPCommand): - - def __init__(self): - super(Start, self).__init__("start") - - def configureParser(self, subparser): - parser = subparser.add_parser("start", - add_help=True, - help="start the managers") - - parser.add_argument("manager", help="the manager to be started") - - def sendRequest(self, synergy_url, args): - super(Start, self).sendRequest(synergy_url + "/synergy/start", - {"manager": args.manager}) - - def log(self): - results = self.getResults() - - max_manager = max(len(max(results.keys(), key=len)), len("manager")) - - max_status = len("status") - max_msg = len("message") - - for result in results.values(): - max_status = max(len(str(result["status"])), max_status) - max_msg = max(len(str(result["message"])), max_msg) - - separator_str = "-" * (max_manager + max_status + max_msg + 10) + "\n" - - format_str = "| {0:%ss} | {1:%ss} | {2:%ss} |\n" % (max_manager, - max_status, - max_msg) - - msg = separator_str - msg += format_str.format("manager", "status", "message") - msg += separator_str - - for manager, values in results.items(): - msg += format_str.format(manager, - values["status"], - values["message"]) - - msg += separator_str - print(msg) - - -class Stop(HTTPCommand): - - def __init__(self): - super(Stop, self).__init__("stop") - - def configureParser(self, subparser): - parser = subparser.add_parser("stop", - add_help=True, - help="stop the managers") - - parser.add_argument("manager", help="the manager to be stopped") - - def sendRequest(self, synergy_url, args): - super(Stop, self).sendRequest(synergy_url + "/synergy/stop", - {"manager": args.manager}) - - def log(self): - results = self.getResults() - - max_manager = max(len(max(results.keys(), key=len)), len("manager")) - max_status = len("status") - max_msg = len("message") - - for result in results.values(): - max_status = max(len(str(result["status"])), max_status) - max_msg = max(len(str(result["message"])), max_msg) - - separator_str = "-" * (max_manager + max_status + max_msg + 10) + "\n" - format_str = "| {0:%ss} | {1:%ss} | {2:%ss} |\n" % (max_manager, - max_status, - max_msg) - - msg = separator_str - msg += format_str.format("manager", "status", "message") - msg += separator_str - - for manager, values in results.items(): - msg += format_str.format(manager, - values["status"], - values["message"]) - - msg += separator_str - print(msg) - - -class Status(HTTPCommand): - - def __init__(self): - super(Status, self).__init__("status") - - def configureParser(self, subparser): - parser = subparser.add_parser("status", - add_help=True, - help="retrieve the manager's status") - - parser.add_argument("manager", nargs='*', help="the managers list") - - def sendRequest(self, synergy_url, args): - super(Status, self).sendRequest(synergy_url + "/synergy/status", - {"manager": args.manager}) - - def log(self): - results = self.getResults() - - max_project_id = max(len(max(results.keys(), key=len)), len("manager")) - max_value = max(len(max(results.values(), key=len)), len("status")) - separator_str = "-" * (max_project_id + max_value + 7) + "\n" - format_str = "| {0:%ss} | {1:%ss} |\n" % (max_project_id, max_value) - - msg = separator_str - msg += format_str.format("manager", "status") - msg += separator_str - - for manager, status in results.items(): - msg += format_str.format(manager, status) - - msg += separator_str - print(msg) - - -class Execute(HTTPCommand): +class ExecuteCommand(HTTPCommand): def __init__(self, name): - super(Execute, self).__init__(name) + super(ExecuteCommand, self).__init__(name) - def sendRequest(self, synergy_url, manager, command, args=None): + def execute(self, synergy_url, manager, command, args=None): if args is None: args = {} + url = synergy_url + "/synergy/execute" + payload = {"manager": manager, "command": command, "args": json.dumps(args)} - super(Execute, self).sendRequest(synergy_url + "/synergy/execute", - payload) + return super(ExecuteCommand, self).execute(url, payload) diff --git a/synergy/client/shell.py b/synergy/client/shell.py index f3c39b9..b97b2d7 100644 --- a/synergy/client/shell.py +++ b/synergy/client/shell.py @@ -175,8 +175,8 @@ def main(): if command_name not in commands: print("command %r not found!" % command_name) - commands[command_name].sendRequest(synergy_url, args) - commands[command_name].log() + commands[command_name].execute(synergy_url, args) + # commands[command_name].log() except KeyboardInterrupt as e: print("Shutting down synergyclient") sys.exit(1) diff --git a/synergy/common/manager.py b/synergy/common/manager.py index ce10771..79c515c 100644 --- a/synergy/common/manager.py +++ b/synergy/common/manager.py @@ -1,7 +1,9 @@ +from serializer import SynergyObject from threading import Condition from threading import Event from threading import Thread + __author__ = "Lisa Zangrando" __email__ = "lisa.zangrando[AT]pd.infn.it" __copyright__ = """Copyright (c) 2015 INFN - INDIGO-DataCloud @@ -21,18 +23,17 @@ See the License for the specific language governing permissions and limitations under the License.""" -class Manager(Thread): +class Manager(SynergyObject, Thread): - def __init__(self, name): + def __init__(self, name=None): super(Manager, self).__init__() - self.setDaemon(True) - self.stop_event = Event() - self.config_opts = [] self.condition = Condition() - self.name = name - self.status = "CREATED" - self.autostart = False - self.rate = -1 + self.stop_event = Event() + self.setDaemon(True) + self.setName(name) + self.setStatus("CREATED") + self.setRate(-1) + self.config_opts = [] self.paused = True # start out paused self.managers = {} @@ -61,24 +62,30 @@ class Manager(Thread): if manager.getName() != manager_name: manager.doOnEvent(event_type, *args, **kargs) - def getName(self): - return self.name - def getOptions(self): return self.config_opts + def getStatus(self): + return self.get("status") + + def setStatus(self, status): + with self.condition: + self.set("status", status) + + self.condition.notifyAll() + def isAutoStart(self): - return self.autostart + return self.get("autostart") def setAutoStart(self, autostart): - self.autostart = autostart - self.paused = not self.autostart + self.set("autostart", autostart) + self.paused = not autostart def getRate(self): - return self.rate + return self.get("rate") def setRate(self, rate): - self.rate = rate + self.set("rate", rate) def setup(self): """Manager initialization @@ -93,15 +100,6 @@ class Manager(Thread): def destroy(self): raise NotImplementedError - def getStatus(self): - return self.status - - def setStatus(self, status): - with self.condition: - self.status = status - - self.condition.notifyAll() - def stop(self): if self.isAlive(): # set event to signal thread to terminate @@ -124,13 +122,13 @@ class Manager(Thread): while not self.stop_event.isSet(): with self.condition: if self.paused: - self.status = "ACTIVE" + self.setStatus("ACTIVE") self.condition.wait() else: - self.status = "RUNNING" + self.setStatus("RUNNING") try: self.task() - self.condition.wait(self.rate * 60) + self.condition.wait(self.getRate() * 60) except Exception as ex: - print("task %r: %s" % (self.name, ex)) + print("task %r: %s" % (self.getName(), ex)) diff --git a/synergy/common/serializer.py b/synergy/common/serializer.py index c9665e1..f0102e2 100644 --- a/synergy/common/serializer.py +++ b/synergy/common/serializer.py @@ -1,9 +1,5 @@ -try: - import oslo_messaging -except ImportError: - import oslo.messaging as oslo_messaging - -from synergy.common import context as ctx +import datetime +from json import JSONEncoder from synergy.common import utils @@ -35,128 +31,136 @@ class SynergyObject(object): necessary "get" classmethod routines as well as "set" object methods as appropriate. """ + VERSION = "1.0" - def __init__(self, name=None): + def __init__(self): + super(SynergyObject, self).__init__() + self.attributes = {} - if name: - self.attributes["name"] = name + def getId(self): + return self.get("id") + + def setId(self, id): + self.set("id", id) def getName(self): - return self.attributes["name"] + return self.get("name") def setName(self, name): - self.attributes["name"] = name + self.set("name", name) - def get(self, field=None): + def get(self, field): return self.attributes.get(field, None) def set(self, field, value): - self.attributes[field] = value - - def setContext(self, context): - self.context = context + if isinstance(value, unicode): + self.attributes[field] = str(value) + else: + self.attributes[field] = value def setAttributes(self, attributes): if attributes: self.attributes = attributes @classmethod - def deserialize(cls, context, entity): - if "synergy_object.namespace" not in entity: - raise Exception("synergy_object.namespace nof defined!") + def deserialize(cls, entity): + if "synergy_object" not in entity: + raise Exception("it seems not a Synergy object!") - if "synergy_object.name" not in entity: - raise Exception("synergy_object.name nof defined!") + synergy_object = entity["synergy_object"] - if "synergy_object.version" not in entity: - raise Exception("synergy_object.version nof defined!") + if "namespace" not in synergy_object: + raise Exception("synergy_object.namespace not defined!") - if entity["synergy_object.namespace"] != 'synergy': + if "name" not in synergy_object: + raise Exception("synergy_object.name not defined!") + + if "version" not in synergy_object: + raise Exception("synergy_object.version mismatch!") + + if synergy_object["version"] != cls.VERSION: + raise Exception("synergy_object.version mis!") + + if synergy_object["namespace"] != "synergy": raise Exception("unsupported object objtype='%s.%s" - % (entity["synergy_object.namespace"], - entity["synergy_object.name"])) + % (synergy_object["namespace"], + synergy_object["name"])) - objName = entity['synergy_object.name'] - # objVer = entity['synergy_object.version'] - objClass = utils.import_class(objName) + objInstance = None - # objInstance = objClass(context=context, data=entity) + try: + objName = synergy_object["name"] + # objVer = synergy_object['version'] + objClass = utils.import_class(objName) + objInstance = objClass() + except Exception as ex: + print(ex) + raise Exception("error on deserializing the object %r: %s" + % (objName, ex)) - objInstance = objClass(name=None) - objInstance.setContext(context) - objInstance.setAttributes(entity) + del entity["synergy_object"] + + for key, value in entity.items(): + if isinstance(value, dict): + if "synergy_object" in value: + objInstance.set(key, SynergyObject.deserialize(value)) + else: + objInstance.set(key, value) + elif isinstance(value, list): + l = [] + + objInstance.set(key, l) + + for item in value: + if isinstance(item, dict) and "synergy_object" in item: + l.append(SynergyObject.deserialize(item)) + else: + l.append(item) + else: + objInstance.set(key, value) return objInstance def serialize(self): name = self.__class__.__module__ + "." + self.__class__.__name__ - self.attributes['synergy_object.name'] = name - self.attributes['synergy_object.version'] = self.VERSION - self.attributes['synergy_object.namespace'] = 'synergy' - return self.attributes - """ - def log(self): + result = {"synergy_object": {}} + result["synergy_object"]["name"] = name + result["synergy_object"]["version"] = self.VERSION + result["synergy_object"]["namespace"] = "synergy" + for key, value in self.attributes.items(): - LOG.info("%s = %s" % (key, value)) - """ + if isinstance(value, SynergyObject): + result[key] = value.serialize() + elif isinstance(value, dict): + result[key] = {} + for k, v in value.items(): + if isinstance(v, SynergyObject): + result[key][k] = v.serialize() + else: + result[key][k] = v + elif isinstance(value, list): + result[key] = [] -class SynergySerializer(oslo_messaging.Serializer): - def __init__(self): - super(SynergySerializer, self).__init__() - - def serialize_entity(self, context, entity): - if not entity: - return entity - - if isinstance(entity, SynergyObject): - entity = entity.serialize() - elif isinstance(entity, dict): - result = {} - - for key, value in entity.items(): - result[key] = self.serialize_entity(context, value) - - entity = result - - return entity - - def deserialize_entity(self, context, entity): - if isinstance(entity, dict): - if 'synergy_object.name' in entity: - entity = SynergyObject.deserialize(context, entity) + for item in value: + if isinstance(item, SynergyObject): + result[key].append(item.serialize()) + else: + result[key].append(item) + elif isinstance(value, datetime.datetime): + result[key] = value.isoformat() else: - result = {} + result[key] = value - for key, value in entity.items(): - result[key] = self.deserialize_entity(context, value) - - entity = result - - return entity - - def serialize_context(self, context): - return context.toDict() - - def deserialize_context(self, context): - return ctx.RequestContext.fromDict(context) + return result -class RequestContextSerializer(oslo_messaging.Serializer): - def __init__(self): - pass - - def serialize_entity(self, context, entity): - return entity - - def deserialize_entity(self, context, entity): - return entity - - def serialize_context(self, context): - return context.toDict() - - def deserialize_context(self, context): - return ctx.RequestContext.fromDict(context) +class SynergyEncoder(JSONEncoder): + def default(self, obj): + if isinstance(obj, SynergyObject): + return obj.serialize() + else: + return JSONEncoder.default(self, obj) diff --git a/synergy/service.py b/synergy/service.py index b56b28d..75bec22 100644 --- a/synergy/service.py +++ b/synergy/service.py @@ -15,8 +15,11 @@ except ImportError: from oslo.config import cfg from synergy.common import config -from synergy.common import service -from synergy.common import wsgi +from synergy.common.manager import Manager +from synergy.common.serializer import SynergyEncoder +from synergy.common.service import Service +from synergy.common.wsgi import Server + __author__ = "Lisa Zangrando" __email__ = "lisa.zangrando[AT]pd.infn.it" @@ -76,7 +79,7 @@ def setLogger(name): logger.addHandler(handler) -class Synergy(service.Service): +class Synergy(Service): """Service object for binaries running on hosts. A service takes a manager and enables rpc by listening to queues based @@ -98,8 +101,7 @@ class Synergy(service.Service): manager_class = entry.load() manager_obj = manager_class(*args, **kwargs) - LOG.info("manager instance %r created!", entry.name) - + manager_obj.setName(entry.name) manager_obj.setAutoStart(CONF.get(entry.name).autostart) manager_obj.setRate(CONF.get(entry.name).rate) @@ -137,14 +139,18 @@ class Synergy(service.Service): result = [] for name, manager in self.managers.items(): - result.append(name) + m = Manager(name) + m.setStatus(manager.getStatus()) + m.setRate(manager.getRate()) + + result.append(m) start_response("200 OK", [("Content-Type", "text/html")]) - return ["%s" % json.dumps(result)] + return ["%s" % json.dumps(result, cls=SynergyEncoder)] def getManagerStatus(self, environ, start_response): manager_list = None - result = {} + result = [] query = environ.get("QUERY_STRING", None) @@ -165,14 +171,20 @@ class Synergy(service.Service): manager_name = escape(manager_name) if manager_name in self.managers: - result[manager_name] = self.managers[manager_name].getStatus() + manager = self.managers[manager_name] + + m = Manager(manager_name) + m.setStatus(manager.getStatus()) + m.setRate(manager.getRate()) + + result.append(m) if len(manager_list) == 1 and len(result) == 0: start_response("404 NOT FOUND", [("Content-Type", "text/plain")]) return ["manager %r not found!" % manager_list[0]] start_response("200 OK", [("Content-Type", "text/html")]) - return ["%s" % json.dumps(result)] + return ["%s" % json.dumps(result, cls=SynergyEncoder)] def executeCommand(self, environ, start_response): manager_name = None @@ -215,16 +227,8 @@ class Synergy(service.Service): try: result = manager.execute(command=command, **manager_args) - if not isinstance(result, dict): - try: - result = result.toDict() - except Exception: - result = result.__dict__ - - LOG.debug("execute command: result=%s" % result) - start_response("200 OK", [("Content-Type", "text/html")]) - return ["%s" % json.dumps(result)] + return ["%s" % json.dumps(result, cls=SynergyEncoder)] except Exception as ex: LOG.debug("execute command: error=%s" % ex) start_response("500 INTERNAL SERVER ERROR", @@ -233,7 +237,7 @@ class Synergy(service.Service): def startManager(self, environ, start_response): manager_list = None - result = {} + result = [] query = environ.get("QUERY_STRING", None) @@ -258,9 +262,11 @@ class Synergy(service.Service): if manager_name not in self.managers: continue - result[manager_name] = {} - manager = self.managers[manager_name] + m = Manager(manager_name) + m.setRate(manager.getRate()) + + result.append(m) if manager.getStatus() == "ACTIVE": LOG.info("starting the %r manager" % (manager_name)) @@ -270,25 +276,25 @@ class Synergy(service.Service): LOG.info("%r manager started! (rate=%s min)" % (manager_name, manager.getRate())) - result[manager_name]["status"] = "RUNNING" - result[manager_name]["message"] = "started successfully" + m.setStatus("RUNNING") + m.set("message", "started successfully") elif manager.getStatus() == "RUNNING": - result[manager_name]["status"] = "RUNNING" - result[manager_name]["message"] = "WARN: already started" + m.setStatus("RUNNING") + m.set("message", "WARN: already started") elif manager.getStatus() == "ERROR": - result[manager_name]["status"] = "ERROR" - result[manager_name]["message"] = "wrong state" + m.setStatus("ERROR") + m.set("message", "wrong state") if len(manager_list) == 1 and len(result) == 0: start_response("404 NOT FOUND", [("Content-Type", "text/plain")]) return ["manager %r not found!" % manager_list[0]] start_response("200 OK", [("Content-Type", "text/html")]) - return ["%s" % json.dumps(result)] + return ["%s" % json.dumps(result, cls=SynergyEncoder)] def stopManager(self, environ, start_response): manager_list = None - result = {} + result = [] query = environ.get("QUERY_STRING", None) @@ -313,10 +319,13 @@ class Synergy(service.Service): if manager_name not in self.managers: continue - result[manager_name] = {} - manager = self.managers[manager_name] + m = Manager(manager_name) + m.setRate(manager.getRate()) + + result.append(m) + if manager.getStatus() == "RUNNING": LOG.info("stopping the %r manager" % (manager_name)) @@ -324,21 +333,21 @@ class Synergy(service.Service): LOG.info("%r manager stopped!" % (manager_name)) - result[manager_name]["status"] = "ACTIVE" - result[manager_name]["message"] = "stopped successfully" + m.setStatus("ACTIVE") + m.set("message", "stopped successfully") elif manager.getStatus() == "ACTIVE": - result[manager_name]["status"] = "ACTIVE" - result[manager_name]["message"] = "WARN: already stopped" + m.setStatus("ACTIVE") + m.set("message", "WARN: already stopped") elif manager.getStatus() == "ERROR": - result[manager_name]["status"] = "ERROR" - result[manager_name]["message"] = "wrong state" + m.setStatus("ERROR") + m.set("message", "wrong state") if len(manager_list) == 1 and len(result) == 0: start_response("404 NOT FOUND", [("Content-Type", "text/plain")]) return ["manager %r not found!" % manager_list[0]] start_response("200 OK", [("Content-Type", "text/html")]) - return ["%s" % json.dumps(result)] + return ["%s" % json.dumps(result, cls=SynergyEncoder)] def start(self): self.model_disconnected = False @@ -357,7 +366,7 @@ class Synergy(service.Service): manager.setStatus("ERROR") raise ex - self.wsgi_server = wsgi.Server( + self.wsgi_server = Server( name="WSGI server", host_name=CONF.WSGI.host, host_port=CONF.WSGI.port, diff --git a/synergy/tests/functional/test_synergy.py b/synergy/tests/functional/test_synergy.py index 9556f1e..811f1d1 100644 --- a/synergy/tests/functional/test_synergy.py +++ b/synergy/tests/functional/test_synergy.py @@ -23,6 +23,7 @@ import sys import time from mock import Mock +from synergy.common import utils from synergy.service import Synergy logging.basicConfig(level=logging.DEBUG) @@ -47,6 +48,21 @@ def getLogger(name): return logger +def objectHookHandler(parsed_dict): + if "synergy_object" in parsed_dict: + synergy_object = parsed_dict["synergy_object"] + try: + objClass = utils.import_class(synergy_object["name"]) + + objInstance = objClass() + return objInstance.deserialize(parsed_dict) + except Exception as ex: + print(ex) + raise ex + else: + return parsed_dict + + class SynergyTests(unittest.TestCase): @mock.patch('synergy.service.LOG', LOG) @@ -66,53 +82,66 @@ class SynergyTests(unittest.TestCase): start_response = Mock() result = self.synergy.listManagers(environ={}, start_response=start_response) - result = json.loads(result[0]) - self.assertEqual(result, ["TimerManager"]) + result = json.loads(result[0], object_hook=objectHookHandler) + self.assertEqual(len(result), 1) + self.assertEqual(result[0].getName(), "TimerManager") @mock.patch('synergy.service.LOG', LOG) def test_getManagerStatus(self): start_response = Mock() result = self.synergy.getManagerStatus(environ={}, start_response=start_response) - result = json.loads(result[0]) - self.assertEqual(result, {'TimerManager': 'ACTIVE'}) + result = json.loads(result[0], object_hook=objectHookHandler) + + self.assertEqual(result[0].getStatus(), 'ACTIVE') @mock.patch('synergy.service.LOG', LOG) def test_startManager(self): - environ = {'QUERY_STRING': 'manager=TimerManager'} start_response = Mock() + environ = {'QUERY_STRING': 'manager=NONE'} result = self.synergy.startManager(environ, start_response) - result = json.loads(result[0]) - self.assertEqual(result, {'TimerManager': { - 'message': 'started successfully', 'status': 'RUNNING'}}) + self.assertEqual(result[0], "manager 'NONE' not found!") + + environ = {'QUERY_STRING': 'manager=TimerManager'} + + result = self.synergy.startManager(environ, start_response) + result = json.loads(result[0], object_hook=objectHookHandler) + + self.assertEqual(result[0].getStatus(), 'RUNNING') + self.assertEqual(result[0].get("message"), 'started successfully') time.sleep(0.5) result = self.synergy.startManager(environ, start_response) - result = json.loads(result[0]) + result = json.loads(result[0], object_hook=objectHookHandler) - self.assertEqual(result, {'TimerManager': { - 'message': 'WARN: already started', 'status': 'RUNNING'}}) + self.assertEqual(result[0].getStatus(), 'RUNNING') + self.assertEqual(result[0].get("message"), 'WARN: already started') @mock.patch('synergy.service.LOG', LOG) def test_stopManager(self): - environ = {'QUERY_STRING': 'manager=TimerManager'} - start_response = Mock() + stop_response = Mock() + environ = {'QUERY_STRING': 'manager=NONE'} - result = self.synergy.startManager(environ, start_response) + result = self.synergy.startManager(environ, stop_response) + + self.assertEqual(result[0], "manager 'NONE' not found!") + + environ = {'QUERY_STRING': 'manager=TimerManager'} + + result = self.synergy.startManager(environ, stop_response) + result = json.loads(result[0], object_hook=objectHookHandler) time.sleep(0.5) - result = self.synergy.stopManager(environ, start_response) + result = self.synergy.stopManager(environ, stop_response) + result = json.loads(result[0], object_hook=objectHookHandler) - result = json.loads(result[0]) - - self.assertEqual(result, {'TimerManager': { - 'message': 'stopped successfully', 'status': 'ACTIVE'}}) + self.assertEqual(result[0].getStatus(), 'ACTIVE') @mock.patch('synergy.service.LOG', LOG) def test_executeCommand(self): diff --git a/synergy/tests/test_manager_abstract.py b/synergy/tests/test_manager_abstract.py index 6ccc4f7..0f5704a 100644 --- a/synergy/tests/test_manager_abstract.py +++ b/synergy/tests/test_manager_abstract.py @@ -27,6 +27,7 @@ class TestManager(base.TestCase): def setUp(self): super(TestManager, self).setUp() self.manager = Manager(name="dummy_manager") + self.manager.setAutoStart(False) def test_get_name(self): self.assertEqual("dummy_manager", self.manager.getName()) diff --git a/test-requirements.txt b/test-requirements.txt index fc29660..56027c3 100644 --- a/test-requirements.txt +++ b/test-requirements.txt @@ -13,3 +13,5 @@ testrepository>=0.0.18 testscenarios>=0.4 testtools>=1.4.0 mock==2.0.0 +tabulate>=0.7.2,<0.8.0 +