ddf.catalog.impl.CatalogFrameworkImplTest.java Source code

Java tutorial

Introduction

Here is the source code for ddf.catalog.impl.CatalogFrameworkImplTest.java

Source

/**
 * 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.impl;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasEntry;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
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.Matchers.anyList;
import static org.mockito.Matchers.anyMap;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.AbstractMap.SimpleEntry;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.UUID;

import javax.activation.MimeType;

import org.apache.commons.lang.StringUtils;
import org.geotools.filter.FilterFactoryImpl;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.MethodRule;
import org.junit.rules.TestWatchman;
import org.junit.runners.model.FrameworkMethod;
import org.mockito.ArgumentCaptor;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.io.ByteSource;

import ddf.catalog.CatalogFramework;
import ddf.catalog.Constants;
import ddf.catalog.cache.impl.ResourceCache;
import ddf.catalog.cache.solr.impl.ValidationQueryFactory;
import ddf.catalog.content.StorageProvider;
import ddf.catalog.content.data.ContentItem;
import ddf.catalog.content.data.impl.ContentItemImpl;
import ddf.catalog.content.impl.MockMemoryStorageProvider;
import ddf.catalog.content.operation.UpdateStorageRequest;
import ddf.catalog.content.operation.impl.CreateStorageRequestImpl;
import ddf.catalog.content.operation.impl.UpdateStorageRequestImpl;
import ddf.catalog.data.AttributeDescriptor;
import ddf.catalog.data.AttributeType;
import ddf.catalog.data.BinaryContent;
import ddf.catalog.data.ContentType;
import ddf.catalog.data.Metacard;
import ddf.catalog.data.MetacardType;
import ddf.catalog.data.Result;
import ddf.catalog.data.impl.AttributeDescriptorImpl;
import ddf.catalog.data.impl.BinaryContentImpl;
import ddf.catalog.data.impl.MetacardImpl;
import ddf.catalog.federation.FederationException;
import ddf.catalog.federation.FederationStrategy;
import ddf.catalog.filter.FilterBuilder;
import ddf.catalog.filter.proxy.adapter.GeotoolsFilterAdapterImpl;
import ddf.catalog.filter.proxy.builder.GeotoolsFilterBuilder;
import ddf.catalog.operation.CreateRequest;
import ddf.catalog.operation.CreateResponse;
import ddf.catalog.operation.DeleteRequest;
import ddf.catalog.operation.DeleteResponse;
import ddf.catalog.operation.Query;
import ddf.catalog.operation.QueryRequest;
import ddf.catalog.operation.QueryResponse;
import ddf.catalog.operation.ResourceRequest;
import ddf.catalog.operation.ResourceResponse;
import ddf.catalog.operation.SourceInfoRequest;
import ddf.catalog.operation.SourceInfoResponse;
import ddf.catalog.operation.SourceResponse;
import ddf.catalog.operation.Update;
import ddf.catalog.operation.UpdateRequest;
import ddf.catalog.operation.UpdateResponse;
import ddf.catalog.operation.impl.CreateRequestImpl;
import ddf.catalog.operation.impl.DeleteRequestImpl;
import ddf.catalog.operation.impl.QueryImpl;
import ddf.catalog.operation.impl.QueryRequestImpl;
import ddf.catalog.operation.impl.QueryResponseImpl;
import ddf.catalog.operation.impl.ResourceRequestById;
import ddf.catalog.operation.impl.SourceInfoRequestEnterprise;
import ddf.catalog.operation.impl.SourceInfoRequestSources;
import ddf.catalog.operation.impl.SourceResponseImpl;
import ddf.catalog.operation.impl.UpdateRequestImpl;
import ddf.catalog.plugin.PluginExecutionException;
import ddf.catalog.plugin.PostIngestPlugin;
import ddf.catalog.plugin.PostQueryPlugin;
import ddf.catalog.plugin.PostResourcePlugin;
import ddf.catalog.plugin.PreQueryPlugin;
import ddf.catalog.plugin.StopProcessingException;
import ddf.catalog.resource.Resource;
import ddf.catalog.resource.ResourceNotFoundException;
import ddf.catalog.resource.ResourceNotSupportedException;
import ddf.catalog.resource.ResourceReader;
import ddf.catalog.source.CatalogProvider;
import ddf.catalog.source.CatalogStore;
import ddf.catalog.source.FederatedSource;
import ddf.catalog.source.IngestException;
import ddf.catalog.source.Source;
import ddf.catalog.source.SourceDescriptor;
import ddf.catalog.source.SourceMonitor;
import ddf.catalog.source.SourceUnavailableException;
import ddf.catalog.source.UnsupportedQueryException;
import ddf.catalog.transform.CatalogTransformerException;
import ddf.catalog.transform.InputTransformer;
import ddf.catalog.transform.MetacardTransformer;
import ddf.catalog.transform.QueryResponseTransformer;
import ddf.catalog.util.impl.CachedSource;
import ddf.catalog.util.impl.SourcePoller;
import ddf.catalog.util.impl.SourcePollerRunner;
import ddf.mime.MimeTypeResolver;
import ddf.mime.MimeTypeToTransformerMapper;
import ddf.mime.mapper.MimeTypeMapperImpl;
import ddf.security.SecurityConstants;
import ddf.security.Subject;
import ddf.security.permission.KeyValueCollectionPermission;

public class CatalogFrameworkImplTest {
    private static final Logger LOGGER = LoggerFactory.getLogger(CatalogFrameworkImplTest.class);

    CatalogFrameworkImpl framework;

    CatalogFrameworkImpl resourceFramework;

    MockMemoryProvider provider;

    MockMemoryStorageProvider storageProvider;

    MockEventProcessor eventAdmin;

    ResourceRequest mockResourceRequest;

    ResourceResponse mockResourceResponse;

    PostResourcePlugin mockPostResourcePlugin;

    ArgumentCaptor<ResourceResponse> argument;

    List<FederatedSource> federatedSources;

    @Rule
    public MethodRule watchman = new TestWatchman() {
        public void starting(FrameworkMethod method) {
            LOGGER.debug("***************************  STARTING: {}  **************************\n",
                    method.getName());
        }

        public void finished(FrameworkMethod method) {
            LOGGER.debug("***************************  END: {}  **************************\n", method.getName());
        }
    };

    @Before
    public void setup() throws StopProcessingException, PluginExecutionException, URISyntaxException,
            FederationException, IOException, CatalogTransformerException {
        // Setup
        /*
         * Prepare to capture the ResourceResponse argument passed into
         * PostResourcePlugin.process(). We will verify that it contains a non-null ResourceRequest
         * in the verification section of this test.
         */
        argument = ArgumentCaptor.forClass(ResourceResponse.class);

        Resource mockResource = mock(Resource.class);

        mockResourceRequest = mock(ResourceRequest.class);
        when(mockResourceRequest.getAttributeValue()).thenReturn(new URI("myURI"));
        when(mockResourceRequest.getAttributeName()).thenReturn(new String("myName"));

        mockResourceResponse = mock(ResourceResponse.class);
        when(mockResourceResponse.getRequest()).thenReturn(mockResourceRequest);
        when(mockResourceResponse.getResource()).thenReturn(mockResource);

        mockPostResourcePlugin = mock(PostResourcePlugin.class);
        /*
         * We verify (see verification section of test) that PostResourcePlugin.process() receives a
         * ResourceResponse with a non-null ResourceRequest. We assume that it works correctly and
         * returns a ResourceResponse with a non-null ResourceRequest, so we return our
         * mockResouceResponse that contains a non-null ResourceRequest.
         */
        when(mockPostResourcePlugin.process(isA(ResourceResponse.class))).thenReturn(mockResourceResponse);

        List<PostResourcePlugin> mockPostResourcePlugins = new ArrayList<PostResourcePlugin>();
        mockPostResourcePlugins.add(mockPostResourcePlugin);

        eventAdmin = new MockEventProcessor();
        provider = new MockMemoryProvider("Provider", "Provider", "v1.0", "DDF", new HashSet<>(), true, new Date());

        storageProvider = new MockMemoryStorageProvider();

        // Mock register the provider in the container
        // Mock the source poller
        SourcePoller mockPoller = mock(SourcePoller.class);
        when(mockPoller.getCachedSource(isA(Source.class))).thenReturn(null);

        ArrayList<PostIngestPlugin> postIngestPlugins = new ArrayList<PostIngestPlugin>();
        postIngestPlugins.add(eventAdmin);

        FederationStrategy federationStrategy = mock(FederationStrategy.class);
        Result result = mock(Result.class);
        when(result.getMetacard()).thenReturn(new MetacardImpl());
        when(federationStrategy.federate(anyList(), anyObject()))
                .thenReturn(new QueryResponseImpl(mock(QueryRequest.class), Collections.singletonList(result), 1));

        federatedSources = createDefaultFederatedSourceList(true);

        MimeTypeResolver mimeTypeResolver = mock(MimeTypeResolver.class);
        MimeTypeToTransformerMapper mimeTypeToTransformerMapper = mock(MimeTypeToTransformerMapper.class);
        InputTransformer inputTransformer = mock(InputTransformer.class);
        when(inputTransformer.transform(any(InputStream.class))).thenReturn(new MetacardImpl());
        when(mimeTypeToTransformerMapper.findMatches(any(Class.class), any(MimeType.class)))
                .thenReturn(Collections.singletonList(inputTransformer));

        FrameworkProperties frameworkProperties = new FrameworkProperties();
        frameworkProperties.setAccessPlugins(new ArrayList<>());
        frameworkProperties.setPolicyPlugins(new ArrayList<>());
        frameworkProperties.setSourcePoller(mockPoller);
        frameworkProperties.setCatalogProviders(Collections.singletonList((CatalogProvider) provider));
        frameworkProperties.setPostResource(mockPostResourcePlugins);
        frameworkProperties.setFederationStrategy(federationStrategy);
        frameworkProperties.setFilterBuilder(new GeotoolsFilterBuilder());
        frameworkProperties.setPreIngest(new ArrayList<>());
        frameworkProperties.setPostIngest(postIngestPlugins);
        frameworkProperties.setPreQuery(new ArrayList<>());
        frameworkProperties.setPostQuery(new ArrayList<>());
        frameworkProperties.setPreResource(new ArrayList<>());
        frameworkProperties.setPostResource(new ArrayList<>());
        frameworkProperties.setQueryResponsePostProcessor(mock(QueryResponsePostProcessor.class));
        frameworkProperties.setStorageProviders(Collections.singletonList(storageProvider));
        frameworkProperties.setMimeTypeMapper(new MimeTypeMapperImpl(Collections.singletonList(mimeTypeResolver)));
        frameworkProperties.setMimeTypeToTransformerMapper(mimeTypeToTransformerMapper);
        frameworkProperties.setValidationQueryFactory(
                new ValidationQueryFactory(new GeotoolsFilterAdapterImpl(), new GeotoolsFilterBuilder()));
        Map<String, FederatedSource> federatedSourceMap = new HashMap<>();
        if (federatedSources != null) {
            for (FederatedSource source : federatedSources) {
                federatedSourceMap.put(source.getId(), source);
            }
        }
        frameworkProperties.setFederatedSources(federatedSourceMap);
        framework = new CatalogFrameworkImpl(frameworkProperties);
        resourceFramework = new CatalogFrameworkImpl(frameworkProperties) {

            @Override
            protected ResourceInfo getResourceInfo(ResourceRequest resourceRequest, String site,
                    boolean isEnterprise, StringBuilder federatedSite, Map<String, Serializable> requestProperties)
                    throws ResourceNotSupportedException, ResourceNotFoundException {
                URI uri = null;
                Metacard metacard = new MetacardImpl();

                try {
                    uri = new URI("myURI");
                } catch (URISyntaxException e) {
                }

                return new ResourceInfo(metacard, uri);
            }

        };
        framework.bind(provider);
        framework.bind(storageProvider);
    }

    // Start testing MetacardWriter

    /**
     * Tests that the framework properly passes a create request to the local provider.
     */
    @Test
    public void testCreate() throws Exception {
        List<Metacard> metacards = new ArrayList<>();

        MetacardImpl newCard = new MetacardImpl();
        newCard.setId(null);
        metacards.add(newCard);

        CreateResponse response = framework.create(new CreateRequestImpl(metacards, null));
        assertEquals(response.getCreatedMetacards().size(), provider.size());
        for (Metacard curCard : response.getCreatedMetacards()) {
            assertNotNull(curCard.getId());
        }

        // make sure that the event was posted correctly
        assertTrue(eventAdmin.wasEventPosted());
        Metacard[] array = {};
        array = response.getCreatedMetacards().toArray(array);
        assertTrue(eventAdmin.wasEventPosted());
        assertEquals(eventAdmin.getLastEvent(), array[array.length - 1]);

    }

    /**
     * Tests that the framework properly passes a create request to the local provider.
     */
    @Test
    public void testCreateStorage() throws Exception {
        List<ContentItem> contentItems = new ArrayList<>();

        MetacardImpl newCard = new MetacardImpl();
        newCard.setId(null);
        ByteSource byteSource = new ByteSource() {
            @Override
            public InputStream openStream() throws IOException {
                return new ByteArrayInputStream("blah".getBytes());
            }
        };
        ContentItemImpl newItem = new ContentItemImpl(byteSource, "application/octet-stream", "blah", newCard);
        contentItems.add(newItem);

        CreateResponse response = framework.create(new CreateStorageRequestImpl(contentItems, null));
        assertEquals(response.getCreatedMetacards().size(), provider.size());
        assertEquals(response.getCreatedMetacards().size(), storageProvider.size());
        for (Metacard curCard : response.getCreatedMetacards()) {
            assertNotNull(curCard.getId());
        }

        // make sure that the event was posted correctly
        assertTrue(eventAdmin.wasEventPosted());
        Metacard[] array = {};
        array = response.getCreatedMetacards().toArray(array);
        assertTrue(eventAdmin.wasEventPosted());
        assertEquals(eventAdmin.getLastEvent(), array[array.length - 1]);

    }

    /**
     * Tests that the framework properly passes a create request to the local provider with attribute overrides.
     */
    @Test
    public void testCreateStorageWithAttributeOverrides() throws Exception {
        List<ContentItem> contentItems = new ArrayList<>();

        Map<String, Serializable> propertiesMap = new HashMap<>();
        HashMap<String, String> attributeMap = new HashMap<>();
        attributeMap.put(Metacard.TITLE, "test");
        attributeMap.put("foo", "bar");
        propertiesMap.put(Constants.ATTRIBUTE_OVERRIDES_KEY, attributeMap);

        MetacardImpl newCard = new MetacardImpl();
        newCard.setId(null);

        MetacardType metacardType = mock(MetacardType.class);

        AttributeDescriptor stringAttributeDescriptor = new AttributeDescriptorImpl(Metacard.TITLE, true, true,
                true, true, new AttributeType<String>() {
                    private static final long serialVersionUID = 1L;

                    @Override
                    public Class<String> getBinding() {
                        return String.class;
                    }

                    @Override
                    public AttributeFormat getAttributeFormat() {
                        return AttributeFormat.STRING;
                    }

                });

        when(metacardType.getAttributeDescriptor(Metacard.TITLE)).thenReturn(stringAttributeDescriptor);

        newCard.setType(metacardType);

        ByteSource byteSource = new ByteSource() {
            @Override
            public InputStream openStream() throws IOException {
                return new ByteArrayInputStream("blah".getBytes());
            }
        };
        ContentItemImpl newItem = new ContentItemImpl(byteSource, "application/octet-stream", "blah", newCard);
        contentItems.add(newItem);

        CreateResponse response = framework.create(new CreateStorageRequestImpl(contentItems, propertiesMap));
        assertEquals(response.getCreatedMetacards().size(), provider.size());
        assertEquals(response.getCreatedMetacards().size(), storageProvider.size());
        for (Metacard curCard : response.getCreatedMetacards()) {
            assertNotNull(curCard.getId());
            // Assert valid attribute is set for the metacard
            assertThat(curCard.getTitle(), is("test"));
            // Assert invalid attribute is not set for the metacard
            assertThat(curCard.getAttribute("foo"), nullValue());
        }

        // Assert That Attribute Overrides do not exist after create
        assertThat(attributeMap.get(Constants.ATTRIBUTE_OVERRIDES_KEY), nullValue());
    }

    /**
     * Tests that the framework properly passes a create request to the local provider with attribute overrides.
     */
    @Test
    public void testCreateStorageWithAttributeOverridesInvalidType() throws Exception {
        List<ContentItem> contentItems = new ArrayList<>();

        Map<String, Serializable> propertiesMap = new HashMap<>();
        HashMap<String, Object> attributeMap = new HashMap<>();
        attributeMap.put(Metacard.CREATED, "bad date");
        propertiesMap.put(Constants.ATTRIBUTE_OVERRIDES_KEY, attributeMap);

        MetacardImpl newCard = new MetacardImpl();
        newCard.setId(null);

        MetacardType metacardType = mock(MetacardType.class);

        AttributeDescriptor dateAttributeDescriptor = new AttributeDescriptorImpl(Metacard.CREATED, true, true,
                true, true, new AttributeType<Date>() {
                    private static final long serialVersionUID = 1L;

                    @Override
                    public Class<Date> getBinding() {
                        return Date.class;
                    }

                    @Override
                    public AttributeFormat getAttributeFormat() {
                        return AttributeFormat.DATE;
                    }

                });

        when(metacardType.getAttributeDescriptor(Metacard.TITLE)).thenReturn(dateAttributeDescriptor);

        newCard.setType(metacardType);

        ByteSource byteSource = new ByteSource() {
            @Override
            public InputStream openStream() throws IOException {
                return new ByteArrayInputStream("blah".getBytes());
            }
        };
        ContentItemImpl newItem = new ContentItemImpl(byteSource, "application/octet-stream", "blah", newCard);
        contentItems.add(newItem);

        CreateResponse response = framework.create(new CreateStorageRequestImpl(contentItems, propertiesMap));
        assertEquals(response.getCreatedMetacards().size(), provider.size());
        assertEquals(response.getCreatedMetacards().size(), storageProvider.size());
        for (Metacard curCard : response.getCreatedMetacards()) {
            assertNotNull(curCard.getId());
            // Assert value is not set for invalid format
            assertThat(curCard.getCreatedDate(), nullValue());
        }
    }

    /**
     * Tests that the framework properly passes an update request to the local provider.
     */
    @Test
    public void testUpdate() throws Exception {
        List<Metacard> metacards = new ArrayList<Metacard>();
        MetacardImpl newCard = new MetacardImpl();
        newCard.setId(null);
        metacards.add(newCard);

        // create the entry manually in the provider
        CreateResponse response = provider.create(new CreateRequestImpl(metacards, null));

        Metacard insertedCard = response.getCreatedMetacards().get(0);
        List<Entry<Serializable, Metacard>> updatedEntries = new ArrayList<Entry<Serializable, Metacard>>();
        updatedEntries.add(new SimpleEntry<Serializable, Metacard>(insertedCard.getId(), insertedCard));
        UpdateRequest request = new UpdateRequestImpl(updatedEntries, Metacard.ID, null);
        // send update to framework
        List<Update> returnedCards = framework.update(request).getUpdatedMetacards();
        for (Update curCard : returnedCards) {
            assertNotNull(curCard.getNewMetacard().getId());
        }

        // make sure that the event was posted correctly
        assertTrue(eventAdmin.wasEventPosted());
        assertEquals(eventAdmin.getLastEvent(), returnedCards.get(returnedCards.size() - 1).getOldMetacard());

    }

    /**
     * Tests that the framework properly passes an update request to the local provider.
     */
    @Test
    public void testUpdateStorage() throws Exception {
        List<ContentItem> contentItems = new ArrayList<>();

        MetacardImpl newCard = new MetacardImpl();
        newCard.setId(null);
        ByteSource byteSource = new ByteSource() {
            @Override
            public InputStream openStream() throws IOException {
                return new ByteArrayInputStream("blah".getBytes());
            }
        };
        ContentItemImpl newItem = new ContentItemImpl(byteSource, "application/octet-stream", "blah", newCard);
        contentItems.add(newItem);

        CreateResponse response = framework.create(new CreateStorageRequestImpl(contentItems, null));

        Metacard insertedCard = response.getCreatedMetacards().get(0);
        List<ContentItem> updatedContentItems = new ArrayList<>();
        updatedContentItems.add(
                new ContentItemImpl(insertedCard.getId(), byteSource, "application/octet-stream", insertedCard));
        UpdateStorageRequest request = new UpdateStorageRequestImpl(updatedContentItems, null);
        // send update to framework
        List<Update> returnedCards = framework.update(request).getUpdatedMetacards();
        for (Update curCard : returnedCards) {
            assertNotNull(curCard.getNewMetacard().getId());
        }

        assertEquals(response.getCreatedMetacards().size(), storageProvider.size());

        // make sure that the event was posted correctly
        assertTrue(eventAdmin.wasEventPosted());

    }

    /**
     * Tests that the framework properly passes a delete request to the local provider.
     */
    @Test
    public void testDelete() throws Exception {
        List<Metacard> metacards = new ArrayList<Metacard>();
        MetacardImpl newCard = new MetacardImpl();
        newCard.setId(null);
        metacards.add(newCard);

        // create the entry manually in the provider
        Metacard insertedCard = provider.create(new CreateRequestImpl(metacards, null)).getCreatedMetacards()
                .iterator().next();

        String[] ids = new String[1];
        ids[0] = insertedCard.getId();

        // send delete to framework
        List<Metacard> returnedCards = framework.delete(new DeleteRequestImpl(ids)).getDeletedMetacards();
        assertEquals(ids.length, returnedCards.size());
        // make sure that the event was posted correctly
        Metacard[] array = {};
        array = returnedCards.toArray(array);
        assertTrue(eventAdmin.wasEventPosted());
        assertEquals(eventAdmin.getLastEvent(), array[array.length - 1]);

    }

    /**
     * Tests that the framework properly passes an update by identifier request to the local
     * provider.
     */
    @Test
    public void testUpdateByIdentifier() throws Exception {
        List<Metacard> metacards = new ArrayList<Metacard>();
        MetacardImpl newCard = new MetacardImpl();
        newCard.setId(null);
        newCard.setResourceURI(new URI("DDF:///12345"));
        metacards.add(newCard);

        // create the entry manually in the provider
        List<Metacard> insertedCards = provider.create(new CreateRequestImpl(metacards)).getCreatedMetacards();

        ArrayList<URI> list = new ArrayList<URI>();

        list.add(new URI("DDF:///12345"));

        UpdateRequest request = new UpdateRequestImpl((URI[]) list.toArray(new URI[list.size()]), insertedCards);

        // send update to framework
        UpdateResponse updateResponse = framework.update(request);
        List<Update> returnedCards = updateResponse.getUpdatedMetacards();
        assertNotNull(returnedCards);
        assertEquals(list.size(), returnedCards.size());
        assertTrue(provider.hasReceivedUpdateByIdentifier());

        // make sure that the event was posted correctly
        assertTrue(eventAdmin.wasEventPosted());
        assertEquals(eventAdmin.getLastEvent(), returnedCards.get(returnedCards.size() - 1).getOldMetacard());
    }

    /**
     * Tests that the framework properly passes a delete by identifier request to the local
     * provider.
     */
    @Ignore
    @Test
    public void testDeleteByIdentifier() {
        // TODO create
    }

    // End testing MetacardWriter

    // Start testing CatalogFramework

    @Ignore
    @Test
    public void testFederateRead() {
        // TODO create
    }

    @Ignore
    @Test
    public void testFederateReadWithFrameworkName() {
        // TODO create
    }

    /*
     * Test for "ResourceResponse returns null ResourceRequest in the PostResourcePlugin"
     * 
     * The error this test case addresses is as follows: The PostResourcePlugin receives a
     * ResourceResponse with a null ResourceRequest.
     */
    @Test
    @Ignore
    public void testGetResourceWhenNonNullResourceRequestExpectPostResourcePluginToReceiveResourceResponseWithNonNullResourceRequest()
            throws Exception {

        String sourceId = "myId";
        resourceFramework.setId(sourceId);
        ResourceCache resourceCache = mock(ResourceCache.class);
        when(resourceCache.containsValid(isA(String.class), isA(Metacard.class))).thenReturn(false);
        //        ResourceResponse resourceResponseInCache = new ResourceResponseImpl(mockResource);
        //        when(resourceCache.put(isA(Metacard.class), isA(ResourceResponse.class),
        //             isA(ResourceRetriever.class), isA(Boolean.class))).thenReturn(resourceResponseInCache);
        resourceFramework.setProductCache(resourceCache);

        String resourceSiteName = "myId";

        // Execute
        LOGGER.debug("Testing CatalogFramework.getResource(ResourceRequest, String)...");
        ResourceResponse resourceResponse = resourceFramework.getResource(mockResourceRequest, resourceSiteName);
        LOGGER.debug("resourceResponse: {}", resourceResponse);

        // Verify
        /*
         * Verify that when PostResoucePlugin.process() is called, the ResourceResponse argument
         * contains a non-null ResourceRequest.
         */
        verify(mockPostResourcePlugin).process(argument.capture());
        assertNotNull("PostResourcePlugin received a ResourceResponse with a null ResourceRequest.",
                argument.getValue().getRequest());

        /*
         * We really don't need to assert this since we return our mockResourceResponse from
         * PostResourcePlugin.process()
         */
        // assertNotNull("ResourceResponse.getResource() returned a ResourceResponse with a null ResourceRequest.",
        // resourceResponse.getRequest());
    }

    @Test(expected = FederationException.class)
    public void testPreQueryStopExecution() throws UnsupportedQueryException, FederationException {

        SourcePoller poller = mock(SourcePoller.class);
        when(poller.getCachedSource(isA(Source.class))).thenReturn(null);

        MockMemoryProvider provider = new MockMemoryProvider("Provider", "Provider", "v1.0", "DDF",
                new HashSet<ContentType>(), true, new Date());

        FederationStrategy federationStrategy = mock(FederationStrategy.class);

        QueryRequest request = mock(QueryRequest.class);

        when(request.getQuery()).thenReturn(mock(Query.class));

        PreQueryPlugin stopQueryPlugin = new PreQueryPlugin() {

            @Override
            public QueryRequest process(QueryRequest input)
                    throws PluginExecutionException, StopProcessingException {
                throw new StopProcessingException("Testing that the framework will stop the query.");
            }
        };

        FrameworkProperties frameworkProperties = new FrameworkProperties();
        frameworkProperties.setSourcePoller(poller);
        frameworkProperties.setPreQuery(Arrays.asList(stopQueryPlugin));
        frameworkProperties.setFederationStrategy(federationStrategy);
        frameworkProperties.setCatalogProviders(Collections.singletonList(provider));

        CatalogFrameworkImpl framework = new CatalogFrameworkImpl(frameworkProperties);

        framework.bind(provider);
        framework.query(request);
    }

    @Test(expected = FederationException.class)
    public void testPostQueryStopExecution() throws UnsupportedQueryException, FederationException {

        SourcePoller poller = mock(SourcePoller.class);

        when(poller.getCachedSource(isA(Source.class))).thenReturn(null);

        BundleContext context = null;

        FilterFactory filterFactory = new FilterFactoryImpl();

        Filter filter = filterFactory.like(filterFactory.property(Metacard.METADATA), "goodyear", "*", "?", "/",
                false);

        QueryRequest request = new QueryRequestImpl(new QueryImpl(filter));

        SourceResponseImpl sourceResponse = new SourceResponseImpl(request, new ArrayList<Result>());

        QueryResponseImpl queryResponse = new QueryResponseImpl(sourceResponse, "anyId");

        CatalogProvider provider = mock(CatalogProvider.class);

        when(provider.query(isA(QueryRequest.class))).thenReturn(sourceResponse);

        FederationStrategy federationStrategy = mock(FederationStrategy.class);

        when(federationStrategy.federate(isA(List.class), isA(QueryRequest.class))).thenReturn(queryResponse);

        PostQueryPlugin stopQueryPlugin = new PostQueryPlugin() {

            @Override
            public QueryResponse process(QueryResponse input)
                    throws PluginExecutionException, StopProcessingException {
                throw new StopProcessingException("Testing that the framework will stop the query.");
            }

        };
        FrameworkProperties props = new FrameworkProperties();
        props.setCatalogProviders(Collections.singletonList((CatalogProvider) provider));
        props.setBundleContext(context);
        props.setPostQuery(Arrays.asList(stopQueryPlugin));
        props.setFederationStrategy(federationStrategy);
        props.setQueryResponsePostProcessor(mock(QueryResponsePostProcessor.class));
        props.setSourcePoller(poller);
        props.setFilterBuilder(new GeotoolsFilterBuilder());
        CatalogFrameworkImpl framework = new CatalogFrameworkImpl(props);

        framework.bind(provider);
        framework.query(request);
    }

    @Ignore
    @Test
    public void testFederateQueryWithFrameworkName() {
        // TODO create
    }

    @Test(expected = CatalogTransformerException.class)
    public void testQueryTransformWithTransformException() throws Exception {
        BundleContext context = mock(BundleContext.class);
        QueryResponseTransformer transformer = mock(QueryResponseTransformer.class);
        ServiceReference reference = mock(ServiceReference.class);
        ServiceReference[] serviceReferences = new ServiceReference[] { reference };
        when(context.getServiceReferences(anyString(), anyString())).thenReturn(serviceReferences);
        when(context.getService(isA(ServiceReference.class))).thenReturn(transformer);
        when(transformer.transform(isA(SourceResponse.class), isA(Map.class)))
                .thenThrow(new CatalogTransformerException("Could not transform"));

        CatalogFramework framework = this.createDummyCatalogFramework(provider, storageProvider, context,
                eventAdmin, true);
        SourceResponse response = new SourceResponseImpl(null, null);

        framework.transform(response, "NONE", new HashMap<String, Serializable>());

    }

    @Test(expected = IllegalArgumentException.class)
    public void testQueryTransformWithNullResponse() throws Exception {
        BundleContext context = mock(BundleContext.class);
        ServiceReference reference = mock(ServiceReference.class);
        ServiceReference[] serviceReferences = new ServiceReference[] { reference };
        when(context.getServiceReferences(anyString(), anyString())).thenReturn(serviceReferences);

        CatalogFramework framework = this.createDummyCatalogFramework(provider, storageProvider, context,
                eventAdmin, true);

        framework.transform((SourceResponse) null, "NONE", new HashMap<String, Serializable>());

    }

    @Test(expected = IllegalArgumentException.class)
    public void testQueryTransformWithInvalidSyntaxException() throws Exception {
        BundleContext context = mock(BundleContext.class);

        when(context.getServiceReferences(anyString(), anyString()))
                .thenThrow(new InvalidSyntaxException("Invalid Syntax", ""));

        CatalogFramework framework = this.createDummyCatalogFramework(provider, storageProvider, context,
                eventAdmin, true);

        framework.transform((SourceResponse) null, "NONE", new HashMap<String, Serializable>());

    }

    @Test
    public void testQueryTransform() throws Exception {
        BundleContext context = mock(BundleContext.class);
        QueryResponseTransformer transformer = mock(QueryResponseTransformer.class);
        ServiceReference reference = mock(ServiceReference.class);
        ServiceReference[] serviceReferences = new ServiceReference[] { reference };
        when(context.getServiceReferences(anyString(), anyString())).thenReturn(serviceReferences);
        when(context.getService(isA(ServiceReference.class))).thenReturn(transformer);
        when(transformer.transform(isA(SourceResponse.class), isA(Map.class)))
                .thenReturn(new BinaryContentImpl(null));

        CatalogFramework framework = this.createDummyCatalogFramework(provider, storageProvider, context,
                eventAdmin, true);
        SourceResponse response = new SourceResponseImpl(null, null);

        BinaryContent content = framework.transform(response, "NONE", new HashMap<String, Serializable>());

        assertNotNull(content);
    }

    @Test(expected = CatalogTransformerException.class)
    public void testMetacardTransformWithTransformException() throws Exception {
        BundleContext context = mock(BundleContext.class);
        MetacardTransformer transformer = mock(MetacardTransformer.class);
        ServiceReference reference = mock(ServiceReference.class);
        ServiceReference[] serviceReferences = new ServiceReference[] { reference };
        when(context.getServiceReferences(anyString(), anyString())).thenReturn(serviceReferences);
        when(context.getService(isA(ServiceReference.class))).thenReturn(transformer);
        when(transformer.transform(isA(Metacard.class), isA(Map.class)))
                .thenThrow(new CatalogTransformerException("Could not transform"));

        CatalogFramework framework = this.createDummyCatalogFramework(provider, storageProvider, context,
                eventAdmin, true);
        MetacardImpl newCard = new MetacardImpl();
        newCard.setId(null);

        framework.transform(newCard, "NONE", new HashMap<String, Serializable>());

    }

    @Test(expected = IllegalArgumentException.class)
    public void testMetacardTransformWithNullMetacard() throws Exception {
        BundleContext context = mock(BundleContext.class);
        ServiceReference reference = mock(ServiceReference.class);
        ServiceReference[] serviceReferences = new ServiceReference[] { reference };
        when(context.getServiceReferences(anyString(), anyString())).thenReturn(serviceReferences);

        CatalogFramework framework = this.createDummyCatalogFramework(provider, storageProvider, context,
                eventAdmin, true);

        framework.transform((Metacard) null, "NONE", new HashMap<String, Serializable>());

    }

    @Test(expected = IllegalArgumentException.class)
    public void testMetacardTransformWithInvalidSyntaxException() throws Exception {
        BundleContext context = mock(BundleContext.class);

        when(context.getServiceReferences(anyString(), anyString()))
                .thenThrow(new InvalidSyntaxException("Invalid Syntax", ""));

        CatalogFramework framework = this.createDummyCatalogFramework(provider, storageProvider, context,
                eventAdmin, true);

        framework.transform((Metacard) null, "NONE", new HashMap<String, Serializable>());

    }

    @Test
    public void testMetacardTransform() throws Exception {
        BundleContext context = mock(BundleContext.class);
        MetacardTransformer transformer = mock(MetacardTransformer.class);
        ServiceReference reference = mock(ServiceReference.class);
        ServiceReference[] serviceReferences = new ServiceReference[] { reference };
        when(context.getServiceReferences(anyString(), anyString())).thenReturn(serviceReferences);
        when(context.getService(isA(ServiceReference.class))).thenReturn(transformer);
        when(transformer.transform(isA(Metacard.class), isA(Map.class))).thenReturn(new BinaryContentImpl(null));

        CatalogFramework framework = this.createDummyCatalogFramework(provider, storageProvider, context,
                eventAdmin, true);
        MetacardImpl newCard = new MetacardImpl();
        newCard.setId(null);

        BinaryContent content = framework.transform(newCard, "NONE", new HashMap<String, Serializable>());

        assertNotNull(content);
    }

    @Test
    public void testGetSites() {
        framework.bind(provider);
        framework.setId("ddf");

        Set<String> ids = new HashSet<String>();
        for (FederatedSource source : federatedSources) {
            ids.add(source.getId());
        }
        ids.add(framework.getId());

        SourceInfoRequest request = new SourceInfoRequestSources(true, ids);

        SourceInfoResponse response = null;
        try {
            response = framework.getSourceInfo(request);
        } catch (SourceUnavailableException e) {
            fail();
        }
        Set<SourceDescriptor> sourceDescriptors = response.getSourceInfo();

        List<String> siteNames = new ArrayList<String>();
        for (SourceDescriptor descriptor : sourceDescriptors) {
            LOGGER.debug("Descriptor id: {}", descriptor.getSourceId());
            siteNames.add(descriptor.getSourceId());
        }

        // add a plus one for now to simulate that the framework is ad
        // assertTrue( sourceDescriptor.containsAll( federatedSources ) );
        // assertTrue( sourceDescriptor.containsAll( expectedSourceSet ) );
        assertEquals(ids.size(), sourceDescriptors.size());

        String[] expectedOrdering = { "A", "B", "C", framework.getId() };

        assertArrayEquals(expectedOrdering, siteNames.toArray(new String[siteNames.size()]));

    }

    @Test
    public void testGetFederatedSources() {
        SourceInfoRequest request = new SourceInfoRequestEnterprise(true);
        SourceInfoResponse response = null;
        try {
            response = framework.getSourceInfo(request);
        } catch (SourceUnavailableException e) {
            fail();
        }
        Set<SourceDescriptor> sourceDescriptors = response.getSourceInfo();
        for (SourceDescriptor descriptor : sourceDescriptors) {
            LOGGER.debug("Descriptor id: {}", descriptor.getSourceId());
        }

        // The "+1" is to account for the CatalogFramework source descriptor.
        // Even if no local catalog provider is configured, the catalog framework's
        // site info is included in the SourceDescriptos list.
        assertEquals(federatedSources.size() + 1, sourceDescriptors.size());
    }

    @Test
    public void testGetUnavailableFederatedSources() {
        List<FederatedSource> federatedSources = createDefaultFederatedSourceList(false);

        // Mock register the federated sources in the container
        SourcePollerRunner runner = new SourcePollerRunner();
        SourcePoller poller = new SourcePoller(runner);
        for (FederatedSource source : federatedSources) {
            runner.bind(source);
        }
        FrameworkProperties frameworkProperties = new FrameworkProperties();
        frameworkProperties.setSourcePoller(poller);
        Map<String, FederatedSource> sources = new HashMap<>();
        for (FederatedSource federatedSource : federatedSources) {
            sources.put(federatedSource.getId(), federatedSource);
        }
        frameworkProperties.setFederatedSources(sources);
        CatalogFrameworkImpl framework = new CatalogFrameworkImpl(frameworkProperties);

        SourceInfoRequest request = new SourceInfoRequestEnterprise(true);
        SourceInfoResponse response = null;
        try {
            response = framework.getSourceInfo(request);
        } catch (SourceUnavailableException e) {
            fail();
        }
        Set<SourceDescriptor> sourceDescriptors = response.getSourceInfo();
        for (SourceDescriptor descriptor : sourceDescriptors) {
            LOGGER.debug("Descriptor id: {}", descriptor.getSourceId());
            if (StringUtils.isNotBlank(descriptor.getId())) {
                assertFalse(descriptor.isAvailable());
                // No contentTypes should be listed if the source is unavailable
                assertTrue(descriptor.getContentTypes().isEmpty());
            }
        }

        // The "+1" is to account for the CatalogFramework source descriptor.
        // Even if no local catalog provider is configured, the catalog
        // framework's
        // site info is included in the SourceDescriptos list.
        assertEquals(federatedSources.size() + 1, sourceDescriptors.size());
    }

    @Test
    public void testGetFederatedSourcesDuplicates() {
        List<FederatedSource> federatedSources = createDefaultFederatedSourceList(true);
        // Duplicate Site
        FederatedSource siteC2 = new MockSource("C", "Site C2", "v1.0", "DDF", null, true, new Date());
        federatedSources.add(siteC2);

        // Expected Sites
        List<FederatedSource> expectedSources = createDefaultFederatedSourceList(true);

        // Mock register the federated sources in the container
        // Mock the source poller
        SourcePoller mockPoller = mock(SourcePoller.class);
        when(mockPoller.getCachedSource(isA(Source.class))).thenReturn(null);

        FrameworkProperties frameworkProperties = new FrameworkProperties();
        frameworkProperties.setSourcePoller(mockPoller);
        Map<String, FederatedSource> sources = new HashMap<>();
        for (FederatedSource federatedSource : expectedSources) {
            sources.put(federatedSource.getId(), federatedSource);
        }
        frameworkProperties.setFederatedSources(sources);
        CatalogFrameworkImpl framework = new CatalogFrameworkImpl(frameworkProperties);

        // Returned Sites
        SourceInfoRequest request = new SourceInfoRequestEnterprise(true);

        SourceInfoResponse response = null;
        try {
            response = framework.getSourceInfo(request);
        } catch (SourceUnavailableException e) {
            LOGGER.debug("SourceUnavilable", e);
            fail();
        }
        Set<SourceDescriptor> sourceDescriptors = response.getSourceInfo();
        // should contain ONLY the original federated sites and the catalog framework's
        // site info (even though it has no local catalog provider configured) - hence,
        // the "+1"
        assertEquals(expectedSources.size() + 1, sourceDescriptors.size());

    }

    @Test
    public void testGetAllSiteNames() {
        String frameworkName = "DDF";
        CatalogProvider provider = new MockMemoryProvider("Provider", "Provider", "v1.0", "DDF",
                new HashSet<ContentType>(), true, new Date());
        List<FederatedSource> federatedSources = createDefaultFederatedSourceList(true);

        // Expected Set of Names
        Set<String> expectedNameSet = new HashSet<String>();
        expectedNameSet.add(frameworkName);
        for (FederatedSource curSite : federatedSources) {
            expectedNameSet.add(curSite.getId());
        }

        // Mock register the provider in the container
        // Mock the source poller
        SourcePoller mockPoller = mock(SourcePoller.class);
        when(mockPoller.getCachedSource(isA(Source.class))).thenReturn(null);

        FrameworkProperties frameworkProperties = new FrameworkProperties();
        frameworkProperties.setSourcePoller(mockPoller);
        Map<String, FederatedSource> sources = new HashMap<>();
        for (FederatedSource federatedSource : federatedSources) {
            sources.put(federatedSource.getId(), federatedSource);
        }
        frameworkProperties.setFederatedSources(sources);
        frameworkProperties.setCatalogProviders(Collections.singletonList(provider));

        CatalogFrameworkImpl framework = new CatalogFrameworkImpl(frameworkProperties);
        framework.bind(provider);
        framework.setId(frameworkName);

        // Returned Set of Names
        // Returned Sites
        SourceInfoRequest request = new SourceInfoRequestEnterprise(true);
        SourceInfoResponse response = null;
        try {
            response = framework.getSourceInfo(request);
        } catch (SourceUnavailableException e) {
            LOGGER.debug("SourceUnavilable", e);
            fail();
        }
        assert (response != null);
        Set<SourceDescriptor> sourceDescriptors = response.getSourceInfo();
        // should contain ONLY the original federated sites
        assertEquals(expectedNameSet.size(), sourceDescriptors.size());
        Set<String> returnedSourceIds = new HashSet<String>();

        for (SourceDescriptor sd : sourceDescriptors) {
            returnedSourceIds.add(sd.getSourceId());
        }

        for (String id : returnedSourceIds) {
            LOGGER.debug("returned sourceId: {}", id);
        }
        assertTrue(expectedNameSet.equals(returnedSourceIds));

    }

    // End testing CatalogFramework

    // Test negative use-cases (expected errors)

    /**
     * Tests that the framework properly throws a catalog exception when the local provider is not
     * available for create.
     *
     * @throws SourceUnavailableException
     */
    @Test(expected = SourceUnavailableException.class)
    public void testProviderUnavailableCreate() throws SourceUnavailableException {
        MockEventProcessor eventAdmin = new MockEventProcessor();
        MockMemoryProvider provider = new MockMemoryProvider("Provider", "Provider", "v1.0", "DDF",
                new HashSet<ContentType>(), false, null);
        CatalogFramework framework = createDummyCatalogFramework(provider, storageProvider, eventAdmin, false);
        List<Metacard> metacards = new ArrayList<Metacard>();
        MetacardImpl newCard = new MetacardImpl();
        newCard.setId(null);
        metacards.add(newCard);

        CreateRequest create = new CreateRequestImpl(metacards);

        // expected to throw exception due to catalog provider being unavailable
        try {
            framework.create(create);
        } catch (IngestException e) {
            fail();
        }

    }

    /**
     * Tests that the framework properly throws a catalog exception when the local provider is not
     * available for update by id.
     *
     * @throws IngestException
     * @throws SourceUnavailableException
     */
    @Test(expected = SourceUnavailableException.class)
    public void testProviderUnavailableUpdateByID() throws SourceUnavailableException {
        MockEventProcessor eventAdmin = new MockEventProcessor();
        MockMemoryProvider provider = new MockMemoryProvider("Provider", "Provider", "v1.0", "DDF",
                new HashSet<ContentType>(), false, null);
        CatalogFramework framework = this.createDummyCatalogFramework(provider, storageProvider, eventAdmin, false);
        List<Metacard> metacards = new ArrayList<Metacard>();
        List<URI> uris = new ArrayList<URI>();
        // expected to throw exception due to catalog provider being unavailable
        try {
            MetacardImpl newCard = new MetacardImpl();
            newCard.setId(null);
            newCard.setResourceURI(new URI("uri:///1234"));
            metacards.add(newCard);
            uris.add(new URI("uri:///1234"));

            UpdateRequest update = new UpdateRequestImpl((URI[]) uris.toArray(new URI[uris.size()]), metacards);

            framework.update(update);
        } catch (URISyntaxException e) {
            fail();
        } catch (IngestException e) {
            fail();
        }
    }

    /**
     * Tests that the framework properly throws a catalog exception when the local provider is not
     * available for update by identifier.
     *
     * @throws IngestException
     * @throws SourceUnavailableException
     */
    @Test(expected = SourceUnavailableException.class)
    public void testProviderUnavailableUpdateByIdentifier() throws SourceUnavailableException {
        MockEventProcessor eventAdmin = new MockEventProcessor();
        MockMemoryProvider provider = new MockMemoryProvider("Provider", "Provider", "v1.0", "DDF",
                new HashSet<ContentType>(), false, null);
        CatalogFramework framework = this.createDummyCatalogFramework(provider, storageProvider, eventAdmin, false);
        List<Metacard> metacards = new ArrayList<Metacard>();
        List<URI> uris = new ArrayList<URI>();

        // expected to throw exception due to catalog provider being unavailable
        try {
            MetacardImpl newCard = new MetacardImpl();
            newCard.setId(null);
            newCard.setResourceURI(new URI("uri:///1234"));
            metacards.add(newCard);
            uris.add(new URI("uri:////1234"));

            UpdateRequest update = new UpdateRequestImpl((URI[]) uris.toArray(new URI[uris.size()]), metacards);

            framework.update(update);
        } catch (URISyntaxException e) {
            fail();
        } catch (IngestException e) {
            fail();
        }
    }

    /**
     * Tests that the framework properly throws a catalog exception when the local provider is not
     * available for delete by id.
     *
     * @throws IngestException
     * @throws SourceUnavailableException
     */
    @Test(expected = SourceUnavailableException.class)
    public void testProviderUnavailableDeleteByID() throws SourceUnavailableException {
        MockEventProcessor eventAdmin = new MockEventProcessor();
        MockMemoryProvider provider = new MockMemoryProvider("Provider", "Provider", "v1.0", "DDF",
                new HashSet<ContentType>(), false, null);
        CatalogFramework framework = this.createDummyCatalogFramework(provider, storageProvider, eventAdmin, false);
        List<String> ids = new ArrayList<String>();
        ids.add("1234");

        DeleteRequest request = new DeleteRequestImpl((String[]) ids.toArray(new String[ids.size()]));

        // expected to throw exception due to catalog provider being unavailable
        try {
            framework.delete(request);
        } catch (IngestException e) {
            fail();
        }

    }

    /**
     * Tests that the framework properly throws a catalog exception when the local provider is not
     * available for delete by identifier.
     *
     * @throws IngestException
     * @throws SourceUnavailableException
     */
    @Test(expected = SourceUnavailableException.class)
    public void testProviderUnavailableDeleteByIdentifier() throws SourceUnavailableException {
        MockEventProcessor eventAdmin = new MockEventProcessor();
        MockMemoryProvider provider = new MockMemoryProvider("Provider", "Provider", "v1.0", "DDF",
                new HashSet<ContentType>(), false, null);
        CatalogFramework framework = this.createDummyCatalogFramework(provider, storageProvider, eventAdmin, false);
        List<URI> uris = new ArrayList<URI>();
        try {
            uris.add(new URI("id://1234"));
            DeleteRequest request = new DeleteRequestImpl((URI[]) uris.toArray(new URI[uris.size()]));

            // expected to throw exception due to catalog provider being
            // unavailable
            framework.delete(request);
        } catch (URISyntaxException e) {
            fail();
        } catch (IngestException e) {
            fail();
        }

    }

    /**
     * Tests that the framework properly throws a catalog exception when there are no sites
     * (federated or local) that are available to perform the query.
     *
     * @throws SourceUnavailableException
     */
    @Ignore
    @Test(expected = SourceUnavailableException.class)
    public void testNoSitesAvailableFederatedQuery() throws SourceUnavailableException {
        CatalogFramework framework = this.createDummyCatalogFramework(null, null, null, false);

        QueryRequest request = new QueryRequestImpl(null);

        try {
            framework.query(request);
        } catch (UnsupportedQueryException e) {
            // we don't even care what the query was
        } catch (FederationException e) {
            fail();
        }
    }

    /**
     * Tests that the framework properly throws a catalog exception when the query being passed in
     * is null.
     *
     * @throws UnsupportedQueryException
     */
    @Test(expected = UnsupportedQueryException.class)
    public void testNullQuery() throws UnsupportedQueryException {
        boolean isAvailable = false;
        CatalogProvider provider = new MockMemoryProvider("Provider", "Provider", "v1.0", "DDF",
                new HashSet<ContentType>(), isAvailable, new Date());

        CatalogFramework framework = this.createDummyCatalogFramework(provider, storageProvider, null, true);

        try {
            framework.query(null);
        } catch (FederationException e) {
            fail();
        } catch (SourceUnavailableException e) {
            fail();
        }
    }

    /**
     * Tests that the framework properly throws a catalog exception when the federated query being
     * passed in is null.
     *
     * @throws UnsupportedQueryException
     */
    @Test(expected = UnsupportedQueryException.class)
    public void testNullFederatedQuery() throws UnsupportedQueryException {
        boolean isAvailable = false;
        CatalogProvider provider = new MockMemoryProvider("Provider", "Provider", "v1.0", "DDF",
                new HashSet<ContentType>(), isAvailable, new Date());
        createDefaultFederatedSourceList(isAvailable);

        CatalogFramework framework = this.createDummyCatalogFramework(provider, storageProvider, null, true);

        try {
            framework.query(null, null);
        } catch (FederationException e) {
            fail();
        } catch (SourceUnavailableException e) {
            fail();
        }
    }

    // @Test( expected = CatalogException.class )
    // public void testNullIdsRead() throws CatalogException
    // {
    // MockEventProcessor eventAdmin = new MockEventProcessor();
    // MockMemoryProvider provider = new MockMemoryProvider( "Provider",
    // "Provider", "v1.0", "DDF",
    // new HashSet<MetacardType>(), true, new Date() );
    // CatalogFramework framework = this.createDummyCatalogFramework(provider,
    // eventAdmin);
    //
    // // call framework with null for the read ids list
    // // framework.read( null, null );
    // }

    @Test(expected = IngestException.class)
    public void testNullEntriesCreate() throws IngestException {
        MockEventProcessor eventAdmin = new MockEventProcessor();
        MockMemoryProvider provider = new MockMemoryProvider("Provider", "Provider", "v1.0", "DDF",
                new HashSet<ContentType>(), true, new Date());
        CatalogFramework framework = this.createDummyCatalogFramework(provider, storageProvider, eventAdmin, true);

        // call framework with null request
        try {
            framework.create((CreateRequest) null);
        } catch (SourceUnavailableException e) {
            fail();
        }
    }

    @Test(expected = IngestException.class)
    public void testNullEntriesUpdate() throws IngestException {
        MockEventProcessor eventAdmin = new MockEventProcessor();
        MockMemoryProvider provider = new MockMemoryProvider("Provider", "Provider", "v1.0", "DDF",
                new HashSet<ContentType>(), true, new Date());
        CatalogFramework framework = this.createDummyCatalogFramework(provider, storageProvider, eventAdmin, true);

        // call framework with null request
        try {
            framework.update((UpdateRequest) null);
        } catch (SourceUnavailableException e) {
            fail();
        }
    }

    @Test(expected = IngestException.class)
    public void testNullIdsDelete() throws IngestException {
        MockEventProcessor eventAdmin = new MockEventProcessor();
        MockMemoryProvider provider = new MockMemoryProvider("Provider", "Provider", "v1.0", "DDF",
                new HashSet<ContentType>(), true, new Date());
        CatalogFramework framework = this.createDummyCatalogFramework(provider, storageProvider, eventAdmin, true);

        // call framework with null request
        try {
            framework.delete(null);
        } catch (SourceUnavailableException e) {
            fail();
        }
    }

    @Test(expected = IngestException.class)
    public void testProviderRuntimeExceptionOnCreate() throws IngestException {
        MockEventProcessor eventAdmin = new MockEventProcessor();
        // use exception provider instead of memory
        MockExceptionProvider provider = new MockExceptionProvider("Provider", "Provider", "v1.0", "DDF",
                new HashSet<ContentType>(), true, null);
        CatalogFramework framework = this.createDummyCatalogFramework(provider, storageProvider, eventAdmin, true);
        List<Metacard> metacards = new ArrayList<Metacard>();
        MetacardImpl newCard = new MetacardImpl();
        newCard.setId(null);
        metacards.add(newCard);

        CreateRequest create = new CreateRequestImpl((Metacard) null);
        try {
            framework.create(create);
        } catch (SourceUnavailableException e) {
            fail();
        }

    }

    @Test(expected = IngestException.class)
    public void testProviderRuntimeExceptionOnUpdateByID() throws IngestException {
        MockEventProcessor eventAdmin = new MockEventProcessor();
        // use exception provider instead of memory
        MockExceptionProvider provider = new MockExceptionProvider("Provider", "Provider", "v1.0", "DDF",
                new HashSet<ContentType>(), true, null);
        CatalogFramework framework = this.createDummyCatalogFramework(provider, storageProvider, eventAdmin, true);
        List<Entry<Object, Metacard>> metacards = new ArrayList<Entry<Object, Metacard>>();
        HashMap<Object, Metacard> map = new HashMap<Object, Metacard>();

        // expected to throw exception due to catalog provider being unavailable
        try {
            MetacardImpl newCard = new MetacardImpl();
            newCard.setId(null);
            newCard.setResourceURI(new URI("uri:///1234"));
            map.put(Metacard.ID, newCard);
            metacards.addAll(map.entrySet());

            UpdateRequest update = new UpdateRequestImpl(null, Metacard.ID, null);
            framework.update(update);
        } catch (URISyntaxException e) {
            fail();
        } catch (SourceUnavailableException e) {
            fail();
        }
    }

    @Test(expected = IngestException.class)
    public void testProviderRuntimeExceptionOnUpdateByIdentifier() throws IngestException {
        MockEventProcessor eventAdmin = new MockEventProcessor();
        // use exception provider instead of memory
        MockExceptionProvider provider = new MockExceptionProvider("Provider", "Provider", "v1.0", "DDF",
                new HashSet<ContentType>(), true, null);
        CatalogFramework framework = this.createDummyCatalogFramework(provider, storageProvider, eventAdmin, true);
        List<Entry<Object, Metacard>> metacards = new ArrayList<Entry<Object, Metacard>>();
        HashMap<Object, Metacard> map = new HashMap<Object, Metacard>();

        try {
            MetacardImpl newCard = new MetacardImpl();
            newCard.setId(null);
            newCard.setResourceURI(new URI("uri:///1234"));
            map.put(Metacard.ID, newCard);
            metacards.addAll(map.entrySet());

            UpdateRequest update = new UpdateRequestImpl(null, Metacard.RESOURCE_URI, null);
            framework.update(update);
        } catch (URISyntaxException e) {
            fail();
        } catch (SourceUnavailableException e) {
            fail();
        }

    }

    @Test(expected = IngestException.class)
    public void testProviderRuntimeExceptionOnDeleteByID() throws IngestException {
        MockEventProcessor eventAdmin = new MockEventProcessor();
        // use exception provider instead of memory
        MockExceptionProvider provider = new MockExceptionProvider("Provider", "Provider", "v1.0", "DDF",
                new HashSet<ContentType>(), true, null);
        MockMemoryStorageProvider storageProvider = new MockMemoryStorageProvider();
        CatalogFramework framework = this.createDummyCatalogFramework(provider, storageProvider, eventAdmin, true);
        List<String> ids = new ArrayList<String>();
        ids.add("1234");

        DeleteRequest request = new DeleteRequestImpl((String[]) ids.toArray(new String[ids.size()]));

        // expected to throw exception due to catalog provider
        try {
            framework.delete(request);
        } catch (SourceUnavailableException e) {
            fail();
        }
    }

    @Test(expected = IngestException.class)
    public void testProviderRuntimeExceptionOnDeleteByIdentifier() throws IngestException {
        MockEventProcessor eventAdmin = new MockEventProcessor();
        // use exception provider instead of memory
        MockExceptionProvider provider = new MockExceptionProvider("Provider", "Provider", "v1.0", "DDF",
                new HashSet<ContentType>(), true, null);
        CatalogFramework framework = this.createDummyCatalogFramework(provider, storageProvider, eventAdmin, true);
        // List<MetacardType> identifiers = new ArrayList<MetacardType>();
        // identifiers.add( new MetacardTypeImpl( "id", "1234" ) );
        ArrayList<URI> uris = new ArrayList<URI>();

        DeleteRequest request = new DeleteRequestImpl((URI[]) uris.toArray(new URI[uris.size()]));
        // expected to throw exception due to catalog provider being unavailable
        try {
            framework.delete(request);
        } catch (SourceUnavailableException e) {
            fail();
        }
    }

    @Ignore
    @Test(expected = CatalogTransformerException.class)
    public void testMetacardTransformWithBadShortname() throws CatalogTransformerException {
        MockEventProcessor eventAdmin = new MockEventProcessor();
        MockMemoryProvider provider = new MockMemoryProvider("Provider", "Provider", "v1.0", "DDF",
                new HashSet<ContentType>(), true, new Date());
        // TODO pass in bundle context
        CatalogFramework framework = this.createDummyCatalogFramework(provider, storageProvider, eventAdmin, true);
        MetacardImpl newCard = new MetacardImpl();
        newCard.setId(null);

        framework.transform(newCard, "NONE", new HashMap<String, Serializable>());

    }

    /**
     * Tests that you can get a resource's (product) options. Covers the case where the source ID
     * specified is actually the local catalog provider's site name (so this reduces down to a
     * getResourceOptions for local provider); and the case where a federated source is specified.
     * <p>
     * Test for DDF-1763.
     *
     * @throws Exception
     */
    @Test
    public void testGetResourceOptions() throws Exception {
        String localProviderName = "ddf";
        String federatedSite1Name = "fed-site-1";
        String metacardId = "123";

        // The resource's URI
        URI metacardUri = new URI(
                "http:///27+Nov+12+12%3A30%3A04?MyPhotograph%0Ahttp%3A%2F%2F172.18.14.53%3A8080%2Fabc%2Fimages%2FActionable.jpg%0AMyAttachment%0Ahttp%3A%2F%2F172.18.14.53%3A8080%2Fabc#abc.xyz.dao.URLResourceOptionDataAccessObject");

        Set<String> supportedOptions = new HashSet<String>();
        supportedOptions.add("MyPhotograph");
        supportedOptions.add("MyAttachment");

        // Catalog Provider
        CatalogProvider provider = mock(CatalogProvider.class);
        when(provider.getId()).thenReturn(localProviderName);
        when(provider.isAvailable(isA(SourceMonitor.class))).thenReturn(true);
        when(provider.isAvailable()).thenReturn(true);

        // Federated Source 1
        FederatedSource federatedSource1 = mock(FederatedSource.class);
        when(federatedSource1.getId()).thenReturn(federatedSite1Name);
        when(federatedSource1.isAvailable(isA(SourceMonitor.class))).thenReturn(true);
        when(federatedSource1.isAvailable()).thenReturn(true);
        when(federatedSource1.getOptions(isA(Metacard.class))).thenReturn(supportedOptions);

        List<FederatedSource> federatedSources = new ArrayList<FederatedSource>();
        federatedSources.add(federatedSource1);

        // Mock register the provider in the container
        // Mock the source poller
        SourcePoller mockPoller = mock(SourcePoller.class);
        when(mockPoller.getCachedSource(isA(Source.class))).thenReturn(null);

        Metacard metacard = mock(Metacard.class);
        when(metacard.getId()).thenReturn(metacardId);
        when(metacard.getResourceURI()).thenReturn(metacardUri);
        Result result = mock(Result.class);
        when(result.getMetacard()).thenReturn(metacard);
        List<Result> results = new ArrayList<Result>();
        results.add(result);

        QueryResponse queryResponse = mock(QueryResponse.class);
        when(queryResponse.getResults()).thenReturn(results);
        FederationStrategy strategy = mock(FederationStrategy.class);
        when(strategy.federate(isA(federatedSources.getClass()), isA(QueryRequest.class)))
                .thenReturn(queryResponse);

        ResourceReader resourceReader = mock(ResourceReader.class);
        Set<String> supportedSchemes = new HashSet<String>();
        supportedSchemes.add("http");
        when(resourceReader.getSupportedSchemes()).thenReturn(supportedSchemes);
        when(resourceReader.getOptions(isA(Metacard.class))).thenReturn(supportedOptions);
        List<ResourceReader> resourceReaders = new ArrayList<ResourceReader>();
        resourceReaders.add(resourceReader);

        FrameworkProperties props = new FrameworkProperties();
        props.setCatalogProviders(Collections.singletonList((CatalogProvider) provider));
        props.setFederatedSources(Collections.singletonMap(federatedSite1Name, federatedSource1));
        props.setResourceReaders(resourceReaders);
        props.setFederationStrategy(strategy);
        props.setQueryResponsePostProcessor(mock(QueryResponsePostProcessor.class));
        props.setSourcePoller(mockPoller);
        props.setFilterBuilder(new GeotoolsFilterBuilder());
        CatalogFrameworkImpl framework = new CatalogFrameworkImpl(props);
        framework.bind(provider);
        framework.setId("ddf");

        Set<String> ids = new HashSet<String>();
        for (FederatedSource source : federatedSources) {
            ids.add(source.getId());
        }
        ids.add(framework.getId());

        // site name = local provider
        Map<String, Set<String>> optionsMap = framework.getResourceOptions(metacardId, localProviderName);
        LOGGER.debug("localProvider optionsMap = {}", optionsMap);
        assertThat(optionsMap, hasEntry("RESOURCE_OPTION", supportedOptions));

        // site name = federated site's name
        optionsMap = framework.getResourceOptions(metacardId, federatedSite1Name);
        LOGGER.debug("federatedSource optionsMap = {}", optionsMap);
        assertThat(optionsMap, hasEntry("RESOURCE_OPTION", supportedOptions));

        // site name = null (should default to local provider)
        optionsMap = framework.getResourceOptions(metacardId, null);
        LOGGER.debug("localProvider optionsMap = {}", optionsMap);
        assertThat(optionsMap, hasEntry("RESOURCE_OPTION", supportedOptions));

        // site name = empty string (should default to local provider)
        optionsMap = framework.getResourceOptions(metacardId, "");
        LOGGER.debug("localProvider optionsMap = {}", optionsMap);
        assertThat(optionsMap, hasEntry("RESOURCE_OPTION", supportedOptions));
    }

    @Test
    public void testGetResourceFromCache() throws Exception {
        String localProviderName = "ddf";
        String federatedSite1Name = "fed-site-1";
        String metacardId = "123";

        // The resource's URI
        URI metacardUri = new URI(
                "http:///27+Nov+12+12%3A30%3A04?MyPhotograph%0Ahttp%3A%2F%2F172.18.14.53%3A8080%2Fabc%2Fimages%2FActionable.jpg%0AMyAttachment%0Ahttp%3A%2F%2F172.18.14.53%3A8080%2Fabc#abc.xyz.dao.URLResourceOptionDataAccessObject");

        Set<String> supportedOptions = new HashSet<String>();
        supportedOptions.add("MyPhotograph");
        supportedOptions.add("MyAttachment");

        // Catalog Provider
        CatalogProvider provider = mock(CatalogProvider.class);
        when(provider.getId()).thenReturn(localProviderName);
        when(provider.isAvailable(isA(SourceMonitor.class))).thenReturn(true);
        when(provider.isAvailable()).thenReturn(true);

        // Federated Source 1
        FederatedSource federatedSource1 = mock(FederatedSource.class);
        when(federatedSource1.getId()).thenReturn(federatedSite1Name);
        when(federatedSource1.isAvailable(isA(SourceMonitor.class))).thenReturn(true);
        when(federatedSource1.isAvailable()).thenReturn(true);
        when(federatedSource1.getOptions(isA(Metacard.class))).thenReturn(supportedOptions);

        List<FederatedSource> federatedSources = new ArrayList<FederatedSource>();
        federatedSources.add(federatedSource1);

        // Mock register the provider in the container
        // Mock the source poller
        SourcePoller mockPoller = mock(SourcePoller.class);
        when(mockPoller.getCachedSource(isA(Source.class))).thenReturn(null);

        Metacard metacard = mock(Metacard.class);
        when(metacard.getId()).thenReturn(metacardId);
        when(metacard.getResourceURI()).thenReturn(metacardUri);
        Result result = mock(Result.class);
        when(result.getMetacard()).thenReturn(metacard);
        List<Result> results = new ArrayList<Result>();
        results.add(result);

        QueryResponse queryResponse = mock(QueryResponse.class);
        when(queryResponse.getResults()).thenReturn(results);
        FederationStrategy strategy = mock(FederationStrategy.class);
        when(strategy.federate(isA(federatedSources.getClass()), isA(QueryRequest.class)))
                .thenReturn(queryResponse);

        ResourceReader resourceReader = mock(ResourceReader.class);
        Set<String> supportedSchemes = new HashSet<String>();
        supportedSchemes.add("http");
        when(resourceReader.getSupportedSchemes()).thenReturn(supportedSchemes);
        when(resourceReader.getOptions(isA(Metacard.class))).thenReturn(supportedOptions);
        List<ResourceReader> resourceReaders = new ArrayList<ResourceReader>();
        resourceReaders.add(resourceReader);

        ResourceCache resourceCache = mock(ResourceCache.class);
        Resource mockResource = mock(Resource.class);
        when(resourceCache.containsValid(isA(String.class), isA(Metacard.class))).thenReturn(true);
        when(resourceCache.getValid(isA(String.class), isA(Metacard.class))).thenReturn(mockResource);

        FrameworkProperties props = new FrameworkProperties();
        props.setCatalogProviders(Collections.singletonList((CatalogProvider) provider));
        props.setFederatedSources(Collections.singletonMap(federatedSite1Name, federatedSource1));
        props.setResourceReaders(resourceReaders);
        props.setFederationStrategy(strategy);
        props.setQueryResponsePostProcessor(mock(QueryResponsePostProcessor.class));
        props.setSourcePoller(mockPoller);
        props.setResourceCache(resourceCache);

        props.setFilterBuilder(new GeotoolsFilterBuilder());
        CatalogFrameworkImpl framework = new CatalogFrameworkImpl(props);
        framework.bind(provider);
        framework.setId("ddf");

        Set<String> ids = new HashSet<String>();
        for (FederatedSource source : federatedSources) {
            ids.add(source.getId());
        }
        ids.add(framework.getId());

        ResourceRequestById request = new ResourceRequestById(metacardId);

        ResourceResponse response = framework.getResource(request, federatedSite1Name);

        assertThat(response, is(ResourceResponse.class));
        Metacard responseMetacard = (Metacard) response.getProperties().get("metacard");
        assertThat(responseMetacard, is(Metacard.class));
    }

    @Test
    public void testCreateWithStores() throws Exception {
        MockEventProcessor eventAdmin = new MockEventProcessor();
        MockMemoryProvider provider = new MockMemoryProvider("Provider", "Provider", "v1.0", "DDF", new HashSet<>(),
                true, new Date());

        Map<String, CatalogStore> storeMap = new HashMap<>();

        MockCatalogStore store = new MockCatalogStore("catalogStoreId-1", true);
        storeMap.put(store.getId(), store);

        CatalogFramework framework = createDummyCatalogFramework(provider, storeMap, null, eventAdmin);

        List<Metacard> metacards = new ArrayList<>();
        MetacardImpl newCard = new MetacardImpl();
        newCard.setId(null);
        metacards.add(newCard);
        Map<String, Serializable> reqProps = new HashMap<>();
        HashSet<String> destinations = new HashSet<>();

        //==== test writing to store and not local ====
        destinations.add("catalogStoreId-1");
        CreateResponse response = framework.create(new CreateRequestImpl(metacards, reqProps, destinations));
        assertEquals(0, provider.size());
        assertEquals(response.getCreatedMetacards().size(), store.size());
        assertEquals(1, store.size());
        assertFalse(eventAdmin.wasEventPosted());

        //==== test writing to store and local ====
        destinations.add("mockMemoryProvider");
        newCard.setId(null);
        reqProps = new HashMap<>();
        response = framework.create(new CreateRequestImpl(metacards, reqProps, destinations));
        assertEquals(1, provider.size());
        assertEquals(response.getCreatedMetacards().size(), provider.size());
        assertEquals(2, store.size());
        assertTrue(eventAdmin.wasEventPosted());

        //==== test writing to local when no destination ====
        destinations.clear();
        newCard.setId(null);
        reqProps = new HashMap<>();
        response = framework.create(new CreateRequestImpl(metacards, reqProps, destinations));
        assertEquals(2, provider.size());
        assertEquals(response.getCreatedMetacards().size(), 1);
        assertEquals(2, store.size());
    }

    @Test
    public void testUpdateWithStores() throws Exception {
        MockEventProcessor eventAdmin = new MockEventProcessor();
        MockMemoryProvider provider = new MockMemoryProvider("Provider", "Provider", "v1.0", "DDF", new HashSet<>(),
                true, new Date());

        Map<String, CatalogStore> storeMap = new HashMap<>();
        Map<String, FederatedSource> sourceMap = new HashMap<>();
        MockCatalogStore store = new MockCatalogStore("catalogStoreId-1", true);
        storeMap.put(store.getId(), store);
        sourceMap.put(store.getId(), store);

        CatalogFramework framework = createDummyCatalogFramework(provider, storeMap, sourceMap, eventAdmin);
        FilterFactory filterFactory = new FilterFactoryImpl();

        Filter filter = filterFactory.like(filterFactory.property(Metacard.METADATA), "*", "*", "?", "/", false);

        List<Metacard> metacards = new ArrayList<>();
        String id = UUID.randomUUID().toString();
        MetacardImpl newCard = new MetacardImpl();
        newCard.setId(id);
        newCard.setAttribute("myKey", "myValue1");
        metacards.add(newCard);
        Map<String, Serializable> reqProps = new HashMap<>();
        HashSet<String> destinations = new HashSet<>();
        destinations.add("mockMemoryProvider");
        destinations.add("catalogStoreId-1");
        framework.create(new CreateRequestImpl(metacards, reqProps, destinations));

        MetacardImpl updateCard = new MetacardImpl();
        updateCard.setId(id);
        updateCard.setAttribute("myKey", "myValue2");
        List<Entry<Serializable, Metacard>> updates = new ArrayList<>();
        updates.add(new SimpleEntry<>(id, updateCard));
        destinations.remove("mockMemoryProvider");
        framework.update(new UpdateRequestImpl(updates, Metacard.ID, new HashMap<>(), destinations));
        assertThat(provider.hasReceivedUpdateByIdentifier(), is(false));
        assertThat(store.hasReceivedUpdateByIdentifier(), is(true));
        QueryResponse storeResponse = framework.query(new QueryRequestImpl(new QueryImpl(filter), destinations));
        assertThat(storeResponse.getResults().size(), is(1));
        assertThat(storeResponse.getResults().get(0).getMetacard().getAttribute("myKey").getValue(),
                equalTo("myValue2"));
        destinations.clear();
        QueryResponse providerResponse = framework.query(new QueryRequestImpl(new QueryImpl(filter), destinations));
        assertThat(providerResponse.getResults().size(), is(1));
        assertThat(providerResponse.getResults().get(0).getMetacard().getAttribute("myKey").getValue(),
                equalTo("myValue1"));

    }

    @Test
    public void testDeleteWithStores() throws Exception {
        MockEventProcessor eventAdmin = new MockEventProcessor();
        MockMemoryProvider provider = new MockMemoryProvider("Provider", "Provider", "v1.0", "DDF", new HashSet<>(),
                true, new Date());

        Map<String, CatalogStore> storeMap = new HashMap<>();
        Map<String, FederatedSource> sourceMap = new HashMap<>();
        MockCatalogStore store = new MockCatalogStore("catalogStoreId-1", true);
        storeMap.put(store.getId(), store);
        sourceMap.put(store.getId(), store);

        CatalogFramework framework = createDummyCatalogFramework(provider, storeMap, sourceMap, eventAdmin);
        FilterFactory filterFactory = new FilterFactoryImpl();

        Filter filter = filterFactory.like(filterFactory.property(Metacard.METADATA), "*", "*", "?", "/", false);

        List<Metacard> metacards = new ArrayList<>();
        String id = UUID.randomUUID().toString();
        MetacardImpl newCard = new MetacardImpl();
        newCard.setId(id);
        newCard.setAttribute("myKey", "myValue1");
        metacards.add(newCard);
        Map<String, Serializable> reqProps = new HashMap<>();
        HashSet<String> destinations = new HashSet<>();
        destinations.add("mockMemoryProvider");
        destinations.add("catalogStoreId-1");
        framework.create(new CreateRequestImpl(metacards, reqProps, destinations));

        DeleteRequest deleteRequest = new DeleteRequestImpl(Collections.singletonList(id), Metacard.ID,
                new HashMap<>(), destinations);
        DeleteResponse response = framework.delete(deleteRequest);
        assertThat(response.getDeletedMetacards().size(), is(1));
        QueryResponse queryResponse = framework.query(new QueryRequestImpl(new QueryImpl(filter), true));
        assertThat(queryResponse.getResults().size(), is(0));

    }

    @Test(expected = FederationException.class)
    public void testFederatedQueryPermissionsNoSubject() throws Exception {
        MockEventProcessor eventAdmin = new MockEventProcessor();
        MockMemoryProvider provider = new MockMemoryProvider("Provider", "Provider", "v1.0", "DDF", new HashSet<>(),
                true, new Date());

        Map<String, CatalogStore> storeMap = new HashMap<>();
        Map<String, FederatedSource> sourceMap = new HashMap<>();

        Map<String, Set<String>> securityAttributes = new HashMap<>();
        securityAttributes.put("role", Collections.singleton("myRole"));
        MockCatalogStore store = new MockCatalogStore("catalogStoreId-1", true, securityAttributes);
        storeMap.put(store.getId(), store);
        sourceMap.put(store.getId(), store);

        CatalogFramework framework = createDummyCatalogFramework(provider, storeMap, sourceMap, eventAdmin);

        FilterBuilder builder = new GeotoolsFilterBuilder();

        QueryImpl query = new QueryImpl(builder.attribute(Metacard.CONTENT_TYPE).is().like().text("someType"));
        QueryRequestImpl request = new QueryRequestImpl(query, Collections.singletonList("catalogStoreId-1"));
        framework.query(request);
    }

    @Test(expected = FederationException.class)
    public void testFederatedQueryPermissionsNotPermitted() throws Exception {
        MockEventProcessor eventAdmin = new MockEventProcessor();
        MockMemoryProvider provider = new MockMemoryProvider("Provider", "Provider", "v1.0", "DDF", new HashSet<>(),
                true, new Date());

        Map<String, CatalogStore> storeMap = new HashMap<>();
        Map<String, FederatedSource> sourceMap = new HashMap<>();

        Map<String, Set<String>> securityAttributes = new HashMap<>();
        securityAttributes.put("role", Collections.singleton("myRole"));
        MockCatalogStore store = new MockCatalogStore("catalogStoreId-1", true, securityAttributes);
        storeMap.put(store.getId(), store);
        sourceMap.put(store.getId(), store);

        CatalogFramework framework = createDummyCatalogFramework(provider, storeMap, sourceMap, eventAdmin);

        FilterBuilder builder = new GeotoolsFilterBuilder();
        Subject subject = mock(Subject.class);
        when(subject.isPermitted(any(KeyValueCollectionPermission.class))).thenReturn(false);
        HashMap<String, Serializable> properties = new HashMap<>();
        properties.put(SecurityConstants.SECURITY_SUBJECT, subject);
        QueryImpl query = new QueryImpl(builder.attribute(Metacard.CONTENT_TYPE).is().like().text("someType"));
        QueryRequestImpl request = new QueryRequestImpl(query, false, Collections.singletonList("catalogStoreId-1"),
                properties);
        framework.query(request);
    }

    @Test
    public void testFederatedQueryPermissions() throws Exception {
        MockEventProcessor eventAdmin = new MockEventProcessor();
        MockMemoryProvider provider = new MockMemoryProvider("Provider", "Provider", "v1.0", "DDF", new HashSet<>(),
                true, new Date());

        Map<String, CatalogStore> storeMap = new HashMap<>();
        Map<String, FederatedSource> sourceMap = new HashMap<>();

        Map<String, Set<String>> securityAttributes = new HashMap<>();
        securityAttributes.put("role", Collections.singleton("myRole"));
        MockCatalogStore store = new MockCatalogStore("catalogStoreId-1", true, securityAttributes);
        storeMap.put(store.getId(), store);
        sourceMap.put(store.getId(), store);

        CatalogFramework framework = createDummyCatalogFramework(provider, storeMap, sourceMap, eventAdmin);

        List<Metacard> metacards = new ArrayList<>();
        MetacardImpl newCard = new MetacardImpl();
        newCard.setId(null);
        newCard.setContentTypeName("someType");
        metacards.add(newCard);
        Map<String, Serializable> reqProps = new HashMap<>();
        HashSet<String> destinations = new HashSet<>();

        //==== test writing to store and not local ====
        destinations.add("catalogStoreId-1");
        framework.create(new CreateRequestImpl(metacards, reqProps, destinations));

        FilterBuilder builder = new GeotoolsFilterBuilder();
        Subject subject = mock(Subject.class);
        when(subject.isPermitted(any(KeyValueCollectionPermission.class))).thenReturn(true);
        HashMap<String, Serializable> properties = new HashMap<>();
        properties.put(SecurityConstants.SECURITY_SUBJECT, subject);
        QueryImpl query = new QueryImpl(builder.attribute(Metacard.CONTENT_TYPE).is().like().text("someType"));
        QueryRequestImpl request = new QueryRequestImpl(query, false, Collections.singletonList("catalogStoreId-1"),
                properties);
        QueryResponse response = framework.query(request);

        assertThat(response.getResults().size(), is(1));
    }

    /**
     * Tests that multiple ResourceReaders with the same scheme will be invoked if the first one did
     * not return a Response.
     *
     * @throws Exception
     */
    @Test
    @Ignore //CACHE
    public void testGetResourceToTestSecondResourceReaderWithSameSchemeGetsCalledIfFirstDoesNotReturnAnything()
            throws Exception {
        String localProviderName = "ddf";
        String metacardId = "123";
        final String EXPECTED = "result from mockResourceResponse2";
        final String DDF = "ddf";

        // Mock a Catalog Provider
        CatalogProvider provider = mock(CatalogProvider.class);
        when(provider.getId()).thenReturn(localProviderName);
        when(provider.isAvailable(isA(SourceMonitor.class))).thenReturn(true);
        when(provider.isAvailable()).thenReturn(true);

        // Mock register the provider in the container
        // Mock the source poller
        SourcePoller mockPoller = mock(SourcePoller.class);
        when(mockPoller.getCachedSource(isA(Source.class))).thenReturn(null);

        // Create two ResourceReaders. The first should not return anything
        // and the second should.
        ResourceReader resourceReader1 = mock(ResourceReader.class);
        ResourceReader resourceReader2 = mock(ResourceReader.class);

        // Set the supported Schemes so that both ResourceReaders use
        // the same scheme ("DAD")
        Set<String> supportedSchemes = new HashSet<String>();
        supportedSchemes.add("DAD");

        when(resourceReader1.getSupportedSchemes()).thenReturn(supportedSchemes);
        when(resourceReader2.getSupportedSchemes()).thenReturn(supportedSchemes);

        List<ResourceReader> resourceReaders = new ArrayList<ResourceReader>();
        resourceReaders.add(resourceReader1);
        resourceReaders.add(resourceReader2);

        // Set up the requests and responses. The first ResourceReader will return null
        // and the second one will retrieve a value, showing that if more than one
        // ResourceReader with the same scheme are used, they will be called until a
        // response is returned
        ResourceRequest mockResourceRequest = mock(ResourceRequest.class);
        URI myURI = new URI("DAD", "host", "/path", "fragment");
        when(mockResourceRequest.getAttributeValue()).thenReturn(myURI);
        when(mockResourceRequest.getAttributeName())
                .thenReturn(new String(ResourceRequest.GET_RESOURCE_BY_PRODUCT_URI));

        Result result = mock(Result.class);
        Metacard metacard = mock(Metacard.class);
        when(metacard.getResourceURI()).thenReturn(myURI);
        when(result.getMetacard()).thenReturn(metacard);
        List<Result> results = new ArrayList<Result>();
        results.add(result);

        QueryResponse queryResponse = mock(QueryResponse.class);
        when(queryResponse.getResults()).thenReturn(results);

        List<Source> federatedSources = new ArrayList<Source>();

        FederationStrategy strategy = mock(FederationStrategy.class);
        when(strategy.federate(isA(federatedSources.getClass()), isA(QueryRequest.class)))
                .thenReturn(queryResponse);

        ResourceResponse mockResourceResponse1 = mock(ResourceResponse.class);
        when(mockResourceResponse1.getRequest()).thenReturn(mockResourceRequest);
        when(mockResourceResponse1.getResource()).thenReturn(null);
        when(resourceReader1.retrieveResource(any(URI.class), anyMap())).thenReturn(null);

        Resource mockResource = mock(Resource.class);
        when(mockResource.getName()).thenReturn(EXPECTED);
        ResourceResponse mockResourceResponse2 = mock(ResourceResponse.class);
        when(mockResourceResponse2.getResource()).thenReturn(mockResource);
        when(resourceReader2.retrieveResource(any(URI.class), anyMap())).thenReturn(mockResourceResponse2);

        FrameworkProperties frameworkProperties = new FrameworkProperties();
        frameworkProperties.setSourcePoller(mockPoller);
        frameworkProperties.setResourceReaders(resourceReaders);
        frameworkProperties.setFederationStrategy(strategy);
        frameworkProperties.setCatalogProviders(Collections.singletonList(provider));

        CatalogFrameworkImpl framework = new CatalogFrameworkImpl(frameworkProperties);
        framework.bind(provider);
        framework.setId(DDF);

        ResourceResponse response = framework.getResource(mockResourceRequest, false, DDF);

        // Verify that the Response is as expected
        org.junit.Assert.assertEquals(EXPECTED, response.getResource().getName());

        // Verify that resourceReader1 was called 1 time
        // This line is equivalent to verify(resourceReader1,
        // times(1)).retrieveResource(any(URI.class), anyMap());
        verify(resourceReader1).retrieveResource(any(URI.class), anyMap());

    }

    /****************************
     * utility methods
     ******************************/

    private List<FederatedSource> createDefaultFederatedSourceList(boolean isAvailable) {
        FederatedSource siteA = new MockSource("A", "Site A", "v1.0", "DDF", null, isAvailable, new Date());
        FederatedSource siteB = new MockSource("B", "Site B", "v1.0", "DDF", null, isAvailable, new Date());
        FederatedSource siteC = new MockSource("C", "Site C", "v1.0", "DDF", null, isAvailable, new Date());
        ArrayList<FederatedSource> federatedSources = new ArrayList<FederatedSource>();
        federatedSources.add(siteC);
        federatedSources.add(siteB);
        federatedSources.add(siteA);

        return federatedSources;
    }

    private CatalogFramework createDummyCatalogFramework(CatalogProvider provider, Map<String, CatalogStore> stores,
            Map<String, FederatedSource> sources, MockEventProcessor eventAdmin) {

        SourcePoller mockPoller = mock(SourcePoller.class);
        when(mockPoller.getCachedSource(isA(Source.class))).thenReturn(null);

        FederationStrategy federationStrategy = new FederationStrategy() {
            @Override
            public QueryResponse federate(List<Source> sources, QueryRequest query) throws FederationException {
                List<Result> results = new ArrayList<>();
                for (Source source : sources) {
                    try {
                        SourceResponse response = source.query(query);
                        results.addAll(response.getResults());
                    } catch (UnsupportedQueryException e) {

                    }
                }
                return new QueryResponseImpl(query, results, results.size());
            }
        };

        ArrayList<PostIngestPlugin> postIngestPlugins = new ArrayList<>();
        postIngestPlugins.add(eventAdmin);
        FrameworkProperties frameworkProperties = new FrameworkProperties();
        frameworkProperties.setCatalogProviders(Collections.singletonList(provider));
        frameworkProperties.setStorageProviders(Collections.singletonList(storageProvider));
        frameworkProperties.setCatalogStoresMap(stores);
        frameworkProperties.setSourcePoller(mockPoller);
        frameworkProperties.setPreIngest(new ArrayList<>());
        frameworkProperties.setPostIngest(postIngestPlugins);
        frameworkProperties.setPreQuery(new ArrayList<>());
        frameworkProperties.setPostQuery(new ArrayList<>());
        frameworkProperties.setPolicyPlugins(new ArrayList<>());
        frameworkProperties.setAccessPlugins(new ArrayList<>());
        frameworkProperties.setFederatedSources(sources);
        frameworkProperties.setConnectedSources(new ArrayList<>());
        frameworkProperties.setFederationStrategy(federationStrategy);
        frameworkProperties.setQueryResponsePostProcessor(new QueryResponsePostProcessor(null, null));
        frameworkProperties.setFilterBuilder(new GeotoolsFilterBuilder());
        frameworkProperties.setValidationQueryFactory(
                new ValidationQueryFactory(new GeotoolsFilterAdapterImpl(), new GeotoolsFilterBuilder()));

        CatalogFrameworkImpl framework = new CatalogFrameworkImpl(frameworkProperties);
        framework.bind(provider);
        framework.bind(storageProvider);
        return framework;

    }

    private CatalogFramework createDummyCatalogFramework(CatalogProvider provider, StorageProvider storageProvider,
            MockEventProcessor admin, boolean sourceAvailability) {
        return createDummyCatalogFramework(provider, storageProvider, null, admin, sourceAvailability);
    }

    private CatalogFramework createDummyCatalogFramework(CatalogProvider provider, StorageProvider storageProvider,
            BundleContext context, MockEventProcessor admin, boolean sourceAvailability) {
        // Mock register the provider in the container
        // Mock the source poller
        SourcePoller mockPoller = mock(SourcePoller.class);
        CachedSource mockSource = mock(CachedSource.class);
        when(mockSource.isAvailable()).thenReturn(sourceAvailability);
        when(mockPoller.getCachedSource(isA(Source.class))).thenReturn(mockSource);

        FrameworkProperties frameworkProperties = new FrameworkProperties();
        frameworkProperties.setCatalogProviders(Collections.singletonList(provider));
        frameworkProperties.setStorageProviders(Collections.singletonList(storageProvider));
        frameworkProperties.setSourcePoller(mockPoller);
        frameworkProperties.setBundleContext(context);

        CatalogFrameworkImpl framework = new CatalogFrameworkImpl(frameworkProperties);
        framework.bind(provider);
        framework.bind(storageProvider);

        return framework;
    }

    public static class MockCatalogStore extends MockMemoryProvider implements CatalogStore {
        private Map<String, Set<String>> attributes = new HashMap<>();

        public MockCatalogStore(String id, boolean isAvailable, Map<String, Set<String>> attributes) {
            this(id, isAvailable);
            this.attributes = attributes;
        }

        public MockCatalogStore(String id, boolean isAvailable) {
            super(id, isAvailable);
        }

        @Override
        public Map<String, Set<String>> getSecurityAttributes() {
            return attributes;
        }
    }
}