def test_insert_balance(self): storage = MemoryBalanceStorage() insert = {str(a): a for a in range(10000)} storage.update(insert=insert, height=66) for a in range(10000): self.assertEqual(storage.get(str(a)), a) self.assertEqual(storage.height, 66)
def test_delete_balance(self): storage = MemoryBalanceStorage() insert = {str(a): a for a in range(10000)} storage.update(insert=insert) for a in range(10000): self.assertEqual(storage.get(str(a)), a) delete = set([str(a) for a in range(5000)]) storage.update(delete=delete, height=44) for a in range(5000): with self.assertRaises(KeyError): storage.get(str(a)) self.assertEqual(storage.height, 44)
def test_get_balance(self): storage = MemoryBalanceStorage() storage.update(insert={"addr1": 1, "addr2": 2}, height=33) self.assertEqual(storage.height, 33) self.assertEqual(storage.get("addr1", 1), 1) self.assertEqual(storage.get("addr2", 2), 2) # Missing address raise exception with self.assertRaises(KeyError): storage.get("addr3") # Check default keyword self.assertEqual(storage.get("addr3", 77), 77) self.assertEqual(storage.get("addr1", 77), 1) self.assertEqual(storage.get("addr2", 77), 2)
def test_update_balance(self): storage = MemoryBalanceStorage() insert = {str(a): a for a in range(10000)} storage.update(insert=insert) for a in range(10000): self.assertEqual(storage.get(str(a)), a) update = {str(a): 10 for a in range(5000)} storage.update(update=update, height=88) for a in range(5000): self.assertEqual(storage.get(str(a)), 10) self.assertEqual(storage.height, 88)
def test_get_bulk_balance(self): """ """ storage = MemoryBalanceStorage() insert = { "addr1": 1, "addr2": 2, "addr3": 3, } storage.update(insert=insert) result = dict(storage.get_bulk(set(["addr1", "addr2", "addr4"]))) self.assertEqual(len(result), 2) self.assertTrue('addr1' in result) self.assertTrue('addr2' in result) result = dict(storage.get_bulk({"addr4": 55})) self.assertEqual(len(result), 0)
def setUp(self): self.balance_storage = BalanceProxyCache(MemoryBalanceStorage(), 10000)
def setUp(self): self.storage = MemoryBalanceStorage()
class TestBalanceProxyCache(TestCase): def setUp(self): self.storage = MemoryBalanceStorage() def test_get(self): """Test balance is cached""" balance_proxy = BalanceProxyCache(self.storage, 1000) for a in range(1000): balance_proxy.update(str(a), a) for a in range(1000): self.assertEqual(balance_proxy.get(str(a)), a) for a in range(1000, 2000): self.assertEqual(balance_proxy.get(str(a)), 0) self.assertEqual(len(balance_proxy), 999) # 0 Update Discarded balance_proxy.commit(12) self.assertEqual(len(balance_proxy), 0) # Update all address and try again for a in range(1000): balance_proxy.update(str(a), 44) for a in range(1000): self.assertEqual(balance_proxy.get(str(a)), a + 44) self.assertEqual(len(balance_proxy), 1000) balance_proxy.commit(14) self.assertEqual(len(balance_proxy), 0) for a in range(1000): self.assertEqual(balance_proxy.get(str(a)), a + 44) for a in range(1000, 2000): self.assertEqual(balance_proxy.get(str(a)), 0) def test_storate_insert_update_delete(self): """Test how BalanceProxyCache translate updates into insert, update and delete operations""" self.storage.update = MagicMock() balance_proxy = BalanceProxyCache(self.storage, 1000) # Insert balance_proxy.update('address_one', 1) # Insert balance_proxy.update('address_two', 2) # Insert self.storage.update.assert_not_called() balance_proxy.commit(33) args = self.storage.update.call_args[1] self.assertEqual(len(args['delete']), 0) self.assertEqual(len(args['update']), 0) self.assertEqual(len(args['insert']), 2) self.assertEqual(args['insert']['address_one'], 1) self.assertEqual(args['insert']['address_two'], 2) # Update + Insert self.storage.update.reset_mock() balance_proxy.update('address_two', 2) # Update balance_proxy.update('address_three', 3) # Insert balance_proxy.commit(44) args = self.storage.update.call_args[1] self.assertEqual(len(args['delete']), 0) self.assertEqual(len(args['update']), 1) self.assertEqual(len(args['insert']), 1) self.assertEqual(args['insert']['address_three'], 3) self.assertEqual(args['update']['address_two'], 4) # Update + Insert + Delete self.storage.update.reset_mock() balance_proxy.update('address_four', 4) # Insert balance_proxy.update('address_three', 1) # Update balance_proxy.update('address_one', -1) # Delete balance_proxy.commit(55) args = self.storage.update.call_args[1] self.assertEqual(len(args['insert']), 1) self.assertEqual(len(args['update']), 1) self.assertEqual(len(args['delete']), 1) self.assertEqual(args['insert']['address_four'], 4) self.assertEqual(args['update']['address_three'], 4) self.assertTrue('address_one' in args['delete']) self.assertEqual(args['height'], 55) def test_cache_trim(self): """Test cache is trimed when it reaches max_size""" self.storage.get = MagicMock(return_value=0) balance_proxy = BalanceProxyCache(self.storage, 1000) # Completely fill cache for a in range(1000): balance_proxy.update(str(a), a + 1) balance_proxy.commit(10) # When the address is cached storage.get() isn't called: self.storage.get.reset_mock() for a in range(1000): self.assertEqual(balance_proxy.get(str(a)), a + 1) self.storage.get.assert_not_called() # Adding another address will cause the proxy to discard the oldest one self.assertEqual(len(balance_proxy._cache), 1000) balance_proxy.update('new_address', 44) balance_proxy.commit(444) # This will call storage.get because atleast one addr isn't cached self.storage.get.reset_mock() for a in range(1000): # WARNING: returned value is mangled because mock get allways # return 0 balance_proxy.get(str(a)) self.assertGreater(self.storage.get.call_count, 0) def test_commit(self): """Test data is stored correctly""" balance_proxy = BalanceProxyCache(self.storage, 50000) for a in range(2000): balance_proxy.update(str(a), a) balance_proxy.commit(1000) for a in range(1, 2000): self.assertEqual(self.storage.get(str(a)), a) # 0 updates are not stored with self.assertRaises(KeyError): self.storage.get('0') self.assertEqual(balance_proxy.get('0'), 0) @staticmethod def concurrent_get(balance_proxy, error_event): """ """ time.sleep(0.1) # Delay to allow commit to start for a in range(50000): if balance_proxy.get(str(a)) != a + 1: error_event.set() def test_concurrent_commit(self): """Test concurrent get() and commit() calls""" self.db_engine, self.db_session = create_memory_db() db_storage = SQLBalanceStorage(self.db_session) balance_proxy = BalanceProxyCache(db_storage, 50000) # Test get during a commit ########################### for a in range(100000): balance_proxy.update(str(a), a + 1) error_event = threading.Event() get_thread = threading.Thread(target=self.concurrent_get, args=(balance_proxy, error_event), daemon=True) get_thread.start() balance_proxy.commit(12) # Check no error was detected get_thread.join() self.assertFalse(error_event.is_set()) # Cleanup database self.db_session.close() self.db_engine.dispose() def test_concurrent_update(self): """Test concurrent get() and update() calls""" self.db_engine, self.db_session = create_memory_db() db_storage = SQLBalanceStorage(self.db_session) balance_proxy = BalanceProxyCache(db_storage, 50000) # Test get during a commit ########################### for a in range(100000): balance_proxy.update(str(a), a + 1) balance_proxy.commit(12) error_event = threading.Event() get_thread = threading.Thread(target=self.concurrent_get, args=(balance_proxy, error_event), daemon=True) get_thread.start() for a in range(100000, 300000): balance_proxy.update(str(a), a) # Check no error was detected get_thread.join() self.assertFalse(error_event.is_set()) # Verify updated address for a in range(100000, 150000): self.assertEqual(balance_proxy.get(str(a)), a) # Cleanup database self.db_session.close() self.db_engine.dispose()
def test_mix_ops(self): """Test mixin insert/update/delete operations""" storage = MemoryBalanceStorage() insert = {str(a): a for a in range(5000)} storage.update(insert=insert, height=77) for a in range(5000): self.assertEqual(storage.get(str(a)), a) # Mixed op insert = {str(a): a for a in range(10000, 15000)} update = {str(a): 66 for a in range(1000)} delete = [str(a) for a in range(1000, 3000)] storage.update(insert=insert, update=update, delete=delete, height=99) for a in range(10000, 15000): self.assertEqual(storage.get(str(a)), a) for a in range(3000, 5000): self.assertEqual(storage.get(str(a)), a) for a in range(1000): self.assertEqual(storage.get(str(a)), 66) for a in range(1000, 3000): with self.assertRaises(KeyError): storage.get(str(a)) self.assertEqual(storage.height, 99)
def test_init(self): storage = MemoryBalanceStorage() self.assertEqual(storage.height, -1)