DATAGEODE-102 - Add support for enforcing Lucene Index creation before Region creation.

This commit is contained in:
John Blum
2018-05-03 23:07:30 -07:00
parent d16bbc8d28
commit dc1e867bd4
11 changed files with 847 additions and 59 deletions

View File

@@ -0,0 +1,139 @@
/*
* Copyright 2018 the original author or authors.
*
* 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 org.springframework.data.gemfire.config.support;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CopyOnWriteArrayList;
import org.apache.geode.cache.Region;
import org.apache.shiro.util.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.data.gemfire.RegionFactoryBean;
import org.springframework.data.gemfire.test.mock.context.GemFireMockObjectsApplicationContextInitializer;
import org.springframework.lang.Nullable;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringRunner;
/**
* Unit tests for {@link LuceneIndexRegionBeanFactoryPostProcessor}.
*
* @author John Blum
* @see org.junit.Test
* @see org.springframework.data.gemfire.config.support.LuceneIndexRegionBeanFactoryPostProcessor
* @since 2.1.0
*/
@RunWith(SpringRunner.class)
@ContextConfiguration(initializers = GemFireMockObjectsApplicationContextInitializer.class)
public class LuceneIndexRegionBeanFactoryPostProcessorIntegrationTests {
private static final List<String> beanNames = new CopyOnWriteArrayList<>();
@Autowired
private ApplicationContext applicationContext;
private BeanDefinition getBeanDefinition(String beanName) {
return Optional.ofNullable(this.applicationContext)
.filter(it -> it instanceof AbstractApplicationContext)
.map(it -> (AbstractApplicationContext) it)
.map(it -> it.getBeanFactory())
.map(beanFactory -> beanFactory.getBeanDefinition(beanName))
.orElse(null);
}
@Test
public void regionLuceneIndexAndDiskStoreBeanDependenciesAreCorrect() {
BeanDefinition mockDiskStore = getBeanDefinition("MockDiskStore");
assertThat(mockDiskStore).isNotNull();
assertThat(nullSafeArray(mockDiskStore.getDependsOn(), String.class))
.doesNotContain("BookTitleLuceneIndex", "ContractDescriptionLuceneIndex");
BeanDefinition bookTitleLuceneIndex = getBeanDefinition("BookTitleLuceneIndex");
assertThat(bookTitleLuceneIndex).isNotNull();
assertThat(nullSafeArray(bookTitleLuceneIndex.getDependsOn(), String.class))
.doesNotContain("Books", "BookTitleLuceneIndex", "ContractDescriptionLuceneIndex");
BeanDefinition contractDescriptionLuceneIndex = getBeanDefinition("ContractDescriptionLuceneIndex");
assertThat(contractDescriptionLuceneIndex).isNotNull();
assertThat(nullSafeArray(contractDescriptionLuceneIndex.getDependsOn(), String.class))
.doesNotContain("Contracts", "BookTitleLuceneIndex", "ContractDescriptionLuceneIndex");
BeanDefinition booksRegion = getBeanDefinition("Books");
assertThat(booksRegion).isNotNull();
assertThat(booksRegion.getDependsOn()).contains("BookTitleLuceneIndex");
assertThat(booksRegion.getDependsOn()).doesNotContain("ContractDescriptionLuceneIndex");
BeanDefinition contractsRegion = getBeanDefinition("Contracts");
assertThat(contractsRegion).isNotNull();
assertThat(contractsRegion.getDependsOn()).contains("ContractDescriptionLuceneIndex");
assertThat(contractsRegion.getDependsOn()).doesNotContain("BookTitleLuceneIndex");
BeanDefinition peopleRegion = getBeanDefinition("People");
assertThat(peopleRegion).isNotNull();
assertThat(nullSafeArray(peopleRegion.getDependsOn(), String.class))
.doesNotContain("BookTitleLuceneIndex", "ContractDescriptionLucenenIndex");
}
@Test
public void gemfireBeanProcessingOrderIsCorrect() {
assertThat(beanNames.indexOf("BookTitleLuceneIndex")).isLessThan(beanNames.indexOf("Books"));
assertThat(beanNames.indexOf("ContractDescriptionLuceneIndex")).isLessThan(beanNames.indexOf("Contracts"));
}
static class BeanProcessingOrderRecordingBeanPostProcessor implements BeanPostProcessor {
@Nullable @Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (isRegionBean(bean)) {
Assert.isTrue(!"Books".equals(beanName) || beanNames.contains("BookTitleLuceneIndex"),
"Expected [BookTitleLuceneIndex] to already exist");
Assert.isTrue(!"Contracts".equals(beanName) || beanNames.contains("ContractDescriptionLuceneIndex"),
"Expected [ContractDescriptionLuceneIndex] to already exist");
}
if (!beanNames.contains(beanName)) {
beanNames.add(beanName);
}
return bean;
}
private boolean isRegionBean(Object bean) {
return bean instanceof Region || bean instanceof RegionFactoryBean;
}
}
}

View File

@@ -31,6 +31,7 @@ import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.when;
import static org.springframework.data.gemfire.util.ArrayUtils.nullSafeArray;
import static org.springframework.data.gemfire.util.CollectionUtils.asSet;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeMap;
import static org.springframework.data.gemfire.util.CollectionUtils.nullSafeSet;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.NOT_SUPPORTED;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalArgumentException;
@@ -55,6 +56,7 @@ import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
@@ -97,6 +99,13 @@ import org.apache.geode.cache.client.Pool;
import org.apache.geode.cache.client.PoolFactory;
import org.apache.geode.cache.control.ResourceManager;
import org.apache.geode.cache.execute.RegionFunctionContext;
import org.apache.geode.cache.lucene.LuceneIndex;
import org.apache.geode.cache.lucene.LuceneIndexFactory;
import org.apache.geode.cache.lucene.LuceneQuery;
import org.apache.geode.cache.lucene.LuceneQueryFactory;
import org.apache.geode.cache.lucene.LuceneQueryProvider;
import org.apache.geode.cache.lucene.LuceneSerializer;
import org.apache.geode.cache.lucene.LuceneService;
import org.apache.geode.cache.query.CqAttributes;
import org.apache.geode.cache.query.CqQuery;
import org.apache.geode.cache.query.Index;
@@ -118,6 +127,7 @@ import org.apache.geode.distributed.DistributedMember;
import org.apache.geode.distributed.DistributedSystem;
import org.apache.geode.internal.concurrent.ConcurrentHashSet;
import org.apache.geode.pdx.PdxSerializer;
import org.apache.lucene.analysis.Analyzer;
import org.mockito.ArgumentMatchers;
import org.mockito.stubbing.Answer;
import org.springframework.data.gemfire.IndexType;
@@ -277,6 +287,20 @@ public abstract class GemFireMockObjectsSupport extends MockObjectsSupport {
}
}
private static <T> T doSafeOperation(ExceptionThrowingOperation<T> operation) {
return doSafeOperation(operation, null);
}
private static <T> T doSafeOperation(ExceptionThrowingOperation<T> operation, T defaultValue) {
try {
return operation.doExceptionThrowingOperation();
}
catch (Exception ignore) {
return defaultValue;
}
}
/**
* Determines whether the given {@link Region} is a root {@link Region}.
*
@@ -400,6 +424,19 @@ public abstract class GemFireMockObjectsSupport extends MockObjectsSupport {
newIllegalStateException("RegionAttributes with ID [%s] cannot be found", regionAttributesId));
}
private static <T> T rethrowAsRuntimeException(ExceptionThrowingOperation<T> operation) {
try {
return operation.doExceptionThrowingOperation();
}
catch (RuntimeException cause) {
throw cause;
}
catch (Exception cause) {
throw new RuntimeException(cause);
}
}
/**
* Converts the given {@link String Region name} into a proper {@link Region#getName() Region name}.
*
@@ -1772,6 +1809,204 @@ public abstract class GemFireMockObjectsSupport extends MockObjectsSupport {
return mock(IndexStatistics.class, mockObjectIdentifier(name));
}
public static LuceneIndexFactory mockLuceneIndexFactory() {
return mockLuceneIndexFactory(null);
}
private static LuceneIndexFactory mockLuceneIndexFactory(Map<LuceneIndexKey, LuceneIndex> luceneIndexes) {
LuceneIndexFactory mockLuceneIndexFactory = mock(LuceneIndexFactory.class);
AtomicReference<LuceneSerializer> luceneSerializerReference = new AtomicReference<>(null);
Map<String, Analyzer> fieldAnalyzers = new ConcurrentHashMap<>();
Set<String> fields = new CopyOnWriteArraySet<>();
when(mockLuceneIndexFactory.addField(anyString())).thenAnswer(invocation -> {
String fieldName = invocation.getArgument(0);
fields.add(fieldName);
return mockLuceneIndexFactory;
});
when(mockLuceneIndexFactory.addField(anyString(), any(Analyzer.class))).thenAnswer(invocation -> {
String fieldName = invocation.getArgument(0);
Analyzer analyzer = invocation.getArgument(1);
fieldAnalyzers.put(fieldName, analyzer);
return mockLuceneIndexFactory;
});
when(mockLuceneIndexFactory.setFields(ArgumentMatchers.<String[]>any())).thenAnswer(invocation -> {
Object[] fieldsArgument = invocation.getArguments();
fields.clear();
Arrays.stream(nullSafeArray(fieldsArgument, Object.class))
.filter(field -> field instanceof String)
.map(String::valueOf)
.forEach(fields::add);
return mockLuceneIndexFactory;
});
when(mockLuceneIndexFactory.setFields(any(Map.class))).thenAnswer(invocation -> {
Map<String, Analyzer> fieldAnalyzersArgument = invocation.getArgument(0);
fieldAnalyzers.clear();
fieldAnalyzers.putAll(nullSafeMap(fieldAnalyzers));
return mockLuceneIndexFactory;
});
when(mockLuceneIndexFactory.setLuceneSerializer(any(LuceneSerializer.class))).thenAnswer(invocation -> {
Optional.ofNullable(invocation.<LuceneSerializer>getArgument(0))
.map(luceneSerializer -> {
luceneSerializerReference.set(luceneSerializer);
return luceneSerializer;
})
.orElseGet(() -> {
luceneSerializerReference.set(null);
return null;
});
return mockLuceneIndexFactory;
});
doAnswer(invocation -> {
String indexName = invocation.getArgument(0);
String regionPath = invocation.getArgument(1);
LuceneIndexKey key = LuceneIndexKey.of(indexName, regionPath);
LuceneIndex mockLuceneIndex = mock(LuceneIndex.class, key.toString());
when(mockLuceneIndex.getFieldAnalyzers()).thenReturn(Collections.unmodifiableMap(fieldAnalyzers));
when(mockLuceneIndex.getFieldNames()).thenAnswer(in -> fields.toArray(new String[fields.size()]));
when(mockLuceneIndex.getLuceneSerializer()).thenAnswer(in -> luceneSerializerReference.get());
when(mockLuceneIndex.getName()).thenReturn(indexName);
when(mockLuceneIndex.getRegionPath()).thenReturn(regionPath);
Optional.ofNullable(luceneIndexes).ifPresent(it -> it.put(key, mockLuceneIndex));
return null;
}).when(mockLuceneIndexFactory).create(anyString(), anyString());
return mockLuceneIndexFactory;
}
public static LuceneQueryFactory mockLuceneQueryFactory() {
LuceneQueryFactory mockLuceneQueryFactory = mock(LuceneQueryFactory.class);
AtomicInteger limit = new AtomicInteger(LuceneQueryFactory.DEFAULT_LIMIT);
AtomicInteger pageSize = new AtomicInteger(LuceneQueryFactory.DEFAULT_PAGESIZE);
when(mockLuceneQueryFactory.setLimit(anyInt())).thenAnswer(invocation -> {
limit.set(invocation.getArgument(0));
return mockLuceneQueryFactory;
});
when(mockLuceneQueryFactory.setPageSize(anyInt())).thenAnswer(invocation -> {
pageSize.set(invocation.getArgument(0));
return mockLuceneQueryFactory;
});
when(mockLuceneQueryFactory.create(anyString(), anyString(), any(LuceneQueryProvider.class)))
.thenAnswer(invocation -> mockLuceneQuery(limit.get(), pageSize.get()));
when(mockLuceneQueryFactory.create(anyString(), anyString(), anyString(), anyString()))
.thenAnswer(invocation -> mockLuceneQuery(limit.get(), pageSize.get()));
return mockLuceneQueryFactory;
}
private static LuceneQuery mockLuceneQuery(int limit, int pageSize) {
LuceneQuery mockLuceneQuery = mock(LuceneQuery.class);
when(mockLuceneQuery.getLimit()).thenReturn(limit);
when(mockLuceneQuery.getPageSize()).thenReturn(pageSize);
doSafeOperation(() -> when(mockLuceneQuery.findKeys())
.thenReturn(Collections.emptySet()), Collections.emptySet());
rethrowAsRuntimeException(() -> when(mockLuceneQuery.findPages())
.thenThrow(newUnsupportedOperationException("Operation Not Supported!")));
doSafeOperation(() -> when(mockLuceneQuery.findResults())
.thenReturn(Collections.emptyList()), Collections.emptyList());
doSafeOperation(() -> when(mockLuceneQuery.findValues())
.thenReturn(Collections.emptyList()), Collections.emptyList());
return mockLuceneQuery;
}
public static LuceneService mockLuceneService(Cache mockCache) {
LuceneService mockLuceneService = mock(LuceneService.class);
Map<LuceneIndexKey, LuceneIndex> luceneIndexes = new ConcurrentHashMap<>();
when(mockLuceneService.createIndexFactory())
.thenAnswer(invocation -> mockLuceneIndexFactory(luceneIndexes));
when(mockLuceneService.createLuceneQueryFactory())
.thenAnswer(invocation -> mockLuceneQueryFactory());
doAnswer(invocation -> {
String indexName = invocation.getArgument(0);
String regionName = invocation .getArgument(1);
luceneIndexes.remove(LuceneIndexKey.of(indexName, regionName));
return null;
}).when(mockLuceneService).destroyIndex(anyString(), anyString());
doAnswer(invocation -> {
String regionPath = invocation.getArgument(0);
luceneIndexes.keySet().stream().filter(key -> key.getRegionPath().equals(regionPath))
.collect(Collectors.toSet()).forEach(key -> luceneIndexes.remove(key));
return null;
}).when(mockLuceneService).destroyIndexes(anyString());
when(mockLuceneService.getAllIndexes()).thenAnswer(invocation ->
Collections.unmodifiableCollection(luceneIndexes.values()));
when(mockLuceneService.getCache()).thenReturn(mockCache);
when(mockLuceneService.getIndex(anyString(), anyString())).thenAnswer(invocation -> {
String indexName = invocation.getArgument(0);
String regionPath = invocation.getArgument(1);
return luceneIndexes.get(LuceneIndexKey.of(indexName, regionPath));
});
doSafeOperation(() ->
when(mockLuceneService.waitUntilFlushed(anyString(), anyString(), anyLong(), any(TimeUnit.class)))
.thenReturn(true));
return mockLuceneService;
}
@SuppressWarnings("unchecked")
public static <K, V> Region<K, V> mockRegion(RegionService regionService, String name,
RegionAttributes<K, V> regionAttributes) {
@@ -2550,7 +2785,78 @@ public abstract class GemFireMockObjectsSupport extends MockObjectsSupport {
return clientCacheFactorySpy;
}
protected interface ExceptionThrowingOperation<T> {
T doExceptionThrowingOperation() throws Exception;
}
protected interface IoExceptionThrowingOperation {
void doIo() throws IOException;
}
public static class LuceneIndexKey {
private final String indexName;
private final String regionPath;
public static LuceneIndexKey of(String indexName, Region<?, ?> region) {
Assert.notNull(region, "Region is required");
return of(indexName, region.getFullPath());
}
public static LuceneIndexKey of(String indexName, String regionPath) {
return new LuceneIndexKey(indexName, regionPath);
}
private LuceneIndexKey(String indexName, String regionPath) {
Assert.hasText(indexName, String.format("LuceneIndex name [%s] is required", indexName));
Assert.hasText(regionPath, String.format("Region path [%s] is required", regionPath));
this.indexName = indexName;
this.regionPath = regionPath;
}
protected String getIndexName() {
return this.indexName;
}
protected String getRegionPath() {
return this.regionPath;
}
@Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof LuceneIndexKey)) {
return false;
}
LuceneIndexKey that = (LuceneIndexKey) obj;
return this.getIndexName().equals(that.getIndexName())
&& this.getRegionPath().equals(that.getRegionPath());
}
@Override
public int hashCode() {
int hashValue = 17;
hashValue = 37 * hashValue + getIndexName().hashCode();
hashValue = 37 * hashValue + getRegionPath().hashCode();
return hashValue;
}
@Override
public String toString() {
return String.format("%1$s.%2$s", getRegionPath(), getIndexName());
}
}
}

View File

@@ -18,8 +18,12 @@
package org.springframework.data.gemfire.util;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -27,6 +31,7 @@ import static org.springframework.data.gemfire.util.ArrayUtils.asArray;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newIllegalStateException;
import static org.springframework.data.gemfire.util.RuntimeExceptionFactory.newRuntimeException;
import java.util.Collections;
import java.util.function.Function;
import java.util.function.Supplier;
@@ -35,6 +40,7 @@ import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
@@ -61,10 +67,12 @@ public class SpringUtilsUnitTests {
when(mockBeanDefinition.getDependsOn()).thenReturn(asArray("testBeanNameOne", "testBeanNameTwo"));
assertThat(SpringUtils.addDependsOn(mockBeanDefinition, "testBeanNameThree")).isSameAs(mockBeanDefinition);
assertThat(SpringUtils.addDependsOn(mockBeanDefinition, "testBeanNameThree"))
.isSameAs(mockBeanDefinition);
verify(mockBeanDefinition, times(1)).getDependsOn();
verify(mockBeanDefinition, times(1)).setDependsOn("testBeanNameOne", "testBeanNameTwo", "testBeanNameThree");
verify(mockBeanDefinition, times(1))
.setDependsOn("testBeanNameOne", "testBeanNameTwo", "testBeanNameThree");
}
@Test
@@ -72,7 +80,8 @@ public class SpringUtilsUnitTests {
when(mockBeanDefinition.getDependsOn()).thenReturn(null);
assertThat(SpringUtils.addDependsOn(mockBeanDefinition, "testBeanName")).isSameAs(mockBeanDefinition);
assertThat(SpringUtils.addDependsOn(mockBeanDefinition, "testBeanName"))
.isSameAs(mockBeanDefinition);
verify(mockBeanDefinition, times(1)).getDependsOn();
verify(mockBeanDefinition, times(1)).setDependsOn("testBeanName");
@@ -91,6 +100,69 @@ public class SpringUtilsUnitTests {
.setDependsOn("testBeanNameOne", "testBeanNameTwo", "testBeanNameThree", "testBeanNameFour");
}
@Test
public void getPropertyValueForExistingPropertyHavingValueReturnsValue() {
MutablePropertyValues propertyValues =
new MutablePropertyValues(Collections.singletonMap("testProperty", "testValue"));
when(mockBeanDefinition.getPropertyValues()).thenReturn(propertyValues);
assertThat(SpringUtils.getPropertyValue(mockBeanDefinition, "testProperty").orElse(null))
.isEqualTo("testValue");
verify(mockBeanDefinition, times(1)).getPropertyValues();
}
@Test
public void getPropertyValueForExistingPropertyHavingNullValueReturnsNull() {
MutablePropertyValues testPropertyValues = spy(new MutablePropertyValues());
PropertyValue testPropertyValue = spy(new PropertyValue("testProperty", null));
when(mockBeanDefinition.getPropertyValues()).thenReturn(testPropertyValues);
doReturn(testPropertyValue).when(testPropertyValues).getPropertyValue(anyString());
assertThat(SpringUtils.getPropertyValue(mockBeanDefinition, "testProperty").orElse(null))
.isNull();
verify(mockBeanDefinition, times(1)).getPropertyValues();
verify(testPropertyValues, times(1)).getPropertyValue(eq("testProperty"));
verify(testPropertyValue, times(1)).getValue();
}
@Test
public void getPropertyValueForNonExistingPropertyReturnsNull() {
MutablePropertyValues testPropertyValues = spy(new MutablePropertyValues());
when(mockBeanDefinition.getPropertyValues()).thenReturn(testPropertyValues);
assertThat(SpringUtils.getPropertyValue(mockBeanDefinition, "testProperty").orElse(null))
.isNull();
verify(mockBeanDefinition, times(1)).getPropertyValues();
verify(testPropertyValues, times(1)).getPropertyValue(eq("testProperty"));
}
@Test
public void getPropertyValueWithNullPropertyValuesReturnsNull() {
when(mockBeanDefinition.getPropertyValues()).thenReturn(null);
assertThat(SpringUtils.getPropertyValue(mockBeanDefinition, "testProperty").orElse(null))
.isNull();
verify(mockBeanDefinition, times(1)).getPropertyValues();
}
@Test
public void getPropertyValueWithNullBeanDefinitionReturnsNull() {
assertThat(SpringUtils.getPropertyValue(null, "testProperty").orElse(null))
.isNull();
}
@Test
@SuppressWarnings("all")
public void setBeanDefinitionPropertyReference() {
@@ -135,6 +207,7 @@ public class SpringUtilsUnitTests {
@Test
public void defaultIfEmptyReturnsValue() {
assertThat(SpringUtils.defaultIfEmpty("test", "DEFAULT")).isEqualTo("test");
assertThat(SpringUtils.defaultIfEmpty("abc123", "DEFAULT")).isEqualTo("abc123");
assertThat(SpringUtils.defaultIfEmpty("123", "DEFAULT")).isEqualTo("123");
@@ -147,6 +220,7 @@ public class SpringUtilsUnitTests {
@Test
public void defaultIfEmptyReturnsDefault() {
assertThat(SpringUtils.defaultIfEmpty(" ", "DEFAULT")).isEqualTo("DEFAULT");
assertThat(SpringUtils.defaultIfEmpty("", "DEFAULT")).isEqualTo("DEFAULT");
assertThat(SpringUtils.defaultIfEmpty(null, "DEFAULT")).isEqualTo("DEFAULT");
@@ -154,6 +228,7 @@ public class SpringUtilsUnitTests {
@Test
public void defaultIfNullReturnsValue() {
assertThat(SpringUtils.defaultIfNull(true, false)).isTrue();
assertThat(SpringUtils.defaultIfNull('x', 'A')).isEqualTo('x');
assertThat(SpringUtils.defaultIfNull(1, 2)).isEqualTo(1);
@@ -163,6 +238,7 @@ public class SpringUtilsUnitTests {
@Test
public void defaultIfNullReturnsDefault() {
assertThat(SpringUtils.defaultIfNull(null, false)).isFalse();
assertThat(SpringUtils.defaultIfNull(null, 'A')).isEqualTo('A');
assertThat(SpringUtils.defaultIfNull(null, 2)).isEqualTo(2);
@@ -173,6 +249,7 @@ public class SpringUtilsUnitTests {
@Test
@SuppressWarnings("unchecked")
public void defaultIfNullWithSupplierReturnsValue() {
Supplier<String> mockSupplier = mock(Supplier.class);
assertThat(SpringUtils.defaultIfNull("value", mockSupplier)).isEqualTo("value");
@@ -183,6 +260,7 @@ public class SpringUtilsUnitTests {
@Test
@SuppressWarnings("unchecked")
public void defaultIfNullWithSupplierReturnsSupplierValue() {
Supplier<String> mockSupplier = mock(Supplier.class);
when(mockSupplier.get()).thenReturn("supplier");
@@ -199,6 +277,7 @@ public class SpringUtilsUnitTests {
@Test
public void equalsIgnoreNullIsTrue() {
assertThat(SpringUtils.equalsIgnoreNull(null, null)).isTrue();
assertThat(SpringUtils.equalsIgnoreNull(true, true)).isTrue();
assertThat(SpringUtils.equalsIgnoreNull('x', 'x')).isTrue();
@@ -210,6 +289,7 @@ public class SpringUtilsUnitTests {
@Test
public void equalsIgnoreNullIsFalse() {
assertThat(SpringUtils.equalsIgnoreNull(null, "null")).isFalse();
assertThat(SpringUtils.equalsIgnoreNull(true, false)).isFalse();
assertThat(SpringUtils.equalsIgnoreNull('x', 'X')).isFalse();