DS-3484: Added SOLR integration for the REST integration tests

This commit is contained in:
Tom Desair
2017-10-09 15:04:51 +02:00
parent 876d0e9a82
commit 9529e5634f
26 changed files with 1032 additions and 153 deletions

View File

@@ -506,6 +506,32 @@
<artifactId>mockito-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.dspace</groupId>
<artifactId>dspace-solr</artifactId>
<classifier>classes</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-icu</artifactId>
<version>${solr.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-smartcn</artifactId>
<version>${solr.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-stempel</artifactId>
<version>${solr.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.rometools</groupId>
<artifactId>rome-modules</artifactId>

View File

@@ -7,6 +7,29 @@
*/
package org.dspace.discovery;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TimeZone;
import java.util.UUID;
import java.util.Vector;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.collections.Transformer;
@@ -14,14 +37,12 @@ import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.commons.validator.routines.UrlValidator;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.log4j.Logger;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrServer;
import org.apache.solr.client.solrj.request.AbstractUpdateRequest;
@@ -32,11 +53,23 @@ import org.apache.solr.client.solrj.util.ClientUtils;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.*;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.FacetParams;
import org.apache.solr.common.params.HighlightParams;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.MoreLikeThisParams;
import org.apache.solr.common.params.SpellingParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.handler.extraction.ExtractingParams;
import org.dspace.content.*;
import org.dspace.authorize.ResourcePolicy;
import org.dspace.authorize.factory.AuthorizeServiceFactory;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.MetadataField;
import org.dspace.content.MetadataSchema;
import org.dspace.content.MetadataValue;
import org.dspace.content.authority.Choices;
import org.dspace.content.authority.service.ChoiceAuthorityService;
import org.dspace.content.authority.service.MetadataAuthorityService;
@@ -44,8 +77,25 @@ import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CollectionService;
import org.dspace.content.service.CommunityService;
import org.dspace.content.service.ItemService;
import org.dspace.core.*;
import org.dspace.discovery.configuration.*;
import org.dspace.core.ConfigurationManager;
import org.dspace.core.Constants;
import org.dspace.core.Context;
import org.dspace.core.Email;
import org.dspace.core.I18nUtil;
import org.dspace.core.LogManager;
import org.dspace.discovery.configuration.DiscoveryConfiguration;
import org.dspace.discovery.configuration.DiscoveryConfigurationParameters;
import org.dspace.discovery.configuration.DiscoveryHitHighlightFieldConfiguration;
import org.dspace.discovery.configuration.DiscoveryHitHighlightingConfiguration;
import org.dspace.discovery.configuration.DiscoveryMoreLikeThisConfiguration;
import org.dspace.discovery.configuration.DiscoveryRecentSubmissionsConfiguration;
import org.dspace.discovery.configuration.DiscoverySearchFilter;
import org.dspace.discovery.configuration.DiscoverySearchFilterFacet;
import org.dspace.discovery.configuration.DiscoverySortConfiguration;
import org.dspace.discovery.configuration.DiscoverySortFieldConfiguration;
import org.dspace.discovery.configuration.HierarchicalSidebarFacetConfiguration;
import org.dspace.eperson.Group;
import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.handle.service.HandleService;
import org.dspace.services.factory.DSpaceServicesFactory;
import org.dspace.storage.rdbms.DatabaseUtils;
@@ -53,21 +103,6 @@ import org.dspace.util.MultiFormatDateParser;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.net.URI;
import java.net.URISyntaxException;
import java.sql.SQLException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import org.dspace.authorize.ResourcePolicy;
import org.dspace.authorize.factory.AuthorizeServiceFactory;
import org.dspace.eperson.Group;
import org.dspace.eperson.factory.EPersonServiceFactory;
/**
* SolrIndexer contains the methods that index Items and their metadata,
* collections, communities, etc. It is meant to either be invoked from the
@@ -122,9 +157,9 @@ public class SolrServiceImpl implements SearchService, IndexingService {
protected MetadataAuthorityService metadataAuthorityService;
/**
* Non-Static CommonsHttpSolrServer for processing indexing events.
* Non-Static SolrServer for processing indexing events.
*/
private HttpSolrServer solr = null;
protected SolrServer solr = null;
protected SolrServiceImpl()
@@ -132,7 +167,7 @@ public class SolrServiceImpl implements SearchService, IndexingService {
}
protected HttpSolrServer getSolr()
protected SolrServer getSolr()
{
if ( solr == null)
{
@@ -143,10 +178,10 @@ public class SolrServiceImpl implements SearchService, IndexingService {
{
try {
log.debug("Solr URL: " + solrService);
solr = new HttpSolrServer(solrService);
HttpSolrServer solrServer = new HttpSolrServer(solrService);
solr.setBaseURL(solrService);
solr.setUseMultiPartPost(true);
solrServer.setBaseURL(solrService);
solrServer.setUseMultiPartPost(true);
// Dummy/test query to search for Item (type=2) of ID=1
SolrQuery solrQuery = new SolrQuery()
.setQuery(RESOURCE_TYPE_FIELD + ":2 AND " + RESOURCE_ID_FIELD + ":1");
@@ -157,6 +192,8 @@ public class SolrServiceImpl implements SearchService, IndexingService {
// As long as Solr initialized, check with DatabaseUtils to see
// if a reindex is in order. If so, reindex everything
DatabaseUtils.checkReindexDiscovery(this);
solr = solrServer;
} catch (SolrServerException e) {
log.error("Error while initializing solr server", e);
}
@@ -1797,7 +1834,7 @@ public class SolrServiceImpl implements SearchService, IndexingService {
@Override
public InputStream searchJSON(Context context, DiscoverQuery discoveryQuery, String jsonIdentifier) throws SearchServiceException {
if (getSolr() == null)
if (getSolr() == null || !(getSolr() instanceof HttpSolrServer))
{
return null;
}
@@ -1809,7 +1846,7 @@ public class SolrServiceImpl implements SearchService, IndexingService {
solrQuery.setParam(CommonParams.WT, "json");
StringBuilder urlBuilder = new StringBuilder();
urlBuilder.append(getSolr().getBaseURL()).append("/select?");
urlBuilder.append(((HttpSolrServer) getSolr()).getBaseURL()).append("/select?");
urlBuilder.append(solrQuery.toString());
try {
@@ -1988,38 +2025,6 @@ public class SolrServiceImpl implements SearchService, IndexingService {
return null;
}
/**
* Simple means to return the search result as an InputStream
*
* @param query discovery query
* @return input stream
* @throws IOException
* A general class of exceptions produced by failed or interrupted I/O operations.
* @throws SearchServiceException if something went wrong with querying the solr server
*/
public java.io.InputStream searchAsInputStream(DiscoverQuery query) throws SearchServiceException, java.io.IOException {
if (getSolr() == null)
{
return null;
}
HttpHost hostURL = (HttpHost)(getSolr().getHttpClient().getParams().getParameter(ClientPNames.DEFAULT_HOST));
HttpGet method = new HttpGet(hostURL.toHostString() + "");
try
{
URI uri = new URIBuilder(method.getURI()).addParameter("q",query.toString()).build();
}
catch (URISyntaxException e)
{
throw new SearchServiceException(e);
}
HttpResponse response = getSolr().getHttpClient().execute(method);
return response.getEntity().getContent();
}
public List<DSpaceObject> search(Context context, String query, int offset, int max, String... filterquery)
{
return search(context, query, null, true, offset, max, filterquery);

View File

@@ -7,6 +7,32 @@
*/
package org.dspace.statistics;
import java.io.File;
import java.io.FileFilter;
import java.io.FileNotFoundException;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.EnumSet;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import au.com.bytecode.opencsv.CSVReader;
import au.com.bytecode.opencsv.CSVWriter;
import com.maxmind.geoip.Location;
@@ -20,6 +46,7 @@ import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.log4j.Logger;
import org.apache.solr.client.solrj.SolrQuery;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.impl.HttpSolrServer;
import org.apache.solr.client.solrj.request.AbstractUpdateRequest;
@@ -36,9 +63,18 @@ import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.luke.FieldFlag;
import org.apache.solr.common.params.*;
import org.dspace.content.*;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.FacetParams;
import org.apache.solr.common.params.MapSolrParams;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.ShardParams;
import org.dspace.content.Bitstream;
import org.dspace.content.Bundle;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.DCDate;
import org.dspace.content.DSpaceObject;
import org.dspace.content.Item;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.BitstreamService;
import org.dspace.content.service.DSpaceObjectLegacySupportService;
@@ -55,15 +91,6 @@ import org.dspace.usage.UsageWorkflowEvent;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import javax.servlet.http.HttpServletRequest;
import java.io.*;
import java.net.URLEncoder;
import java.sql.SQLException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* Static holder for a HttpSolrClient connection pool to issue
* usage logging events to Solr from DSpace libraries, and some static query
@@ -77,7 +104,7 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea
{
private static final Logger log = Logger.getLogger(SolrLoggerServiceImpl.class);
private static final String MULTIPLE_VALUES_SPLITTER = "|";
protected HttpSolrServer solr;
protected SolrServer solr;
public static final String DATE_FORMAT_8601 = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
@@ -1183,6 +1210,10 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea
@Override
public void shardSolrIndex() throws IOException, SolrServerException {
if(!(solr instanceof HttpSolrServer)) {
return;
}
/*
Start by faceting by year so we can include each year in a separate core !
*/
@@ -1243,14 +1274,14 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea
//Start by creating a new core
String coreName = "statistics-" + dcStart.getYearUTC();
HttpSolrServer statisticsYearServer = createCore(solr, coreName);
HttpSolrServer statisticsYearServer = createCore((HttpSolrServer) solr, coreName);
System.out.println("Moving: " + totalRecords + " into core " + coreName);
log.info("Moving: " + totalRecords + " records into core " + coreName);
List<File> filesToUpload = new ArrayList<File>();
for (int i = 0; i < totalRecords; i+=10000) {
String solrRequestUrl = solr.getBaseURL() + "/select";
String solrRequestUrl = ((HttpSolrServer) solr).getBaseURL() + "/select";
solrRequestUrl = generateURL(solrRequestUrl, yearQueryParams);
HttpGet get = new HttpGet(solrRequestUrl);
@@ -1356,6 +1387,10 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea
@Override
public void reindexBitstreamHits(boolean removeDeletedBitstreams) throws Exception {
if(!(solr instanceof HttpSolrServer)) {
return;
}
Context context = new Context();
try {
@@ -1380,7 +1415,7 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea
params.put(CommonParams.ROWS, String.valueOf(10000));
params.put(CommonParams.START, String.valueOf(i));
String solrRequestUrl = solr.getBaseURL() + "/select";
String solrRequestUrl = ((HttpSolrServer) solr).getBaseURL() + "/select";
solrRequestUrl = generateURL(solrRequestUrl, params);
HttpGet get = new HttpGet(solrRequestUrl);
@@ -1587,7 +1622,7 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea
* This code is synchonized in the event that 2 threads trigger the initialization at the same time.
*/
protected synchronized void initSolrYearCores() {
if (statisticYearCoresInit) {
if (statisticYearCoresInit || !(solr instanceof HttpSolrServer)) {
return;
}
try
@@ -1603,16 +1638,16 @@ public class SolrLoggerServiceImpl implements SolrLoggerService, InitializingBea
}
});
//Base url should like : http://localhost:{port.number}/solr
String baseSolrUrl = solr.getBaseURL().replace("statistics", "");
String baseSolrUrl = ((HttpSolrServer) solr).getBaseURL().replace("statistics", "");
for (File solrCoreFile : solrCoreFiles) {
log.info("Loading core with name: " + solrCoreFile.getName());
createCore(solr, solrCoreFile.getName());
createCore((HttpSolrServer) solr, solrCoreFile.getName());
//Add it to our cores list so we can query it !
statisticYearCores.add(baseSolrUrl.replace("http://", "").replace("https://", "") + solrCoreFile.getName());
}
//Also add the core containing the current year !
statisticYearCores.add(solr.getBaseURL().replace("http://", "").replace("https://", ""));
statisticYearCores.add(((HttpSolrServer) solr).getBaseURL().replace("http://", "").replace("https://", ""));
} catch (Exception e) {
log.error(e.getMessage(), e);
}

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-3.0.xsd"
default-autowire-candidates="*Service,*DAO,javax.sql.DataSource">
<context:annotation-config /> <!-- allows us to use spring annotations in beans -->
<!-- Run an internal SOLR server for the Discovery search service -->
<bean class="org.dspace.discovery.MockSolrServiceImpl" id="org.dspace.discovery.SearchService"/>
<!-- Run an internal SOLR server for the statistics service -->
<bean class="org.dspace.statistics.MockSolrLoggerServiceImpl" id="solrLoggerService" lazy-init="true"/>
</beans>

View File

@@ -0,0 +1,31 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.discovery;
import org.dspace.solr.MockSolrServer;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;
/**
* Mock SOLR service for the Search Core
*/
@Service
public class MockSolrServiceImpl extends SolrServiceImpl implements InitializingBean, DisposableBean {
private MockSolrServer mockSolrServer;
public void afterPropertiesSet() throws Exception {
mockSolrServer = new MockSolrServer("search");
solr = mockSolrServer.getSolrServer();
}
public void destroy() throws Exception {
mockSolrServer.destroy();
}
}

View File

@@ -0,0 +1,57 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.solr;
import java.io.File;
import java.io.IOException;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.embedded.EmbeddedSolrServer;
import org.apache.solr.core.CoreContainer;
/**
* Abstract class to mock a service that uses SOLR
*/
public class MockSolrServer {
private String coreName;
private SolrServer solrServer = null;
public MockSolrServer(final String coreName) throws Exception {
this.coreName = coreName;
initSolrServer();
}
public SolrServer getSolrServer() {
return solrServer;
}
protected void initSolrServer() throws Exception {
CoreContainer container = new CoreContainer(System.getProperty("dspace.dir") + File.separator + "solr");
container.load();
solrServer = new EmbeddedSolrServer(container, coreName);
//Start with an empty index
try {
solrServer.deleteByQuery("*:*");
solrServer.commit();
} catch (SolrServerException | IOException e) {
e.printStackTrace();
}
}
public void destroy() throws Exception {
if(solrServer != null) {
solrServer.shutdown();
}
}
}

View File

@@ -0,0 +1,42 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.statistics;
import java.io.File;
import java.io.IOException;
import com.maxmind.geoip.Location;
import com.maxmind.geoip.LookupService;
/**
* Mock service to mock the location Lookup Service used by the SOLR statistics logger
*/
public class MockLookupService extends LookupService {
public MockLookupService() throws IOException {
//Just give our super class a file so that he's happy. We'll mock all responses anyway.
super(System.getProperty("dspace.dir") + File.separator + "config" + File.separator + "dspace.cfg");
}
@Override
public Location getLocation(String str) {
Location location = new Location();
location.countryCode = "US";
location.countryName = "United States";
location.region = "NY";
location.city = "New York";
location.postalCode = "10036";
location.latitude = 40.760498F;
location.longitude = -73.9933F;
location.dma_code = 501;
location.area_code = 212;
location.metro_code = 501;
return location;
}
}

View File

@@ -0,0 +1,38 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.statistics;
import org.dspace.services.ConfigurationService;
import org.dspace.solr.MockSolrServer;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Mock service that uses an embedded SOLR server for the statistics core
*/
public class MockSolrLoggerServiceImpl extends SolrLoggerServiceImpl implements InitializingBean, DisposableBean {
private MockSolrServer mockSolrServer;
@Autowired(required = true)
private ConfigurationService configurationService;
@Override
public void afterPropertiesSet() throws Exception {
mockSolrServer = new MockSolrServer("statistics");
solr = mockSolrServer.getSolrServer();
locationService = new MockLookupService();
useProxies = configurationService.getBooleanProperty("useProxies");
}
public void destroy() throws Exception {
mockSolrServer.destroy();
}
}

View File

@@ -15,7 +15,7 @@ import org.dspace.services.ConfigurationService;
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public interface DSpaceKernel {
public interface DSpaceKernel extends CommonLifecycle<DSpaceKernel> {
public static final String KERNEL_NAME = "Kernel";
public static final String MBEAN_PREFIX = "org.dspace:name=";

View File

@@ -24,7 +24,6 @@ import javax.management.modelmbean.ModelMBeanAttributeInfo;
import javax.management.modelmbean.ModelMBeanInfoSupport;
import javax.management.modelmbean.ModelMBeanOperationInfo;
import org.dspace.kernel.CommonLifecycle;
import org.dspace.kernel.DSpaceKernel;
import org.dspace.kernel.DSpaceKernelManager;
import org.dspace.kernel.ServiceManager;
@@ -50,7 +49,7 @@ import org.slf4j.LoggerFactory;
*
* @author Aaron Zeckoski (azeckoski @ gmail.com)
*/
public final class DSpaceKernelImpl implements DSpaceKernel, DynamicMBean, CommonLifecycle<DSpaceKernel> {
public final class DSpaceKernelImpl implements DSpaceKernel, DynamicMBean {
private static Logger log = LoggerFactory.getLogger(DSpaceKernelImpl.class);
@@ -197,6 +196,7 @@ public final class DSpaceKernelImpl implements DSpaceKernel, DynamicMBean, Commo
/* (non-Javadoc)
* @see org.dspace.kernel.CommonLifecycle#destroy()
*/
@Override
public void destroy() {
if (this.destroyed) {
return;

View File

@@ -289,6 +289,30 @@
<artifactId>json-path-assert</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.dspace</groupId>
<artifactId>dspace-solr</artifactId>
<classifier>classes</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-icu</artifactId>
<version>${solr.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-smartcn</artifactId>
<version>${solr.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-stempel</artifactId>
<version>${solr.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

View File

@@ -19,6 +19,7 @@ import org.dspace.app.rest.filter.DSpaceRequestContextFilter;
import org.dspace.app.rest.model.hateoas.DSpaceRelProvider;
import org.dspace.app.rest.utils.ApplicationConfig;
import org.dspace.app.util.DSpaceContextListener;
import org.dspace.kernel.DSpaceKernel;
import org.dspace.kernel.DSpaceKernelManager;
import org.dspace.servicemanager.DSpaceKernelImpl;
import org.dspace.servicemanager.DSpaceKernelInit;
@@ -87,7 +88,7 @@ public class Application extends SpringBootServletInitializer {
public ServletContextInitializer contextInitializer() {
return new ServletContextInitializer() {
private transient DSpaceKernelImpl kernelImpl;
private transient DSpaceKernel dspaceKernel;
@Override
public void onStartup(ServletContext servletContext)
@@ -95,22 +96,23 @@ public class Application extends SpringBootServletInitializer {
servletContext.setInitParameter("dspace.dir", configuration.getDspaceHome());
// start the kernel when the webapp starts
if (DSpaceKernelManager.getDefaultKernel() == null) {
this.dspaceKernel = DSpaceKernelManager.getDefaultKernel();
if (this.dspaceKernel == null) {
DSpaceKernelImpl kernelImpl = null;
try {
this.kernelImpl = DSpaceKernelInit.getKernel(null);
if (!this.kernelImpl.isRunning()) {
this.kernelImpl.start(getProvidedHome(configuration.getDspaceHome())); // init the kernel
kernelImpl = DSpaceKernelInit.getKernel(null);
if (!kernelImpl.isRunning()) {
kernelImpl.start(getProvidedHome(configuration.getDspaceHome())); // init the kernel
}
//Set the DSpace Kernel Application context as a parent of the Spring Boot context so that
//we can auto-wire all DSpace Kernel services
springBootApplicationContext.setParent(kernelImpl.getServiceManager().getApplicationContext());
this.dspaceKernel = kernelImpl;
//Add a listener for Spring Boot application shutdown so that we can nicely cleanup the DSpace kernel.
springBootApplicationContext.addApplicationListener(new DSpaceKernelDestroyer(kernelImpl));
} catch (Exception e) {
// failed to start so destroy it and log and throw an exception
try {
this.kernelImpl.destroy();
if(kernelImpl != null) {
kernelImpl.destroy();
}
this.dspaceKernel = null;
} catch (Exception e1) {
// nothing
}
@@ -119,6 +121,15 @@ public class Application extends SpringBootServletInitializer {
throw new RuntimeException(message, e);
}
}
if(springBootApplicationContext.getParent() == null) {
//Set the DSpace Kernel Application context as a parent of the Spring Boot context so that
//we can auto-wire all DSpace Kernel services
springBootApplicationContext.setParent(dspaceKernel.getServiceManager().getApplicationContext());
//Add a listener for Spring Boot application shutdown so that we can nicely cleanup the DSpace kernel.
springBootApplicationContext.addApplicationListener(new DSpaceKernelDestroyer(dspaceKernel));
}
}
/**
@@ -208,16 +219,16 @@ public class Application extends SpringBootServletInitializer {
/** Utility class that will destory the DSpace Kernel on Spring Boot shutdown */
private class DSpaceKernelDestroyer implements ApplicationListener<ContextClosedEvent> {
private DSpaceKernelImpl kernelImpl;
private DSpaceKernel dspaceKernel;
public DSpaceKernelDestroyer(DSpaceKernelImpl kernelImpl) {
this.kernelImpl = kernelImpl;
public DSpaceKernelDestroyer(DSpaceKernel kernelImpl) {
this.dspaceKernel = kernelImpl;
}
public void onApplicationEvent(final ContextClosedEvent event) {
if (this.kernelImpl != null) {
this.kernelImpl.destroy();
this.kernelImpl = null;
if (this.dspaceKernel != null) {
this.dspaceKernel.destroy();
this.dspaceKernel = null;
}
}
}

View File

@@ -7,14 +7,18 @@
*/
package org.dspace.app.rest;
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.text.IsEqualIgnoringCase.equalToIgnoringCase;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import org.dspace.app.rest.builder.CollectionBuilder;
import org.dspace.app.rest.builder.CommunityBuilder;
import org.dspace.app.rest.builder.ItemBuilder;
import org.dspace.app.rest.matcher.BrowseIndexMatchers;
import org.dspace.app.rest.test.AbstractControllerIntegrationTest;
import org.hamcrest.Matcher;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.Item;
import org.junit.Test;
/**
@@ -42,48 +46,117 @@ public class BrowsesResourceControllerTest extends AbstractControllerIntegration
//Check that all (and only) the default browse indexes are present
.andExpect(jsonPath("$._embedded.browses", containsInAnyOrder(
dateIssuedBrowseIndex("asc"),
contributorBrowseIndex("asc"),
titleBrowseIndex("asc"),
subjectBrowseIndex("asc")
BrowseIndexMatchers.dateIssuedBrowseIndex("asc"),
BrowseIndexMatchers.contributorBrowseIndex("asc"),
BrowseIndexMatchers.titleBrowseIndex("asc"),
BrowseIndexMatchers.subjectBrowseIndex("asc")
)))
;
}
private Matcher<? super Object> subjectBrowseIndex(final String order) {
return allOf(
hasJsonPath("$.metadata", contains("dc.subject.*")),
hasJsonPath("$.metadataBrowse", is(true)),
hasJsonPath("$.order", equalToIgnoringCase(order)),
hasJsonPath("$.sortOptions[*].name", containsInAnyOrder("title", "dateissued", "dateaccessioned"))
);
@Test
public void findBrowseByTitle() throws Exception {
//When we call the root endpoint
mockMvc.perform(get("/api/discover/browses/title"))
//The status has to be 200 OK
.andExpect(status().isOk())
//We expect the content type to be "application/hal+json;charset=UTF-8"
.andExpect(content().contentType(contentType))
//Check that the JSON root matches the expected browse index
.andExpect(jsonPath("$", BrowseIndexMatchers.titleBrowseIndex("asc")))
;
}
private Matcher<? super Object> titleBrowseIndex(final String order) {
return allOf(
hasJsonPath("$.metadata", contains("dc.title")),
hasJsonPath("$.metadataBrowse", is(false)),
hasJsonPath("$.order", equalToIgnoringCase(order)),
hasJsonPath("$.sortOptions[*].name", containsInAnyOrder("title", "dateissued", "dateaccessioned"))
);
@Test
public void findBrowseByDateIssued() throws Exception {
//When we call the root endpoint
mockMvc.perform(get("/api/discover/browses/dateissued"))
//The status has to be 200 OK
.andExpect(status().isOk())
//We expect the content type to be "application/hal+json;charset=UTF-8"
.andExpect(content().contentType(contentType))
//Check that the JSON root matches the expected browse index
.andExpect(jsonPath("$", BrowseIndexMatchers.dateIssuedBrowseIndex("asc")))
;
}
private Matcher<? super Object> contributorBrowseIndex(final String order) {
return allOf(
hasJsonPath("$.metadata", contains("dc.contributor.*", "dc.creator")),
hasJsonPath("$.metadataBrowse", is(true)),
hasJsonPath("$.order", equalToIgnoringCase(order)),
hasJsonPath("$.sortOptions[*].name", containsInAnyOrder("title", "dateissued", "dateaccessioned"))
);
@Test
public void findBrowseByContributor() throws Exception {
//When we call the root endpoint
mockMvc.perform(get("/api/discover/browses/author"))
//The status has to be 200 OK
.andExpect(status().isOk())
//We expect the content type to be "application/hal+json;charset=UTF-8"
.andExpect(content().contentType(contentType))
//Check that the JSON root matches the expected browse index
.andExpect(jsonPath("$", BrowseIndexMatchers.contributorBrowseIndex("asc")))
;
}
private Matcher<? super Object> dateIssuedBrowseIndex(final String order) {
return allOf(
hasJsonPath("$.metadata", contains("dc.date.issued")),
hasJsonPath("$.metadataBrowse", is(false)),
hasJsonPath("$.order", equalToIgnoringCase(order)),
hasJsonPath("$.sortOptions[*].name", containsInAnyOrder("title", "dateissued", "dateaccessioned"))
);
@Test
public void findBrowseBySubject() throws Exception {
//When we call the root endpoint
mockMvc.perform(get("/api/discover/browses/subject"))
//The status has to be 200 OK
.andExpect(status().isOk())
//We expect the content type to be "application/hal+json;charset=UTF-8"
.andExpect(content().contentType(contentType))
//Check that the JSON root matches the expected browse index
.andExpect(jsonPath("$", BrowseIndexMatchers.subjectBrowseIndex("asc")))
;
}
@Test
public void findBrowseByTitleItems() throws Exception {
context.turnOffAuthorisationSystem();
parentCommunity = new CommunityBuilder().createCommunity(context)
.withName("Parent Community")
.build();
Community child1 = new CommunityBuilder().createSubCommunity(context, parentCommunity)
.withName("Sub Community")
.build();
Collection col1 = new CollectionBuilder().createCollection(context, child1).withName("Collection 1").build();
Collection col2 = new CollectionBuilder().createCollection(context, child1).withName("Collection 2").build();
Item item1 = new ItemBuilder().createItem(context, col1)
.withTitle("My first test item")
.withIssueDate("2017-10-17")
.withAuthor("Smith, Donald")
.withAuthor("Doe, John")
.withSubject("Java")
.withSubject("Unit Testing")
.build();
Item item2 = new ItemBuilder().createItem(context, col2)
.withTitle("My second test item")
.withIssueDate("2016-02-13")
.withAuthor("Smith, Maria")
.withAuthor("Doe, Jane")
.withSubject("Angular")
.withSubject("Unit Testing")
.build();
context.restoreAuthSystemState();
//When we browse the items in the Browse by item endpoint
mockMvc.perform(get("/api/discover/browses/title/items"))
//The status has to be 200 OK
.andExpect(status().isOk())
//We expect the content type to be "application/hal+json;charset=UTF-8"
.andExpect(content().contentType(contentType))
//We expect our two created items to be present
.andExpect(jsonPath("$.page.size", is(20)))
.andExpect(jsonPath("$.page.totalElements", is(2)))
.andExpect(jsonPath("$.page.totalPages", is(1)))
.andExpect(jsonPath("$.page.number", is(0)))
;
}
}

View File

@@ -30,17 +30,17 @@ public class RootRestResourceControllerTest extends AbstractControllerIntegratio
//We expect the content type to be "application/hal+json;charset=UTF-8"
.andExpect(content().contentType(contentType))
//Check that all required root links are present and that they are absolute
.andExpect(jsonPath("$._links.bitstreamformats.href", startsWith("http://localhost/api")))
.andExpect(jsonPath("$._links.bitstreams.href", startsWith("http://localhost/api")))
.andExpect(jsonPath("$._links.browses.href", startsWith("http://localhost/api")))
.andExpect(jsonPath("$._links.collections.href", startsWith("http://localhost/api")))
.andExpect(jsonPath("$._links.communities.href", startsWith("http://localhost/api")))
.andExpect(jsonPath("$._links.epersons.href", startsWith("http://localhost/api")))
.andExpect(jsonPath("$._links.groups.href", startsWith("http://localhost/api")))
.andExpect(jsonPath("$._links.items.href", startsWith("http://localhost/api")))
.andExpect(jsonPath("$._links.metadatafields.href", startsWith("http://localhost/api")))
.andExpect(jsonPath("$._links.metadataschemas.href", startsWith("http://localhost/api")))
.andExpect(jsonPath("$._links.sites.href", startsWith("http://localhost/api")))
.andExpect(jsonPath("$._links.bitstreamformats.href", startsWith(REST_SERVER_URL)))
.andExpect(jsonPath("$._links.bitstreams.href", startsWith(REST_SERVER_URL)))
.andExpect(jsonPath("$._links.browses.href", startsWith(REST_SERVER_URL)))
.andExpect(jsonPath("$._links.collections.href", startsWith(REST_SERVER_URL)))
.andExpect(jsonPath("$._links.communities.href", startsWith(REST_SERVER_URL)))
.andExpect(jsonPath("$._links.epersons.href", startsWith(REST_SERVER_URL)))
.andExpect(jsonPath("$._links.groups.href", startsWith(REST_SERVER_URL)))
.andExpect(jsonPath("$._links.items.href", startsWith(REST_SERVER_URL)))
.andExpect(jsonPath("$._links.metadatafields.href", startsWith(REST_SERVER_URL)))
.andExpect(jsonPath("$._links.metadataschemas.href", startsWith(REST_SERVER_URL)))
.andExpect(jsonPath("$._links.sites.href", startsWith(REST_SERVER_URL)))
;
}

View File

@@ -0,0 +1,46 @@
package org.dspace.app.rest.builder;
import org.apache.log4j.Logger;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.BitstreamService;
import org.dspace.content.service.BundleService;
import org.dspace.content.service.CollectionService;
import org.dspace.content.service.CommunityService;
import org.dspace.content.service.InstallItemService;
import org.dspace.content.service.ItemService;
import org.dspace.content.service.WorkspaceItemService;
import org.dspace.core.Context;
import org.dspace.discovery.IndexingService;
import org.dspace.eperson.factory.EPersonServiceFactory;
import org.dspace.eperson.service.EPersonService;
import org.dspace.eperson.service.GroupService;
import org.dspace.services.factory.DSpaceServicesFactory;
/**
* TODO TOM UNIT TEST
*/
public class AbstractBuilder {
protected CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService();
protected CollectionService collectionService = ContentServiceFactory.getInstance().getCollectionService();
protected ItemService itemService = ContentServiceFactory.getInstance().getItemService();
protected InstallItemService installItemService = ContentServiceFactory.getInstance().getInstallItemService();
protected WorkspaceItemService workspaceItemService = ContentServiceFactory.getInstance().getWorkspaceItemService();
protected EPersonService ePersonService = EPersonServiceFactory.getInstance().getEPersonService();
protected GroupService groupService = EPersonServiceFactory.getInstance().getGroupService();
protected BundleService bundleService = ContentServiceFactory.getInstance().getBundleService();
protected BitstreamService bitstreamService = ContentServiceFactory.getInstance().getBitstreamService();
protected IndexingService indexingService = DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName(IndexingService.class.getName(),IndexingService.class);
protected Context context;
/** log4j category */
private static final Logger log = Logger.getLogger(AbstractBuilder.class);
protected <T> T handleException(final Exception e) {
log.error(e);
return null;
}
}

View File

@@ -0,0 +1,50 @@
package org.dspace.app.rest.builder;
import java.sql.SQLException;
import org.dspace.content.Collection;
import org.dspace.content.Community;
import org.dspace.content.Item;
import org.dspace.content.MetadataSchema;
import org.dspace.core.Context;
import org.dspace.discovery.SearchServiceException;
/**
* TODO TOM UNIT TEST
*/
public class CollectionBuilder extends AbstractBuilder {
private Collection collection;
private Context context;
public CollectionBuilder createCollection(final Context context, final Community parent) {
this.context = context;
try {
this.collection = collectionService.create(context, parent);
} catch (Exception e) {
return handleException(e);
}
return this;
}
public CollectionBuilder withName(final String name) {
try {
collectionService.setMetadataSingleValue(context, collection, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, name);
} catch (SQLException e) {
return handleException(e);
}
return this;
}
public Collection build() {
context.dispatchEvents();
try {
indexingService.commit();
} catch (SearchServiceException e) {
return handleException(e);
}
return collection;
}
}

View File

@@ -0,0 +1,63 @@
package org.dspace.app.rest.builder;
import java.sql.SQLException;
import org.dspace.content.Community;
import org.dspace.content.Item;
import org.dspace.content.MetadataSchema;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.content.service.CommunityService;
import org.dspace.core.Context;
import org.dspace.discovery.IndexingService;
import org.dspace.discovery.SearchServiceException;
import org.dspace.services.factory.DSpaceServicesFactory;
/**
* TODO TOM UNIT TEST
*/
public class CommunityBuilder {
protected CommunityService communityService = ContentServiceFactory.getInstance().getCommunityService();
protected IndexingService indexingService = DSpaceServicesFactory.getInstance().getServiceManager().getServiceByName(IndexingService.class.getName(),IndexingService.class);
private Community community;
private Context context;
public CommunityBuilder createCommunity(final Context context) {
return createSubCommunity(context, null);
}
public CommunityBuilder createSubCommunity(final Context context, final Community parent) {
this.context = context;
try {
community = communityService.create(parent, context);
} catch (Exception e) {
e.printStackTrace();
return null;
}
return this;
}
public CommunityBuilder withName(final String communityName) {
try {
communityService.setMetadataSingleValue(context, community, MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, communityName);
} catch (SQLException e) {
e.printStackTrace();
return null;
}
return this;
}
public Community build() {
context.dispatchEvents();
try {
indexingService.commit();
} catch (SearchServiceException e) {
e.printStackTrace();
return null;
}
return community;
}
}

View File

@@ -0,0 +1,74 @@
package org.dspace.app.rest.builder;
import java.sql.SQLException;
import org.dspace.content.Collection;
import org.dspace.content.DCDate;
import org.dspace.content.Item;
import org.dspace.content.MetadataSchema;
import org.dspace.content.WorkspaceItem;
import org.dspace.core.Context;
/**
* TODO TOM UNIT TEST
*/
public class ItemBuilder extends AbstractBuilder {
private WorkspaceItem workspaceItem;
public ItemBuilder createItem(final Context context, final Collection col1) {
this.context = context;
try {
workspaceItem = workspaceItemService.create(context, col1, false);
} catch (Exception e) {
return handleException(e);
}
return this;
}
public ItemBuilder withTitle(final String title) {
try {
itemService.setMetadataSingleValue(context, workspaceItem.getItem(), MetadataSchema.DC_SCHEMA, "title", null, Item.ANY, title);
} catch (SQLException e) {
return handleException(e);
}
return this;
}
public ItemBuilder withIssueDate(final String issueDate) {
return addMetadataValueToItem(MetadataSchema.DC_SCHEMA, "date", "issued", new DCDate(issueDate).toString());
}
public ItemBuilder withAuthor(final String authorName) {
return addMetadataValueToItem(MetadataSchema.DC_SCHEMA, "date", "issued", authorName);
}
public ItemBuilder withSubject(final String subject) {
return addMetadataValueToItem(MetadataSchema.DC_SCHEMA, "subject", null, subject);
}
public Item build() {
try {
Item item = installItemService.installItem(context, workspaceItem);
context.dispatchEvents();
indexingService.commit();
return item;
} catch (Exception e) {
return handleException(e);
}
}
private ItemBuilder addMetadataValueToItem(final String schema, final String element, final String qualifier, final String value) {
try {
itemService.addMetadata(context, workspaceItem.getItem(), schema, element, qualifier, Item.ANY, value);
} catch (SQLException e) {
return handleException(e);
}
return this;
}
}

View File

@@ -0,0 +1,60 @@
package org.dspace.app.rest.matcher;
import static com.jayway.jsonpath.matchers.JsonPathMatchers.hasJsonPath;
import static org.dspace.app.rest.test.AbstractControllerIntegrationTest.REST_SERVER_URL;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.text.IsEqualIgnoringCase.equalToIgnoringCase;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers;
public class BrowseIndexMatchers {
public BrowseIndexMatchers() {
}
public static Matcher<? super Object> subjectBrowseIndex(final String order) {
return allOf(
hasJsonPath("$.metadata", contains("dc.subject.*")),
hasJsonPath("$.metadataBrowse", Matchers.is(true)),
hasJsonPath("$.order", equalToIgnoringCase(order)),
hasJsonPath("$.sortOptions[*].name", containsInAnyOrder("title", "dateissued", "dateaccessioned")),
hasJsonPath("$._links.self.href", is(REST_SERVER_URL + "discover/browses/subject")),
hasJsonPath("$._links.entries.href", is(REST_SERVER_URL + "discover/browses/subject/entries")),
hasJsonPath("$._links.items.href", is(REST_SERVER_URL + "discover/browses/subject/items"))
);
}
public static Matcher<? super Object> titleBrowseIndex(final String order) {
return allOf(
hasJsonPath("$.metadata", contains("dc.title")),
hasJsonPath("$.metadataBrowse", Matchers.is(false)),
hasJsonPath("$.order", equalToIgnoringCase(order)),
hasJsonPath("$.sortOptions[*].name", containsInAnyOrder("title", "dateissued", "dateaccessioned")),
hasJsonPath("$._links.self.href", is(REST_SERVER_URL + "discover/browses/title")),
hasJsonPath("$._links.items.href", is(REST_SERVER_URL + "discover/browses/title/items"))
);
}
public static Matcher<? super Object> contributorBrowseIndex(final String order) {
return allOf(
hasJsonPath("$.metadata", contains("dc.contributor.*", "dc.creator")),
hasJsonPath("$.metadataBrowse", Matchers.is(true)),
hasJsonPath("$.order", equalToIgnoringCase(order)),
hasJsonPath("$.sortOptions[*].name", containsInAnyOrder("title", "dateissued", "dateaccessioned")),
hasJsonPath("$._links.self.href", is(REST_SERVER_URL + "discover/browses/author")),
hasJsonPath("$._links.entries.href", is(REST_SERVER_URL + "discover/browses/author/entries")),
hasJsonPath("$._links.items.href", is(REST_SERVER_URL + "discover/browses/author/items"))
);
}
public static Matcher<? super Object> dateIssuedBrowseIndex(final String order) {
return allOf(
hasJsonPath("$.metadata", contains("dc.date.issued")),
hasJsonPath("$.metadataBrowse", Matchers.is(false)),
hasJsonPath("$.order", equalToIgnoringCase(order)),
hasJsonPath("$.sortOptions[*].name", containsInAnyOrder("title", "dateissued", "dateaccessioned")),
hasJsonPath("$._links.self.href", is(REST_SERVER_URL + "discover/browses/dateissued")),
hasJsonPath("$._links.items.href", is(REST_SERVER_URL + "discover/browses/dateissued/items"))
);
}
}

View File

@@ -17,6 +17,7 @@ import javax.servlet.Filter;
import org.apache.commons.io.Charsets;
import org.dspace.app.rest.Application;
import org.dspace.app.rest.utils.ApplicationConfig;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.runner.RunWith;
@@ -48,10 +49,12 @@ import org.springframework.web.context.WebApplicationContext;
@WebAppConfiguration
public class AbstractControllerIntegrationTest extends AbstractUnitTestWithDatabase {
public static final String REST_SERVER_URL = "http://localhost/api/";
protected MediaType contentType = new MediaType(MediaTypes.HAL_JSON.getType(),
MediaTypes.HAL_JSON.getSubtype(), Charsets.UTF_8);
protected MockMvc mockMvc;
protected MockMvc mockMvc = null;
protected HttpMessageConverter mappingJackson2HttpMessageConverter;
@@ -74,10 +77,18 @@ public class AbstractControllerIntegrationTest extends AbstractUnitTestWithDatab
@Before
public void setUp() throws Exception {
super.setUp();
this.mockMvc = webAppContextSetup(webApplicationContext)
//Add all filter implementations
.addFilters(requestFilters.toArray(new Filter[requestFilters.size()]))
.build();
if(mockMvc == null) {
mockMvc = webAppContextSetup(webApplicationContext)
//Add all filter implementations
.addFilters(requestFilters.toArray(new Filter[requestFilters.size()]))
.build();
}
}
@After
public void destroy() {
super.destroy();
mockMvc = null;
}
}

View File

@@ -13,6 +13,8 @@ import java.sql.SQLException;
import org.apache.log4j.Logger;
import org.dspace.authorize.AuthorizeException;
import org.dspace.content.Community;
import org.dspace.content.factory.ContentServiceFactory;
import org.dspace.core.Context;
import org.dspace.core.I18nUtil;
import org.dspace.eperson.EPerson;
@@ -40,6 +42,11 @@ public class AbstractUnitTestWithDatabase extends AbstractDSpaceTest {
*/
protected EPerson eperson;
/**
* The test Parent Community
*/
protected Community parentCommunity = null;
/**
* This method will be run before the first test as per @BeforeClass. It will
* initialize shared resources required for all tests of this class.
@@ -134,8 +141,21 @@ public class AbstractUnitTestWithDatabase extends AbstractDSpaceTest {
{
// Cleanup our global context object
try {
context.commit();
parentCommunity = context.reloadEntity(parentCommunity);
eperson = context.reloadEntity(eperson);
context.turnOffAuthorisationSystem();
if(parentCommunity != null) {
ContentServiceFactory.getInstance().getCommunityService().delete(context, parentCommunity);
}
if(eperson != null) {
EPersonServiceFactory.getInstance().getEPersonService().delete(context, eperson);
}
parentCommunity = null;
cleanupContext(context);
} catch (SQLException e) {
} catch (Exception e) {
throw new RuntimeException(e);
}
}

View File

@@ -0,0 +1,23 @@
package org.dspace.app.rest.test;
import java.util.List;
import org.dspace.kernel.DSpaceKernelManager;
import org.springframework.test.context.ContextConfigurationAttributes;
import org.springframework.test.context.ContextCustomizer;
import org.springframework.test.context.ContextCustomizerFactory;
/**
* Context customizer factory to set the parent context of our Spring Boot application in TEST mode
*/
public class DSpaceKernelContextCustomizerFactory implements ContextCustomizerFactory {
@Override
public ContextCustomizer createContextCustomizer(Class<?> testClass,
List<ContextConfigurationAttributes> configAttributes) {
return (context, mergedConfig) -> {
context.setParent(DSpaceKernelManager.getDefaultKernel().getServiceManager().getApplicationContext());
};
}
}

View File

@@ -0,0 +1,31 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.discovery;
import org.dspace.solr.MockSolrServer;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Service;
/**
* Mock SOLR service for the Search Core
*/
@Service
public class MockSolrServiceImpl extends SolrServiceImpl implements InitializingBean, DisposableBean {
private MockSolrServer mockSolrServer;
public void afterPropertiesSet() throws Exception {
mockSolrServer = new MockSolrServer("search");
solr = mockSolrServer.getSolrServer();
}
public void destroy() throws Exception {
mockSolrServer.destroy();
}
}

View File

@@ -0,0 +1,57 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.solr;
import java.io.File;
import java.io.IOException;
import org.apache.solr.client.solrj.SolrServer;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.embedded.EmbeddedSolrServer;
import org.apache.solr.core.CoreContainer;
/**
* Abstract class to mock a service that uses SOLR
*/
public class MockSolrServer {
private String coreName;
private SolrServer solrServer = null;
public MockSolrServer(final String coreName) throws Exception {
this.coreName = coreName;
initSolrServer();
}
public SolrServer getSolrServer() {
return solrServer;
}
protected void initSolrServer() throws Exception {
CoreContainer container = new CoreContainer(System.getProperty("dspace.dir") + File.separator + "solr");
container.load();
solrServer = new EmbeddedSolrServer(container, coreName);
//Start with an empty index
try {
solrServer.deleteByQuery("*:*");
solrServer.commit();
} catch (SolrServerException | IOException e) {
e.printStackTrace();
}
}
public void destroy() throws Exception {
if(solrServer != null) {
solrServer.shutdown();
}
}
}

View File

@@ -0,0 +1,42 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.statistics;
import java.io.File;
import java.io.IOException;
import com.maxmind.geoip.Location;
import com.maxmind.geoip.LookupService;
/**
* Mock service to mock the location Lookup Service used by the SOLR statistics logger
*/
public class MockLookupService extends LookupService {
public MockLookupService() throws IOException {
//Just give our super class a file so that he's happy. We'll mock all responses anyway.
super(System.getProperty("dspace.dir") + File.separator + "config" + File.separator + "dspace.cfg");
}
@Override
public Location getLocation(String str) {
Location location = new Location();
location.countryCode = "US";
location.countryName = "United States";
location.region = "NY";
location.city = "New York";
location.postalCode = "10036";
location.latitude = 40.760498F;
location.longitude = -73.9933F;
location.dma_code = 501;
location.area_code = 212;
location.metro_code = 501;
return location;
}
}

View File

@@ -0,0 +1,38 @@
/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE and NOTICE files at the root of the source
* tree and available online at
*
* http://www.dspace.org/license/
*/
package org.dspace.statistics;
import org.dspace.services.ConfigurationService;
import org.dspace.solr.MockSolrServer;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
/**
* Mock service that uses an embedded SOLR server for the statistics core
*/
public class MockSolrLoggerServiceImpl extends SolrLoggerServiceImpl implements InitializingBean, DisposableBean {
private MockSolrServer mockSolrServer;
@Autowired(required = true)
private ConfigurationService configurationService;
@Override
public void afterPropertiesSet() throws Exception {
mockSolrServer = new MockSolrServer("statistics");
solr = mockSolrServer.getSolrServer();
locationService = new MockLookupService();
useProxies = configurationService.getBooleanProperty("useProxies");
}
public void destroy() throws Exception {
mockSolrServer.destroy();
}
}