diff --git a/db/core/build.gradle b/db/core/build.gradle index 9d228310f..6ee6126af 100644 --- a/db/core/build.gradle +++ b/db/core/build.gradle @@ -1,7 +1,20 @@ dependencies { - api project(':types') - api project(':crypto') + api(project(':types')) { + exclude group: 'junit' + } + + api(project(':crypto')) { + exclude group: 'junit' + } api "org.rocksdb:rocksdbjni" api "com.googlecode.concurrent-locks:concurrent-locks" + + testImplementation 'org.junit.jupiter:junit-jupiter:5.5.1' + + test { + useJUnitPlatform { + excludeTags 'FIX' + } + } } diff --git a/db/core/src/main/java/org/ethereum/beacon/db/flush/BufferSizeObserver.java b/db/core/src/main/java/org/ethereum/beacon/db/flush/BufferSizeObserver.java index 865105b79..606c863dd 100644 --- a/db/core/src/main/java/org/ethereum/beacon/db/flush/BufferSizeObserver.java +++ b/db/core/src/main/java/org/ethereum/beacon/db/flush/BufferSizeObserver.java @@ -4,6 +4,9 @@ import org.apache.logging.log4j.Logger; import org.ethereum.beacon.db.source.WriteBuffer; +import javax.annotation.Nonnull; +import java.util.Objects; + /** * Flushing strategy that observes a size of given buffer and emits a flush whenever size limit is * exceeded. @@ -19,13 +22,16 @@ public class BufferSizeObserver implements DatabaseFlusher { /** A limit of buffer size in bytes. */ private final long bufferSizeLimit; - BufferSizeObserver(WriteBuffer buffer, WriteBuffer commitTrack, long bufferSizeLimit) { + BufferSizeObserver(@Nonnull WriteBuffer buffer, @Nonnull WriteBuffer commitTrack, long bufferSizeLimit) { + Objects.requireNonNull(buffer); + Objects.requireNonNull(commitTrack); this.buffer = buffer; this.commitTrack = commitTrack; this.bufferSizeLimit = bufferSizeLimit; } - public static BufferSizeObserver create(WriteBuffer buffer, long bufferSizeLimit) { + public static BufferSizeObserver create(@Nonnull WriteBuffer buffer, long bufferSizeLimit) { + Objects.requireNonNull(buffer); WriteBuffer commitTrack = new WriteBuffer<>(buffer, false); return new BufferSizeObserver(buffer, commitTrack, bufferSizeLimit); } diff --git a/db/core/src/test/java/org/ethereum/beacon/db/DatabaseTest.java b/db/core/src/test/java/org/ethereum/beacon/db/DatabaseTest.java new file mode 100644 index 000000000..99262c1b5 --- /dev/null +++ b/db/core/src/test/java/org/ethereum/beacon/db/DatabaseTest.java @@ -0,0 +1,97 @@ +package org.ethereum.beacon.db; + +import org.ethereum.beacon.db.source.DataSource; +import org.ethereum.beacon.db.util.FileUtil; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import org.rocksdb.RocksDBException; +import tech.pegasys.artemis.util.bytes.BytesValue; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class DatabaseTest { + + @Test + void testInvalidCreation() { + final Database database = Database.rocksDB("", 0); + assertThatThrownBy(() -> database.createStorage("test-db")) + .isInstanceOf(RuntimeException.class) + .hasCauseExactlyInstanceOf(RocksDBException.class); + } + + @Test + void testInvalidCreationWithNull() { + assertThatThrownBy(() -> Database.rocksDB(null, 0)).isInstanceOf(NullPointerException.class); + } + + @ParameterizedTest + @MethodSource("validArgumentsProvider") + void testValidCreation(String path, long bufferLimitsInBytes) throws IOException { + final Database database = Database.rocksDB(path, bufferLimitsInBytes); + final DataSource storage = database.createStorage("test-db"); + final Path directory = Paths.get(path); + assertThat(Files.exists(directory)).isTrue(); + + final BytesValue key = BytesValue.of(123); + final BytesValue value = BytesValue.of(1, 2, 3); + storage.put(key, value); + assertThat(storage.get(key)).isPresent().hasValue(value); + + storage.remove(key); + assertThat(storage.get(key)).isNotPresent(); + database.close(); + + FileUtil.removeRecursively("rocksdb"); + } + + private static Stream validArgumentsProvider() { + return Stream.of( + Arguments.of("rocksdb", 0), + Arguments.of("rocksdb2", Long.MAX_VALUE), + Arguments.of("rocksdb3", Long.MIN_VALUE)); + } + + @Test + void testCreateDifferentStoresForSameDb() throws IOException { + final Database database = Database.rocksDB("rocksdb", Long.MAX_VALUE); + final DataSource s1 = database.createStorage("test-db"); + final DataSource s2 = database.createStorage("test-db2"); + assertThat(Files.exists(Paths.get("rocksdb"))).isTrue(); + + s1.put(BytesValue.of(123), BytesValue.of(1, 2, 3)); + s2.put(BytesValue.of(123), BytesValue.of(1, 2, 3)); + database.commit(); + database.close(); + + s1.remove(BytesValue.of(123)); + s2.remove(BytesValue.of(123)); + assertThatThrownBy(database::commit).isInstanceOf(Exception.class); //TODO: should not commit after close + + FileUtil.removeRecursively("rocksdb"); + } + + @Test + void testCreateDuplicateStorage() throws IOException { + final Database database = Database.rocksDB("rocksdb", Long.MAX_VALUE); + final DataSource s1 = database.createStorage("test-db"); + final DataSource s2 = database.createStorage("test-db"); + assertThat(Files.exists(Paths.get("rocksdb"))).isTrue(); + + //TODO: how to test without casting + s1.put(BytesValue.of(123), BytesValue.of(1, 2, 3)); + s2.put(BytesValue.of(123), BytesValue.of(1, 2, 3)); + database.commit(); + database.close(); + + FileUtil.removeRecursively("rocksdb"); + } +} diff --git a/db/core/src/test/java/org/ethereum/beacon/db/EngineDrivenDatabaseTest.java b/db/core/src/test/java/org/ethereum/beacon/db/EngineDrivenDatabaseTest.java index 28f27f043..e9273951a 100644 --- a/db/core/src/test/java/org/ethereum/beacon/db/EngineDrivenDatabaseTest.java +++ b/db/core/src/test/java/org/ethereum/beacon/db/EngineDrivenDatabaseTest.java @@ -1,9 +1,15 @@ package org.ethereum.beacon.db; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import org.ethereum.beacon.db.source.DataSource; +import org.ethereum.beacon.db.source.StorageEngineSource; +import org.ethereum.beacon.db.source.impl.MemSizeEvaluators; +import org.junit.jupiter.api.Disabled; +import org.junit.jupiter.api.Test; +import tech.pegasys.artemis.util.bytes.Bytes32; +import tech.pegasys.artemis.util.bytes.BytesValue; +import tech.pegasys.artemis.util.uint.UInt64; +import javax.annotation.Nonnull; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -13,20 +19,15 @@ import java.util.Optional; import java.util.Random; import java.util.Set; -import javax.annotation.Nonnull; -import org.ethereum.beacon.db.source.DataSource; -import org.ethereum.beacon.db.source.StorageEngineSource; -import org.ethereum.beacon.db.source.impl.MemSizeEvaluators; -import org.junit.Ignore; -import org.junit.Test; -import tech.pegasys.artemis.util.bytes.Bytes32; -import tech.pegasys.artemis.util.bytes.BytesValue; -import tech.pegasys.artemis.util.uint.UInt64; -public class EngineDrivenDatabaseTest { +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class EngineDrivenDatabaseTest { @Test - public void generalCasesAreCorrect() { + void generalCasesAreCorrect() { TestStorageSource engineSource = new TestStorageSource(); EngineDrivenDatabase db = EngineDrivenDatabase.createWithInstantFlusher(engineSource); @@ -36,21 +37,21 @@ public void generalCasesAreCorrect() { storage.put(wrap("TWO"), wrap("SECOND")); assertTrue(engineSource.source.isEmpty()); - assertEquals(wrap("FIRST"), storage.get(wrap("ONE")).get()); - assertEquals(wrap("SECOND"), storage.get(wrap("TWO")).get()); - assertFalse(storage.get(wrap("THREE")).isPresent()); + assertThat(wrap("FIRST")).isEqualTo(storage.get(wrap("ONE")).get()); + assertThat(wrap("SECOND")).isEqualTo(storage.get(wrap("TWO")).get()); + assertThat(storage.get(wrap("THREE"))).isNotPresent(); db.commit(); - assertFalse(db.getWriteBuffer().getCacheEntry(wrap("ONE")).isPresent()); - assertFalse(db.getWriteBuffer().getCacheEntry(wrap("TWO")).isPresent()); - assertEquals(0L, db.getWriteBuffer().evaluateSize()); + assertThat(db.getWriteBuffer().getCacheEntry(wrap("ONE"))).isNotPresent(); + assertThat(db.getWriteBuffer().getCacheEntry(wrap("TWO"))).isNotPresent(); + assertThat(0L).isEqualTo(db.getWriteBuffer().evaluateSize()); assertTrue(engineSource.source.containsValue(wrap("FIRST"))); assertTrue(engineSource.source.containsValue(wrap("SECOND"))); - assertEquals(wrap("FIRST"), storage.get(wrap("ONE")).get()); - assertEquals(wrap("SECOND"), storage.get(wrap("TWO")).get()); - assertFalse(storage.get(wrap("THREE")).isPresent()); + assertThat(wrap("FIRST")).isEqualTo(storage.get(wrap("ONE")).get()); + assertThat(wrap("SECOND")).isEqualTo(storage.get(wrap("TWO")).get()); + assertThat(storage.get(wrap("THREE"))).isNotPresent(); storage.remove(wrap("SECOND")); storage.put(wrap("THREE"), wrap("THIRD")); @@ -60,9 +61,9 @@ public void generalCasesAreCorrect() { assertTrue(engineSource.source.containsValue(wrap("SECOND"))); assertFalse(engineSource.source.containsValue(wrap("THIRD"))); - assertEquals(wrap("FIRST"), storage.get(wrap("ONE")).get()); - assertFalse(storage.get(wrap("TWO")).isPresent()); - assertEquals(wrap("THIRD"), storage.get(wrap("THREE")).get()); + assertThat(wrap("FIRST")).isEqualTo(storage.get(wrap("ONE")).get()); + assertThat(storage.get(wrap("TWO"))).isNotPresent(); + assertThat(wrap("THIRD")).isEqualTo(storage.get(wrap("THREE")).get()); db.commit(); @@ -70,13 +71,13 @@ public void generalCasesAreCorrect() { assertFalse(engineSource.source.containsValue(wrap("SECOND"))); assertTrue(engineSource.source.containsValue(wrap("THIRD"))); - assertEquals(wrap("FIRST"), storage.get(wrap("ONE")).get()); - assertFalse(storage.get(wrap("TWO")).isPresent()); - assertEquals(wrap("THIRD"), storage.get(wrap("THREE")).get()); + assertThat(wrap("FIRST")).isEqualTo(storage.get(wrap("ONE")).get()); + assertThat(storage.get(wrap("TWO"))).isNotPresent(); + assertThat(wrap("THIRD")).isEqualTo(storage.get(wrap("THREE")).get()); } @Test - public void multipleStorageCase() { + void multipleStorageCase() { TestStorageSource engineSource = new TestStorageSource(); EngineDrivenDatabase db = EngineDrivenDatabase.createWithInstantFlusher(engineSource); @@ -90,39 +91,39 @@ public void multipleStorageCase() { dos.put(wrap("FOUR"), wrap("DOS_FOURTH")); db.commit(); - assertEquals(wrap("FIRST"), uno.get(wrap("ONE")).get()); - assertEquals(wrap("SECOND"), uno.get(wrap("TWO")).get()); - assertEquals(wrap("SECOND"), dos.get(wrap("TWO")).get()); - assertEquals(wrap("UNO_THIRD"), uno.get(wrap("THREE")).get()); - assertEquals(wrap("DOS_FOURTH"), dos.get(wrap("FOUR")).get()); - assertFalse(uno.get(wrap("FOUR")).isPresent()); - assertFalse(dos.get(wrap("ONE")).isPresent()); - assertFalse(dos.get(wrap("THREE")).isPresent()); + assertThat(wrap("FIRST")).isEqualTo(uno.get(wrap("ONE")).get()); + assertThat(wrap("SECOND")).isEqualTo(uno.get(wrap("TWO")).get()); + assertThat(wrap("SECOND")).isEqualTo(dos.get(wrap("TWO")).get()); + assertThat(wrap("UNO_THIRD")).isEqualTo(uno.get(wrap("THREE")).get()); + assertThat(wrap("DOS_FOURTH")).isEqualTo(dos.get(wrap("FOUR")).get()); + assertThat(uno.get(wrap("FOUR"))).isNotPresent(); + assertThat(dos.get(wrap("ONE"))).isNotPresent(); + assertThat(dos.get(wrap("THREE"))).isNotPresent(); uno.remove(wrap("TWO")); dos.put(wrap("THREE"), wrap("DOS_THIRD")); - assertFalse(uno.get(wrap("TWO")).isPresent()); - assertEquals(wrap("DOS_THIRD"), dos.get(wrap("THREE")).get()); - assertEquals(wrap("UNO_THIRD"), uno.get(wrap("THREE")).get()); + assertThat(uno.get(wrap("TWO"))).isNotPresent(); + assertThat(wrap("DOS_THIRD")).isEqualTo(dos.get(wrap("THREE")).get()); + assertThat(wrap("UNO_THIRD")).isEqualTo(uno.get(wrap("THREE")).get()); db.commit(); - assertFalse(uno.get(wrap("TWO")).isPresent()); - assertEquals(wrap("DOS_THIRD"), dos.get(wrap("THREE")).get()); - assertEquals(wrap("UNO_THIRD"), uno.get(wrap("THREE")).get()); + assertThat(uno.get(wrap("TWO"))).isNotPresent(); + assertThat(wrap("DOS_THIRD")).isEqualTo(dos.get(wrap("THREE")).get()); + assertThat(wrap("UNO_THIRD")).isEqualTo(uno.get(wrap("THREE")).get()); dos.remove(wrap("FOUR")); uno.put(wrap("FOUR"), wrap("UNO_FOURTH")); - assertEquals(wrap("UNO_FOURTH"), uno.get(wrap("FOUR")).get()); - assertFalse(dos.get(wrap("FOUR")).isPresent()); + assertThat(wrap("UNO_FOURTH")).isEqualTo(uno.get(wrap("FOUR")).get()); + assertThat(dos.get(wrap("FOUR"))).isNotPresent(); db.commit(); - assertEquals(wrap("UNO_FOURTH"), uno.get(wrap("FOUR")).get()); - assertFalse(dos.get(wrap("FOUR")).isPresent()); + assertThat(wrap("UNO_FOURTH")).isEqualTo(uno.get(wrap("FOUR")).get()); + assertThat(dos.get(wrap("FOUR"))).isNotPresent(); } @Test - public void checkBufferSizeFlusher() { + void checkBufferSizeFlusher() { TestStorageSource engineSource = new TestStorageSource(); EngineDrivenDatabase db = EngineDrivenDatabase.create(engineSource, 512); @@ -142,29 +143,27 @@ public void checkBufferSizeFlusher() { // should be flushed now db.commit(); - assertEquals(4, engineSource.source.size()); - assertEquals(0L, db.getWriteBuffer().evaluateSize()); - assertFalse(db.getWriteBuffer().getCacheEntry(wrap("ONE")).isPresent()); - assertFalse(db.getWriteBuffer().getCacheEntry(wrap("TWO")).isPresent()); - assertFalse(db.getWriteBuffer().getCacheEntry(wrap("THREE")).isPresent()); - assertFalse(db.getWriteBuffer().getCacheEntry(wrap("FOUR")).isPresent()); + assertThat(4).isEqualTo(engineSource.source.size()); + assertThat(0L).isEqualTo(db.getWriteBuffer().evaluateSize()); + assertThat(db.getWriteBuffer().getCacheEntry(wrap("ONE"))).isNotPresent(); + assertThat(db.getWriteBuffer().getCacheEntry(wrap("TWO"))).isNotPresent(); + assertThat(db.getWriteBuffer().getCacheEntry(wrap("THREE"))).isNotPresent(); + assertThat(db.getWriteBuffer().getCacheEntry(wrap("FOUR"))).isNotPresent(); storage.put(wrap("FIVE"), Bytes32.random(rnd)); storage.put(wrap("SIX"), Bytes32.random(rnd)); - assertEquals( - 4 * MemSizeEvaluators.BytesValueEvaluator.apply(Bytes32.random(rnd)), - db.getWriteBuffer().evaluateSize()); + assertThat(4 * MemSizeEvaluators.BytesValueEvaluator.apply(Bytes32.random(rnd))) + .isEqualTo(db.getWriteBuffer().evaluateSize()); storage.remove(wrap("FIVE")); - assertEquals( - 2 * MemSizeEvaluators.BytesValueEvaluator.apply(Bytes32.random(rnd)), - db.getWriteBuffer().evaluateSize()); + assertThat(2 * MemSizeEvaluators.BytesValueEvaluator.apply(Bytes32.random(rnd))) + .isEqualTo(db.getWriteBuffer().evaluateSize()); } @Test - @Ignore - public void checkWithConcurrentAccessTake1() throws InterruptedException { + @Disabled + void checkWithConcurrentAccessTake1() throws InterruptedException { TestStorageSource engineSource = new TestStorageSource(); EngineDrivenDatabase db = EngineDrivenDatabase.createWithInstantFlusher(engineSource); @@ -204,12 +203,12 @@ public void checkWithConcurrentAccessTake1() throws InterruptedException { Set expectedValues = new HashSet<>(writtenToOne.values()); expectedValues.addAll(writtenToTwo.values()); - assertEquals(expectedValues, sourceValues); + assertThat(expectedValues).isEqualTo(sourceValues); } @Test - @Ignore - public void checkWithConcurrentAccessTake2() throws InterruptedException { + @Disabled + void checkWithConcurrentAccessTake2() throws InterruptedException { TestStorageSource engineSource = new TestStorageSource(); EngineDrivenDatabase db = EngineDrivenDatabase.createWithInstantFlusher(engineSource); diff --git a/db/core/src/test/java/org/ethereum/beacon/db/InMemoryDatabaseTest.java b/db/core/src/test/java/org/ethereum/beacon/db/InMemoryDatabaseTest.java new file mode 100644 index 000000000..c217df6a5 --- /dev/null +++ b/db/core/src/test/java/org/ethereum/beacon/db/InMemoryDatabaseTest.java @@ -0,0 +1,59 @@ +package org.ethereum.beacon.db; + +import org.ethereum.beacon.db.source.DataSource; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; +import tech.pegasys.artemis.util.bytes.BytesValue; + +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; + +class InMemoryDatabaseTest { + + @ParameterizedTest + @ValueSource(strings = {"TEST_KEY"}) + void testGetBackingDataSource(String param) { + final InMemoryDatabase database = new InMemoryDatabase(); + final DataSource dataSource = database.getBackingDataSource(); + final BytesValue key = BytesValue.wrap(param.getBytes()); + final BytesValue value = BytesValue.EMPTY; + dataSource.put(key, value); + + final Optional expected = dataSource.get(key); + assertThat(expected).isPresent().hasValue(value); + assertThat(database.getBackingDataSource().get(key)).isPresent().hasValue(expected.get()); + + dataSource.remove(key); + assertThat(dataSource.get(key)).isNotPresent(); + assertThat(database.getBackingDataSource().get(key)).isNotPresent(); + } + + @Test + void testPutGetRemove_DifferentDatabase() { + final InMemoryDatabase first = new InMemoryDatabase(); + final InMemoryDatabase second = new InMemoryDatabase(); + + final BytesValue key = BytesValue.of(123); + final BytesValue value = BytesValue.of(1, 2, 3); + + final DataSource firstDS = first.getBackingDataSource(); + final DataSource secondDS = second.getBackingDataSource(); + + firstDS.put(key, value); + assertThat(first.getBackingDataSource().get(key)).isPresent().hasValue(value); + assertThat(secondDS.get(key)).isNotPresent(); + + firstDS.put(key, value); + secondDS.put(key, value); + assertThat(first.getBackingDataSource().get(key)).isPresent().hasValue(value); + assertThat(second.getBackingDataSource().get(key)).isPresent().hasValue(value); + + firstDS.remove(key); + assertThat(first.getBackingDataSource().get(key)).isNotPresent(); + assertThat(second.getBackingDataSource().get(key)).isPresent().hasValue(value); + } + + //TODO: commit and close methods do nothing, is it ok? +} diff --git a/db/core/src/test/java/org/ethereum/beacon/db/RocksDbDrivenDatabaseTest.java b/db/core/src/test/java/org/ethereum/beacon/db/RocksDbDrivenDatabaseTest.java index 6cdccc574..cb4c196f4 100644 --- a/db/core/src/test/java/org/ethereum/beacon/db/RocksDbDrivenDatabaseTest.java +++ b/db/core/src/test/java/org/ethereum/beacon/db/RocksDbDrivenDatabaseTest.java @@ -1,26 +1,26 @@ package org.ethereum.beacon.db; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; - -import java.io.IOException; import org.ethereum.beacon.db.source.DataSource; import org.ethereum.beacon.db.util.FileUtil; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import tech.pegasys.artemis.util.bytes.BytesValue; -public class RocksDbDrivenDatabaseTest { +import java.io.IOException; + +import static org.assertj.core.api.Assertions.assertThat; + +class RocksDbDrivenDatabaseTest { - @After - @Before - public void cleanUp() throws IOException { + @AfterEach + @BeforeEach + void cleanUp() throws IOException { FileUtil.removeRecursively("test-db"); } @Test - public void basicOperations() { + void basicOperations() { Database db = Database.rocksDB("test-db", -1); DataSource uno = db.createStorage("uno"); @@ -33,42 +33,42 @@ public void basicOperations() { dos.put(wrap("FOUR"), wrap("DOS_FOURTH")); db.commit(); - assertEquals(wrap("FIRST"), uno.get(wrap("ONE")).get()); - assertEquals(wrap("SECOND"), uno.get(wrap("TWO")).get()); - assertEquals(wrap("SECOND"), dos.get(wrap("TWO")).get()); - assertEquals(wrap("UNO_THIRD"), uno.get(wrap("THREE")).get()); - assertEquals(wrap("DOS_FOURTH"), dos.get(wrap("FOUR")).get()); - assertFalse(uno.get(wrap("FOUR")).isPresent()); - assertFalse(dos.get(wrap("ONE")).isPresent()); - assertFalse(dos.get(wrap("THREE")).isPresent()); - assertFalse(uno.get(wrap("FOUR")).isPresent()); + assertThat(wrap("FIRST")).isEqualTo(uno.get(wrap("ONE")).get()); + assertThat(wrap("SECOND")).isEqualTo(uno.get(wrap("TWO")).get()); + assertThat(wrap("SECOND")).isEqualTo(dos.get(wrap("TWO")).get()); + assertThat(wrap("UNO_THIRD")).isEqualTo(uno.get(wrap("THREE")).get()); + assertThat(wrap("DOS_FOURTH")).isEqualTo(dos.get(wrap("FOUR")).get()); + assertThat(uno.get(wrap("FOUR"))).isNotPresent(); + assertThat(dos.get(wrap("ONE"))).isNotPresent(); + assertThat(dos.get(wrap("THREE"))).isNotPresent(); + assertThat(uno.get(wrap("FOUR"))).isNotPresent(); uno.remove(wrap("TWO")); dos.put(wrap("THREE"), wrap("DOS_THIRD")); - assertFalse(uno.get(wrap("TWO")).isPresent()); - assertEquals(wrap("DOS_THIRD"), dos.get(wrap("THREE")).get()); - assertEquals(wrap("UNO_THIRD"), uno.get(wrap("THREE")).get()); + assertThat(uno.get(wrap("TWO"))).isNotPresent(); + assertThat(wrap("DOS_THIRD")).isEqualTo(dos.get(wrap("THREE")).get()); + assertThat(wrap("UNO_THIRD")).isEqualTo(uno.get(wrap("THREE")).get()); db.commit(); - assertFalse(uno.get(wrap("TWO")).isPresent()); - assertEquals(wrap("DOS_THIRD"), dos.get(wrap("THREE")).get()); - assertEquals(wrap("UNO_THIRD"), uno.get(wrap("THREE")).get()); + assertThat(uno.get(wrap("TWO"))).isNotPresent(); + assertThat(wrap("DOS_THIRD")).isEqualTo(dos.get(wrap("THREE")).get()); + assertThat(wrap("UNO_THIRD")).isEqualTo(uno.get(wrap("THREE")).get()); dos.remove(wrap("FOUR")); uno.put(wrap("FOUR"), wrap("UNO_FOURTH")); - assertEquals(wrap("UNO_FOURTH"), uno.get(wrap("FOUR")).get()); - assertFalse(dos.get(wrap("FOUR")).isPresent()); + assertThat(wrap("UNO_FOURTH")).isEqualTo(uno.get(wrap("FOUR")).get()); + assertThat(dos.get(wrap("FOUR"))).isNotPresent(); db.commit(); - assertEquals(wrap("UNO_FOURTH"), uno.get(wrap("FOUR")).get()); - assertFalse(dos.get(wrap("FOUR")).isPresent()); + assertThat(wrap("UNO_FOURTH")).isEqualTo(uno.get(wrap("FOUR")).get()); + assertThat(dos.get(wrap("FOUR"))).isNotPresent(); db.close(); } @Test - public void reopenWithoutFlush() { + void reopenWithoutFlush() { Database db = Database.rocksDB("test-db", -1); DataSource storage = db.createStorage("uno"); @@ -81,9 +81,9 @@ public void reopenWithoutFlush() { storage = db.createStorage("uno"); - assertEquals(wrap("FIRST"), storage.get(wrap("ONE")).get()); - assertEquals(wrap("SECOND"), storage.get(wrap("TWO")).get()); - assertEquals(wrap("THIRD"), storage.get(wrap("THREE")).get()); + assertThat(wrap("FIRST")).isEqualTo(storage.get(wrap("ONE")).get()); + assertThat(wrap("SECOND")).isEqualTo(storage.get(wrap("TWO")).get()); + assertThat(wrap("THIRD")).isEqualTo(storage.get(wrap("THREE")).get()); db.close(); } diff --git a/db/core/src/test/java/org/ethereum/beacon/db/XorKeyDatabaseTest.java b/db/core/src/test/java/org/ethereum/beacon/db/XorKeyDatabaseTest.java new file mode 100644 index 000000000..431e519e5 --- /dev/null +++ b/db/core/src/test/java/org/ethereum/beacon/db/XorKeyDatabaseTest.java @@ -0,0 +1,101 @@ +package org.ethereum.beacon.db; + +import org.ethereum.beacon.db.source.DataSource; +import org.ethereum.beacon.db.source.impl.HashMapDataSource; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import tech.pegasys.artemis.util.bytes.BytesValue; +import tech.pegasys.artemis.util.bytes.MutableBytesValue; + +import java.util.function.Function; + +import static org.assertj.core.api.Assertions.assertThat; + +class XorKeyDatabaseTest { + + private XorKeyDatabase db; + + @BeforeEach + void setUp() { + final HashMapDataSource mapds = new HashMapDataSource<>(); + db = new XorKeyDatabase(mapds, Function.identity()) { + @Override + public void commit() { + } + + @Override + public void close() { + } + }; + assertThat(db.getBackingDataSource()).isEqualTo(mapds); + } + + @Test + void testCreateStorage_EmptyStorage() { + final DataSource storage1 = db.createStorage("Storage1"); + final BytesValue key = BytesValue.of(1, 2, 3); + final BytesValue value = BytesValue.of(1, 4); + storage1.put(key, value); + assertThat(storage1.get(key)).isPresent().hasValue(value); + } + + @Test + void testCreateStorage() { + final DataSource storage0 = db.createStorage("Storage1"); + final BytesValue key = BytesValue.of(1, 2, 3); + final BytesValue value = BytesValue.of(1, 4); + storage0.put(key, value); + final DataSource storage1 = db.createStorage("Storage1"); + assertThat(storage1.get(key)).isPresent().hasValue(value); + } + + @Test + void testCreateStorage_1() { + final DataSource storage0 = db.createStorage("Storage1"); + final BytesValue key = BytesValue.of(1, 2, 3); + final BytesValue storage0_value = BytesValue.of(1, 4); + storage0.put(key, storage0_value); + + final DataSource storage1 = db.createStorage("Storage2"); + assertThat(storage1.get(key)).isNotPresent(); + + final BytesValue storage1_value = BytesValue.of(1, 4, 5); + storage1.put(key, storage1_value); + assertThat(storage1.get(key)).isPresent().hasValue(storage1_value); + assertThat(storage0.get(key)).isPresent().hasValue(storage0_value); + } + + @Test + void testSourceNameHasher() { + final HashMapDataSource mapds = new HashMapDataSource<>(); + db = new XorKeyDatabase(mapds, f -> BytesValue.wrap(f, BytesValue.of(99))) { + @Override + public void commit() { + } + + @Override + public void close() { + } + }; + assertThat(db.getBackingDataSource()).isEqualTo(mapds); + + final DataSource storage = db.createStorage("test-db"); + final BytesValue key = BytesValue.of(123); + final BytesValue value = BytesValue.of(1, 2, 3); + storage.put(key, value); + + assertThat(db.getBackingDataSource().get(key)).isNotPresent(); + } + + private BytesValue xorLongest(BytesValue v1, BytesValue v2) { + BytesValue longVal = v1.size() >= v2.size() ? v1 : v2; + BytesValue shortVal = v1.size() < v2.size() ? v1 : v2; + MutableBytesValue ret = longVal.mutableCopy(); + int longLen = longVal.size(); + int shortLen = shortVal.size(); + for (int i = 0; i < shortLen; i++) { + ret.set(longLen - i - 1, (byte) (ret.get(longLen - i - 1) ^ shortVal.get(shortLen - i - 1))); + } + return ret; + } +} diff --git a/db/core/src/test/java/org/ethereum/beacon/db/flush/BufferSizeObserverTest.java b/db/core/src/test/java/org/ethereum/beacon/db/flush/BufferSizeObserverTest.java new file mode 100644 index 000000000..04fe26621 --- /dev/null +++ b/db/core/src/test/java/org/ethereum/beacon/db/flush/BufferSizeObserverTest.java @@ -0,0 +1,152 @@ +package org.ethereum.beacon.db.flush; + +import org.ethereum.beacon.db.source.WriteBuffer; +import org.ethereum.beacon.db.source.impl.HashMapDataSource; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + + +//TODO: need more tests +class BufferSizeObserverTest { + + private WriteBuffer buffer; + private WriteBuffer commitTrack; + private BufferSizeObserver observer; + + private boolean commitTrackDoFlush; + private boolean bufferFlushed; + + @BeforeEach + void setUp() { + commitTrackDoFlush = false; + bufferFlushed = false; + + final HashMapDataSource upstream = new HashMapDataSource() { + @Override + public void flush() { + bufferFlushed = true; + super.flush(); + } + }; + buffer = new WriteBuffer<>(upstream, false); + assertThat(buffer.getUpstream()).isEqualTo(upstream); + assertThat(buffer.evaluateSize()).isEqualTo(0); + + commitTrack = new WriteBuffer(upstream, false) { + @Override + public void doFlush() { + commitTrackDoFlush = true; + super.doFlush(); + } + }; + assertThat(commitTrack.getUpstream()).isEqualTo(upstream); + assertThat(commitTrack.evaluateSize()).isEqualTo(0); + + observer = new BufferSizeObserver(buffer, commitTrack, Long.MAX_VALUE); + } + + @ParameterizedTest + @MethodSource("nullArgumentsProvider") + void testInvalidCreation(WriteBuffer buffer, WriteBuffer commitTrack, long bufferLimitSize) { + assertThatThrownBy(() -> new BufferSizeObserver(buffer, commitTrack, bufferLimitSize)).isInstanceOf(NullPointerException.class); + } + + private static Stream nullArgumentsProvider() { + return Stream.of( + Arguments.of(null, null, Long.MAX_VALUE), + Arguments.of(null, new WriteBuffer(new HashMapDataSource<>(), true), Long.MAX_VALUE), + Arguments.of(new WriteBuffer(new HashMapDataSource<>(), true), null, Long.MAX_VALUE) + ); + } + + @ParameterizedTest + @MethodSource("nullKeyValueArgumentsProvider") + void testPutNullKeyValue(String key, String value) { + assertThatThrownBy(() -> buffer.put(key, value)).isInstanceOf(NullPointerException.class); + } + + private static Stream nullKeyValueArgumentsProvider() { + return Stream.of( + Arguments.of(null, null), + Arguments.of("not_null", null), + Arguments.of(null, "not_null") + ); + } + + @Test + void testCreate() { + + String TEST_KEY_0 = "TEST_KEY_0"; + String TEST_VALUE_0 = "TEST_VALUE_0"; + String TEST_KEY_1 = "TEST_KEY_1"; + String TEST_VALUE_1 = "TEST_VALUE_1"; + + buffer = new WriteBuffer<>(new HashMapDataSource<>(), false); + observer = BufferSizeObserver.create(buffer, Long.MAX_VALUE); + buffer.put(TEST_KEY_0, TEST_VALUE_0); + + + assertThat(buffer.get(TEST_KEY_0)).isPresent().hasValue(TEST_VALUE_0); + assertThat(buffer.getCacheEntry(TEST_KEY_0)).isPresent(); + + observer.flush(); + assertThat(buffer.getCacheEntry(TEST_KEY_0)).isNotPresent(); + assertThat(buffer.getUpstream().get(TEST_KEY_0)).isPresent().hasValue(TEST_VALUE_0); + + buffer.put(TEST_KEY_1, TEST_VALUE_1); + + assertThat(buffer.getUpstream().get(TEST_KEY_1)).isNotPresent(); + assertThat(buffer.getCacheEntry(TEST_KEY_1)).isPresent(); + + observer.commit(); + assertThat(buffer.getUpstream().get(TEST_KEY_1)).isPresent().hasValue(TEST_VALUE_1); + } + + @ParameterizedTest + @CsvSource({ "test_key, test_value"}) + void testFlush(String key, String value) { + buffer.put(key, value); + assertThat(buffer.get(key)).isPresent().hasValue(value); + + observer.flush(); + assertThat(buffer.getUpstream().get(key)).isPresent().hasValue(value); + + buffer.getUpstream().remove(key); + assertThat(buffer.get(key)).isNotPresent(); + assertThat(buffer.getUpstream().get(key)).isNotPresent(); + + } + + @ParameterizedTest + @CsvSource({ "test_key, test_value"}) + void testCommitWithoutBufferFlushing(String key, String value) { + commitTrack.put(key, value); + assertThat(commitTrack.get(key)).isPresent().hasValue(value); + assertThat(commitTrack.getUpstream().get(key)).isNotPresent(); + assertThat(buffer.getUpstream().get(key)).isNotPresent(); + assertThat(commitTrackDoFlush).isFalse(); + assertThat(bufferFlushed).isFalse(); + + observer.commit(); + assertThat(commitTrackDoFlush).isTrue(); + assertThat(bufferFlushed).isFalse(); + assertThat(commitTrack.get(key)).isPresent().hasValue(value); + assertThat(commitTrack.getUpstream().get(key)).isPresent().hasValue(value); + assertThat(buffer.get(key)).isPresent().hasValue(value); + assertThat(buffer.getUpstream().get(key)).isPresent().hasValue(value); + + commitTrack.getUpstream().remove(key); + assertThat(commitTrack.get(key)).isNotPresent(); + assertThat(commitTrack.getUpstream().get(key)).isNotPresent(); + assertThat(buffer.getUpstream().get(key)).isNotPresent(); + } +} diff --git a/db/core/src/test/java/org/ethereum/beacon/db/flush/DatabaseFlusherTest.java b/db/core/src/test/java/org/ethereum/beacon/db/flush/DatabaseFlusherTest.java new file mode 100644 index 000000000..7fd7690b0 --- /dev/null +++ b/db/core/src/test/java/org/ethereum/beacon/db/flush/DatabaseFlusherTest.java @@ -0,0 +1,45 @@ +package org.ethereum.beacon.db.flush; + +import org.junit.jupiter.api.*; + +import static org.assertj.core.api.Assertions.assertThat; + +class DatabaseFlusherTest { + + private DatabaseFlusher databaseFlusher; + + private boolean flushed; + private boolean committed; + + @BeforeEach + void setUp() { + flushed = false; + committed = false; + + databaseFlusher = new DatabaseFlusher() { + @Override + public void flush() { + flushed = true; + } + + @Override + public void commit() { + committed = true; + } + }; + } + + @Test + void flush() { + assertThat(flushed).isFalse(); + databaseFlusher.flush(); + assertThat(flushed).isTrue(); + } + + @Test + void commit() { + assertThat(committed).isFalse(); + databaseFlusher.commit(); + assertThat(committed).isTrue(); + } +} diff --git a/db/core/src/test/java/org/ethereum/beacon/db/flush/InstantFlusherTest.java b/db/core/src/test/java/org/ethereum/beacon/db/flush/InstantFlusherTest.java new file mode 100644 index 000000000..e846eb09d --- /dev/null +++ b/db/core/src/test/java/org/ethereum/beacon/db/flush/InstantFlusherTest.java @@ -0,0 +1,90 @@ +package org.ethereum.beacon.db.flush; + +import org.ethereum.beacon.db.source.WriteBuffer; +import org.ethereum.beacon.db.source.impl.HashMapDataSource; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class InstantFlusherTest { + + private boolean doFlush; + private boolean datasourceFlush; + private boolean instantFlushed; + + @BeforeEach + void setUp() { + doFlush = false; + datasourceFlush = false; + instantFlushed = false; + } + + @Test + @Tag("FIX") + void testInvalidInstanceCreation() { + assertThatThrownBy(() -> new InstantFlusher(null)).isInstanceOf(NullPointerException.class); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void flush(boolean upstreamFlush) { + final InstantFlusher instantFlusher = new InstantFlusher(new WriteBuffer(new HashMapDataSource() { + @Override + public void flush() { + datasourceFlush = true; + } + }, upstreamFlush) { + @Override + public void doFlush() { + doFlush = true; + } + }) { + @Override + public void flush() { + instantFlushed = true; + } + }; + + assertThat(doFlush).isFalse(); + assertThat(datasourceFlush).isFalse(); + assertThat(instantFlushed).isFalse(); + instantFlusher.flush(); + assertThat(doFlush).isFalse(); + assertThat(datasourceFlush).isFalse(); + assertThat(instantFlushed).isTrue(); + } + + @ParameterizedTest + @ValueSource(booleans = {true, false}) + void commit(boolean upstreamFlush) { + final InstantFlusher instantFlusher = new InstantFlusher(new WriteBuffer(new HashMapDataSource() { + @Override + public void flush() { + datasourceFlush = true; + } + }, upstreamFlush) { + @Override + public void doFlush() { + doFlush = true; + } + }) { + @Override + public void flush() { + instantFlushed = true; + } + }; + + assertThat(doFlush).isFalse(); + assertThat(datasourceFlush).isFalse(); + assertThat(instantFlushed).isFalse(); + instantFlusher.commit(); + assertThat(doFlush).isTrue(); + assertThat(datasourceFlush).isEqualTo(upstreamFlush); + assertThat(instantFlushed).isFalse(); + } +} diff --git a/db/core/src/test/java/org/ethereum/beacon/db/rocksdb/RocksDbSourceTest.java b/db/core/src/test/java/org/ethereum/beacon/db/rocksdb/RocksDbSourceTest.java index ce9a837f5..2d662dc98 100644 --- a/db/core/src/test/java/org/ethereum/beacon/db/rocksdb/RocksDbSourceTest.java +++ b/db/core/src/test/java/org/ethereum/beacon/db/rocksdb/RocksDbSourceTest.java @@ -1,35 +1,35 @@ package org.ethereum.beacon.db.rocksdb; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; +import org.ethereum.beacon.db.util.FileUtil; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import tech.pegasys.artemis.util.bytes.BytesValue; import java.io.IOException; import java.nio.file.Paths; import java.util.HashMap; import java.util.Map; -import org.ethereum.beacon.db.util.FileUtil; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import tech.pegasys.artemis.util.bytes.BytesValue; -public class RocksDbSourceTest { +import static org.assertj.core.api.Assertions.assertThat; + +class RocksDbSourceTest { - @After - @Before - public void cleanUp() throws IOException { + @AfterEach + @BeforeEach + void cleanUp() throws IOException { FileUtil.removeRecursively("test-db"); } @Test - public void basicOperations() { + void basicOperations() { RocksDbSource rocksDb = new RocksDbSource(Paths.get("test-db")); rocksDb.open(); rocksDb.put(wrap("ONE"), wrap("FIRST")); - assertFalse(rocksDb.get(wrap("TWO")).isPresent()); - assertEquals(wrap("FIRST"), rocksDb.get(wrap("ONE")).get()); + assertThat(rocksDb.get(wrap("TWO"))).isNotPresent(); + assertThat(wrap("FIRST")).isEqualTo(rocksDb.get(wrap("ONE")).get()); Map batch = new HashMap<>(); batch.put(wrap("ONE"), null); @@ -39,22 +39,22 @@ public void basicOperations() { rocksDb.batchUpdate(batch); - assertFalse(rocksDb.get(wrap("ONE")).isPresent()); - assertEquals(wrap("SECOND"), rocksDb.get(wrap("TWO")).get()); - assertEquals(wrap("THIRD"), rocksDb.get(wrap("THREE")).get()); - assertEquals(wrap("FOURTH"), rocksDb.get(wrap("FOUR")).get()); + assertThat(rocksDb.get(wrap("ONE"))).isNotPresent(); + assertThat(wrap("SECOND")).isEqualTo(rocksDb.get(wrap("TWO")).get()); + assertThat(wrap("THIRD")).isEqualTo(rocksDb.get(wrap("THREE")).get()); + assertThat(wrap("FOURTH")).isEqualTo(rocksDb.get(wrap("FOUR")).get()); rocksDb.remove(wrap("THREE")); - assertFalse(rocksDb.get(wrap("THREE")).isPresent()); + assertThat(rocksDb.get(wrap("THREE"))).isNotPresent(); rocksDb.close(); rocksDb.open(); - assertFalse(rocksDb.get(wrap("ONE")).isPresent()); - assertEquals(wrap("SECOND"), rocksDb.get(wrap("TWO")).get()); - assertFalse(rocksDb.get(wrap("THREE")).isPresent()); - assertEquals(wrap("FOURTH"), rocksDb.get(wrap("FOUR")).get()); - assertFalse(rocksDb.get(wrap("FIVE")).isPresent()); + assertThat(rocksDb.get(wrap("ONE"))).isNotPresent(); + assertThat(wrap("SECOND")).isEqualTo(rocksDb.get(wrap("TWO")).get()); + assertThat(rocksDb.get(wrap("THREE"))).isNotPresent(); + assertThat(wrap("FOURTH")).isEqualTo(rocksDb.get(wrap("FOUR")).get()); + assertThat(rocksDb.get(wrap("FIVE"))).isNotPresent(); rocksDb.close(); } diff --git a/db/core/src/test/java/org/ethereum/beacon/db/source/AbstractLinkedDataSourceTest.java b/db/core/src/test/java/org/ethereum/beacon/db/source/AbstractLinkedDataSourceTest.java new file mode 100644 index 000000000..e92455e06 --- /dev/null +++ b/db/core/src/test/java/org/ethereum/beacon/db/source/AbstractLinkedDataSourceTest.java @@ -0,0 +1,123 @@ +package org.ethereum.beacon.db.source; + +import org.ethereum.beacon.db.source.impl.HashMapDataSource; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import javax.annotation.Nonnull; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class AbstractLinkedDataSourceTest { + + private final String TEST_KEY = "test_key"; + private final String TEST_VALUE = "test_value"; + private final String TEST_FLUSH = "flush"; + private final String TEST_DO_FLUSH = "do_flush"; + + private AbstractLinkedDataSource dataSource; + + @BeforeEach + void setUp() { + final HashMapDataSource upstream = new HashMapDataSource<>(); + dataSource = new AbstractLinkedDataSource(upstream) { + public Optional get(@Nonnull String key) { + return getUpstream().get(key); + } + + public void put(@Nonnull String key, @Nonnull String value) { + getUpstream().put(key, value); + } + + public void remove(@Nonnull String key) { + getUpstream().remove(key); + } + }; + + assertThat(dataSource.getUpstream()).isEqualTo(upstream); + } + + @Test + void testInvalidSourceCreation() { + assertThatThrownBy(() -> new AbstractLinkedDataSource(null) { + public Optional get(@Nonnull Object key) { + return Optional.empty(); + } + + public void put(@Nonnull Object key, @Nonnull Object value) { + + } + + public void remove(@Nonnull Object key) { + + } + }).isInstanceOf(NullPointerException.class); + } + + @Test + void testGetPutRemoveUpstreamFlush() { + final HashMapDataSource upstream = new HashMapDataSource() { + public void flush() { + getStore().put(TEST_FLUSH, TEST_FLUSH); + } + }; + dataSource = new AbstractLinkedDataSource(upstream, true) { + public Optional get(@Nonnull String key) { + return getUpstream().get(key); + } + + public void put(@Nonnull String key, @Nonnull String value) { + getUpstream().put(key, value); + } + + public void remove(@Nonnull String key) { + getUpstream().remove(key); + } + + protected void doFlush() { + getUpstream().put(TEST_DO_FLUSH, TEST_DO_FLUSH); + } + }; + + assertThat(dataSource.getUpstream()).isEqualTo(upstream); + + dataSource.put(TEST_KEY, TEST_VALUE); + assertThat(dataSource.get(TEST_KEY)).isPresent().hasValue(TEST_VALUE); + + dataSource.remove(TEST_KEY); + assertThat(dataSource.get(TEST_KEY)).isNotPresent(); + + dataSource.flush(); + assertThat(dataSource.get(TEST_FLUSH)).isPresent().hasValue(TEST_FLUSH); + assertThat(dataSource.get(TEST_DO_FLUSH)).isPresent().hasValue(TEST_DO_FLUSH); + } + + @Test + void testFlushIsFalse() { + dataSource = new AbstractLinkedDataSource(new HashMapDataSource() { + public void flush() { + getStore().put(TEST_FLUSH, TEST_FLUSH); + } + }) { + public Optional get(@Nonnull String key) { + return getUpstream().get(key); + } + + public void put(@Nonnull String key, @Nonnull String value) { + } + + public void remove(@Nonnull String key) { + } + + protected void doFlush() { + getUpstream().put(TEST_DO_FLUSH, TEST_DO_FLUSH); + } + }; + + dataSource.flush(); + assertThat(dataSource.get(TEST_FLUSH)).isNotPresent(); + assertThat(dataSource.get(TEST_DO_FLUSH)).isPresent().hasValue(TEST_DO_FLUSH); + } +} diff --git a/db/core/src/test/java/org/ethereum/beacon/db/source/BatchUpdateDataSourceTest.java b/db/core/src/test/java/org/ethereum/beacon/db/source/BatchUpdateDataSourceTest.java new file mode 100644 index 000000000..b9b0f8738 --- /dev/null +++ b/db/core/src/test/java/org/ethereum/beacon/db/source/BatchUpdateDataSourceTest.java @@ -0,0 +1,102 @@ +package org.ethereum.beacon.db.source; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import javax.annotation.Nonnull; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class BatchUpdateDataSourceTest { + + private BatchUpdateDataSource dataSource; + + @BeforeEach + void setUp() + { + final HashMap store = new HashMap<>(); + dataSource = new BatchUpdateDataSource() { + @Override + public void batchUpdate(Map updates) { + updates.forEach(this::put); + } + + @Override + public Optional get(@Nonnull String key) { + Objects.requireNonNull(key); + return Optional.ofNullable(store.get(key)); + } + + @Override + public void put(@Nonnull String key, @Nonnull String value) { + Objects.requireNonNull(key); + Objects.requireNonNull(value); + store.put(key, value); + } + + @Override + public void remove(@Nonnull String key) { + Objects.requireNonNull(key); + store.remove(key); + } + + @Override + public void flush() { + store.put("test_flush", "test_flush"); + } + }; + + assertThat(dataSource.get("something")).isNotPresent(); + } + + @Test + void testBatchUpdate() { + final Map updates = new HashMap<>(); + updates.put("test_key_1", "test_value_1"); + updates.put("test_key_2", "test_value_2"); + updates.put("test_key_3", "test_value_3"); + updates.put("test_key_4", "test_value_4"); + updates.put("test_key_5", "test_value_5"); + dataSource.batchUpdate(updates); + assertThat(dataSource.get("test_key_1")).isPresent().hasValue("test_value_1"); + assertThat(dataSource.get("test_key_2")).isPresent().hasValue("test_value_2"); + assertThat(dataSource.get("test_key_3")).isPresent().hasValue("test_value_3"); + assertThat(dataSource.get("test_key_4")).isPresent().hasValue("test_value_4"); + assertThat(dataSource.get("test_key_5")).isPresent().hasValue("test_value_5"); + } + + @Test + void testFlush() { + dataSource.flush(); + assertThat(dataSource.get("test_flush")).isPresent().hasValue("test_flush"); + } + + @Test + void testPutGetRemove() { + assertThat(dataSource.get("test_key_0")).isNotPresent(); + dataSource.put("test_key_0", "test_value_0"); + assertThat(dataSource.get("test_key_0")).isPresent().hasValue("test_value_0"); + dataSource.remove("test_key_0"); + assertThat(dataSource.get("test_key_0")).isNotPresent(); + } + + @Test + void testNullValues() { + assertThatThrownBy(() -> dataSource.put(null, null)).isInstanceOf(NullPointerException.class); + assertThatThrownBy(() -> dataSource.put("not_null", null)).isInstanceOf(NullPointerException.class); + assertThatThrownBy(() -> dataSource.put(null, "not_null")).isInstanceOf(NullPointerException.class); + assertThatThrownBy(() -> dataSource.get(null)).isInstanceOf(NullPointerException.class); + assertThatThrownBy(() -> dataSource.remove(null)).isInstanceOf(NullPointerException.class); + + final HashMap updates = new HashMap(); + updates.put(null, null); + updates.put(null, "test_value_0"); + updates.put("test_value_0", null); + assertThatThrownBy(() -> dataSource.batchUpdate(updates)).isInstanceOf(NullPointerException.class); + } +} diff --git a/db/core/src/test/java/org/ethereum/beacon/db/source/CacheDataSourceTest.java b/db/core/src/test/java/org/ethereum/beacon/db/source/CacheDataSourceTest.java new file mode 100644 index 000000000..b91a5e516 --- /dev/null +++ b/db/core/src/test/java/org/ethereum/beacon/db/source/CacheDataSourceTest.java @@ -0,0 +1,118 @@ +package org.ethereum.beacon.db.source; + +import org.ethereum.beacon.db.source.impl.HashMapDataSource; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import javax.annotation.Nonnull; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.function.Function; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class CacheDataSourceTest { + + private long size; + private CacheDataSource dataSource; + + @BeforeEach + void setUp() { + final Function keyEvaluator = getKeyValueEvaluator(); + final Function valueEvaluator = keyEvaluator; + + final Map store = new HashMap<>(); + final HashMapDataSource upStream = new HashMapDataSource<>(); + dataSource = new CacheDataSource() { + @Override + public Optional> getCacheEntry(@Nonnull String key) { + Objects.requireNonNull(key); + String entry = store.get(key); + return Optional.ofNullable(entry == null ? null : Optional.ofNullable(entry)); + } + + @Override + public long evaluateSize() { + return size; + } + + @Nonnull + @Override + public DataSource getUpstream() { + return upStream; + } + + @Override + public Optional get(@Nonnull String key) { + Objects.requireNonNull(key); + return Optional.ofNullable(store.get(key)); + } + + @Override + public void put(@Nonnull String key, @Nonnull String value) { + Objects.requireNonNull(key); + Objects.requireNonNull(value); + store.put(key, value); + size += keyEvaluator.apply(key); + size += valueEvaluator.apply(value); + + } + + @Override + public void remove(@Nonnull String key) { + Objects.requireNonNull(key); + store.remove(key); + size -= keyEvaluator.apply(key); + size -= valueEvaluator.apply(key); + } + + @Override + public void flush() { + store.forEach(upStream::put); + size = 0; + store.clear(); + } + }; + + assertThat(dataSource.evaluateSize()).isEqualTo(size); + } + + private Function getKeyValueEvaluator() { + return s -> 1L; + } + + @Test + void testGetPutRemoveFlushCacheEntrySize(){ + assertThat(dataSource.get("test_key_0")).isNotPresent(); + dataSource.put("test_key_0", "test_value_0"); + assertThat(dataSource.evaluateSize()).isGreaterThan(0); + + dataSource.put("test_key_1", "test_value_1"); + dataSource.put("test_key_2", "test_value_2"); + dataSource.put("test_key_3", "test_value_3"); + assertThat(dataSource.getCacheEntry("test_key_0")).isPresent().hasValue(Optional.ofNullable("test_value_0")); + + dataSource.remove("test_key_0"); + assertThat(dataSource.getCacheEntry("test_key_0")).isNotPresent(); + assertThat(dataSource.getCacheEntry("test_key_1")).isPresent().hasValue(Optional.ofNullable("test_value_1")); + + dataSource.flush(); + assertThat(dataSource.evaluateSize()).isEqualTo(0); + assertThat(dataSource.get("test_key_1")).isNotPresent(); + assertThat(dataSource.getUpstream().get("test_key_1")).isPresent().hasValue("test_value_1"); + + } + + @Test + void testNullValues() { + assertThatThrownBy(() -> dataSource.put(null, null)).isInstanceOf(NullPointerException.class); + assertThatThrownBy(() -> dataSource.put("not_null", null)).isInstanceOf(NullPointerException.class); + assertThatThrownBy(() -> dataSource.put(null, "not_null")).isInstanceOf(NullPointerException.class); + assertThatThrownBy(() -> dataSource.get(null)).isInstanceOf(NullPointerException.class); + assertThatThrownBy(() -> dataSource.remove(null)).isInstanceOf(NullPointerException.class); + assertThatThrownBy(() -> dataSource.getCacheEntry(null)).isInstanceOf(NullPointerException.class); + } +} diff --git a/db/core/src/test/java/org/ethereum/beacon/db/source/CacheSizeEvaluatorTest.java b/db/core/src/test/java/org/ethereum/beacon/db/source/CacheSizeEvaluatorTest.java new file mode 100644 index 000000000..fb0f180da --- /dev/null +++ b/db/core/src/test/java/org/ethereum/beacon/db/source/CacheSizeEvaluatorTest.java @@ -0,0 +1,135 @@ +package org.ethereum.beacon.db.source; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.function.Function; + +import static org.assertj.core.api.Assertions.assertThat; + +class CacheSizeEvaluatorTest { + + private static final int emptySize = 0; + + private long size; + private CacheSizeEvaluator cacheSizeEvaluator; + + @BeforeEach + void setUp() { + final Function keyEvaluator = getKeyValueEvaluator(); + cacheSizeEvaluator = new CacheSizeEvaluator() { + @Override + public long getEvaluatedSize() { + return size; + } + + @Override + public void reset() { + size = 0; + } + + @Override + public void added(String key, String value) { + size += keyEvaluator.apply(key); + } + + @Override + public void removed(String key, String value) { + size -= keyEvaluator.apply(key); + } + }; + assertThat(cacheSizeEvaluator.getEvaluatedSize()).isEqualTo(size); + } + + private Function getKeyValueEvaluator() { + return s -> 1L; + } + + @Test + void testAddedRemoveResetSize(){ + cacheSizeEvaluator.added("key_0", "value_0"); + assertThat(cacheSizeEvaluator.getEvaluatedSize()).isGreaterThan(emptySize); + long evaluatedSize = cacheSizeEvaluator.getEvaluatedSize(); + cacheSizeEvaluator.removed("key_0", "value_0"); + assertThat(cacheSizeEvaluator.getEvaluatedSize()).isEqualTo(emptySize); + cacheSizeEvaluator.added("key_1", "value_1"); + cacheSizeEvaluator.added("key_2", "value_2"); + assertThat(cacheSizeEvaluator.getEvaluatedSize()).isGreaterThan(evaluatedSize); + + cacheSizeEvaluator.reset(); + assertThat(cacheSizeEvaluator.getEvaluatedSize()).isEqualTo(emptySize); + } + + @Test + void testNoSizeEvaluator() { + cacheSizeEvaluator = CacheSizeEvaluator.noSizeEvaluator(); + assertThat(cacheSizeEvaluator.getEvaluatedSize()).isEqualTo(emptySize); + cacheSizeEvaluator.added("key_0", "value_0"); + assertThat(cacheSizeEvaluator.getEvaluatedSize()).isEqualTo(emptySize); + size = cacheSizeEvaluator.getEvaluatedSize(); + cacheSizeEvaluator.removed("key_0", "value_0"); + assertThat(cacheSizeEvaluator.getEvaluatedSize()).isEqualTo(emptySize); + cacheSizeEvaluator.added("key_1", "value_1"); + cacheSizeEvaluator.added("key_2", "value_2"); + assertThat(cacheSizeEvaluator.getEvaluatedSize()).isEqualTo(size); + + cacheSizeEvaluator.reset(); + assertThat(cacheSizeEvaluator.getEvaluatedSize()).isEqualTo(emptySize); + } + + @Test + void testKeySizeGetIntance(){ + final Function keyEvaluator = s -> 1L; + cacheSizeEvaluator = CacheSizeEvaluator.getInstance(keyEvaluator); + assertThat(cacheSizeEvaluator.getEvaluatedSize()).isEqualTo(emptySize); + + cacheSizeEvaluator.added("key_0", "value_0"); + assertThat(cacheSizeEvaluator.getEvaluatedSize()).isGreaterThan(emptySize); + size = cacheSizeEvaluator.getEvaluatedSize(); + cacheSizeEvaluator.removed("key_0", "value_0"); + assertThat(cacheSizeEvaluator.getEvaluatedSize()).isEqualTo(emptySize); + cacheSizeEvaluator.added("key_1", "value_1"); + cacheSizeEvaluator.added("key_2", "value_2"); + cacheSizeEvaluator.added("key_3", "value_3"); + assertThat(cacheSizeEvaluator.getEvaluatedSize()).isGreaterThan(size); + + cacheSizeEvaluator.reset(); + assertThat(cacheSizeEvaluator.getEvaluatedSize()).isEqualTo(emptySize); + + } + + @Test + void testKeyValueSizeGetInstance() { + final Function keyEvaluator = s -> 1L; + final Function valueEvaluator = keyEvaluator; + cacheSizeEvaluator = CacheSizeEvaluator.getInstance(keyEvaluator, valueEvaluator); + assertThat(cacheSizeEvaluator.getEvaluatedSize()).isEqualTo(emptySize); + cacheSizeEvaluator.added("key_0", "value_0"); + assertThat(cacheSizeEvaluator.getEvaluatedSize()).isGreaterThan(emptySize); + size = cacheSizeEvaluator.getEvaluatedSize(); + cacheSizeEvaluator.removed("key_0", "value_0"); + assertThat(cacheSizeEvaluator.getEvaluatedSize()).isEqualTo(emptySize); + cacheSizeEvaluator.added("key_1", "value_1"); + cacheSizeEvaluator.added("key_2", "value_2"); + cacheSizeEvaluator.added("key_3", "value_3"); + assertThat(cacheSizeEvaluator.getEvaluatedSize()).isGreaterThan(size); + + cacheSizeEvaluator.reset(); + assertThat(cacheSizeEvaluator.getEvaluatedSize()).isEqualTo(emptySize); + } + + @Test + void testNullValuesCreation() { + assertThat(CacheSizeEvaluator.getInstance(null, null)).isNotNull(); + assertThat(CacheSizeEvaluator.getInstance(null)).isNotNull(); + } + + @Test + void testNullValues() { + cacheSizeEvaluator.added(null, null); + cacheSizeEvaluator.added(null, "not_null"); + cacheSizeEvaluator.added("not_null", null); + assertThat(cacheSizeEvaluator.getEvaluatedSize()).isGreaterThan(emptySize); + } + +} diff --git a/db/core/src/test/java/org/ethereum/beacon/db/source/CodecSourceTest.java b/db/core/src/test/java/org/ethereum/beacon/db/source/CodecSourceTest.java new file mode 100644 index 000000000..fd0b44211 --- /dev/null +++ b/db/core/src/test/java/org/ethereum/beacon/db/source/CodecSourceTest.java @@ -0,0 +1,125 @@ +package org.ethereum.beacon.db.source; + +import org.ethereum.beacon.db.source.impl.HashMapDataSource; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.function.Function; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + +class CodecSourceTest { + + private CodecSource source; + + @BeforeEach + void setUp() { + source = new CodecSource<>(new HashMapDataSource<>(), Function.identity(), Function.identity(), Function.identity()); + } + + @ParameterizedTest + @MethodSource("nullArgumentsProvider") + void testInvalidSourceCreation(DataSource ds, Function f1, Function f2, Function f3) { + assertThatThrownBy(() -> new CodecSource(ds, f1, f2, f3)) + .isInstanceOf(NullPointerException.class); + } + + private static Stream nullArgumentsProvider() { + return Stream.of( + Arguments.of(null, Function.identity(), Function.identity(), Function.identity()), + Arguments.of(new HashMapDataSource(), null, Function.identity(), Function.identity()), + Arguments.of(new HashMapDataSource(), Function.identity(), null, Function.identity()), + Arguments.of(new HashMapDataSource(), Function.identity(), Function.identity(), null) + ); + } + + @ParameterizedTest + @MethodSource("keyOnlyCodecSourceArgumentsProvider") + void testInvalidKeyOnlyCreation(DataSource ds, Function f1) { + assertThatThrownBy(() -> new CodecSource.KeyOnly<>(ds, f1)) + .isInstanceOf(NullPointerException.class); + } + + private static Stream keyOnlyCodecSourceArgumentsProvider() { + return Stream.of( + Arguments.of(null, Function.identity()), + Arguments.of(new HashMapDataSource(), null) + ); + } + + @ParameterizedTest + @MethodSource("valueOnlyCodecSourceArgumentsProvider") + void testInvalidValueOnlyCreation(DataSource ds, Function f1, Function f2) { + assertThatThrownBy(() -> new CodecSource.ValueOnly<>(ds, f1, f2)) + .isInstanceOf(NullPointerException.class); + } + + private static Stream valueOnlyCodecSourceArgumentsProvider() { + return Stream.of( + Arguments.of(null, Function.identity(), Function.identity()), + Arguments.of(new HashMapDataSource(), null, Function.identity()), + Arguments.of(new HashMapDataSource(), Function.identity(), null) + ); + } + + @ParameterizedTest + @MethodSource("keyValueArgumentsProvider") + void testPutGetRemove(String key, String value) { + assertThat(source.get(key)).isNotPresent(); + + source.put(key, value); + assertThat(source.get(key)).isPresent().hasValue(value); + + source.remove(key); + assertThat(source.get(key)).isNotPresent(); + } + + private static Stream keyValueArgumentsProvider() { + return Stream.of( + Arguments.of("test_key", "test_value") + ); + } + + @ParameterizedTest + @MethodSource("keyValueArgumentsProvider") + void testKeyConversion(String key, String value) { + source = new CodecSource<>(new HashMapDataSource<>(), k -> encode(k, key), Function.identity(), Function.identity()); + assertThat(source.get(key)).isNotPresent(); + + source.put(key, value); + assertThat(source.get(key)).isPresent().hasValue(value); + } + + private String encode(String value, String valueModifier) { + return value.concat(valueModifier); + } + + @ParameterizedTest + @MethodSource("keyValueArgumentsProvider") + void testValueTargetValueToUpValueConversion(String key, String value) { + source = new CodecSource<>(new HashMapDataSource<>(), k -> encode(k, key), k -> encode(k, value), Function.identity()); + assertThat(source.get(key)).isNotPresent(); + + source.put(key, value); + assertThat(source.get(key)).isPresent().hasValue(value.concat(value)); + } + + @ParameterizedTest + @MethodSource("keyValueArgumentsProvider") + void testValueUpValueToTargetValueConversion(String key, String value) { + source = new CodecSource<>(new HashMapDataSource<>(), k -> encode(k, key), k -> encode(k, value), k -> decode()); + assertThat(source.get(key)).isNotPresent(); + + source.put(key, value); + assertThat(source.get(key)).isPresent().hasValue(""); + } + + private String decode() { + return ""; + } + +} diff --git a/db/core/src/test/java/org/ethereum/beacon/db/source/DataSourceTest.java b/db/core/src/test/java/org/ethereum/beacon/db/source/DataSourceTest.java new file mode 100644 index 000000000..4dad9f6cb --- /dev/null +++ b/db/core/src/test/java/org/ethereum/beacon/db/source/DataSourceTest.java @@ -0,0 +1,86 @@ +package org.ethereum.beacon.db.source; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import javax.annotation.Nonnull; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Java6Assertions.assertThatThrownBy; + +class DataSourceTest { + + private DataSource dataSource; + + @BeforeEach + void setUp() { + final Map store = new ConcurrentHashMap<>(); + dataSource = new DataSource() { + @Override + public Optional get(@Nonnull String key) { + return Optional.ofNullable(store.get(key)); + } + + @Override + public void put(@Nonnull String key, @Nonnull String value) { + store.put(key, value); + } + + @Override + public void remove(@Nonnull String key) { + store.remove(key); + } + + @Override + public void flush() { + store.put("test_flush", "test_flush"); + } + }; + + assertThat(dataSource.get("something")).isNotPresent(); + } + + @Test + void testPutGetRemoveFlush() { + dataSource.put("test_key_0", "test_value_0"); + dataSource.put("test_key_1", "test_value_1"); + assertThat(dataSource.get("test_key_0")).isPresent().hasValue("test_value_0"); + assertThat(dataSource.get("test_key_1")).isPresent().hasValue("test_value_1"); + dataSource.remove("test_key_0"); + assertThat(dataSource.get("test_key_0")).isNotPresent(); + + dataSource.flush(); + assertThat(dataSource.get("test_flush")).isPresent().hasValue("test_flush"); + } + + @ParameterizedTest + @MethodSource("invalidArgumentsProvider") + void testPutNull(String key, String value) { + assertThatThrownBy(() -> dataSource.put(key, value)).isInstanceOf(NullPointerException.class); + } + + private static Stream invalidArgumentsProvider() { + return Stream.of( + Arguments.of(null, null), + Arguments.of("not_null", null), + Arguments.of(null, "not_null") + ); + } + + @Test + void testGetNull() { + assertThatThrownBy(() -> dataSource.get(null)).isInstanceOf(NullPointerException.class); + } + + @Test + void testRemoveNull() { + assertThatThrownBy(() -> dataSource.remove(null)).isInstanceOf(NullPointerException.class); + } +} diff --git a/db/core/src/test/java/org/ethereum/beacon/db/source/HoleyListTest.java b/db/core/src/test/java/org/ethereum/beacon/db/source/HoleyListTest.java new file mode 100644 index 000000000..63789952e --- /dev/null +++ b/db/core/src/test/java/org/ethereum/beacon/db/source/HoleyListTest.java @@ -0,0 +1,81 @@ +package org.ethereum.beacon.db.source; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +class HoleyListTest { + + private final Long TEST_KEY_0 = 0L; + private final Long TEST_KEY_1 = 1L; + private final Long TEST_KEY_LESS_ZERO = -1L; + private final String TEST_VALUE = "test_value"; + private final String TEST_DEFAULT_VALUE = "test_default_value"; + + private HoleyList list; + + @BeforeEach + void setUp() { + list = new HoleyList() { + private final Map store = new HashMap<>(); + + public long size() { + return store.size(); + } + + public void put(long idx, String value) { + store.put(idx, value); + } + + public Optional get(long idx) { + return Optional.of(store.get(idx)); + } + }; + + assertThat(list.size()).isEqualTo(0); + } + + @Test + void testAdd() { + list.put(TEST_KEY_0, TEST_VALUE); + final long indexToAdd = list.size(); + list.add(TEST_VALUE); + + assertThat(list.size()).isEqualTo(2); + assertThat(list.get(indexToAdd)).isPresent().hasValue(TEST_VALUE); + } + + @Test + void testAddNull() { + list.put(TEST_KEY_0, TEST_VALUE); + list.add(null); + + assertThat(list.size()).isEqualTo(1); + } + + @Test + void testUpdateExistingValue() { + list.put(TEST_KEY_0, TEST_VALUE); + assertThat(list.update(TEST_KEY_0, key -> "")).isPresent().hasValue(""); + } + + @Test + void testUpdateExistingValueOverIndex() { + list.put(TEST_KEY_0, TEST_VALUE); + assertThat(list.update(TEST_KEY_1, key -> "")).isNotPresent(); + assertThat(list.update(TEST_KEY_LESS_ZERO, key -> "")).isNotPresent(); + } + + @Test + void testUpdateExistingValueOrPutDefault() { + list.put(TEST_KEY_0, TEST_VALUE); + assertThat(list.update(TEST_KEY_0, key -> "", () -> TEST_DEFAULT_VALUE)).isEqualTo(""); + assertThat(list.update(TEST_KEY_1, key -> "", () -> TEST_DEFAULT_VALUE)).isEqualTo(TEST_DEFAULT_VALUE); + } + +} diff --git a/db/core/src/test/java/org/ethereum/beacon/db/source/LinkedDataSourceTest.java b/db/core/src/test/java/org/ethereum/beacon/db/source/LinkedDataSourceTest.java new file mode 100644 index 000000000..f497226f8 --- /dev/null +++ b/db/core/src/test/java/org/ethereum/beacon/db/source/LinkedDataSourceTest.java @@ -0,0 +1,76 @@ +package org.ethereum.beacon.db.source; + +import org.ethereum.beacon.db.source.impl.HashMapDataSource; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import javax.annotation.Nonnull; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat; + +class LinkedDataSourceTest { + + private LinkedDataSource dataSource; + + @BeforeEach + void setUp() { + dataSource = new LinkedDataSource() { + public Optional get(@Nonnull String key) { + return Optional.empty(); + } + + public void put(@Nonnull String key, @Nonnull String value) { + + } + + public void remove(@Nonnull String key) { + + } + + public void flush() { + + } + + @Nonnull + public DataSource getUpstream() { + return null; + } + }; + + assertThat(dataSource.getUpstream()).isNull(); + } + + @Test + void testSetUpstream() { + assertThatThrownBy(() -> dataSource.setUpstream(new HashMapDataSource<>())).isInstanceOf(UnsupportedOperationException.class); + } + + @Test + void testGetUpstream() { + dataSource = new LinkedDataSource() { + public Optional get(@Nonnull String key) { + return Optional.empty(); + } + + public void put(@Nonnull String key, @Nonnull String value) { + + } + + public void remove(@Nonnull String key) { + + } + + public void flush() { + + } + + @Nonnull + public DataSource getUpstream() { + return new HashMapDataSource<>(); + } + }; + assertThat(dataSource.getUpstream()).isNotNull(); + } +} diff --git a/db/core/src/test/java/org/ethereum/beacon/db/source/ReadonlyDataSourceTest.java b/db/core/src/test/java/org/ethereum/beacon/db/source/ReadonlyDataSourceTest.java new file mode 100644 index 000000000..3e029a5b0 --- /dev/null +++ b/db/core/src/test/java/org/ethereum/beacon/db/source/ReadonlyDataSourceTest.java @@ -0,0 +1,43 @@ +package org.ethereum.beacon.db.source; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.HashMap; +import java.util.Objects; +import java.util.Optional; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class ReadonlyDataSourceTest { + + private ReadonlyDataSource readonlyDataSource; + + @BeforeEach + void setUp() { + final HashMap store = new HashMap<>(); + readonlyDataSource = key -> { + Objects.requireNonNull(key); + return Optional.ofNullable(store.get(key)); + }; + + store.put("test_key_0", "test_value_0"); + assertThat(store.get("test_key_0")).isNotNull(); + } + + @Test + void testGet() { + assertThat(readonlyDataSource.get("test_key_0")).isPresent().hasValue("test_value_0"); + } + + @Test + void testInvalidGet() { + assertThat(readonlyDataSource.get("test_key_1")).isNotPresent(); + } + + @Test + void testNullValue(){ + assertThatThrownBy(() -> readonlyDataSource.get(null)).isInstanceOf(NullPointerException.class); + } +} diff --git a/db/core/src/test/java/org/ethereum/beacon/db/source/SingleValueSourceTest.java b/db/core/src/test/java/org/ethereum/beacon/db/source/SingleValueSourceTest.java new file mode 100644 index 000000000..9a268cf24 --- /dev/null +++ b/db/core/src/test/java/org/ethereum/beacon/db/source/SingleValueSourceTest.java @@ -0,0 +1,147 @@ +package org.ethereum.beacon.db.source; + +import org.ethereum.beacon.db.source.impl.HashMapDataSource; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +class SingleValueSourceTest { + + private static final String TEST_KEY = "test_key"; + private static final String TEST_VALUE = "test_value"; + private SingleValueSource source; + + @BeforeEach + void setUp() { + source = new SingleValueSource() { + String value; + + @Override + public Optional get() { + return Optional.ofNullable(value); + } + + @Override + public void set(String value) { + this.value = value; + } + + @Override + public void remove() { + this.value = null; + } + }; + + assertThat(source.get()).isEmpty(); + } + + @Tag("FIX") + @ParameterizedTest + @MethodSource("invalidFromDefaultDataSourceArgumentsProvider") + void testInvalidFromDefaultDataSource(DataSource ds, Object key) { + assertThatThrownBy(() -> SingleValueSource.fromDataSource(ds, key)).isInstanceOf(NullPointerException.class); + } + + private static Stream invalidFromDefaultDataSourceArgumentsProvider() { + return Stream.of( + Arguments.of(null, null), + Arguments.of(null, TEST_KEY), + Arguments.of(new HashMapDataSource(), null) + ); + } + + @Test + void testValidFromDefaultDataSource() { + assertThat(SingleValueSource.fromDataSource(new HashMapDataSource<>(), TEST_KEY)).isNotNull(); + } + + + @Tag("FIX") + @ParameterizedTest + @MethodSource("invalidFromDataSourceArgumentsProvider") + void testInvalidFromDataSource(DataSource ds, Object key, Function coder, Function decoder) { + assertThatThrownBy(() -> SingleValueSource.fromDataSource(ds, key, coder, decoder)).isInstanceOf(NullPointerException.class); + } + + private static Stream invalidFromDataSourceArgumentsProvider() { + return Stream.of( + Arguments.of(null, null, null, null), + Arguments.of(null, null, null, Function.identity()), + Arguments.of(null, null, Function.identity(), null), + Arguments.of(null, null, Function.identity(), Function.identity()), + Arguments.of(new HashMapDataSource<>(), null, null, null), + Arguments.of(new HashMapDataSource<>(), TEST_KEY, null, null), + Arguments.of(new HashMapDataSource<>(), TEST_KEY, Function.identity(), null), + Arguments.of(new HashMapDataSource<>(), null, Function.identity(), null), + Arguments.of(new HashMapDataSource<>(), null, null, Function.identity()), + Arguments.of(new HashMapDataSource<>(), TEST_KEY, null, Function.identity()), + Arguments.of(null, TEST_KEY, Function.identity(), Function.identity()), + Arguments.of(null, TEST_KEY, Function.identity(), null), + Arguments.of(null, TEST_KEY, null, Function.identity()), + Arguments.of(null, TEST_KEY, null, null), + Arguments.of(new HashMapDataSource<>(), null, Function.identity(), Function.identity()) + ); + } + + + @Test + void testValidFromDataSource() { + assertThat(SingleValueSource.fromDataSource(new HashMapDataSource<>(), TEST_KEY, Function.identity(), Function.identity())).isNotNull(); + } + + @Test + void testGetSetRemoveSourceValue() { + source = SingleValueSource.fromDataSource(new HashMapDataSource<>(), TEST_KEY, Function.identity(), Function.identity()); + assertThat(source.get()).isNotPresent(); + source.set(TEST_VALUE); + assertThat(source.get()).isPresent().hasValue(TEST_VALUE); + source.remove(); + assertThat(source.get()).isEmpty(); + } + + @Test + void testGetSetRemoveWithEncode() { + source = SingleValueSource.fromDataSource(new HashMapDataSource<>(), TEST_KEY, key -> encode(key, TEST_VALUE), Function.identity()); + source.set(TEST_VALUE); + assertThat(source.get()).isPresent().hasValue(TEST_VALUE.concat(TEST_VALUE)); + source.remove(); + assertThat(source.get()).isEmpty(); + } + + @Test + void testGetSetRemoveWithEncodeDecode() { + source = SingleValueSource.fromDataSource(new HashMapDataSource<>(), TEST_KEY, key -> encode(key, TEST_VALUE), key -> decode()); + source.set(TEST_VALUE); + assertThat(source.get()).isPresent().hasValue(""); + source.remove(); + assertThat(source.get()).isEmpty(); + } + + @Test + void memSourceGetSetRemoveTest() { + source = SingleValueSource.memSource(); + assertThat(source.get()).isNotPresent(); + source.set(TEST_VALUE); + assertThat(source.get()).isPresent().hasValue(TEST_VALUE); + source.remove(); + assertThat(source.get()).isEmpty(); + } + + private String encode(String value, String valueModifier) { + return value.concat(valueModifier); + } + + private String decode() { + return ""; + } +} diff --git a/db/core/src/test/java/org/ethereum/beacon/db/source/StorageEngineSourceTest.java b/db/core/src/test/java/org/ethereum/beacon/db/source/StorageEngineSourceTest.java new file mode 100644 index 000000000..f38369e0b --- /dev/null +++ b/db/core/src/test/java/org/ethereum/beacon/db/source/StorageEngineSourceTest.java @@ -0,0 +1,107 @@ +package org.ethereum.beacon.db.source; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import tech.pegasys.artemis.util.bytes.BytesValue; + +import javax.annotation.Nonnull; +import java.util.HashMap; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class StorageEngineSourceTest { + + private StorageEngineSource storageEngineSource; + private boolean opened; + + @BeforeEach + void setUp() { + final Map store = new ConcurrentHashMap<>(); + storageEngineSource = new StorageEngineSource() { + @Override + public void open() { + opened = true; + } + + @Override + public void close() { + opened = false; + } + + @Override + public void batchUpdate(Map updates) { + assertTrue(opened); + store.putAll(updates); + } + + @Override + public Optional get(@Nonnull BytesValue key) { + assertTrue(opened); + return Optional.ofNullable(store.get(key)); + } + + @Override + public void put(@Nonnull BytesValue key, @Nonnull String value) { + assertTrue(opened); + store.put(key, value); + } + + @Override + public void remove(@Nonnull BytesValue key) { + assertTrue(opened); + store.remove(key); + } + + @Override + public void flush() { + assertTrue(opened); + store.put(wrap("test_flush"), "test_flush"); + } + }; + } + + @Test + void testBasicOperations(){ + storageEngineSource.open(); + storageEngineSource.put(wrap("key_0"), "value_0"); + assertThat(storageEngineSource.get(wrap("key_0")).get()).isEqualTo("value_0"); + + final Map batch = new HashMap<>(); + batch.put(wrap("key_2"), "value_2"); + batch.put(wrap("key_3"), "value_3"); + batch.put(wrap("key_4"), "value_4"); + + storageEngineSource.batchUpdate(batch); + + assertThat("value_2").isEqualTo(storageEngineSource.get(wrap("key_2")).get()); + assertThat("value_3").isEqualTo(storageEngineSource.get(wrap("key_3")).get()); + assertThat("value_4").isEqualTo(storageEngineSource.get(wrap("key_4")).get()); + + batch.put(wrap("key_1"), null); + assertThatThrownBy(() -> storageEngineSource.batchUpdate(batch)).isInstanceOf(NullPointerException.class); + assertThat(storageEngineSource.get(wrap("key_1"))).isNotPresent(); + + storageEngineSource.remove(wrap("key_3")); + assertThat(storageEngineSource.get(wrap("key_3"))).isNotPresent(); + + storageEngineSource.close(); + storageEngineSource.open(); + + assertThat(storageEngineSource.get(wrap("key_1"))).isNotPresent(); + assertThat("value_2").isEqualTo(storageEngineSource.get(wrap("key_2")).get()); + assertThat(storageEngineSource.get(wrap("key_3"))).isNotPresent(); + assertThat("value_4").isEqualTo(storageEngineSource.get(wrap("key_4")).get()); + assertThat(storageEngineSource.get(wrap("key_5"))).isNotPresent(); + + storageEngineSource.close(); + } + + private BytesValue wrap(String value) { + return BytesValue.wrap(value.getBytes()); + } +} diff --git a/db/core/src/test/java/org/ethereum/beacon/db/source/TransactionalDataSourceTest.java b/db/core/src/test/java/org/ethereum/beacon/db/source/TransactionalDataSourceTest.java new file mode 100644 index 000000000..a2f5715ba --- /dev/null +++ b/db/core/src/test/java/org/ethereum/beacon/db/source/TransactionalDataSourceTest.java @@ -0,0 +1,117 @@ +package org.ethereum.beacon.db.source; + + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import javax.annotation.Nonnull; +import java.util.Map; +import java.util.Optional; +import java.util.concurrent.ConcurrentHashMap; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +class TransactionalDataSourceTest { + + private final String TEST_KEY = "test_key"; + private final String TEST_VALUE = "test_value"; + private final String TEST_FLUSH = "flush"; + + private TransactionalDataSource.Transaction transaction; + private TransactionalDataSource transactionalDataSource; + + @BeforeEach + void setUp() { + Map store = new ConcurrentHashMap<>(); + transaction = new TransactionalDataSource.Transaction() { + @Override + public void rollback() { + store.clear(); + } + + @Override + public Optional get(@Nonnull String key) { + return Optional.ofNullable(store.get(key)); + } + + @Override + public void put(@Nonnull String key, @Nonnull String value) { + store.put(key, value); + } + + @Override + public void remove(@Nonnull String key) { + store.remove(key); + } + + @Override + public void flush() { + store.put(TEST_FLUSH, TEST_FLUSH); + } + }; + + transactionalDataSource = new TransactionalDataSource() { + @Override + public Transaction startTransaction(TransactionOptions transactionOptions) { + return transaction; + } + + @Override + public Optional get(@Nonnull String key) { + return transaction.get(key); + } + }; + } + + @Test + void testValidStartTransaction() { + final TransactionalDataSource.TransactionOptions transactionOptions = () -> TransactionalDataSource.IsolationLevel.Snapshot; + assertThat(transactionalDataSource.startTransaction(transactionOptions)).isEqualTo(transaction); + assertThat(transactionOptions.getIsolationLevel()).isIn(TransactionalDataSource.IsolationLevel.values()); + } + + @Test + void testInvalidStartTransaction() { + final TransactionalDataSource.TransactionOptions transactionOptions = () -> TransactionalDataSource.IsolationLevel.valueOf("illegalArgument"); + assertThat(transactionalDataSource.startTransaction(transactionOptions)).isEqualTo(transaction); + assertThat(transactionalDataSource.startTransaction(null)).isEqualTo(transaction); + assertThatThrownBy(() -> transactionOptions.getIsolationLevel().equals(TransactionalDataSource.IsolationLevel.Snapshot)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void testGetPutRemoveElementsInDb() { + transaction.put(TEST_KEY, TEST_VALUE); + assertThat(transactionalDataSource.get(TEST_KEY)).isPresent().hasValue(TEST_VALUE); + assertThat(transaction.get(TEST_KEY)).isPresent().hasValue(TEST_VALUE); + transaction.remove(TEST_KEY); + assertThat(transaction.get(TEST_KEY)).isNotPresent(); + transaction.commit(); + assertThat(transaction.get(TEST_FLUSH)).isPresent().hasValue(TEST_FLUSH); + } + + @Test + void testRollback() { + transaction.put("test_key_1", "test_value_1"); + transaction.put("test_key_2", "test_value_2"); + assertThat(transactionalDataSource.get("test_key_1")).isPresent().hasValue("test_value_1"); + assertThat(transaction.get("test_key_1")).isPresent().hasValue("test_value_1"); + transaction.rollback(); + assertThat(transaction.get("test_value_1")).isNotPresent(); + assertThat(transaction.get("test_key_2")).isNotPresent(); + } + + @Test + void testNullValues() { + assertThatThrownBy(() -> transaction.put(null, null)).isInstanceOf(NullPointerException.class); + assertThatThrownBy(() -> transaction.put("not_null", null)).isInstanceOf(NullPointerException.class); + assertThatThrownBy(() -> transaction.put(null, "not_null")).isInstanceOf(NullPointerException.class); + } + + @Test + void testException() { + assertThat(new TransactionalDataSource.TransactionException("exception")).isNotNull(); + assertThat(new TransactionalDataSource.TransactionException("exception", new Throwable(""))).isNotNull(); + } +} diff --git a/db/core/src/test/java/org/ethereum/beacon/db/source/WriteBufferTest.java b/db/core/src/test/java/org/ethereum/beacon/db/source/WriteBufferTest.java new file mode 100644 index 000000000..f73396d8d --- /dev/null +++ b/db/core/src/test/java/org/ethereum/beacon/db/source/WriteBufferTest.java @@ -0,0 +1,118 @@ +package org.ethereum.beacon.db.source; + +import org.ethereum.beacon.db.source.impl.HashMapDataSource; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.Optional; +import java.util.function.Function; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class WriteBufferTest { + + private WriteBuffer buffer; + private static CacheSizeEvaluator evaluator; + private Function keyValueEvaluator; + private HashMapDataSource dataSource; + + @BeforeEach + void setUp() { + keyValueEvaluator = s -> 1L; + evaluator = CacheSizeEvaluator.getInstance(keyValueEvaluator); + dataSource = new HashMapDataSource(); + buffer = new WriteBuffer<>(dataSource, evaluator, true); + assertThat(buffer.evaluateSize()).isEqualTo(evaluator.getEvaluatedSize()); + assertThat(buffer.getUpstream()).isEqualTo(dataSource); + } + + @ParameterizedTest + @MethodSource("invalidArgumentsProvider") + void testInvalidWriteBufferCreation(DataSource ds, CacheSizeEvaluator evaluator, boolean upstreamFlush) { + assertThatThrownBy(() -> new WriteBuffer(ds, evaluator, upstreamFlush)).isInstanceOf(NullPointerException.class); + } + + private static Stream invalidArgumentsProvider() { + return Stream.of( + Arguments.of(null, null, false), + Arguments.of(null, null, true), + Arguments.of(null, evaluator, false), + Arguments.of(null, evaluator, true), + Arguments.of(new HashMapDataSource<>(), null, false), + Arguments.of(new HashMapDataSource<>(), null, true) + ); + } + + @ParameterizedTest + @MethodSource("invalidArgsProvider") + void testInvalidArgsWriteBufferCreation(DataSource ds, boolean upstreamFlush) { + assertThatThrownBy(() -> new WriteBuffer(ds, upstreamFlush)).isInstanceOf(NullPointerException.class); + } + + private static Stream invalidArgsProvider() { + return Stream.of( + Arguments.of(null, false), + Arguments.of(null, true) + ); + } + + @Test + void testGetPutRemoveFlushReset() + { + assertThat(buffer.evaluateSize()).isEqualTo(0); + buffer.put("test_key_0","test_value_0"); + buffer.put("test_key_1","test_value_1"); + buffer.put("test_key_2","test_value_2"); + buffer.put("test_key_3","test_value_3"); + buffer.put("test_key_4","test_value_4"); + assertThat(buffer.evaluateSize()).isGreaterThan(0); + assertThat(buffer.getCacheEntry("test_key_0")).isPresent().hasValue(Optional.of("test_value_0")); + buffer.doFlush(); + assertThat(buffer.evaluateSize()).isEqualTo(0); + assertThat(buffer.getUpstream().get("test_key_0")).isPresent().hasValue("test_value_0"); + buffer.reset(); + assertThat(buffer.evaluateSize()).isEqualTo(0); + assertThat(buffer.getUpstream().get("test_key_0")).isPresent().hasValue("test_value_0"); + } + + @Test + void testGetPutRemoveFlushResetNoSize() + { + buffer = new WriteBuffer<>(new HashMapDataSource<>(), true); + assertThat(buffer.evaluateSize()).isEqualTo(0); + buffer.put("test_key_0","test_value_0"); + buffer.put("test_key_1","test_value_1"); + buffer.put("test_key_2","test_value_2"); + buffer.put("test_key_3","test_value_3"); + buffer.put("test_key_4","test_value_4"); + assertThat(buffer.evaluateSize()).isEqualTo(0); + assertThat(buffer.getCacheEntry("test_key_0")).isPresent().hasValue(Optional.of("test_value_0")); + buffer.doFlush(); + assertThat(buffer.evaluateSize()).isEqualTo(0); + assertThat(buffer.getUpstream().get("test_key_0")).isPresent().hasValue("test_value_0"); + buffer.reset(); + assertThat(buffer.evaluateSize()).isEqualTo(0); + assertThat(buffer.getUpstream().get("test_key_0")).isPresent().hasValue("test_value_0"); + } + + @ParameterizedTest + @MethodSource("nullArgumentsProvider") + void testNullValues(String key, String value) { + assertThatThrownBy(() -> buffer.put(key, value)).isInstanceOf(NullPointerException.class); + assertThatThrownBy(() -> buffer.get(null)).isInstanceOf(NullPointerException.class); + assertThatThrownBy(() -> buffer.remove(null)).isInstanceOf(NullPointerException.class); + } + + private static Stream nullArgumentsProvider() { + return Stream.of( + Arguments.of(null, null), + Arguments.of("not_null", null), + Arguments.of(null, "not_null") + ); + } +} diff --git a/db/core/src/test/java/org/ethereum/beacon/db/source/impl/CacheSizeEvaluatorImplTest.java b/db/core/src/test/java/org/ethereum/beacon/db/source/impl/CacheSizeEvaluatorImplTest.java new file mode 100644 index 000000000..c582f2f6f --- /dev/null +++ b/db/core/src/test/java/org/ethereum/beacon/db/source/impl/CacheSizeEvaluatorImplTest.java @@ -0,0 +1,60 @@ +package org.ethereum.beacon.db.source.impl; + +import org.ethereum.beacon.db.source.CacheSizeEvaluator; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; + +import java.util.function.Function; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class CacheSizeEvaluatorImplTest { + + private static final long EMPTY_SIZE = 0L; + private static final String KEY = "key"; + private static final String VALUE = "value"; + + private CacheSizeEvaluator cacheSizeEvaluator; + private long createdStorageSize; + + @BeforeEach + void setUp() { + cacheSizeEvaluator = new CacheSizeEvaluatorImpl<>(key -> (long) key.length(), key -> (long) key.length()); + createdStorageSize = cacheSizeEvaluator.getEvaluatedSize(); + assertThat(createdStorageSize).isEqualTo(EMPTY_SIZE); + } + + @Test + @Tag("FIX") + void testInvalidInstanceCreation() { + assertThatThrownBy(() -> new CacheSizeEvaluatorImpl<>(null, null)) + .isInstanceOf(NullPointerException.class); + assertThatThrownBy(() -> new CacheSizeEvaluatorImpl<>(null, Function.identity())) + .isInstanceOf(NullPointerException.class); + assertThatThrownBy(() -> new CacheSizeEvaluatorImpl<>(Function.identity(), null)) + .isInstanceOf(NullPointerException.class); + } + + @Test + void added() { + cacheSizeEvaluator.added(KEY, VALUE); + final long newSize = createdStorageSize + KEY.length() + VALUE.length(); + assertThat(cacheSizeEvaluator.getEvaluatedSize()).isEqualTo(newSize); + } + + @Test + void removed() { + cacheSizeEvaluator.added(KEY, VALUE); + cacheSizeEvaluator.removed(KEY, VALUE); + assertThat(cacheSizeEvaluator.getEvaluatedSize()).isEqualTo(createdStorageSize); + } + + @Test + void reset() { + cacheSizeEvaluator.added(KEY, VALUE); + cacheSizeEvaluator.reset(); + assertThat(cacheSizeEvaluator.getEvaluatedSize()).isEqualTo(EMPTY_SIZE); + } +} diff --git a/db/core/src/test/java/org/ethereum/beacon/db/source/impl/DataSourceListTest.java b/db/core/src/test/java/org/ethereum/beacon/db/source/impl/DataSourceListTest.java new file mode 100644 index 000000000..13c05c2da --- /dev/null +++ b/db/core/src/test/java/org/ethereum/beacon/db/source/impl/DataSourceListTest.java @@ -0,0 +1,76 @@ +package org.ethereum.beacon.db.source.impl; + +import org.ethereum.beacon.db.source.DataSource; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; +import tech.pegasys.artemis.util.bytes.BytesValue; + +import java.util.function.Function; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class DataSourceListTest { + + private DataSourceList dataSourceList; + + @BeforeEach + void setUp() { + dataSourceList = new DataSourceList<>(new HashMapDataSource<>(), serialize(), deserialize()); + assertThat(dataSourceList.size()).isEqualTo(0); + } + + private Function serialize() { + return key -> BytesValue.EMPTY; + } + + private Function deserialize() { + return key -> ""; + } + + @ParameterizedTest + @MethodSource("nullArgumentsProvider") + void testInvalidSourceCreation(DataSource ds, Function f1, Function f2) { + assertThatThrownBy(() -> new DataSourceList<>(ds, f1, f2)) + .isInstanceOf(NullPointerException.class); + } + + private static Stream nullArgumentsProvider() { + return Stream.of( + Arguments.of(new HashMapDataSource<>(), null, Function.identity()), + Arguments.of(new HashMapDataSource<>(), Function.identity(), null) + ); + } + + @ParameterizedTest + @MethodSource("putGetSizeArgumentsProvider") + void testPutGetSizeSerialization(Long key, String value, int expectedSize) { + assertThat(dataSourceList.get(key)).isNotPresent(); + dataSourceList.put(key, value); + assertThat(dataSourceList.size()).isEqualTo(expectedSize); + } + + private static Stream putGetSizeArgumentsProvider() { + return Stream.of( + Arguments.of(0L, "test_value", 1), + Arguments.of(0L, null, 0), + Arguments.of(1L, "test_value", 2) + ); + } + + @Test + void testGetOverIndex() { + final long TEST_KEY_0 = 0L; + final long TEST_KEY_1 = 1L; + final long TEST_KEY_LESS_ZERO = -1L; + final String TEST_VALUE = "test_value"; + + dataSourceList.put(TEST_KEY_0, TEST_VALUE); + assertThat(dataSourceList.get(TEST_KEY_LESS_ZERO)).isEmpty(); + assertThat(dataSourceList.get(TEST_KEY_1)).isEmpty(); + } +} diff --git a/db/core/src/test/java/org/ethereum/beacon/db/source/impl/DelegateDataSourceTest.java b/db/core/src/test/java/org/ethereum/beacon/db/source/impl/DelegateDataSourceTest.java new file mode 100644 index 000000000..3ca6221b1 --- /dev/null +++ b/db/core/src/test/java/org/ethereum/beacon/db/source/impl/DelegateDataSourceTest.java @@ -0,0 +1,66 @@ +package org.ethereum.beacon.db.source.impl; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Java6Assertions.assertThatThrownBy; + +class DelegateDataSourceTest { + + private final String TEST_KEY = "test_key"; + private final String TEST_VALUE = "test_value"; + private final String TEST_FLUSH = "flush"; + + private DelegateDataSource delegateDataSource; + + @BeforeEach + void setUp() { + delegateDataSource = new DelegateDataSource<>(new HashMapDataSource<>()); + assertThat(delegateDataSource.get(TEST_KEY)).isNotPresent(); + } + + @Test + void testPutGetRemove() { + delegateDataSource.put(TEST_KEY, TEST_VALUE); + assertThat(delegateDataSource.get(TEST_KEY)).isPresent().hasValue(TEST_VALUE); + + delegateDataSource.remove(TEST_KEY); + assertThat(delegateDataSource.get(TEST_KEY)).isNotPresent(); + } + + @ParameterizedTest + @MethodSource("nullArgumentsProvider") + void testInvalidSourceCreation(String key, String value) { + assertThatThrownBy(() -> delegateDataSource.put(key, value)).isInstanceOf(NullPointerException.class); + } + + private static Stream nullArgumentsProvider() { + return Stream.of( + Arguments.of(null, "test_value"), + Arguments.of("test_key", null) + ); + } + + @Test + void testFlush() { + delegateDataSource = new DelegateDataSource<>(new HashMapDataSource() { + public void flush() { + store.put(TEST_FLUSH, TEST_FLUSH); + } + }); + assertThat(delegateDataSource.get(TEST_KEY)).isNotPresent(); + + delegateDataSource.put(TEST_KEY, TEST_VALUE); + assertThat(delegateDataSource.get(TEST_KEY)).isPresent().hasValue(TEST_VALUE); + + assertThat(delegateDataSource.get(TEST_FLUSH)).isNotPresent(); + delegateDataSource.flush(); + assertThat(delegateDataSource.get(TEST_FLUSH)).isPresent().hasValue(TEST_FLUSH); + } +} diff --git a/db/core/src/test/java/org/ethereum/beacon/db/source/impl/HashMapDataSourceTest.java b/db/core/src/test/java/org/ethereum/beacon/db/source/impl/HashMapDataSourceTest.java new file mode 100644 index 000000000..8e8a58a13 --- /dev/null +++ b/db/core/src/test/java/org/ethereum/beacon/db/source/impl/HashMapDataSourceTest.java @@ -0,0 +1,65 @@ +package org.ethereum.beacon.db.source.impl; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.CsvSource; +import org.junit.jupiter.params.provider.MethodSource; +import org.junit.jupiter.params.provider.ValueSource; + +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class HashMapDataSourceTest { + + private HashMapDataSource dataSource; + + @BeforeEach + void setUp() { + dataSource = new HashMapDataSource<>(); + } + + @ParameterizedTest + @CsvSource({ "test_key, test_value"}) + void testGetPutRemove(String key, String value) { + assertThat(dataSource.store).doesNotContainKeys(key); + dataSource.put(key, value); + assertThat(dataSource.get(key)).isPresent().hasValue(value); + dataSource.remove(key); + assertThat(dataSource.get(key)).isNotPresent(); + } + + @ParameterizedTest + @ValueSource(strings = "test_flush") + void testFlush(String flush) { + dataSource.getStore().put(flush, flush); + assertThat(dataSource.getStore().get(flush)).isEqualTo(flush); +} + + @ParameterizedTest + @CsvSource({ "test_key, test_value"}) + void testGetStore(String key, String value) { + dataSource.put(key, value); + assertThat(dataSource.getStore().get(key)).isEqualTo(value); + dataSource.getStore().remove(key); + assertThat(dataSource.get(key)).isNotPresent(); + } + + + + @ParameterizedTest + @MethodSource("nullArgumentsProvider") + void testNullValues(String key, String value) { + assertThatThrownBy(() -> dataSource.put(key, value)).isInstanceOf(NullPointerException.class); + } + + private static Stream nullArgumentsProvider() { + return Stream.of( + Arguments.of(null, null), + Arguments.of("not_null", null), + Arguments.of(null, "not_null") + ); + } +} diff --git a/db/core/src/test/java/org/ethereum/beacon/db/source/impl/HashMapHoleyListTest.java b/db/core/src/test/java/org/ethereum/beacon/db/source/impl/HashMapHoleyListTest.java new file mode 100644 index 000000000..06044cfe2 --- /dev/null +++ b/db/core/src/test/java/org/ethereum/beacon/db/source/impl/HashMapHoleyListTest.java @@ -0,0 +1,80 @@ +package org.ethereum.beacon.db.source.impl; + +import org.ethereum.beacon.db.source.HoleyList; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.stream.Stream; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +class HashMapHoleyListTest { + + private HoleyList map; + + @BeforeEach + void setUp() { + map = new HashMapHoleyList<>(); + assertThat(map.size()).isEqualTo(0L); + } + + @ParameterizedTest + @MethodSource("keyValueArgumentsProvider") + void testPutSize(Long key, String value, Long size) { + map.put(key, value); + assertThat(map.size()).isEqualTo(size); + } + + private static Stream keyValueArgumentsProvider() { + return Stream.of( + Arguments.of(0L, "test_value", 1L), + Arguments.of(0L, null, 0L) + ); + } + + @ParameterizedTest + @MethodSource("keyValueGetArgumentsProvider") + void testValidGet(Long key, String value) { + map.put(key, value); + assertThat(map.get(key)).isPresent().hasValue(value); + } + + private static Stream keyValueGetArgumentsProvider() { + return Stream.of( + Arguments.of(0L, "test_value") + ); + } + + @ParameterizedTest + @MethodSource("invalidKeyArgumentsProvider") + void testGetOverIndex(Long key, String value, Long wrongKey) { + map.put(key, value); + assertThat(map.get(wrongKey)).isNotPresent(); + } + + private static Stream invalidKeyArgumentsProvider() { + return Stream.of( + Arguments.of(0L, "test_value", 1L), + Arguments.of(0L, "test_value", -1L) + ); + } + + @Test + void testPutSameKey() { + final long TEST_KEY = 0L; + final long TEST_KEY_1 = 1L; + final String TEST_VALUE = "test_value"; + final String TEST_VALUE_NEW = "NewTestValue"; + + map.put(TEST_KEY, TEST_VALUE); + map.put(TEST_KEY_1, TEST_VALUE); + assertThat(map.size()).isEqualTo(2L); + + map.put(TEST_KEY, TEST_VALUE_NEW); + assertThat(map.size()).isEqualTo(2L); + assertThat(map.get(TEST_KEY)).isPresent().hasValue(TEST_VALUE_NEW); + } +} diff --git a/db/core/src/test/java/org/ethereum/beacon/db/source/impl/MemSizeEvaluatorTest.java b/db/core/src/test/java/org/ethereum/beacon/db/source/impl/MemSizeEvaluatorTest.java index 3a203e477..d5632d9bd 100644 --- a/db/core/src/test/java/org/ethereum/beacon/db/source/impl/MemSizeEvaluatorTest.java +++ b/db/core/src/test/java/org/ethereum/beacon/db/source/impl/MemSizeEvaluatorTest.java @@ -1,16 +1,17 @@ package org.ethereum.beacon.db.source.impl; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Test; import tech.pegasys.artemis.util.bytes.BytesValue; -public class MemSizeEvaluatorTest { +import static org.assertj.core.api.Assertions.assertThat; + +class MemSizeEvaluatorTest { @Test - public void bytesValueEvaluator() { + void bytesValueEvaluator() { long evaluatedSize = MemSizeEvaluators.BytesValueEvaluator.apply(BytesValue.wrap(new byte[1000])); System.out.println("Evaluated size: " + evaluatedSize); - Assert.assertTrue(evaluatedSize > 1000); + assertThat(evaluatedSize).isGreaterThan(1000); } } diff --git a/db/core/src/test/java/org/ethereum/beacon/db/source/impl/XorDataSourceTest.java b/db/core/src/test/java/org/ethereum/beacon/db/source/impl/XorDataSourceTest.java new file mode 100644 index 000000000..a009df537 --- /dev/null +++ b/db/core/src/test/java/org/ethereum/beacon/db/source/impl/XorDataSourceTest.java @@ -0,0 +1,27 @@ +package org.ethereum.beacon.db.source.impl; + + +import org.junit.jupiter.api.Test; +import tech.pegasys.artemis.util.bytes.BytesValue; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class XorDataSourceTest { + + @Test + void testDataSourceCreation() { + assertThatThrownBy(() -> new XorDataSource<>(null, BytesValue.EMPTY)) + .isInstanceOf(NullPointerException.class); + + assertThatThrownBy(() -> new XorDataSource<>(null, null)) + .isInstanceOf(NullPointerException.class); + + final HashMapDataSource upstream = new HashMapDataSource<>(); + XorDataSource actual = new XorDataSource<>(upstream, null); + assertThat(actual.getUpstream()).isEqualTo(upstream); + + actual = new XorDataSource<>(upstream, BytesValue.of(1, 2, 3)); + assertThat(actual.getUpstream()).isEqualTo(upstream); + } +} diff --git a/db/core/src/test/java/org/ethereum/beacon/db/util/AutoCloseableLockTest.java b/db/core/src/test/java/org/ethereum/beacon/db/util/AutoCloseableLockTest.java new file mode 100644 index 000000000..e80e278f1 --- /dev/null +++ b/db/core/src/test/java/org/ethereum/beacon/db/util/AutoCloseableLockTest.java @@ -0,0 +1,110 @@ +package org.ethereum.beacon.db.util; + +import org.jetbrains.annotations.NotNull; +import org.junit.jupiter.api.Tag; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.Arguments; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.concurrent.TimeUnit; +import java.util.concurrent.locks.Condition; +import java.util.concurrent.locks.Lock; +import java.util.concurrent.locks.ReentrantLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; +import java.util.stream.Stream; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatThrownBy; + +class AutoCloseableLockTest { + + @Tag("FIX") + @Test + void testInvalidCreation() { + assertThatThrownBy(() -> new AutoCloseableLock(null)).isInstanceOf(NullPointerException.class); + assertThatThrownBy(() -> AutoCloseableLock.wrap(null)).isInstanceOf(NullPointerException.class); + } + + @ParameterizedTest + @MethodSource("creationArgumentsProvider") + void testValidCreation(Lock lock) { + final AutoCloseableLock result = new AutoCloseableLock(lock); + result + .lock() + .unlock(); + } + + private static Stream creationArgumentsProvider() { + return Stream.of( + Arguments.of(new ReentrantLock()), + Arguments.of(new ReentrantReadWriteLock().writeLock()), + Arguments.of(new ReentrantReadWriteLock().readLock()) + ); + } + + @ParameterizedTest + @MethodSource("creationArgumentsProvider") + void wrap(Lock lock) { + final AutoCloseableLock result = AutoCloseableLock.wrap(lock); + result + .lock() + .unlock(); + } + + private boolean locked; + private boolean unlocked; + + @Test + void testLockUnlockCloseCreation() { + locked = false; + unlocked = false; + + final Lock lock = new Lock() { + @Override + public void lock() { + locked = true; + } + + @Override + public void lockInterruptibly() { + + } + + @Override + public boolean tryLock() { + return false; + } + + @Override + public boolean tryLock(long time, @NotNull TimeUnit unit) { + return false; + } + + @Override + public void unlock() { + unlocked = true; + } + + @NotNull + @Override + public Condition newCondition() { + return null; + } + }; + + final AutoCloseableLock result = new AutoCloseableLock(lock); + assertThat(locked).isFalse(); + result.lock(); + assertThat(locked).isTrue(); + + assertThat(unlocked).isFalse(); + result.close(); + assertThat(unlocked).isTrue(); + + unlocked = false; + assertThat(unlocked).isFalse(); + result.unlock(); + assertThat(unlocked).isTrue(); + } +} diff --git a/test/build.gradle b/test/build.gradle index 6a5d5561b..761796a80 100644 --- a/test/build.gradle +++ b/test/build.gradle @@ -9,7 +9,9 @@ dependencies { testImplementation project(':consensus') testImplementation project(':core') testImplementation project(':start:config') - testImplementation project(':db:core') + testImplementation(project(':db:core')) { + exclude group: 'org.junit.jupiter' + } testImplementation project(':chain') testImplementation project(':start:simulator') testImplementation project(':util') @@ -35,4 +37,4 @@ task submodulesUpdate(type:Exec) { group 'Build Setup' } -test.dependsOn(submodulesUpdate) \ No newline at end of file +test.dependsOn(submodulesUpdate)