def _proxy_request(request: 'flask.Request', destination: Server, verify=False) -> requests.Response: url = destination.url() + request.full_path req_data = request.get_json() if request.path == '/ping': server_data = {'id': str(g.server.id), 'name': g.server.name, 'time': get_now().strftime(defaults.DATETIME_FORMAT)} if req_data: if 'servers' not in req_data: req_data['servers'] = {} req_data['servers'].update({len(req_data['servers']) + 1: server_data}) else: req_data = dict(servers={1: server_data}) kwargs = { 'json': req_data, 'allow_redirects': False } headers = {key.lower(): value for key, value in request.headers.items()} # Let requests reset the host for us. if 'host' in headers: del headers['host'] headers['d-source'] = headers.get('d-source', '') + ':' + str(g.server.id) kwargs['headers'] = headers cookies = request.cookies kwargs['cookies'] = cookies return requests.request(request.method, url, verify=verify, **kwargs)
def test_url(self, mock_url, mock_check_host): self.set_servers_and_routes() mock_check_host.return_value = True self.assertEqual(f'https://1.1.1.1:{defaults.DEFAULT_PORT}', self.n1.url()) self.assertEqual(f'https://n2_dns:{defaults.DEFAULT_PORT}', self.n2.url()) self.assertEqual(f'https://n3:8000', self.n3.url()) self.assertEqual(f'https://1.1.1.1:{defaults.DEFAULT_PORT}', self.r1.url()) self.assertEqual(f'https://n2_dns:{defaults.DEFAULT_PORT}', self.r2.url()) mock_url.return_value = '/' self.assertEqual(f'https://1.1.1.1:{defaults.DEFAULT_PORT}/', self.n1.url('api')) mock_url.assert_called_once_with('api') me = Server(name='me', gates=[('127.0.0.1', 5), ('192.168.1.2', 2)], me=True) self.assertEqual(f'https://127.0.0.1:5/', me.url('api')) with mock.patch('dimensigon.domain.entities.server.current_app' ) as mock_current_app: type(mock_current_app.dm.config).http_config = mock.PropertyMock( return_value={'keyfile': 'x'}) me = Server(name='me', gates=[('192.168.1.2', 2)], me=True) self.assertEqual(f'http://192.168.1.2:2/', me.url('api')) s = Server('test', port=8000) with self.assertRaises(errors.UnreachableDestination): s.url()
def test_upgrade_catalog_catalog_mismatch(self, mock_lock, mock_entities): mock_lock.return_value.__enter__.return_value = 'applicant' mock_entities.return_value = [('ActionTemplate', ActionTemplate), ('Server', Server)] s = Server('server', last_modified_at=dt.datetime(2019, 4, 1, tzinfo=dt.timezone.utc), port=8000) Route(s, cost=0) at1 = ActionTemplate(id='aaaaaaaa-1234-5678-1234-56781234aaa1', name='mkdir', version=1, action_type=ActionType.SHELL, code='mkdir {dir}', expected_output=None, expected_rc=None, system_kwargs={}, last_modified_at=dt.datetime( 2019, 4, 1, tzinfo=dt.timezone.utc)) at2 = ActionTemplate(id='aaaaaaaa-1234-5678-1234-56781234aaa2', name='rmdir', version=1, action_type=ActionType.SHELL, code='rmdir {dir}', expected_output=None, expected_rc=None, system_kwargs={}, last_modified_at=dt.datetime( 2019, 4, 2, tzinfo=dt.timezone.utc)) responses.add( method='GET', url=re.compile('^' + s.url( 'api_1_0.catalog', data_mark='12345').replace('12345', '')), json={"ActionTemplate": [at1.to_json(), at2.to_json()]}) with self.assertRaises(errors.CatalogMismatch): upgrade_catalog_from_server(s)
def test_upgrade_catalog_no_data(self, mock_lock, mock_entities): mock_lock.return_value.__enter__.return_value = 'applicant' mock_entities.return_value = [('ActionTemplate', ActionTemplate)] s = Server('server', last_modified_at=dt.datetime(2019, 4, 1, tzinfo=dt.timezone.utc)) g = Gate(server=s, port=80) Route(s, cost=0) responses.add( method='GET', url=re.compile('^' + s.url( 'api_1_0.catalog', data_mark='12345').replace('12345', '')), json={"ActionTemplate": []}) upgrade_catalog_from_server(s) atl = [at.to_json() for at in ActionTemplate.query.all()] self.assertEqual(0, len(atl))
class TestLock(FlaskAppMixin, TestCase): def setUp(self): super().setUp() set_initial() self.n1 = Server("node1", port=8000) Route(self.n1, cost=0) self.n2 = Server("node2", port=8000) Route(self.n2, cost=0) db.session.add_all([self.n1, self.n2]) db.session.commit() self.datemark = Catalog.max_catalog(str) def test_lock_no_server(self): with self.assertRaises(errors.NoServerToLock): ret = lock(Scope.ORCHESTRATION) @aioresponses() def test_lock_catalog(self, m): def callback_prevent(url, **kwargs): assert kwargs['json'] == { 'scope': 'CATALOG', 'datemark': self.datemark, 'applicant': [Server.get_current().id, self.n1.id, self.n2.id] } return CallbackResult("{'message': 'Preventing lock acquired'}", status=200) def callback_lock(url, **kwargs): assert kwargs['json'] == { 'scope': 'CATALOG', 'applicant': [ str(Server.get_current().id), str(self.n1.id), str(self.n2.id) ] } return CallbackResult("{'message': 'Locked'}", status=200) m.post(Server.get_current().url('api_1_0.locker_prevent'), callback=callback_prevent) m.post(self.n1.url('api_1_0.locker_prevent'), callback=callback_prevent) m.post(self.n2.url('api_1_0.locker_prevent'), callback=callback_prevent) m.post(Server.get_current().url('api_1_0.locker_lock'), callback=callback_lock) m.post(self.n1.url('api_1_0.locker_lock'), callback=callback_lock) m.post(self.n2.url('api_1_0.locker_lock'), callback=callback_lock) applicant = lock(Scope.CATALOG, [Server.get_current(), self.n1, self.n2], identity=ROOT) self.assertEqual(applicant, [Server.get_current().id, self.n1.id, self.n2.id]) @aioresponses() def test_lock_catalog_error_on_preventing(self, m): def callback_prevent(url, **kwargs): self.assertDictEqual( kwargs['json'], { 'scope': 'CATALOG', 'applicant': [ str(Server.get_current().id), str(self.n1.id), str(self.n2.id) ] }) return CallbackResult("{'message': 'Preventing lock acquired'}", status=200) def callback_unlock(url, **kwargs): self.assertDictEqual( kwargs['json'], { 'scope': 'CATALOG', 'action': 'UNLOCK', 'applicant': [ str(Server.get_current().id), str(self.n1.id), str(self.n2.id) ] }) return CallbackResult("{'message': 'UnLocked'}", status=200) m.post(Server.get_current().url('api_1_0.locker_prevent'), callback=callback_prevent) m.post(self.n1.url('api_1_0.locker_prevent'), exception=ClientConnectionError()) m.post(self.n2.url('api_1_0.locker_prevent'), callback=callback_prevent) m.post(Server.get_current().url('api_1_0.locker_unlock'), callback=callback_unlock) m.post(self.n2.url('api_1_0.locker_unlock'), callback=callback_unlock) with self.assertRaises(errors.LockError): lock(Scope.CATALOG, [Server.get_current(), self.n1, self.n2], identity=ROOT) c = Locker.query.get(Scope.CATALOG) self.assertEqual(State.UNLOCKED, c.state) @aioresponses() def test_lock_unreachable_network(self, m): def callback_prevent(url, **kwargs): return CallbackResult("{'message': 'Preventing lock acquired'}", status=200) def callback_unlock(url, **kwargs): return CallbackResult("{'message': 'UnLocked'}", status=200) m.post(self.n1.url('api_1_0.locker_prevent'), callback=callback_prevent) m.post(self.n2.url('api_1_0.locker_prevent'), callback=callback_prevent) m.post(self.n2.url('api_1_0.locker_unlock'), callback=callback_unlock) self.n1.route.cost = None self.n1.route.gate = None self.n1.route.proxy_server = None with self.assertRaises(errors.LockError) as e: lock(Scope.CATALOG, servers=[self.n1, self.n2], identity=ROOT) self.assertEqual(Scope.CATALOG, e.exception.scope) self.assertEqual(errors.LockError.action_map['P'], e.exception.action) self.assertDictEqual( errors.format_error_content( errors.LockError( Scope.CATALOG, action='P', responses=[ Response(exception=errors.UnreachableDestination( self.n1), server=self.n1) ])), errors.format_error_content(e.exception)) self.assertEqual(2, len(m.requests))
class TestLockUnlock(TestCase): def setUp(self): """Create and configure a new app instance for each test.""" # create the app with common test config self.app = create_app('test') self.app_context = self.app.app_context() self.app_context.push() self.client = self.app.test_client() self.headers = { "Authorization": f"Bearer {create_access_token('00000000-0000-0000-0000-000000000001')}" } db.create_all() set_initial() self.n1 = Server("node1", port=8000) Route(self.n1, cost=0) self.n2 = Server("node2", port=8000) Route(self.n2, cost=0) db.session.add_all([self.n1, self.n2]) db.session.commit() self.datamark = Catalog.max_catalog(str) def tearDown(self) -> None: db.session.remove() db.drop_all() self.app_context.pop() @aioresponses() def test_lock_unlock_lock(self, m): def callback_prevent(url, **kwargs): self.assertDictEqual( kwargs['json'], { 'scope': 'ORCHESTRATION', 'datemark': self.datamark, 'applicant': [str(self.n1.id), str(self.n2.id)] }) return CallbackResult("{'message': 'Preventing lock acquired'}", status=200) def callback_lock(url, **kwargs): self.assertDictEqual( kwargs['json'], { 'scope': 'ORCHESTRATION', 'applicant': [str(self.n1.id), str(self.n2.id)] }) return CallbackResult("{'message': 'Locked'}", status=200) m.post(self.n1.url('api_1_0.locker_prevent'), callback=callback_prevent) m.post(self.n2.url('api_1_0.locker_prevent'), callback=callback_prevent) m.post(self.n1.url('api_1_0.locker_lock'), callback=callback_lock) m.post(self.n2.url('api_1_0.locker_lock'), callback=callback_lock) ret = lock_unlock('L', Scope.ORCHESTRATION, [self.n1, self.n2], applicant=[str(self.n1.id), str(self.n2.id)], identity=ROOT) self.assertIsNone(ret) @aioresponses() def test_lock_unlock_lock_with_error_on_preventing(self, m): m.post(self.n1.url('api_1_0.locker_prevent'), status=200, payload={'message': 'Preventing lock acquired'}) m.post(self.n2.url('api_1_0.locker_prevent'), status=409, payload={'error': 'Unable to request for lock'}) with self.assertRaises(errors.LockerError) as e: ret = lock_unlock('L', Scope.ORCHESTRATION, [self.n1, self.n2], identity=ROOT) self.assertEqual(Scope.ORCHESTRATION, e.exception.scope) self.assertEqual('prevent', e.exception.action) self.assertEqual(1, len(e.exception.responses)) self.assertListEqual([ Response(msg={'error': 'Unable to request for lock'}, code=409, server=self.n2, url=self.n2.url('api_1_0.locker_prevent')) ], e.exception.responses) @aioresponses() def test_lock_unlock_lock_with_server_error_on_preventing(self, m): m.post(self.n1.url('api_1_0.locker_prevent'), status=200, payload={'message': 'Preventing lock acquired'}) m.post(self.n2.url('api_1_0.locker_prevent'), status=500, body="Error message") with self.assertRaises(errors.LockError) as e: ret = lock_unlock('L', Scope.ORCHESTRATION, [self.n1, self.n2], identity=ROOT) self.assertEqual(Scope.ORCHESTRATION, e.exception.scope) self.assertListEqual([ Response("Error message", code=500, server=self.n2, url=self.n2.url('api_1_0.locker_prevent')) ], e.exception.responses) @aioresponses() def test_lock_unlock_lock_with_connection_error(self, m): m.post(self.n1.url('api_1_0.locker_prevent'), status=200, payload={'message': 'Preventing lock acquired'}) m.post(self.n2.url('api_1_0.locker_prevent'), exception=aiohttp.ClientConnectionError('test')) with self.assertRaises(errors.LockError) as e: ret = lock_unlock('L', Scope.ORCHESTRATION, [self.n1, self.n2], identity=ROOT) self.assertEqual(Scope.ORCHESTRATION, e.exception.scope) self.assertEqual(1, len(e.exception.responses)) response = e.exception.responses[0] self.assertIsNone(response.msg) self.assertIsNone(response.code) self.assertEqual(self.n2, response.server) self.assertIsInstance(response.exception, aiohttp.ClientConnectionError) self.assertTupleEqual(('test', ), response.exception.args) @aioresponses() def test_lock_unlock_lock_error_on_lock(self, m): m.post(self.n1.url('api_1_0.locker_prevent'), status=200, payload={'message': 'Preventing lock acquired'}) m.post(self.n2.url('api_1_0.locker_prevent'), status=200, payload={'message': 'Preventing lock acquired'}) m.post(self.n1.url('api_1_0.locker_lock'), status=200, payload={'message': 'Locked'}) m.post(self.n2.url('api_1_0.locker_lock'), status=409, payload={'error': 'Unable to lock'}) with self.assertRaises(errors.LockError) as e: ret = lock_unlock('L', Scope.ORCHESTRATION, [self.n1, self.n2], identity=ROOT) self.assertEqual(Scope.ORCHESTRATION, e.exception.scope) self.assertListEqual([ Response(msg={'error': 'Unable to lock'}, code=409, server=self.n2, url=self.n2.url('api_1_0.locker_lock')) ], e.exception.responses) @aioresponses() def test_lock_unlock_unlock(self, m): def callback_unlock(url, **kwargs): self.assertDictEqual( kwargs['json'], { 'scope': 'ORCHESTRATION', 'applicant': [str(self.n1.id), str(self.n2.id)] }) return CallbackResult(payload={'message': 'UnLocked'}, status=200) m.post(self.n1.url('api_1_0.locker_unlock'), callback=callback_unlock) m.post(self.n2.url('api_1_0.locker_unlock'), callback=callback_unlock) ret = lock_unlock('U', Scope.ORCHESTRATION, [self.n1, self.n2], identity=ROOT) self.assertIsNone(ret) @aioresponses() def test_lock_unlock_unlock_with_error(self, m): m.post(self.n2.url('api_1_0.locker_unlock'), status=200, payload={'message': 'UnLocked'}) m.post(self.n1.url('api_1_0.locker_unlock'), status=409, payload={'error': 'Unable to unlock.'}) with self.assertRaises(errors.LockError) as e: lock_unlock('U', Scope.ORCHESTRATION, [self.n1, self.n2], [str(self.n1.id), str(self.n2.id)], identity=ROOT) self.assertEqual(Scope.ORCHESTRATION, e.exception.scope) self.assertListEqual([ Response(msg={'error': 'Unable to unlock.'}, code=409, server=self.n1, url=self.n1.url('api_1_0.locker_unlock')) ], e.exception.responses)
class TestLogSender(FlaskAppMixin): def setUp(self): """Create and configure a new app instance for each test.""" # create the app with common test config User.set_initial() self.source = Server('source', port=8000, me=True) self.dest = Server('dest', port=8000) Route(self.dest, cost=0) db.session.add_all([self.source, self.dest]) _PygtailBuffer._fh = mock.MagicMock() self.mock_dm = mock.Mock() self.log_sender = LogSender(dimensigon=self.mock_dm) @patch('dimensigon.use_cases.log_sender.os.walk', autospec=True) @patch('dimensigon.use_cases.log_sender.os.path.isfile', autospec=True) @patch.object(Pygtail, 'update_offset_file') @patch.object(_PygtailBuffer, 'readlines', return_value='content', autospec=True) @aioresponses() def test_log_sender_file(self, mock_pb_rl, mock_pt_uof, mock_isfile, mock_walk, m): def callback(url, **kwargs): self.assertDictEqual( {"file": '/dimensigon/logs/dimensigon.log', 'data': base64.b64encode('content'.encode()).decode('ascii')}, kwargs['json']) return CallbackResult('POST', status=200) m.post(self.dest.url('api_1_0.logresource', log_id='aaaaaaaa-1234-5678-1234-56781234aaa1'), callback=callback) mock_isfile.return_value = True log = Log(id='aaaaaaaa-1234-5678-1234-56781234aaa1', source_server=self.source, target='/var/log/dimensigon.log', destination_server=self.dest, dest_folder='/dimensigon/logs/') db.session.add(log) run(self.log_sender.send_new_data()) mock_isfile.assert_called_once() mock_walk.assert_not_called() mock_pb_rl.assert_called_once() mock_pt_uof.assert_called_once() @patch('dimensigon.use_cases.log_sender.os.path.isfile', autospec=True) @patch.object(Pygtail, 'update_offset_file') @patch.object(_PygtailBuffer, 'readlines', return_value='content', autospec=True) @aioresponses() def test_log_sender_file_no_dest_folder(self, mock_pb_rl, mock_pt_uof, mock_isfile, m): def callback(url, **kwargs): self.assertDictEqual( {"file": '/var/log/dimensigon.log', 'data': base64.b64encode('content'.encode()).decode('ascii')}, kwargs['json']) return CallbackResult('POST', status=200) m.post(self.dest.url('api_1_0.logresource', log_id='aaaaaaaa-1234-5678-1234-56781234aaa1'), callback=callback) mock_isfile.return_value = True log = Log(id='aaaaaaaa-1234-5678-1234-56781234aaa1', source_server=self.source, target='/var/log/dimensigon.log', destination_server=self.dest, dest_folder=None) db.session.add(log) run(self.log_sender.send_new_data()) mock_isfile.assert_called_once() mock_pb_rl.assert_called_once() mock_pt_uof.assert_called_once() @async_patch('dimensigon.use_cases.log_sender.async_post', autospec=True) @patch('dimensigon.use_cases.log_sender.os.walk', autospec=True) @patch('dimensigon.use_cases.log_sender.os.path.isfile', autospec=True) @patch.object(Pygtail, 'update_offset_file') @patch.object(_PygtailBuffer, 'readlines', side_effect=['content1', 'newcontent2'], autospec=True) @aioresponses() def test_log_sender_folder(self, mock_pb_rl, mock_pt_uof, mock_isfile, mock_walk, mock_post, m): def callback(url, **kwargs): if kwargs['json']['file'] == '/dimensigon/logs/log1': self.assertDictEqual( {"file": '/dimensigon/logs/log1', 'data': base64.b64encode('content1'.encode()).decode('ascii')}, kwargs['json']) return CallbackResult('POST', payload={'offset': 8}, status=200) elif kwargs['json']['file'] == '/dimensigon/logs/dir1/log2': self.assertDictEqual( {"file": '/dimensigon/logs/dir1/log2', 'data': base64.b64encode('newcontent2'.encode()).decode('ascii')}, kwargs['json']) return CallbackResult('POST', payload={'offset': 11}, status=200) else: raise mock_post.side_effect = [({'offset': 8}, 200), ({'offset': 11}, 200), ({'offset': 8}, 200)] m.post(self.dest.url('api_1_0.logresource', log_id='aaaaaaaa-1234-5678-1234-56781234aaa1'), callback=callback) m.post(self.dest.url('api_1_0.logresource', log_id='aaaaaaaa-1234-5678-1234-56781234aaa1'), callback=callback) m.post(self.dest.url('api_1_0.logresource', log_id='aaaaaaaa-1234-5678-1234-56781234aaa1'), callback=callback) mock_isfile.return_value = False mock_walk.side_effect = [ [('/var/log', ['dir1'], ['log1', 'file']), ('/var/log/dir1', ['dir2'], ['log2'])], [('/var/log', ['dir1'], ['log1', 'file']), ('/var/log/dir1', ['dir2'], [])] ] log = Log(id='aaaaaaaa-1234-5678-1234-56781234aaa1', source_server=self.source, target='/var/log', destination_server=self.dest, dest_folder='/dimensigon/logs/', include='^(log|dir)', exclude='^dir2', recursive=True) db.session.add(log) run(self.log_sender.send_new_data()) mock_isfile.assert_called_once() self.assertEqual(2, mock_pb_rl.call_count) self.assertEqual(2, mock_pt_uof.call_count)
def test_upgrade_catalog(self, mock_lock, mock_entities, mock_now, mock_tzlocal): mock_lock.return_value.__enter__.return_value = 'applicant' mock_entities.return_value = [('ActionTemplate', ActionTemplate), ('Server', Server), ('Gate', Gate)] mock_now.return_value = dt.datetime(2019, 4, 1, tzinfo=dt.timezone.utc) mock_tzlocal.return_value = dt.timezone.utc at1 = ActionTemplate(id='aaaaaaaa-1234-5678-1234-56781234aaa1', name='mkdir', version=1, action_type=ActionType.SHELL, code='mkdir {dir}', expected_output=None, expected_rc=None, system_kwargs={}) db.session.add(at1) db.session.commit() s = Server(id='aaaaaaaa-1234-5678-1234-56781234bbb1', name='server', last_modified_at=dt.datetime(2019, 4, 1, tzinfo=dt.timezone.utc)) s_json = s.to_json() g = Gate(server=s, port=80, dns='server', last_modified_at=dt.datetime(2019, 4, 1, tzinfo=dt.timezone.utc)) g_json = g.to_json() Route(s, cost=0) at2 = ActionTemplate(id='aaaaaaaa-1234-5678-1234-56781234aaa2', name='rmdir', version=1, action_type=ActionType.SHELL, code='rmdir {dir}', expected_output=None, expected_rc=None, system_kwargs={}, last_modified_at=dt.datetime( 2019, 4, 2, tzinfo=dt.timezone.utc)) at2_json = at2.to_json() del at2 at1_json = at1.to_json() del at1 at1_json['code'] = 'mkdir -p {dir}' responses.add( method='GET', url=re.compile('^' + s.url( 'api_1_0.catalog', data_mark='12345').replace('12345', '')), json={ "ActionTemplate": [at1_json, at2_json], "Server": [s_json], "Gate": [g_json] }) upgrade_catalog_from_server(s) db.session.expire_all() atl = [at.to_json() for at in ActionTemplate.query.all()] self.assertListEqual([at1_json, at2_json], atl) c = Catalog.query.get('ActionTemplate') self.assertEqual(dt.datetime(2019, 4, 2, tzinfo=dt.timezone.utc), c.last_modified_at) at1 = ActionTemplate.query.get('aaaaaaaa-1234-5678-1234-56781234aaa1') self.assertEqual('mkdir -p {dir}', at.code)
class TestServer(OneNodeMixin, TestCase): def set_servers_and_routes(self): self.n1 = Server(name='n1', dns_or_ip='1.1.1.1') self.n2 = Server(name='n2', dns_or_ip='n2_dns') self.n3 = Server(name='n3', port=8000) self.r1 = Server(name='r1', dns_or_ip='3.3.3.3') self.r2 = Server(name='r2', dns_or_ip='r2_dns') db.session.add_all([self.n1, self.n2, self.r1, self.r2]) db.session.commit() Route(destination=self.n1, cost=0) Route(destination=self.n2, cost=0) Route(destination=self.n3, cost=0) Route(destination=self.r1, proxy_server_or_gate=self.n1, cost=1) Route(destination=self.r2, proxy_server_or_gate=self.n2, cost=1) db.session.commit() @mock.patch('dimensigon.domain.entities.route.check_host') @mock.patch('dimensigon.domain.entities.server.url_for') def test_url(self, mock_url, mock_check_host): self.set_servers_and_routes() mock_check_host.return_value = True self.assertEqual(f'https://1.1.1.1:{defaults.DEFAULT_PORT}', self.n1.url()) self.assertEqual(f'https://n2_dns:{defaults.DEFAULT_PORT}', self.n2.url()) self.assertEqual(f'https://n3:8000', self.n3.url()) self.assertEqual(f'https://1.1.1.1:{defaults.DEFAULT_PORT}', self.r1.url()) self.assertEqual(f'https://n2_dns:{defaults.DEFAULT_PORT}', self.r2.url()) mock_url.return_value = '/' self.assertEqual(f'https://1.1.1.1:{defaults.DEFAULT_PORT}/', self.n1.url('api')) mock_url.assert_called_once_with('api') me = Server(name='me', gates=[('127.0.0.1', 5), ('192.168.1.2', 2)], me=True) self.assertEqual(f'https://127.0.0.1:5/', me.url('api')) with mock.patch('dimensigon.domain.entities.server.current_app' ) as mock_current_app: type(mock_current_app.dm.config).http_config = mock.PropertyMock( return_value={'keyfile': 'x'}) me = Server(name='me', gates=[('192.168.1.2', 2)], me=True) self.assertEqual(f'http://192.168.1.2:2/', me.url('api')) s = Server('test', port=8000) with self.assertRaises(errors.UnreachableDestination): s.url() def test_get_neighbours(self): n1 = Server('n1', port=8000) n2 = Server('n2', port=8000) n3 = Server('n3', port=8000) r1 = Server('r1', port=8000) Route(destination=n1, cost=0) Route(destination=n2, proxy_server_or_gate=n2.gates[0]) Route(destination=r1, proxy_server_or_gate=n1, cost=1) me = Server('me', port=8000, me=True) db.session.add_all([n1, n2, n3, r1, me]) self.assertListEqual([n1, n2], me.get_neighbours()) self.assertListEqual([n2], me.get_neighbours(exclude=n1)) self.assertListEqual([n2], me.get_neighbours(exclude=[n1, n3])) self.assertListEqual([n2], me.get_neighbours(exclude=[n1.id, n3.id])) def test_get_neighbours_no_route(self): n1 = Server('n1', port=8000) me = Server('me', port=8000, me=True) db.session.add_all([n1, me]) self.assertListEqual([], me.get_neighbours()) def test_get_not_neighbours(self): n1 = Server('n1', port=8000, id='22cd859d-ee91-4079-a112-000000000001') n2 = Server('n2', port=8000, id='22cd859d-ee91-4079-a112-000000000002') n3 = Server('n3', port=8000, id='22cd859d-ee91-4079-a112-000000000003') n3.route = None r1 = Server('r1', port=8000, id='22cd859d-ee91-4079-a112-000000000011') Route(destination=n1, cost=0) Route(destination=n2, proxy_server_or_gate=n2.gates[0]) Route(destination=r1, proxy_server_or_gate=n1, cost=1) me = Server('me', port=8000, me=True) db.session.add_all([n1, n2, n3, r1, me]) self.assertListEqual([n3, r1], me.get_not_neighbours()) def test_get_reachable_servers(self): n1 = Server('n1', port=8000, id='22cd859d-ee91-4079-a112-000000000001') n2 = Server('n2', port=8000, id='22cd859d-ee91-4079-a112-000000000002') n3 = Server('n3', port=8000, id='22cd859d-ee91-4079-a112-000000000003') n3.route = None n4 = Server('n4', port=8000, id='22cd859d-ee91-4079-a112-000000000004') r1 = Server('r1', port=8000, id='22cd859d-ee91-4079-a112-000000000011') Route(destination=n1, cost=0) Route(destination=n2, proxy_server_or_gate=n2.gates[0]) Route(destination=n4) Route(destination=r1, proxy_server_or_gate=n1, cost=1) me = Server('me', port=8000, me=True) db.session.add_all([n1, n2, n3, n4, r1, me]) self.assertListEqual([n1, n2, r1], me.get_reachable_servers()) self.assertListEqual([n2, r1], me.get_reachable_servers(exclude=n1)) self.assertListEqual([n2, r1], me.get_reachable_servers(exclude=n1.id)) self.assertListEqual([r1], me.get_reachable_servers(exclude=[n1.id, n2]))