/* * Copyright 2016 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.xml; import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Matchers.isA; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.Collections; import java.util.Map; import java.util.Optional; import org.apache.geode.cache.GemFireCache; import org.apache.geode.cache.lucene.LuceneIndex; import org.apache.geode.cache.lucene.LuceneService; import org.apache.lucene.analysis.Analyzer; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.springframework.beans.BeansException; import org.springframework.beans.factory.FactoryBean; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringRunner; /** * Unit tests for the {@link LuceneServiceParser} and {@link LuceneIndexParser}. * * @author John Blum * @see org.junit.Test * @see org.junit.runner.RunWith * @see org.springframework.test.context.ContextConfiguration * @see org.springframework.test.context.junit4.SpringRunner * @since 1.1.0 */ @RunWith(SpringRunner.class) @ContextConfiguration @SuppressWarnings("unused") public class LuceneNamespaceUnitTests { private static final String[] EMPTY_STRING_ARRAY = {}; @Autowired private LuceneService luceneService; @Autowired @Qualifier("IndexOne") private LuceneIndex luceneIndexOne; @Autowired @Qualifier("IndexTwo") private LuceneIndex luceneIndexTwo; @Autowired @Qualifier("IndexThree") private LuceneIndex luceneIndexThree; @Autowired @Qualifier("IndexFour") private LuceneIndex luceneIndexFour; protected void assertLuceneIndex(LuceneIndex index, String name, String regionPath) { assertThat(index).isNotNull(); assertThat(index.getName()).isEqualTo(name); assertThat(index.getRegionPath()).isEqualTo(regionPath); } protected void assertLuceneIndexWithFieldAnalyzers(LuceneIndex index, String name, String regionPath, String... keys) { assertLuceneIndex(index, name, regionPath); assertThat(index.getFieldNames()).isEmpty(); assertThat(index.getFieldAnalyzers()).hasSize(keys.length); assertThat(index.getFieldAnalyzers()).containsKeys(keys); } protected void assertLuceneIndexWithFields(LuceneIndex index, String name, String regionPath, String... fieldNames) { assertLuceneIndex(index, name, regionPath); assertThat(index.getFieldAnalyzers()).isEmpty(); assertThat(index.getFieldNames()).contains(fieldNames); } @Test @SuppressWarnings({ "deprecation", "unchecked" }) public void luceneServiceConfigurationAndInteractionsAreCorrect() { assertThat(this.luceneService).isNotNull(); verify(this.luceneService, times(1)) .createIndex(eq("IndexOne"), eq("/Example"), eq("fieldOne"), eq("fieldTwo")); verify(this.luceneService, times(1)) .createIndex(eq("IndexTwo"), eq("/AnotherExample"), isA(Map.class)); verify(this.luceneService, never()).destroyIndex(any(LuceneIndex.class)); } @Test public void luceneIndexOneIsConfiguredCorrectly() { assertLuceneIndexWithFields(this.luceneIndexOne, "IndexOne", "/Example", "fieldOne", "fieldTwo"); } @Test public void luceneIndexTwoIsConfiguredCorrectly() { assertLuceneIndexWithFieldAnalyzers(this.luceneIndexTwo, "IndexTwo", "/AnotherExample", "fieldOne", "fieldTwo"); } @Test public void luceneIndexThreeIsConfiguredCorrectly() { assertLuceneIndexWithFields(this.luceneIndexThree, "IndexThree", "/Example", "singleField"); } @Test public void luceneIndexFourIsConfiguredCorrectly() { assertLuceneIndexWithFieldAnalyzers(this.luceneIndexFour, "IndexFour", "/YetAnotherExample", "singleField"); } public static class LuceneNamespaceUnitTestsBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException { beanFactory.getBeanDefinition("luceneService") .setBeanClassName(MockLuceneServiceFactoryBean.class.getName()); } } public static class MockLuceneServiceFactoryBean implements FactoryBean<LuceneService>, InitializingBean { @SuppressWarnings("all") private GemFireCache gemfireCache; private LuceneService luceneService; @Override public void afterPropertiesSet() throws Exception { assertThat(this.gemfireCache).describedAs("GemFireCache must not be null").isNotNull(); } @Override @SuppressWarnings("unchecked") public LuceneService getObject() throws Exception { return Optional.ofNullable(this.luceneService).orElseGet(() -> { this.luceneService = mock(LuceneService.class); Answer<LuceneIndex> mockLuceneIndex = newMockLuceneIndex(this.luceneService); doAnswer(mockLuceneIndex).when(this.luceneService) .createIndex(anyString(), anyString(), (String[]) any()); doAnswer(mockLuceneIndex).when(this.luceneService) .createIndex(anyString(), anyString(), isA(Map.class)); return this.luceneService; }); } @SuppressWarnings("unchecked") private Answer<LuceneIndex> newMockLuceneIndex(LuceneService mockLuceneService) { return (invocationOnMock) -> { String indexName = invocationOnMock.getArgument(0); String regionPath = invocationOnMock.getArgument(1); LuceneIndex mockLuceneIndex = mock(LuceneIndex.class, indexName); when(mockLuceneIndex.getName()).thenReturn(indexName); when(mockLuceneIndex.getRegionPath()).thenReturn(regionPath); if (invocationOnMock.getArguments().length > 2) { Object fields = invocationOnMock.getArgument(2); if (fields instanceof Map) { when(mockLuceneIndex.getFieldAnalyzers()).thenReturn((Map<String, Analyzer>) fields); when(mockLuceneIndex.getFieldNames()).thenReturn(EMPTY_STRING_ARRAY); } else { when(mockLuceneIndex.getFieldAnalyzers()).thenReturn(Collections.emptyMap()); when(mockLuceneIndex.getFieldNames()).thenReturn(extractFields(invocationOnMock)); } } when(mockLuceneService.getIndex(eq(indexName), eq(regionPath))).thenReturn(mockLuceneIndex); return mockLuceneIndex; }; } private String[] asStringArray(Object fields) { return (fields instanceof String[] ? (String[]) fields : String.valueOf(fields).split(", ")); } @SuppressWarnings("all") private String[] extractFields(InvocationOnMock invocationOnMock) { String[] fields = new String[invocationOnMock.getArguments().length - 2]; System.arraycopy(invocationOnMock.getArguments(), 2, fields, 0, fields.length); return fields; } @Override public Class<?> getObjectType() { return Optional.ofNullable(this.luceneService).<Class<?>>map(LuceneService::getClass) .orElse(LuceneService.class); } public void setCache(GemFireCache gemfireCache) { this.gemfireCache = gemfireCache; } } public static class MockAnalyzerFactoryBean implements FactoryBean<Analyzer> { @SuppressWarnings("unused") private Analyzer analyzer; private String name; @Override public Analyzer getObject() throws Exception { return Optional.ofNullable(this.analyzer).orElseGet(() -> this.analyzer = mock(Analyzer.class, getName())); } @Override public Class<?> getObjectType() { return Optional.ofNullable(this.analyzer).<Class<?>>map(Analyzer::getClass).orElse(Analyzer.class); } public void setName(String name) { this.name = name; } public String getName() { return this.name; } } }