/** * Copyright (C) 2014 Cohesive Integrations, LLC (info@cohesiveintegrations.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.di2e.ecdr.libs.result.relevance; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.fail; import static org.mockito.Matchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.io.IOException; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import net.di2e.ecdr.libs.result.relevance.RelevanceNormalizer; import org.apache.commons.io.IOUtils; import org.junit.Test; import org.opengis.filter.Filter; import org.opengis.filter.expression.PropertyName; import org.opengis.filter.sort.SortOrder; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ddf.catalog.data.Result; import ddf.catalog.data.impl.MetacardImpl; import ddf.catalog.data.impl.ResultImpl; import ddf.catalog.filter.FilterAdapter; import ddf.catalog.filter.FilterDelegate; import ddf.catalog.filter.impl.PropertyNameImpl; import ddf.catalog.filter.impl.SortByImpl; import ddf.catalog.operation.QueryResponse; import ddf.catalog.operation.impl.QueryImpl; import ddf.catalog.operation.impl.QueryRequestImpl; import ddf.catalog.operation.impl.QueryResponseImpl; public class RelevanceNormalizerTest { private static final String SEARCH_KEY = "q"; private static final String EXAMPLE_PHRASE = "snow"; private static final String ID_1 = "metacard1"; private static final String ID_2 = "metacard2"; private static final String ID_3 = "metacard3"; private static final String XML_FILE1 = "example1.xml"; private static final String XML_FILE2 = "example2.xml"; private static final String XML_FILE3 = "example3.xml"; private static final double ORIG_SCORE1 = .225; private static final double ORIG_SCORE2 = .556; private static final double ORIG_SCORE3 = .121; private static final Logger LOGGER = LoggerFactory.getLogger( RelevanceNormalizerTest.class ); /** * Tests out that the scores of results are changed after the plugin is run. * * @throws Exception */ @Test public void testReindexScores() throws Exception { Result result1 = createResult( ID_1, XML_FILE1, ORIG_SCORE1 ); Result result2 = createResult( ID_2, XML_FILE2, ORIG_SCORE2 ); Result result3 = createResult( ID_3, XML_FILE3, ORIG_SCORE3 ); List<Result> results = Arrays.asList( result1, result2, result3 ); QueryResponse queryResponse = createResponse( new PropertyNameImpl( Result.RELEVANCE ), SortOrder.DESCENDING, results ); Map<String, String> paramMap = new HashMap<>(); paramMap.put( SEARCH_KEY, EXAMPLE_PHRASE ); FilterAdapter filterAdapter = createAdapter( paramMap ); RelevanceNormalizer resultNormalizer = new RelevanceNormalizer( filterAdapter ); List<Result> returnResponse = resultNormalizer.normalize( queryResponse.getResults(), queryResponse.getRequest().getQuery() ); assertNotSame( queryResponse.getResults(), returnResponse ); for ( Result curResult : returnResponse ) { if ( ID_1.equals( curResult.getMetacard().getId() ) ) { compareResults( result1, curResult ); } else if ( ID_2.equals( curResult.getMetacard().getId() ) ) { compareResults( result2, curResult ); } else if (ID_3.equals( curResult.getMetacard().getId() ) ) { compareResults( result3, curResult ); // should not have matched on search assertEquals(Double.valueOf( 0 ), curResult.getRelevanceScore()); } else { fail( "metacard IDs do not match original metacards." ); } } } /** * Verifies that the plugin is skipped when search phrase is not present * * @throws Exception */ @Test public void testNoPhraseSort() throws Exception { QueryResponse queryResponse = createResponse( new PropertyNameImpl( Result.RELEVANCE ), SortOrder.DESCENDING, Collections.<Result>emptyList() ); FilterAdapter filterAdapter = createAdapter( Collections.<String, String>emptyMap() ); RelevanceNormalizer resultNormalizer = new RelevanceNormalizer( filterAdapter ); List<Result> returnResponse = resultNormalizer.normalize( queryResponse.getResults(), queryResponse.getRequest().getQuery() ); assertEquals( queryResponse.getResults(), returnResponse ); } /** * Verifies that the plugin is skipped when the query has temporal sorting * * @throws Exception */ @Test public void testTemporalSort() throws Exception { QueryResponse queryResponse = createResponse( new PropertyNameImpl( Result.TEMPORAL ), SortOrder.ASCENDING, Collections.<Result>emptyList() ); Map<String, String> paramMap = new HashMap<>(); paramMap.put( SEARCH_KEY, EXAMPLE_PHRASE ); FilterAdapter filterAdapter = createAdapter( paramMap ); RelevanceNormalizer resultNormalizer = new RelevanceNormalizer( filterAdapter ); List<Result> returnResponse = resultNormalizer.normalize( queryResponse.getResults(), queryResponse.getRequest().getQuery() ); assertEquals( queryResponse.getResults(), returnResponse ); } /** * Verifies that the plugin is skipped when the query has distance sorting * * @throws Exception */ @Test public void testSpatialSort() throws Exception { QueryResponse queryResponse = createResponse( new PropertyNameImpl( Result.DISTANCE ), SortOrder.ASCENDING, Collections.<Result>emptyList() ); Map<String, String> paramMap = new HashMap<>(); paramMap.put( SEARCH_KEY, EXAMPLE_PHRASE ); FilterAdapter filterAdapter = createAdapter( paramMap ); RelevanceNormalizer resultNormalizer = new RelevanceNormalizer( filterAdapter ); List<Result> returnResponse = resultNormalizer.normalize( queryResponse.getResults(), queryResponse.getRequest().getQuery() ); assertEquals( queryResponse.getResults(), returnResponse ); } /** * Verifies that the plugin is skipped when there is no contextual criteria (search phrase). * * @throws Exception */ @Test public void testNoSearchPhrase() throws Exception { QueryResponse queryResponse = createResponse( new PropertyNameImpl( Result.DISTANCE ), SortOrder.ASCENDING, Collections.<Result>emptyList() ); FilterAdapter filterAdapter = createAdapter( Collections.<String, String>emptyMap() ); RelevanceNormalizer resultNormalizer = new RelevanceNormalizer( filterAdapter ); List<Result> returnResponse = resultNormalizer.normalize( queryResponse.getResults(), queryResponse.getRequest().getQuery() ); assertEquals( queryResponse.getResults(), returnResponse ); } /** * Creates a response with the given sortproperty and sortorder. * * @param sortProperty * @param sortOrder * @param resultList * @return * @throws Exception */ private QueryResponse createResponse( PropertyName sortProperty, SortOrder sortOrder, List<Result> resultList ) throws Exception { Filter filter = mock( Filter.class ); QueryImpl query = new QueryImpl( filter ); query.setSortBy( new SortByImpl( sortProperty, sortOrder ) ); QueryRequestImpl queryRequest = new QueryRequestImpl( query ); QueryResponseImpl queryResponse = new QueryResponseImpl( queryRequest, resultList, true, resultList.size() ); LOGGER.debug( "Created response." ); return queryResponse; } /** * Create an adapter that returns the given map when adapt is called. * * @param adapterMap * @return * @throws Exception */ private FilterAdapter createAdapter( Map<String, String> adapterMap ) throws Exception { FilterAdapter filterAdapter = mock( FilterAdapter.class ); when( filterAdapter.adapt( any( Filter.class ), any( FilterDelegate.class ) ) ).thenReturn( adapterMap ); return filterAdapter; } private Result createResult( String id, String xmlFile, double origScore ) throws IOException { MetacardImpl metacard = new MetacardImpl(); metacard.setId( id ); metacard.setMetadata( IOUtils.toString( getClass().getResourceAsStream( "/" + xmlFile ) ) ); ResultImpl result = new ResultImpl( metacard ); result.setRelevanceScore( origScore ); return result; } /** * Compares two results and asserts that only the relevance was changed. * * @param origResult * @param newResult */ private void compareResults( Result origResult, Result newResult ) { assertEquals( origResult.getMetacard(), newResult.getMetacard() ); assertNotSame( origResult.getRelevanceScore(), newResult.getRelevanceScore() ); } }