From afa0c0a15e914040b30e5b979d3ee1fe09a30d0c Mon Sep 17 00:00:00 2001 From: Jim Blake Date: Thu, 15 May 2014 18:12:21 -0400 Subject: [PATCH] VIVO-742 a first stab at Solr integration tests To replace SolrQueryTest unit test. --- .gitignore | 1 + utilities/solrtester/log4j.properties | 9 + utilities/solrtester/solrtester-build.xml | 110 ++++++++ .../utilities/solrtest/SolrConfigTester.java | 243 ++++++++++++++++++ 4 files changed, 363 insertions(+) create mode 100644 utilities/solrtester/log4j.properties create mode 100644 utilities/solrtester/solrtester-build.xml create mode 100644 utilities/solrtester/src/edu/cornell/mannlib/vitro/utilities/solrtest/SolrConfigTester.java diff --git a/.gitignore b/.gitignore index d138d06a3..279a9183f 100644 --- a/.gitignore +++ b/.gitignore @@ -8,3 +8,4 @@ /webapp/config/runtime.properties /webapp/config/debug.log4j.properties .build +utilities/solrtester/.work diff --git a/utilities/solrtester/log4j.properties b/utilities/solrtester/log4j.properties new file mode 100644 index 000000000..b18505604 --- /dev/null +++ b/utilities/solrtester/log4j.properties @@ -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 diff --git a/utilities/solrtester/solrtester-build.xml b/utilities/solrtester/solrtester-build.xml new file mode 100644 index 000000000..9df9e042b --- /dev/null +++ b/utilities/solrtester/solrtester-build.xml @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +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. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/utilities/solrtester/src/edu/cornell/mannlib/vitro/utilities/solrtest/SolrConfigTester.java b/utilities/solrtester/src/edu/cornell/mannlib/vitro/utilities/solrtest/SolrConfigTester.java new file mode 100644 index 000000000..4b0b5e069 --- /dev/null +++ b/utilities/solrtester/src/edu/cornell/mannlib/vitro/utilities/solrtest/SolrConfigTester.java @@ -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 expected = Arrays.asList(expectedDocIds); + List 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 + * + *
+ * // ** Let's index a document into our embedded server
+ * 
+ * SolrInputDocument newDoc = new SolrInputDocument();
+ * newDoc.addField("title", "Test Document 1");
+ * newDoc.addField("id", "doc-1");
+ * newDoc.addField("text", "Hello world!");
+ * server.add(newDoc);
+ * server.commit();
+ * 
+ * // ** And now let's query for it
+ * 
+ * params.set("q", "title:test");
+ * QueryResponse qResp = server.query(params);
+ * 
+ * SolrDocumentList docList = qResp.getResults();
+ * System.out.println("Num docs: " + docList.getNumFound());
+ * SolrDocument doc = docList.get(0);
+ * System.out.println("Title: " + doc.getFirstValue("title").toString());
+ * 
+ */