From 21d8f250308bfc5e730b4771af1cd7581bed3774 Mon Sep 17 00:00:00 2001 From: zhangshuang Date: Wed, 27 Nov 2019 16:56:05 +0800 Subject: [PATCH] add mockito test for block rollback --- .../ledger/core/BlockFullRollBackTest.java | 272 ++++++++++++++++++ .../service/utils/MemoryKVStorage.java | 5 - .../intgr/IntegrationBlockFullRollback.java | 105 ------- 3 files changed, 272 insertions(+), 110 deletions(-) create mode 100644 source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/BlockFullRollBackTest.java delete mode 100644 source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBlockFullRollback.java diff --git a/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/BlockFullRollBackTest.java b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/BlockFullRollBackTest.java new file mode 100644 index 00000000..a974844a --- /dev/null +++ b/source/ledger/ledger-core/src/test/java/test/com/jd/blockchain/ledger/core/BlockFullRollBackTest.java @@ -0,0 +1,272 @@ +package test.com.jd.blockchain.ledger.core; + +import com.jd.blockchain.binaryproto.DataContractRegistry; +import com.jd.blockchain.crypto.HashDigest; +import com.jd.blockchain.ledger.*; +import com.jd.blockchain.ledger.core.*; +import com.jd.blockchain.storage.service.ExPolicyKVStorage; +import com.jd.blockchain.storage.service.KVStorageService; +import com.jd.blockchain.storage.service.VersioningKVStorage; +import com.jd.blockchain.storage.service.utils.MemoryKVStorage; +import com.jd.blockchain.utils.Bytes; +import org.junit.Test; +import org.mockito.Mockito; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.lang.reflect.Method; +import java.util.Set; + +import static org.junit.Assert.*; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Mockito.when; + +public class BlockFullRollBackTest { + + static { + DataContractRegistry.register(TransactionContent.class); + DataContractRegistry.register(TransactionContentBody.class); + DataContractRegistry.register(TransactionRequest.class); + DataContractRegistry.register(NodeRequest.class); + DataContractRegistry.register(EndpointRequest.class); + DataContractRegistry.register(TransactionResponse.class); + DataContractRegistry.register(UserRegisterOperation.class); + DataContractRegistry.register(DataAccountRegisterOperation.class); + } + + private static final String LEDGER_KEY_PREFIX = "LDG://"; + + private HashDigest ledgerHash = null; + + private boolean isRollBack = false; + + private BlockchainKeypair parti0 = BlockchainKeyGenerator.getInstance().generate(); + private BlockchainKeypair parti1 = BlockchainKeyGenerator.getInstance().generate(); + private BlockchainKeypair parti2 = BlockchainKeyGenerator.getInstance().generate(); + private BlockchainKeypair parti3 = BlockchainKeyGenerator.getInstance().generate(); + + private BlockchainKeypair[] participants = { parti0, parti1, parti2, parti3 }; + + + @Test + public void testBlockFullkRollBack() { + + final MemoryKVStorage STORAGE = new MemoryKVStorage(); + + final MemoryKVStorage STORAGE_Mock = Mockito.mock(MemoryKVStorage.class); + + + Answer answers = new Answer() { + + @Override + public Object answer(InvocationOnMock invocationOnMock) throws Throwable { + + Method method = invocationOnMock.getMethod(); + if (method.getName().equalsIgnoreCase("set")) { + Object arg2Obj = invocationOnMock.getArguments()[2]; + if (isRollBack) { + if (arg2Obj instanceof ExPolicyKVStorage.ExPolicy) { + return false; + } else { + return -1; + } + } else { + if (arg2Obj instanceof ExPolicyKVStorage.ExPolicy) { + return STORAGE.set((Bytes) (invocationOnMock.getArguments()[0]), (byte[])(invocationOnMock.getArguments()[1]), (ExPolicyKVStorage.ExPolicy)(arg2Obj)); + } else { + return STORAGE.set((Bytes) (invocationOnMock.getArguments()[0]), (byte[])(invocationOnMock.getArguments()[1]), (long)(arg2Obj)); + } + } + } else if ((method.getName().equalsIgnoreCase("get")) && (method.getParameterCount() == 1)) { + return STORAGE.get((Bytes)(invocationOnMock.getArguments()[0])); + } else if ((method.getName().equalsIgnoreCase("get")) && (method.getParameterCount() == 2)) { + return STORAGE.get((Bytes)(invocationOnMock.getArguments()[0]), (long)(invocationOnMock.getArguments()[1])); + } else if (method.getName().equalsIgnoreCase("getVersion")) { + return STORAGE.getVersion((Bytes)(invocationOnMock.getArguments()[0])); + } else if (method.getName().equalsIgnoreCase("getEntry")) { + return STORAGE.get((Bytes)(invocationOnMock.getArguments()[0]), (long)(invocationOnMock.getArguments()[1])); + } else if (method.getName().equalsIgnoreCase("exist")) { + return STORAGE.get((Bytes)(invocationOnMock.getArguments()[0])); + } else if (method.getName().equalsIgnoreCase("keySet")) { + return STORAGE.keySet(); + } else if (method.getName().equalsIgnoreCase("getStorageKeySet")) { + return STORAGE.getStorageKeySet(); + } else if (method.getName().equalsIgnoreCase("getValue")) { + return STORAGE.getValue((Bytes)(invocationOnMock.getArguments()[0])); + } else if (method.getName().equalsIgnoreCase("getStorageCount")) { + return STORAGE.getStorageCount(); + } else if (method.getName().equalsIgnoreCase("getExPolicyKVStorage")) { + return STORAGE.getExPolicyKVStorage(); + } else if (method.getName().equalsIgnoreCase("getVersioningKVStorage")) { + return STORAGE.getVersioningKVStorage(); + } + + return null; + } + }; + + when(STORAGE_Mock.set(any(), any(), anyLong())).thenAnswer(answers); + when(STORAGE_Mock.set(any(), any(), any(ExPolicyKVStorage.ExPolicy.class))).thenAnswer(answers); + when(STORAGE_Mock.get(any())).thenAnswer(answers); + when(STORAGE_Mock.get(any(), anyLong())).thenAnswer(answers); + when(STORAGE_Mock.getVersion(any())).thenAnswer(answers); + when(STORAGE_Mock.getEntry(any(), anyLong())).thenAnswer(answers); + when(STORAGE_Mock.exist(any())).thenAnswer(answers); + when(STORAGE_Mock.keySet()).thenAnswer(answers); + when(STORAGE_Mock.getStorageKeySet()).thenAnswer(answers); + when(STORAGE_Mock.getValue(any())).thenAnswer(answers); + when(STORAGE_Mock.getStorageCount()).thenAnswer(answers); + when(STORAGE_Mock.getExPolicyKVStorage()).thenAnswer(answers); + when(STORAGE_Mock.getVersioningKVStorage()).thenAnswer(answers); + + + // 初始化账本到指定的存储库; + ledgerHash = initLedger(STORAGE_Mock, parti0, parti1, parti2, parti3); + + System.out.println("---------- Ledger init OK !!! ----------"); + + // 加载账本; + LedgerManager ledgerManager = new LedgerManager(); + + KVStorageService kvStorageService = new KVStorageService() { + @Override + public ExPolicyKVStorage getExPolicyKVStorage() { + return STORAGE_Mock; + } + + @Override + public VersioningKVStorage getVersioningKVStorage() { + return STORAGE_Mock; + } + }; + + LedgerRepository ledgerRepo = ledgerManager.register(ledgerHash, kvStorageService); + + // 构造存储错误,并产生区块回滚 + isRollBack = true; + LedgerEditor newBlockEditor = ledgerRepo.createNextBlock(); + + OperationHandleRegisteration opReg = new DefaultOperationHandleRegisteration(); + LedgerSecurityManager securityManager = getSecurityManager(); + TransactionBatchProcessor txbatchProcessor = new TransactionBatchProcessor(securityManager, newBlockEditor, + ledgerRepo, opReg); + + // 注册新用户; + BlockchainKeypair userKeypair = BlockchainKeyGenerator.getInstance().generate(); + TransactionRequest transactionRequest = LedgerTestUtils.createTxRequest_UserReg(userKeypair, ledgerHash, + parti0, parti0); + TransactionResponse txResp = txbatchProcessor.schedule(transactionRequest); + + LedgerBlock newBlock = newBlockEditor.prepare(); + try { + newBlockEditor.commit(); + } catch (BlockRollbackException e) { + newBlockEditor.cancel(); + } + + // 验证正确性; + ledgerManager = new LedgerManager(); + ledgerRepo = ledgerManager.register(ledgerHash, STORAGE_Mock); + LedgerBlock latestBlock = ledgerRepo.getLatestBlock(); + assertEquals(ledgerRepo.getBlockHash(0), latestBlock.getHash()); + assertEquals(0, latestBlock.getHeight()); + + LedgerDataQuery ledgerDS = ledgerRepo.getLedgerData(latestBlock); + boolean existUser = ledgerDS.getUserAccountSet().contains(userKeypair.getAddress()); + + assertFalse(existUser); + + //区块正常提交 + isRollBack = false; + // 生成新区块; + LedgerEditor newBlockEditor1 = ledgerRepo.createNextBlock(); + + OperationHandleRegisteration opReg1 = new DefaultOperationHandleRegisteration(); + LedgerSecurityManager securityManager1 = getSecurityManager(); + TransactionBatchProcessor txbatchProcessor1 = new TransactionBatchProcessor(securityManager1, newBlockEditor1, + ledgerRepo, opReg1); + + // 注册新用户; + BlockchainKeypair userKeypair1 = BlockchainKeyGenerator.getInstance().generate(); + TransactionRequest transactionRequest1 = LedgerTestUtils.createTxRequest_UserReg(userKeypair1, ledgerHash, + parti0, parti0); + TransactionResponse txResp1 = txbatchProcessor1.schedule(transactionRequest1); + + LedgerBlock newBlock1 = newBlockEditor1.prepare(); + + try { + newBlockEditor1.commit(); + } catch (BlockRollbackException e) { + newBlockEditor1.cancel(); + } + + ledgerManager = new LedgerManager(); + ledgerRepo = ledgerManager.register(ledgerHash, STORAGE_Mock); + LedgerBlock latestBlock1 = ledgerRepo.getLatestBlock(); + assertEquals(newBlock1.getHash(), latestBlock1.getHash()); + assertEquals(1, latestBlock1.getHeight()); + + LedgerDataQuery ledgerDS1 = ledgerRepo.getLedgerData(latestBlock1); + boolean existUser1 = ledgerDS1.getUserAccountSet().contains(userKeypair1.getAddress()); + + assertTrue(existUser1); + + } + + private static LedgerSecurityManager getSecurityManager() { + LedgerSecurityManager securityManager = Mockito.mock(LedgerSecurityManager.class); + + SecurityPolicy securityPolicy = Mockito.mock(SecurityPolicy.class); + when(securityPolicy.isEndpointEnable(any(LedgerPermission.class), any())).thenReturn(true); + when(securityPolicy.isEndpointEnable(any(TransactionPermission.class), any())).thenReturn(true); + when(securityPolicy.isNodeEnable(any(LedgerPermission.class), any())).thenReturn(true); + when(securityPolicy.isNodeEnable(any(TransactionPermission.class), any())).thenReturn(true); + + when(securityManager.createSecurityPolicy(any(), any())).thenReturn(securityPolicy); + + return securityManager; + } + + private HashDigest initLedger(MemoryKVStorage storage, BlockchainKeypair... partiKeys) { + // 创建初始化配置; + LedgerInitSetting initSetting = LedgerTestUtils.createLedgerInitSetting(partiKeys); + + // 创建账本; + LedgerEditor ldgEdt = LedgerTransactionalEditor.createEditor(initSetting, LEDGER_KEY_PREFIX, storage, storage); + + TransactionRequest genesisTxReq = LedgerTestUtils.createLedgerInitTxRequest(partiKeys); + LedgerTransactionContext genisisTxCtx = ldgEdt.newTransaction(genesisTxReq); + LedgerDataset ldgDS = genisisTxCtx.getDataset(); + + for (int i = 0; i < partiKeys.length; i++) { + UserAccount userAccount = ldgDS.getUserAccountSet().register(partiKeys[i].getAddress(), + partiKeys[i].getPubKey()); + userAccount.setProperty("Name", "参与方-" + i, -1); + userAccount.setProperty("Share", "" + (10 + i), -1); + } + + LedgerTransaction tx = genisisTxCtx.commit(TransactionState.SUCCESS); + + assertEquals(genesisTxReq.getTransactionContent().getHash(), tx.getTransactionContent().getHash()); + assertEquals(0, tx.getBlockHeight()); + + LedgerBlock block = ldgEdt.prepare(); + + assertEquals(0, block.getHeight()); + assertNotNull(block.getHash()); + assertNull(block.getPreviousHash()); + + // 创世区块的账本哈希为 null; + assertNull(block.getLedgerHash()); + assertNotNull(block.getHash()); + + // 提交数据,写入存储; + ldgEdt.commit(); + + HashDigest ledgerHash = block.getHash(); + return ledgerHash; + } +} diff --git a/source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/utils/MemoryKVStorage.java b/source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/utils/MemoryKVStorage.java index 1cb202fa..0c2192a3 100644 --- a/source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/utils/MemoryKVStorage.java +++ b/source/storage/storage-service/src/main/java/com/jd/blockchain/storage/service/utils/MemoryKVStorage.java @@ -12,8 +12,6 @@ import com.jd.blockchain.utils.io.BytesMap; public class MemoryKVStorage implements ExPolicyKVStorage, VersioningKVStorage, KVStorageService, BytesMap { - public static boolean isBlockFullRollbackTest = false; - private ExistancePolicyKVStorageMap exStorage = new ExistancePolicyKVStorageMap(); private VersioningKVStorageMap verStorage = new VersioningKVStorageMap(); @@ -34,9 +32,6 @@ public class MemoryKVStorage implements ExPolicyKVStorage, VersioningKVStorage, @Override public long set(Bytes key, byte[] value, long version) { - if (isBlockFullRollbackTest) { - return -1; - } return verStorage.set(key, value, version); } diff --git a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBlockFullRollback.java b/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBlockFullRollback.java deleted file mode 100644 index b3a68c77..00000000 --- a/source/test/test-integration/src/test/java/test/com/jd/blockchain/intgr/IntegrationBlockFullRollback.java +++ /dev/null @@ -1,105 +0,0 @@ -package test.com.jd.blockchain.intgr; - -import com.jd.blockchain.crypto.*; -import com.jd.blockchain.gateway.GatewayConfigProperties; -import com.jd.blockchain.ledger.core.LedgerQuery; -import com.jd.blockchain.sdk.BlockchainService; -import com.jd.blockchain.sdk.client.GatewayServiceFactory; -import com.jd.blockchain.storage.service.DbConnectionFactory; -import com.jd.blockchain.storage.service.utils.MemoryKVStorage; -import com.jd.blockchain.tools.initializer.LedgerBindingConfig; -import com.jd.blockchain.utils.concurrent.ThreadInvoker; -import org.junit.Test; -import test.com.jd.blockchain.intgr.initializer.LedgerInitializeTest; -import test.com.jd.blockchain.intgr.initializer.LedgerInitializeWeb4Nodes; - -import static test.com.jd.blockchain.intgr.IntegrationBase.*; - -public class IntegrationBlockFullRollback { - - private static final String DB_TYPE_MEM = "mem"; - - @Test - public void test4Memory() { - test(LedgerInitConsensusConfig.bftsmartProvider, DB_TYPE_MEM, LedgerInitConsensusConfig.memConnectionStrings); - } - - public void test(String[] providers, String dbType, String[] dbConnections) { - - // 内存账本初始化 - HashDigest ledgerHash = initLedger(dbConnections); - - // 启动Peer节点 - PeerTestRunner[] peerNodes = peerNodeStart(ledgerHash, dbType); - - DbConnectionFactory dbConnectionFactory0 = peerNodes[0].getDBConnectionFactory(); - DbConnectionFactory dbConnectionFactory1 = peerNodes[1].getDBConnectionFactory(); - DbConnectionFactory dbConnectionFactory2 = peerNodes[2].getDBConnectionFactory(); - DbConnectionFactory dbConnectionFactory3 = peerNodes[3].getDBConnectionFactory(); - - String encodedBase58Pwd = KeyGenUtils.encodePasswordAsBase58(LedgerInitializeTest.PASSWORD); - - GatewayConfigProperties.KeyPairConfig gwkey0 = new GatewayConfigProperties.KeyPairConfig(); - gwkey0.setPubKeyValue(IntegrationBase.PUB_KEYS[0]); - gwkey0.setPrivKeyValue(IntegrationBase.PRIV_KEYS[0]); - gwkey0.setPrivKeyPassword(encodedBase58Pwd); - GatewayTestRunner gateway = new GatewayTestRunner("127.0.0.1", 11000, gwkey0, - peerNodes[0].getServiceAddress(), providers,null); - - ThreadInvoker.AsyncCallback gwStarting = gateway.start(); - - gwStarting.waitReturn(); - - // 执行测试用例之前,校验每个节点的一致性; - LedgerQuery[] ledgers = buildLedgers(new LedgerBindingConfig[]{ - peerNodes[0].getLedgerBindingConfig(), - peerNodes[1].getLedgerBindingConfig(), - peerNodes[2].getLedgerBindingConfig(), - peerNodes[3].getLedgerBindingConfig(), - }, - new DbConnectionFactory[]{ - dbConnectionFactory0, - dbConnectionFactory1, - dbConnectionFactory2, - dbConnectionFactory3}); - - IntegrationBase.testConsistencyAmongNodes(ledgers); - - LedgerQuery ledgerRepository = ledgers[0]; - - GatewayServiceFactory gwsrvFact = GatewayServiceFactory.connect(gateway.getServiceAddress()); - - PrivKey privkey0 = KeyGenUtils.decodePrivKeyWithRawPassword(IntegrationBase.PRIV_KEYS[0], IntegrationBase.PASSWORD); - - PubKey pubKey0 = KeyGenUtils.decodePubKey(IntegrationBase.PUB_KEYS[0]); - - AsymmetricKeypair adminKey = new AsymmetricKeypair(pubKey0, privkey0); - - BlockchainService blockchainService = gwsrvFact.getBlockchainService(); - - //Block commit will be fail, due to storage error - MemoryKVStorage.isBlockFullRollbackTest = true; - - IntegrationBase.KeyPairResponse userResponse = IntegrationBase.testSDK_BlockFullRollBack(adminKey, ledgerHash, blockchainService); - - //Block commit will be normal - MemoryKVStorage.isBlockFullRollbackTest = false; - - IntegrationBase.KeyPairResponse userResponse1 = IntegrationBase.testSDK_RegisterUser(adminKey, ledgerHash, blockchainService); - - try { - System.out.println("----------------- Init Completed -----------------"); - Thread.sleep(Integer.MAX_VALUE); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - IntegrationBase.testConsistencyAmongNodes(ledgers); - } - private HashDigest initLedger(String[] dbConnections) { - LedgerInitializeWeb4Nodes ledgerInit = new LedgerInitializeWeb4Nodes(); - HashDigest ledgerHash = ledgerInit.testInitWith4Nodes(LedgerInitConsensusConfig.bftsmartConfig, dbConnections); - System.out.printf("LedgerHash = %s \r\n", ledgerHash.toBase58()); - return ledgerHash; - } -}