From 3b568b70a0c9c394938a8be48098c51e10868300 Mon Sep 17 00:00:00 2001 From: Lisa Zangrando Date: Wed, 24 May 2017 10:39:26 +0200 Subject: [PATCH] Enhancement in handling the parameters defined in the user request The Synergy's methods startManager() stopManager() getManagerStatus() and executeCommand() require the parsing of the parameters included into the user request and make some checks for the mandatory parameters. This commit enhances this parsing and checking steps by using the Python decorators. Moreover it simplifies the execution of the methods startManager() stopManager() and getManagerStatus() by handling requests for only one manager at a time. Change-Id: Ic295ad20f03459cf3e512e795529c35bd6969ed3 Sem-Ver: bugfix --- synergy/client/command.py | 21 +- synergy/client/shell.py | 14 +- synergy/service.py | 271 +++++++----------- synergy/tests/functional/test_synergy.py | 38 ++- .../test_client_command_managercommand.py | 154 ++-------- 5 files changed, 171 insertions(+), 327 deletions(-) diff --git a/synergy/client/command.py b/synergy/client/command.py index 48593c8..d5fa88c 100644 --- a/synergy/client/command.py +++ b/synergy/client/command.py @@ -80,19 +80,18 @@ class ManagerCommand(HTTPCommand): "status", add_help=True, help="show the managers status") status_parser.add_argument( - "manager", nargs='*', help="one or more manager name") + "manager", nargs='?', default=None, help="at most one manager") start_parser = manager_parsers.add_parser( "start", add_help=True, help="start the manager") - start_parser.add_argument( - "manager", nargs='+', help="one or more manager name") + start_parser.add_argument("manager", help="the manager to start") stop_parser = manager_parsers.add_parser( "stop", add_help=True, help="stop the manager") stop_parser.add_argument( - "manager", nargs='+', help="one or more manager name") + "manager", help="the manager to stop") def execute(self, synergy_url, args=None): table = [] @@ -113,21 +112,19 @@ class ManagerCommand(HTTPCommand): headers.append("rate (min)") url += "/synergy/" + args.command - managers = super(ManagerCommand, self).execute( + result = super(ManagerCommand, self).execute( url, {"manager": args.manager}) if args.command == "status": - for manager in managers: + for manager in result: table.append([manager.getName(), manager.getStatus(), manager.getRate()]) else: - for manager in managers: - msg = manager.get("message") - - table.append([manager.getName(), - manager.getStatus() + " (%s)" % msg, - manager.getRate()]) + msg = result.get("message") + table.append([result.getName(), + result.getStatus() + " (%s)" % msg, + result.getRate()]) print(tabulate(table, headers, tablefmt="fancy_grid")) diff --git a/synergy/client/shell.py b/synergy/client/shell.py index 627a1c4..41ba896 100644 --- a/synergy/client/shell.py +++ b/synergy/client/shell.py @@ -1,10 +1,12 @@ import os import os.path -import requests import sys from argparse import ArgumentParser from pkg_resources import iter_entry_points +from requests.exceptions import ConnectionError +from requests.exceptions import HTTPError +from requests.exceptions import RequestException from synergy.client import keystone_v3 __author__ = "Lisa Zangrando" @@ -167,14 +169,14 @@ def main(): commands[command_name].setToken(token) commands[command_name].execute(synergy_url, args) - except KeyboardInterrupt as e: + except KeyboardInterrupt: print("Shutting down synergyclient") sys.exit(1) - except requests.exceptions.HTTPError as e: - print("HTTPError: %s" % e.response._content) + except (RequestException, ConnectionError, HTTPError) as ex: + print("connection to %s failed!" % synergy_url) sys.exit(1) - except Exception as e: - print("ERROR: %s" % e) + except Exception as ex: + print(ex.message) sys.exit(1) diff --git a/synergy/service.py b/synergy/service.py index e5a1b55..92b8dba 100644 --- a/synergy/service.py +++ b/synergy/service.py @@ -153,15 +153,58 @@ class Synergy(Service): self.saved_args, self.saved_kwargs = args, kwargs - def authorizationRequired(f): + def parseParameters(f): + def wrapper(self, *args, **kw): + context = args[0] + + query = context.get("QUERY_STRING", None) + + if query: + parameters = parse_qs(query) + + for key in parameters: + value = escape(parameters[key][0]) + value = value.replace("'", "\"") + + try: + value = json.loads(value) + except ValueError: + pass + + context[key] = value + + return f(self, *args, **kw) + + return wrapper + + def checkParameters(paremeters): + def check(f): + def wrapper(self, *args, **kw): + context = args[0] + start_response = args[1] + + for parameter in paremeters: + value = context.get(parameter, None) + + if not value: + start_response("400 BAD REQUEST", + [("Content-Type", "text/plain")]) + return "parameter %s not found!" % parameter + + if parameter == "manager" and value not in self.managers: + start_response("404 NOT FOUND", + [("Content-Type", "text/plain")]) + return "manager %s not found!" % value + + return f(self, *args, **kw) + return wrapper + return check + + def authorize(f): def wrapper(self, *args, **kw): if self.auth_plugin: context = args[0] context["managers"] = self.managers - query = context.get("QUERY_STRING", None) - - if query: - context.update(parse_qs(query)) try: self.auth_plugin.authorize(context) @@ -174,7 +217,7 @@ class Synergy(Service): return wrapper - @authorizationRequired + @authorize def listManagers(self, environ, start_response): result = [] @@ -188,23 +231,21 @@ class Synergy(Service): start_response("200 OK", [("Content-Type", "text/html")]) return ["%s" % json.dumps(result, cls=SynergyEncoder)] - @authorizationRequired + @parseParameters + @authorize def getManagerStatus(self, environ, start_response): + manager_name = environ.get("manager", None) + manager_list = None result = [] - query = environ.get("QUERY_STRING", None) + if manager_name: + if manager_name not in self.managers: + start_response("404 NOT FOUND", + [("Content-Type", "text/plain")]) + return "manager %s not found!" % manager_name - if query: - parameters = parse_qs(query) - - if "manager" in parameters: - if isinstance(parameters['manager'], (list, tuple)): - manager_list = parameters['manager'] - else: - manager_list = [parameters['manager']] - else: - manager_list = self.managers.keys() + manager_list = [manager_name] else: manager_list = self.managers.keys() @@ -220,184 +261,94 @@ class Synergy(Service): result.append(m) - if len(manager_list) == 1 and len(result) == 0: - start_response("404 NOT FOUND", [("Content-Type", "text/plain")]) - return ["manager %s not found!" % manager_list[0]] - start_response("200 OK", [("Content-Type", "text/html")]) - return ["%s" % json.dumps(result, cls=SynergyEncoder)] + return [json.dumps(result, cls=SynergyEncoder)] - @authorizationRequired + @parseParameters + @checkParameters(["manager", "command", "args"]) + @authorize def executeCommand(self, environ, start_response): - manager_name = None - command = None - query = environ.get("QUERY_STRING", None) - - if not query: - start_response("400 BAD REQUEST", [("Content-Type", "text/plain")]) - return ["bad request"] - - parameters = parse_qs(query) - LOG.debug("execute command: parameters=%s" % parameters) - - if "manager" not in parameters: - start_response("400 BAD REQUEST", [("Content-Type", "text/plain")]) - return ["manager not specified!"] - - manager_name = escape(parameters['manager'][0]) - - if manager_name not in self.managers: - start_response("404 NOT FOUND", [("Content-Type", "text/plain")]) - return ["manager %s not found!" % manager_name] - - if "command" not in parameters: - start_response("400 BAD REQUEST", [("Content-Type", "text/plain")]) - return ["bad request"] - - command = escape(parameters['command'][0]) - - if "args" in parameters: - manager_args = escape(parameters['args'][0]) - manager_args = manager_args.replace("'", "\"") - manager_args = json.loads(manager_args) - else: - manager_args = {} - + manager_name = environ["manager"] manager = self.managers[manager_name] + manager_args = environ["args"] + command = environ["command"] try: result = manager.execute(command=command, **manager_args) start_response("200 OK", [("Content-Type", "text/html")]) - return ["%s" % json.dumps(result, cls=SynergyEncoder)] + return [json.dumps(result, cls=SynergyEncoder)] except NotImplementedError: message = "execute() not implemented!" LOG.error(message) start_response("500 INTERNAL SERVER ERROR", [("Content-Type", "text/plain")]) - return ["error: %s" % message] + return message except SynergyError as ex: LOG.debug("execute command: error=%s" % ex) + start_response("500 INTERNAL SERVER ERROR", [("Content-Type", "text/plain")]) - return ["error: %s" % ex] + return "%s" % ex - @authorizationRequired + @parseParameters + @checkParameters(["manager"]) + @authorize def startManager(self, environ, start_response): - manager_list = None - result = [] + manager_name = environ["manager"] + manager = self.managers[manager_name] + result = Manager(manager_name) + result.setRate(manager.getRate()) - query = environ.get("QUERY_STRING", None) + if manager.getStatus() == "ACTIVE": + LOG.info("starting the %s manager" % (manager_name)) - if not query: - start_response("400 BAD REQUEST", [("Content-Type", "text/plain")]) - return ["bad request"] + manager.resume() - parameters = parse_qs(query) + LOG.info("%s manager started! (rate=%s min)" + % (manager_name, manager.getRate())) - if "manager" not in parameters: - start_response("400 BAD REQUEST", [("Content-Type", "text/plain")]) - return ["manager not specified!"] - - if isinstance(parameters['manager'], (list, tuple)): - manager_list = parameters['manager'] - else: - manager_list = [parameters['manager']] - - for manager_name in manager_list: - manager_name = escape(manager_name) - - if manager_name not in self.managers: - continue - - manager = self.managers[manager_name] - m = Manager(manager_name) - m.setRate(manager.getRate()) - - result.append(m) - - if manager.getStatus() == "ACTIVE": - LOG.info("starting the %s manager" % (manager_name)) - - manager.resume() - - LOG.info("%s manager started! (rate=%s min)" - % (manager_name, manager.getRate())) - - m.setStatus("RUNNING") - m.set("message", "started successfully") - elif manager.getStatus() == "RUNNING": - m.setStatus("RUNNING") - m.set("message", "WARN: already started") - elif manager.getStatus() == "ERROR": - 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]] + result.setStatus("RUNNING") + result.set("message", "started successfully") + elif manager.getStatus() == "RUNNING": + result.setStatus("RUNNING") + result.set("message", "WARN: already started") + elif manager.getStatus() == "ERROR": + result.setStatus("ERROR") + result.set("message", "wrong state") start_response("200 OK", [("Content-Type", "text/html")]) - return ["%s" % json.dumps(result, cls=SynergyEncoder)] + return json.dumps(result, cls=SynergyEncoder) - @authorizationRequired + @parseParameters + @checkParameters(["manager"]) + @authorize def stopManager(self, environ, start_response): - manager_list = None - result = [] - query = environ.get("QUERY_STRING", None) + manager_name = environ["manager"] + manager = self.managers[manager_name] + result = Manager(manager_name) + result.setRate(manager.getRate()) - if not query: - start_response("400 BAD REQUEST", [("Content-Type", "text/plain")]) - return ["bad request"] + if manager.getStatus() == "RUNNING": + LOG.info("stopping the %s manager" % (manager_name)) - parameters = parse_qs(query) + manager.pause() - if "manager" not in parameters: - start_response("400 BAD REQUEST", [("Content-Type", "text/plain")]) - return ["manager not specified!"] + LOG.info("%s manager stopped!" % (manager_name)) - if isinstance(parameters['manager'], (list, tuple)): - manager_list = parameters['manager'] - else: - manager_list = [parameters['manager']] - - for manager_name in manager_list: - manager_name = escape(manager_name) - - if manager_name not in self.managers: - continue - - manager = self.managers[manager_name] - - m = Manager(manager_name) - m.setRate(manager.getRate()) - - result.append(m) - - if manager.getStatus() == "RUNNING": - LOG.info("stopping the %s manager" % (manager_name)) - - manager.pause() - - LOG.info("%s manager stopped!" % (manager_name)) - - m.setStatus("ACTIVE") - m.set("message", "stopped successfully") - elif manager.getStatus() == "ACTIVE": - m.setStatus("ACTIVE") - m.set("message", "WARN: already stopped") - elif manager.getStatus() == "ERROR": - 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]] + result.setStatus("ACTIVE") + result.set("message", "stopped successfully") + elif manager.getStatus() == "ACTIVE": + result.setStatus("ACTIVE") + result.set("message", "WARN: already stopped") + elif manager.getStatus() == "ERROR": + result.setStatus("ERROR") + result.set("message", "wrong state") start_response("200 OK", [("Content-Type", "text/html")]) - return ["%s" % json.dumps(result, cls=SynergyEncoder)] + return json.dumps(result, cls=SynergyEncoder) def start(self): self.model_disconnected = False diff --git a/synergy/tests/functional/test_synergy.py b/synergy/tests/functional/test_synergy.py index 4ab1859..32e8efa 100644 --- a/synergy/tests/functional/test_synergy.py +++ b/synergy/tests/functional/test_synergy.py @@ -75,7 +75,17 @@ class SynergyTests(unittest.TestCase): @mock.patch('synergy.service.LOG', LOG) def test_getManagerStatus(self): start_response = Mock() - result = self.synergy.getManagerStatus(environ={}, + environ = {} + result = self.synergy.getManagerStatus(environ, + start_response=start_response) + + result = json.loads(result[0], object_hook=objectHookHandler) + + self.assertEqual(result[0].getStatus(), 'ACTIVE') + + environ = {'QUERY_STRING': 'manager=TimerManager'} + + result = self.synergy.getManagerStatus(environ, start_response=start_response) result = json.loads(result[0], object_hook=objectHookHandler) @@ -89,23 +99,23 @@ class SynergyTests(unittest.TestCase): result = self.synergy.startManager(environ, start_response) - self.assertEqual(result[0], "manager 'NONE' not found!") + self.assertEqual(result, "manager NONE not found!") environ = {'QUERY_STRING': 'manager=TimerManager'} result = self.synergy.startManager(environ, start_response) - result = json.loads(result[0], object_hook=objectHookHandler) + result = json.loads(result, object_hook=objectHookHandler) - self.assertEqual(result[0].getStatus(), 'RUNNING') - self.assertEqual(result[0].get("message"), 'started successfully') + self.assertEqual(result.getStatus(), 'RUNNING') + self.assertEqual(result.get("message"), 'started successfully') time.sleep(0.5) result = self.synergy.startManager(environ, start_response) - result = json.loads(result[0], object_hook=objectHookHandler) + result = json.loads(result, object_hook=objectHookHandler) - self.assertEqual(result[0].getStatus(), 'RUNNING') - self.assertEqual(result[0].get("message"), 'WARN: already started') + self.assertEqual(result.getStatus(), 'RUNNING') + self.assertEqual(result.get("message"), 'WARN: already started') @mock.patch('synergy.service.LOG', LOG) def test_stopManager(self): @@ -114,23 +124,25 @@ class SynergyTests(unittest.TestCase): result = self.synergy.startManager(environ, stop_response) - self.assertEqual(result[0], "manager 'NONE' not found!") + self.assertEqual(result, "manager NONE not found!") environ = {'QUERY_STRING': 'manager=TimerManager'} result = self.synergy.startManager(environ, stop_response) - result = json.loads(result[0], object_hook=objectHookHandler) + result = json.loads(result, object_hook=objectHookHandler) time.sleep(0.5) result = self.synergy.stopManager(environ, stop_response) - result = json.loads(result[0], object_hook=objectHookHandler) + result = json.loads(result, object_hook=objectHookHandler) - self.assertEqual(result[0].getStatus(), 'ACTIVE') + self.assertEqual(result.getStatus(), 'ACTIVE') @mock.patch('synergy.service.LOG', LOG) def test_executeCommand(self): - environ = {'QUERY_STRING': 'manager=TimerManager&command=GET_TIME'} + environ = {'QUERY_STRING': + 'manager=TimerManager&args=%7B%22id%22%3A' + '+null%2C+%22name%22%3A+%22prj_a%22%7D&command=GET_TIME'} start_response = Mock() result = self.synergy.executeCommand(environ, start_response) diff --git a/synergy/tests/unit/test_client_command_managercommand.py b/synergy/tests/unit/test_client_command_managercommand.py index daa9b68..fe6f0d2 100644 --- a/synergy/tests/unit/test_client_command_managercommand.py +++ b/synergy/tests/unit/test_client_command_managercommand.py @@ -49,22 +49,22 @@ class TestManagerCommand(base.TestCase): # manager status res = root_parser.parse_args(["manager", "status"]) - ns = Namespace(command_name="manager", command="status", manager=[]) + ns = Namespace(command_name="manager", command="status", manager=None) self.assertEqual(ns, res) res = root_parser.parse_args(["manager", "status", "TestManager"]) ns = Namespace( command_name="manager", command="status", - manager=["TestManager"]) + manager="TestManager") self.assertEqual(ns, res) res = root_parser.parse_args( - ["manager", "status", "Test1", "Test2", "Test3"]) + ["manager", "status", "Test1"]) ns = Namespace( command_name="manager", command="status", - manager=["Test1", "Test2", "Test3"]) + manager="Test1") self.assertEqual(ns, res) # manager start @@ -77,15 +77,15 @@ class TestManagerCommand(base.TestCase): ns = Namespace( command_name="manager", command="start", - manager=["TestManager"]) + manager="TestManager") self.assertEqual(ns, res) res = root_parser.parse_args( - ["manager", "start", "Test1", "Test2"]) + ["manager", "start", "Test1"]) ns = Namespace( command_name="manager", command="start", - manager=["Test1", "Test2"]) + manager="Test1") self.assertEqual(ns, res) # manager stop @@ -98,15 +98,15 @@ class TestManagerCommand(base.TestCase): ns = Namespace( command_name="manager", command="stop", - manager=["TestManager"]) + manager="TestManager") self.assertEqual(ns, res) res = root_parser.parse_args( - ["manager", "stop", "Test1", "Test2"]) + ["manager", "stop", "Test1"]) ns = Namespace( command_name="manager", command="stop", - manager=["Test1", "Test2"]) + manager="Test1") self.assertEqual(ns, res) @mock.patch('synergy.client.command.tabulate') @@ -204,50 +204,12 @@ class TestManagerCommand(base.TestCase): tablefmt="fancy_grid") @mock.patch('synergy.client.command.tabulate') - def test_execute_status_two_managers(self, mock_tabulate): - """Check the CLI output of "manager status ManagerA ManagerB".""" - # Mock the parser call - mock_parser = mock.Mock() - mock_parser.args.command = "status" - mock_parser.args.manager = ["ManagerA", "ManagerB"] - - # Mock 2 managers and their statuses - manager_a = mock.Mock() - manager_a.getName.return_value = "ManagerA" - manager_a.getStatus.return_value = "UP" - manager_a.getRate.return_value = 5 - manager_b = mock.Mock() - manager_b.getName.return_value = "ManagerB" - manager_b.getStatus.return_value = "DOWN" - manager_b.getRate.return_value = 10 - mgrs = [manager_a, manager_b] - - # Execute "manager status ManagerA ManagerB" - with mock.patch.object(HTTPCommand, 'execute', return_value=mgrs) as m: - self.manager_command.execute(synergy_url="", args=mock_parser.args) - - # Check the executed call - m.assert_called_once_with( - "/synergy/status", - {"manager": ["ManagerA", "ManagerB"]}) - - # Check the data when we call tabulate - headers = ["manager", "status", "rate (min)"] - table = [ - ["ManagerA", "UP", 5], - ["ManagerB", "DOWN", 10]] - mock_tabulate.assert_called_once_with( - table, - headers, - tablefmt="fancy_grid") - - @mock.patch('synergy.client.command.tabulate') - def test_execute_start_one_manager(self, mock_tabulate): + def test_execute_start_manager(self, mock_tabulate): """Check the CLI output of "manager start ManagerA".""" # Mock the parser call mock_parser = mock.Mock() mock_parser.args.command = "start" - mock_parser.args.manager = ["ManagerA"] + mock_parser.args.manager = "ManagerA" # Mock a manager manager_a = mock.Mock() @@ -255,7 +217,7 @@ class TestManagerCommand(base.TestCase): manager_a.getStatus.return_value = "RUNNING" manager_a.get.return_value = "started successfully" manager_a.getRate.return_value = 1 - mgrs = [manager_a] + mgrs = manager_a # Execute "manager start ManagerA" with mock.patch.object(HTTPCommand, 'execute', return_value=mgrs) as m: @@ -264,7 +226,7 @@ class TestManagerCommand(base.TestCase): # Check the executed call to "manager start ManagerA" m.assert_called_once_with( "/synergy/start", - {"manager": ["ManagerA"]}) + {"manager": "ManagerA"}) # Check the data when we call tabulate headers = ["manager", "status", "rate (min)"] @@ -275,52 +237,12 @@ class TestManagerCommand(base.TestCase): tablefmt="fancy_grid") @mock.patch('synergy.client.command.tabulate') - def test_execute_start_two_managers(self, mock_tabulate): - """Check the CLI output of "manager start ManagerA ManagerB".""" - # Mock the parser call - mock_parser = mock.Mock() - mock_parser.args.command = "start" - mock_parser.args.manager = ["ManagerA", "ManagerB"] - - # Mock 2 managers - manager_a = mock.Mock() - manager_a.getName.return_value = "ManagerA" - manager_a.getStatus.return_value = "RUNNING" - manager_a.get.return_value = "started successfully" - manager_a.getRate.return_value = 1 - manager_b = mock.Mock() - manager_b.getName.return_value = "ManagerB" - manager_b.getStatus.return_value = "RUNNING" - manager_b.get.return_value = "started successfully" - manager_b.getRate.return_value = 4 - mgrs = [manager_a, manager_b] - - # Execute "manager start ManagerA ManagerB" - with mock.patch.object(HTTPCommand, 'execute', return_value=mgrs) as m: - self.manager_command.execute(synergy_url='', args=mock_parser.args) - - # Check the executed call to "manager start ManagerA ManagerB" - m.assert_called_once_with( - "/synergy/start", - {"manager": ["ManagerA", "ManagerB"]}) - - # Check the data when we call tabulate - headers = ["manager", "status", "rate (min)"] - table = [ - ["ManagerA", "RUNNING (started successfully)", 1], - ["ManagerB", "RUNNING (started successfully)", 4]] - mock_tabulate.assert_called_once_with( - table, - headers, - tablefmt="fancy_grid") - - @mock.patch('synergy.client.command.tabulate') - def test_execute_stop_one_manager(self, mock_tabulate): + def test_execute_stop_manager(self, mock_tabulate): """Check the CLI output of "manager stop ManagerA".""" # Mock the parser call mock_parser = mock.Mock() mock_parser.args.command = "stop" - mock_parser.args.manager = ["ManagerA"] + mock_parser.args.manager = "ManagerA" # Mock a manager manager_a = mock.Mock() @@ -328,7 +250,7 @@ class TestManagerCommand(base.TestCase): manager_a.getStatus.return_value = "ACTIVE" manager_a.get.return_value = "stopped successfully" manager_a.getRate.return_value = 1 - mgrs = [manager_a] + mgrs = manager_a # Execute "manager stop ManagerA" with mock.patch.object(HTTPCommand, 'execute', return_value=mgrs) as m: @@ -337,7 +259,7 @@ class TestManagerCommand(base.TestCase): # Check the executed call to "manager stop ManagerA" m.assert_called_once_with( "/synergy/stop", - {"manager": ["ManagerA"]}) + {"manager": "ManagerA"}) # Check the data when we call tabulate headers = ["manager", "status", "rate (min)"] @@ -346,43 +268,3 @@ class TestManagerCommand(base.TestCase): table, headers, tablefmt="fancy_grid") - - @mock.patch('synergy.client.command.tabulate') - def test_execute_stop_two_managers(self, mock_tabulate): - """Check the CLI output of "manager stop ManagerA ManagerB".""" - # Mock the parser call - mock_parser = mock.Mock() - mock_parser.args.command = "stop" - mock_parser.args.manager = ["ManagerA", "ManagerB"] - - # Mock 2 managers - manager_a = mock.Mock() - manager_a.getName.return_value = "ManagerA" - manager_a.getStatus.return_value = "ACTIVE" - manager_a.get.return_value = "stopped successfully" - manager_a.getRate.return_value = 1 - manager_b = mock.Mock() - manager_b.getName.return_value = "ManagerB" - manager_b.getStatus.return_value = "ACTIVE" - manager_b.get.return_value = "stopped successfully" - manager_b.getRate.return_value = 4 - mgrs = [manager_a, manager_b] - - # Execute "manager stop ManagerA ManagerB" - with mock.patch.object(HTTPCommand, 'execute', return_value=mgrs) as m: - self.manager_command.execute(synergy_url='', args=mock_parser.args) - - # Check the executed call to "manager start ManagerA ManagerB" - m.assert_called_once_with( - "/synergy/stop", - {"manager": ["ManagerA", "ManagerB"]}) - - # Check the data when we call tabulate - headers = ["manager", "status", "rate (min)"] - table = [ - ["ManagerA", "ACTIVE (stopped successfully)", 1], - ["ManagerB", "ACTIVE (stopped successfully)", 4]] - mock_tabulate.assert_called_once_with( - table, - headers, - tablefmt="fancy_grid")