org.codice.ddf.confluence.source.ConfluenceSourceTest.java Source code

Java tutorial

Introduction

Here is the source code for org.codice.ddf.confluence.source.ConfluenceSourceTest.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 org.codice.ddf.confluence.source;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import ddf.catalog.data.AttributeRegistry;
import ddf.catalog.data.AttributeType;
import ddf.catalog.data.Metacard;
import ddf.catalog.data.MetacardType;
import ddf.catalog.data.impl.AttributeDescriptorImpl;
import ddf.catalog.data.impl.BasicTypes;
import ddf.catalog.data.impl.MetacardImpl;
import ddf.catalog.data.impl.MetacardTypeImpl;
import ddf.catalog.data.types.Associations;
import ddf.catalog.data.types.Contact;
import ddf.catalog.data.types.Core;
import ddf.catalog.data.types.Media;
import ddf.catalog.data.types.Security;
import ddf.catalog.data.types.Topic;
import ddf.catalog.filter.FilterAdapter;
import ddf.catalog.filter.FilterBuilder;
import ddf.catalog.filter.impl.SortByImpl;
import ddf.catalog.filter.proxy.adapter.GeotoolsFilterAdapterImpl;
import ddf.catalog.filter.proxy.builder.GeotoolsFilterBuilder;
import ddf.catalog.operation.QueryRequest;
import ddf.catalog.operation.SourceResponse;
import ddf.catalog.operation.impl.QueryImpl;
import ddf.catalog.operation.impl.QueryRequestImpl;
import ddf.catalog.resource.ResourceReader;
import ddf.catalog.source.SourceMonitor;
import ddf.catalog.source.UnsupportedQueryException;
import ddf.security.encryption.EncryptionService;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import javax.ws.rs.core.Response;
import javax.xml.bind.DatatypeConverter;
import org.apache.commons.io.IOUtils;
import org.apache.cxf.jaxrs.client.WebClient;
import org.codice.ddf.confluence.api.SearchResource;
import org.codice.ddf.cxf.client.ClientFactoryFactory;
import org.codice.ddf.cxf.client.SecureCxfClientFactory;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.opengis.filter.sort.SortOrder;

public class ConfluenceSourceTest {
    private static final String JSON_RESPONSE = getFileContent("full_response.json");

    private TestConfluenceSource confluence;

    private FilterBuilder builder = new GeotoolsFilterBuilder();

    private FilterAdapter adapter = new GeotoolsFilterAdapterImpl();

    private SecureCxfClientFactory<SearchResource> factory;

    private ClientFactoryFactory clientFactoryFactory;

    private EncryptionService encryptionService;

    private ResourceReader reader;

    private AttributeRegistry registry;

    private SearchResource client;

    private Response clientResponse;

    private ConfluenceInputTransformer transformer;

    @Before
    public void setup() {

        MetacardType type = new MetacardTypeImpl("confluence",
                MetacardImpl.BASIC_METACARD.getAttributeDescriptors());
        transformer = new ConfluenceInputTransformer(type, Collections.emptyList());

        encryptionService = mock(EncryptionService.class);
        reader = mock(ResourceReader.class);
        factory = mock(SecureCxfClientFactory.class);
        clientFactoryFactory = mock(ClientFactoryFactory.class);
        client = mock(SearchResource.class);
        registry = mock(AttributeRegistry.class);
        clientResponse = mock(Response.class);
        when(factory.getClient()).thenReturn(client);
        doReturn(clientResponse).when(client).search(anyString(), anyString(), anyString(), anyString(), anyInt(),
                anyInt(), anyBoolean());
        when(encryptionService.decryptValue(anyString())).thenReturn("decryptedPass");
        when(registry.lookup("attrib1")).thenReturn(Optional
                .of(new AttributeDescriptorImpl("attrib1", true, true, true, false, BasicTypes.STRING_TYPE)));
        when(registry.lookup("attrib2")).thenReturn(Optional
                .of(new AttributeDescriptorImpl("attrib2", true, true, true, true, BasicTypes.STRING_TYPE)));
        confluence = new TestConfluenceSource(adapter, encryptionService, transformer, reader, registry, factory,
                clientFactoryFactory);
        confluence.setAvailabilityPollInterval(1);
        confluence.setConfigurationPid("configPid");
        confluence.setEndpointUrl("https://confluence/rest/api/content");
        confluence.setExpandedSections(Collections.singletonList("expandedField"));
        confluence.setUsername("username");
        confluence.setPassword("password");
        confluence.setIncludeArchivedSpaces(false);
        List<String> additionalAttributes = new ArrayList<>();
        additionalAttributes.add("attrib1=val1");
        additionalAttributes.add("attrib2=val1,val2,val3");
        confluence.setAttributeOverrides(additionalAttributes);
    }

    @Test
    public void testQuery() throws Exception {
        QueryRequest request = new QueryRequestImpl(
                new QueryImpl(builder.attribute("anyText").is().like().text("searchValue"), 1, 1,
                        new SortByImpl("title", SortOrder.DESCENDING), false, 1000));
        InputStream entity = new ByteArrayInputStream(JSON_RESPONSE.getBytes(StandardCharsets.UTF_8));
        when(clientResponse.getEntity()).thenReturn(entity);
        when(clientResponse.getStatus()).thenReturn(Response.Status.OK.getStatusCode());

        SourceResponse response = confluence.query(request);
        assertThat(response.getHits(), is(1L));
        assertThat(response.getResults().get(0).getMetacard(), notNullValue());
    }

    @Test
    public void testQuerySortOnNonConfluenceAttribute() throws Exception {
        QueryRequest request = new QueryRequestImpl(
                new QueryImpl(builder.attribute("anyText").is().like().text("searchValue"), 1, 1,
                        new SortByImpl("someAttribute", SortOrder.DESCENDING), false, 1000));
        InputStream entity = new ByteArrayInputStream(JSON_RESPONSE.getBytes(StandardCharsets.UTF_8));
        when(clientResponse.getEntity()).thenReturn(entity);
        when(clientResponse.getStatus()).thenReturn(Response.Status.OK.getStatusCode());

        SourceResponse response = confluence.query(request);
        assertThat(response.getHits(), is(1L));
        assertThat(response.getResults().get(0).getMetacard(), notNullValue());
    }

    @Test
    public void testQueryNullSort() throws Exception {
        QueryRequest request = new QueryRequestImpl(new QueryImpl(
                builder.attribute("anyText").is().like().text("searchValue"), 1, 1, null, false, 1000));
        InputStream entity = new ByteArrayInputStream(JSON_RESPONSE.getBytes(StandardCharsets.UTF_8));
        when(clientResponse.getEntity()).thenReturn(entity);
        when(clientResponse.getStatus()).thenReturn(Response.Status.OK.getStatusCode());

        SourceResponse response = confluence.query(request);
        assertThat(response.getHits(), is(1L));
        assertThat(response.getResults().get(0).getMetacard(), notNullValue());
    }

    @Test(expected = UnsupportedQueryException.class)
    public void testFailedQuery() throws Exception {
        QueryRequest request = new QueryRequestImpl(
                new QueryImpl(builder.attribute("anyText").is().like().text("searchValue"), 1, 1,
                        new SortByImpl("title", SortOrder.DESCENDING), false, 1000));
        InputStream entity = new ByteArrayInputStream("Something bad happened".getBytes(StandardCharsets.UTF_8));
        when(clientResponse.getEntity()).thenReturn(entity);
        when(clientResponse.getStatus()).thenReturn(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());

        SourceResponse response = confluence.query(request);
    }

    @Test(expected = UnsupportedQueryException.class)
    public void testFailedQueryStreamError() throws Exception {
        QueryRequest request = new QueryRequestImpl(
                new QueryImpl(builder.attribute("anyText").is().like().text("searchValue"), 1, 1,
                        new SortByImpl("title", SortOrder.DESCENDING), false, 1000));
        InputStream entity = mock(InputStream.class);
        when(entity.read(any())).thenThrow(new IOException("exception"));
        when(clientResponse.getEntity()).thenReturn(entity);
        when(clientResponse.getStatus()).thenReturn(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());

        SourceResponse response = confluence.query(request);
    }

    @Test
    public void testQueryWithSpace() throws Exception {
        QueryRequest request = new QueryRequestImpl(
                new QueryImpl(builder.attribute("anyText").is().like().text("searchValue"), 1, 1,
                        new SortByImpl("title", SortOrder.DESCENDING), false, 1000));
        InputStream entity = new ByteArrayInputStream(JSON_RESPONSE.getBytes(StandardCharsets.UTF_8));
        confluence.setConfluenceSpaces(Collections.singletonList("DDF"));
        when(clientResponse.getEntity()).thenReturn(entity);
        when(clientResponse.getStatus()).thenReturn(Response.Status.OK.getStatusCode());

        SourceResponse response = confluence.query(request);
        assertThat(response.getHits(), is(1L));
        Metacard mcard = response.getResults().get(0).getMetacard();
        assertThat(mcard, notNullValue());
        assertThat(mcard.getAttribute("attrib1").getValue(), is("val1"));
        assertThat(mcard.getAttribute("attrib2").getValues().size(), is(3));
    }

    @Test
    public void testNonConfluenceQuery() throws Exception {
        QueryRequest request = new QueryRequestImpl(
                new QueryImpl(builder.attribute("metacard-tags").is().like().text("nonConfluecneTag"), 1, 1,
                        new SortByImpl("title", SortOrder.DESCENDING), false, 1000));

        SourceResponse response = confluence.query(request);
        assertThat(response.getHits(), is(0L));
    }

    @Test
    public void testQueryNonConfluenceAttribute() throws Exception {
        QueryRequest request = new QueryRequestImpl(new QueryImpl(
                builder.attribute("someAttribute").is().like().text("someValue"), 1, 1, null, false, 1000));

        SourceResponse response = confluence.query(request);
        assertThat(response.getHits(), is(0L));
    }

    @Test
    public void testIsAvailable() throws Exception {
        WebClient mockClient = mock(WebClient.class);
        when(factory.getWebClient()).thenReturn(mockClient);
        Response mockResponse = mock(Response.class);
        when(mockClient.head()).thenReturn(mockResponse);
        when(mockResponse.getStatus()).thenReturn(Response.Status.OK.getStatusCode());
        assertThat(confluence.isAvailable(), is(true));
    }

    @Test
    public void testCachedAvailable() throws Exception {
        WebClient mockClient = mock(WebClient.class);
        when(factory.getWebClient()).thenReturn(mockClient);
        Response mockResponse = mock(Response.class);
        when(mockClient.head()).thenReturn(mockResponse);
        when(mockResponse.getStatus()).thenReturn(Response.Status.OK.getStatusCode(),
                Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());

        confluence.setAvailabilityPollInterval(100000);
        assertThat(confluence.isAvailable(), is(true));
        assertThat(confluence.isAvailable(), is(true));
    }

    @Test
    public void testCachedAvailableExpired() throws Exception {
        WebClient mockClient = mock(WebClient.class);
        when(factory.getWebClient()).thenReturn(mockClient);
        Response mockResponse = mock(Response.class);
        when(mockClient.head()).thenReturn(mockResponse);
        when(mockResponse.getStatus()).thenReturn(Response.Status.OK.getStatusCode(),
                Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());

        confluence.setAvailabilityPollInterval(5);
        assertThat(confluence.isAvailable(), is(true));
        Thread.sleep(10);
        assertThat(confluence.isAvailable(), is(false));
    }

    @Test
    public void testAvailibilityConnectionException() throws Exception {
        WebClient mockClient = mock(WebClient.class);
        when(factory.getWebClient()).thenReturn(mockClient);
        when(mockClient.head()).thenThrow(new RuntimeException("Connection exception"));
        assertThat(confluence.isAvailable(), is(false));
    }

    @Test
    public void testAvaliabilitySourceMonitor() throws Exception {
        SourceMonitor monitor = mock(SourceMonitor.class);
        WebClient mockClient = mock(WebClient.class);
        when(factory.getWebClient()).thenReturn(mockClient);
        Response mockResponse = mock(Response.class);
        when(mockClient.head()).thenReturn(mockResponse);
        when(mockResponse.getStatus()).thenReturn(Response.Status.OK.getStatusCode(),
                Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
        assertThat(confluence.isAvailable(monitor), is(true));
        verify(monitor).setAvailable();
        Thread.sleep(10);
        assertThat(confluence.isAvailable(monitor), is(false));
        verify(monitor).setUnavailable();
    }

    @Test
    public void testRetrieveResource() throws Exception {
        when(reader.retrieveResource(any(), any())).thenReturn(null);
        confluence.retrieveResource(new URI("/my/uri"), new HashMap<>());
        ArgumentCaptor<URI> uriCaptor = ArgumentCaptor.forClass(URI.class);
        ArgumentCaptor<Map> mapCaptor = ArgumentCaptor.forClass(Map.class);
        verify(reader).retrieveResource(uriCaptor.capture(), mapCaptor.capture());
        assertThat(mapCaptor.getValue().get("username"), is("username"));
        assertThat(mapCaptor.getValue().get("password"), is("decryptedPass"));
    }

    @Test
    public void testInitNoEndpointUrl() throws Exception {
        ConfluenceSource source = new ConfluenceSource(adapter, encryptionService, transformer, reader, registry,
                clientFactoryFactory);
        source.setUsername("myname");
        source.setPassword("mypass");
        source.init();
        assertThat(source.getClientFactory(), is(nullValue()));
    }

    @Test
    public void testAttributeOverrides() throws Exception {
        QueryRequest request = new QueryRequestImpl(
                new QueryImpl(builder.attribute("anyText").is().like().text("searchValue"), 1, 1,
                        new SortByImpl("title", SortOrder.DESCENDING), false, 1000));
        InputStream entity = new ByteArrayInputStream(JSON_RESPONSE.getBytes(StandardCharsets.UTF_8));
        when(clientResponse.getEntity()).thenReturn(entity);
        when(clientResponse.getStatus()).thenReturn(Response.Status.OK.getStatusCode());

        setupRegistryEntry("dateAttribute", BasicTypes.DATE_TYPE);
        setupRegistryEntry("boolAttribute", BasicTypes.BOOLEAN_TYPE);
        setupRegistryEntry("longAttribute", BasicTypes.LONG_TYPE);
        setupRegistryEntry("intAttribute", BasicTypes.INTEGER_TYPE);
        setupRegistryEntry("shortAttribute", BasicTypes.SHORT_TYPE);
        setupRegistryEntry("floatAttribute", BasicTypes.FLOAT_TYPE);
        setupRegistryEntry("doubleAttribute", BasicTypes.DOUBLE_TYPE);
        setupRegistryEntry("binaryAttribute", BasicTypes.BINARY_TYPE);
        setupRegistryEntry("badAttribute", BasicTypes.INTEGER_TYPE);
        when(registry.lookup("missingAttribute")).thenReturn(Optional.empty());

        Instant now = Instant.now();

        List<String> additionalAttributes = new ArrayList<>();
        additionalAttributes.add("attrib1=val1");
        additionalAttributes.add("attrib2=val1,val2,val3");
        additionalAttributes.add("dateAttribute=2018-06-28T10:44:00+07:00");
        additionalAttributes.add("boolAttribute=true");
        additionalAttributes.add("longAttribute=12345678900000");
        additionalAttributes.add("intAttribute=1234");
        additionalAttributes.add("shortAttribute=1");
        additionalAttributes.add("floatAttribute=1.1");
        additionalAttributes.add("doubleAttribute=1.23456");
        additionalAttributes.add("binaryAttribute=binaryString");
        additionalAttributes.add("badAttribute=1.23456");
        additionalAttributes.add("missingAttribute=something");

        confluence.setAttributeOverrides(additionalAttributes);

        SourceResponse response = confluence.query(request);
        assertThat(response.getHits(), is(1L));
        Metacard mcard = response.getResults().get(0).getMetacard();
        assertThat(mcard, notNullValue());
        assertThat(mcard.getAttribute("attrib1").getValue(), is("val1"));
        assertThat(mcard.getAttribute("attrib2").getValues().size(), is(3));
        assertThat(mcard.getAttribute("dateAttribute").getValue(),
                is(DatatypeConverter.parseDateTime("2018-06-28T10:44:00+07:00").getTime()));
        assertThat(mcard.getAttribute("boolAttribute").getValue(), is(true));
        assertThat(mcard.getAttribute("longAttribute").getValue(), is(12345678900000L));
        assertThat(mcard.getAttribute("intAttribute").getValue(), is(1234));
        assertThat(mcard.getAttribute("shortAttribute").getValue(), is((short) 1));
        assertThat(mcard.getAttribute("floatAttribute").getValue(), is(1.1f));
        assertThat(mcard.getAttribute("doubleAttribute").getValue(), is(1.23456));
        assertThat(mcard.getAttribute("binaryAttribute").getValue(),
                is("binaryString".getBytes(Charset.forName("UTF-8"))));
        assertThat(mcard.getAttribute("badAttribute"), is(nullValue()));
        assertThat(mcard.getAttribute("missingAttribute"), is(nullValue()));
    }

    @Test
    public void verifyAllMappings() throws Exception {
        QueryRequest request = new QueryRequestImpl(
                new QueryImpl(builder.attribute("anyText").is().like().text("searchValue"), 1, 1,
                        new SortByImpl("title", SortOrder.DESCENDING), false, 1000));
        InputStream entity = new ByteArrayInputStream(JSON_RESPONSE.getBytes(StandardCharsets.UTF_8));
        when(clientResponse.getEntity()).thenReturn(entity);
        when(clientResponse.getStatus()).thenReturn(Response.Status.OK.getStatusCode());

        SourceResponse response = confluence.query(request);
        assertThat(response.getHits(), is(1L));
        Metacard mcard = response.getResults().get(0).getMetacard();
        assertThat(mcard.getCreatedDate(),
                is(DatatypeConverter.parseDateTime("2013-09-18T14:50:42.616-07:00").getTime()));
        assertThat(mcard.getModifiedDate(),
                is(DatatypeConverter.parseDateTime("2015-06-16T19:21:39.141-07:00").getTime()));
        assertThat(mcard.getAttribute(Core.METACARD_CREATED).getValue(),
                is(DatatypeConverter.parseDateTime("2013-09-18T14:50:42.616-07:00").getTime()));
        assertThat(mcard.getAttribute(Core.METACARD_MODIFIED).getValue(),
                is(DatatypeConverter.parseDateTime("2015-06-16T19:21:39.141-07:00").getTime()));
        assertThat(mcard.getTags(), contains("confluence", "resource"));
        assertThat(mcard.getId(), is("1179681"));
        assertThat(mcard.getTitle(), is("Formatting Source Code"));
        assertThat(mcard.getAttribute(Associations.EXTERNAL).getValues(),
                contains("https://codice.atlassian.net/wiki/display/DDF/Formatting+Source+Code"));
        assertThat(mcard.getAttribute(Contact.CREATOR_NAME).getValue(), is("another"));
        assertThat(mcard.getAttribute(Contact.CONTRIBUTOR_NAME).getValue(), is("first.last"));
        assertThat(mcard.getAttribute(Media.TYPE).getValue(), is("text/html"));
        assertThat(mcard.getAttribute(Security.ACCESS_GROUPS).getValue(), is("ddf-developers"));
        assertThat(mcard.getAttribute(Security.ACCESS_INDIVIDUALS).getValue(), is("first.last"));
        assertThat(mcard.getAttribute(Topic.CATEGORY).getValue(), is("page"));
        assertThat(mcard.getAttribute(Topic.VOCABULARY).getValue(), is(
                "https://developer.atlassian.com/confdev/confluence-server-rest-api/advanced-searching-using-cql/cql-field-reference#CQLFieldReference-titleTitleType"));
        assertThat(mcard.getAttribute(Topic.KEYWORD).getValue(), is("testlabel"));
    }

    private void setupRegistryEntry(String attributeName, AttributeType type) {
        when(registry.lookup(attributeName))
                .thenReturn(Optional.of(new AttributeDescriptorImpl(attributeName, true, true, true, false, type)));
    }

    class TestConfluenceSource extends ConfluenceSource {
        private SecureCxfClientFactory<SearchResource> mockFactory;

        public TestConfluenceSource(FilterAdapter adapter, EncryptionService encryptionService,
                ConfluenceInputTransformer transformer, ResourceReader reader, AttributeRegistry registry,
                SecureCxfClientFactory<SearchResource> mockFactory, ClientFactoryFactory clientFactoryFactory) {
            super(adapter, encryptionService, transformer, reader, registry, clientFactoryFactory);
            this.mockFactory = mockFactory;
        }

        @Override
        public void init() {
        }

        public SecureCxfClientFactory<SearchResource> getClientFactory() {
            return mockFactory;
        }
    }

    private static String getFileContent(String filePath) {
        try {
            return IOUtils.toString(ConfluenceSourceTest.class.getClassLoader().getResourceAsStream(filePath),
                    StandardCharsets.UTF_8.toString());
        } catch (IOException e) {
            throw new RuntimeException("Failed to read filepath: " + filePath);
        }
    }
}