From 64df20c7cee4bc81841dd888773e0215b31afff0 Mon Sep 17 00:00:00 2001 From: Marek Franciszkiewicz Date: Sat, 7 Apr 2018 23:04:57 +0200 Subject: [PATCH] Node.quit RPC call (#2589) --- golem/node.py | 13 +++++++ golem/rpc/mapping/rpcmethodnames.py | 5 ++- tests/golem/test_opt_node.py | 60 +++++++++++++++++++++++++++-- 3 files changed, 72 insertions(+), 6 deletions(-) diff --git a/golem/node.py b/golem/node.py index 2dd84de4ee..c5d65a33d5 100644 --- a/golem/node.py +++ b/golem/node.py @@ -108,6 +108,19 @@ def on_rpc_ready() -> Deferred: except Exception as exc: # pylint: disable=broad-except logger.exception("Application error: %r", exc) + def quit(self) -> None: + + def _quit(): + reactor = self._reactor + if self.client: + self.client.quit() + if reactor.running: + reactor.callFromThread(reactor.stop) + + # Call in a separate thread and return early + from threading import Thread + Thread(target=_quit).start() + def set_password(self, password: str) -> bool: logger.info("Got password") diff --git a/golem/rpc/mapping/rpcmethodnames.py b/golem/rpc/mapping/rpcmethodnames.py index b382412a63..04dc8fe06c 100644 --- a/golem/rpc/mapping/rpcmethodnames.py +++ b/golem/rpc/mapping/rpcmethodnames.py @@ -88,9 +88,8 @@ withdraw= 'pay.withdraw', get_withdraw_gas_cost= 'pay.withdraw.gas_cost', - quit= 'ui.quit', resume= 'ui.start', - pause= 'ui.stop' + pause= 'ui.stop', ) NODE_METHOD_MAP = dict( @@ -100,4 +99,6 @@ are_terms_accepted= 'golem.terms', accept_terms= 'golem.terms.accept', show_terms= 'golem.terms.show', + + quit= 'ui.quit', ) diff --git a/tests/golem/test_opt_node.py b/tests/golem/test_opt_node.py index 9f009ede49..8f1e1e6ee5 100644 --- a/tests/golem/test_opt_node.py +++ b/tests/golem/test_opt_node.py @@ -485,6 +485,23 @@ def set_keys_auth(obj): obj._keys_auth = Mock() +def call_now(fn, *args, **kwargs): + fn(*args, **kwargs) + + +class MockThread: + + def __init__(self, target=None) -> None: + self._target = target + + def start(self): + self._target() + + @property + def target(self): + return self._target + + @patch('golem.node.Node._start_keys_auth', set_keys_auth) @patch('golem.node.Node._start_docker') @patch('golem.node.async_run', mock_async_run) @@ -501,10 +518,11 @@ def setUp(self): self.node = None def tearDown(self): - if self.node.client: - self.node.client.quit() - if self.node._db: - self.node._db.close() + if self.node: + if self.node.client: + self.node.client.quit() + if self.node._db: + self.node._db.close() super().tearDown() def test_start_rpc_router(self, reactor, *_): @@ -674,3 +692,37 @@ def test_error(self, reactor, *_): error_result = error('error message') assert reactor.callFromThread.called assert error_result is None + + @patch('golem.node.Database') + @patch('threading.Thread', MockThread) + @patch('twisted.internet.reactor', create=True) + def test_quit_mock(self, reactor, *_): + reactor.running = False + reactor.callFromThread = call_now + + node = Node.__new__(Node) + + setattr(node, '_reactor', reactor) + setattr(node, 'client', None) + + node.quit() + + assert not node._reactor.stop.called + + @patch('golem.node.Database') + @patch('threading.Thread', MockThread) + @patch('twisted.internet.reactor', create=True) + def test_quit(self, reactor, *_): + reactor.running = True + + self.node = Node(datadir=self.path, + app_config=Mock(), + config_desc=ClientConfigDescriptor(), + use_docker_manager=False) + + self.node.client = Mock() + self.node._reactor.callFromThread = call_now + + self.node.quit() + assert self.node.client.quit.called + assert self.node._reactor.stop.called