/**
* Copyright (c) Codice Foundation
* <p>
* This is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser
* General Public License as published by the Free Software Foundation, either version 3 of the
* License, or any later version.
* <p>
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
* even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details. A copy of the GNU Lesser General Public License
* is distributed along with this program and can be found at
* <http://www.gnu.org/licenses/lgpl.html>.
*/
package ddf.catalog.federation.impl;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.geotools.filter.FilterFactoryImpl;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.Mockito;
import org.opengis.filter.FilterFactory;
import org.opengis.filter.sort.SortOrder;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.rule.PowerMockRule;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ddf.catalog.data.ContentType;
import ddf.catalog.data.Metacard;
import ddf.catalog.data.Result;
import ddf.catalog.data.defaultvalues.DefaultAttributeValueRegistryImpl;
import ddf.catalog.data.impl.MetacardImpl;
import ddf.catalog.federation.FederationException;
import ddf.catalog.federation.base.AbstractFederationStrategy;
import ddf.catalog.filter.proxy.builder.GeotoolsFilterBuilder;
import ddf.catalog.history.Historian;
import ddf.catalog.impl.CatalogFrameworkImpl;
import ddf.catalog.impl.FrameworkProperties;
import ddf.catalog.impl.MockDelayProvider;
import ddf.catalog.impl.QueryResponsePostProcessor;
import ddf.catalog.impl.operations.CreateOperations;
import ddf.catalog.impl.operations.DeleteOperations;
import ddf.catalog.impl.operations.MetacardFactory;
import ddf.catalog.impl.operations.OperationsCatalogStoreSupport;
import ddf.catalog.impl.operations.OperationsMetacardSupport;
import ddf.catalog.impl.operations.OperationsSecuritySupport;
import ddf.catalog.impl.operations.OperationsStorageSupport;
import ddf.catalog.impl.operations.QueryOperations;
import ddf.catalog.impl.operations.SourceOperations;
import ddf.catalog.impl.operations.UpdateOperations;
import ddf.catalog.operation.CreateResponse;
import ddf.catalog.operation.Query;
import ddf.catalog.operation.QueryRequest;
import ddf.catalog.operation.QueryResponse;
import ddf.catalog.operation.SourceResponse;
import ddf.catalog.operation.impl.CreateRequestImpl;
import ddf.catalog.operation.impl.QueryImpl;
import ddf.catalog.operation.impl.QueryRequestImpl;
import ddf.catalog.operation.impl.QueryResponseImpl;
import ddf.catalog.plugin.PostFederatedQueryPlugin;
import ddf.catalog.plugin.PreFederatedQueryPlugin;
import ddf.catalog.source.CatalogProvider;
import ddf.catalog.source.IngestException;
import ddf.catalog.source.Source;
import ddf.catalog.source.SourceUnavailableException;
import ddf.catalog.source.UnsupportedQueryException;
import ddf.catalog.util.impl.SourcePoller;
import ddf.catalog.util.impl.SourcePollerRunner;
@PrepareForTest(AbstractFederationStrategy.class)
public class FederationStrategyTest {
private static final long SHORT_TIMEOUT = 25;
private static final long LONG_TIMEOUT = TimeUnit.MINUTES.toMillis(1);
private static final Logger LOGGER =
LoggerFactory.getLogger(FederationStrategyTest.class.getName());
private FilterFactory filterFactory;
private ExecutorService executor;
private Query mockQuery;
@Rule
public PowerMockRule rule = new PowerMockRule();
@Before
public void setup() throws Exception {
mockQuery = mock(Query.class);
when(mockQuery.getTimeoutMillis()).thenReturn(LONG_TIMEOUT);
filterFactory = new FilterFactoryImpl();
refreshExecutor();
}
@After
public void finish() throws Exception {
killAndWaitForExecutor();
}
/**
* Tests that the framework properly times out using the default federation strategy.
*/
@Test
public void testQueryTimeout() throws Exception {
long queryDelay = 100;
MockDelayProvider provider = new MockDelayProvider("Provider",
"Provider",
"v1.0",
"DDF",
new HashSet<ContentType>(),
true,
new Date());
provider.setQueryDelayMillis(queryDelay);
// Mock register the provider in the container
SourcePollerRunner runner = new SourcePollerRunner();
SourcePoller poller = new SourcePoller(runner);
runner.bind(provider);
// Must have more than one thread or sleeps will block the monitor
SortedFederationStrategy fedStrategy = new SortedFederationStrategy(executor,
new ArrayList<>(),
new ArrayList<>());
FrameworkProperties props = new FrameworkProperties();
props.setCatalogProviders(Collections.singletonList(provider));
props.setFederationStrategy(fedStrategy);
props.setSourcePoller(poller);
props.setQueryResponsePostProcessor(mock(QueryResponsePostProcessor.class));
props.setFilterBuilder(new GeotoolsFilterBuilder());
props.setDefaultAttributeValueRegistry(new DefaultAttributeValueRegistryImpl());
OperationsSecuritySupport opsSecurity = new OperationsSecuritySupport();
MetacardFactory metacardFactory =
new MetacardFactory(props.getMimeTypeToTransformerMapper());
OperationsMetacardSupport opsMetacard = new OperationsMetacardSupport(props,
metacardFactory);
Historian historian = new Historian();
historian.setHistoryEnabled(false);
SourceOperations sourceOperations = new SourceOperations(props);
QueryOperations queryOperations = new QueryOperations(props,
sourceOperations,
opsSecurity,
opsMetacard);
OperationsStorageSupport opsStorage = new OperationsStorageSupport(sourceOperations,
queryOperations);
OperationsCatalogStoreSupport opsCatStore = new OperationsCatalogStoreSupport(props,
sourceOperations);
CreateOperations createOperations = new CreateOperations(props,
queryOperations,
sourceOperations,
opsSecurity,
opsMetacard,
opsCatStore,
opsStorage);
UpdateOperations updateOperations = new UpdateOperations(props,
queryOperations,
sourceOperations,
opsSecurity,
opsMetacard,
opsCatStore,
opsStorage);
DeleteOperations deleteOperations = new DeleteOperations(props,
queryOperations,
sourceOperations,
opsSecurity,
opsMetacard);
opsStorage.setHistorian(historian);
updateOperations.setHistorian(historian);
deleteOperations.setHistorian(historian);
deleteOperations.setOpsCatStoreSupport(opsCatStore);
CatalogFrameworkImpl framework = new CatalogFrameworkImpl(createOperations,
updateOperations,
deleteOperations,
queryOperations,
null,
null,
null);
sourceOperations.bind(provider);
List<Metacard> metacards = new ArrayList<Metacard>();
MetacardImpl newCard = new MetacardImpl();
newCard.setId(null);
metacards.add(newCard);
CreateResponse createResponse = null;
try {
try {
createResponse = framework.create(new CreateRequestImpl(metacards, null));
} catch (SourceUnavailableException e) {
long timeout = System.currentTimeMillis() + TimeUnit.SECONDS.toMillis(10);
//this is a hack because the unit test is flaky and should be removed once a better test is possible
while (System.currentTimeMillis() < timeout) {
Thread.sleep(1000);
try {
createResponse = framework.create(new CreateRequestImpl(metacards, null));
break;
} catch (SourceUnavailableException e1) {
//ignore
}
}
}
if (createResponse == null) {
fail();
}
} catch (IngestException e) {
fail();
}
assertEquals(createResponse.getCreatedMetacards()
.size(), provider.size());
for (Metacard curCard : createResponse.getCreatedMetacards()) {
assertNotNull(curCard.getId());
}
QueryImpl query = new QueryImpl(filterFactory.equals(filterFactory.property(Metacard.ID),
filterFactory.literal(createResponse.getCreatedMetacards()
.get(0)
.getId())));
query.setTimeoutMillis(SHORT_TIMEOUT);
query.setSortBy(new FilterFactoryImpl().sort(Result.RELEVANCE, SortOrder.ASCENDING));
QueryRequest fedQueryRequest = new QueryRequestImpl(query);
try {
QueryResponse response = framework.query(fedQueryRequest);
assertEquals("Timeout should happen before results return", 0, response.getHits());
} catch (UnsupportedQueryException e) {
fail();
} catch (FederationException e) {
LOGGER.error("Unexpected federation exception during test", e);
fail();
}
}
@Test
public void testNegativePageSizeQuery() throws Exception {
when(mockQuery.getPageSize()).thenReturn(-1);
QueryRequest fedQueryRequest = mock(QueryRequest.class);
when(fedQueryRequest.getQuery()).thenReturn(mockQuery);
Result mockResult = mock(Result.class);
SourceResponse mockResponse = mock(SourceResponse.class);
List<Result> results = Arrays.asList(mockResult);
when(mockResponse.getHits()).thenReturn((long) results.size());
when(mockResponse.getResults()).thenReturn(results);
CatalogProvider mockProvider = mock(CatalogProvider.class);
when(mockProvider.query(any(QueryRequest.class))).thenReturn(mockResponse);
when(mockProvider.getId()).thenReturn("mock provider");
List<Source> sources = new ArrayList<Source>();
sources.add(mockProvider);
SortedFederationStrategy sortedStrategy = new SortedFederationStrategy(executor,
new ArrayList<PreFederatedQueryPlugin>(),
new ArrayList<PostFederatedQueryPlugin>());
QueryResponse fedResponse = sortedStrategy.federate(sources, fedQueryRequest);
assertEquals(1,
fedResponse.getResults()
.size());
FifoFederationStrategy fifoStrategy = new FifoFederationStrategy(executor,
new ArrayList<PreFederatedQueryPlugin>(),
new ArrayList<PostFederatedQueryPlugin>());
fedResponse = fifoStrategy.federate(sources, fedQueryRequest);
assertEquals(1,
fedResponse.getResults()
.size());
}
/**
* Verify that a modified version of the mockQuery passed is used by the sources.
* <p>
* Special results handling done by OffsetResultsHandler.
*/
@Test
public void testFederateTwoSourcesOffsetTwoPageSizeThree() throws Exception {
LOGGER.debug("testFederate_TwoSources_OffsetTwo_PageSizeThree()");
// Test Setup
Query mockQuery = mock(QueryImpl.class);
// Offset of 2
when(mockQuery.getStartIndex()).thenReturn(2);
// Page size of 3
when(mockQuery.getPageSize()).thenReturn(3);
QueryRequest queryRequest = mock(QueryRequest.class);
when(queryRequest.getQuery()).thenReturn(mockQuery);
ArgumentCaptor<QueryRequest> argument1 = ArgumentCaptor.forClass(QueryRequest.class);
ArgumentCaptor<QueryRequest> argument2 = ArgumentCaptor.forClass(QueryRequest.class);
/**
* When using a modified mockQuery to mockQuery the sources, the desired offset and page size are
* NOT used. So, the results returned by each source start at index 1 and end at (offset +
* pageSize - 1).
*
* Number of results returned by each source = offset + pageSize - 1 4 = 2 + 3 - 1
*/
Result mockSource1Result1 = mock(Result.class);
Result mockSource1Result2 = mock(Result.class);
Result mockSource1Result3 = mock(Result.class);
Result mockSource1Result4 = mock(Result.class);
SourceResponse mockSource1Response = mock(SourceResponse.class);
List<Result> mockSource1Results = Arrays.asList(mockSource1Result1,
mockSource1Result2,
mockSource1Result3,
mockSource1Result4);
when(mockSource1Response.getResults()).thenReturn(mockSource1Results);
Source mockSource1 = mock(Source.class);
when(mockSource1.query(any(QueryRequest.class))).thenReturn(mockSource1Response);
when(mockSource1.getId()).thenReturn("####### MOCK SOURCE 1.3 #######");
/**
* When using a modified mockQuery to mockQuery the sources, the desired offset and page size are
* NOT used. So, the results returned by each source start at index 1 and end at (offset +
* pageSize - 1).
*
* Number of results returned by each source = offset + pageSize - 1 4 = 2 + 3 - 1
*/
Result mockSource2Result1 = mock(Result.class);
Result mockSource2Result2 = mock(Result.class);
Result mockSource2Result3 = mock(Result.class);
Result mockSource2Result4 = mock(Result.class);
SourceResponse mockSource2Response = mock(SourceResponse.class);
List<Result> mockSource2Results = Arrays.asList(mockSource2Result1,
mockSource2Result2,
mockSource2Result3,
mockSource2Result4);
when(mockSource2Response.getResults()).thenReturn(mockSource2Results);
Source mockSource2 = mock(Source.class);
when(mockSource2.query(any(QueryRequest.class))).thenReturn(mockSource2Response);
when(mockSource2.getId()).thenReturn("####### MOCK SOURCE 2.3 #######");
// Two sources
List<Source> sources = new ArrayList<Source>(2);
sources.add(mockSource1);
sources.add(mockSource2);
Result mockSortedResult1 = mock(Result.class);
Result mockSortedResult2 = mock(Result.class);
Result mockSortedResult3 = mock(Result.class);
Result mockSortedResult4 = mock(Result.class);
Result mockSortedResult5 = mock(Result.class);
Result mockSortedResult6 = mock(Result.class);
Result mockSortedResult7 = mock(Result.class);
Result mockSortedResult8 = mock(Result.class);
List<Result> mockSortedResults = Arrays.asList(mockSortedResult1,
mockSortedResult2,
mockSortedResult3,
mockSortedResult4,
mockSortedResult5,
mockSortedResult6,
mockSortedResult7,
mockSortedResult8);
QueryResponseImpl mockOriginalResults = Mockito.mock(QueryResponseImpl.class);
// Return true for the number of mockSortedResults
Mockito.when(mockOriginalResults.hasMoreResults())
.thenReturn(true, true, true, true, true, true, true, true, false);
Mockito.when(mockOriginalResults.getResults())
.thenReturn(mockSortedResults);
// Returns the sorted results from both sources (4 + 4 = 8)
Mockito.when(mockOriginalResults.take())
.thenReturn(mockSortedResult1,
mockSortedResult2,
mockSortedResult3,
mockSortedResult4,
mockSortedResult5,
mockSortedResult6,
mockSortedResult7,
mockSortedResult8);
QueryResponseImpl offsetResultQueue = new QueryResponseImpl(queryRequest, null);
PowerMockito.whenNew(QueryResponseImpl.class)
.withArguments(queryRequest, (Map<String, Serializable>) null)
.thenReturn(mockOriginalResults, offsetResultQueue);
SortedFederationStrategy strategy = new SortedFederationStrategy(executor,
new ArrayList<PreFederatedQueryPlugin>(),
new ArrayList<PostFederatedQueryPlugin>());
// Run Test
QueryResponse federatedResponse = strategy.federate(sources, queryRequest);
// Make sure we've finished running the test
killAndWaitForExecutor();
// Verification
assertNotNull(federatedResponse);
verify(mockSource1).query(argument1.capture());
// The modified query should have a start index of 1 and an end index of offset + pageSize -
// 1
assertEquals(1,
argument1.getValue()
.getQuery()
.getStartIndex());
assertEquals(4,
argument1.getValue()
.getQuery()
.getPageSize());
verify(mockSource2).query(argument2.capture());
assertThat(mockQuery,
not(argument2.getValue()
.getQuery()));
// The modified query should have a start index of 1 and an end index of offset + pageSize -
// 1
assertEquals(1,
argument2.getValue()
.getQuery()
.getStartIndex());
assertEquals(4,
argument2.getValue()
.getQuery()
.getPageSize());
/**
* Verify three results (page size) are returned. The sorted results returned by the sources
* do NOT have the offset and page size taken into account, so the offset and page size are
* applied to the sorted results in the OffsetResultHandler.
*
* Offset of 2 (start at result 2) and page size of 3 (end at result 4).
*/
LOGGER.debug("mockSortedResult1: {}", mockSortedResult1);
LOGGER.debug("mockSortedResult2: {}", mockSortedResult2);
LOGGER.debug("mockSortedResult3: {}", mockSortedResult3);
LOGGER.debug("mockSortedResult4: {}", mockSortedResult4);
assertEquals(3,
federatedResponse.getResults()
.size());
assertEquals(mockSortedResult2,
federatedResponse.getResults()
.get(0));
assertEquals(mockSortedResult3,
federatedResponse.getResults()
.get(1));
assertEquals(mockSortedResult4,
federatedResponse.getResults()
.get(2));
for (Result result : federatedResponse.getResults()) {
LOGGER.debug("federated response result: {}", result);
}
}
/**
* Verify that the original query is used by the source.
* <p>
* No special results handling done by OffsetResultsHandler.
*/
@Test
public void testFederateOneSourceOffsetTwoPageSizeTwo() throws Exception {
LOGGER.debug("testFederate_OneSource_OffsetTwo_PageSizeTwo()");
// Offset of 2
when(mockQuery.getStartIndex()).thenReturn(2);
// Page size of 2
when(mockQuery.getPageSize()).thenReturn(2);
QueryRequest queryRequest = mock(QueryRequest.class);
when(queryRequest.getQuery()).thenReturn(mockQuery);
// ArgumentCaptor<QueryRequest> argument = ArgumentCaptor.forClass(QueryRequest.class);
/**
* When using the original query to query the source, the desired offset and page size are
* used. So, the results returned by the source already have the offset and page size taken
* into account.
*/
Result mockResult1 = mock(Result.class);
Result mockResult2 = mock(Result.class);
SourceResponse mockSourceResponse = mock(SourceResponse.class);
List<Result> results = Arrays.asList(mockResult1, mockResult2);
when(mockSourceResponse.getResults()).thenReturn(results);
Source mockSource1 = mock(Source.class);
when(mockSource1.query(any(QueryRequest.class))).thenReturn(mockSourceResponse);
when(mockSource1.getId()).thenReturn("####### MOCK SOURCE 1.1 #######");
// Only one source
List<Source> sources = new ArrayList<Source>(1);
sources.add(mockSource1);
SortedFederationStrategy strategy = new SortedFederationStrategy(executor,
new ArrayList<PreFederatedQueryPlugin>(),
new ArrayList<PostFederatedQueryPlugin>());
// Run Test
QueryResponse federatedResponse = strategy.federate(sources, queryRequest);
// Verification
assertNotNull(federatedResponse);
LOGGER.debug("Federated response result size: {}",
federatedResponse.getResults()
.size());
/**
* Verify two results (page size) are returned. The results returned by the source already
* have the offset and page size taken into account, so we can verify that the lists match.
*/
assertEquals(2,
federatedResponse.getResults()
.size());
assertEquals(mockResult1,
federatedResponse.getResults()
.get(0));
assertEquals(mockResult2,
federatedResponse.getResults()
.get(1));
LOGGER.debug("mockResult1: {}", mockResult1);
LOGGER.debug("mockResult2: {}", mockResult2);
for (Result result : federatedResponse.getResults()) {
LOGGER.debug("result: {}", result);
}
}
/**
* Verify that the original query passed is used by the sources.
* <p>
* No special results handling done by OffsetResultsHandler.
*/
@Test
public void testFederateTwoSourcesOffsetOnePageSizeThree() throws Exception {
LOGGER.debug("testFederate_TwoSources_OffsetOne_PageSizeThree()");
// Offset of 1
when(mockQuery.getStartIndex()).thenReturn(1);
// Page size of 3
when(mockQuery.getPageSize()).thenReturn(3);
QueryRequest queryRequest = mock(QueryRequest.class);
when(queryRequest.getQuery()).thenReturn(mockQuery);
/**
* When using the original query to query the sources, the desired offset and page size are
* used. So, the results returned by the sources already have the offset and page size taken
* into account.
*/
Result mockSource1Result1 = mock(Result.class);
Mockito.when(mockSource1Result1.getRelevanceScore())
.thenReturn(0.7);
Result mockSource1Result2 = mock(Result.class);
Mockito.when(mockSource1Result2.getRelevanceScore())
.thenReturn(0.5);
Result mockSource1Result3 = mock(Result.class);
Mockito.when(mockSource1Result3.getRelevanceScore())
.thenReturn(0.3);
Result mockSource1Result4 = mock(Result.class);
Mockito.when(mockSource1Result4.getRelevanceScore())
.thenReturn(0.1);
SourceResponse mockSource1Response = mock(SourceResponse.class);
List<Result> mockSource1Results = Arrays.asList(mockSource1Result1,
mockSource1Result2,
mockSource1Result3,
mockSource1Result4);
when(mockSource1Response.getResults()).thenReturn(mockSource1Results);
Source mockSource1 = mock(Source.class);
when(mockSource1.query(any(QueryRequest.class))).thenReturn(mockSource1Response);
when(mockSource1.getId()).thenReturn("####### MOCK SOURCE 1.4 #######");
Result mockSource2Result1 = mock(Result.class);
Mockito.when(mockSource2Result1.getRelevanceScore())
.thenReturn(0.8);
Result mockSource2Result2 = mock(Result.class);
Mockito.when(mockSource2Result2.getRelevanceScore())
.thenReturn(0.6);
Result mockSource2Result3 = mock(Result.class);
Mockito.when(mockSource2Result3.getRelevanceScore())
.thenReturn(0.4);
Result mockSource2Result4 = mock(Result.class);
Mockito.when(mockSource2Result4.getRelevanceScore())
.thenReturn(0.2);
SourceResponse mockSource2Response = mock(SourceResponse.class);
List<Result> mockSource2Results = Arrays.asList(mockSource2Result1,
mockSource2Result2,
mockSource2Result3,
mockSource2Result4);
when(mockSource2Response.getResults()).thenReturn(mockSource2Results);
Source mockSource2 = mock(Source.class);
when(mockSource2.query(any(QueryRequest.class))).thenReturn(mockSource2Response);
when(mockSource2.getId()).thenReturn("####### MOCK SOURCE 2.4 #######");
// Two sources
List<Source> sources = new ArrayList<Source>(2);
sources.add(mockSource1);
sources.add(mockSource2);
SortedFederationStrategy strategy = new SortedFederationStrategy(executor,
new ArrayList<PreFederatedQueryPlugin>(),
new ArrayList<PostFederatedQueryPlugin>());
// Run Test
QueryResponse federatedResponse = strategy.federate(sources, queryRequest);
// Verification
assertNotNull(federatedResponse);
LOGGER.debug("Federated response result size: {}",
federatedResponse.getResults()
.size());
/**
* Verify three results (page size) are returned. Since we are using mock Results, the
* relevance score is 0.0, and the merged and sorted results of both sources is
* mockSource2Result1, mockSource1Result1, mockSource2Result2, mockSource1Result2,
* mockSource2Result3, mockSource1Result3, mockSource2Result4, mockSource1Result4. So, the
* results are mockSource2Result1, mockSource1Result1, mockSource2Result2. No need to use
* OffsetResultHander in this case.
*/
assertEquals(3,
federatedResponse.getResults()
.size());
assertEquals(mockSource2Result1,
federatedResponse.getResults()
.get(0));
assertEquals(mockSource1Result1,
federatedResponse.getResults()
.get(1));
assertEquals(mockSource2Result2,
federatedResponse.getResults()
.get(2));
LOGGER.debug("mockSource2Result1: {}", mockSource2Result1);
LOGGER.debug("mockSource1Result1: {}", mockSource1Result1);
LOGGER.debug("mockSource2Result2: {}", mockSource2Result2);
for (Result result : federatedResponse.getResults()) {
LOGGER.debug("federated response result: {}", result);
}
// Check the responseProperties
List<String> siteList = (List) federatedResponse.getPropertyValue(QueryResponse.SITE_LIST);
assertTrue(siteList.contains("####### MOCK SOURCE 2.4 #######"));
Map<String, Serializable> siteProperties = (Map) federatedResponse.getPropertyValue(
"####### MOCK SOURCE 2.4 #######");
assertNotNull(siteProperties.get(QueryResponse.TOTAL_HITS));
assertNotNull(siteProperties.get(QueryResponse.TOTAL_RESULTS_RETURNED));
assertTrue(siteList.contains("####### MOCK SOURCE 2.4 #######"));
siteProperties =
(Map) federatedResponse.getPropertyValue("####### MOCK SOURCE 1.4 #######");
assertNotNull(siteProperties.get(QueryResponse.TOTAL_HITS));
assertNotNull(siteProperties.get(QueryResponse.TOTAL_RESULTS_RETURNED));
}
/**
* Verify that the original query is used by the source.
* <p>
* No special results handling done by OffsetResultsHandler.
*/
@Test
public void testFederateOneSourceOffsetOnePageSizeTwo() throws Exception {
LOGGER.debug("testFederate_OneSource_OffsetOne_PageSizeTwo()");
// Offset of 1
when(mockQuery.getStartIndex()).thenReturn(1);
// Page size of 2
when(mockQuery.getPageSize()).thenReturn(2);
QueryRequest queryRequest = mock(QueryRequest.class);
when(queryRequest.getQuery()).thenReturn(mockQuery);
/**
* When using the original query to query the source, the desired offset and page size are
* used. So, the results returned by the source already have the offset and page size taken
* into account.
*/
Result mockResult1 = mock(Result.class);
Result mockResult2 = mock(Result.class);
SourceResponse mockSourceResponse = mock(SourceResponse.class);
List<Result> results = Arrays.asList(mockResult1, mockResult2);
when(mockSourceResponse.getResults()).thenReturn(results);
Source mockSource1 = mock(Source.class);
when(mockSource1.query(any(QueryRequest.class))).thenReturn(mockSourceResponse);
when(mockSource1.getId()).thenReturn("####### MOCK SOURCE 1.2 #######");
// Only one source
List<Source> sources = new ArrayList<Source>(1);
sources.add(mockSource1);
SortedFederationStrategy strategy = new SortedFederationStrategy(executor,
new ArrayList<PreFederatedQueryPlugin>(),
new ArrayList<PostFederatedQueryPlugin>());
// Run Test
QueryResponse federatedResponse = strategy.federate(sources, queryRequest);
// Verification
assertNotNull(federatedResponse);
LOGGER.debug("Federated response result size: {}",
federatedResponse.getResults()
.size());
/**
* Verify two results (page size) are returned. The results returned by the source already
* have the offset and page size taken into account, so we can verify that the lists match.
*/
assertEquals(2,
federatedResponse.getResults()
.size());
assertEquals(mockResult1,
federatedResponse.getResults()
.get(0));
assertEquals(mockResult2,
federatedResponse.getResults()
.get(1));
LOGGER.debug("mockResult1: {}", mockResult1);
LOGGER.debug("mockResult2: {}", mockResult2);
for (Result result : federatedResponse.getResults()) {
LOGGER.debug("result: {}", result);
}
// Check the responseProperties
assertEquals("####### MOCK SOURCE 1.2 #######", ((List) federatedResponse.getPropertyValue(
QueryResponse.SITE_LIST)).get(0));
Map<String, Serializable> siteProperties = (Map) federatedResponse.getPropertyValue(
"####### MOCK SOURCE 1.2 #######");
assertNotNull(siteProperties.get(QueryResponse.TOTAL_HITS));
assertNotNull(siteProperties.get(QueryResponse.TOTAL_RESULTS_RETURNED));
}
private void killAndWaitForExecutor() throws Exception {
if (executor != null && !executor.isShutdown()) {
executor.shutdown();
executor.awaitTermination(1L, TimeUnit.MINUTES);
}
}
private void refreshExecutor() throws Exception {
killAndWaitForExecutor();
executor = Executors.newFixedThreadPool(2);
}
}