diff --git a/exonum-java-binding/core/src/test/java/com/exonum/binding/blockchain/Blockchain2IntegrationTest.java b/exonum-java-binding/core/src/test/java/com/exonum/binding/blockchain/Blockchain2IntegrationTest.java deleted file mode 100644 index 1cce8567ce..0000000000 --- a/exonum-java-binding/core/src/test/java/com/exonum/binding/blockchain/Blockchain2IntegrationTest.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Copyright 2018 The Exonum Team - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package com.exonum.binding.blockchain; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -import com.exonum.binding.common.blockchain.TransactionLocation; -import com.exonum.binding.common.blockchain.TransactionResult; -import com.exonum.binding.common.configuration.StoredConfiguration; -import com.exonum.binding.common.hash.HashCode; -import com.exonum.binding.storage.indices.KeySetIndexProxy; -import com.exonum.binding.storage.indices.ListIndexProxy; -import com.exonum.binding.storage.indices.MapIndex; -import com.exonum.binding.storage.indices.ProofListIndexProxy; -import com.exonum.binding.storage.indices.ProofMapIndexProxy; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -@SuppressWarnings("unchecked") // Don't warn of unchecked assignment of mocks -@ExtendWith(MockitoExtension.class) -// todo: rename in ECR-3195 -class Blockchain2IntegrationTest { - - private static final long HEIGHT = 10L; - - private static final Block BLOCK = Block.builder() - .proposerId(1) - .height(HEIGHT) - .numTransactions(1) - .blockHash(HashCode.fromString("ab")) - .previousBlockHash(HashCode.fromString("bc")) - .txRootHash(HashCode.fromString("cd")) - .stateHash(HashCode.fromString("ab")) - .build(); - - private Blockchain blockchain; - - @Mock - private CoreSchemaProxy mockSchema; - - @BeforeEach - void setUp() { - blockchain = new Blockchain(mockSchema); - } - - @Test - void getHeight() { - when(mockSchema.getHeight()).thenReturn(HEIGHT); - - assertThat(blockchain.getHeight()).isEqualTo(HEIGHT); - } - - @Test - void getAllBlockHashes() { - ListIndexProxy blockHashes = mock(ListIndexProxy.class); - when(mockSchema.getBlockHashes()).thenReturn(blockHashes); - - assertThat(blockchain.getBlockHashes()).isEqualTo(blockHashes); - } - - @Test - void getBlockTransactionsByHeight() { - ProofListIndexProxy transactions = mock(ProofListIndexProxy.class); - when(mockSchema.getBlockTransactions(HEIGHT)).thenReturn(transactions); - - assertThat(blockchain.getBlockTransactions(HEIGHT)).isEqualTo(transactions); - } - - @Test - void getBlockTransactionsByBlockId() { - ProofListIndexProxy transactions = mock(ProofListIndexProxy.class); - MapIndex blocks = mock(MapIndex.class); - HashCode blockId = HashCode.fromString("ab"); - - when(mockSchema.getBlocks()).thenReturn(blocks); - when(blocks.get(blockId)).thenReturn(BLOCK); - when(mockSchema.getBlockTransactions(HEIGHT)).thenReturn(transactions); - - assertThat(blockchain.getBlockTransactions(blockId)).isEqualTo(transactions); - } - - @Test - void getTxMessages() { - MapIndex txMessages = mock(MapIndex.class); - when(mockSchema.getTxMessages()).thenReturn(txMessages); - - assertThat(blockchain.getTxMessages()).isEqualTo(txMessages); - } - - @Test - void getTxResults() { - ProofMapIndexProxy txResults = mock(ProofMapIndexProxy.class); - when(mockSchema.getTxResults()).thenReturn(txResults); - - assertThat(blockchain.getTxResults()).isEqualTo(txResults); - } - - @Test - void getTxResult() { - ProofMapIndexProxy txResults = mock(ProofMapIndexProxy.class); - HashCode messageHash = HashCode.fromString("ab"); - TransactionResult txResult = TransactionResult.successful(); - - when(txResults.get(messageHash)).thenReturn(txResult); - when(mockSchema.getTxResults()).thenReturn(txResults); - - assertThat(blockchain.getTxResult(messageHash).get()).isEqualTo(txResult); - } - - @Test - void getNonexistentTxResult() { - ProofMapIndexProxy txResults = mock(ProofMapIndexProxy.class); - HashCode messageHash = HashCode.fromString("ab"); - - when(txResults.get(messageHash)).thenReturn(null); - when(mockSchema.getTxResults()).thenReturn(txResults); - - assertThat(blockchain.getTxResult(messageHash)).isEmpty(); - } - - @Test - void getTxLocations() { - MapIndex txLocations = mock(MapIndex.class); - when(mockSchema.getTxLocations()).thenReturn(txLocations); - - assertThat(blockchain.getTxLocations()).isEqualTo(txLocations); - } - - @Test - void getTxLocation() { - MapIndex txLocations = mock(MapIndex.class); - HashCode messageHash = HashCode.fromString("ab"); - TransactionLocation txLocation = TransactionLocation.valueOf(1L, 1L); - - when(txLocations.get(messageHash)).thenReturn(txLocation); - when(mockSchema.getTxLocations()).thenReturn(txLocations); - - assertThat(blockchain.getTxLocation(messageHash).get()).isEqualTo(txLocation); - } - - @Test - void getNonexistentTxLocation() { - MapIndex blocks = mock(MapIndex.class); - HashCode messageHash = HashCode.fromString("ab"); - - when(blocks.get(messageHash)).thenReturn(null); - when(mockSchema.getTxLocations()).thenReturn(blocks); - - assertThat(blockchain.getTxLocation(messageHash)).isEmpty(); - } - - @Test - void getBlocks() { - MapIndex mockMapIndex = mock(MapIndex.class); - when(mockSchema.getBlocks()).thenReturn(mockMapIndex); - - assertThat(blockchain.getBlocks()).isEqualTo(mockMapIndex); - } - - @Test - void findBlock() { - MapIndex blocks = mock(MapIndex.class); - HashCode blockHash = HashCode.fromString("ab"); - - when(blocks.get(blockHash)).thenReturn(BLOCK); - when(mockSchema.getBlocks()).thenReturn(blocks); - - assertThat(blockchain.findBlock(blockHash).get()).isEqualTo(BLOCK); - } - - @Test - void findNonexistentBlock() { - MapIndex blocks = mock(MapIndex.class); - HashCode blockHash = HashCode.fromString("ab"); - - when(blocks.get(blockHash)).thenReturn(null); - when(mockSchema.getBlocks()).thenReturn(blocks); - - assertThat(blockchain.findBlock(blockHash)).isEmpty(); - } - - @Test - void getLastBlock() { - when(mockSchema.getLastBlock()).thenReturn(BLOCK); - - assertThat(blockchain.getLastBlock()).isEqualTo(BLOCK); - } - - @Test - void getActualConfiguration() { - StoredConfiguration configuration = mock(StoredConfiguration.class); - when(mockSchema.getActualConfiguration()).thenReturn(configuration); - - assertThat(blockchain.getActualConfiguration()).isEqualTo(configuration); - } - - @Test - void getTransactionPool() { - KeySetIndexProxy transactions = mock(KeySetIndexProxy.class); - when(mockSchema.getTransactionPool()).thenReturn(transactions); - - assertThat(blockchain.getTransactionPool()).isEqualTo(transactions); - } -} diff --git a/exonum-java-binding/core/src/test/java/com/exonum/binding/blockchain/BlockchainIntegrationTest.java b/exonum-java-binding/core/src/test/java/com/exonum/binding/blockchain/BlockchainIntegrationTest.java deleted file mode 100644 index e4066f5765..0000000000 --- a/exonum-java-binding/core/src/test/java/com/exonum/binding/blockchain/BlockchainIntegrationTest.java +++ /dev/null @@ -1,288 +0,0 @@ -/* - * Copyright 2018 The Exonum Team - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.exonum.binding.blockchain; - -import static com.exonum.binding.blockchain.Blocks.withProperHash; -import static java.nio.charset.StandardCharsets.UTF_8; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.mockito.Mockito.lenient; -import static org.mockito.Mockito.when; - -import com.exonum.binding.blockchain.Block.Builder; -import com.exonum.binding.blockchain.serialization.BlockSerializer; -import com.exonum.binding.common.hash.HashCode; -import com.exonum.binding.common.hash.HashFunction; -import com.exonum.binding.common.hash.Hashing; -import com.exonum.binding.common.serialization.StandardSerializers; -import com.exonum.binding.proxy.Cleaner; -import com.exonum.binding.proxy.CloseFailuresException; -import com.exonum.binding.storage.database.Fork; -import com.exonum.binding.storage.database.MemoryDb; -import com.exonum.binding.storage.database.Snapshot; -import com.exonum.binding.storage.indices.ListIndex; -import com.exonum.binding.storage.indices.ListIndexProxy; -import com.exonum.binding.storage.indices.MapIndex; -import com.exonum.binding.storage.indices.MapIndexProxy; -import com.exonum.binding.storage.indices.ProofListIndexProxy; -import com.exonum.binding.test.RequiresNativeLibrary; -import com.google.common.collect.ImmutableList; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.LongStream; -import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Nested; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.junit.jupiter.params.ParameterizedTest; -import org.junit.jupiter.params.provider.ValueSource; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -@RequiresNativeLibrary -@ExtendWith(MockitoExtension.class) -class BlockchainIntegrationTest { - - private static final String TEST_BLOCKS = "test_blocks"; - private static final String TEST_BLOCK_HASHES = "test_block_hashes"; - private static final String TEST_BLOCK_TRANSACTIONS = "test_block_transactions"; - - @Mock - CoreSchemaProxy coreSchema; - - private Blockchain blockchain; - - private MemoryDb database; - - @BeforeEach - void setUp() { - blockchain = new Blockchain(coreSchema); - database = MemoryDb.newInstance(); - } - - @AfterEach - void tearDown() { - database.close(); - } - - @Nested - class WithSingleBlock { - final List expectedBlockTransactions = ImmutableList.of(HashCode.fromInt(1)); - - Cleaner cleaner; - Block block; - - @BeforeEach - void setUp() { - cleaner = new Cleaner(); - Fork fork = database.createFork(cleaner); - - // Setup blocks - MapIndex blocks = MapIndexProxy.newInstance(TEST_BLOCKS, fork, - StandardSerializers.hash(), BlockSerializer.INSTANCE); - int blockHeight = 1; - block = withProperHash(aBlock(blockHeight) - .numTransactions(expectedBlockTransactions.size()) - .build()); - blocks.put(block.getBlockHash(), block); - when(coreSchema.getBlocks()).thenReturn(blocks); - - // Setup tx hashes - ProofListIndexProxy transactionHashes = ProofListIndexProxy.newInstance( - TEST_BLOCK_TRANSACTIONS, fork, StandardSerializers.hash()); - transactionHashes.addAll(expectedBlockTransactions); - lenient().when(coreSchema.getBlockTransactions(blockHeight)) - .thenReturn(transactionHashes); - } - - @AfterEach - void tearDown() throws CloseFailuresException { - cleaner.close(); - } - - @Test - void containsBlock() { - assertTrue(blockchain.containsBlock(block)); - } - - @Test - void containsBlockNoSuchBlock() { - Block unknownBlock = aBlock(Long.MAX_VALUE).build(); - assertFalse(blockchain.containsBlock(unknownBlock)); - } - - @Test - void containsBlockSameHashDistinctFields() { - // Check against a block that has the same hash, but different fields. - Block unknownBlock = aBlock(10L) - .blockHash(block.getBlockHash()) - .build(); - assertFalse(blockchain.containsBlock(unknownBlock)); - } - - @Test - void getBlockTransactionsByBlock() { - assertThat(blockchain.getBlockTransactions(block)) - .hasSameElementsAs(expectedBlockTransactions); - } - - @Test - void getBlockTransactionsByBlockNoSuchBlock() { - Block unknownBlock = aBlock(Long.MAX_VALUE).build(); - - Exception e = assertThrows(IllegalArgumentException.class, - () -> blockchain.getBlockTransactions(unknownBlock)); - - String hashAsString = unknownBlock.getBlockHash().toString(); - assertThat(e).hasMessageContaining(hashAsString); - } - - @Test - void getBlockTransactionsByBlockSameHashDistinctFields() { - // Check against a block that has the same hash, but different fields. - Block unknownBlock = aBlock(10L) - .blockHash(block.getBlockHash()) - .build(); - - Exception e = assertThrows(IllegalArgumentException.class, - () -> blockchain.getBlockTransactions(unknownBlock)); - - String hashAsString = unknownBlock.getBlockHash().toString(); - assertThat(e).hasMessageContaining(hashAsString); - } - } - - @Nested - class WithSeveralBlocks { - - private static final long HEIGHT = 2; - - Cleaner cleaner; - List blocks; - - @BeforeEach - void setUp() throws CloseFailuresException { - // Fill database with test data - blocks = createTestBlockchain(HEIGHT); - - // Create a cleaner for Snapshot - cleaner = new Cleaner(); - Snapshot snapshot = database.createSnapshot(cleaner); - - // Setup mocks - setupMocks(snapshot); - } - - @AfterEach - void tearDown() throws CloseFailuresException { - cleaner.close(); - } - - private List createTestBlockchain(long blockchainHeight) - throws CloseFailuresException { - try (Cleaner cleaner = new Cleaner()) { - List blocks = LongStream.rangeClosed(0, blockchainHeight) - .mapToObj(h -> aBlock(h).build()) - .map(Blocks::withProperHash) - .collect(Collectors.toList()); - - // Add the blocks - // … to the map of blocks - Fork fork = database.createFork(cleaner); - MapIndex blocksByHash = MapIndexProxy.newInstance(TEST_BLOCKS, fork, - StandardSerializers.hash(), BlockSerializer.INSTANCE); - - for (Block b : blocks) { - blocksByHash.put(b.getBlockHash(), b); - } - - // … to the list of block hashes - ListIndex blockHashes = ListIndexProxy.newInstance(TEST_BLOCK_HASHES, fork, - StandardSerializers.hash()); - for (Block b : blocks) { - blockHashes.add(b.getBlockHash()); - } - - // Merge the changes - database.merge(fork); - - return blocks; - } - } - - private void setupMocks(Snapshot snapshot) { - when(coreSchema.getHeight()).thenReturn(HEIGHT); - MapIndex blocksByHash = MapIndexProxy.newInstance(TEST_BLOCKS, snapshot, - StandardSerializers.hash(), BlockSerializer.INSTANCE); - lenient().when(coreSchema.getBlocks()).thenReturn(blocksByHash); - ListIndex blockHashes = ListIndexProxy.newInstance(TEST_BLOCK_HASHES, snapshot, - StandardSerializers.hash()); - lenient().when(coreSchema.getBlockHashes()).thenReturn(blockHashes); - } - - @Test - void getBlockAtHeight() { - long blockchainHeight = HEIGHT; - - // Test that correct blocks are returned - for (int height = 0; height <= blockchainHeight; height++) { - Block actualBlock = blockchain.getBlock(height); - Block expectedBlock = blocks.get(height); - - assertThat(actualBlock).isEqualTo(expectedBlock); - } - // Test no blocks beyond the height - assertThrows(IndexOutOfBoundsException.class, - () -> blockchain.getBlock(blockchainHeight + 2)); - } - - @ParameterizedTest - @ValueSource(longs = { - Long.MIN_VALUE, -1, HEIGHT + 1, HEIGHT + 2, Long.MAX_VALUE - }) - void getBlockAtInvalidHeight(long invalidBlockchainHeight) { - Exception e = assertThrows(IndexOutOfBoundsException.class, - () -> blockchain.getBlock(invalidBlockchainHeight)); - - assertThat(e).hasMessageContaining(Long.toString(invalidBlockchainHeight)); - } - } - - /** - * Creates a builder of a block, fully initialized with defaults, inferred from the height. - * An invocation with the same height will produce exactly the same builder. The block hash - * is not equal to the hash of the block with such parameters. - * - * @param blockHeight a block height - * @return a new block builder - */ - private static Builder aBlock(long blockHeight) { - HashFunction hashFunction = Hashing.sha256(); - return Block.builder() - .proposerId(0) - .height(blockHeight) - .numTransactions(0) - .blockHash(hashFunction.hashLong(blockHeight)) - .previousBlockHash(hashFunction.hashLong(blockHeight - 1)) - .txRootHash(hashFunction.hashString("transactions at" + blockHeight, UTF_8)) - .stateHash(hashFunction.hashString("state hash at " + blockHeight, UTF_8)); - } - -} diff --git a/exonum-java-binding/integration-tests/src/test/java/com/exonum/binding/test/BlockchainIntegrationTest.java b/exonum-java-binding/integration-tests/src/test/java/com/exonum/binding/test/BlockchainIntegrationTest.java index 5c0af77c45..7c2f2ae87f 100644 --- a/exonum-java-binding/integration-tests/src/test/java/com/exonum/binding/test/BlockchainIntegrationTest.java +++ b/exonum-java-binding/integration-tests/src/test/java/com/exonum/binding/test/BlockchainIntegrationTest.java @@ -61,6 +61,8 @@ class BlockchainIntegrationTest { private static final CryptoFunction CRYPTO_FUNCTION = CryptoFunctions.ed25519(); private static final KeyPair KEY_PAIR = CRYPTO_FUNCTION.generateKeyPair(); private static final short VALIDATOR_COUNT = 1; + private static final HashCode ZERO_HASH_CODE = HashCode.fromBytes( + new byte[DEFAULT_HASH_SIZE_BYTES]); private TestKit testKit; private Block block; @@ -291,6 +293,16 @@ void getBlockByHeight() { }); } + @Test + void getBlockByHeightGenesis() { + testKitTest((blockchain) -> { + long genesisBlockHeight = 0; + Block genesisBlock = blockchain.getBlock(0); + assertThat(genesisBlock.getHeight()).isEqualTo(genesisBlockHeight); + assertThat(genesisBlock.getPreviousBlockHash()).isEqualTo(ZERO_HASH_CODE); + }); + } + @Test void getBlockByInvalidHeight() { testKitTest((blockchain) -> { @@ -311,6 +323,15 @@ void getBlockById() { }); } + @Test + void getUnknownBlockById() { + testKitTest((blockchain) -> { + HashCode blockHash = HashCode.fromString("ab"); + Optional block = blockchain.findBlock(blockHash); + assertThat(block).isEmpty(); + }); + } + @Test void getLastBlock() { testKitTest((blockchain) -> { @@ -337,8 +358,7 @@ void getActualConfiguration() { assertThat(serviceKeys).isEqualTo(expectedKeys); // Check the previous config is empty - HashCode zeroHashCode = HashCode.fromBytes(new byte[DEFAULT_HASH_SIZE_BYTES]); - assertThat(configuration.previousCfgHash()).isEqualTo(zeroHashCode); + assertThat(configuration.previousCfgHash()).isEqualTo(ZERO_HASH_CODE); }); } diff --git a/exonum-java-binding/time-oracle/src/test/java/com/exonum/binding/time/TimeSchemaProxyIntegrationTest.java b/exonum-java-binding/time-oracle/src/test/java/com/exonum/binding/time/TimeSchemaProxyIntegrationTest.java deleted file mode 100644 index b2f6b4bb10..0000000000 --- a/exonum-java-binding/time-oracle/src/test/java/com/exonum/binding/time/TimeSchemaProxyIntegrationTest.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2019 The Exonum Team - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - */ - -package com.exonum.binding.time; - -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.fail; - -import com.exonum.binding.proxy.Cleaner; -import com.exonum.binding.proxy.CloseFailuresException; -import com.exonum.binding.storage.database.MemoryDb; -import com.exonum.binding.storage.database.Snapshot; -import com.exonum.binding.test.RequiresNativeLibrary; -import java.util.function.Consumer; -import org.junit.jupiter.api.Test; - -@RequiresNativeLibrary -class TimeSchemaProxyIntegrationTest { - - @Test - void getTimeTest() { - assertSchema((schema) -> assertFalse(schema.getTime().isPresent())); - } - - @Test - void getValidatorsTimesTest() { - assertSchema((schema) -> assertFalse(schema.getValidatorsTimes().entries().hasNext())); - } - - private static void assertSchema(Consumer assertion) { - try (MemoryDb db = MemoryDb.newInstance(); - Cleaner cleaner = new Cleaner()) { - Snapshot view = db.createSnapshot(cleaner); - assertion.accept(new TimeSchemaProxy(view)); - } catch (CloseFailuresException e) { - fail(e); - } - } -}