/*
* This is eMonocot, a global online biodiversity information resource.
*
* Copyright © 2011–2015 The Board of Trustees of the Royal Botanic Gardens, Kew and The University of Oxford
*
* eMonocot is free software: you can redistribute it and/or modify it under the terms of the
* GNU Affero General Public License as published by the Free Software Foundation, either version 3
* of the License, or (at your option) any later version.
*
* eMonocot 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 Affero General Public License for more details.
*
* The complete text of the GNU Affero General Public License is in the source repository as the file
* ‘COPYING’. It is also available from <http://www.gnu.org/licenses/>.
*/
package org.emonocot.service.impl;
import static org.hamcrest.collection.IsArrayContaining.hasItemInArray;
import static org.hamcrest.collection.IsIterableContainingInAnyOrder.containsInAnyOrder;
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import org.apache.solr.client.solrj.response.FacetField;
import org.emonocot.api.AnnotationService;
import org.emonocot.api.ImageService;
import org.emonocot.api.OrganisationService;
import org.emonocot.api.PlaceService;
import org.emonocot.api.SearchableObjectService;
import org.emonocot.api.TaxonService;
import org.emonocot.api.UserService;
import org.emonocot.model.Annotation;
import org.emonocot.model.Image;
import org.emonocot.model.Place;
import org.emonocot.model.SearchableObject;
import org.emonocot.model.Taxon;
import org.emonocot.model.auth.User;
import org.emonocot.model.constants.Location;
import org.emonocot.model.registry.Organisation;
import org.emonocot.pager.Page;
import org.emonocot.test.DataManagementSupport;
import org.gbif.ecat.voc.Rank;
import org.gbif.ecat.voc.TaxonomicStatus;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.acls.domain.BasePermission;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
*
* @author ben
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration({"classpath*:META-INF/spring/applicationContext*.xml" })
public class FacetingTest extends DataManagementSupport {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private TaxonService taxonService;
@Autowired
private ImageService imageService;
@Autowired
private AnnotationService annotationService;
@Autowired
private OrganisationService sourceService;
@Autowired
private PlaceService placeService;
@Autowired
private SearchableObjectService searchableObjectService;
private User user;
private UsernamePasswordAuthenticationToken token;
/**
* @throws java.lang.Exception if there is a problem
*/
@Before
public final void setUp() throws Exception {
setUpTestData();
for (Object obj : getSetUp()) {
if (obj.getClass().equals(Taxon.class)) {
taxonService.saveOrUpdate((Taxon) obj);
} else if (obj.getClass().equals(Image.class)) {
imageService.saveOrUpdate((Image) obj);
} else if (obj.getClass().equals(Annotation.class)) {
annotationService.saveOrUpdate((Annotation) obj);
} else if (obj.getClass().equals(Organisation.class)) {
sourceService.saveOrUpdate((Organisation) obj);
} else if (obj.getClass().equals(Place.class)) {
placeService.saveOrUpdate((Place) obj);
}
}
token = new UsernamePasswordAuthenticationToken("admin@e-monocot.org", "sPePhAz6");
Authentication authentication = authenticationManager.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
SecurityContextHolder.clearContext();
}
/**
* @throws java.lang.Exception if there is a problem
*/
@After
public final void tearDown() throws Exception {
setSetUp(new ArrayList<Object>());
token = new UsernamePasswordAuthenticationToken("admin@e-monocot.org",
"sPePhAz6");
Authentication authentication = authenticationManager.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(authentication);
while (!getTearDown().isEmpty()) {
Object obj = getTearDown().pop();
if (obj.getClass().equals(Taxon.class)) {
taxonService.delete(((Taxon) obj).getIdentifier());
} else if (obj.getClass().equals(Image.class)) {
imageService.delete(((Image) obj).getIdentifier());
} else if (obj.getClass().equals(Annotation.class)) {
annotationService.delete(((Annotation) obj).getIdentifier());
} else if (obj.getClass().equals(Organisation.class)) {
sourceService.delete(((Organisation) obj).getIdentifier());
} else if (obj.getClass().equals(Place.class)) {
placeService.delete(((Place) obj).getIdentifier());
}
}
SecurityContextHolder.clearContext();
}
/**
*
*/
@Override
public final void setUpTestData() {
Organisation source1 = createSource("test", "http://example.com", "Test Organisation", "test@example.com");
Organisation source2 = createSource("source2", "http://source2.com", "Test Organisation 2", "test@example2.com");
Taxon taxon1 = createTaxon("Aus", "1", null, null, "Ausaceae", null,
null, "(1753)", Rank.GENUS, TaxonomicStatus.Accepted,
source1, new Location[] {}, new Organisation[] {source1});
Taxon taxon2 = createTaxon("Aus bus", "2", taxon1, null, "Ausaceae",
null, null, "(1775)", Rank.SPECIES, TaxonomicStatus.Accepted,
source1, new Location[] {Location.AUSTRALASIA,
Location.BRAZIL, Location.CARIBBEAN }, new Organisation[] {source1,source2});
Taxon taxon3 = createTaxon("Aus ceus", "3", taxon1, null, "Ausaceae",
null, null, "(1805)", Rank.SPECIES, TaxonomicStatus.Accepted,
source1, new Location[] {Location.NEW_ZEALAND }, new Organisation[] {source1,source2});
Taxon taxon4 = createTaxon("Aus deus", "4", null, taxon2, "Ausaceae",
null, null, "(1895)", Rank.SPECIES, TaxonomicStatus.Synonym,
source1, new Location[] {}, new Organisation[] {source1});
Taxon taxon5 = createTaxon("Aus eus", "5", null, taxon3, "Ausaceae",
null, null, "(1935)", Rank.SPECIES, TaxonomicStatus.Synonym,
source1, new Location[] {}, new Organisation[] {source1});
Image img1 = createImage("Aus", "1", source2,taxon2, new Organisation[] {source2,source1});
Image img2 = createImage("Aus bus", "2", source2,taxon2, new Organisation[] {source2,source1});
Place place1 = createPlace("gb", "Great Britain");
}
/**
*
*/
@Test
public final void testSearch() throws Exception {
Page<SearchableObject> pager = searchableObjectService.search("Aus",
null, null, null, null, null, null, null, null);
assertEquals("there should be seven objects saved", (Integer) 7,
pager.getSize());
}
/**
*
*/
@Test
public final void testSearchWithFacets() throws Exception {
Map<String, String> selectedFacets = new HashMap<String, String>();
selectedFacets.put("base.class_s", "org.emonocot.model.Taxon");
Page<SearchableObject> pager = searchableObjectService.search("Aus",
null, null, null, new String[] {"base.class_s",
"taxon.family_ss", "taxon.distribution_TDWG_0_ss",
"searchable.sources_ss" },
null, selectedFacets, null, null);
assertThat("There should be two facets returned",
pager.getFacetNames(), containsInAnyOrder("base.class_s",
"taxon.family_ss", "taxon.distribution_TDWG_0_ss",
"searchable.sources_ss"));
FacetField classFacet = pager.getFacetField("base.class_s");
String[] Strings = new String[classFacet.getValueCount()];
for (int i = 0; i < Strings.length; i++) {
Strings[i] = classFacet.getValues().get(i).getName();
}
assertThat("org.emonocot.model.Taxon should be a facet in CLASS",
Strings, hasItemInArray("org.emonocot.model.Taxon"));
assertEquals("There should be one value for the FAMILY facet", 1, pager
.getFacetField("taxon.family_ss").getValues().size());
}
/**
*
*/
@Test
public final void testSearchWithRegion() throws Exception {
Map<String, String> selectedFacets = new HashMap<String, String>();
selectedFacets.put("base.class_s", "org.emonocot.model.Taxon");
selectedFacets.put("taxon.distribution_TDWG_1_ss", "AUSTRALASIA_NEW_ZEALAND");
Page<SearchableObject> pager = searchableObjectService.search("Aus",
null, null, null, new String[] {"base.class_s",
"taxon.family_ss", "taxon.distribution_TDWG_0_ss",
"taxon.distribution_TDWG_1_ss", "searchable.sources_ss" },
null, selectedFacets, null, null);
assertThat("There should be two facets returned",
pager.getFacetNames(), containsInAnyOrder("base.class_s",
"taxon.family_ss", "taxon.distribution_TDWG_0_ss",
"taxon.distribution_TDWG_1_ss", "searchable.sources_ss"));
FacetField classFacet = pager.getFacetField("base.class_s");
String[] Strings = new String[classFacet.getValueCount()];
for (int i = 0; i < Strings.length; i++) {
Strings[i] = classFacet.getValues().get(i).getName();
}
assertThat("org.emonocot.model.Taxon should be a facet in CLASS",
Strings, hasItemInArray("org.emonocot.model.Taxon"));
assertEquals("There should be one value for the FAMILY facet", 1, pager
.getFacetField("taxon.family_ss").getValueCount());
}
/**
* @throws Exception
* if there is a problem tearing down and adding the test data
*/
@Test
public final void testSearchWithFacetsInTaxonDao() throws Exception {
Map<String, String> selectedFacets = new HashMap<String, String>();
selectedFacets.put("base.class_s", "org.emonocot.model.Taxon");
Page<SearchableObject> pager = searchableObjectService.search("Aus", null, null, null,
new String[] { "base.class_s", "taxon.family_ss",
"taxon.distribution_TDWG_0_ss", "searchable.sources_ss",
"taxon.taxon_rank_s", "taxon.taxonomic_status_s" },
null, selectedFacets, null, null);
assertEquals("There should be five taxa returned", (Integer) 5,
pager.getSize());
assertThat("There should be six facets returned",
pager.getFacetNames(), containsInAnyOrder("base.class_s", "taxon.family_ss",
"taxon.distribution_TDWG_0_ss", "searchable.sources_ss",
"taxon.taxon_rank_s", "taxon.taxonomic_status_s"));
FacetField classFacet = pager.getFacetField("base.class_s");
String[] Strings = new String[classFacet.getValueCount()];
for (int i = 0; i < Strings.length; i++) {
Strings[i] = classFacet.getValues().get(i).getName();
}
assertThat("org.emonocot.model.Taxon should be a facet in CLASS",
Strings, hasItemInArray("org.emonocot.model.Taxon"));
assertEquals("There should be one values for the FAMILY facet", 1, pager
.getFacetField("taxon.family_ss").getValueCount());
selectedFacets.put("taxon.taxon_rank_s", "SPECIES");
pager = searchableObjectService.search("Aus", null, null, null,
new String[] {"base.class_s", "taxon.family_ss",
"taxon.distribution_TDWG_0_ss", "searchable.sources_ss",
"taxon.taxon_rank_s", "taxon.taxonomic_status_s" },
null, selectedFacets, null, null);
assertEquals("There should be four taxa returned", (Integer) 4,
pager.getSize());
}
/**
*
*/
@Test
public final void testSearchWithSorting() throws Exception {
Page<SearchableObject> results = searchableObjectService.search("Au*",
null, null, null, null, null, null, null, null);
String sort = "searchable.label_sort_asc";
results = searchableObjectService.search("Au*", null, null, null, null,
null, null, sort, null);
String[] actual = new String[results.getSize()];
for (int i = 0; i < results.getSize(); i++) {
if (results.getRecords().get(i).getClassName().equals("Taxon")) {
actual[i] = ((Taxon) results.getRecords().get(i)).getScientificName();
} else {
actual[i] = ((Image) results.getRecords().get(i)).getTitle();
}
}
String[] expected = new String[] {"Aus", "Aus", "Aus bus", "Aus bus",
"Aus ceus", "Aus deus", "Aus eus" };
assertArrayEquals(expected, actual);
}
@Test
public final void testFacetOnSource() throws Exception {
Map<String, String> selectedFacets = new HashMap<String, String>();
Page<?> results = searchableObjectService.search(null,
null, null, null,
new String[] {"base.class_s", "taxon.family_ss", "taxon.distribution_TDWG_0_ss","searchable.sources_ss" },
null, null, null, null);
selectedFacets.clear();
selectedFacets.put("taxon.family_ss", "Ausaceae");
results = searchableObjectService.search(null,
null, null, null,
new String[] {"base.class_s", "taxon.family_ss", "taxon.distribution_TDWG_0_ss","searchable.sources_ss" },
null, selectedFacets, null, null);
selectedFacets.clear();
selectedFacets.put("taxon.family_ss", "Ausaceae");
selectedFacets.put("base.class_s", "org.emonocot.model.taxon.Taxon");
selectedFacets.put("searchable.sources_ss", "source2");
results = searchableObjectService.search(null,
null, null, null,
new String[] {"base.class_s","taxon.family_ss", "taxon.distribution_TDWG_0_ss","searchable.sources_ss"},
null, selectedFacets, null, null);
selectedFacets.clear();
selectedFacets.put("searchable.sources_ss", "source2");
results = searchableObjectService.search(null,
null, null, null,
new String[] {"base.class_s","taxon.family_ss", "taxon.distribution_TDWG_0_ss","searchable.sources_ss"},
null, selectedFacets, null, null);
}
/**
* BUG # 334 As a user of eMonocot I want to be able to perform a faceted search by place
*/
@Test
public final void testFacetOnPlace() throws Exception {
Map<String, String> selectedFacets = new HashMap<String, String>();
selectedFacets.put("base.class_s", "org.emonocot.model.Place");
Page<SearchableObject> places = searchableObjectService.search(null, null, 10, 0, new String[] {}, null, selectedFacets, null, null);
assertEquals("There should be one place in the result list",(Integer)places.getSize(),(Integer)1);
}
}