/** * 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.source.solr; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.io.IOException; import java.util.concurrent.Future; import org.apache.solr.client.solrj.SolrClient; import org.apache.solr.client.solrj.SolrServerException; import org.apache.solr.client.solrj.response.SolrPingResponse; import org.apache.solr.common.SolrException; import org.apache.solr.common.util.NamedList; import org.codice.solr.factory.impl.ConfigurationStore; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import ddf.catalog.filter.FilterAdapter; import ddf.catalog.operation.CreateRequest; import ddf.catalog.operation.DeleteRequest; import ddf.catalog.operation.QueryRequest; import ddf.catalog.operation.UpdateRequest; import ddf.catalog.source.CatalogProvider; import ddf.catalog.source.IngestException; import ddf.catalog.source.UnsupportedQueryException; public class RemoteSolrCatalogProviderTest { private static String cipherSuites; private static String protocols; @BeforeClass public static void setUp() { cipherSuites = System.getProperty("https.cipherSuites"); System.setProperty("https.cipherSuites", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_RSA_WITH_AES_128_CBC_SHA,TLS_DHE_DSS_WITH_AES_128_CBC_SHA,TLS_RSA_WITH_AES_128_CBC_SHA"); protocols = System.getProperty("https.protocols"); System.setProperty("https.protocols", "TLSv1.1, TLSv1.2"); } @AfterClass public static void tearDown() { if (cipherSuites != null) { System.setProperty("https.cipherSuites", cipherSuites); } else { System.clearProperty("https.cipherSuites"); } if (protocols != null) { System.setProperty("https.protocols", protocols); } else { System.clearProperty("https.protocols"); } } @Test(expected = IllegalArgumentException.class) public void testNullFilterAdapator() { new RemoteSolrCatalogProvider(null, mock(SolrClient.class), mock(SolrFilterDelegateFactory.class), mock(DynamicSchemaResolver.class)) { @Override protected Future<SolrClient> createClient() { return null; } }; } @Test(expected = IllegalArgumentException.class) public void testNullSolrFilterDelegateFactory() { new RemoteSolrCatalogProvider(mock(FilterAdapter.class), mock(SolrClient.class), null, mock(DynamicSchemaResolver.class)) { @Override protected Future<SolrClient> createClient() { return null; } }; } @Test public void testId() { CatalogProvider provider = new MockedRemoteSolrCatalogProvider(null); provider.maskId("myId"); assertEquals("myId", provider.getId()); } @Test public void testDescribableProperties() { CatalogProvider provider = new MockedRemoteSolrCatalogProvider(null); assertNotNull(provider.getTitle()); assertNotNull(provider.getDescription()); assertNotNull(provider.getOrganization()); assertNotNull(provider.getVersion()); } @Test public void testUnconfiguredCreate() throws IngestException, SolrServerException, IOException { SolrClient givenClient = givenSolrClient(false); CatalogProvider provider = new MockedRemoteSolrCatalogProvider(givenClient); try { provider.create(mock(CreateRequest.class)); } catch (IllegalStateException e) { assertThat(e.getMessage(), containsString("Solr client is not connected")); } } /** * Tests what happens when a {@link SolrException} is thrown when Solr is pinged * * @throws IngestException * @throws SolrServerException * @throws IOException */ @Test public void testUnconfiguredCreateSolrException() throws IngestException, SolrServerException, IOException { // given SolrClient givenClient = mock(SolrClient.class); when(givenClient.ping()).thenThrow(SolrException.class); CatalogProvider provider = new MockedRemoteSolrCatalogProvider(givenClient); // when String message = null; try { provider.create(mock(CreateRequest.class)); } catch (IllegalStateException e) { message = e.getMessage(); } // then assertThat(message, containsString("Solr client is not connected")); verify(givenClient, times(1)).ping(); } @Test(expected = IllegalStateException.class) public void testUnconfiguredDelete() throws IngestException { CatalogProvider provider = new MockedRemoteSolrCatalogProvider(null); provider.delete(mock(DeleteRequest.class)); } @Test(expected = IllegalStateException.class) public void testUnconfiguredUpdate() throws IngestException { CatalogProvider provider = new MockedRemoteSolrCatalogProvider(null); provider.update(mock(UpdateRequest.class)); } @Test(expected = IllegalStateException.class) public void testUnconfiguredQuery() throws UnsupportedQueryException { CatalogProvider provider = new MockedRemoteSolrCatalogProvider(null); provider.query(mock(QueryRequest.class)); } @Test public void testAvailability() throws IngestException { CatalogProvider provider = new MockedRemoteSolrCatalogProvider(null); assertThat(provider.isAvailable(), is(false)); } @Test public void testAvailabilitySourceMonitor() throws IngestException { CatalogProvider provider = new MockedRemoteSolrCatalogProvider(null); assertThat(provider.isAvailable(null), is(false)); } @Test(expected = IllegalStateException.class) public void testUnconfiguredGetContentTypes() throws IngestException { CatalogProvider provider = new MockedRemoteSolrCatalogProvider(null); provider.getContentTypes(); } /** * Tests that property replacement is performed on the URL provided to * {@link RemoteSolrCatalogProvider#setUrl(String)}. */ @Test public void testSetUrlResolvesProperties() throws Exception { // given SolrClient givenClient = givenSolrClient(true); RemoteSolrCatalogProvider provider = new MockedRemoteSolrCatalogProvider(givenClient); System.setProperty("test-property", "solr-url"); // when provider.setUrl("https://hostname:443/${test-property}"); // then assertThat(provider.getUrl(), is("https://hostname:443/solr-url")); // should be no failures/exceptions } @Test public void testSetUrlToNull() throws IngestException { RemoteSolrCatalogProvider provider = new MockedRemoteSolrCatalogProvider(null); provider.setUrl(null); // should be no failures/exceptions } @Test public void testUpdateConfigurationUrlPropertyNull() throws Exception { // given SolrClient givenClient = givenSolrClient(true); RemoteSolrCatalogProvider provider = new MockedRemoteSolrCatalogProvider(givenClient); // when provider.setUrl(null); // then assertThat(provider.getUrl(), is(nullValue())); verify(givenClient, times(0)).ping(); verify(givenClient, times(0)).close(); // should be no failures/exceptions } /** * Tests if the ConfigurationStore is set properly * * @throws IngestException */ @Test public void testForceAutoCommit() throws IngestException { RemoteSolrCatalogProvider provider = new MockedRemoteSolrCatalogProvider(null); provider.setForceAutoCommit(true); assertThat(ConfigurationStore.getInstance() .isForceAutoCommit(), is(true)); } /** * If the first connection was a failure, do a ping and attempt to connect to the new address. * * @throws IngestException * @throws SolrServerException * @throws IOException */ @Test public void testReAttemptSolrConnectionOnFail() throws IngestException, SolrServerException, IOException { // given String badAddress = "http://localhost:8183/solr"; boolean clientStatus = false; SolrClient givenClient = givenSolrClient(clientStatus); RemoteSolrCatalogProvider provider = new MockedRemoteSolrCatalogProvider(givenClient); // when try { provider.create(mock(CreateRequest.class)); } catch (IllegalStateException e) { } provider.setUrl(badAddress); // then verify(givenClient, times(1)).close(); verify(givenClient, times(1)).ping(); } @Test public void testShutdown() throws SolrServerException, IOException { boolean clientStatus = true; SolrClient givenClient = givenSolrClient(clientStatus); RemoteSolrCatalogProvider provider = new MockedRemoteSolrCatalogProvider(givenClient); provider.shutdown(); verify(givenClient, times(1)).close(); } /** * @return * @throws IOException * @throws SolrServerException */ private SolrClient givenSolrClient(boolean ok) throws SolrServerException, IOException { SolrClient client = mock(SolrClient.class); SolrPingResponse pingResponse = mock(SolrPingResponse.class); NamedList<Object> namedList = new NamedList<Object>(); if (ok) { namedList.add("status", "OK"); } else { namedList.add("status", "NOT_OK"); } when(pingResponse.getResponse()).thenReturn(namedList); when(client.ping()).thenReturn(pingResponse); return client; } private class MockedRemoteSolrCatalogProvider extends RemoteSolrCatalogProvider { public MockedRemoteSolrCatalogProvider(SolrClient client) { super(mock(FilterAdapter.class), client, mock(SolrFilterDelegateFactory.class), mock(DynamicSchemaResolver.class)); } @Override protected Future<SolrClient> createClient() { return null; } } }