From ae6215c625a8f520e74ee513a38448b6a99d7c09 Mon Sep 17 00:00:00 2001 From: Aleksey Lim Date: Sat, 12 Oct 2013 12:49:20 +0000 Subject: While monitoring connectivity status, handle getting offline --- diff --git a/sugar_network/client/routes.py b/sugar_network/client/routes.py index 42b1a36..0d869d0 100644 --- a/sugar_network/client/routes.py +++ b/sugar_network/client/routes.py @@ -124,8 +124,6 @@ class ClientRoutes(model.FrontRoutes, implementations.Routes, journal.Routes): @route('GET', cmd='inline', mime_type='application/json') def inline(self): - if not self._server_mode and not self._inline.is_set(): - self._remote_connect() return self._inline.is_set() def whoami(self, request, response): @@ -229,20 +227,17 @@ class ClientRoutes(model.FrontRoutes, implementations.Routes, journal.Routes): def _got_offline(self, force=False): if not force and not self._inline.is_set(): return - _logger.debug('Got offline on %r', self._node) - self._node.close() + if self._node is not None: + _logger.debug('Got offline on %r', self._node) + self._node.close() + if self._inline.is_set(): + self.broadcast({'event': 'inline', 'state': 'offline'}) self._inline.clear() - self.broadcast({'event': 'inline', 'state': 'offline'}) self._local.volume.broadcast = self.broadcast - def _fall_offline(self): - if self._inline_job: - _logger.debug('Fall to offline on %r', self._node) - self._inline_job.kill() - def _restart_online(self): - self._fall_offline() - _logger.debug('Try to become online in %s seconds', _RECONNECT_TIMEOUT) + _logger.debug('Lost %r connection, try to reconnect in %s seconds', + self._node, _RECONNECT_TIMEOUT) self._remote_connect(_RECONNECT_TIMEOUT) def _discover_node(self): @@ -253,10 +248,11 @@ class ClientRoutes(model.FrontRoutes, implementations.Routes, journal.Routes): self._remote_connect() def _wait_for_connectivity(self): - for i in netlink.wait_for_route(): - self._fall_offline() - if i: + for gw in netlink.wait_for_route(): + if gw: self._remote_connect() + else: + self._got_offline() def _remote_connect(self, timeout=0): @@ -306,8 +302,8 @@ class ClientRoutes(model.FrontRoutes, implementations.Routes, journal.Routes): timeout *= _RECONNECT_TIMEOUT timeout = min(timeout, _RECONNECT_TIMEOUT_MAX) - if not self._inline_job: - self._inline_job.spawn_later(timeout, connect) + self._inline_job.kill() + self._inline_job.spawn_later(timeout, connect) def _found_mount(self, root): if self._inline.is_set(): diff --git a/sugar_network/toolkit/netlink.py b/sugar_network/toolkit/netlink.py index 0eb857a..9ad8370 100644 --- a/sugar_network/toolkit/netlink.py +++ b/sugar_network/toolkit/netlink.py @@ -66,7 +66,7 @@ def wait_for_route(): if not line: break dst, gw = line.split('\t', 3)[1:3] - if int(dst, 16) == 0: + if int(dst, 16) in (0, 224): return gw old_route = get_route() diff --git a/tests/__init__.py b/tests/__init__.py index 7fd18d9..84df9b3 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -294,9 +294,9 @@ class Test(unittest.TestCase): if classes is None: classes = [User, Context, Implementation] volume = db.Volume('client', classes) - commands = routes(volume, client.api_url.value) + self.client_routes = routes(volume, client.api_url.value) self.client = coroutine.WSGIServer( - ('127.0.0.1', client.ipc_port.value), Router(commands)) + ('127.0.0.1', client.ipc_port.value), Router(self.client_routes)) coroutine.spawn(self.client.serve_forever) coroutine.dispatch() return volume @@ -316,8 +316,8 @@ class Test(unittest.TestCase): def start_offline_client(self, resources=None): self.home_volume = db.Volume('db', resources or model.RESOURCES) - commands = ClientRoutes(self.home_volume) - server = coroutine.WSGIServer(('127.0.0.1', client.ipc_port.value), Router(commands)) + self.client_routes = ClientRoutes(self.home_volume) + server = coroutine.WSGIServer(('127.0.0.1', client.ipc_port.value), Router(self.client_routes)) coroutine.spawn(server.serve_forever) coroutine.dispatch() return IPCConnection() diff --git a/tests/units/client/online_routes.py b/tests/units/client/online_routes.py index d326223..6ad7484 100755 --- a/tests/units/client/online_routes.py +++ b/tests/units/client/online_routes.py @@ -1335,7 +1335,7 @@ Can't find all required implementations: yield 'emote"' node_pid = self.fork_master([User], NodeRoutes) - ipc.get(cmd='inline') + self.client_routes._remote_connect() self.wait_for_events(ipc, event='inline', state='online').wait() ts = time.time() @@ -1353,7 +1353,7 @@ Can't find all required implementations: assert not ipc.get(cmd='inline') node_pid = self.fork_master([User], NodeRoutes) - ipc.get(cmd='inline') + self.client_routes._remote_connect() self.wait_for_events(ipc, event='inline', state='online').wait() coroutine.spawn(kill) @@ -1361,7 +1361,7 @@ Can't find all required implementations: assert not ipc.get(cmd='inline') node_pid = self.fork_master([User], NodeRoutes) - ipc.get(cmd='inline') + self.client_routes._remote_connect() self.wait_for_events(ipc, event='inline', state='online').wait() coroutine.spawn(kill) @@ -1423,18 +1423,18 @@ Can't find all required implementations: assert Routes.subscribe_tries > 2 def test_inline(self): + routes._RECONNECT_TIMEOUT = 2 + cp = ClientRoutes(Volume('client', model.RESOURCES), client.api_url.value) assert not cp.inline() trigger = self.wait_for_events(cp, event='inline', state='online') - coroutine.sleep(1) + coroutine.sleep(.5) self.start_master() - trigger.wait(1) + trigger.wait(.5) assert trigger.value is None assert not cp.inline() - request = Request(method='GET', cmd='whoami') - cp.whoami(request, Response()) trigger.wait() assert cp.inline() diff --git a/tests/units/client/routes.py b/tests/units/client/routes.py index 6b0d6e5..53b1924 100755 --- a/tests/units/client/routes.py +++ b/tests/units/client/routes.py @@ -145,7 +145,7 @@ class RoutesTest(tests.Test): trigger = self.wait_for_events(cp, event='inline', state='online') node_volume = self.start_master() - call(cp, Request(method='GET', cmd='inline')) + cp._remote_connect() trigger.wait() guid = call(cp, post) @@ -169,7 +169,7 @@ class RoutesTest(tests.Test): trigger = self.wait_for_events(cp, event='push') self.start_master() - call(cp, Request(method='GET', cmd='inline')) + cp._remote_connect() trigger.wait() self.assertEqual([[3, None]], json.load(file('client/push.sequence'))) @@ -198,7 +198,7 @@ class RoutesTest(tests.Test): trigger = self.wait_for_events(cp, event='push') self.start_master() - call(cp, Request(method='GET', cmd='inline')) + cp._remote_connect() trigger.wait() self.assertEqual([[4, None]], json.load(file('client/push.sequence'))) @@ -227,7 +227,7 @@ class RoutesTest(tests.Test): trigger = self.wait_for_events(cp, event='push') self.start_master([User, Report]) - call(cp, Request(method='GET', cmd='inline')) + cp._remote_connect() trigger.wait() assert not volume['report'].exists(guid) @@ -250,7 +250,7 @@ class RoutesTest(tests.Test): trigger = self.wait_for_events(cp, event='push') self.start_master() - call(cp, Request(method='GET', cmd='inline')) + cp._remote_connect() trigger.wait() self.assertEqual([[2, None]], json.load(file('client/push.sequence'))) @@ -275,7 +275,7 @@ class RoutesTest(tests.Test): trigger = self.wait_for_events(cp, event='inline', state='online') self.start_master() - call(cp, Request(method='GET', cmd='inline')) + cp._remote_connect() trigger.wait() assert not self.node_volume['context'].exists(guid) diff --git a/tests/units/toolkit/options.py b/tests/units/toolkit/options.py index 385c4da..1c5afa5 100755 --- a/tests/units/toolkit/options.py +++ b/tests/units/toolkit/options.py @@ -1,6 +1,8 @@ #!/usr/bin/env python # sugar-lint: disable +from ConfigParser import ConfigParser + from __init__ import tests from sugar_network.toolkit import Option @@ -33,14 +35,14 @@ class OptionsTest(tests.Test): '[section]', 'option = 1', ])) - Option.load(['config']) + Option.load(['./config']) self.assertEqual('1', option.value) option.value = '2' Option.save() option.value = '' - Option.load(['config']) + Option.load(['./config']) self.assertEqual('2', option.value) def test_PreserveNonSeekConfigOnSave(self): @@ -55,7 +57,7 @@ class OptionsTest(tests.Test): '[bar]', 'o2 = 2 # bar', ])) - Option.load(['config']) + Option.load(['./config']) self.assertEqual('1', option.value) option.value = '2' @@ -74,6 +76,40 @@ class OptionsTest(tests.Test): ]), file('config').read()) + def test_SaveOnlyChangedOptions(self): + option1 = Option(name='option1', default='1') + option2 = Option(name='option2', default='2') + option3 = Option(name='option3', default='3') + Option.seek('section', [option1, option2, option3]) + Option.load(['./config']) + + self.assertEqual('1', option1.value) + self.assertEqual('2', option2.value) + self.assertEqual('3', option3.value) + + Option.save() + parser = ConfigParser() + parser.read('config') + assert not parser.has_option('section', 'option1') + assert not parser.has_option('section', 'option2') + assert not parser.has_option('section', 'option3') + + option1.value = '1_' + Option.save() + parser = ConfigParser() + parser.read('config') + self.assertEqual('1_', parser.get('section', 'option1')) + assert not parser.has_option('section', 'option2') + assert not parser.has_option('section', 'option3') + + option2.value = '2_' + Option.save() + parser = ConfigParser() + parser.read('config') + self.assertEqual('1_', parser.get('section', 'option1')) + self.assertEqual('2_', parser.get('section', 'option2')) + assert not parser.has_option('section', 'option3') + if __name__ == '__main__': tests.main() -- cgit v0.9.1