VIVO-742 a first stab at Solr integration tests

To replace SolrQueryTest unit test.
This commit is contained in:
Jim Blake 2014-05-15 18:12:21 -04:00
parent 4405d76683
commit afa0c0a15e
4 changed files with 363 additions and 0 deletions

View file

@ -0,0 +1,9 @@
log4j.appender.AllAppender=org.apache.log4j.ConsoleAppender
log4j.appender.AllAppender.layout=org.apache.log4j.PatternLayout
log4j.appender.AllAppender.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c] %m%n
# log4j.appender.AllAppender.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %-5p [%c{1}] %m%n
log4j.rootLogger=INFO, AllAppender
# Make all of the Solr classes quieter...
log4j.logger.org.apache.solr=WARN

View file

@ -0,0 +1,110 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- $This file is distributed under the terms of the license in /doc/license.txt$ -->
<!-- ======================================================================
Integration tests to be sure that the Solr configuration does what we
want.
====================================================================== -->
<project name="solr-tester" default="describe">
<property name="src.dir" location="src" />
<property name="vitro.libs.dir" location="../../webapp/lib" />
<property name="solr.home.template"
location="../../solr/homeDirectoryTemplate" />
<property name="solr.war.file" location="../../solr/solr-4.7.2.war" />
<property name="working.dir" location=".work" />
<property name="classes.dir" location="${working.dir}/classes" />
<property name="solr.working.dir" location="${working.dir}/solrHome" />
<property name="solr.libs.dir" location="${working.dir}/solrLibs" />
<path id="main.compile.classpath">
<fileset dir="${vitro.libs.dir}" includes="*.jar" />
<fileset dir="${solr.libs.dir}" includes="*.jar" />
</path>
<path id="test.run.classpath">
<pathelement location="${classes.dir}" />
<path refid="main.compile.classpath" />
</path>
<!-- =================================
target: describe
================================= -->
<target name="describe"
description="--> Describe the targets (this is the default).">
<echo>
all - Runs "clean", then "test".
clean - Delete all artifacts so the next build will be from scratch.
test - Set up the Solr configuration, compile, and run the JUnit tests.
</echo>
</target>
<!-- =================================
target: all
================================= -->
<target name="all"
depends="clean,test"
description="Build from scratch and run the tests.">
</target>
<!-- =================================
target: clean
================================= -->
<target name="clean"
description="Delete the Solr configuration and the compiled clases.">
<delete dir="${working.dir}" />
</target>
<!-- =================================
target: test
================================= -->
<target name="test" depends="compile" description="Run the tests.">
<java classname="org.junit.runner.JUnitCore"
fork="yes"
failonerror="true">
<arg value="edu.cornell.mannlib.vitro.utilities.solrtest.SolrConfigTester" />
<classpath refid="test.run.classpath" />
<sysproperty key="test.solr.home" value="${solr.working.dir}" />
</java>
</target>
<!-- - - - - - - - - - - - - - - - - -
target: setup
- - - - - - - - - - - - - - - - - -->
<target name="setup">
<mkdir dir="${working.dir}" />
<mkdir dir="${solr.working.dir}" />
<sync todir="${solr.working.dir}" includeemptydirs="true">
<fileset dir="${solr.home.template}" />
</sync>
<mkdir dir="${solr.libs.dir}" />
<unwar src="${solr.war.file}" dest="${solr.libs.dir}">
<patternset includes="WEB-INF/lib/*" />
<mapper type="flatten" />
</unwar>
<mkdir dir="${classes.dir}" />
<copy file="log4j.properties" todir="${classes.dir}" />
</target>
<!-- - - - - - - - - - - - - - - - - -
target: compile
- - - - - - - - - - - - - - - - - -->
<target name="compile" depends="setup">
<javac srcdir="${src.dir}"
destdir="${classes.dir}"
debug="true"
deprecation="true"
encoding="UTF8"
includeantruntime="false"
optimize="true"
source="1.7">
<classpath refid="main.compile.classpath" />
</javac>
</target>
</project>

View file

@ -0,0 +1,243 @@
/* $This file is distributed under the terms of the license in /doc/license.txt$ */
package edu.cornell.mannlib.vitro.utilities.solrtest;
import static org.junit.Assert.assertEquals;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.io.FileUtils;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.client.solrj.embedded.EmbeddedSolrServer;
import org.apache.solr.client.solrj.response.QueryResponse;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.core.CoreContainer;
import org.apache.solr.core.SolrCore;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/**
* TODO
*/
@RunWith(JUnit4.class)
public class SolrConfigTester {
private static CoreContainer container;
private static EmbeddedSolrServer server;
@Before
public void setup() throws Exception {
String solrHomeString = System.getProperty("test.solr.home");
container = new CoreContainer(solrHomeString);
try (LogLeveler l = new LogLeveler(SolrCore.class, Level.ERROR)) {
container.load();
}
server = new EmbeddedSolrServer(container, "collection1");
server.deleteByQuery("*:*");
server.commit();
}
@After
public void tearDown() throws Exception {
server.shutdown();
}
// ----------------------------------------------------------------------
// The tests
// ----------------------------------------------------------------------
@Test
public void serverResponds() throws Exception {
server.ping();
}
@Test(expected = SolrException.class)
public void docIdIsRequred() throws Exception {
try (LogLeveler l = new LogLeveler(SolrCore.class, Level.OFF)) {
addDocuments(inputDoc(null, field("nameRaw", "No ID")));
}
}
@Test
public void simpleName() throws Exception {
addDocuments(inputDoc("idSimple", field("nameRaw", "SimpleName")));
assertQueryResults("simple name", "SimpleName", "idSimple");
}
@Test
public void upperLowerName() throws Exception {
addDocuments(inputDoc("idUpperLower", field("nameRaw", "Lower, Upper")));
assertQueryResults("upper lower name", "Lower", "idUpperLower");
assertQueryResults("upper lower name", "lower", "idUpperLower");
assertQueryResults("upper lower name", "UPPER", "idUpperLower");
}
@Test
public void nameIsNotStemmed() throws Exception {
addDocuments(inputDoc("nameStemming", field("nameRaw", "Swimming, Bills"),
field("nameLowercaseSingleValued", "Lower, Upper")));
assertQueryResults("name not stemmed", "Swimming", "nameStemming");
assertQueryResults("name not stemmed", "Bills", "nameStemming");
assertQueryResults("name not stemmed", "Swim");
assertQueryResults("name not stemmed", "Bill");
}
/**
* A name with an umlaut over an o is found exactly, or with the umlaut
* missing, upper case or lower case.
*/
@Test
public void nameWithUmlaut() throws Exception {
addDocuments(inputDoc("idUmlaut",
field("nameRaw", "P\u00F6ysen B\u00F6ysen")));
assertQueryResults("name with umlaut", "Boysen", "idUmlaut");
assertQueryResults("name with umlaut", "B\u00F6ysen", "idUmlaut");
assertQueryResults("name with umlaut", "BOYSEN", "idUmlaut");
assertQueryResults("name with umlaut", "B\u00D6YSEN", "idUmlaut");
}
/**
* ALLTEXT is searched, but to make the 3rd case work, we need
* ALLTEXTUNSTEMMED also. Why is that?
*/
@Test
public void allTextIsSearched() throws Exception {
addDocuments(inputDoc("allTextSearch", field("ALLTEXT", "Wonderful"),
field("ALLTEXTUNSTEMMED", "Wonderful")));
assertQueryResults("all text", "Wonderful", "allTextSearch");
assertQueryResults("all text", "wonderful", "allTextSearch");
assertQueryResults("all text", "WoNdErFuL", "allTextSearch");
}
@Test
public void allTextIsStemmed() throws Exception {
addDocuments(inputDoc("allTextStem", field("ALLTEXT", "Swimming"),
field("ALLTEXTUNSTEMMED", "Swimming")));
assertQueryResults("all text stem", "Swim", "allTextStem");
assertQueryResults("all text stem", "swim", "allTextStem");
}
// ----------------------------------------------------------------------
// Helper methods
// ----------------------------------------------------------------------
public InputField field(String name, String... values) {
return new InputField(name, null, values);
}
public InputField field(String name, Float boost, String... values) {
return new InputField(name, boost, values);
}
public SolrInputDocument inputDoc(String docId, InputField... fields) {
SolrInputDocument doc = new SolrInputDocument();
if (docId != null) {
doc.addField("DocId", docId);
}
for (InputField f : fields) {
for (String value : f.values) {
if (f.boost == null) {
doc.addField(f.name, value);
} else {
doc.addField(f.name, value, f.boost);
}
}
}
return doc;
}
public void addDocuments(SolrInputDocument... documents)
throws SolrServerException, IOException {
for (SolrInputDocument doc : documents) {
server.add(doc);
}
server.commit();
}
private void assertQueryResults(String message, String query,
String... expectedDocIds) throws SolrServerException {
ModifiableSolrParams params = new ModifiableSolrParams();
params.set("q", query);
QueryResponse qResp = server.query(params);
SolrDocumentList docList = qResp.getResults();
List<String> expected = Arrays.asList(expectedDocIds);
List<String> actual = new ArrayList<>();
for (int i = 0; i < docList.getNumFound(); i++) {
actual.add(String.valueOf(docList.get(i).getFirstValue("DocId")));
}
assertEquals(message + " : '" + query + "'", expected, actual);
}
// ----------------------------------------------------------------------
// Helper classes
// ----------------------------------------------------------------------
public static class InputField {
final String name;
final Float boost;
final String[] values;
public InputField(String name, Float boost, String[] values) {
this.name = name;
this.boost = boost;
this.values = values;
}
}
public static class LogLeveler implements AutoCloseable {
private final Logger logger;
private final Level initialLevel;
public LogLeveler(Class<?> clazz, Level desiredLevel) {
this.logger = Logger.getLogger(clazz);
this.initialLevel = this.logger.getLevel();
this.logger.setLevel(desiredLevel);
}
@Override
public void close() {
this.logger.setLevel(this.initialLevel);
}
}
}
/**
* TODO
*
* <pre>
* // ** Let's index a document into our embedded server
*
* SolrInputDocument newDoc = new SolrInputDocument();
* newDoc.addField(&quot;title&quot;, &quot;Test Document 1&quot;);
* newDoc.addField(&quot;id&quot;, &quot;doc-1&quot;);
* newDoc.addField(&quot;text&quot;, &quot;Hello world!&quot;);
* server.add(newDoc);
* server.commit();
*
* // ** And now let's query for it
*
* params.set(&quot;q&quot;, &quot;title:test&quot;);
* QueryResponse qResp = server.query(params);
*
* SolrDocumentList docList = qResp.getResults();
* System.out.println(&quot;Num docs: &quot; + docList.getNumFound());
* SolrDocument doc = docList.get(0);
* System.out.println(&quot;Title: &quot; + doc.getFirstValue(&quot;title&quot;).toString());
* </pre>
*/