class TestIcxStorageForMalformedAddress(unittest.TestCase): def setUp(self): empty_address = MalformedAddress.from_string('') short_address_without_hx = MalformedAddress.from_string('12341234') short_address = MalformedAddress.from_string('hx1234512345') long_address_without_hx = MalformedAddress.from_string( 'cf85fac2d0b507a2db9ce9526e6d01476f16a2d269f51636f9c4b2d512017faf') long_address = MalformedAddress.from_string( 'hxcf85fac2d0b507a2db9ce9526e6d01476f16a2d269f51636f9c4b2d512017faf' ) self.addresses = [ empty_address, short_address_without_hx, short_address, long_address_without_hx, long_address ] self.db_name = 'icx.db' db = ContextDatabase.from_path(self.db_name) self.assertIsNotNone(db) self.storage = IcxStorage(db) self.factory = IconScoreContextFactory(max_size=1) context = self.factory.create(IconScoreContextType.DIRECT) self.context = context def tearDown(self): context = self.context self.storage.close(context) shutil.rmtree(self.db_name) def test_get_put_account(self): context = self.context account = Account() account.deposit(10**19) for address in self.addresses: account.address = address self.storage.put_account(context, account.address, account) account2 = self.storage.get_account(context, account.address) self.assertEqual(account, account2) def test_delete_account(self): context = self.context account = Account() for address in self.addresses: account.address = address self.storage.put_account(context, account.address, account) ret = self.storage.is_address_present(context, account.address) self.assertTrue(ret) self.storage.delete_account(context, account.address) ret = self.storage.is_address_present(context, account.address) self.assertFalse(ret)
class TestIcxStorage(unittest.TestCase): def setUp(self): self.db_name = 'icx.db' self.address = create_address(AddressPrefix.EOA) db = ContextDatabase.from_path(self.db_name) self.assertIsNotNone(db) self.storage = IcxStorage(db) self.factory = IconScoreContextFactory(max_size=1) context = self.factory.create(IconScoreContextType.DIRECT) context.tx_batch = TransactionBatch() context.block_batch = BlockBatch() self.context = context def tearDown(self): context = self.context self.storage.delete_account(context, self.address) self.storage.close(context) shutil.rmtree(self.db_name) def test_get_put_account(self): context = self.context account = Account() account.address = create_address(AddressPrefix.EOA) account.deposit(10**19) self.storage.put_account(context, account.address, account) account2 = self.storage.get_account(context, account.address) self.assertEqual(account, account2) def test_delete_account(self): context = self.context account = Account() account.address = create_address(AddressPrefix.EOA) self.storage.put_account(context, account.address, account) ret = self.storage.is_address_present(context, account.address) self.assertTrue(ret) self.storage.delete_account(context, account.address) ret = self.storage.is_address_present(context, self.address) self.assertFalse(ret)
class TestIcxStorage(unittest.TestCase): def setUp(self): self.db_name = 'icx.db' self.address = create_address(AddressPrefix.EOA) db = ContextDatabase.from_path(self.db_name) self.assertIsNotNone(db) self.storage = IcxStorage(db) context = IconScoreContext(IconScoreContextType.DIRECT) context.tx_batch = TransactionBatch() context.block_batch = BlockBatch() self.context = context def tearDown(self): context = self.context self.storage.delete_account(context, self.address) self.storage.close(context) shutil.rmtree(self.db_name) def test_get_put_account(self): context = self.context account = Account() account.address = create_address(AddressPrefix.EOA) account.deposit(10**19) self.storage.put_account(context, account.address, account) account2 = self.storage.get_account(context, account.address) self.assertEqual(account, account2) def test_delete_account(self): context = self.context account = Account() account.address = create_address(AddressPrefix.EOA) self.storage.put_account(context, account.address, account) ret = self.storage.is_address_present(context, account.address) self.assertTrue(ret) self.storage.delete_account(context, account.address) ret = self.storage.is_address_present(context, self.address) self.assertFalse(ret) def test_get_put_text(self): context = self.context key_name = 'test_genesis' expected_text = json.dumps({ 'version': 0, 'address': str(create_address(AddressPrefix.EOA)) }) self.storage.put_text(context, key_name, expected_text) actual_stored_text = self.storage.get_text(context, key_name) self.assertEqual(expected_text, actual_stored_text) def test_get_put_total_supply(self): context = self.context current_total_supply = self.storage.get_total_supply(context) self.assertEqual(0, current_total_supply) putting_total_supply_amount = 1000 self.storage.put_total_supply(context, putting_total_supply_amount) actual_stored_total_supply = self.storage.get_total_supply(context) self.assertEqual(putting_total_supply_amount, actual_stored_total_supply)
class TestIconScoreEngine(unittest.TestCase): _ROOT_SCORE_PATH = os.path.join(TEST_ROOT_PATH, 'score') _TEST_DB_PATH = 'tests/test_db/' def setUp(self): rmtree(self._ROOT_SCORE_PATH) rmtree(self._TEST_DB_PATH) archive_path = 'tests/sample/valid.zip' archive_path = os.path.join(TEST_ROOT_PATH, archive_path) zip_bytes = self.read_zipfile_as_byte(archive_path) install_path = os.path.join(TEST_ROOT_PATH, self._ROOT_SCORE_PATH) self.__unpack_zip_file(install_path, zip_bytes) db_path = os.path.join(TEST_ROOT_PATH, self._TEST_DB_PATH) ContextDatabaseFactory.open( db_path, ContextDatabaseFactory.Mode.SINGLE_DB) self.__ensure_dir(db_path) icx_db = ContextDatabaseFactory.create_by_name('icx_db') self.icx_storage = IcxStorage(icx_db) deploy_storage = IconScoreDeployStorage(self.icx_storage.db) deploy_engine = IconScoreDeployEngine() deploy_engine.open(self._ROOT_SCORE_PATH, deploy_storage) self.icon_score_loader = IconScoreLoader(self._ROOT_SCORE_PATH) IconScoreMapper.icon_score_loader = self.icon_score_loader IconScoreMapper.deploy_storage = deploy_storage self.icon_score_mapper = IconScoreMapper() self.engine = IconScoreEngine() self.engine.open( self.icx_storage, self.icon_score_mapper) self._from = create_address(AddressPrefix.EOA) self._icon_score_address = create_address(AddressPrefix.CONTRACT) self.factory = IconScoreContextFactory(max_size=1) IconScoreContext.icon_score_deploy_engine = deploy_engine self._context = self.factory.create(IconScoreContextType.DIRECT) self._context.msg = Message(self._from, 0) tx_hash = create_tx_hash() self._context.tx = Transaction( tx_hash, origin=create_address(AddressPrefix.EOA)) block_hash = create_block_hash() self._context.block = Block(1, block_hash, 0, None) def tearDown(self): self.engine = None self.icx_storage.close(self._context) self.factory.destroy(self._context) ContextDatabaseFactory.close() remove_path = os.path.join(TEST_ROOT_PATH, self._ROOT_SCORE_PATH) IconScoreDeployer.remove_existing_score(remove_path) remove_path = os.path.join(TEST_ROOT_PATH, self._TEST_DB_PATH) IconScoreDeployer.remove_existing_score(remove_path) @staticmethod def read_zipfile_as_byte(archive_path: str) -> bytes: with open(archive_path, 'rb') as f: byte_data = f.read() return byte_data @staticmethod def __unpack_zip_file(install_path: str, data: bytes): file_info_generator = IconScoreDeployer._extract_files_gen(data) for name, file_info, parent_directory in file_info_generator: if not os.path.exists(os.path.join(install_path, parent_directory)): os.makedirs(os.path.join(install_path, parent_directory)) with file_info as file_info_context,\ open(os.path.join(install_path, name), 'wb') as dest: contents = file_info_context.read() dest.write(contents) return True @staticmethod def __ensure_dir(file_path): directory = os.path.dirname(file_path) if not os.path.exists(directory): os.makedirs(directory) # FIXME # def test_install(self): # proj_name = 'test_score' # path = os.path.join(TEST_ROOT_PATH, 'tests/tmp/{}'.format(proj_name)) # install_data = {'contentType': 'application/tbears', 'content': path} # self._engine.invoke( # self._context, self._icon_score_address, 'install', install_data) # self._engine.commit(self._context) def test_call_method(self): calldata = {'method': 'total_supply', 'params': {}} # proj_name = 'test_score' # path = os.path.join(TEST_ROOT_PATH, 'tests/tmp/{}'.format(proj_name)) # install_data = {'contentType': 'application/tbears', 'content': path} # self._engine.invoke( # self._context, self._icon_score_address, 'install', install_data) # self._engine.commit(self._context) context = self.factory.create(IconScoreContextType.QUERY) with self.assertRaises(InvalidParamsException) as cm: self.engine.query( context, self._icon_score_address, 'call', calldata) e = cm.exception self.assertEqual(ExceptionCode.INVALID_PARAMS, e.code) print(e) self.factory.destroy(context)
class TestScoreDeployEngine(unittest.TestCase): _ROOT_SCORE_PATH = 'tests/score' _TEST_DB_PATH = 'tests/test_db' @classmethod def setUpClass(cls): db_path = os.path.join(PROJECT_ROOT_PATH, cls._TEST_DB_PATH) ContextDatabaseFactory.open(db_path, ContextDatabaseFactory.Mode.SINGLE_DB) @classmethod def tearDownClass(cls): ContextDatabaseFactory.close() def setUp(self): db_path = os.path.join(PROJECT_ROOT_PATH, self._TEST_DB_PATH) score_path = os.path.join(PROJECT_ROOT_PATH, self._ROOT_SCORE_PATH) self.score_path = score_path self._tx_index = 0 self.__ensure_dir(db_path) self._icx_db = ContextDatabaseFactory.create_by_name(ICON_DEX_DB_NAME) self._icx_db.address = ICX_ENGINE_ADDRESS self._icx_storage = IcxStorage(self._icx_db) self._score_deploy_engine = isde.IconScoreDeployEngine() self._deploy_storage = IconScoreDeployStorage(self._icx_db) self._icon_score_mapper = IconScoreMapper() self.addr1 = create_address(AddressPrefix.EOA) self.addr2 = create_address(AddressPrefix.EOA) self.score_address = create_address(AddressPrefix.CONTRACT) self._score_deploy_engine.open( score_deploy_storage=self._deploy_storage) self.make_context() def tearDown(self): try: self._context = IconScoreContext(IconScoreContextType.DIRECT) self._icx_storage.close(self._context) finally: remove_path = os.path.join(PROJECT_ROOT_PATH, self._ROOT_SCORE_PATH) rmtree(remove_path) remove_path = os.path.join(PROJECT_ROOT_PATH, self._TEST_DB_PATH) rmtree(remove_path) def make_context(self): self._tx_index += 1 self._context = IconScoreContext(IconScoreContextType.DIRECT) self._context.msg = Message(self.addr1, 0) self._context.tx = Transaction(create_tx_hash(), origin=self.addr1) self._context.block = Block(1, create_block_hash(), 0, None) self._context.icon_score_mapper = self._icon_score_mapper self._context.icx = IcxEngine() self.__step_counter_factory = IconScoreStepCounterFactory() self._context.revision = 0 self._context.new_icon_score_mapper = {} self._step_counter: IconScoreStepCounter = \ self.__step_counter_factory.create(IconScoreContextType.INVOKE) self._context.step_counter = self._step_counter self._context.icx.open(self._icx_storage) self._context.event_logs = Mock(spec=list) self._context.traces = Mock(spec=list) def _invoke_setUp(self, _is_audit_needed: bool): self._score_deploy_engine._is_audit_needed = Mock( return_value=_is_audit_needed) self._score_deploy_engine.deploy = Mock() self._deploy_storage.put_deploy_info_and_tx_params = Mock() def _is_audit_needed_setUp(self, revision: int, get_owner, is_service_flag_on: bool): self._context.revision = revision IconScoreContextUtil.is_service_flag_on.return_value = is_service_flag_on IconScoreContextUtil.get_owner.return_value = get_owner def _deploy_setUp(self, get_deploy_tx_params=None): self._score_deploy_engine._score_deploy = Mock() self._deploy_storage.update_score_info = Mock() self._deploy_storage.get_deploy_tx_params = Mock( return_value=get_deploy_tx_params) def _score_deploy_setUp(self, legacy_tbears_mode: bool = False): self._score_deploy_engine._on_deploy = Mock() self._context.legacy_tbears_mode = legacy_tbears_mode # case when icon_score_address is in (None, ZERO_ADDRESS) @patch_several(VALIDATE_SCORE_BLACKLIST_PATCHER, IS_SERVICE_FLAG_ON_PATCHER, VALIDATE_DEPLOYER) def test_invoke_case1(self): self._invoke_setUp(True) with self.assertRaises(AssertionError): self._score_deploy_engine.invoke(self._context, GOVERNANCE_SCORE_ADDRESS, ZERO_SCORE_ADDRESS, {}) IconScoreContextUtil.validate_score_blacklist.assert_not_called() IconScoreContextUtil.validate_deployer.assert_not_called() self._deploy_storage.put_deploy_info_and_tx_params.assert_not_called() self._score_deploy_engine._is_audit_needed.assert_not_called() self._score_deploy_engine.deploy.assert_not_called() with self.assertRaises(AssertionError): self._score_deploy_engine.invoke(self._context, GOVERNANCE_SCORE_ADDRESS, None, {}) IconScoreContextUtil.validate_score_blacklist.assert_not_called() IconScoreContextUtil.validate_deployer.assert_not_called() self._deploy_storage.put_deploy_info_and_tx_params.assert_not_called() self._score_deploy_engine._is_audit_needed.assert_not_called() self._score_deploy_engine.deploy.assert_not_called() # case when deployer_white_list flag on, ignore audit @patch_several(VALIDATE_SCORE_BLACKLIST_PATCHER, IS_SERVICE_FLAG_ON_PATCHER, VALIDATE_DEPLOYER) def test_invoke_case2(self): self._invoke_setUp(False) self._score_deploy_engine.invoke(self._context, ZERO_SCORE_ADDRESS, GOVERNANCE_SCORE_ADDRESS, {}) IconScoreContextUtil.validate_score_blacklist.assert_called_with( self._context, GOVERNANCE_SCORE_ADDRESS) IconScoreContextUtil.validate_deployer.assert_called_with( self._context, self._context.tx.origin) self._deploy_storage.put_deploy_info_and_tx_params.\ assert_called_with(self._context, GOVERNANCE_SCORE_ADDRESS, DeployType.INSTALL, self._context.tx.origin, self._context.tx.hash, {}) self._score_deploy_engine.deploy.assert_called_with( self._context, self._context.tx.hash) # case when deployer_white_list flag on, audit @patch_several(VALIDATE_SCORE_BLACKLIST_PATCHER, IS_SERVICE_FLAG_ON_PATCHER, VALIDATE_DEPLOYER) def test_invoke_case3(self): self._invoke_setUp(True) self._score_deploy_engine.invoke(self._context, ZERO_SCORE_ADDRESS, GOVERNANCE_SCORE_ADDRESS, {}) IconScoreContextUtil.validate_score_blacklist.assert_called_with( self._context, GOVERNANCE_SCORE_ADDRESS) IconScoreContextUtil.validate_deployer.assert_called_with( self._context, self._context.tx.origin) self._deploy_storage.put_deploy_info_and_tx_params.\ assert_called_with(self._context, GOVERNANCE_SCORE_ADDRESS, DeployType.INSTALL, self._context.tx.origin, self._context.tx.hash, {}) self._score_deploy_engine.deploy.assert_not_called() # case when deployer_white_list flag off, audit @patch_several(VALIDATE_SCORE_BLACKLIST_PATCHER, IS_SERVICE_FLAG_ON_PATCHER, VALIDATE_DEPLOYER) def test_invoke_case4(self): self._invoke_setUp(False) self._score_deploy_engine.invoke(self._context, ZERO_SCORE_ADDRESS, GOVERNANCE_SCORE_ADDRESS, {}) IconScoreContextUtil.validate_score_blacklist.assert_called_with( self._context, GOVERNANCE_SCORE_ADDRESS) IconScoreContextUtil.validate_deployer.assert_called_with( self._context, self._context.tx.origin) self._deploy_storage.put_deploy_info_and_tx_params. \ assert_called_with(self._context, GOVERNANCE_SCORE_ADDRESS, DeployType.INSTALL, self._context.tx.origin, self._context.tx.hash, {}) self._score_deploy_engine.deploy.assert_called_with( self._context, self._context.tx.hash) # case when deployer_white_list flag off, audit on @patch_several(VALIDATE_SCORE_BLACKLIST_PATCHER, IS_SERVICE_FLAG_ON_PATCHER, VALIDATE_DEPLOYER) def test_invoke_case5(self): self._invoke_setUp(True) self._score_deploy_engine.invoke(self._context, ZERO_SCORE_ADDRESS, GOVERNANCE_SCORE_ADDRESS, {}) IconScoreContextUtil.validate_score_blacklist.assert_called_with( self._context, GOVERNANCE_SCORE_ADDRESS) IconScoreContextUtil.validate_deployer.assert_called_with( self._context, self._context.tx.origin) self._score_deploy_engine.deploy.assert_not_called() # case when revision0, owner, audit false @patch_several(GET_OWNER_PATCHER, IS_SERVICE_FLAG_ON_PATCHER) def test_is_audit_needed_case1(self): self._is_audit_needed_setUp(0, self.addr1, False) result = self._score_deploy_engine._is_audit_needed( self._context, GOVERNANCE_SCORE_ADDRESS) IconScoreContextUtil.get_owner.assert_called_with( self._context, GOVERNANCE_SCORE_ADDRESS) IconScoreContextUtil.is_service_flag_on.assert_called_with( self._context, IconServiceFlag.AUDIT) self.assertFalse(result) # case when revision0, owner x, audit false @patch_several(GET_OWNER_PATCHER, IS_SERVICE_FLAG_ON_PATCHER) def test_is_audit_needed_case2(self): self._is_audit_needed_setUp(0, self.addr2, False) result = self._score_deploy_engine._is_audit_needed( self._context, GOVERNANCE_SCORE_ADDRESS) IconScoreContextUtil.get_owner.assert_called_with( self._context, GOVERNANCE_SCORE_ADDRESS) IconScoreContextUtil.is_service_flag_on.assert_called_with( self._context, IconServiceFlag.AUDIT) self.assertFalse(result) # case when revision0, owner, audit true @patch_several(GET_OWNER_PATCHER, IS_SERVICE_FLAG_ON_PATCHER) def test_is_audit_needed_case3(self): self._is_audit_needed_setUp(0, self.addr1, True) result = self._score_deploy_engine._is_audit_needed( self._context, GOVERNANCE_SCORE_ADDRESS) IconScoreContextUtil.get_owner.assert_called_with( self._context, GOVERNANCE_SCORE_ADDRESS) IconScoreContextUtil.is_service_flag_on.assert_called_with( self._context, IconServiceFlag.AUDIT) self.assertTrue(result) # case when revision0, owner x, audit true @patch_several(GET_OWNER_PATCHER, IS_SERVICE_FLAG_ON_PATCHER) def test_is_audit_needed_case4(self): self._is_audit_needed_setUp(0, self.addr2, True) result = self._score_deploy_engine._is_audit_needed( self._context, GOVERNANCE_SCORE_ADDRESS) IconScoreContextUtil.get_owner.assert_called_with( self._context, GOVERNANCE_SCORE_ADDRESS) IconScoreContextUtil.is_service_flag_on.assert_called_with( self._context, IconServiceFlag.AUDIT) self.assertTrue(result) # case when revision2, transaction requested by owner, audit true, system_score @patch_several(GET_OWNER_PATCHER, IS_SERVICE_FLAG_ON_PATCHER) def test_is_audit_needed_case5(self): self._is_audit_needed_setUp(2, self.addr1, True) result = self._score_deploy_engine._is_audit_needed( self._context, GOVERNANCE_SCORE_ADDRESS) IconScoreContextUtil.get_owner.assert_called_with( self._context, GOVERNANCE_SCORE_ADDRESS) IconScoreContextUtil.is_service_flag_on.assert_called_with( self._context, IconServiceFlag.AUDIT) self.assertFalse(result) # case when revision2, transaction requested by stranger, audit true, system_score @patch_several(GET_OWNER_PATCHER, IS_SERVICE_FLAG_ON_PATCHER) def test_is_audit_needed_case6(self): self._is_audit_needed_setUp(2, self.addr2, True) result = self._score_deploy_engine._is_audit_needed( self._context, GOVERNANCE_SCORE_ADDRESS) IconScoreContextUtil.get_owner.assert_called_with( self._context, GOVERNANCE_SCORE_ADDRESS) IconScoreContextUtil.is_service_flag_on.assert_called_with( self._context, IconServiceFlag.AUDIT) self.assertTrue(result) # case when revision2, transaction requested by owner, audit false, system_score @patch_several(GET_OWNER_PATCHER, IS_SERVICE_FLAG_ON_PATCHER) def test_is_audit_needed_case7(self): self._is_audit_needed_setUp(2, self.addr1, False) result = self._score_deploy_engine._is_audit_needed( self._context, GOVERNANCE_SCORE_ADDRESS) IconScoreContextUtil.get_owner.assert_called_with( self._context, GOVERNANCE_SCORE_ADDRESS) IconScoreContextUtil.is_service_flag_on.assert_called_with( self._context, IconServiceFlag.AUDIT) self.assertFalse(result) # case when revision2, transaction requested by stranger, audit false, system_score @patch_several(GET_OWNER_PATCHER, IS_SERVICE_FLAG_ON_PATCHER) def test_is_audit_needed_case8(self): self._is_audit_needed_setUp(2, self.addr1, False) result = self._score_deploy_engine._is_audit_needed( self._context, GOVERNANCE_SCORE_ADDRESS) IconScoreContextUtil.get_owner.assert_called_with( self._context, GOVERNANCE_SCORE_ADDRESS) IconScoreContextUtil.is_service_flag_on.assert_called_with( self._context, IconServiceFlag.AUDIT) self.assertFalse(result) # case when revision2, transaction requested by owner, audit true, normal_score @patch_several(GET_OWNER_PATCHER, IS_SERVICE_FLAG_ON_PATCHER) def test_is_audit_needed_case9(self): self._is_audit_needed_setUp(2, self.addr1, True) result = self._score_deploy_engine._is_audit_needed( self._context, self.score_address) IconScoreContextUtil.get_owner.assert_called_with( self._context, self.score_address) IconScoreContextUtil.is_service_flag_on.assert_called_with( self._context, IconServiceFlag.AUDIT) self.assertTrue(result) # case when revision2, transaction requested by stranger, audit true, normal_score @patch_several(GET_OWNER_PATCHER, IS_SERVICE_FLAG_ON_PATCHER) def test_is_audit_needed_case10(self): self._is_audit_needed_setUp(2, self.addr2, True) result = self._score_deploy_engine._is_audit_needed( self._context, self.score_address) IconScoreContextUtil.get_owner.assert_called_with( self._context, self.score_address) IconScoreContextUtil.is_service_flag_on.assert_called_with( self._context, IconServiceFlag.AUDIT) self.assertTrue(result) # case when revision2, transaction requested by owner, audit false, normal_score @patch_several(GET_OWNER_PATCHER, IS_SERVICE_FLAG_ON_PATCHER) def test_is_audit_needed_case11(self): self._is_audit_needed_setUp(2, self.addr1, False) result = self._score_deploy_engine._is_audit_needed( self._context, self.score_address) IconScoreContextUtil.get_owner.assert_called_with( self._context, self.score_address) IconScoreContextUtil.is_service_flag_on.assert_called_with( self._context, IconServiceFlag.AUDIT) self.assertFalse(result) # case when revision2, transaction requested by stranger, audit false, normal_score @patch_several(GET_OWNER_PATCHER, IS_SERVICE_FLAG_ON_PATCHER) def test_is_audit_needed_case12(self): self._is_audit_needed_setUp(2, self.addr1, False) result = self._score_deploy_engine._is_audit_needed( self._context, self.score_address) IconScoreContextUtil.get_owner.assert_called_with( self._context, self.score_address) IconScoreContextUtil.is_service_flag_on.assert_called_with( self._context, IconServiceFlag.AUDIT) self.assertFalse(result) # case when tx_param is None @patch_several(GET_DEPLOY_TX_PARAMS_PATCHER) def test_deploy_case1(self): self._deploy_setUp() with self.assertRaises(InvalidParamsException) as e: self._score_deploy_engine.deploy(self._context, self._context.tx.hash) self._deploy_storage.get_deploy_tx_params.assert_called_with( self._context, self._context.tx.hash) self.assertEqual(e.exception.code, ExceptionCode.INVALID_PARAMETER) self._score_deploy_engine._score_deploy.assert_not_called() self._score_deploy_engine._score_deploy_storage.update_score_info.assert_not_called( ) # case when tx_param is not None @patch_several(GET_DEPLOY_TX_PARAMS_PATCHER) def test_deploy_case2(self): tx_params = Mock(spec=IconScoreDeployTXParams) tx_params.configure_mock(score_address=GOVERNANCE_SCORE_ADDRESS) self._deploy_setUp(tx_params) self._score_deploy_engine.deploy(self._context, self._context.tx.hash) self._score_deploy_engine._score_deploy.assert_called_with( self._context, tx_params) self._score_deploy_engine._score_deploy_storage.\ update_score_info.assert_called_with(self._context, GOVERNANCE_SCORE_ADDRESS, self._context.tx.hash) # test for tbears mode, legacy_tbears_mode is True def test_score_deploy_case1(self): self._score_deploy_setUp(True) tx_params = Mock(spec=IconScoreDeployTXParams) tx_params.configure_mock(deploy_data={ 'contentType': 'application/tbears', 'content': '0x1234' }) self._score_deploy_engine._score_deploy(self._context, tx_params) self._score_deploy_engine._on_deploy.assert_called_with( self._context, tx_params) # test for tbears mode, and legacy_tbears_mode is False def test_score_deploy_case2(self): tx_params = Mock(spec=IconScoreDeployTXParams) tx_params.configure_mock(deploy_data={ 'contentType': 'application/tbears', 'content': '0x1234' }) self._score_deploy_setUp() with self.assertRaises(InvalidParamsException) as e: self._score_deploy_engine._score_deploy(self._context, tx_params) self.assertEqual(e.exception.code, ExceptionCode.INVALID_PARAMETER) self.assertEqual(e.exception.message, f"Invalid contentType: application/tbears") self._score_deploy_engine._on_deploy.assert_not_called() # test for zip mode def test_score_deploy_case3(self): tx_params = Mock(spec=IconScoreDeployTXParams) tx_params.configure_mock(deploy_data={ 'contentType': 'application/zip', 'content': '0x1234' }) self._score_deploy_setUp() self._score_deploy_engine._score_deploy(self._context, tx_params) self._score_deploy_engine._on_deploy.assert_called_with( self._context, tx_params) # test for wrong contentType def test_score_deploy_case4(self): self._score_deploy_setUp() tx_params = Mock(spec=IconScoreDeployTXParams) tx_params.configure_mock(deploy_data={ 'contentType': 'wrong/content', 'content': '0x1234' }) with self.assertRaises(InvalidParamsException) as e: self._score_deploy_engine._score_deploy(self._context, tx_params) self.assertEqual(e.exception.code, ExceptionCode.INVALID_PARAMETER) self.assertEqual(e.exception.message, f'Invalid contentType: wrong/content') self._score_deploy_engine._on_deploy.assert_not_called() # Case when deploy_info is not None, zip, revision0, score validator flag False, SCORE is not None @patch_several(VALIDATE_PACKAGE_PATCHER) def test_on_deploy(self): mock_score = MockScore() mock_score.owner = self.addr1 deploy_params = {"a": 1} deploy_data = {"params": deploy_params} deploy_info = Mock(spec=IconScoreDeployInfo) deploy_type = 'deploy_type' next_tx_hash = b'\00\01' * 16 deploy_info.configure_mock(next_tx_hash=next_tx_hash) tx_params = Mock(spec=IconScoreDeployTXParams) tx_params.configure_mock(score_address=self.score_address, deploy_data=deploy_data, deploy_type=deploy_type, params=deploy_params) backup_msg, backup_tx = self._context.msg, self._context.tx self._score_deploy_engine._write_score_to_filesystem = Mock() score_info = Mock() score_info.configure_mock(get_score=Mock(return_value=mock_score)) self._score_deploy_engine._create_score_info = Mock( return_value=score_info) self._deploy_storage.get_deploy_info = Mock(return_value=deploy_info) self._score_deploy_engine._initialize_score = Mock() self._score_deploy_engine._on_deploy(self._context, tx_params) self._deploy_storage.get_deploy_info.assert_called_with( self._context, self.score_address) self._score_deploy_engine._write_score_to_filesystem.assert_called_with( self._context, self.score_address, next_tx_hash, deploy_data) IconScoreContextUtil.validate_score_package.assert_called_with( self._context, self.score_address, next_tx_hash) self._score_deploy_engine._create_score_info.assert_called_with( self._context, self.score_address, next_tx_hash) score_info.get_score.assert_called_with(self._context.revision) self._score_deploy_engine._initialize_score.assert_called_with( deploy_type, mock_score, deploy_params) self.assertEqual(self._context.msg, backup_msg) self.assertEqual(self._context.tx, backup_tx) # tbears mode def test_write_score_to_filesystem_case1(self): content = '0x1234' deploy_data = {'contentType': 'application/tbears', 'content': content} self._score_deploy_engine._write_score_to_score_deploy_path_on_tbears_mode = Mock( ) self._score_deploy_engine._write_score_to_filesystem( self._context, GOVERNANCE_SCORE_ADDRESS, self._context.tx.hash, deploy_data) self._score_deploy_engine._write_score_to_score_deploy_path_on_tbears_mode.\ assert_called_with(self._context, GOVERNANCE_SCORE_ADDRESS, self._context.tx.hash, content) # normal mode def test_write_score_to_filesystem_case2(self): content = '0x1234' deploy_data = {'contentType': 'application/zip', 'content': content} self._score_deploy_engine._write_score_to_score_deploy_path = Mock() self._score_deploy_engine._write_score_to_filesystem( self._context, GOVERNANCE_SCORE_ADDRESS, self._context.tx.hash, deploy_data) self._score_deploy_engine._write_score_to_score_deploy_path. \ assert_called_with(self._context, GOVERNANCE_SCORE_ADDRESS, self._context.tx.hash, content) # case when current_score_info is None @patch_several(GET_SCORE_INFO_PATCHER, CREATE_SCORE_INFO_PATCHER) def test_create_score_info_case1(self): IconScoreContextUtil.get_score_info.return_value = None self._score_deploy_engine._create_score_info(self._context, GOVERNANCE_SCORE_ADDRESS, self._context.tx.hash) IconScoreContextUtil.create_score_info.assert_called_with( self._context, GOVERNANCE_SCORE_ADDRESS, self._context.tx.hash, None) # case when current_score_info is not None @patch_several(GET_SCORE_INFO_PATCHER, CREATE_SCORE_INFO_PATCHER) def test_create_score_info_case2(self): db = 'db' score_info_mock = Mock() score_info_mock.configure_mock(score_db=db) IconScoreContextUtil.get_score_info.return_value = score_info_mock self._score_deploy_engine._create_score_info(self._context, GOVERNANCE_SCORE_ADDRESS, self._context.tx.hash) IconScoreContextUtil.create_score_info.assert_called_with( self._context, GOVERNANCE_SCORE_ADDRESS, self._context.tx.hash, db) @patch_several(GET_SCORE_PATH_PATCHER, GET_SCORE_DEPLOY_PATH_PATCHER, SYMLINK_PATCHER, MAKE_DIR_PATCHER) def test_write_score_to_score_deploy_path_on_tbears_mode(self): score_deploy_path = 'score_deploy_path' isde.get_score_deploy_path.return_value = score_deploy_path score_path = 'score_path' isde.get_score_path.return_value = score_path self._score_deploy_engine._write_score_to_score_deploy_path_on_tbears_mode\ (self._context, GOVERNANCE_SCORE_ADDRESS, self._context.tx.hash, None) isde.get_score_path.assert_called_with(self._context.score_root_path, GOVERNANCE_SCORE_ADDRESS) os.makedirs.assert_called_with(score_path, exist_ok=True) os.symlink.assert_called_with(None, score_deploy_path, target_is_directory=True) # case when revision3 @patch_several(DEPLOY_PATCHER, REMOVE_PATH_PATCHER, GET_SCORE_DEPLOY_PATH_PATCHER, OS_PATH_JOIN_PATCHER) def test_write_score_to_score_deploy_path_case1(self): self._context.revision = 3 score_path = 'score_path' score_deploy_path = 'score_deploy_path' isde.get_score_deploy_path.return_value = 'score_deploy_path' os.path.join.return_value = score_path self._score_deploy_engine._write_score_to_score_deploy_path( self._context, GOVERNANCE_SCORE_ADDRESS, self._context.tx.hash, None) isde.get_score_deploy_path.assert_called_with( self._context.score_root_path, GOVERNANCE_SCORE_ADDRESS, self._context.tx.hash) os.path.join.assert_called_with( self._context.score_root_path, GOVERNANCE_SCORE_ADDRESS.to_bytes().hex(), f"0x{self._context.tx.hash.hex()}") isde.remove_path.assert_called_with(score_path) IconScoreDeployer.deploy.assert_called_with(score_deploy_path, None, 3) # case when revision2 @patch_several(DEPLOY_PATCHER, REMOVE_PATH_PATCHER, GET_SCORE_DEPLOY_PATH_PATCHER, OS_PATH_JOIN_PATCHER) def test_write_score_to_score_deploy_path_case1(self): self._context.revision = 2 score_path = 'score_path' score_deploy_path = 'score_deploy_path' isde.get_score_deploy_path.return_value = 'score_deploy_path' os.path.join.return_value = score_path self._score_deploy_engine._write_score_to_score_deploy_path( self._context, GOVERNANCE_SCORE_ADDRESS, self._context.tx.hash, None) isde.get_score_deploy_path.assert_called_with( self._context.score_root_path, GOVERNANCE_SCORE_ADDRESS, self._context.tx.hash) os.path.join.assert_not_called() isde.remove_path.assert_not_called() IconScoreDeployer.deploy.assert_called_with(score_deploy_path, None, 2) # case when revision0 @patch_several(DEPLOY_PATCHER, DEPLOY_LEGACY_PATCHER, REMOVE_PATH_PATCHER, GET_SCORE_DEPLOY_PATH_PATCHER, OS_PATH_JOIN_PATCHER) def test_write_score_to_score_deploy_path_case1(self): score_path = 'score_path' score_deploy_path = 'score_deploy_path' isde.get_score_deploy_path.return_value = 'score_deploy_path' os.path.join.return_value = score_path self._score_deploy_engine._write_score_to_score_deploy_path( self._context, GOVERNANCE_SCORE_ADDRESS, self._context.tx.hash, None) isde.get_score_deploy_path.assert_called_with( self._context.score_root_path, GOVERNANCE_SCORE_ADDRESS, self._context.tx.hash) os.path.join.assert_not_called() isde.remove_path.assert_not_called() IconScoreDeployer.deploy.assert_not_called() IconScoreDeployer.deploy_legacy.assert_called_with( score_deploy_path, None) # case on_install @patch_several(MAKE_ANNOTATIONS_FROM_METHOD_PATCHER, CONVERT_DATA_PARAMS_PATCHER) def test_initialize_score_case1(self): mock_score = MockScore() on_install = Mock() mock_score.on_install = on_install deploy_type = DeployType.INSTALL params = {"param1": '0x1', "param2": "string"} self._score_deploy_engine._initialize_score(deploy_type, mock_score, params) TypeConverter.make_annotations_from_method.assert_called_with( on_install) TypeConverter.convert_data_params.assert_called_with( 'annotations', params) on_install.assert_called_with(**params) # case on_update @patch_several(MAKE_ANNOTATIONS_FROM_METHOD_PATCHER, CONVERT_DATA_PARAMS_PATCHER) def test_initialize_score_case2(self): mock_score = MockScore() on_update = Mock() mock_score.on_update = on_update deploy_type = DeployType.UPDATE params = {"param1": '0x1', "param2": "string"} self._score_deploy_engine._initialize_score(deploy_type, mock_score, params) TypeConverter.make_annotations_from_method.assert_called_with( on_update) TypeConverter.convert_data_params.assert_called_with( 'annotations', params) on_update.assert_called_with(**params) # case strange method name @patch_several(MAKE_ANNOTATIONS_FROM_METHOD_PATCHER, CONVERT_DATA_PARAMS_PATCHER) def test_initialize_score_case3(self): mock_score = MockScore() on_strange = Mock() mock_score.on_install = on_strange deploy_type = "strange" params = {"param1": '0x1', "param2": "string"} with self.assertRaises(InvalidParamsException) as e: self._score_deploy_engine._initialize_score( deploy_type, mock_score, params) self.assertEqual(e.exception.code, ExceptionCode.INVALID_PARAMETER) self.assertEqual(e.exception.message, f"Invalid deployType: {deploy_type}") TypeConverter.make_annotations_from_method.assert_not_called() TypeConverter.convert_data_params.assert_not_called() on_strange.assert_not_called() @staticmethod def __ensure_dir(dir_path): if not os.path.exists(dir_path): os.makedirs(dir_path)
class TestScoreDeployEngine(unittest.TestCase): _ROOT_SCORE_PATH = 'tests/score' _TEST_DB_PATH = 'tests/test_db' @classmethod def setUpClass(cls): db_path = os.path.join(TEST_ROOT_PATH, cls._TEST_DB_PATH) ContextDatabaseFactory.open(db_path, ContextDatabaseFactory.Mode.SINGLE_DB) @classmethod def tearDownClass(cls): ContextDatabaseFactory.close() def setUp(self): db_path = os.path.join(TEST_ROOT_PATH, self._TEST_DB_PATH) score_path = os.path.join(TEST_ROOT_PATH, self._ROOT_SCORE_PATH) self._tx_index = 0 self.__ensure_dir(db_path) self._icx_db = ContextDatabaseFactory.create_by_name('icon_dex') self._icx_db.address = ICX_ENGINE_ADDRESS self._icx_storage = IcxStorage(self._icx_db) self._score_deploy_engine = IconScoreDeployEngine() self._deploy_storage = IconScoreDeployStorage(self._icx_db) self._icon_score_loader = IconScoreLoader(score_path) self._icon_score_mapper = IconScoreMapper() self._addr1 = create_address(AddressPrefix.EOA) self._score_deploy_engine.open( score_root_path=score_path, icon_deploy_storage=self._deploy_storage) self._factory = IconScoreContextFactory(max_size=1) self.make_context() def tearDown(self): try: self._context = self._factory.create(IconScoreContextType.DIRECT) self._factory.destroy(self._context) self._icx_storage.close(self._context) finally: remove_path = os.path.join(TEST_ROOT_PATH, self._ROOT_SCORE_PATH) rmtree(remove_path) remove_path = os.path.join(TEST_ROOT_PATH, self._TEST_DB_PATH) rmtree(remove_path) def make_context(self): self._tx_index += 1 self._context = self._factory.create(IconScoreContextType.DIRECT) self._context.msg = Message(self._addr1, 0) self._context.tx = Transaction(create_tx_hash(), origin=self._addr1) self._context.block = Block(1, create_block_hash(), 0, None) self._context.icon_score_mapper = self._icon_score_mapper self._context.icx = IcxEngine() self.__step_counter_factory = IconScoreStepCounterFactory() self._step_counter: IconScoreStepCounter = \ self.__step_counter_factory.create(100) self._context.step_counter = self._step_counter self._context.icx.open(self._icx_storage) self._context.event_logs = Mock(spec=list) self._context.traces = Mock(spec=list) @staticmethod def __ensure_dir(dir_path): if not os.path.exists(dir_path): os.makedirs(dir_path)