def test_notification_on_set(self): pubsub = self.redis.rds.pubsub() pubsub.subscribe(RedisRoutingTable.update_channel) listener = pubsub.listen() next(listener) # subscription message self.rtbl.set_routing( RoutingRecord('aservice', ['ahost', 'bhost'], [2.0, 3.0])) msg = next(listener) # subscription message self.assertEqual('aservice', msg['data']) self.rtbl.set_routing( RoutingRecord('bservice', ['ahost', 'bhost'], [2.0, 3.0])) msg = next(listener) # subscription message self.assertEqual('bservice', msg['data']) self.rtbl.remove_service('bservice') msg = next(listener) # subscription message self.assertEqual('bservice', msg['data']) pubsub.unsubscribe(RedisRoutingTable.update_channel) pubsub.close()
def test_set_routing_invalid_record(self): record = RoutingRecord('aservice', ['ahost', 'bhost'], [1.0]) self.assertRaises(ValueError, self.rtbl.set_routing, record) self.assertEqual(0, len(self.rtbl.get_routes())) record = RoutingRecord('aservice', ['ahost'], [1.0, 2.0]) self.assertRaises(ValueError, self.rtbl.set_routing, record) self.assertEqual(0, len(self.rtbl.get_routes()))
def test_list_services(self): self.rtbl.set_routing( RoutingRecord('aservice', ['ahost', 'bhost'], [1.0, 2.0])) self.rtbl.set_routing( RoutingRecord('bservice', ['ahost', 'bhost'], [1.0, 2.0])) services = self.rtbl.list_services() self.assertIn('aservice', services) self.assertIn('bservice', services) self.assertEqual(2, len(services))
def get_routing(service): if service == 'aservice': return RoutingRecord('aservice', hosts=['a', 'b', 'c'], weights=[1, 4, 5]) elif service == 'bservice': return RoutingRecord('bservice', hosts=['a', 'd'], weights=[2, 8]) else: raise ValueError
def test_remove_service(self): self.rtbl.set_routing( RoutingRecord('aservice', ['ahost', 'bhost'], [1.0, 2.0])) self.rtbl.set_routing( RoutingRecord('bservice', ['ahost', 'bhost'], [2.0, 3.0])) self.rtbl.remove_service('aservice') routes = self.rtbl.get_routes() self.assertEqual(1, len(routes)) self.assertEqual('bservice', routes[0].service) services = self.rtbl.list_services() self.assertNotIn('aservice', services)
def test_get_routing_after_update_returns_correct_value(self): # FIXME use polling self.rtbl_mutable.set_routing( RoutingRecord('aservice', ['ahost', 'bhost'], [2.0, 3.0])) record1 = self.rtbl.get_routing('aservice') self.rtbl_mutable.set_routing( RoutingRecord('aservice', ['ahost'], [2.0])) time.sleep(0.25) record2 = self.rtbl.get_routing('aservice') self.assertNotEqual(id(record1), id(record2)) self.assertEqual('ahost', record2.hosts[0]) self.assertEqual(1, len(record2.hosts))
def test_set_routing(self): record = RoutingRecord('aservice', ['ahost', 'bhost'], [1.0, 2.0]) self.rtbl.set_routing(record) routes = self.rtbl.get_routes() self.assertEqual(1, len(routes)) self.assertEqual(record, routes[0])
def test_cache_returns_same_object(self): self.rtbl_mutable.set_routing( RoutingRecord('aservice', ['ahost', 'bhost'], [2.0, 3.0])) record1 = self.rtbl.get_routing('aservice') record2 = self.rtbl.get_routing('aservice') self.assertEqual(id(record1), id(record2))
def test_list_services_returns_correct_services(self): # FIXME use polling self.rtbl_mutable.set_routing( RoutingRecord('aservice', ['ahost', 'bhost'], [2.0, 3.0])) time.sleep(0.25) self.assertIn('aservice', self.rtbl.list_services()) self.assertEqual(1, len(self.rtbl.list_services())) self.rtbl_mutable.set_routing( RoutingRecord('bservice', ['ahost', 'bhost'], [2.0, 3.0])) time.sleep(0.25) self.assertIn('aservice', self.rtbl.list_services()) self.assertIn('bservice', self.rtbl.list_services()) self.assertEqual(2, len(self.rtbl.list_services())) self.rtbl_mutable.remove_service('aservice') time.sleep(0.25) self.assertIn('bservice', self.rtbl.list_services()) self.assertEqual(1, len(self.rtbl.list_services()))
def test_weighted_round_robin_removing_hosts(self): rtbl = RoutingTable() rtbl.list_services = unittest.mock.MagicMock(return_value=['aservice']) rtbl.get_routing = unittest.mock.MagicMock(return_value=RoutingRecord( 'aservice', hosts=['a', 'b', 'c', 'd'], weights=[1, 1, 1, 1])) balancer = WeightedRoundRobinBalancer(rtbl) for _ in range(50): balancer.next_host('aservice') rtbl.get_routing = unittest.mock.MagicMock(return_value=RoutingRecord( 'aservice', hosts=['a', 'b', 'c'], weights=[1, 4, 5])) hosts = [] for i in range(100): hosts.append(balancer.next_host('aservice')) cnt = Counter(hosts) self.assertAlmostEqual(10, cnt['a'], delta=1) self.assertAlmostEqual(40, cnt['b'], delta=1) self.assertAlmostEqual(50, cnt['c'], delta=1)
def test_weighted_random(self): services = ['aservice'] route = RoutingRecord('aservice', hosts=['a', 'b'], weights=[2, 4]) # 0.333 / 0.666 rtbl = RoutingTable() rtbl.list_services = unittest.mock.MagicMock(return_value=services) rtbl.get_routing = unittest.mock.MagicMock(return_value=route) balancer = WeightedRandomBalancer(rtbl) hosts = [] for i in range(100): hosts.append(balancer.next_host('aservice')) cnt = Counter(hosts) self.assertAlmostEqual(33, cnt['a'], delta=15) self.assertAlmostEqual(66, cnt['b'], delta=15)
def test_weighted_round_robin(self): services = ['aservice'] route = RoutingRecord('aservice', hosts=['a', 'b', 'c'], weights=[1, 4, 5]) # 0.1 / 0.4 / 0.5 rtbl = RoutingTable() rtbl.list_services = unittest.mock.MagicMock(return_value=services) rtbl.get_routing = unittest.mock.MagicMock(return_value=route) balancer = WeightedRoundRobinBalancer(rtbl) hosts = [] for i in range(100): hosts.append(balancer.next_host('aservice')) cnt = Counter(hosts) self.assertAlmostEqual(10, cnt['a'], delta=1) self.assertAlmostEqual(40, cnt['b'], delta=1) self.assertAlmostEqual(50, cnt['c'], delta=1)
def test_get_routing_of_non_existing_service(self): self.rtbl.set_routing( RoutingRecord('aservice', ['ahost', 'bhost'], [1.0, 2.0])) self.assertRaises(ValueError, self.rtbl.get_routing, 'bservice')