/** * Copyright (c) Codice Foundation * * 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. * * 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.spatial.ogc.wfs.v1_0_0.catalog.source; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.mockito.Matchers.any; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.io.ByteArrayInputStream; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.Set; import javax.xml.namespace.QName; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.stream.StreamSource; import org.apache.ws.commons.schema.XmlSchema; import org.apache.ws.commons.schema.XmlSchemaCollection; import org.codice.ddf.spatial.ogc.catalog.common.AvailabilityTask; import org.codice.ddf.spatial.ogc.wfs.catalog.common.WfsException; import org.codice.ddf.spatial.ogc.wfs.catalog.common.WfsFeatureCollection; import org.codice.ddf.spatial.ogc.wfs.catalog.source.WfsUriResolver; import org.codice.ddf.spatial.ogc.wfs.v1_0_0.catalog.common.DescribeFeatureTypeRequest; import org.codice.ddf.spatial.ogc.wfs.v1_0_0.catalog.common.GetCapabilitiesRequest; import org.codice.ddf.spatial.ogc.wfs.v1_0_0.catalog.common.Wfs10Constants; import org.codice.ddf.spatial.ogc.wfs.v1_0_0.catalog.source.reader.FeatureCollectionMessageBodyReaderWfs10; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import org.opengis.filter.Filter; import org.osgi.framework.BundleContext; import ddf.catalog.data.ContentType; import ddf.catalog.data.Metacard; import ddf.catalog.data.Result; import ddf.catalog.data.impl.MetacardImpl; import ddf.catalog.filter.proxy.adapter.GeotoolsFilterAdapterImpl; import ddf.catalog.filter.proxy.builder.GeotoolsFilterBuilder; import ddf.catalog.operation.Query; 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.source.UnsupportedQueryException; import ogc.schema.opengis.filter.v_1_0_0.BinaryLogicOpType; import ogc.schema.opengis.filter.v_1_0_0.LogicOpsType; import ogc.schema.opengis.filter.v_1_0_0.PropertyIsLikeType; import ogc.schema.opengis.filter.v_1_0_0.SpatialOpsType; import ogc.schema.opengis.filter_capabilities.v_1_0_0.BBOX; import ogc.schema.opengis.filter_capabilities.v_1_0_0.FilterCapabilities; import ogc.schema.opengis.filter_capabilities.v_1_0_0.Intersect; import ogc.schema.opengis.filter_capabilities.v_1_0_0.SpatialCapabilitiesType; import ogc.schema.opengis.filter_capabilities.v_1_0_0.SpatialOperatorsType; import ogc.schema.opengis.wfs.v_1_0_0.GetFeatureType; import ogc.schema.opengis.wfs.v_1_0_0.QueryType; import ogc.schema.opengis.wfs_capabilities.v_1_0_0.FeatureTypeListType; import ogc.schema.opengis.wfs_capabilities.v_1_0_0.FeatureTypeType; import ogc.schema.opengis.wfs_capabilities.v_1_0_0.WFSCapabilitiesType; public class TestWfsSource { private static final String ONE_TEXT_PROPERTY_SCHEMA = "<?xml version=\"1.0\"?>" + "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">" + "<xs:element name=\"shiporder\">" + "<xs:complexType>" + "<xs:sequence>" + "<xs:element name=\"orderperson\" type=\"xs:string\"/>" + "</xs:sequence>" + "</xs:complexType>" + "</xs:element>" + "</xs:schema>"; private static final String TWO_TEXT_PROPERTY_SCHEMA = "<?xml version=\"1.0\"?>" + "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">" + "<xs:element name=\"shiporder\">" + "<xs:complexType>" + "<xs:sequence>" + "<xs:element name=\"orderperson\" type=\"xs:string\"/>" + "<xs:element name=\"orderdog\" type=\"xs:string\"/>" + "</xs:sequence>" + "</xs:complexType>" + "</xs:element>" + "</xs:schema>"; private static final String NO_PROPERTY_SCHEMA = "<?xml version=\"1.0\"?>" + "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\">" + "<xs:element name=\"shiporder\">" + "<xs:complexType>" + "<xs:sequence>" + "</xs:sequence>" + "</xs:complexType>" + "</xs:element>" + "</xs:schema>"; private static final String ONE_GML_PROPERTY_SCHEMA = "<?xml version=\"1.0\"?>" + "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" " + "xmlns:gml=\"http://www.opengis.net/gml\" " + "targetNamespace=\"http://www.opengis.net/gml\">" + "<xs:element name=\"shiporder\">" + "<xs:complexType>" + "<xs:sequence>" + "<xs:element name=\"orderperson\" type=\"gml:FakeGmlProperty\"/>" + "</xs:sequence>" + "</xs:complexType>" + "</xs:element>" + "<xs:complexType name=\"FakeGmlProperty\" />" + "</xs:schema>"; private static final String TWO_GML_PROPERTY_SCHEMA = "<?xml version=\"1.0\"?>" + "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" " + "xmlns:gml=\"http://www.opengis.net/gml\" " + "targetNamespace=\"http://www.opengis.net/gml\">" + "<xs:element name=\"shiporder\">" + "<xs:complexType>" + "<xs:sequence>" + "<xs:element name=\"orderperson\" type=\"gml:FakeGmlProperty\"/>" + "<xs:element name=\"orderdog\" type=\"gml:FakeGmlProperty\"/>" + "</xs:sequence>" + "</xs:complexType>" + "</xs:element>" + "<xs:complexType name=\"FakeGmlProperty\" />" + "</xs:schema>"; private static final String GML_IMPORT_SCHEMA = "<?xml version=\"1.0\"?>" + "<xs:schema xmlns:xs=\"http://www.w3.org/2001/XMLSchema\" " + "xmlns:gml=\"http://www.opengis.net/gml\" " + "targetNamespace=\"http://www.opengis.net/gml\">" + "<xs:import namespace=\"http://www.opengis.net/gml\" schemaLocation=\"http://schemas.opengis.net/gml/2.1.2/feature.xsd\"/>" + "<xs:element name=\"shiporder\">" + "<xs:complexType>" + "<xs:sequence>" + "<xs:element name=\"orderperson\" type=\"gml:FakeGmlProperty\"/>" + "</xs:sequence>" + "</xs:complexType>" + "</xs:element>" + "<xs:complexType name=\"FakeGmlProperty\" />" + "</xs:schema>"; private static final String POLYGON_WKT = "POLYGON ((30 10, 10 20, 20 40, 40 40, 30 10))"; private static final String ORDER_PERSON = "orderperson"; private static final String ORDER_DOG = "orderdog"; private static final Integer MAX_FEATURES = 10; private static final Integer ONE_FEATURE = 1; private static final Integer TWO_FEATURES = 2; private static final String SRS_NAME = "EPSG:4326"; private static final String LITERAL = "literal"; private static byte[] resultsByteArray; private static final Comparator<QueryType> QUERY_TYPE_COMPARATOR = new Comparator<QueryType>() { public int compare(QueryType queryType1, QueryType queryType2) { String typeName1 = queryType1.getTypeName().getLocalPart(); String typeName2 = queryType2.getTypeName().getLocalPart(); return typeName1.compareTo(typeName2); } }; private final GeotoolsFilterBuilder builder = new GeotoolsFilterBuilder(); private RemoteWfs mockWfs = mock(RemoteWfs.class); private WFSCapabilitiesType mockCapabilites = new WFSCapabilitiesType(); private WfsFeatureCollection mockFeatureCollection = mock(WfsFeatureCollection.class); private BundleContext mockContext = mock(BundleContext.class); private FeatureCollectionMessageBodyReaderWfs10 mockReader = mock( FeatureCollectionMessageBodyReaderWfs10.class); private List<QName> sampleFeatures; private WfsUriResolver wfsUriResolver = new WfsUriResolver(); private WfsSource source; private AvailabilityTask mockAvailabilityTask = mock(AvailabilityTask.class); public void setUp(final String schema, final List<Object> supportedGeos, final String srsName, final Integer numFeatures, final Integer numResults) throws WfsException { // GetCapabilities Response when(mockWfs.getCapabilities(any(GetCapabilitiesRequest.class))) .thenReturn(mockCapabilites); mockCapabilites.setFilterCapabilities(new FilterCapabilities()); mockCapabilites.getFilterCapabilities() .setSpatialCapabilities(new SpatialCapabilitiesType()); mockCapabilites.getFilterCapabilities().getSpatialCapabilities() .setSpatialOperators(new SpatialOperatorsType()); if (null != supportedGeos && !supportedGeos.isEmpty()) { mockCapabilites.getFilterCapabilities().getSpatialCapabilities().getSpatialOperators() .getBBOXOrEqualsOrDisjoint().addAll(supportedGeos); } // DescribeFeatureType Response XmlSchema xmlSchema = null; if (null != schema) { XmlSchemaCollection schemaCollection = new XmlSchemaCollection(); wfsUriResolver.setGmlNamespace(Wfs10Constants.GML_NAMESPACE); wfsUriResolver.setWfsNamespace(Wfs10Constants.WFS_NAMESPACE); schemaCollection.setSchemaResolver(wfsUriResolver); xmlSchema = schemaCollection .read(new StreamSource(new ByteArrayInputStream(schema.getBytes()))); } when(mockWfs.describeFeatureType(any(DescribeFeatureTypeRequest.class))) .thenReturn(xmlSchema); sampleFeatures = new ArrayList<QName>(); mockCapabilites.setFeatureTypeList(new FeatureTypeListType()); if (numFeatures != null) { for (int ii = 0; ii < numFeatures; ii++) { FeatureTypeType feature = new FeatureTypeType(); QName qName; if (ii == 0) { qName = new QName("SampleFeature" + ii); } else { qName = new QName("http://example.com", "SampleFeature" + ii, "Prefix" + ii); } sampleFeatures.add(qName); feature.setName(qName); // feature.setName(SAMPLE_FEATURE[ii]); if (null != srsName) { feature.setSRS(srsName); } mockCapabilites.getFeatureTypeList().getFeatureType().add(feature); } } when(mockWfs.getFeatureCollectionReader()).thenReturn(mockReader); // GetFeature Response when(mockWfs.getFeature(any(GetFeatureType.class))).thenReturn(mockFeatureCollection); when(mockFeatureCollection.getFeatureMembers()).thenAnswer(new Answer<List<Metacard>>() { @Override public List<Metacard> answer(InvocationOnMock invocation) { // Create as many metacards as there are features Integer resultsToReturn = numResults; if (resultsToReturn == null && numFeatures != null) { resultsToReturn = numFeatures; } List<Metacard> metacards = new ArrayList<Metacard>(resultsToReturn); for (int i = 0; i < resultsToReturn; i++) { MetacardImpl mc = new MetacardImpl(); mc.setId("ID_" + String.valueOf(i + 1)); metacards.add(mc); } return metacards; } }); when(mockAvailabilityTask.isAvailable()).thenReturn(true); source = new WfsSource(mockWfs, new GeotoolsFilterAdapterImpl(), mockContext, mockAvailabilityTask); } @Test public void testAvailability() throws WfsException { setUp(NO_PROPERTY_SCHEMA, null, null, ONE_FEATURE, null); assertTrue(source.isAvailable()); } @Test(expected = UnsupportedQueryException.class) public void testQueryEmptyQueryList() throws UnsupportedQueryException, WfsException { setUp(NO_PROPERTY_SCHEMA, null, null, ONE_FEATURE, null); QueryImpl propertyIsLikeQuery = new QueryImpl( builder.attribute(Metacard.ANY_TEXT).is().like().text(LITERAL)); propertyIsLikeQuery.setPageSize(MAX_FEATURES); source.query(new QueryRequestImpl(propertyIsLikeQuery)); } @Test public void testPropertyIsLikeQuery() throws UnsupportedQueryException, WfsException { setUp(ONE_TEXT_PROPERTY_SCHEMA, null, null, ONE_FEATURE, null); QueryImpl propertyIsLikeQuery = new QueryImpl( builder.attribute(Metacard.ANY_TEXT).is().like().text("literal")); propertyIsLikeQuery.setPageSize(MAX_FEATURES); ArgumentCaptor<GetFeatureType> captor = ArgumentCaptor.forClass(GetFeatureType.class); source.query(new QueryRequestImpl(propertyIsLikeQuery)); verify(mockWfs).getFeature(captor.capture()); GetFeatureType getFeatureType = captor.getValue(); assertMaxFeatures(getFeatureType, propertyIsLikeQuery); assertTrue(getFeatureType.getQuery().size() == ONE_FEATURE); QueryType query = getFeatureType.getQuery().get(0); assertTrue(query.getTypeName().equals(sampleFeatures.get(0))); assertTrue(query.getFilter().isSetComparisonOps()); assertTrue(query.getFilter().getComparisonOps().getValue() instanceof PropertyIsLikeType); } @Test public void testTwoPropertyQuery() throws UnsupportedQueryException, WfsException { setUp(TWO_TEXT_PROPERTY_SCHEMA, null, null, ONE_FEATURE, null); QueryImpl propertyIsLikeQuery = new QueryImpl( builder.attribute(Metacard.ANY_TEXT).is().like().text(LITERAL)); propertyIsLikeQuery.setPageSize(MAX_FEATURES); ArgumentCaptor<GetFeatureType> captor = ArgumentCaptor.forClass(GetFeatureType.class); source.query(new QueryRequestImpl(propertyIsLikeQuery)); verify(mockWfs).getFeature(captor.capture()); GetFeatureType getFeatureType = captor.getValue(); assertMaxFeatures(getFeatureType, propertyIsLikeQuery); assertTrue(getFeatureType.getQuery().size() == ONE_FEATURE); QueryType query = getFeatureType.getQuery().get(0); assertTrue(query.getTypeName().equals(sampleFeatures.get(0))); // The Text Properties should be ORed assertTrue(query.getFilter().isSetLogicOps()); assertTrue(query.getFilter().getLogicOps().getValue() instanceof BinaryLogicOpType); } @Test public void testContentTypeQuery() throws UnsupportedQueryException, WfsException { setUp(ONE_TEXT_PROPERTY_SCHEMA, null, null, ONE_FEATURE, null); Filter propertyIsLikeFilter = builder.attribute(Metacard.ANY_TEXT).is().like() .text(LITERAL); Filter contentTypeFilter = builder.attribute(Metacard.CONTENT_TYPE).is().like() .text(sampleFeatures.get(0) .getLocalPart()); // .text(SAMPLE_FEATURE[0].getLocalPart()); QueryImpl propertyIsLikeQuery = new QueryImpl( builder.allOf(propertyIsLikeFilter, contentTypeFilter)); propertyIsLikeQuery.setPageSize(MAX_FEATURES); ArgumentCaptor<GetFeatureType> captor = ArgumentCaptor.forClass(GetFeatureType.class); source.query(new QueryRequestImpl(propertyIsLikeQuery)); verify(mockWfs).getFeature(captor.capture()); GetFeatureType getFeatureType = captor.getValue(); assertMaxFeatures(getFeatureType, propertyIsLikeQuery); assertTrue(getFeatureType.getQuery().size() == ONE_FEATURE); QueryType query = getFeatureType.getQuery().get(0); assertTrue(query.getTypeName().equals(sampleFeatures.get(0))); // SAMPLE_FEATURE[0])); assertTrue(query.getFilter().isSetComparisonOps()); assertTrue(query.getFilter().getComparisonOps().getValue() instanceof PropertyIsLikeType); } @Test public void testContentTypeAndNoPropertyQuery() throws UnsupportedQueryException, WfsException { setUp(NO_PROPERTY_SCHEMA, null, null, ONE_FEATURE, null); Filter contentTypeFilter = builder.attribute(Metacard.CONTENT_TYPE).is().like() .text(sampleFeatures.get(0).getLocalPart()); QueryImpl propertyIsLikeQuery = new QueryImpl(contentTypeFilter); propertyIsLikeQuery.setPageSize(MAX_FEATURES); ArgumentCaptor<GetFeatureType> captor = ArgumentCaptor.forClass(GetFeatureType.class); source.query(new QueryRequestImpl(propertyIsLikeQuery)); verify(mockWfs).getFeature(captor.capture()); GetFeatureType getFeatureType = captor.getValue(); assertMaxFeatures(getFeatureType, propertyIsLikeQuery); assertEquals(ONE_FEATURE.intValue(), getFeatureType.getQuery().size()); assertEquals(sampleFeatures.get(0), getFeatureType.getQuery().get(0).getTypeName()); } @Test public void testTwoContentTypeAndNoPropertyQuery() throws UnsupportedQueryException, WfsException { setUp(NO_PROPERTY_SCHEMA, null, null, TWO_FEATURES, null); Filter contentTypeFilter = builder.attribute(Metacard.CONTENT_TYPE).is().like() .text(sampleFeatures.get(0).getLocalPart()); Filter contentTypeFilter2 = builder.attribute(Metacard.CONTENT_TYPE).is().like() .text(sampleFeatures.get(1).getLocalPart()); QueryImpl twoContentTypeQuery = new QueryImpl( builder.anyOf(Arrays.asList(contentTypeFilter, contentTypeFilter2))); twoContentTypeQuery.setPageSize(MAX_FEATURES); ArgumentCaptor<GetFeatureType> captor = ArgumentCaptor.forClass(GetFeatureType.class); source.query(new QueryRequestImpl(twoContentTypeQuery)); verify(mockWfs).getFeature(captor.capture()); GetFeatureType getFeatureType = captor.getValue(); assertMaxFeatures(getFeatureType, twoContentTypeQuery); Collections.sort(getFeatureType.getQuery(), QUERY_TYPE_COMPARATOR); assertEquals(TWO_FEATURES.intValue(), getFeatureType.getQuery().size()); assertEquals(sampleFeatures.get(0), getFeatureType.getQuery().get(0).getTypeName()); } @Test public void testAndQuery() throws UnsupportedQueryException, WfsException { setUp(ONE_TEXT_PROPERTY_SCHEMA, null, null, ONE_FEATURE, null); Filter propertyIsLikeFilter = builder.attribute(Metacard.ANY_TEXT).is().like() .text(LITERAL); Filter contentTypeFilter = builder.attribute(Metacard.ANY_TEXT).is().like() .text(sampleFeatures.get(0).getLocalPart()); QueryImpl propertyIsLikeQuery = new QueryImpl( builder.allOf(propertyIsLikeFilter, contentTypeFilter)); propertyIsLikeQuery.setPageSize(MAX_FEATURES); ArgumentCaptor<GetFeatureType> captor = ArgumentCaptor.forClass(GetFeatureType.class); source.query(new QueryRequestImpl(propertyIsLikeQuery)); verify(mockWfs).getFeature(captor.capture()); GetFeatureType getFeatureType = captor.getValue(); assertMaxFeatures(getFeatureType, propertyIsLikeQuery); assertTrue(getFeatureType.getQuery().size() == ONE_FEATURE); QueryType query = getFeatureType.getQuery().get(0); assertTrue(query.getTypeName().equals(sampleFeatures.get(0))); assertTrue(query.getFilter().isSetLogicOps()); assertTrue(query.getFilter().getLogicOps().getValue() instanceof BinaryLogicOpType); } @Test public void testIntersectQuery() throws UnsupportedQueryException, WfsException { setUp(ONE_GML_PROPERTY_SCHEMA, Arrays.asList(new Intersect(), new BBOX()), SRS_NAME, ONE_FEATURE, null); Filter intersectFilter = builder.attribute(Metacard.ANY_GEO).is().intersecting() .wkt(POLYGON_WKT); QueryImpl intersectQuery = new QueryImpl(intersectFilter); intersectQuery.setPageSize(MAX_FEATURES); ArgumentCaptor<GetFeatureType> captor = ArgumentCaptor.forClass(GetFeatureType.class); source.query(new QueryRequestImpl(intersectQuery)); verify(mockWfs).getFeature(captor.capture()); GetFeatureType getFeatureType = captor.getValue(); assertMaxFeatures(getFeatureType, intersectQuery); assertTrue(getFeatureType.getQuery().size() == ONE_FEATURE); QueryType query = getFeatureType.getQuery().get(0); assertTrue(query.getTypeName().equals(sampleFeatures.get(0))); assertTrue(query.getFilter().isSetSpatialOps()); assertTrue(query.getFilter().getSpatialOps().getValue() instanceof SpatialOpsType); } @Test public void testTwoIntersectQuery() throws UnsupportedQueryException, WfsException { setUp(TWO_GML_PROPERTY_SCHEMA, Arrays.asList(new Intersect(), new BBOX()), SRS_NAME, ONE_FEATURE, null); Filter intersectFilter = builder.attribute(Metacard.ANY_GEO).is().intersecting() .wkt(POLYGON_WKT); QueryImpl intersectQuery = new QueryImpl(intersectFilter); intersectQuery.setPageSize(MAX_FEATURES); ArgumentCaptor<GetFeatureType> captor = ArgumentCaptor.forClass(GetFeatureType.class); source.query(new QueryRequestImpl(intersectQuery)); verify(mockWfs).getFeature(captor.capture()); GetFeatureType getFeatureType = captor.getValue(); assertMaxFeatures(getFeatureType, intersectQuery); assertTrue(getFeatureType.getQuery().size() == ONE_FEATURE); QueryType query = getFeatureType.getQuery().get(0); assertTrue(query.getTypeName().equals(sampleFeatures.get(0))); // The Text Properties should be ORed assertNotNull(query.getFilter()); assertTrue(query.getFilter().isSetLogicOps()); assertTrue(query.getFilter().getLogicOps().getValue() instanceof LogicOpsType); } @Test public void testBboxQuery() throws UnsupportedQueryException, WfsException { List<Object> bbox = new ArrayList<Object>(); bbox.add(new BBOX()); setUp(ONE_GML_PROPERTY_SCHEMA, bbox, SRS_NAME, ONE_FEATURE, null); Filter intersectFilter = builder.attribute(Metacard.ANY_GEO).is().intersecting() .wkt(POLYGON_WKT); QueryImpl intersectQuery = new QueryImpl(intersectFilter); intersectQuery.setPageSize(MAX_FEATURES); ArgumentCaptor<GetFeatureType> captor = ArgumentCaptor.forClass(GetFeatureType.class); source.query(new QueryRequestImpl(intersectQuery)); verify(mockWfs).getFeature(captor.capture()); GetFeatureType getFeatureType = captor.getValue(); assertMaxFeatures(getFeatureType, intersectQuery); assertTrue(getFeatureType.getQuery().size() == ONE_FEATURE); QueryType query = getFeatureType.getQuery().get(0); assertTrue(query.getTypeName().equals(sampleFeatures.get(0))); assertTrue(query.getFilter().isSetSpatialOps()); assertTrue(query.getFilter().getSpatialOps().getValue() instanceof SpatialOpsType); } @Test public void testGmlImport() throws UnsupportedQueryException, WfsException { List<Object> bbox = new ArrayList<Object>(); bbox.add(new BBOX()); setUp(GML_IMPORT_SCHEMA, bbox, SRS_NAME, ONE_FEATURE, null); Filter intersectFilter = builder.attribute(Metacard.ANY_GEO).is().intersecting() .wkt(POLYGON_WKT); QueryImpl intersectQuery = new QueryImpl(intersectFilter); intersectQuery.setPageSize(MAX_FEATURES); ArgumentCaptor<GetFeatureType> captor = ArgumentCaptor.forClass(GetFeatureType.class); source.query(new QueryRequestImpl(intersectQuery)); verify(mockWfs).getFeature(captor.capture()); GetFeatureType getFeatureType = captor.getValue(); assertMaxFeatures(getFeatureType, intersectQuery); assertTrue(getFeatureType.getQuery().size() == ONE_FEATURE); QueryType query = getFeatureType.getQuery().get(0); assertTrue(query.getTypeName().equals(sampleFeatures.get(0))); assertTrue(query.getFilter().isSetSpatialOps()); assertTrue(query.getFilter().getSpatialOps().getValue() instanceof SpatialOpsType); } @Test(expected = UnsupportedQueryException.class) public void testNoGeoAttribuesQuery() throws UnsupportedQueryException, WfsException { setUp(NO_PROPERTY_SCHEMA, null, null, ONE_FEATURE, null); Filter intersectFilter = builder.attribute(Metacard.ANY_GEO).is().intersecting() .wkt(POLYGON_WKT); QueryImpl intersectQuery = new QueryImpl(intersectFilter); intersectQuery.setPageSize(MAX_FEATURES); source.query(new QueryRequestImpl(intersectQuery)); } @Test public void testTwoFeatureTypesQuery() throws UnsupportedQueryException, WfsException { setUp(ONE_TEXT_PROPERTY_SCHEMA, null, null, TWO_FEATURES, null); QueryImpl propertyIsLikeQuery = new QueryImpl( builder.attribute(Metacard.ANY_TEXT).is().like().text(LITERAL)); propertyIsLikeQuery.setPageSize(MAX_FEATURES); ArgumentCaptor<GetFeatureType> captor = ArgumentCaptor.forClass(GetFeatureType.class); source.query(new QueryRequestImpl(propertyIsLikeQuery)); verify(mockWfs).getFeature(captor.capture()); GetFeatureType getFeatureType = captor.getValue(); assertMaxFeatures(getFeatureType, propertyIsLikeQuery); assertTrue(getFeatureType.getQuery().size() == TWO_FEATURES); Collections.sort(getFeatureType.getQuery(), QUERY_TYPE_COMPARATOR); QueryType query = getFeatureType.getQuery().get(0); assertTrue(query.getTypeName().equals(sampleFeatures.get(0))); assertTrue(query.getFilter().isSetComparisonOps()); assertTrue(query.getFilter().getComparisonOps().getValue() instanceof PropertyIsLikeType); QueryType query2 = getFeatureType.getQuery().get(1); assertTrue(query2.getTypeName().equals(sampleFeatures.get(1))); assertTrue(query2.getFilter().isSetComparisonOps()); assertTrue(query2.getFilter().getComparisonOps().getValue() instanceof PropertyIsLikeType); } /** * Given 10 features (and metacards) exist that match search criteria, since page size=4 and * startIndex=1, should get 4 results back - metacards 1 thru 4. * * @throws WfsException * @throws TransformerConfigurationException * @throws UnsupportedQueryException */ @Test public void testPagingStartIndexOne() throws WfsException, TransformerConfigurationException, UnsupportedQueryException { int pageSize = 4; int startIndex = 1; setUp(ONE_TEXT_PROPERTY_SCHEMA, null, null, MAX_FEATURES, null); SourceResponse response = executeQuery(startIndex, pageSize); List<Result> results = response.getResults(); assertThat(results.size(), is(pageSize)); assertThat(response.getHits(), equalTo(new Long(MAX_FEATURES))); // Verify that metacards 1 thru 4 were returned since pageSize=4 assertCorrectMetacardsReturned(results, startIndex, pageSize); } /** * Given 10 features (and metacards) exist that match search criteria, since page size=4 and * startIndex=2, should get 4 results back - metacards 2 thru 5. * * @throws WfsException * @throws TransformerConfigurationException * @throws UnsupportedQueryException */ @Test public void testPagingStartIndexTwo() throws WfsException, TransformerConfigurationException, UnsupportedQueryException { int pageSize = 4; int startIndex = 2; setUp(ONE_TEXT_PROPERTY_SCHEMA, null, null, MAX_FEATURES, null); SourceResponse response = executeQuery(startIndex, pageSize); List<Result> results = response.getResults(); assertThat(results.size(), is(pageSize)); assertThat(response.getHits(), equalTo(new Long(MAX_FEATURES))); // Verify that metacards 2 thru 5 were returned since pageSize=4 assertCorrectMetacardsReturned(results, startIndex, pageSize); } /** * Given 2 features (and metacards) exist that match search criteria, since page size=4 and * startIndex=3, should get 0 results back and total hits of 2. * * @throws WfsException * @throws TransformerConfigurationException * @throws UnsupportedQueryException */ @Test public void testPagingStartIndexGreaterThanNumberOfFeatures() throws WfsException, TransformerConfigurationException, UnsupportedQueryException { int pageSize = 4; int startIndex = 3; int numFeatures = 2; setUp(ONE_TEXT_PROPERTY_SCHEMA, null, null, numFeatures, null); SourceResponse response = executeQuery(startIndex, pageSize); List<Result> results = response.getResults(); assertThat(results.size(), is(0)); assertThat(response.getHits(), equalTo(new Long(numFeatures))); } // Simulates query by ID (which is analogous to clicking on link in search // results to // view associated metacard in XML) @Test public void testPaging() throws WfsException, TransformerConfigurationException, UnsupportedQueryException { int pageSize = 4; int startIndex = 1; int numFeatures = 1; setUp(ONE_TEXT_PROPERTY_SCHEMA, null, null, numFeatures, null); SourceResponse response = executeQuery(startIndex, pageSize); List<Result> results = response.getResults(); assertThat(results.size(), is(1)); assertThat(response.getHits(), equalTo(new Long(numFeatures))); } /** * Given 10 features (and metacards) exist that match search criteria, since page size=20 (which * is larger than number of features) and startIndex=1, should get 10 results back - metacards 1 * thru 10. * * @throws WfsException * @throws TransformerConfigurationException * @throws UnsupportedQueryException */ @Test public void testPagingPageSizeExceedsFeatureCountStartIndexOne() throws WfsException, TransformerConfigurationException, UnsupportedQueryException { int pageSize = 20; int startIndex = 1; setUp(ONE_TEXT_PROPERTY_SCHEMA, null, null, MAX_FEATURES, null); SourceResponse response = executeQuery(startIndex, pageSize); List<Result> results = response.getResults(); assertThat(results.size(), is(MAX_FEATURES)); assertThat(response.getHits(), equalTo(new Long(MAX_FEATURES))); // Verify that metacards 1 thru 10 were returned assertCorrectMetacardsReturned(results, startIndex, MAX_FEATURES); } /** * Given 10 features (and metacards) exist that match search criteria, since page size=20 (which * is larger than number of features) and startIndex=2, should get 9 results back - metacards 2 * thru 10. * * @throws WfsException * @throws TransformerConfigurationException * @throws UnsupportedQueryException */ @Test public void testPagingPageSizeExceedsFeatureCountStartIndexTwo() throws WfsException, TransformerConfigurationException, UnsupportedQueryException { int pageSize = 20; int startIndex = 2; setUp(ONE_TEXT_PROPERTY_SCHEMA, null, null, MAX_FEATURES, null); SourceResponse response = executeQuery(startIndex, pageSize); List<Result> results = response.getResults(); assertThat(results.size(), is(MAX_FEATURES - 1)); assertThat(response.getHits(), equalTo(new Long(MAX_FEATURES))); // Verify that metacards 2 thru 10 were returned assertCorrectMetacardsReturned(results, startIndex, MAX_FEATURES - 1); } /** * Verify that, per DDF Query API Javadoc, if the startIndex is negative, the WfsSource throws * an UnsupportedQueryException. * * @throws WfsException * @throws TransformerConfigurationException * @throws UnsupportedQueryException */ @Test(expected = UnsupportedQueryException.class) public void testPagingStartIndexNegative() throws WfsException, TransformerConfigurationException, UnsupportedQueryException { int pageSize = 4; int startIndex = -1; setUp(ONE_TEXT_PROPERTY_SCHEMA, null, null, MAX_FEATURES, null); executeQuery(startIndex, pageSize); } /** * Verify that, per DDF Query API Javadoc, if the startIndex is zero, the WfsSource throws an * UnsupportedQueryException. * * @throws WfsException * @throws TransformerConfigurationException * @throws UnsupportedQueryException */ @Test(expected = UnsupportedQueryException.class) public void testPagingStartIndexZero() throws WfsException, TransformerConfigurationException, UnsupportedQueryException { int pageSize = 4; int startIndex = 0; setUp(ONE_TEXT_PROPERTY_SCHEMA, null, null, MAX_FEATURES, null); executeQuery(startIndex, pageSize); } /** * Verify that if page size is negative, WfsSource defaults it to the max features that can be * returned. * * @throws WfsException * @throws TransformerConfigurationException * @throws UnsupportedQueryException */ @Test public void testPagingPageSizeNegative() throws WfsException, TransformerConfigurationException, UnsupportedQueryException { int pageSize = -1; int startIndex = 1; int numResults = WfsSource.WFS_MAX_FEATURES_RETURNED + 10; setUp(ONE_TEXT_PROPERTY_SCHEMA, null, null, 1, numResults); SourceResponse response = executeQuery(startIndex, pageSize); List<Result> results = response.getResults(); assertThat(results.size(), is(WfsSource.WFS_MAX_FEATURES_RETURNED)); assertThat(response.getHits(), equalTo(new Long(numResults))); } /** * Verify that if page size is zero, WfsSource defaults it to the max features that can be * returned. * * @throws WfsException * @throws TransformerConfigurationException * @throws UnsupportedQueryException */ @Test public void testPagingPageSizeZero() throws WfsException, TransformerConfigurationException, UnsupportedQueryException { int pageSize = 0; int startIndex = 1; int numResults = WfsSource.WFS_MAX_FEATURES_RETURNED + 10; setUp(ONE_TEXT_PROPERTY_SCHEMA, null, null, 1, numResults); SourceResponse response = executeQuery(startIndex, pageSize); List<Result> results = response.getResults(); assertThat(results.size(), is(WfsSource.WFS_MAX_FEATURES_RETURNED)); assertThat(response.getHits(), equalTo(new Long(numResults))); } /** * Given 1010 features (and metacards) exist that match search criteria, since page size=1001 * (which is larger than max number of features the WfsSource allows to be returned) and * startIndex=1, should get 1000 results back, but a total hits of 1010. * * @throws WfsException * @throws TransformerConfigurationException * @throws UnsupportedQueryException */ @Test public void testPagingPageSizeExceedsMaxFeaturesThatCanBeReturned() throws WfsException, TransformerConfigurationException, UnsupportedQueryException { int pageSize = WfsSource.WFS_MAX_FEATURES_RETURNED + 1; int startIndex = 1; int numResults = WfsSource.WFS_MAX_FEATURES_RETURNED + 10; setUp(ONE_TEXT_PROPERTY_SCHEMA, null, null, 1, numResults); SourceResponse response = executeQuery(startIndex, pageSize); List<Result> results = response.getResults(); assertThat(results.size(), is(WfsSource.WFS_MAX_FEATURES_RETURNED)); assertThat(response.getHits(), equalTo(new Long(numResults))); } @Test public void testGetContentTypes() throws WfsException { setUp(ONE_TEXT_PROPERTY_SCHEMA, null, null, 2, null); Set<ContentType> contentTypes = source.getContentTypes(); assertTrue(contentTypes.size() == TWO_FEATURES); for (ContentType contentType : contentTypes) { assertTrue(sampleFeatures.get(0).getLocalPart().equals(contentType.getName()) || sampleFeatures.get(1).getLocalPart().equals(contentType.getName())); } } @Test public void testQueryTwoFeaturesOneInvalid() throws UnsupportedQueryException, WfsException { setUp(TWO_TEXT_PROPERTY_SCHEMA, null, null, TWO_FEATURES, null); Filter orderPersonFilter = builder.attribute(sampleFeatures.get(0) + "." + ORDER_PERSON) .is().like().text(LITERAL); Filter mctFeature1Fitler = builder.attribute(Metacard.CONTENT_TYPE).is().like() .text(sampleFeatures.get(0).getLocalPart()); Filter feature1Filter = builder.allOf(Arrays.asList(orderPersonFilter, mctFeature1Fitler)); Filter orderDogFilter = builder.attribute("FAKE").is().like().text(LITERAL); Filter mctFeature2Fitler = builder.attribute(Metacard.CONTENT_TYPE).is().like() .text(sampleFeatures.get(1).getLocalPart()); Filter feature2Filter = builder.allOf(Arrays.asList(orderDogFilter, mctFeature2Fitler)); Filter totalFilter = builder.anyOf(Arrays.asList(feature1Filter, feature2Filter)); QueryImpl inQuery = new QueryImpl(totalFilter); inQuery.setPageSize(MAX_FEATURES); ArgumentCaptor<GetFeatureType> captor = ArgumentCaptor.forClass(GetFeatureType.class); source.query(new QueryRequestImpl(inQuery)); verify(mockWfs).getFeature(captor.capture()); GetFeatureType getFeatureType = captor.getValue(); assertMaxFeatures(getFeatureType, inQuery); assertEquals(ONE_FEATURE.intValue(), getFeatureType.getQuery().size()); QueryType query = getFeatureType.getQuery().get(0); assertTrue(query.getTypeName().equals(sampleFeatures.get(0))); // The Text Properties should be ORed assertTrue(query.getFilter().isSetComparisonOps()); assertTrue(query.getFilter().getComparisonOps().getValue() instanceof PropertyIsLikeType); PropertyIsLikeType pilt = (PropertyIsLikeType) query.getFilter().getComparisonOps() .getValue(); assertEquals(ORDER_PERSON, pilt.getPropertyName().getContent()); } @Test public void testQueryTwoFeaturesWithMixedPropertyNames() throws UnsupportedQueryException, WfsException { setUp(TWO_TEXT_PROPERTY_SCHEMA, null, null, TWO_FEATURES, null); Filter orderPersonFilter = builder .attribute(sampleFeatures.get(0).getLocalPart() + "." + ORDER_PERSON).is().like() .text(LITERAL); Filter mctFeature1Fitler = builder.attribute(Metacard.CONTENT_TYPE).is().like() .text(sampleFeatures.get(0).getLocalPart()); Filter feature1Filter = builder.allOf(Arrays.asList(orderPersonFilter, mctFeature1Fitler)); Filter orderDogFilter = builder .attribute(sampleFeatures.get(1).getLocalPart() + "." + ORDER_DOG).is().like() .text(LITERAL); Filter mctFeature2Fitler = builder.attribute(Metacard.CONTENT_TYPE).is().like() .text(sampleFeatures.get(1).getLocalPart()); Filter feature2Filter = builder.allOf(Arrays.asList(orderDogFilter, mctFeature2Fitler)); Filter totalFilter = builder.anyOf(Arrays.asList(feature1Filter, feature2Filter)); QueryImpl inQuery = new QueryImpl(totalFilter); inQuery.setPageSize(MAX_FEATURES); ArgumentCaptor<GetFeatureType> captor = ArgumentCaptor.forClass(GetFeatureType.class); source.query(new QueryRequestImpl(inQuery)); verify(mockWfs).getFeature(captor.capture()); GetFeatureType getFeatureType = captor.getValue(); assertMaxFeatures(getFeatureType, inQuery); Collections.sort(getFeatureType.getQuery(), QUERY_TYPE_COMPARATOR); assertEquals(TWO_FEATURES.intValue(), getFeatureType.getQuery().size()); // Feature 1 QueryType query = getFeatureType.getQuery().get(0); assertThat(query.getTypeName(), equalTo(sampleFeatures.get(0))); // this should only have 1 filter which is a comparison assertTrue(query.getFilter().isSetComparisonOps()); assertTrue(query.getFilter().getComparisonOps().getValue() instanceof PropertyIsLikeType); PropertyIsLikeType pilt = (PropertyIsLikeType) query.getFilter().getComparisonOps() .getValue(); assertNotNull(pilt); assertEquals(ORDER_PERSON, pilt.getPropertyName().getContent()); // Feature 2 QueryType query2 = getFeatureType.getQuery().get(1); assertTrue(query2.getTypeName().equals(sampleFeatures.get(1))); // this should only have 1 filter which is a comparison assertTrue(query2.getFilter().isSetComparisonOps()); assertTrue(query2.getFilter().getComparisonOps().getValue() instanceof PropertyIsLikeType); PropertyIsLikeType pilt2 = (PropertyIsLikeType) query2.getFilter().getComparisonOps() .getValue(); assertEquals(ORDER_DOG, pilt2.getPropertyName().getContent()); } @Test public void testIDQuery() throws UnsupportedQueryException, WfsException { setUp(NO_PROPERTY_SCHEMA, null, null, TWO_FEATURES, null); QueryImpl idQuery = new QueryImpl(builder.attribute(Metacard.ID).is().text(ORDER_PERSON)); ArgumentCaptor<GetFeatureType> captor = ArgumentCaptor.forClass(GetFeatureType.class); source.query(new QueryRequestImpl(idQuery)); verify(mockWfs).getFeature(captor.capture()); GetFeatureType getFeatureType = captor.getValue(); assertEquals(ONE_FEATURE.intValue(), getFeatureType.getQuery().get(0).getFilter().getFeatureId().size()); assertEquals(ORDER_PERSON, getFeatureType.getQuery().get(0).getFilter().getFeatureId().get(0).getFid()); } @Test public void testTwoIDQuery() throws UnsupportedQueryException, WfsException { setUp(NO_PROPERTY_SCHEMA, null, null, TWO_FEATURES, null); Filter idFilter1 = builder.attribute(Metacard.ID).is().text(ORDER_PERSON); Filter idFilter2 = builder.attribute(Metacard.ID).is().text(ORDER_DOG); QueryImpl twoIDQuery = new QueryImpl(builder.anyOf(Arrays.asList(idFilter1, idFilter2))); ArgumentCaptor<GetFeatureType> captor = ArgumentCaptor.forClass(GetFeatureType.class); source.query(new QueryRequestImpl(twoIDQuery)); verify(mockWfs).getFeature(captor.capture()); GetFeatureType getFeatureType = captor.getValue(); assertEquals(TWO_FEATURES.intValue(), getFeatureType.getQuery().get(0).getFilter().getFeatureId().size()); assertTrue(ORDER_PERSON .equals(getFeatureType.getQuery().get(0).getFilter().getFeatureId().get(0).getFid()) || ORDER_PERSON .equals(getFeatureType.getQuery().get(0).getFilter().getFeatureId().get(1) .getFid())); assertTrue(ORDER_DOG .equals(getFeatureType.getQuery().get(0).getFilter().getFeatureId().get(0).getFid()) || ORDER_DOG .equals(getFeatureType.getQuery().get(0).getFilter().getFeatureId().get(1) .getFid())); } @Test(expected = UnsupportedQueryException.class) public void testOneIDOnePropertyQuery() throws UnsupportedQueryException, WfsException { setUp(ONE_TEXT_PROPERTY_SCHEMA, null, null, TWO_FEATURES, null); Filter idFilter = builder.attribute(Metacard.ID).is().text(ORDER_PERSON); Filter propertyIsLikeFilter = builder.attribute(Metacard.ANY_TEXT).is().like() .text(LITERAL); QueryImpl query = new QueryImpl( builder.anyOf(Arrays.asList(propertyIsLikeFilter, idFilter))); // we are verifying that mixing featureID filters with other filters is // not supported source.query(new QueryRequestImpl(query)); } @Test(expected = UnsupportedQueryException.class) public void testNoFeatures() throws UnsupportedQueryException, WfsException { setUp(ONE_TEXT_PROPERTY_SCHEMA, null, null, 0, null); QueryImpl propertyIsLikeQuery = new QueryImpl( builder.attribute(Metacard.ANY_TEXT).is().like().text("literal")); propertyIsLikeQuery.setPageSize(MAX_FEATURES); // when(mockWfs.getCapabilities(any(GetCapabilitiesRequest.class))).thenReturn(null); source.query(new QueryRequestImpl(propertyIsLikeQuery)); } @Test public void testTimeoutConfiguration() throws WfsException { setUp(ONE_TEXT_PROPERTY_SCHEMA, null, null, ONE_FEATURE, null); source.setConnectionTimeout(10000); source.setReceiveTimeout(10000); // Perform test source.updateTimeouts(); verify(mockWfs, atLeastOnce()).setTimeouts(any(Integer.class), any(Integer.class)); } private SourceResponse executeQuery(int startIndex, int pageSize) throws UnsupportedQueryException { Filter filter = builder.attribute(Metacard.ANY_TEXT).is().like().text(LITERAL); Query query = new QueryImpl(filter, startIndex, pageSize, null, false, 0); QueryRequest request = new QueryRequestImpl(query); SourceResponse response = source.query(request); return response; } private void assertMaxFeatures(GetFeatureType getFeatureType, Query inQuery) { int pageSize = (inQuery.getStartIndex() / MAX_FEATURES + 1) * inQuery.getPageSize() * WfsSource.WFS_QUERY_PAGE_SIZE_MULTIPLIER; assertTrue(getFeatureType.getMaxFeatures().equals(BigInteger.valueOf(pageSize))); } private void assertCorrectMetacardsReturned(List<Result> results, int startIndex, int expectedNumberOfMetacards) { for (int i = 0; i < expectedNumberOfMetacards; i++) { int id = startIndex + i; assertThat(results.get(i).getMetacard().getId(), equalTo("ID_" + String.valueOf(id))); } } }