/**
* 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.catalog.plugin.metacard.backup;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyMap;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.doThrow;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.codice.ddf.catalog.async.data.api.internal.ProcessCreateItem;
import org.codice.ddf.catalog.async.data.api.internal.ProcessDeleteItem;
import org.codice.ddf.catalog.async.data.api.internal.ProcessRequest;
import org.codice.ddf.catalog.async.data.api.internal.ProcessResourceItem;
import org.codice.ddf.catalog.async.data.api.internal.ProcessUpdateItem;
import org.codice.ddf.catalog.plugin.metacard.backup.storage.filestorage.MetacardBackupFileStorage;
import org.codice.ddf.catalog.plugin.metacard.backup.storage.internal.MetacardBackupException;
import org.codice.ddf.catalog.plugin.metacard.backup.storage.internal.MetacardBackupStorageProvider;
import org.junit.Before;
import org.junit.Test;
import ddf.catalog.data.BinaryContent;
import ddf.catalog.data.Metacard;
import ddf.catalog.data.impl.AttributeImpl;
import ddf.catalog.data.impl.BinaryContentImpl;
import ddf.catalog.data.impl.MetacardImpl;
import ddf.catalog.data.types.Core;
import ddf.catalog.plugin.PluginExecutionException;
import ddf.catalog.transform.CatalogTransformerException;
import ddf.catalog.transform.MetacardTransformer;
public class MetacardBackupPluginTest {
private static final String METACARD_TRANSFORMER_ID = "metadata";
private static final List<String> METACARD_IDS = Arrays.asList("1b6482b1b8f730e343a96d61e0e089",
"2b6482b2b8f730e343a96d61e0e089",
"2b6482b2b8f730e343a96d61e0e082");
private static final String XML_METADATA =
" <csw:Record\n" + " xmlns:ows=\"http://www.opengis.net/ows\"\n"
+ " xmlns:csw=\"http://www.opengis.net/cat/csw/2.0.2\"\n"
+ " xmlns:dc=\"http://purl.org/dc/elements/1.1/\"\n"
+ " xmlns:dct=\"http://purl.org/dc/terms/\"\n"
+ " xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\">\n"
+ " <dc:identifier>$id$</dc:identifier>\n"
+ " <dc:title>Aliquam fermentum purus quis arcu</dc:title>\n"
+ " <dc:type>http://purl.org/dc/dcmitype/Text</dc:type>\n"
+ " <dc:subject>Hydrography--Dictionaries</dc:subject>\n"
+ " <dc:format>application/pdf</dc:format>\n"
+ " <dc:date>2006-05-12</dc:date>\n"
+ " <dct:abstract>Vestibulum quis ipsum sit amet metus imperdiet vehicula. Nulla scelerisque cursus mi.</dct:abstract>\n"
+ " <ows:BoundingBox crs=\"urn:x-ogc:def:crs:EPSG:6.11:4326\">\n"
+ " <ows:LowerCorner>44.792 -6.171</ows:LowerCorner>\n"
+ " <ows:UpperCorner>51.126 -2.228</ows:UpperCorner>\n"
+ " </ows:BoundingBox>\n" + " </csw:Record>";
private static final String OUTPUT_DIRECTORY = "target" + File.separator;
private static final String FILE_STORAGE_PROVIDER_ID = "TestFileStorageProvider";
private static final String MOCK_ID = "MockProvider";
private MetacardBackupPlugin metacardBackupPlugin;
private MetacardBackupFileStorage fileStorageProvider = new MetacardBackupFileStorage();
private ProcessRequest<ProcessCreateItem> createRequest;
private ProcessRequest<ProcessUpdateItem> updateRequest;
private ProcessRequest<ProcessDeleteItem> deleteRequest;
private MetacardTransformer metacardTransformer;
private MetacardBackupStorageProvider mockProvider = mock(MetacardBackupStorageProvider.class);
@SuppressWarnings("unchecked")
@Before
public void setUp() throws Exception {
metacardTransformer = mock(MetacardTransformer.class);
BinaryContent binaryContent =
new BinaryContentImpl(new ByteArrayInputStream(XML_METADATA.getBytes(
StandardCharsets.UTF_8)));
when(metacardTransformer.transform(any(Metacard.class),
anyMap())).thenReturn(binaryContent);
doThrow(new MetacardBackupException("Not Implemented")).when(mockProvider)
.store(any(), any());
doThrow(new MetacardBackupException("Not Implemented")).when(mockProvider)
.delete(any());
doReturn(MOCK_ID).when(mockProvider)
.getId();
metacardBackupPlugin = new MetacardBackupPlugin();
metacardBackupPlugin.setMetacardTransformerId(METACARD_TRANSFORMER_ID);
metacardBackupPlugin.setMetacardTransformer(metacardTransformer);
createRequest = generateProcessRequest(ProcessCreateItem.class, true);
updateRequest = generateProcessRequest(ProcessUpdateItem.class, true);
deleteRequest = generateDeleteRequest();
fileStorageProvider.setId(FILE_STORAGE_PROVIDER_ID);
fileStorageProvider.setOutputDirectory(OUTPUT_DIRECTORY);
metacardBackupPlugin.setMetacardOutputProviderIds(Collections.singletonList(
FILE_STORAGE_PROVIDER_ID));
metacardBackupPlugin.setStorageBackupPlugins(Arrays.asList(new MetacardBackupStorageProvider[] {
fileStorageProvider}));
}
@Test
public void testDefaultKeepDeletedMetacards() {
assertThat(metacardBackupPlugin.getKeepDeletedMetacards(), is(false));
}
@Test
public void testSetKeepDeletedMetacards() {
metacardBackupPlugin.setKeepDeletedMetacards(true);
assertThat(metacardBackupPlugin.getKeepDeletedMetacards(), is(true));
}
@Test
public void testMetacardTransformerId() {
assertThat(metacardBackupPlugin.getMetacardTransformerId(), is(METACARD_TRANSFORMER_ID));
}
@Test
public void testRefresh() {
String newMetacardTransformer = "tika";
Map<String, Object> properties = new HashMap<>();
properties.put("metacardTransformerId", newMetacardTransformer);
properties.put("keepDeletedMetacards", Boolean.TRUE);
properties.put("backupInvalidMetacards", Boolean.TRUE);
metacardBackupPlugin.refresh(properties);
assertThat(metacardBackupPlugin.getKeepDeletedMetacards(), is(true));
assertThat(metacardBackupPlugin.getMetacardTransformerId(), is(newMetacardTransformer));
assertThat(metacardBackupPlugin.getBackupInvalidMetacards(), is(true));
}
@Test
public void testRefreshBadValues() {
Map<String, Object> properties = new HashMap<>();
properties.put("metacardTransformerId", 2);
properties.put("keepDeletedMetacards", "bad");
properties.put("backupInvalidMetacards", "bad");
metacardBackupPlugin.refresh(properties);
assertThat(metacardBackupPlugin.getKeepDeletedMetacards(), is(false));
assertThat(metacardBackupPlugin.getMetacardTransformerId(), is(METACARD_TRANSFORMER_ID));
assertThat(metacardBackupPlugin.getBackupInvalidMetacards(), is(true));
}
@Test
public void testRefreshEmptyStrings() {
Map<String, Object> properties = new HashMap<>();
properties.put("metacardTransformerId", "");
metacardBackupPlugin.refresh(properties);
assertThat(metacardBackupPlugin.getMetacardTransformerId(), is(METACARD_TRANSFORMER_ID));
}
@Test
public void testCreateRequest() throws Exception {
metacardBackupPlugin.setMetacardOutputProviderIds(Collections.singletonList(
FILE_STORAGE_PROVIDER_ID));
metacardBackupPlugin.setStorageBackupPlugins(Arrays.asList(new MetacardBackupStorageProvider[] {
fileStorageProvider}));
metacardBackupPlugin.processCreate(createRequest);
assertFiles(true);
cleanup();
}
@Test
public void testCreateAndDeleteRequestOneBadProvider() throws Exception {
cleanup();
metacardBackupPlugin.setMetacardOutputProviderIds(Arrays.asList(MOCK_ID,
FILE_STORAGE_PROVIDER_ID));
metacardBackupPlugin.setStorageBackupPlugins(Arrays.asList(mockProvider,
fileStorageProvider));
metacardBackupPlugin.processCreate(createRequest);
assertFiles(true);
cleanup();
metacardBackupPlugin.setMetacardOutputProviderIds(Collections.singletonList(
FILE_STORAGE_PROVIDER_ID));
metacardBackupPlugin.setStorageBackupPlugins(Arrays.asList(new MetacardBackupStorageProvider[] {
fileStorageProvider}));
}
@Test(expected = PluginExecutionException.class)
public void testCreateRequestNullMetacardTransformer() throws Exception {
metacardBackupPlugin.setMetacardTransformer(null);
metacardBackupPlugin.processCreate(createRequest);
}
@Test(expected = PluginExecutionException.class)
public void testCreateRequestWithFailedTransform() throws Exception {
when(metacardTransformer.transform(any(Metacard.class), anyMap())).thenThrow(
CatalogTransformerException.class);
metacardBackupPlugin.processCreate(createRequest);
}
@Test(expected = PluginExecutionException.class)
public void testCreateRequestWithNullContent() throws Exception {
when(metacardTransformer.transform(any(Metacard.class), anyMap())).thenReturn(null);
metacardBackupPlugin.processCreate(createRequest);
}
@Test(expected = PluginExecutionException.class)
public void testCreateRequestWithNullContentInputStream() throws Exception {
BinaryContent binaryContent = mock(BinaryContent.class);
when(binaryContent.getInputStream()).thenReturn(null);
when(metacardTransformer.transform(any(Metacard.class),
anyMap())).thenReturn(binaryContent);
metacardBackupPlugin.processCreate(createRequest);
}
@Test
public void testCreateRequestNoStoragePlugin() throws Exception {
cleanup();
metacardBackupPlugin.setStorageBackupPlugins(Arrays.asList(new MetacardBackupStorageProvider[] {
fileStorageProvider}));
metacardBackupPlugin.setMetacardOutputProviderIds(Collections.singletonList("BogusId"));
metacardBackupPlugin.processCreate(createRequest);
assertFiles(false);
}
@Test
public void testUpdateRequest() throws Exception {
metacardBackupPlugin.processUpdate(updateRequest);
assertFiles(true);
cleanup();
}
@Test
public void testDeleteRequest() throws Exception {
metacardBackupPlugin.processCreate(createRequest);
metacardBackupPlugin.processDelete(deleteRequest);
assertFiles(false);
}
@Test
public void testDeleteRequestKeepDeletedMetacard() throws Exception {
metacardBackupPlugin.processCreate(createRequest);
metacardBackupPlugin.setKeepDeletedMetacards(true);
assertFiles(true);
cleanup();
}
@Test
public void testGetContentBytes() throws Exception {
BinaryContent binaryContent = mock(BinaryContent.class);
byte[] content = {'a'};
when(binaryContent.getByteArray()).thenReturn(content);
byte[] bytes = metacardBackupPlugin.getContentBytes(binaryContent, "metacard");
assertThat(bytes, equalTo(content));
}
@Test(expected = PluginExecutionException.class)
public void testGetContentBytesNoContent() throws Exception {
metacardBackupPlugin.getContentBytes(null, "metacard");
}
@Test(expected = PluginExecutionException.class)
public void testGetContentBytesNoContentBytes() throws Exception {
BinaryContent binaryContent = mock(BinaryContent.class);
when(binaryContent.getByteArray()).thenReturn(null);
metacardBackupPlugin.getContentBytes(binaryContent, "metacard");
}
@Test
public void testValidationNoBackup() throws Exception {
cleanup();
metacardBackupPlugin.setBackupInvalidMetacards(false);
ProcessRequest<ProcessCreateItem> createRequest = generateProcessRequest(ProcessCreateItem.class, false);
metacardBackupPlugin.processCreate(createRequest);
assertFiles(false);
metacardBackupPlugin.setBackupInvalidMetacards(true);
cleanup();
}
@Test
public void testValidationBackupInvalid() throws Exception {
cleanup();
metacardBackupPlugin.setBackupInvalidMetacards(true);
assertThat(metacardBackupPlugin.getBackupInvalidMetacards(), is(true));
ProcessRequest<ProcessCreateItem> createRequest = generateProcessRequest(ProcessCreateItem.class, false);
metacardBackupPlugin.processCreate(createRequest);
assertFiles(true);
cleanup();
}
@Test
public void testNoValidationTagsBackupSuccess() throws Exception {
cleanup();
metacardBackupPlugin.setBackupInvalidMetacards(false);
metacardBackupPlugin.processCreate(createRequest);
assertFiles(true);
metacardBackupPlugin.setBackupInvalidMetacards(true);
cleanup();
}
private ProcessRequest<ProcessDeleteItem> generateDeleteRequest() {
List<ProcessDeleteItem> processDeleteItems = new ArrayList<>();
for (String id : METACARD_IDS) {
Metacard metacard = new MetacardImpl();
metacard.setAttribute(new AttributeImpl(Core.ID, id));
metacard.setAttribute(new AttributeImpl(Core.METADATA, XML_METADATA));
ProcessDeleteItem processDeleteItem = mock(ProcessDeleteItem.class);
when(processDeleteItem.getMetacard()).thenReturn(metacard);
processDeleteItems.add(processDeleteItem);
}
ProcessRequest<ProcessDeleteItem> processRequest = mock(ProcessRequest.class);
when(processRequest.getProcessItems()).thenReturn(processDeleteItems);
return processRequest;
}
private ProcessRequest generateProcessRequest(Class<? extends ProcessResourceItem> clazz, boolean validCard) {
List<ProcessResourceItem> processCreateItems = new ArrayList<>();
for (String id : METACARD_IDS) {
Metacard metacard = new MetacardImpl();
metacard.setAttribute(new AttributeImpl(Core.ID, id));
metacard.setAttribute(new AttributeImpl(Core.METADATA, XML_METADATA));
if (!validCard) {
metacard.setAttribute(new AttributeImpl(Core.METACARD_TAGS, "INVALID"));
}
ProcessResourceItem processResourceItem;
if (clazz.getName()
.contains("ProcessCreateItem")) {
processResourceItem = mock(ProcessCreateItem.class);
} else {
processResourceItem = mock(ProcessUpdateItem.class);
}
when(processResourceItem.getMetacard()).thenReturn(metacard);
processCreateItems.add(processResourceItem);
}
ProcessRequest localCreateRequest = mock(ProcessRequest.class);
when(localCreateRequest.getProcessItems()).thenReturn(processCreateItems);
return localCreateRequest;
}
private void assertFiles(boolean exists) {
for (String id : METACARD_IDS) {
Path path = fileStorageProvider.getMetacardDirectory(id);
assertThat(path.toFile()
.exists(), is(exists));
}
}
private void cleanup() throws PluginExecutionException {
metacardBackupPlugin.processDelete(deleteRequest);
}
}