/** * 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.CoreMatchers.is; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.stub; import java.util.Arrays; import java.util.Calendar; import java.util.Date; import java.util.TimeZone; import org.apache.solr.client.solrj.SolrQuery; import org.junit.Test; import ddf.catalog.data.AttributeType.AttributeFormat; import ddf.catalog.data.Metacard; public class TestSolrFilterDelegate { private DynamicSchemaResolver mockResolver = mock(DynamicSchemaResolver.class); private SolrFilterDelegate toTest = new SolrFilterDelegate(mockResolver); @Test(expected = UnsupportedOperationException.class) public void intersectsWithNullWkt() { // given null WKT and a valid property name stub(mockResolver.getField("testProperty", AttributeFormat.GEOMETRY, false)) .toReturn("testProperty_geohash_index"); // when the delegate intersects toTest.intersects("testProperty", null); // then the operation is unsupported } @Test(expected = UnsupportedOperationException.class) public void intersectsWithNullPropertyName() { // given null property name // when the delegate intersects toTest.intersects(null, "wkt"); // then the operation is unsupported } @Test public void intersectsWithInvalidJtsWkt() { // given a geospatial property stub(mockResolver.getField("testProperty", AttributeFormat.GEOMETRY, false)) .toReturn("testProperty_geohash_index"); // when the delegate intersects on WKT not handled by JTS SolrQuery query = toTest.intersects("testProperty", "invalid JTS wkt"); // then return a valid Solr query using the given WKT assertThat(query.getQuery(), is("testProperty_geohash_index:\"Intersects(invalid JTS wkt)\"")); } @Test public void reservedSpecialCharactersIsEqual() { // given a text property stub(mockResolver.getField("testProperty", AttributeFormat.STRING, true)) .toReturn("testProperty_txt_index"); // when searching for exact reserved characters SolrQuery equalQuery = toTest .propertyIsEqualTo("testProperty", "+ - && || ! ( ) { } [ ] ^ \" ~ :", true); // then return escaped special characters in the query assertThat(equalQuery.getQuery(), is("testProperty_txt_index:\"\\+ \\- \\&& \\|| \\! \\( \\) \\{ \\} \\[ \\] \\^ \\\" \\~ \\:\"")); } @Test public void reservedSpecialCharactersIsLike() { // given a tokenized text property stub(mockResolver.getField("testProperty", AttributeFormat.STRING, false)) .toReturn("testProperty_txt_index"); stub(mockResolver.getCaseSensitiveField("testProperty_txt_index")) .toReturn("testProperty_txt_index_tokenized"); // when searching for like reserved characters SolrQuery likeQuery = toTest .propertyIsLike("testProperty", "+ - && || ! ( ) { } [ ] ^ \" ~ : \\*?", true); // then return escaped special characters in the query assertThat(likeQuery.getQuery(), is("testProperty_txt_index_tokenized:(\\+ \\- \\&& \\|| \\! \\( \\) \\{ \\} \\[ \\] \\^ \\\" \\~ \\: \\*?)")); } /* DDF-314: COmmented out until the ANY_TEXT functionality is added back in - then these tests can be activated. @Test public void testPropertyIsEqualTo_AnyText_CaseSensitive() { String expectedQuery = "any_text:\"mySearchPhrase\""; String searchPhrase = "mySearchPhrase"; boolean isCaseSensitive = true; SolrQuery equalToQuery = toTest.propertyIsEqualTo(Metacard.ANY_TEXT, searchPhrase, isCaseSensitive); assertThat(equalToQuery.getQuery(), is(expectedQuery)); } @Test(expected = UnsupportedOperationException.class) public void testPropertyIsEqualTo_AnyText_CaseInsensitive() { String searchPhrase = "mySearchPhrase"; boolean isCaseSensitive = false; toTest.propertyIsEqualTo(Metacard.ANY_TEXT, searchPhrase, isCaseSensitive); } @Test public void testPropertyIsFuzzy_AnyText() { String expectedQuery = "+any_text:mysearchphrase~ "; String searchPhrase = "mySearchPhrase"; SolrQuery fuzzyQuery = toTest.propertyIsFuzzy(Metacard.ANY_TEXT, searchPhrase); assertThat(fuzzyQuery.getQuery(), is(expectedQuery)); } @Test public void testPropertyIsLike_AnyText_CaseInsensitive() { String expectedQuery = "any_text:\"mySearchPhrase\""; String searchPhrase = "mySearchPhrase"; boolean isCaseSensitive = false; SolrQuery isLikeQuery = toTest.propertyIsLike(Metacard.ANY_TEXT, searchPhrase, isCaseSensitive); assertThat(isLikeQuery.getQuery(), is(expectedQuery)); } @Test public void testPropertyIsLike_AnyText_CaseSensitive() { String expectedQuery = "any_text_has_case:\"mySearchPhrase\""; String searchPhrase = "mySearchPhrase"; boolean isCaseSensitive = true; when(mockResolver.getCaseSensitiveField("any_text")).thenReturn( "any_text" + ddf.catalog.source.solr.SchemaFields.HAS_CASE); SolrQuery isLikeQuery = toTest.propertyIsLike(Metacard.ANY_TEXT, searchPhrase, isCaseSensitive); assertThat(isLikeQuery.getQuery(), is(expectedQuery)); } END OMIT per DDF-314*/ @Test public void testPropertyIsLikeWildcard() { String searchPhrase = "abc-123*"; String expectedQuery = SolrFilterDelegate.WHITESPACE_TOKENIZED_METADATA_FIELD + ":(abc\\-123*)"; boolean isCaseSensitive = false; SolrQuery isLikeQuery = toTest.propertyIsLike(Metacard.ANY_TEXT, searchPhrase, isCaseSensitive); assertThat(isLikeQuery.getQuery(), is(expectedQuery)); } @Test public void testPropertyIsLikeWildcardNoTokens() { String searchPhrase = "title*"; String expectedQuery = SolrFilterDelegate.WHITESPACE_TOKENIZED_METADATA_FIELD + ":(title*)"; boolean isCaseSensitive = false; SolrQuery isLikeQuery = toTest .propertyIsLike(Metacard.ANY_TEXT, searchPhrase, isCaseSensitive); assertThat(isLikeQuery.getQuery(), is(expectedQuery)); } @Test public void testPropertyIsLikeMultipleTermsWithWildcard() { String searchPhrase = "abc 123*"; String expectedQuery = SolrFilterDelegate.WHITESPACE_TOKENIZED_METADATA_FIELD + ":(abc 123*)"; SolrQuery isLikeQuery = toTest.propertyIsLike(Metacard.ANY_TEXT, searchPhrase, false); assertThat(isLikeQuery.getQuery(), is(expectedQuery)); } @Test public void testPropertyIsLikeCaseSensitiveWildcard() { String searchPhrase = "abc-123*"; String expectedQuery = SolrFilterDelegate.WHITESPACE_TOKENIZED_METADATA_FIELD + SchemaFields.HAS_CASE + ":(abc\\-123*)"; SolrQuery isLikeQuery = toTest.propertyIsLike(Metacard.ANY_TEXT, searchPhrase, true); assertThat(isLikeQuery.getQuery(), is(expectedQuery)); } @Test public void testTemporalBefore() { stub(mockResolver.getField("created", AttributeFormat.DATE, false)) .toReturn("created_date"); String expectedQuery = " created_date:[ * TO 1995-11-24T23:59:56.765Z } "; SolrQuery temporalQuery = toTest.before(Metacard.CREATED, getCannedTime()); assertThat(temporalQuery.getQuery(), is(expectedQuery)); } @Test public void testTemporalAfter() { stub(mockResolver.getField("created", AttributeFormat.DATE, false)) .toReturn("created_date"); String expectedQuery = " created_date:{ 1995-11-24T23:59:56.765Z TO * ] "; SolrQuery temporalQuery = toTest.after(Metacard.CREATED, getCannedTime()); assertThat(temporalQuery.getQuery(), is(expectedQuery)); } @Test public void testDatePropertyGreaterThan() { stub(mockResolver.getField("created", AttributeFormat.DATE, false)) .toReturn("created_date"); String expectedQuery = " created_date:{ 1995-11-24T23:59:56.765Z TO * ] "; SolrQuery temporalQuery = toTest.propertyIsGreaterThan(Metacard.CREATED, getCannedTime()); assertThat(temporalQuery.getQuery(), is(expectedQuery)); } @Test public void testDatePropertyGreaterThanOrEqualTo() { stub(mockResolver.getField("created", AttributeFormat.DATE, false)) .toReturn("created_date"); String expectedQuery = " created_date:[ 1995-11-24T23:59:56.765Z TO * ] "; SolrQuery temporalQuery = toTest .propertyIsGreaterThanOrEqualTo(Metacard.CREATED, getCannedTime()); assertThat(temporalQuery.getQuery(), is(expectedQuery)); } @Test public void testDatePropertyLessThan() { stub(mockResolver.getField("created", AttributeFormat.DATE, false)) .toReturn("created_date"); String expectedQuery = " created_date:[ * TO 1995-11-24T23:59:56.765Z } "; SolrQuery temporalQuery = toTest.propertyIsLessThan(Metacard.CREATED, getCannedTime()); assertThat(temporalQuery.getQuery(), is(expectedQuery)); } @Test public void testDatePropertyLessThanOrEqualTo() { stub(mockResolver.getField("created", AttributeFormat.DATE, false)) .toReturn("created_date"); String expectedQuery = " created_date:[ * TO 1995-11-24T23:59:56.765Z ] "; SolrQuery temporalQuery = toTest .propertyIsLessThanOrEqualTo(Metacard.CREATED, getCannedTime()); assertThat(temporalQuery.getQuery(), is(expectedQuery)); } @Test public void testDatePropertyIsBetween() { stub(mockResolver.getField("created", AttributeFormat.DATE, false)) .toReturn("created_date"); String expectedQuery = " created_date:[ 1995-11-24T23:59:56.765Z TO 1995-11-27T04:59:56.765Z ] "; SolrQuery temporalQuery = toTest.propertyIsBetween(Metacard.CREATED, getCannedTime(), getCannedTime(1995, Calendar.NOVEMBER, 27, 4)); assertThat(temporalQuery.getQuery(), is(expectedQuery)); } @Test public void testXpathExists() { String xpath = "//root/sub/@attribute"; String expectedQuery = "{!xpath}xpath:\"" + xpath + "\""; SolrQuery xpathQuery = toTest.xpathExists(xpath); assertThat(xpathQuery.getFilterQueries()[0], is(expectedQuery)); } @Test public void testXpathIsLike() { String xpath = "//root/sub/@attribute"; String expectedQuery = "{!xpath}xpath:\"" + xpath + "[contains(lower-case(.), 'example')]\""; SolrQuery xpathQuery = toTest.xpathIsLike(xpath, "example", false); assertThat(xpathQuery.getFilterQueries()[0], is(expectedQuery)); } @Test public void testXpathOR() { String xpath = "//root/sub/@attribute"; String expected1Query = "{!xpath}xpath:\"" + xpath + "[contains(lower-case(.), 'example1')]\""; SolrQuery xpath1Query = toTest.xpathIsLike(xpath, "example1", false); assertThat(xpath1Query.getFilterQueries()[0], is(expected1Query)); String expected2Query = "{!xpath}xpath:\"" + xpath + "[contains(lower-case(.), 'example2')]\""; SolrQuery xpath2Query = toTest.xpathIsLike(xpath, "example2", false); assertThat(xpath2Query.getFilterQueries()[0], is(expected2Query)); SolrQuery combinedQuery = toTest.or(Arrays.asList(xpath1Query, xpath2Query)); String combinedExpectedFilter = "{!xpath}xpath:\"(" + xpath + "[contains(lower-case(.), 'example1')] or " + xpath + "[contains(lower-case(.), 'example2')])\""; String expectedIndex = "{!xpath}(xpath_index:\"" + xpath + "[contains(lower-case(.), 'example1')]\") OR " + "(xpath_index:\"" + xpath + "[contains(lower-case(.), 'example2')]\")"; assertThat(combinedQuery.getFilterQueries().length, is(2)); assertThat(combinedQuery.getFilterQueries()[0], is(combinedExpectedFilter)); assertThat(combinedQuery.getFilterQueries()[1], is(expectedIndex)); } private Date getCannedTime() { return getCannedTime(1995, Calendar.NOVEMBER, 24, 23); } private Date getCannedTime(int year, int month, int day, int hour) { Calendar calendar = Calendar.getInstance(TimeZone.getTimeZone("UTC")); calendar.clear(); calendar.set(year, month, day, hour, 59, 56); calendar.set(Calendar.MILLISECOND, 765); return calendar.getTime(); } }