diff --git a/README.md b/README.md index 4c68a58..6623b47 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,7 @@ public class MyAerospikeStore extends AerospikeStore { } @Override - protected boolean isValidDataItem(final TestData testData) { + protected boolean isValidDataItem(final TestData userData) { return true; // you may do additional checks here } } diff --git a/aerospike-crud-store/pom.xml b/aerospike-crud-store/pom.xml index efec479..94a6806 100644 --- a/aerospike-crud-store/pom.xml +++ b/aerospike-crud-store/pom.xml @@ -5,7 +5,7 @@ crud-store com.livetheoogway.crudstore - 1.2.3 + 1.2.4 4.0.0 @@ -68,5 +68,11 @@ ${junit.mockito.version} test + + net.java.dev.jna + jna + 5.7.0 + test + \ No newline at end of file diff --git a/aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/AerospikeStoreTest.java b/aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/AerospikeStoreTest.java index cdc964e..f6c768f 100644 --- a/aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/AerospikeStoreTest.java +++ b/aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/AerospikeStoreTest.java @@ -18,11 +18,17 @@ import com.aerospike.client.AerospikeException; import com.aerospike.client.IAerospikeClient; import com.aerospike.client.Key; -import com.aerospike.client.policy.Policy; import com.aerospike.client.policy.WritePolicy; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import com.livetheoogway.crudstore.aerospike.data.ProfileData; +import com.livetheoogway.crudstore.aerospike.data.UserData; +import com.livetheoogway.crudstore.aerospike.stores.TestTypeRefAerospikeStore; +import com.livetheoogway.crudstore.aerospike.stores.UserAerospikeReplaceStore; +import com.livetheoogway.crudstore.aerospike.stores.UserAerospikeStore; +import com.livetheoogway.crudstore.aerospike.util.DataUtils; +import com.livetheoogway.crudstore.aerospike.util.TestUtils; import io.appform.testcontainers.aerospike.AerospikeContainerConfiguration; import io.appform.testcontainers.aerospike.container.AerospikeContainer; import org.junit.jupiter.api.AfterAll; @@ -47,7 +53,7 @@ class AerospikeStoreTest { private static AerospikeContainer aerospikeContainer; - private static AerospikeStore store; + private static AerospikeStore store; private static AerospikeClient aerospikeClient; @BeforeAll @@ -60,7 +66,7 @@ static void beforeAll() { aerospikeContainer = new AerospikeContainer(config); aerospikeContainer.start(); aerospikeClient = ContainerHelper.provideAerospikeClient(aerospikeContainer, config); - store = new TestAerospikeStore(aerospikeClient, + store = new UserAerospikeStore(aerospikeClient, new NamespaceSet("test", "test"), new ObjectMapper(), new DefaultErrorHandler<>()); @@ -71,7 +77,7 @@ static void afterAll() { aerospikeContainer.stop(); } - private static void validateTestData(final Optional testData, final TestData meToo) { + private static void validateTestData(final Optional testData, final UserData meToo) { assertTrue(testData.isPresent()); assertEquals(meToo.id(), testData.get().id()); assertEquals(meToo.name(), testData.get().name()); @@ -81,49 +87,53 @@ private static void validateTestData(final Optional testData, final Te @Test void testStoreOperations() { - /* put some data */ - final var me = DataUtils.generateTestData(); - store.create(me); - - /* get it back */ - Optional testData = store.get(me.id()); - validateTestData(testData, me); - - /* get on unknown id */ - assertFalse(store.get("unknown").isPresent()); - - /* update existing data */ - final var meToo = DataUtils.generateTestData(me.id()); - store.update(meToo); - testData = store.get(meToo.id()); - validateTestData(testData, meToo); - - /* update unknown id */ - assertThrows(RuntimeException.class, () -> store.update(new TestData("unknown", "me too", 5))); - - /* create already existing id */ - assertThrows(RuntimeException.class, () -> store.create(new TestData("1", "me too", 5))); - - /* get bulk */ - final TestData you = DataUtils.generateTestData("2", "you", 5); - store.create(you); - final Map result = store.get(List.of(meToo.id(), you.id())); - assertTrue(result.containsKey(meToo.id())); - assertTrue(result.containsKey(you.id())); - assertEquals(2, result.size()); - - /* list */ - final List result2 = store.list(); - assertEquals(2, result2.size()); + final UserData me = DataUtils.generateTestData(); + TestUtils.testStoreOperations(store, + () -> me, + () -> DataUtils.generateTestData(me.id()), + () -> DataUtils.generateTestData("2", "you", 5), + () -> new UserData("unknown", "me too", 5), + (data, result) -> { + assertTrue(result.isPresent()); + assertEquals(data.id(), result.get().id()); + assertEquals(data.name(), result.get().name()); + assertEquals(data.age(), result.get().age()); + return true; + }); + } + @Test + void testStoreOperationsForTypeRef() { + + final TestTypeRefAerospikeStore> store + = new TestTypeRefAerospikeStore<>(aerospikeClient, + new NamespaceSet("test", "test-2"), + new ObjectMapper(), + new TypeReference<>() {}, + new DefaultErrorHandler<>()); + + final ProfileData me = DataUtils.generateProfileData(); + TestUtils.testStoreOperations(store, + () -> me, + () -> DataUtils.generateProfileData(me.id()), + () -> DataUtils.generateProfileData("2"), + () -> new ProfileData<>("unknown", new UserData("unknown", "me too", 5)), + (data, result) -> { + assertTrue(result.isPresent()); + assertEquals(data.id(), result.get().id()); + assertEquals(data.profile().name(), result.get().profile().name()); + assertEquals(data.profile().age(), result.get().profile().age()); + return true; + }); } + @Test void testStoreOperationsOnReplace() { - final TestAerospikeStoreReplace storeWithReplace - = new TestAerospikeStoreReplace(aerospikeClient, - new NamespaceSet("test", "test-2"), + final UserAerospikeReplaceStore storeWithReplace + = new UserAerospikeReplaceStore(aerospikeClient, + new NamespaceSet("test", "test-3"), new ObjectMapper(), new DefaultErrorHandler<>()); /* put some data */ @@ -131,7 +141,7 @@ void testStoreOperationsOnReplace() { storeWithReplace.create(me); /* get it back */ - Optional testData = storeWithReplace.get(me.id()); + Optional testData = storeWithReplace.get(me.id()); validateTestData(testData, me); /* get on unknown id */ @@ -152,7 +162,7 @@ void testStoreDeleteExistingKeySuccessful() { store.create(me); /* get it back */ - Optional testData = store.get(me.id()); + Optional testData = store.get(me.id()); validateTestData(testData, me); /* delete it */ @@ -168,10 +178,10 @@ void testStoreDeleteExistingKeySuccessful() { @Test void testHandlerForJsonSerializationExceptionDuringCreate() throws JsonProcessingException { final ObjectMapper mapper = mock(ObjectMapper.class); - final ErrorHandler errorHandler = mock(ErrorHandler.class); + final ErrorHandler errorHandler = mock(ErrorHandler.class); when(mapper.writeValueAsString(any())).thenThrow(JsonProcessingException.class); - final TestAerospikeStore newStore - = new TestAerospikeStore(aerospikeClient, + final UserAerospikeStore newStore + = new UserAerospikeStore(aerospikeClient, new NamespaceSet("test", "json-error-1"), mapper, errorHandler); newStore.create(DataUtils.generateTestData()); @@ -183,45 +193,45 @@ void testHandlerForJsonSerializationExceptionDuringCreate() throws JsonProcessin void testHandlerForJsonSerializationExceptionDuringGet() throws JsonProcessingException { final ObjectMapper validObjectMapper = new ObjectMapper(); final ObjectMapper mapper = mock(ObjectMapper.class); - final ErrorHandler errorHandler = mock(ErrorHandler.class); + final ErrorHandler errorHandler = mock(ErrorHandler.class); when(mapper.readValue(anyString(), any(TypeReference.class))).thenThrow(JsonProcessingException.class); final var testData = DataUtils.generateTestData("31"); when(mapper.writeValueAsString(any())).thenReturn(validObjectMapper.writeValueAsString(testData)); - final TestAerospikeStore newStore - = new TestAerospikeStore(aerospikeClient, + final UserAerospikeStore newStore + = new UserAerospikeStore(aerospikeClient, new NamespaceSet("test", "json-error-2"), mapper, errorHandler); newStore.create(testData); - final Optional result = newStore.get(testData.id()); + final Optional result = newStore.get(testData.id()); assertFalse(result.isPresent()); Mockito.verify(errorHandler, Mockito.times(1)).onDeSerializationError(any(), any()); final var anotherTestData = DataUtils.generateTestData("32"); newStore.create(anotherTestData); - final Map result2 = newStore.get(List.of(testData.id(), anotherTestData.id())); + final Map result2 = newStore.get(List.of(testData.id(), anotherTestData.id())); assertTrue(result2.isEmpty()); Mockito.verify(errorHandler, Mockito.times(3)).onDeSerializationError(any(), any()); } @Test void testHandlerForNoRecordFoundExceptionDuringGet() { - final ErrorHandler errorHandler = mock(ErrorHandler.class); - final TestAerospikeStore newStore - = new TestAerospikeStore(aerospikeClient, + final ErrorHandler errorHandler = mock(ErrorHandler.class); + final UserAerospikeStore newStore + = new UserAerospikeStore(aerospikeClient, new NamespaceSet("test", "no-record-error-2"), new ObjectMapper(), errorHandler); final var testData = DataUtils.generateTestData(); - final Optional result = newStore.get(testData.id()); + final Optional result = newStore.get(testData.id()); assertFalse(result.isPresent()); Mockito.verify(errorHandler, Mockito.times(1)).onNoRecordFound(any()); final var anotherTestData = DataUtils.generateTestData("2"); - final Map result2 = newStore.get(List.of(testData.id(), anotherTestData.id())); + final Map result2 = newStore.get(List.of(testData.id(), anotherTestData.id())); assertTrue(result2.isEmpty()); Mockito.verify(errorHandler, Mockito.times(3)).onNoRecordFound(any()); } - + @Test void testHandlerForAerospikeExceptionDuringPut() { final IAerospikeClient newASClient = mock(AerospikeClient.class); @@ -229,9 +239,9 @@ void testHandlerForAerospikeExceptionDuringPut() { doNothing().when(newASClient).put(any(WritePolicy.class), any(Key.class), any()); doThrow(new AerospikeException(22, "test-error-on-put")).when(newASClient).put(any(WritePolicy.class), any(Key.class), any()); - final ErrorHandler errorHandler = mock(ErrorHandler.class); - final TestAerospikeStore newStore - = new TestAerospikeStore(newASClient, + final ErrorHandler errorHandler = mock(ErrorHandler.class); + final UserAerospikeStore newStore + = new UserAerospikeStore(newASClient, new NamespaceSet("test", "no-record-error-2"), new ObjectMapper(), errorHandler); diff --git a/aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/DataUtils.java b/aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/DataUtils.java deleted file mode 100644 index 88e50ac..0000000 --- a/aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/DataUtils.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.livetheoogway.crudstore.aerospike; - -import lombok.experimental.UtilityClass; - -import java.util.Random; - -@UtilityClass -public class DataUtils { - private static final Random RANDOM = new Random(System.currentTimeMillis()); - - public TestData generateTestData() { - return generateTestData("1", "me", RANDOM.nextInt(100)); - } - - public TestData generateTestData(String id) { - return generateTestData(id, "me too", RANDOM.nextInt(100)); - } - - public TestData generateTestData(String id, String name, int age) { - return new TestData(id, name, age); - } -} diff --git a/aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/TestData.java b/aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/data/ProfileData.java similarity index 78% rename from aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/TestData.java rename to aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/data/ProfileData.java index 85173c2..9423b98 100644 --- a/aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/TestData.java +++ b/aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/data/ProfileData.java @@ -12,13 +12,11 @@ * under the License. */ -package com.livetheoogway.crudstore.aerospike; +package com.livetheoogway.crudstore.aerospike.data; import com.livetheoogway.crudstore.core.Id; -public record TestData(String id, String name, int age) implements Id { - @Override - public String id() { - return id; - } +public record ProfileData( + String id, + T profile) implements Id { } diff --git a/aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/data/UserData.java b/aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/data/UserData.java new file mode 100644 index 0000000..a74e661 --- /dev/null +++ b/aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/data/UserData.java @@ -0,0 +1,23 @@ +/* + * Copyright 2022. Live the Oogway, Tushar Naik + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and limitations + * under the License. + */ + +package com.livetheoogway.crudstore.aerospike.data; + +import com.livetheoogway.crudstore.core.Id; + +public record UserData( + String id, + String name, + int age) implements Id { +} diff --git a/aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/TestAerospikeStoreReplace.java b/aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/stores/TestTypeRefAerospikeStore.java similarity index 54% rename from aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/TestAerospikeStoreReplace.java rename to aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/stores/TestTypeRefAerospikeStore.java index 223f6d3..b76cef1 100644 --- a/aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/TestAerospikeStoreReplace.java +++ b/aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/stores/TestTypeRefAerospikeStore.java @@ -12,17 +12,23 @@ * under the License. */ -package com.livetheoogway.crudstore.aerospike; +package com.livetheoogway.crudstore.aerospike.stores; import com.aerospike.client.IAerospikeClient; +import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; +import com.livetheoogway.crudstore.aerospike.AerospikeStore; +import com.livetheoogway.crudstore.aerospike.ErrorHandler; +import com.livetheoogway.crudstore.aerospike.NamespaceSet; +import com.livetheoogway.crudstore.core.Id; -public class TestAerospikeStoreReplace extends AerospikeStore { +public class TestTypeRefAerospikeStore extends AerospikeStore { - protected TestAerospikeStoreReplace(final IAerospikeClient client, + public TestTypeRefAerospikeStore(final IAerospikeClient client, final NamespaceSet namespaceSet, final ObjectMapper mapper, - final ErrorHandler errorHandler) { - super(client, namespaceSet, mapper, TestData.class, errorHandler, false); + final TypeReference typeReference, + final ErrorHandler errorHandler) { + super(client, namespaceSet, mapper, typeReference, errorHandler); } } diff --git a/aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/stores/UserAerospikeReplaceStore.java b/aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/stores/UserAerospikeReplaceStore.java new file mode 100644 index 0000000..658fad9 --- /dev/null +++ b/aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/stores/UserAerospikeReplaceStore.java @@ -0,0 +1,32 @@ +/* + * Copyright 2022. Live the Oogway, Tushar Naik + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either + * express or implied. See the License for the specific language governing permissions and limitations + * under the License. + */ + +package com.livetheoogway.crudstore.aerospike.stores; + +import com.aerospike.client.IAerospikeClient; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.livetheoogway.crudstore.aerospike.AerospikeStore; +import com.livetheoogway.crudstore.aerospike.ErrorHandler; +import com.livetheoogway.crudstore.aerospike.NamespaceSet; +import com.livetheoogway.crudstore.aerospike.data.UserData; + +public class UserAerospikeReplaceStore extends AerospikeStore { + + public UserAerospikeReplaceStore(final IAerospikeClient client, + final NamespaceSet namespaceSet, + final ObjectMapper mapper, + final ErrorHandler errorHandler) { + super(client, namespaceSet, mapper, UserData.class, errorHandler, false); + } +} diff --git a/aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/TestAerospikeStore.java b/aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/stores/UserAerospikeStore.java similarity index 59% rename from aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/TestAerospikeStore.java rename to aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/stores/UserAerospikeStore.java index 80d6bde..766e7e8 100644 --- a/aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/TestAerospikeStore.java +++ b/aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/stores/UserAerospikeStore.java @@ -12,22 +12,26 @@ * under the License. */ -package com.livetheoogway.crudstore.aerospike; +package com.livetheoogway.crudstore.aerospike.stores; import com.aerospike.client.IAerospikeClient; import com.fasterxml.jackson.databind.ObjectMapper; +import com.livetheoogway.crudstore.aerospike.AerospikeStore; +import com.livetheoogway.crudstore.aerospike.ErrorHandler; +import com.livetheoogway.crudstore.aerospike.NamespaceSet; +import com.livetheoogway.crudstore.aerospike.data.UserData; -public class TestAerospikeStore extends AerospikeStore { +public class UserAerospikeStore extends AerospikeStore { - protected TestAerospikeStore(final IAerospikeClient client, + public UserAerospikeStore(final IAerospikeClient client, final NamespaceSet namespaceSet, final ObjectMapper mapper, - final ErrorHandler errorHandler) { - super(client, namespaceSet, mapper, TestData.class, errorHandler); + final ErrorHandler errorHandler) { + super(client, namespaceSet, mapper, UserData.class, errorHandler); } @Override - public boolean isValidDataItem(final TestData testData) { + public boolean isValidDataItem(final UserData userData) { return true; } } diff --git a/aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/util/DataUtils.java b/aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/util/DataUtils.java new file mode 100644 index 0000000..4230fbf --- /dev/null +++ b/aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/util/DataUtils.java @@ -0,0 +1,32 @@ +package com.livetheoogway.crudstore.aerospike.util; + +import com.livetheoogway.crudstore.aerospike.data.ProfileData; +import com.livetheoogway.crudstore.aerospike.data.UserData; +import lombok.experimental.UtilityClass; + +import java.util.Random; + +@UtilityClass +public class DataUtils { + private static final Random RANDOM = new Random(System.currentTimeMillis()); + + public UserData generateTestData() { + return generateTestData("1", "me", RANDOM.nextInt(100)); + } + + public UserData generateTestData(String id) { + return generateTestData(id, "me too", RANDOM.nextInt(100)); + } + + public ProfileData generateProfileData() { + return new ProfileData<>("1", generateTestData("1", "me", RANDOM.nextInt(100))); + } + + public ProfileData generateProfileData(String id) { + return new ProfileData<>(id, generateTestData(id, "me too", RANDOM.nextInt(100))); + } + + public UserData generateTestData(String id, String name, int age) { + return new UserData(id, name, age); + } +} diff --git a/aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/util/TestUtils.java b/aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/util/TestUtils.java new file mode 100644 index 0000000..3d54e7d --- /dev/null +++ b/aerospike-crud-store/src/test/java/com/livetheoogway/crudstore/aerospike/util/TestUtils.java @@ -0,0 +1,63 @@ +package com.livetheoogway.crudstore.aerospike.util; + +import com.livetheoogway.crudstore.aerospike.AerospikeStore; +import com.livetheoogway.crudstore.core.Id; +import lombok.experimental.UtilityClass; + +import java.util.List; +import java.util.Map; +import java.util.Optional; +import java.util.function.BiFunction; +import java.util.function.Supplier; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +@UtilityClass +public class TestUtils { + + public void testStoreOperations(final AerospikeStore store, + final Supplier initialData, + final Supplier updatedData, + final Supplier anotherData, + final Supplier unknownData, + final BiFunction, Boolean> validator) { + + /* put some data */ + final T data = initialData.get(); + store.create(data); + + /* get it back */ + final var result = store.get(data.id()); + assertTrue(validator.apply(data, result)); + + /* get on unknown id */ + assertFalse(store.get("unknown").isPresent()); + + /* update existing data */ + final var updated = updatedData.get(); + store.update(updated); + final var updatedResult = store.get(updated.id()); + assertTrue(validator.apply(updated, updatedResult)); + + /* update unknown id */ + assertThrows(RuntimeException.class, () -> store.update(unknownData.get())); + + /* create already existing id */ + assertThrows(RuntimeException.class, () -> store.create(data)); + + /* get bulk */ + final T another = anotherData.get(); + store.create(another); + final Map resultMap = store.get(List.of(updated.id(), another.id())); + assertTrue(resultMap.containsKey(updated.id())); + assertTrue(resultMap.containsKey(another.id())); + assertEquals(2, resultMap.size()); + + /* list */ + final List result2 = store.list(); + assertEquals(2, result2.size()); + } +} diff --git a/crud-store-core/pom.xml b/crud-store-core/pom.xml index 48a43af..11bfb2b 100644 --- a/crud-store-core/pom.xml +++ b/crud-store-core/pom.xml @@ -5,7 +5,7 @@ crud-store com.livetheoogway.crudstore - 1.2.3 + 1.2.4 4.0.0 diff --git a/pom.xml b/pom.xml index 6d8603b..f06913e 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.livetheoogway.crudstore crud-store pom - 1.2.3 + 1.2.4 crud-store