/**
* 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 org.codice.ddf.commands.catalog;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertThat;
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import org.apache.commons.io.IOUtils;
import org.apache.felix.service.command.CommandSession;
import org.codice.ddf.commands.catalog.facade.CatalogFacade;
import org.codice.ddf.commands.catalog.facade.Framework;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import ddf.catalog.CatalogFramework;
import ddf.catalog.data.Metacard;
import ddf.catalog.data.Result;
import ddf.catalog.data.impl.MetacardImpl;
import ddf.catalog.data.impl.ResultImpl;
import ddf.catalog.federation.FederationException;
import ddf.catalog.filter.FilterBuilder;
import ddf.catalog.filter.proxy.builder.GeotoolsFilterBuilder;
import ddf.catalog.operation.CreateRequest;
import ddf.catalog.operation.CreateResponse;
import ddf.catalog.operation.Query;
import ddf.catalog.operation.QueryRequest;
import ddf.catalog.operation.QueryResponse;
import ddf.catalog.source.IngestException;
import ddf.catalog.source.SourceUnavailableException;
import ddf.catalog.source.UnsupportedQueryException;
public class TestReplicationCommand {
private static final Set<String> SOURCE_IDS = new HashSet<String>(
Arrays.asList("sourceId1", "sourceId2"));
private static final int HITS = 1000;
private static ConsoleOutput consoleOutput;
private CatalogFramework catalogFramework;
private QueryResponse mockQueryResponse = mock(QueryResponse.class);
private CreateResponse mockCreateResponse = mock(CreateResponse.class);
private CommandSession mockSession = mock(CommandSession.class);
private InputStream mockIS = IOUtils.toInputStream("sourceId1");
private ReplicationCommand replicationCmd;
private int pageSize;
@AfterClass
public static void cleanUp() throws IOException {
consoleOutput.resetSystemOut();
consoleOutput.closeBuffer();
}
@Before
public void setUp()
throws UnsupportedQueryException, SourceUnavailableException, FederationException,
IngestException {
consoleOutput = new ConsoleOutput();
consoleOutput.interceptSystemOut();
catalogFramework = mock(CatalogFramework.class);
replicationCmd = new ReplicationCommand() {
@Override
public String getInput(String message) throws IOException {
return "sourceId1";
}
@Override
protected CatalogFacade getCatalog() throws InterruptedException {
return new Framework(catalogFramework);
}
@Override
protected FilterBuilder getFilterBuilder() throws InterruptedException {
return new GeotoolsFilterBuilder();
}
@Override
protected <T> T getService(Class<T> classObject) {
T service = null;
if (classObject.equals(CatalogFramework.class)) {
return (T) catalogFramework;
}
return service;
}
};
when(mockSession.getKeyboard()).thenReturn(mockIS);
when(catalogFramework.getSourceIds()).thenReturn(SOURCE_IDS);
when(catalogFramework.query(isA(QueryRequest.class)))
.thenAnswer(new Answer<QueryResponse>() {
@Override
public QueryResponse answer(InvocationOnMock invocation)
throws Throwable {
Object[] args = invocation.getArguments();
QueryRequest request = (QueryRequest) args[0];
pageSize = request.getQuery().getPageSize();
return mockQueryResponse;
}
});
when(mockQueryResponse.getHits()).thenReturn(Long.valueOf(HITS));
when(mockQueryResponse.getResults()).thenAnswer(new Answer<List<Result>>() {
@Override
public List<Result> answer(InvocationOnMock invocation) throws Throwable {
return getResultList(pageSize);
}
});
when(catalogFramework.create(isA(CreateRequest.class)))
.thenAnswer(new Answer<CreateResponse>() {
@Override
public CreateResponse answer(InvocationOnMock invocation)
throws Throwable {
Object[] args = invocation.getArguments();
CreateRequest request = (CreateRequest) args[0];
when(mockCreateResponse.getCreatedMetacards())
.thenReturn(request.getMetacards());
return mockCreateResponse;
}
});
}
@Test
public void testBadBatchSize() throws Exception {
replicationCmd.isProvider = true;
replicationCmd.isUseTemporal = false;
replicationCmd.sourceId = "sourceId1";
replicationCmd.batchSize = -1;
replicationCmd.doExecute();
assertThat(consoleOutput.getOutput(),
containsString("Batch Size must be between 1 and 1000."));
consoleOutput.reset();
}
@Test
public void testPrintSourceIds() throws Exception {
replicationCmd.isProvider = true;
replicationCmd.isUseTemporal = false;
replicationCmd.sourceId = "";
replicationCmd.doExecute();
assertThat(consoleOutput.getOutput(),
containsString("Please enter the Source ID you would like to replicate:"));
assertThat(consoleOutput.getOutput(), containsString("sourceId1"));
assertThat(consoleOutput.getOutput(), containsString("sourceId2"));
consoleOutput.reset();
}
@Test
public void testDefaultQuery() throws Exception {
replicationCmd.isProvider = true;
replicationCmd.isUseTemporal = false;
replicationCmd.sourceId = "sourceId1";
replicationCmd.doExecute();
ArgumentCaptor<QueryRequest> argument = ArgumentCaptor.forClass(QueryRequest.class);
verify(catalogFramework, times(HITS / replicationCmd.batchSize + 1))
.query(argument.capture());
QueryRequest request = argument.getValue();
assertThat(request, notNullValue());
Query query = request.getQuery();
assertThat(query, notNullValue());
assertThat(query.getPageSize(), is(ReplicationCommand.MAX_BATCH_SIZE));
assertThat(query.getStartIndex(), is(1));
}
@Test
public void testSmallBatchSize() throws Exception {
replicationCmd.isProvider = true;
replicationCmd.isUseTemporal = false;
replicationCmd.sourceId = "sourceId1";
replicationCmd.batchSize = 10;
replicationCmd.doExecute();
ArgumentCaptor<QueryRequest> argument = ArgumentCaptor.forClass(QueryRequest.class);
verify(catalogFramework, times(HITS / replicationCmd.batchSize + 1))
.query(argument.capture());
QueryRequest request = argument.getValue();
assertThat(request, notNullValue());
Query query = request.getQuery();
assertThat(query, notNullValue());
assertThat(query.getPageSize(), is(replicationCmd.batchSize));
assertThat(query.getStartIndex(), is(991));
}
@Test
public void testMultithreaded() throws Exception {
replicationCmd.isProvider = true;
replicationCmd.isUseTemporal = false;
replicationCmd.sourceId = "sourceId1";
replicationCmd.batchSize = 10;
replicationCmd.multithreaded = 4;
replicationCmd.doExecute();
ArgumentCaptor<QueryRequest> argument = ArgumentCaptor.forClass(QueryRequest.class);
verify(catalogFramework, times(HITS / replicationCmd.batchSize + 1))
.query(argument.capture());
QueryRequest request = argument.getValue();
assertThat(request, notNullValue());
Query query = request.getQuery();
assertThat(query, notNullValue());
assertThat(query.getPageSize(), is(replicationCmd.batchSize));
assertThat(consoleOutput.getOutput(),
containsString("1000 record(s) replicated; 0 record(s) failed"));
consoleOutput.reset();
}
@Test
public void testTemporalFlag() throws Exception {
replicationCmd.isProvider = true;
replicationCmd.isUseTemporal = true;
replicationCmd.sourceId = "sourceId1";
replicationCmd.doExecute();
ArgumentCaptor<QueryRequest> argument = ArgumentCaptor.forClass(QueryRequest.class);
verify(catalogFramework, times(HITS / replicationCmd.batchSize + 1))
.query(argument.capture());
QueryRequest request = argument.getValue();
assertThat(request, notNullValue());
Query query = request.getQuery();
assertThat(query, notNullValue());
assertThat(query.getPageSize(), is(replicationCmd.batchSize));
assertThat(query.getStartIndex(), is(1));
assertThat(query.getSortBy().getPropertyName().getPropertyName(), is(Metacard.EFFECTIVE));
// TODO - How do I validate the acutal filter
}
@Test
public void testFailedtoIngestHalf() throws Exception {
when(catalogFramework.create(isA(CreateRequest.class)))
.thenAnswer(new Answer<CreateResponse>() {
@Override
public CreateResponse answer(InvocationOnMock invocation)
throws Throwable {
Object[] args = invocation.getArguments();
CreateRequest request = (CreateRequest) args[0];
when(mockCreateResponse.getCreatedMetacards()).thenReturn(
request.getMetacards()
.subList(0, request.getMetacards().size() / 2));
return mockCreateResponse;
}
});
replicationCmd.isProvider = true;
replicationCmd.isUseTemporal = false;
replicationCmd.sourceId = "sourceId1";
replicationCmd.doExecute();
assertThat(consoleOutput.getOutput(), containsString("500 record(s) failed"));
consoleOutput.reset();
}
private List<Result> getResultList(int size) {
List<Result> results = new ArrayList<Result>();
for (int i = 0; i < size; i++) {
MetacardImpl metacard = new MetacardImpl();
metacard.setId(UUID.randomUUID().toString());
Result result = new ResultImpl(metacard);
results.add(result);
}
return results;
}
}