Skip to content

Commit

Permalink
Merge pull request #18 from livetheoogway/issue-16
Browse files Browse the repository at this point in the history
Added more tests for typeref based initialization
  • Loading branch information
Tushar-Naik authored Aug 28, 2023
2 parents 65138c6 + d43fcfd commit 2cdfbdd
Show file tree
Hide file tree
Showing 13 changed files with 255 additions and 103 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ public class MyAerospikeStore extends AerospikeStore<TestData> {
}

@Override
protected boolean isValidDataItem(final TestData testData) {
protected boolean isValidDataItem(final TestData userData) {
return true; // you may do additional checks here
}
}
Expand Down
8 changes: 7 additions & 1 deletion aerospike-crud-store/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<parent>
<artifactId>crud-store</artifactId>
<groupId>com.livetheoogway.crudstore</groupId>
<version>1.2.3</version>
<version>1.2.4</version>
</parent>
<modelVersion>4.0.0</modelVersion>

Expand Down Expand Up @@ -68,5 +68,11 @@
<version>${junit.mockito.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.java.dev.jna</groupId>
<artifactId>jna</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -47,7 +53,7 @@

class AerospikeStoreTest {
private static AerospikeContainer aerospikeContainer;
private static AerospikeStore<TestData> store;
private static AerospikeStore<UserData> store;
private static AerospikeClient aerospikeClient;

@BeforeAll
Expand All @@ -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<>());
Expand All @@ -71,7 +77,7 @@ static void afterAll() {
aerospikeContainer.stop();
}

private static void validateTestData(final Optional<TestData> testData, final TestData meToo) {
private static void validateTestData(final Optional<UserData> testData, final UserData meToo) {
assertTrue(testData.isPresent());
assertEquals(meToo.id(), testData.get().id());
assertEquals(meToo.name(), testData.get().name());
Expand All @@ -81,57 +87,61 @@ private static void validateTestData(final Optional<TestData> testData, final Te
@Test
void testStoreOperations() {

/* put some data */
final var me = DataUtils.generateTestData();
store.create(me);

/* get it back */
Optional<TestData> 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<String, TestData> 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<TestData> 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<ProfileData<UserData>> store
= new TestTypeRefAerospikeStore<>(aerospikeClient,
new NamespaceSet("test", "test-2"),
new ObjectMapper(),
new TypeReference<>() {},
new DefaultErrorHandler<>());

final ProfileData<UserData> 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 */
final var me = DataUtils.generateTestData("11");
storeWithReplace.create(me);

/* get it back */
Optional<TestData> testData = storeWithReplace.get(me.id());
Optional<UserData> testData = storeWithReplace.get(me.id());
validateTestData(testData, me);

/* get on unknown id */
Expand All @@ -152,7 +162,7 @@ void testStoreDeleteExistingKeySuccessful() {
store.create(me);

/* get it back */
Optional<TestData> testData = store.get(me.id());
Optional<UserData> testData = store.get(me.id());
validateTestData(testData, me);

/* delete it */
Expand All @@ -168,10 +178,10 @@ void testStoreDeleteExistingKeySuccessful() {
@Test
void testHandlerForJsonSerializationExceptionDuringCreate() throws JsonProcessingException {
final ObjectMapper mapper = mock(ObjectMapper.class);
final ErrorHandler<TestData> errorHandler = mock(ErrorHandler.class);
final ErrorHandler<UserData> 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());
Expand All @@ -183,55 +193,55 @@ void testHandlerForJsonSerializationExceptionDuringCreate() throws JsonProcessin
void testHandlerForJsonSerializationExceptionDuringGet() throws JsonProcessingException {
final ObjectMapper validObjectMapper = new ObjectMapper();
final ObjectMapper mapper = mock(ObjectMapper.class);
final ErrorHandler<TestData> errorHandler = mock(ErrorHandler.class);
final ErrorHandler<UserData> 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<TestData> result = newStore.get(testData.id());
final Optional<UserData> 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<String, TestData> result2 = newStore.get(List.of(testData.id(), anotherTestData.id()));
final Map<String, UserData> 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<TestData> errorHandler = mock(ErrorHandler.class);
final TestAerospikeStore newStore
= new TestAerospikeStore(aerospikeClient,
final ErrorHandler<UserData> 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<TestData> result = newStore.get(testData.id());
final Optional<UserData> result = newStore.get(testData.id());
assertFalse(result.isPresent());
Mockito.verify(errorHandler, Mockito.times(1)).onNoRecordFound(any());

final var anotherTestData = DataUtils.generateTestData("2");
final Map<String, TestData> result2 = newStore.get(List.of(testData.id(), anotherTestData.id()));
final Map<String, UserData> 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);
when(newASClient.getWritePolicyDefault()).thenReturn(new WritePolicy());
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<TestData> errorHandler = mock(ErrorHandler.class);
final TestAerospikeStore newStore
= new TestAerospikeStore(newASClient,
final ErrorHandler<UserData> errorHandler = mock(ErrorHandler.class);
final UserAerospikeStore newStore
= new UserAerospikeStore(newASClient,
new NamespaceSet("test", "no-record-error-2"),
new ObjectMapper(), errorHandler);

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -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<T>(
String id,
T profile) implements Id {
}
Original file line number Diff line number Diff line change
@@ -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 {
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<TestData> {
public class TestTypeRefAerospikeStore<T extends Id> extends AerospikeStore<T> {

protected TestAerospikeStoreReplace(final IAerospikeClient client,
public TestTypeRefAerospikeStore(final IAerospikeClient client,
final NamespaceSet namespaceSet,
final ObjectMapper mapper,
final ErrorHandler<TestData> errorHandler) {
super(client, namespaceSet, mapper, TestData.class, errorHandler, false);
final TypeReference<T> typeReference,
final ErrorHandler<T> errorHandler) {
super(client, namespaceSet, mapper, typeReference, errorHandler);
}
}
Original file line number Diff line number Diff line change
@@ -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<UserData> {

public UserAerospikeReplaceStore(final IAerospikeClient client,
final NamespaceSet namespaceSet,
final ObjectMapper mapper,
final ErrorHandler<UserData> errorHandler) {
super(client, namespaceSet, mapper, UserData.class, errorHandler, false);
}
}
Loading

0 comments on commit 2cdfbdd

Please sign in to comment.