/**
* 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.opensearch;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.eq;
import static org.mockito.Matchers.isA;
import static org.mockito.Mockito.mock;
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.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.MultivaluedHashMap;
import javax.ws.rs.core.MultivaluedMap;
import javax.ws.rs.core.Response;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.util.ParameterParser;
import org.apache.cxf.jaxrs.client.Client;
import org.apache.cxf.jaxrs.client.WebClient;
import org.junit.Ignore;
import org.junit.Test;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.opengis.filter.Filter;
import org.osgi.framework.InvalidSyntaxException;
import junit.framework.Assert;
import ddf.catalog.data.BinaryContent;
import ddf.catalog.data.Metacard;
import ddf.catalog.data.Result;
import ddf.catalog.data.impl.BinaryContentImpl;
import ddf.catalog.data.impl.MetacardImpl;
import ddf.catalog.filter.FilterAdapter;
import ddf.catalog.filter.FilterBuilder;
import ddf.catalog.filter.proxy.adapter.GeotoolsFilterAdapterImpl;
import ddf.catalog.filter.proxy.builder.GeotoolsFilterBuilder;
import ddf.catalog.operation.Query;
import ddf.catalog.operation.ResourceResponse;
import ddf.catalog.operation.SourceResponse;
import ddf.catalog.operation.impl.QueryImpl;
import ddf.catalog.operation.impl.QueryRequestImpl;
import ddf.catalog.resource.ResourceNotFoundException;
import ddf.catalog.resource.ResourceNotSupportedException;
import ddf.catalog.source.UnsupportedQueryException;
import ddf.catalog.transform.CatalogTransformerException;
import ddf.catalog.transform.InputTransformer;
/**
* Tests parts of the {@link OpenSearchSource}
*
* @author Ashraf Barakat
* @author ddf.isgs@lmco.com
*
*/
public class TestOpenSearchSource {
private static final GeotoolsFilterAdapterImpl FILTER_ADAPTER = new GeotoolsFilterAdapterImpl();
private static final String SAMPLE_ID = "abcdef12345678900987654321fedcba";
private static final String SAMPLE_SEARCH_PHRASE = "foobar";
private static final String BYTES_TO_SKIP = "BytesToSkip";
private static FilterBuilder filterBuilder = new GeotoolsFilterBuilder();
private static InputStream getSampleAtomStream() {
String response =
"<feed xmlns=\"http://www.w3.org/2005/Atom\" xmlns:os=\"http://a9.com/-/spec/opensearch/1.1/\">\r\n"
+ " <title type=\"text\">Query Response</title>\r\n"
+ " <updated>2013-01-31T23:22:37.298Z</updated>\r\n"
+ " <id>urn:uuid:a27352c9-f935-45f0-9b8c-5803095164bb</id>\r\n"
+ " <link href=\"#\" rel=\"self\" />\r\n" + " <author>\r\n"
+ " <name>Codice</name>\r\n" + " </author>\r\n"
+ " <generator version=\"2.1.0.20130129-1341\">ddf123</generator>\r\n"
+ " <os:totalResults>1</os:totalResults>\r\n"
+ " <os:itemsPerPage>10</os:itemsPerPage>\r\n"
+ " <os:startIndex>1</os:startIndex>\r\n"
+ " <entry xmlns:relevance=\"http://a9.com/-/opensearch/extensions/relevance/1.0/\" xmlns:fs=\"http://a9.com/-/opensearch/extensions/federation/1.0/\"\r\n"
+ " xmlns:georss=\"http://www.georss.org/georss\">\r\n"
+ " <fs:resultSource fs:sourceId=\"ddf123\" />\r\n"
+ " <relevance:score>0.19</relevance:score>\r\n"
+ " <id>urn:catalog:id:ee7a161e01754b9db1872bfe39d1ea09</id>\r\n"
+ " <title type=\"text\">F-15 lands in Libya; Crew Picked Up</title>\r\n"
+ " <updated>2013-01-31T23:22:31.648Z</updated>\r\n"
+ " <published>2013-01-31T23:22:31.648Z</published>\r\n"
+ " <link href=\"http://123.45.67.123:8181/services/catalog/ddf123/ee7a161e01754b9db1872bfe39d1ea09\" rel=\"alternate\" title=\"View Complete Metacard\" />\r\n"
+ " <category term=\"Resource\" />\r\n"
+ " <georss:where xmlns:gml=\"http://www.opengis.net/gml\">\r\n"
+ " <gml:Point>\r\n"
+ " <gml:pos>32.8751900768792 13.1874561309814</gml:pos>\r\n"
+ " </gml:Point>\r\n" + " </georss:where>\r\n"
+ " <content type=\"application/xml\">\r\n"
+ " <ns3:metacard xmlns:ns3=\"urn:catalog:metacard\" xmlns:ns2=\"http://www.w3.org/1999/xlink\" xmlns:ns1=\"http://www.opengis.net/gml\"\r\n"
+ " xmlns:ns4=\"http://www.w3.org/2001/SMIL20/\" xmlns:ns5=\"http://www.w3.org/2001/SMIL20/Language\" ns1:id=\"4535c53fc8bc4404a1d32a5ce7a29585\">\r\n"
+ " <ns3:type>ddf.metacard</ns3:type>\r\n"
+ " <ns3:source>ddf.distribution</ns3:source>\r\n"
+ " <ns3:geometry name=\"location\">\r\n"
+ " <ns3:value>\r\n"
+ " <ns1:Point>\r\n"
+ " <ns1:pos>32.8751900768792 13.1874561309814</ns1:pos>\r\n"
+ " </ns1:Point>\r\n"
+ " </ns3:value>\r\n"
+ " </ns3:geometry>\r\n"
+ " <ns3:dateTime name=\"created\">\r\n"
+ " <ns3:value>2013-01-31T16:22:31.648-07:00</ns3:value>\r\n"
+ " </ns3:dateTime>\r\n"
+ " <ns3:dateTime name=\"modified\">\r\n"
+ " <ns3:value>2013-01-31T16:22:31.648-07:00</ns3:value>\r\n"
+ " </ns3:dateTime>\r\n"
+ " <ns3:stringxml name=\"metadata\">\r\n"
+ " <ns3:value>\r\n"
+ " <ns6:xml xmlns:ns6=\"urn:sample:namespace\" xmlns=\"urn:sample:namespace\">Example description.</ns6:xml>\r\n"
+ " </ns3:value>\r\n"
+ " </ns3:stringxml>\r\n"
+ " <ns3:string name=\"metadata-content-type-version\">\r\n"
+ " <ns3:value>myVersion</ns3:value>\r\n"
+ " </ns3:string>\r\n"
+ " <ns3:string name=\"metadata-content-type\">\r\n"
+ " <ns3:value>myType</ns3:value>\r\n"
+ " </ns3:string>\r\n"
+ " <ns3:string name=\"title\">\r\n"
+ " <ns3:value>Example title</ns3:value>\r\n"
+ " </ns3:string>\r\n" + " </ns3:metacard>\r\n"
+ " </content>\r\n" + " </entry>\r\n" + "</feed>";
return new ByteArrayInputStream(response.getBytes());
}
private static InputStream getSampleRssStream() {
String response =
"<rss version=\"2.0\" xmlns:os=\"http://a9.com/-/spec/opensearch/1.1/\" xmlns:content=\"http://purl.org/rss/1.0/modules/content/\"><channel>\r\n"
+ " <title type=\"text\">Query Response</title>\r\n"
+ " <lastBuildDate>2013-01-31T23:22:37.298Z</lastBuildDate>\r\n"
+ " <guid>urn:uuid:a27352c9-f935-45f0-9b8c-5803095164bb</guid>\r\n"
+ " <link href=\"#\" rel=\"self\" />\r\n" + " <managingEditor>\r\n"
+ " Codice\r\n" + " </managingEditor>\r\n"
+ " <generator>ddf123</generator>\r\n"
+ " <os:totalResults>1</os:totalResults>\r\n"
+ " <os:itemsPerPage>10</os:itemsPerPage>\r\n"
+ " <os:startIndex>1</os:startIndex>\r\n"
+ " <item xmlns:relevance=\"http://a9.com/-/opensearch/extensions/relevance/1.0/\" xmlns:fs=\"http://a9.com/-/opensearch/extensions/federation/1.0/\"\r\n"
+ " xmlns:georss=\"http://www.georss.org/georss\">\r\n"
+ " <fs:resultSource fs:sourceId=\"ddf123\" />\r\n"
+ " <relevance:score>0.19</relevance:score>\r\n"
+ " <guid>urn:catalog:id:ee7a161e01754b9db1872bfe39d1ea09</guid>\r\n"
+ " <title type=\"text\">F-15 lands in Libya; Crew Picked Up</title>\r\n"
+ " <pubDate>2013-01-31T23:22:31.648Z</pubDate>\r\n"
+ " <link href=\"http://123.45.67.123:8181/services/catalog/ddf123/ee7a161e01754b9db1872bfe39d1ea09\" rel=\"alternate\" title=\"View Complete Metacard\" />\r\n"
+ " <category>Resource</category>\r\n"
+ " <georss:where xmlns:gml=\"http://www.opengis.net/gml\">\r\n"
+ " <gml:Point>\r\n"
+ " <gml:pos>32.8751900768792 13.1874561309814</gml:pos>\r\n"
+ " </gml:Point>\r\n" + " </georss:where>\r\n"
+ " <content:encoded>\r\n"
+ " <![CDATA[<ns3:metacard xmlns:ns3=\"urn:catalog:metacard\" xmlns:ns2=\"http://www.w3.org/1999/xlink\" xmlns:ns1=\"http://www.opengis.net/gml\"\r\n"
+ " xmlns:ns4=\"http://www.w3.org/2001/SMIL20/\" xmlns:ns5=\"http://www.w3.org/2001/SMIL20/Language\" ns1:id=\"4535c53fc8bc4404a1d32a5ce7a29585\">\r\n"
+ " <ns3:type>ddf.metacard</ns3:type>\r\n"
+ " <ns3:source>ddf.distribution</ns3:source>\r\n"
+ " <ns3:geometry name=\"location\">\r\n"
+ " <ns3:value>\r\n"
+ " <ns1:Point>\r\n"
+ " <ns1:pos>32.8751900768792 13.1874561309814</ns1:pos>\r\n"
+ " </ns1:Point>\r\n"
+ " </ns3:value>\r\n"
+ " </ns3:geometry>\r\n"
+ " <ns3:dateTime name=\"created\">\r\n"
+ " <ns3:value>2013-01-31T16:22:31.648-07:00</ns3:value>\r\n"
+ " </ns3:dateTime>\r\n"
+ " <ns3:dateTime name=\"modified\">\r\n"
+ " <ns3:value>2013-01-31T16:22:31.648-07:00</ns3:value>\r\n"
+ " </ns3:dateTime>\r\n"
+ " <ns3:stringxml name=\"metadata\">\r\n"
+ " <ns3:value>\r\n"
+ " <ns6:xml xmlns:ns6=\"urn:sample:namespace\" xmlns=\"urn:sample:namespace\">Example description.</ns6:xml>\r\n"
+ " </ns3:value>\r\n"
+ " </ns3:stringxml>\r\n"
+ " <ns3:string name=\"metadata-content-type-version\">\r\n"
+ " <ns3:value>myVersion</ns3:value>\r\n"
+ " </ns3:string>\r\n"
+ " <ns3:string name=\"metadata-content-type\">\r\n"
+ " <ns3:value>myType</ns3:value>\r\n"
+ " </ns3:string>\r\n"
+ " <ns3:string name=\"title\">\r\n"
+ " <ns3:value>Example title</ns3:value>\r\n"
+ " </ns3:string>\r\n" + " </ns3:metacard>]]>\r\n"
+ " </content:encoded>\r\n" + " </item>\r\n" + "</channel></rss>";
return new ByteArrayInputStream(response.getBytes());
}
private static InputStream getBinaryData() {
byte[] sampleBytes = {80, 81, 82};
return new ByteArrayInputStream(sampleBytes);
}
private static InputStream getSampleXmlStream() {
String response = "\r\n"
+ " <ns3:metacard xmlns:ns3=\"urn:catalog:metacard\" xmlns:ns2=\"http://www.w3.org/1999/xlink\" xmlns:ns1=\"http://www.opengis.net/gml\"\r\n"
+ " xmlns:ns4=\"http://www.w3.org/2001/SMIL20/\" xmlns:ns5=\"http://www.w3.org/2001/SMIL20/Language\" ns1:id=\"4535c53fc8bc4404a1d32a5ce7a29585\">\r\n"
+ " <ns3:type>ddf.metacard</ns3:type>\r\n"
+ " <ns3:source>ddf.distribution</ns3:source>\r\n"
+ " <ns3:geometry name=\"location\">\r\n"
+ " <ns3:value>\r\n" + " <ns1:Point>\r\n"
+ " <ns1:pos>32.8751900768792 13.1874561309814</ns1:pos>\r\n"
+ " </ns1:Point>\r\n"
+ " </ns3:value>\r\n" + " </ns3:geometry>\r\n"
+ " <ns3:dateTime name=\"created\">\r\n"
+ " <ns3:value>2013-01-31T16:22:31.648-07:00</ns3:value>\r\n"
+ " </ns3:dateTime>\r\n"
+ " <ns3:dateTime name=\"modified\">\r\n"
+ " <ns3:value>2013-01-31T16:22:31.648-07:00</ns3:value>\r\n"
+ " </ns3:dateTime>\r\n"
+ " <ns3:stringxml name=\"metadata\">\r\n"
+ " <ns3:value>\r\n"
+ " <ns6:xml xmlns:ns6=\"urn:sample:namespace\" xmlns=\"urn:sample:namespace\">Example description.</ns6:xml>\r\n"
+ " </ns3:value>\r\n" + " </ns3:stringxml>\r\n"
+ " <ns3:string name=\"metadata-content-type-version\">\r\n"
+ " <ns3:value>myVersion</ns3:value>\r\n"
+ " </ns3:string>\r\n"
+ " <ns3:string name=\"metadata-content-type\">\r\n"
+ " <ns3:value>myType</ns3:value>\r\n"
+ " </ns3:string>\r\n"
+ " <ns3:string name=\"title\">\r\n"
+ " <ns3:value>Example title</ns3:value>\r\n"
+ " </ns3:string>\r\n" + " </ns3:metacard>\r\n";
return new ByteArrayInputStream(response.getBytes());
}
/**
* Tests the proper query is sent to the remote source for query by id.
*
* @throws UnsupportedQueryException
* @throws IOException
* @throws MalformedURLException
*/
@Test
public void testQueryById() throws UnsupportedQueryException, IOException {
WebClient client = mock(WebClient.class);
Response clientResponse = mock(Response.class);
OpenSearchConnection openSearchConnection = mock(OpenSearchConnection.class);
when(openSearchConnection.getOpenSearchWebClient()).thenReturn(client);
when(client.get()).thenReturn(clientResponse);
when(clientResponse.getStatus()).thenReturn(Response.Status.OK.getStatusCode());
Client proxy = mock(Client.class);
when(openSearchConnection
.newRestClient(any(String.class), any(Query.class), any(String.class),
any(Boolean.class))).thenReturn(proxy);
when(openSearchConnection.getWebClientFromClient(proxy)).thenReturn(client);
when(clientResponse.getEntity())
.thenReturn(new BinaryContentImpl(getSampleXmlStream()).getInputStream());
OverridenOpenSearchSource source = new OverridenOpenSearchSource(FILTER_ADAPTER);
source.setInputTransformer(getMockInputTransformer());
source.setEndpointUrl("http://localhost:8181/services/catalog/query");
source.init();
source.setParameters(
"q,src,mr,start,count,mt,dn,lat,lon,radius,bbox,polygon,dtstart,dtend,dateName,filter,sort");
source.openSearchConnection = openSearchConnection;
Filter filter = filterBuilder.attribute(Metacard.ID).equalTo().text(SAMPLE_ID);
// when
SourceResponse response = source.query(new QueryRequestImpl(new QueryImpl(filter)));
// then
Assert.assertEquals(1, response.getHits());
}
@Test
@Ignore
// Ignored because Content Type support has yet to be added.
public void testQueryByContentType()
throws UnsupportedQueryException, IOException, URISyntaxException {
// given
FirstArgumentCapture answer = new FirstArgumentCapture(getSampleAtomStream());
OpenSearchSource source = givenSource(answer);
Filter filter = filterBuilder.attribute(Metacard.CONTENT_TYPE).equalTo().text(SAMPLE_ID);
// when
SourceResponse response = source.query(new QueryRequestImpl(new QueryImpl(filter)));
// then
List<NameValuePair> pairs = extractQueryParams(answer);
verifyOpenSearchUrl(pairs, pair("type", SAMPLE_ID));
}
@Test
public void testQueryBySearchPhrase()
throws UnsupportedQueryException, URISyntaxException, IOException {
WebClient client = mock(WebClient.class);
Response clientResponse = mock(Response.class);
OpenSearchConnection openSearchConnection = mock(OpenSearchConnection.class);
when(openSearchConnection.getOpenSearchWebClient()).thenReturn(client);
when(client.get()).thenReturn(clientResponse);
when(clientResponse.getStatus()).thenReturn(Response.Status.OK.getStatusCode());
when(clientResponse.getEntity())
.thenReturn(new BinaryContentImpl(getSampleAtomStream()).getInputStream());
OverridenOpenSearchSource source = new OverridenOpenSearchSource(FILTER_ADAPTER);
source.setInputTransformer(getMockInputTransformer());
source.setEndpointUrl("http://localhost:8181/services/catalog/query");
source.init();
source.setParameters(
"q,src,mr,start,count,mt,dn,lat,lon,radius,bbox,polygon,dtstart,dtend,dateName,filter,sort");
source.openSearchConnection = openSearchConnection;
Filter filter = filterBuilder.attribute(Metacard.METADATA).like()
.text(SAMPLE_SEARCH_PHRASE);
// when
SourceResponse response = source.query(new QueryRequestImpl(new QueryImpl(filter)));
Assert.assertEquals(1, response.getHits());
List<Result> results = response.getResults();
Assert.assertTrue(results.size() == 1);
Result result = results.get(0);
Metacard metacard = result.getMetacard();
Assert.assertNotNull(metacard);
Assert.assertEquals("Resource", metacard.getContentTypeName());
}
@Test
public void testQueryBySearchPhraseRss()
throws UnsupportedQueryException, URISyntaxException, IOException {
WebClient client = mock(WebClient.class);
Response clientResponse = mock(Response.class);
OpenSearchConnection openSearchConnection = mock(OpenSearchConnection.class);
when(openSearchConnection.getOpenSearchWebClient()).thenReturn(client);
when(client.get()).thenReturn(clientResponse);
when(clientResponse.getStatus()).thenReturn(Response.Status.OK.getStatusCode());
when(clientResponse.getEntity())
.thenReturn(new BinaryContentImpl(getSampleRssStream()).getInputStream());
OverridenOpenSearchSource source = new OverridenOpenSearchSource(FILTER_ADAPTER);
source.setInputTransformer(getMockInputTransformer());
source.setEndpointUrl("http://localhost:8181/services/catalog/query");
source.init();
source.setParameters(
"q,src,mr,start,count,mt,dn,lat,lon,radius,bbox,polygon,dtstart,dtend,dateName,filter,sort");
source.openSearchConnection = openSearchConnection;
Filter filter = filterBuilder.attribute(Metacard.METADATA).like()
.text(SAMPLE_SEARCH_PHRASE);
// when
SourceResponse response = source.query(new QueryRequestImpl(new QueryImpl(filter)));
Assert.assertEquals(1, response.getHits());
List<Result> results = response.getResults();
Assert.assertTrue(results.size() == 1);
Result result = results.get(0);
Metacard metacard = result.getMetacard();
Assert.assertNotNull(metacard);
Assert.assertEquals("Resource", metacard.getContentTypeName());
}
@Test
public void testQueryBySearchPhraseContentTypeSet()
throws UnsupportedQueryException, URISyntaxException, IOException {
WebClient client = mock(WebClient.class);
Response clientResponse = mock(Response.class);
OpenSearchConnection openSearchConnection = mock(OpenSearchConnection.class);
when(openSearchConnection.getOpenSearchWebClient()).thenReturn(client);
when(client.get()).thenReturn(clientResponse);
when(clientResponse.getStatus()).thenReturn(Response.Status.OK.getStatusCode());
when(clientResponse.getEntity())
.thenReturn(new BinaryContentImpl(getSampleAtomStream()).getInputStream());
OverridenOpenSearchSource source = new OverridenOpenSearchSource(FILTER_ADAPTER);
InputTransformer inputTransformer = mock(InputTransformer.class);
MetacardImpl generatedMetacard = new MetacardImpl();
generatedMetacard.setMetadata(getSample());
generatedMetacard.setId(SAMPLE_ID);
generatedMetacard.setContentTypeName("myType");
try {
when(inputTransformer.transform(isA(InputStream.class))).thenReturn(generatedMetacard);
when(inputTransformer.transform(isA(InputStream.class), isA(String.class)))
.thenReturn(generatedMetacard);
} catch (IOException e) {
fail();
} catch (CatalogTransformerException e) {
fail();
}
source.setInputTransformer(inputTransformer);
source.setEndpointUrl("http://localhost:8181/services/catalog/query");
source.init();
source.setParameters(
"q,src,mr,start,count,mt,dn,lat,lon,radius,bbox,polygon,dtstart,dtend,dateName,filter,sort");
source.openSearchConnection = openSearchConnection;
Filter filter = filterBuilder.attribute(Metacard.METADATA).like()
.text(SAMPLE_SEARCH_PHRASE);
SourceResponse response = source.query(new QueryRequestImpl(new QueryImpl(filter)));
Assert.assertEquals(1, response.getHits());
List<Result> results = response.getResults();
Assert.assertTrue(results.size() == 1);
Result result = results.get(0);
Metacard metacard = result.getMetacard();
Assert.assertNotNull(metacard);
Assert.assertEquals("myType", metacard.getContentTypeName());
}
@Test
public void testQueryBySearchPhraseContentTypeSetRss()
throws UnsupportedQueryException, URISyntaxException, IOException {
WebClient client = mock(WebClient.class);
Response clientResponse = mock(Response.class);
OpenSearchConnection openSearchConnection = mock(OpenSearchConnection.class);
when(openSearchConnection.getOpenSearchWebClient()).thenReturn(client);
when(client.get()).thenReturn(clientResponse);
when(clientResponse.getStatus()).thenReturn(Response.Status.OK.getStatusCode());
when(clientResponse.getEntity())
.thenReturn(new BinaryContentImpl(getSampleRssStream()).getInputStream());
OverridenOpenSearchSource source = new OverridenOpenSearchSource(FILTER_ADAPTER);
InputTransformer inputTransformer = mock(InputTransformer.class);
MetacardImpl generatedMetacard = new MetacardImpl();
generatedMetacard.setMetadata(getSample());
generatedMetacard.setId(SAMPLE_ID);
generatedMetacard.setContentTypeName("myType");
try {
when(inputTransformer.transform(isA(InputStream.class))).thenReturn(generatedMetacard);
when(inputTransformer.transform(isA(InputStream.class), isA(String.class)))
.thenReturn(generatedMetacard);
} catch (IOException e) {
fail();
} catch (CatalogTransformerException e) {
fail();
}
source.setInputTransformer(inputTransformer);
source.setEndpointUrl("http://localhost:8181/services/catalog/query");
source.init();
source.setParameters(
"q,src,mr,start,count,mt,dn,lat,lon,radius,bbox,polygon,dtstart,dtend,dateName,filter,sort");
source.openSearchConnection = openSearchConnection;
Filter filter = filterBuilder.attribute(Metacard.METADATA).like()
.text(SAMPLE_SEARCH_PHRASE);
SourceResponse response = source.query(new QueryRequestImpl(new QueryImpl(filter)));
Assert.assertEquals(1, response.getHits());
List<Result> results = response.getResults();
Assert.assertTrue(results.size() == 1);
Result result = results.get(0);
Metacard metacard = result.getMetacard();
Assert.assertNotNull(metacard);
Assert.assertEquals("myType", metacard.getContentTypeName());
}
@Test
public void testQueryAnyText()
throws UnsupportedQueryException, URISyntaxException, IOException {
WebClient client = mock(WebClient.class);
Response clientResponse = mock(Response.class);
when(clientResponse.getStatus()).thenReturn(Response.Status.OK.getStatusCode());
OpenSearchConnection openSearchConnection = mock(OpenSearchConnection.class);
when(openSearchConnection.getOpenSearchWebClient()).thenReturn(client);
when(client.get()).thenReturn(clientResponse);
OverridenOpenSearchSource source = new OverridenOpenSearchSource(FILTER_ADAPTER);
source.setInputTransformer(getMockInputTransformer());
source.setEndpointUrl("http://localhost:8181/services/catalog/query");
source.init();
source.setParameters(
"q,src,mr,start,count,mt,dn,lat,lon,radius,bbox,polygon,dtstart,dtend,dateName,filter,sort");
source.openSearchConnection = openSearchConnection;
Filter filter = filterBuilder.attribute(Metacard.ANY_TEXT).like()
.text(SAMPLE_SEARCH_PHRASE);
// when
SourceResponse response = source.query(new QueryRequestImpl(new QueryImpl(filter)));
Assert.assertEquals(0, response.getHits());
}
@Test(expected = UnsupportedQueryException.class)
public void testQueryBadResponse() throws UnsupportedQueryException, IOException {
WebClient client = mock(WebClient.class);
Response clientResponse = mock(Response.class);
when(clientResponse.getStatus())
.thenReturn(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode());
OpenSearchConnection openSearchConnection = mock(OpenSearchConnection.class);
when(openSearchConnection.getOpenSearchWebClient()).thenReturn(client);
when(client.get()).thenReturn(clientResponse);
OverridenOpenSearchSource source = new OverridenOpenSearchSource(FILTER_ADAPTER);
source.setInputTransformer(getMockInputTransformer());
source.setEndpointUrl("http://localhost:8181/services/catalog/query");
source.init();
source.setParameters(
"q,src,mr,start,count,mt,dn,lat,lon,radius,bbox,polygon,dtstart,dtend,dateName,filter,sort");
source.openSearchConnection = openSearchConnection;
Filter filter = filterBuilder.attribute(Metacard.ANY_TEXT).like()
.text(SAMPLE_SEARCH_PHRASE);
source.query(new QueryRequestImpl(new QueryImpl(filter)));
}
/**
* Basic retrieve product case. Tests the url sent to the connection is correct.
*
* @throws ResourceNotSupportedException
* @throws IOException
* @throws ResourceNotFoundException
*/
@Test
public void testRetrieveResource()
throws ResourceNotSupportedException, IOException, ResourceNotFoundException {
// given
FirstArgumentCapture answer = new FirstArgumentCapture(getBinaryData());
OpenSearchSource source = givenSource(answer);
Map<String, Serializable> requestProperties = new HashMap<String, Serializable>();
requestProperties.put(Metacard.ID, SAMPLE_ID);
// when
ResourceResponse response = source.retrieveResource(null, requestProperties);
Assert.assertEquals(3, response.getResource().getByteArray().length);
}
@Test
public void testRetrieveResourceWithBytesToSkip()
throws ResourceNotSupportedException, IOException, ResourceNotFoundException {
// given
FirstArgumentCapture answer = new FirstArgumentCapture(getBinaryData());
OpenSearchSource source = givenSource(answer);
Map<String, Serializable> requestProperties = new HashMap<String, Serializable>();
requestProperties.put(Metacard.ID, SAMPLE_ID);
requestProperties.put(OpenSearchSource.BYTES_TO_SKIP, Long.valueOf(2));
// when
ResourceResponse response = source.retrieveResource(null, requestProperties);
//DDF-643 Assert.assertEquals(1, response.getResource().getByteArray().length);
Assert.assertTrue((Boolean) response.getPropertyValue(OpenSearchSource.BYTES_SKIPPED));
}
/**
* Given all null params, nothing will be returned, expect an exception.
*
* @throws ResourceNotSupportedException
*/
@Test
public void testRetrieveNullProduct() throws ResourceNotSupportedException, IOException {
WebClient client = mock(WebClient.class);
Response clientResponse = mock(Response.class);
OpenSearchConnection openSearchConnection = mock(OpenSearchConnection.class);
when(openSearchConnection.getOpenSearchWebClient()).thenReturn(client);
when(client.get()).thenReturn(clientResponse);
OverridenOpenSearchSource source = new OverridenOpenSearchSource(FILTER_ADAPTER);
source.openSearchConnection = openSearchConnection;
// when
try {
source.retrieveResource(null, null);
// then
fail("Should have thrown " + ResourceNotFoundException.class.getName()
+ " because of null uri.");
} catch (ResourceNotFoundException e) {
/*
* this exception should have been thrown.
*/
assertThat(e.getMessage(),
containsString(OpenSearchSource.COULD_NOT_RETRIEVE_RESOURCE_MESSAGE));
assertThat(e.getMessage(), containsString("null"));
}
}
@Test
public void testRetrieveProductUriSyntaxException()
throws ResourceNotSupportedException, IOException {
WebClient client = mock(WebClient.class);
Response clientResponse = mock(Response.class);
OpenSearchConnection openSearchConnection = mock(OpenSearchConnection.class);
when(openSearchConnection.getOpenSearchWebClient()).thenReturn(client);
when(client.get()).thenReturn(clientResponse);
OverridenOpenSearchSource source = new OverridenOpenSearchSource(FILTER_ADAPTER);
source.openSearchConnection = openSearchConnection;
source.setEndpointUrl("http://example.com/q?s=^LMT");
Map<String, Serializable> requestProperties = new HashMap<String, Serializable>();
requestProperties.put(Metacard.ID, SAMPLE_ID);
// when
try {
source.retrieveResource(null, requestProperties);
// then
fail("Should have thrown " + ResourceNotFoundException.class.getName()
+ " because of null uri.");
} catch (ResourceNotFoundException e) {
/*
* this exception should have been thrown.
*/
assertThat(e.getMessage(),
containsString(OpenSearchSource.COULD_NOT_RETRIEVE_RESOURCE_MESSAGE));
}
}
@Test
public void testRetrieveProductMalformedUrlException()
throws ResourceNotSupportedException, IOException {
WebClient client = mock(WebClient.class);
Response clientResponse = mock(Response.class);
OpenSearchConnection openSearchConnection = mock(OpenSearchConnection.class);
when(openSearchConnection.getOpenSearchWebClient()).thenReturn(client);
when(client.get()).thenReturn(clientResponse);
OverridenOpenSearchSource source = new OverridenOpenSearchSource(FILTER_ADAPTER);
source.openSearchConnection = openSearchConnection;
source.setEndpointUrl("unknownProtocol://localhost:8181/services/catalog/query");
Map<String, Serializable> requestProperties = new HashMap<String, Serializable>();
requestProperties.put(Metacard.ID, SAMPLE_ID);
// when
try {
source.retrieveResource(null, requestProperties);
// then
fail("Should have thrown " + ResourceNotFoundException.class.getName()
+ " because of null uri.");
} catch (ResourceNotFoundException e) {
/*
* this exception should have been thrown.
*/
assertThat(e.getMessage(),
containsString(OpenSearchSource.COULD_NOT_RETRIEVE_RESOURCE_MESSAGE));
}
}
// DDF-161
@Test
public void testQueryQueryByMetacardIdFollowedByAnyTextQuery() throws Exception {
WebClient client = mock(WebClient.class);
Response clientResponse = mock(Response.class);
when(clientResponse.getStatus()).thenReturn(Response.Status.OK.getStatusCode());
OpenSearchConnection openSearchConnection = mock(OpenSearchConnection.class);
when(openSearchConnection.getOpenSearchWebClient()).thenReturn(client);
when(client.get()).thenReturn(clientResponse);
Client proxy = mock(Client.class);
when(openSearchConnection
.newRestClient(any(String.class), any(Query.class), any(String.class),
any(Boolean.class))).thenReturn(proxy);
when(openSearchConnection.getWebClientFromClient(proxy)).thenReturn(client);
when(clientResponse.getEntity())
.thenReturn(new BinaryContentImpl(getSampleXmlStream()).getInputStream())
.thenReturn(new BinaryContentImpl(getSampleAtomStream()).getInputStream());
OverridenOpenSearchSource source = new OverridenOpenSearchSource(FILTER_ADAPTER);
source.setLocalQueryOnly(true);
source.setInputTransformer(getMockInputTransformer());
source.setEndpointUrl("http://localhost:8181/services/catalog/query");
source.init();
source.setParameters(
"q,src,mr,start,count,mt,dn,lat,lon,radius,bbox,polygon,dtstart,dtend,dateName,filter,sort");
source.openSearchConnection = openSearchConnection;
// Metacard ID filter
Filter idFilter = filterBuilder.attribute(Metacard.ID).equalTo().text(SAMPLE_ID);
// Any text filter
Filter anyTextFilter = filterBuilder.attribute(Metacard.ANY_TEXT).like()
.text(SAMPLE_SEARCH_PHRASE);
// Perform Test (Query by ID followed by Any Text Query)
SourceResponse response1 = source.query(new QueryRequestImpl(new QueryImpl(idFilter)));
SourceResponse response2 = source.query(new QueryRequestImpl(new QueryImpl(anyTextFilter)));
// Verification - Verify that we don't see any exceptions when
// processing the input stream from the endpoint.
// Verify 1 metacard is in the results
assertThat(response1.getResults().size(), is(1));
// Verify that the atom feed is converted into 1 metacard result
assertThat(response2.getResults().size(), is(1));
}
// DDF-161
@Test
public void testQueryQueryByMetacardIdFollowedByAnyTextQueryRss() throws Exception {
WebClient client = mock(WebClient.class);
Response clientResponse = mock(Response.class);
when(clientResponse.getStatus()).thenReturn(Response.Status.OK.getStatusCode());
OpenSearchConnection openSearchConnection = mock(OpenSearchConnection.class);
when(openSearchConnection.getOpenSearchWebClient()).thenReturn(client);
when(client.get()).thenReturn(clientResponse);
Client proxy = mock(Client.class);
when(openSearchConnection
.newRestClient(any(String.class), any(Query.class), any(String.class),
any(Boolean.class))).thenReturn(proxy);
when(openSearchConnection.getWebClientFromClient(proxy)).thenReturn(client);
when(clientResponse.getEntity())
.thenReturn(new BinaryContentImpl(getSampleXmlStream()).getInputStream())
.thenReturn(new BinaryContentImpl(getSampleRssStream()).getInputStream());
OverridenOpenSearchSource source = new OverridenOpenSearchSource(FILTER_ADAPTER);
source.setLocalQueryOnly(true);
source.setInputTransformer(getMockInputTransformer());
source.setEndpointUrl("http://localhost:8181/services/catalog/query");
source.init();
source.setParameters(
"q,src,mr,start,count,mt,dn,lat,lon,radius,bbox,polygon,dtstart,dtend,dateName,filter,sort");
source.openSearchConnection = openSearchConnection;
// Metacard ID filter
Filter idFilter = filterBuilder.attribute(Metacard.ID).equalTo().text(SAMPLE_ID);
// Any text filter
Filter anyTextFilter = filterBuilder.attribute(Metacard.ANY_TEXT).like()
.text(SAMPLE_SEARCH_PHRASE);
// Perform Test (Query by ID followed by Any Text Query)
SourceResponse response1 = source.query(new QueryRequestImpl(new QueryImpl(idFilter)));
SourceResponse response2 = source.query(new QueryRequestImpl(new QueryImpl(anyTextFilter)));
// Verification - Verify that we don't see any exceptions when
// processing the input stream from the endpoint.
// Verify 1 metacard is in the results
assertThat(response1.getResults().size(), is(1));
// Verify that the atom feed is converted into 1 metacard result
assertThat(response2.getResults().size(), is(1));
}
private NameValuePair pair(String name, String value) {
return new NameValuePair(name, value);
}
private List<NameValuePair> extractQueryParams(FirstArgumentCapture answer)
throws MalformedURLException, URISyntaxException {
URL url = new URI(answer.getInputArg()).toURL();
ParameterParser paramParser = new ParameterParser();
List<NameValuePair> pairs = paramParser.parse(url.getQuery(), '&');
return pairs;
}
private void verifyOpenSearchUrl(List<NameValuePair> pairs, NameValuePair... answers) {
ConcurrentHashMap<String, String> nvpMap = createMapFor(pairs);
for (NameValuePair answerPair : answers) {
assertThat(nvpMap.get(answerPair.getName()), is(answerPair.getValue()));
nvpMap.remove(answerPair.getName());
}
assertThat(nvpMap.get("count"), is("20"));
nvpMap.remove("count");
assertThat(nvpMap.get("mt"), is("0"));
nvpMap.remove("mt");
assertThat(nvpMap.get("src"), is("local"));
nvpMap.remove("src");
verifyAllEntriesBlank(nvpMap);
}
/**
* Verifies that the rest of the entries don't have a corresponding value
*
* @param nvpMap
*/
private void verifyAllEntriesBlank(ConcurrentHashMap<String, String> nvpMap) {
for (Entry<String, String> entry : nvpMap.entrySet()) {
String errorMessage =
"[" + entry.getKey() + "]" + " should not have a corresponding value.";
assertThat(errorMessage, entry.getValue(), is(""));
}
}
private ConcurrentHashMap<String, String> createMapFor(List<NameValuePair> pairs) {
ConcurrentHashMap<String, String> map = new ConcurrentHashMap<String, String>();
for (NameValuePair pair : pairs) {
map.put(pair.getName(), pair.getValue());
}
return map;
}
private OpenSearchSource givenSource(Answer<BinaryContent> answer) throws IOException {
WebClient client = mock(WebClient.class);
OpenSearchConnection openSearchConnection = mock(OpenSearchConnection.class);
Client proxy = mock(Client.class);
when(openSearchConnection
.newRestClient(any(String.class), any(Query.class), any(String.class),
any(Boolean.class))).thenReturn(proxy);
when(openSearchConnection.getWebClientFromClient(proxy)).thenReturn(client);
Response clientResponse = mock(Response.class);
when(client.get()).thenReturn(clientResponse);
when(clientResponse.getEntity()).thenReturn(getBinaryData());
when(clientResponse.getHeaderString(eq(OpenSearchSource.HEADER_ACCEPT_RANGES)))
.thenReturn(OpenSearchSource.BYTES);
when(openSearchConnection.getOpenSearchWebClient()).thenReturn(client);
MultivaluedMap<String, Object> headers = new MultivaluedHashMap<String, Object>();
headers.put(HttpHeaders.CONTENT_TYPE, Arrays.<Object>asList("application/octet-stream"));
when(clientResponse.getHeaders()).thenReturn(headers);
OverridenOpenSearchSource source = new OverridenOpenSearchSource(FILTER_ADAPTER);
source.setEndpointUrl("http://localhost:8181/services/catalog/query");
source.setParameters(
"q,src,mr,start,count,mt,dn,lat,lon,radius,bbox,polygon,dtstart,dtend,dateName,filter,sort");
source.init();
source.setLocalQueryOnly(true);
source.setInputTransformer(getMockInputTransformer());
source.openSearchConnection = openSearchConnection;
return source;
}
protected InputTransformer getMockInputTransformer() {
InputTransformer inputTransformer = mock(InputTransformer.class);
Metacard generatedMetacard = getSimpleMetacard();
try {
when(inputTransformer.transform(isA(InputStream.class))).thenReturn(generatedMetacard);
when(inputTransformer.transform(isA(InputStream.class), isA(String.class)))
.thenReturn(generatedMetacard);
} catch (IOException e) {
fail();
} catch (CatalogTransformerException e) {
fail();
}
return inputTransformer;
}
protected Metacard getSimpleMetacard() {
MetacardImpl generatedMetacard = new MetacardImpl();
generatedMetacard.setMetadata(getSample());
generatedMetacard.setId(SAMPLE_ID);
return generatedMetacard;
}
private String getSample() {
return "<xml></xml>";
}
private class FirstArgumentCapture implements Answer<BinaryContent> {
private InputStream returnInputStream;
private String inputArg;
public FirstArgumentCapture() {
this.returnInputStream = getSampleXmlStream();
}
public FirstArgumentCapture(InputStream inputStream) {
this.returnInputStream = inputStream;
}
public String getInputArg() {
return inputArg;
}
@Override
public BinaryContent answer(InvocationOnMock invocation) throws Throwable {
this.inputArg = (String) invocation.getArguments()[0];
return new BinaryContentImpl(returnInputStream);
}
}
private class OverridenOpenSearchSource extends OpenSearchSource {
private InputTransformer transformer;
/**
* Creates an OpenSearch Site instance. Sets an initial default endpointUrl that can be
* overwritten using the setter methods.
*
* @throws UnsupportedQueryException
* @param filterAdapter
*/
public OverridenOpenSearchSource(FilterAdapter filterAdapter) {
super(filterAdapter);
}
protected void setInputTransformer(InputTransformer inputTransformer) {
transformer = inputTransformer;
}
@Override
protected InputTransformer lookupTransformerReference(String namespaceUri)
throws InvalidSyntaxException {
return transformer;
}
}
}