You are viewing a plain text version of this content. The canonical link for it is here.
Posted to solr-commits@lucene.apache.org by ho...@apache.org on 2006/04/11 06:36:49 UTC
svn commit: r393142 [1/2] - in /incubator/solr/trunk: ./
src/java/org/apache/solr/request/ src/java/org/apache/solr/util/
src/test/org/apache/solr/
Author: hossman
Date: Mon Apr 10 21:36:46 2006
New Revision: 393142
URL: http://svn.apache.org/viewcvs?rev=393142&view=rev
Log:
SOLR-3 - a general purpose test harness, JUnit base class, and migrated version of SolrTest's newtest.txt to JUnit
Added:
incubator/solr/trunk/src/java/org/apache/solr/util/AbstractSolrTestCase.java
incubator/solr/trunk/src/java/org/apache/solr/util/TestHarness.java
incubator/solr/trunk/src/test/org/apache/solr/BasicFunctionalityTest.java
incubator/solr/trunk/src/test/org/apache/solr/ConvertedLegacyTest.java
incubator/solr/trunk/src/test/org/apache/solr/SampleTest.java
Modified:
incubator/solr/trunk/build.xml
incubator/solr/trunk/src/java/org/apache/solr/request/SolrQueryRequest.java
incubator/solr/trunk/src/java/org/apache/solr/util/XML.java
Modified: incubator/solr/trunk/build.xml
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/build.xml?rev=393142&r1=393141&r2=393142&view=diff
==============================================================================
--- incubator/solr/trunk/build.xml (original)
+++ incubator/solr/trunk/build.xml Mon Apr 10 21:36:46 2006
@@ -29,6 +29,11 @@
<property name="javadoc.packages" value="org.apache.solr.*"/>
<property name="build.javadoc" value="${build.docs}/api"/>
+ <property name="junit.output.dir" location="${dest}/test-results"/>
+ <property name="junit.reports" location="${dest}/test-results/reports"/>
+ <property name="junit.includes" value="**/Test*.java,**/*Test.java"/>
+
+
<!-- Default target: usage. Prints out instructions. -->
<target name="usage"
description="Prints out instructions">
@@ -67,11 +72,11 @@
<javac destdir="${dest}"
target="1.5"
- source="1.5"
+ source="1.5"
debug="on"
classpathref="compile.classpath">
<src path="${src}/java" />
- <src path="${src}/webapp" />
+ <src path="${src}/webapp/src" />
</javac>
</target>
@@ -132,9 +137,11 @@
<!-- Run unit tests. -->
<target name="test"
description="Runs the unit tests."
- depends="compileTests">
- <echo message="TO-DO later or after we convert tests to JUnit." />
-
+ depends="compileTests, junit" />
+
+ <target name="legacyTest"
+ depends="compileTests" >
+ <!-- DEPRECATED: no description so it doesn't show up in project help -->
<java classname="SolrTest" fork="true" dir="src/apps/SolrTest" failonerror="true">
<arg line="-test newtest.txt"/>
<classpath>
@@ -143,7 +150,48 @@
</java>
</target>
+
+ <target name="junit" depends="compileTests">
+ <!-- no description so it doesn't show up in -projecthelp -->
+ <mkdir dir="${junit.output.dir}"/>
+
+ <!-- :TODO: either SolrCore needs a way to specify the
+ solrconfig.xml, or all test are going to need to use the same
+ conf file, either way we need a specific run directory for
+ the tests.
+ -->
+ <junit printsummary="on"
+ haltonfailure="no"
+ errorProperty="tests.failed"
+ failureProperty="tests.failed"
+ dir="src/apps/SolrTest"
+ >
+ <syspropertyset>
+ <propertyref prefix="solr" />
+ </syspropertyset>
+ <classpath refid="test.run.classpath"/>
+ <formatter type="xml"/>
+ <batchtest fork="yes" todir="${junit.output.dir}" unless="testcase">
+ <fileset dir="src/test" includes="${junit.includes}"/>
+ </batchtest>
+ <batchtest fork="yes" todir="${junit.output.dir}" if="testcase">
+ <fileset dir="src/test" includes="**/${testcase}.java"/>
+ </batchtest>
+ </junit>
+ <fail if="tests.failed">Tests failed!</fail>
+ </target>
+
+ <target name="test-reports">
+ <!-- no description so it doesn't show up in -projecthelp ... yet -->
+ <mkdir dir="${junit.reports}"/>
+ <junitreport todir="${junit.output.dir}">
+ <fileset dir="${junit.output.dir}">
+ <include name="TEST-*.xml"/>
+ </fileset>
+ <report format="frames" todir="${junit.reports}"/>
+ </junitreport>
+ </target>
<!-- ========================================================================= -->
Modified: incubator/solr/trunk/src/java/org/apache/solr/request/SolrQueryRequest.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/request/SolrQueryRequest.java?rev=393142&r1=393141&r2=393142&view=diff
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/request/SolrQueryRequest.java (original)
+++ incubator/solr/trunk/src/java/org/apache/solr/request/SolrQueryRequest.java Mon Apr 10 21:36:46 2006
@@ -25,6 +25,10 @@
* @version $Id$
*/
public interface SolrQueryRequest {
+
+ /** All uses of this request are finished, resources can be freed */
+ public void close();
+
public String getParam(String name);
public String getQueryString();
Added: incubator/solr/trunk/src/java/org/apache/solr/util/AbstractSolrTestCase.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/util/AbstractSolrTestCase.java?rev=393142&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/util/AbstractSolrTestCase.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/util/AbstractSolrTestCase.java Mon Apr 10 21:36:46 2006
@@ -0,0 +1,250 @@
+
+package org.apache.solr.util;
+
+import org.apache.solr.request.*;
+import org.apache.solr.util.TestHarness;
+
+import org.xml.sax.SAXException;
+import junit.framework.TestCase;
+import javax.xml.xpath.XPathExpressionException;
+
+import java.util.*;
+import java.io.*;
+
+/**
+ * An Abstract base class that makes writing Solr JUnit tests "easier"
+ *
+ * <p>
+ * Test classes that subclass this need only specify the path to the
+ * schema.xml file (:TODO: the solrconfig.xml as well) and write some
+ * testMethods. This class takes care of creating/destroying the index,
+ * and provides several assert methods to assist you.
+ * </p>
+ *
+ * @see #setUp
+ * @see #tearDown
+ */
+public abstract class AbstractSolrTestCase extends TestCase {
+
+ /**
+ * Harness initialized by initTestHarness.
+ *
+ * <p>
+ * For use in test methods as needed.
+ * </p>
+ */
+ protected TestHarness h;
+ /**
+ * LocalRequestFactory initialized by initTestHarness using sensible
+ * defaults.
+ *
+ * <p>
+ * For use in test methods as needed.
+ * </p>
+ */
+ protected TestHarness.LocalRequestFactory lrf;
+
+ /**
+ * Subclasses must define this method to return the path of the
+ * schema.xml they wish to use.
+ */
+ public abstract String getSchemaPath();
+
+ /**
+ * The directory used to story the index managed by the TestHarness h
+ */
+ protected File dataDir;
+
+ /**
+ * Initializes things your test might need
+ *
+ * <ul>
+ * <li>Creates a dataDir in the "java.io.tmpdir"</li>
+ * <li>initializes the TestHarness h using this data directory, and getSchemaPath()</li>
+ * <li>initializes the LocalRequestFactory lrf using sensible defaults.</li>
+ * </ul>
+ *
+ */
+ public void setUp() throws Exception {
+
+ dataDir = new File(System.getProperty("java.io.tmpdir")
+ + System.getProperty("file.separator")
+ + getClass().getName() + "-" + getName() + "-"
+ + System.currentTimeMillis());
+ dataDir.mkdirs();
+ h = new TestHarness(dataDir.getAbsolutePath(), getSchemaPath());
+ lrf = h.getRequestFactory
+ ("standard",0,20,"version","2.0");
+
+ }
+
+ /**
+ * Shuts down the test harness, and makes the best attempt possible
+ * to delete dataDir, unless the system property "solr.test.leavedatadir"
+ * is set.
+ */
+ public void tearDown() throws Exception {
+ h.close();
+ String skip = System.getProperty("solr.test.leavedatadir");
+ if (null != skip && 0 != skip.trim().length()) {
+ System.err.println("NOTE: per solr.test.leavedatadir, dataDir will not be removed: " + dataDir.getAbsolutePath());
+ } else {
+ if (!recurseDelete(dataDir)) {
+ System.err.println("!!!! WARNING: best effort to remove " + dataDir.getAbsolutePath() + " FAILED !!!!!");
+ }
+ }
+ }
+
+ /** Validates an update XML String is successful
+ */
+ public void assertU(String update) {
+ assertU(null, update);
+ }
+
+ /** Validates an update XML String is successful
+ */
+ public void assertU(String message, String update) {
+ try {
+ String m = (null == message) ? "" : message + " ";
+
+ String res = h.validateUpdate(update);
+ if (null != res) {
+ fail(m + "update was not successful: " + res);
+ }
+ } catch (SAXException e) {
+ throw new RuntimeException("Invalid XML", e);
+ }
+ }
+
+ /** Validates a query matches some XPath test expressions and closes the query */
+ public void assertQ(SolrQueryRequest req, String... tests) {
+ assertQ(null, req, tests);
+ }
+
+ /** Validates a query matches some XPath test expressions and closes the query */
+ public void assertQ(String message, SolrQueryRequest req, String... tests) {
+ try {
+ String m = (null == message) ? "" : message + " ";
+ String response = h.query(req);
+ String results = h.validateXPath(response, tests);
+ if (null != results) {
+ fail(m + "query failed XPath: " + results +
+ " xml response was: " + response);
+ }
+ } catch (XPathExpressionException e1) {
+ throw new RuntimeException("XPath is invalid", e1);
+ } catch (Exception e2) {
+ throw new RuntimeException("Exception during query", e2);
+ }
+ }
+
+ /**
+ * @see TestHarness#optimize
+ */
+ public String optimize(String... args) {
+ return h.optimize();
+ }
+ /**
+ * @see TestHarness#commit
+ */
+ public String commit(String... args) {
+ return h.commit();
+ }
+
+ /**
+ * Generates a simple <add><doc>... XML String with no options
+ *
+ * @param fieldsAndValues 0th and Even numbered args are fields names odds are field values.
+ * @see #add
+ * @see #doc
+ */
+ public String adoc(String... fieldsAndValues) {
+ Doc d = doc(fieldsAndValues);
+ return add(d);
+ }
+
+ /**
+ * Generates an <add><doc>... XML String with options
+ * on the add.
+ *
+ * @param doc the Document to add
+ * @param args 0th and Even numbered args are param names, Odds are param values.
+ * @see #add
+ * @see #doc
+ */
+ public String add(Doc doc, String... args) {
+ try {
+ StringWriter r = new StringWriter();
+
+ // this is anoying
+ if (null == args || 0 == args.length) {
+ r.write("<add>");
+ r.write(doc.xml);
+ r.write("</add>");
+ } else {
+ XML.writeUnescapedXML(r, "add", doc.xml, (Object[])args);
+ }
+
+ return r.getBuffer().toString();
+ } catch (IOException e) {
+ throw new RuntimeException
+ ("this should never happen with a StringWriter", e);
+ }
+ }
+
+ /**
+ * Generates a <delete>... XML string for an ID
+ *
+ * @see TestHarness#deleteById
+ */
+ public String delI(String id) {
+ return h.deleteById(id);
+ }
+ /**
+ * Generates a <delete>... XML string for an query
+ *
+ * @see TestHarness#deleteByQuery
+ */
+ public String delQ(String q) {
+ return h.deleteByQuery(q);
+ }
+
+ /**
+ * Generates a simple <doc>... XML String with no options
+ *
+ * @param fieldsAndValues 0th and Even numbered args are fields names, Odds are field values.
+ * @see TestHarness#makeSimpleDoc
+ */
+ public Doc doc(String... fieldsAndValues) {
+ Doc d = new Doc();
+ d.xml = h.makeSimpleDoc(fieldsAndValues).toString();
+ return d;
+ }
+
+ /**
+ * Generates a SolrQueryRequest using the LocalRequestFactory
+ * @see #lrf
+ */
+ public SolrQueryRequest req( String q ) {
+ return lrf.makeRequest(q);
+ }
+
+ /** Neccessary to make method signatures un-ambiguous */
+ public static class Doc {
+ public String xml;
+ public String toString() { return xml; }
+ }
+
+ public static boolean recurseDelete(File f) {
+ if (f.isDirectory()) {
+ for (File sub : f.listFiles()) {
+ if (!recurseDelete(sub)) {
+ return false;
+ }
+ }
+ }
+ return f.delete();
+ }
+
+
+}
Added: incubator/solr/trunk/src/java/org/apache/solr/util/TestHarness.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/util/TestHarness.java?rev=393142&view=auto
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/util/TestHarness.java (added)
+++ incubator/solr/trunk/src/java/org/apache/solr/util/TestHarness.java Mon Apr 10 21:36:46 2006
@@ -0,0 +1,372 @@
+/**
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * 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 org.apache.solr.util;
+
+import org.apache.solr.schema.IndexSchema;
+import org.apache.solr.core.SolrCore;
+import org.apache.solr.request.*;
+
+import org.xml.sax.SAXException;
+import org.w3c.dom.Document;
+
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
+import javax.xml.xpath.XPathExpressionException;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathFactory;
+import javax.xml.xpath.XPathConstants;
+import java.io.*;
+import java.util.*;
+
+
+/**
+ * This class provides a simple harness that may be usefull when
+ * writing testcasses.
+ *
+ * <p>
+ * This class lives in the main source tree (and not in the test source
+ * tree) so that it will be included with even the most minimal solr
+ * distribution -- to encourage plugin writers to creat unit tests for their
+ * plugins.
+ *
+ * @author hossman
+ * @version $Id:$
+ */
+public class TestHarness {
+
+ private SolrCore core;
+ private XMLResponseWriter xmlwriter = new XMLResponseWriter();
+ private XPath xpath = XPathFactory.newInstance().newXPath();
+ private DocumentBuilder builder;
+
+ /**
+ * @param dataDirectory path for index data, will not be cleaned up
+ * @param schemaFile path of schema file
+ */
+ public TestHarness(String dataDirectory, String schemaFile) {
+ core = new SolrCore(dataDirectory, new IndexSchema(schemaFile));
+ try {
+ builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+
+ /**
+ * Processes an "update" (add, commit or optimize) and
+ * returns the response as a String.
+ *
+ * @param xml The XML of the update
+ * @return The XML response to the update
+ */
+ public String update(String xml) {
+
+ StringReader req = new StringReader(xml);
+ StringWriter writer = new StringWriter(32000);
+ core.update(req, writer);
+ return writer.toString();
+
+ }
+
+
+ /**
+ * Validates that an "update" (add, commit or optimize) results in success.
+ *
+ * :TODO: currently only deals with one add/doc at a time, this will need changed if/when SOLR-2 is resolved
+ *
+ * @param xml The XML of the update
+ * @return null if succesful, otherwise the XML response to the update
+ */
+ public String validateUpdate(String xml) throws SAXException {
+ try {
+ String res = update(xml);
+ String valid = validateXPath(res, "//result[@status=0]" );
+ return (null == valid) ? null : res;
+ } catch (XPathExpressionException e) {
+ throw new RuntimeException
+ ("?!? static xpath has bug?", e);
+ }
+ }
+
+
+ /**
+ * Validates that an add of a single document results in success.
+ *
+ * @param fieldsAndValues Odds are field names, Evens are values
+ * @return null if succesful, otherwise the XML response to the update
+ * @see appendSimpleDoc
+ */
+ public String validateAddDoc(String... fieldsAndValues)
+ throws XPathExpressionException, SAXException, IOException {
+
+ StringBuffer buf = new StringBuffer();
+ buf.append("<add>");
+ appendSimpleDoc(buf, fieldsAndValues);
+ buf.append("</add>");
+
+ String res = update(buf.toString());
+ String valid = validateXPath(res, "//result[@status=0]" );
+ return (null == valid) ? null : res;
+ }
+
+
+
+ /**
+ * Validates a "query" response against an array of XPath test strings
+ *
+ * @param req the Query to process
+ * @return null if all good, otherwise the first test that fails.
+ * @exception Exception any exception in the response.
+ * @exception IOException if there is a problem writing the XML
+ * @see LocalSolrQueryRequest
+ */
+ public String validateQuery(SolrQueryRequest req, String... tests)
+ throws IOException, Exception {
+
+ String res = query(req);
+ return validateXPath(res, tests);
+ }
+
+ /**
+ * Processes a "query" using a user constructed SolrQueryRequest
+ *
+ * @param req the Query to process, will be closed.
+ * @return The XML response to the query
+ * @exception Exception any exception in the response.
+ * @exception IOException if there is a problem writing the XML
+ * @see LocalSolrQueryRequest
+ */
+ public String query(SolrQueryRequest req) throws IOException, Exception {
+
+ SolrQueryResponse rsp = new SolrQueryResponse();
+ core.execute(req,rsp);
+ if (rsp.getException() != null) {
+ throw rsp.getException();
+ }
+
+ StringWriter writer = new StringWriter(32000);
+ xmlwriter.write(writer,req,rsp);
+
+ req.close();
+
+ return writer.toString();
+ }
+
+
+ /**
+ * A helper method which valides a String against an array of XPath test
+ * strings.
+ *
+ * @param xml The xml String to validate
+ * @param tests Array of XPath strings to test (in boolean mode) on the xml
+ * @return null if all good, otherwise the first test that fails.
+ */
+ public String validateXPath(String xml, String... tests)
+ throws XPathExpressionException, SAXException {
+
+ if (tests==null || tests.length == 0) return null;
+
+ Document document=null;
+ try {
+ document = builder.parse(new ByteArrayInputStream
+ (xml.getBytes("UTF-8")));
+ } catch (UnsupportedEncodingException e1) {
+ throw new RuntimeException("Totally weird UTF-8 exception", e1);
+ } catch (IOException e2) {
+ throw new RuntimeException("Totally weird io exception", e2);
+ }
+
+ for (String xp : tests) {
+ xp=xp.trim();
+ Boolean bool = (Boolean) xpath.evaluate(xp, document,
+ XPathConstants.BOOLEAN);
+
+ if (!bool) {
+ return xp;
+ }
+ }
+ return null;
+
+ }
+
+ public SolrCore getCore() {
+ return core;
+ }
+
+ /**
+ * Shuts down and frees any resources
+ */
+ public void close() {
+ core.close();
+ }
+
+ /**
+ * A helper that adds an xml <doc> containing all of the
+ * fields and values specified (odds are fields, evens are values)
+ * to a StringBuffer.
+ */
+ public void appendSimpleDoc(StringBuffer buf, String... fieldsAndValues)
+ throws IOException {
+
+ buf.append(makeSimpleDoc(fieldsAndValues));
+ }
+ /**
+ * A helper that creates an xml <doc> containing all of the
+ * fields and values specified
+ *
+ * @param fieldsAndValues 0 and Even numbered args are fields names odds are field values.
+ */
+ public static StringBuffer makeSimpleDoc(String... fieldsAndValues) {
+
+ try {
+ StringWriter w = new StringWriter();
+ w.append("<doc>");
+ for (int i = 0; i < fieldsAndValues.length; i+=2) {
+ XML.writeXML(w, "field", fieldsAndValues[i+1], "name",
+ fieldsAndValues[i]);
+ }
+ w.append("</doc>");
+ return w.getBuffer();
+ } catch (IOException e) {
+ throw new RuntimeException
+ ("this should never happen with a StringWriter", e);
+ }
+ }
+
+ /**
+ * Generates a delete by query xml string
+ * @param q Query that has not already been xml escaped
+ */
+ public static String deleteByQuery(String q) {
+ return delete("query", q);
+ }
+ /**
+ * Generates a delete by id xml string
+ * @param id ID that has not already been xml escaped
+ */
+ public static String deleteById(String id) {
+ return delete("id", id);
+ }
+
+ /**
+ * Generates a delete xml string
+ * @param val text that has not already been xml escaped
+ */
+ private static String delete(String deltype, String val) {
+ try {
+ StringWriter r = new StringWriter();
+
+ r.write("<delete>");
+ XML.writeXML(r, deltype, val);
+ r.write("</delete>");
+
+ return r.getBuffer().toString();
+ } catch (IOException e) {
+ throw new RuntimeException
+ ("this should never happen with a StringWriter", e);
+ }
+ }
+
+ /**
+ * Helper that returns an <optimize> String with
+ * optional key/val pairs.
+ *
+ * @param args 0 and Even numbered args are params, Odd numbered args are values.
+ */
+ public static String optimize(String... args) {
+ return simpleTag("optimize", args);
+ }
+
+ private static String simpleTag(String tag, String... args) {
+ try {
+ StringWriter r = new StringWriter();
+
+ // this is anoying
+ if (null == args || 0 == args.length) {
+ XML.writeXML(r, tag, null);
+ } else {
+ XML.writeXML(r, tag, null, (Object)args);
+ }
+ return r.getBuffer().toString();
+ } catch (IOException e) {
+ throw new RuntimeException
+ ("this should never happen with a StringWriter", e);
+ }
+ }
+
+ /**
+ * Helper that returns an <commit> String with
+ * optional key/val pairs.
+ *
+ * @param args 0 and Even numbered args are params, Odd numbered args are values.
+ */
+ public static String commit(String... args) {
+ return simpleTag("commit", args);
+ }
+
+ public LocalRequestFactory getRequestFactory(String qtype,
+ int start,
+ int limit) {
+ LocalRequestFactory f = new LocalRequestFactory();
+ f.qtype = qtype;
+ f.start = start;
+ f.limit = limit;
+ return f;
+ }
+
+ /**
+ * 0 and Even numbered args are keys, Odd numbered args are values.
+ */
+ public LocalRequestFactory getRequestFactory(String qtype,
+ int start, int limit,
+ String... args) {
+ LocalRequestFactory f = getRequestFactory(qtype, start, limit);
+ for (int i = 0; i < args.length; i+=2) {
+ f.args.put(args[i], args[i+1]);
+ }
+ return f;
+
+ }
+
+ public LocalRequestFactory getRequestFactory(String qtype,
+ int start, int limit,
+ Map<String,String> args) {
+
+ LocalRequestFactory f = getRequestFactory(qtype, start, limit);
+ f.args.putAll(args);
+ return f;
+ }
+
+ /**
+ * A Factory that generates LocalSolrQueryRequest objects using a
+ * specified set of default options.
+ */
+ public class LocalRequestFactory {
+ public String qtype = "standard";
+ public int start = 0;
+ public int limit = 1000;
+ public Map<String,String> args = new HashMap<String,String>();
+ public LocalRequestFactory() {
+ }
+ public LocalSolrQueryRequest makeRequest(String q) {
+ return new LocalSolrQueryRequest(TestHarness.this.getCore(),
+ q, qtype, start, limit, args);
+ }
+ }
+}
Modified: incubator/solr/trunk/src/java/org/apache/solr/util/XML.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/java/org/apache/solr/util/XML.java?rev=393142&r1=393141&r2=393142&view=diff
==============================================================================
--- incubator/solr/trunk/src/java/org/apache/solr/util/XML.java (original)
+++ incubator/solr/trunk/src/java/org/apache/solr/util/XML.java Mon Apr 10 21:36:46 2006
@@ -121,6 +121,29 @@
}
}
+ /** does NOT escape character data in val, must already be valid XML */
+ public final static void writeUnescapedXML(Writer out, String tag, String val, Object... attrs) throws IOException {
+ out.write('<');
+ out.write(tag);
+ for (int i=0; i<attrs.length; i++) {
+ out.write(' ');
+ out.write(attrs[i++].toString());
+ out.write("=\"");
+ out.write(attrs[i].toString());
+ out.write("\"");
+ }
+ if (val == null) {
+ out.write("/>");
+ } else {
+ out.write('>');
+ out.write(val);
+ out.write("</");
+ out.write(tag);
+ out.write('>');
+ }
+ }
+
+ /** escapes character data in val */
public final static void writeXML(Writer out, String tag, String val, Object... attrs) throws IOException {
out.write('<');
out.write(tag);
Added: incubator/solr/trunk/src/test/org/apache/solr/BasicFunctionalityTest.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/test/org/apache/solr/BasicFunctionalityTest.java?rev=393142&view=auto
==============================================================================
--- incubator/solr/trunk/src/test/org/apache/solr/BasicFunctionalityTest.java (added)
+++ incubator/solr/trunk/src/test/org/apache/solr/BasicFunctionalityTest.java Mon Apr 10 21:36:46 2006
@@ -0,0 +1,163 @@
+/**
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * 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 org.apache.solr;
+
+import org.apache.solr.request.*;
+import org.apache.solr.util.*;
+
+/**
+ * Tests some basic functionality of Solr while demonstrating good
+ * Best Practices for using AbstractSolrTestCase
+ */
+public class BasicFunctionalityTest extends AbstractSolrTestCase {
+
+ public String getSchemaPath() { return "solr/conf/schema.xml"; }
+
+ public void setUp() throws Exception {
+ // if you override setUp or tearDown, you better call
+ // the super classes version
+ super.setUp();
+ }
+ public void tearDown() throws Exception {
+ // if you override setUp or tearDown, you better call
+ // the super classes version
+ super.tearDown();
+
+ }
+
+ public void testSomeStuff() throws Exception {
+
+ assertQ("test query on empty index",
+ req("qlkciyopsbgzyvkylsjhchghjrdf")
+ ,"//result[@numFound='0']"
+ );
+
+ // test escaping of ";"
+ assertU("deleting 42 for no reason at all",
+ delI("42"));
+ assertU("adding doc#42",
+ adoc("id", "42", "val_s", "aa;bb"));
+ assertU("does commit work?",
+ commit());
+
+ assertQ("backslash escaping semicolon",
+ req("id:42 AND val_s:aa\\;bb")
+ ,"//*[@numFound='1']"
+ ,"//int[@name='id'][.='42']"
+ );
+
+ assertQ("quote escaping semicolon",
+ req("id:42 AND val_s:\"aa;bb\"")
+ ,"//*[@numFound='1']"
+ ,"//int[@name='id'][.='42']"
+ );
+
+ assertQ("no escaping semicolon",
+ req("id:42 AND val_s:aa")
+ ,"//*[@numFound='0']"
+ );
+
+ assertU(delI("42"));
+ assertU(commit());
+ assertQ(req("id:42")
+ ,"//*[@numFound='0']"
+ );
+
+ // test allowDups default of false
+
+ assertU(adoc("id", "42", "val_s", "AAA"));
+ assertU(adoc("id", "42", "val_s", "BBB"));
+ assertU(commit());
+ assertQ(req("id:42")
+ ,"//*[@numFound='1']"
+ ,"//str[.='BBB']"
+ );
+ assertU(adoc("id", "42", "val_s", "CCC"));
+ assertU(adoc("id", "42", "val_s", "DDD"));
+ assertU(commit());
+ assertQ(req("id:42")
+ ,"//*[@numFound='1']"
+ ,"//str[.='DDD']"
+ );
+
+ // test deletes
+ String [] adds = new String[] {
+ add( doc("id","101"), "allowDups", "false" ),
+ add( doc("id","101"), "allowDups", "false" ),
+ add( doc("id","105"), "allowDups", "true" ),
+ add( doc("id","102"), "allowDups", "false" ),
+ add( doc("id","103"), "allowDups", "true" ),
+ add( doc("id","101"), "allowDups", "false" ),
+ };
+ for (String a : adds) {
+ assertU(a, a);
+ }
+ assertU(commit());
+ assertQ(req("id:[100 TO 110]")
+ ,"//*[@numFound='4']"
+ );
+ assertU(delI("102"));
+ assertU(commit());
+ assertQ(req("id:[100 TO 110]")
+ ,"//*[@numFound='3']"
+ );
+ assertU(delI("105"));
+ assertU(commit());
+ assertQ(req("id:[100 TO 110]")
+ ,"//*[@numFound='2']"
+ );
+ assertU(delQ("id:[100 TO 110]"));
+ assertU(commit());
+ assertQ(req("id:[100 TO 110]")
+ ,"//*[@numFound='0']"
+ );
+ }
+
+
+ public void testMultipleUpdatesPerAdd() {
+
+ // big freaking kludge since the response is currently not well formed.
+ String res = h.update("<add><doc><field name=\"id\">1</field></doc><doc><field name=\"id\">2</field></doc></add>");
+ assertEquals("<result status=\"0\"></result><result status=\"0\"></result>", res);
+ assertU("<commit/>");
+ assertQ(req("id:[0 TO 99]")
+ ,"//*[@numFound='2']"
+ );
+
+ }
+
+
+// /** this doesn't work, but if it did, this is how we'd test it. */
+// public void testOverwriteFalse() {
+
+// assertU(adoc("id", "overwrite", "val_s", "AAA"));
+// assertU(commit());
+
+// assertU(add(doc("id", "overwrite", "val_s", "BBB")
+// ,"allowDups", "false"
+// ,"overwriteCommitted","false"
+// ,"overwritePending","false"
+// ));
+// assertU(commit());
+// assertQ(req("id:overwrite")
+// ,"//*[@numFound='1']"
+// ,"//str[.='AAA']"
+// );
+// }
+
+
+}
Added: incubator/solr/trunk/src/test/org/apache/solr/ConvertedLegacyTest.java
URL: http://svn.apache.org/viewcvs/incubator/solr/trunk/src/test/org/apache/solr/ConvertedLegacyTest.java?rev=393142&view=auto
==============================================================================
--- incubator/solr/trunk/src/test/org/apache/solr/ConvertedLegacyTest.java (added)
+++ incubator/solr/trunk/src/test/org/apache/solr/ConvertedLegacyTest.java Mon Apr 10 21:36:46 2006
@@ -0,0 +1,1296 @@
+/**
+ * Copyright 2006 The Apache Software Foundation
+ *
+ * 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 org.apache.solr;
+
+import org.apache.solr.request.*;
+import org.apache.solr.util.*;
+
+import java.util.*;
+import java.io.IOException;
+
+/**
+ * This tests was converted from a legacy testing system.
+ *
+ * it does not represent the best practices that should be used when
+ * writing Solr JUnit tests
+ */
+public class ConvertedLegacyTest extends AbstractSolrTestCase {
+
+ public String getSchemaPath() { return "solr/conf/schema.xml"; }
+
+ public void testABunchOfConvertedStuff() {
+ // these may be reused by things that need a special query
+ SolrQueryRequest req = null;
+ Map<String,String> args = new HashMap<String,String>();
+
+ // compact the index, keep things from getting out of hand
+
+ assertU("<optimize/>");
+
+ // test query
+
+ assertQ(req("qlkciyopsbgzyvkylsjhchghjrdf")
+ ,"//result[@numFound='0']"
+ );
+
+ // test escaping of ";"
+
+ assertU("<delete><id>42</id></delete>");
+ assertU("<add><doc><field name=\"id\">42</field><field name=\"val_s\">aa;bb</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("id:42 AND val_s:aa\\;bb")
+ ,"//*[@numFound='1']"
+ );
+ assertQ(req("id:42 AND val_s:\"aa;bb\"")
+ ,"//*[@numFound='1']"
+ );
+ assertQ(req("id:42 AND val_s:\"aa\"")
+ ,"//*[@numFound='0']"
+ );
+
+
+
+ // test allowDups default of false
+
+ assertU("<delete><id>42</id></delete>");
+ assertU("<add><doc><field name=\"id\">42</field><field name=\"val_s\">AAA</field></doc></add>");
+ assertU("<add><doc><field name=\"id\">42</field><field name=\"val_s\">BBB</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("id:42")
+ ,"//*[@numFound='1'] "
+ ,"//str[.='BBB']"
+ );
+ assertU("<add><doc><field name=\"id\">42</field><field name=\"val_s\">CCC</field></doc></add>");
+ assertU("<add><doc><field name=\"id\">42</field><field name=\"val_s\">DDD</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("id:42")
+ ,"//*[@numFound='1'] "
+ ,"//str[.='DDD']"
+ );
+ assertU("<delete><id>42</id></delete>");
+
+ // test deletes
+
+ assertU("<delete><query>id:[100 TO 110]</query></delete>");
+ assertU("<add allowDups=\"false\"><doc><field name=\"id\">101</field></doc></add>");
+ assertU("<add allowDups=\"false\"><doc><field name=\"id\">101</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">105</field></doc></add>");
+ assertU("<add allowDups=\"false\"><doc><field name=\"id\">102</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">103</field></doc></add>");
+ assertU("<add allowDups=\"false\"><doc><field name=\"id\">101</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("id:[100 TO 110]")
+ ,"//*[@numFound='4']"
+ );
+ assertU("<delete><id>102</id></delete>");
+ assertU("<commit/>");
+ assertQ(req("id:[100 TO 110]")
+ ,"//*[@numFound='3']"
+ );
+ assertU("<delete><query>id:105</query></delete>");
+ assertU("<commit/>");
+ assertQ(req("id:[100 TO 110]")
+ ,"//*[@numFound='2']"
+ );
+ assertU("<delete><query>id:[100 TO 110]</query></delete>");
+ assertU("<commit/>");
+ assertQ(req("id:[100 TO 110]")
+ ,"//*[@numFound='0']"
+ );
+
+ // test range
+
+ assertU("<delete><id>44</id></delete>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"val_s\">apple</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"val_s\">banana</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"val_s\">pear</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("val_s:[a TO z]")
+ ,"//*[@numFound='3'] "
+ ,"*[count(//doc)=3] "
+ ,"//*[@start='0']"
+ );
+ args = new HashMap<String,String>();
+ args.put("version","2.0");
+ req = new LocalSolrQueryRequest(h.getCore(), "val_s:[a TO z]",
+ "standard", 2, 5 , args);
+ assertQ(req
+ ,"//*[@numFound='3'] "
+ ,"*[count(//doc)=1] "
+ ,"*//doc[1]/str[.='pear'] "
+ ,"//*[@start='2']"
+ );
+ args = new HashMap<String,String>();
+ args.put("version","2.0");
+ req = new LocalSolrQueryRequest(h.getCore(), "val_s:[a TO z]",
+ "standard", 3, 5 , args);
+ assertQ(req
+ ,"//*[@numFound='3'] "
+ ,"*[count(//doc)=0]"
+ );
+ args = new HashMap<String,String>();
+ args.put("version","2.0");
+ req = new LocalSolrQueryRequest(h.getCore(), "val_s:[a TO z]",
+ "standard", 4, 5 , args);
+ assertQ(req
+ ,"//*[@numFound='3'] "
+ ,"*[count(//doc)=0]"
+ );
+ args = new HashMap<String,String>();
+ args.put("version","2.0");
+ req = new LocalSolrQueryRequest(h.getCore(), "val_s:[a TO z]",
+ "standard", 25, 5 , args);
+ assertQ(req
+ ,"//*[@numFound='3'] "
+ ,"*[count(//doc)=0]"
+ );
+ args = new HashMap<String,String>();
+ args.put("version","2.0");
+ req = new LocalSolrQueryRequest(h.getCore(), "val_s:[a TO z]",
+ "standard", 0, 1 , args);
+ assertQ(req
+ ,"//*[@numFound='3'] "
+ ,"*[count(//doc)=1] "
+ ,"*//doc[1]/str[.='apple']"
+ );
+ args = new HashMap<String,String>();
+ args.put("version","2.0");
+ req = new LocalSolrQueryRequest(h.getCore(), "val_s:[a TO z]",
+ "standard", 0, 2 , args);
+ assertQ(req
+ ,"//*[@numFound='3'] "
+ ,"*[count(//doc)=2] "
+ ,"*//doc[2]/str[.='banana']"
+ );
+ args = new HashMap<String,String>();
+ args.put("version","2.0");
+ req = new LocalSolrQueryRequest(h.getCore(), "val_s:[a TO z]",
+ "standard", 1, 1 , args);
+ assertQ(req
+ ,"//*[@numFound='3'] "
+ ,"*[count(//doc)=1] "
+ ,"*//doc[1]/str[.='banana']"
+ );
+ args = new HashMap<String,String>();
+ args.put("version","2.0");
+ req = new LocalSolrQueryRequest(h.getCore(), "val_s:[a TO z]",
+ "standard", 3, 1 , args);
+ assertQ(req
+ ,"//*[@numFound='3'] "
+ ,"*[count(//doc)=0]"
+ );
+ args = new HashMap<String,String>();
+ args.put("version","2.0");
+ req = new LocalSolrQueryRequest(h.getCore(), "val_s:[a TO z]",
+ "standard", 4, 1 , args);
+ assertQ(req
+ ,"//*[@numFound='3'] "
+ ,"*[count(//doc)=0]"
+ );
+ args = new HashMap<String,String>();
+ args.put("version","2.0");
+ req = new LocalSolrQueryRequest(h.getCore(), "val_s:[a TO z]",
+ "standard", 1, 0 , args);
+ assertQ(req
+ ,"//*[@numFound='3'] "
+ ,"*[count(//doc)=0]"
+ );
+ args = new HashMap<String,String>();
+ args.put("version","2.0");
+ req = new LocalSolrQueryRequest(h.getCore(), "val_s:[a TO z]",
+ "standard", 0, 0 , args);
+ assertQ(req
+ ,"//*[@numFound='3'] "
+ ,"*[count(//doc)=0]"
+ );
+ args = new HashMap<String,String>();
+ args.put("version","2.0");
+ req = new LocalSolrQueryRequest(h.getCore(), "val_s:[a TO z];val_s asc",
+ "standard", 0, 0 , args);
+ assertQ(req
+ ,"//*[@numFound='3'] "
+ ,"*[count(//doc)=0]"
+ );
+ args = new HashMap<String,String>();
+ args.put("version","2.0");
+ req = new LocalSolrQueryRequest(h.getCore(), "val_s:[a TO z];val_s desc",
+ "standard", 0, 0 , args);
+ assertQ(req
+ ,"//*[@numFound='3'] "
+ ,"*[count(//doc)=0]"
+ );
+ assertQ(req("val_s:[a TO b]")
+ ,"//*[@numFound='1']"
+ );
+ assertQ(req("val_s:[a TO cat]")
+ ,"//*[@numFound='2']"
+ );
+ assertQ(req("val_s:[a TO *]")
+ ,"//*[@numFound='3']"
+ );
+ assertQ(req("val_s:[* TO z]")
+ ,"//*[@numFound='3']"
+ );
+ assertQ(req("val_s:[* TO *]")
+ ,"//*[@numFound='3']"
+ );
+ assertQ(req("val_s:[apple TO pear]")
+ ,"//*[@numFound='3']"
+ );
+ assertQ(req("val_s:[bear TO boar]")
+ ,"//*[@numFound='0']"
+ );
+ assertQ(req("val_s:[a TO a]")
+ ,"//*[@numFound='0']"
+ );
+ assertQ(req("val_s:[apple TO apple]")
+ ,"//*[@numFound='1']"
+ );
+ assertQ(req("val_s:{apple TO pear}")
+ ,"//*[@numFound='1']"
+ );
+ assertQ(req("val_s:{a TO z}")
+ ,"//*[@numFound='3']"
+ );
+ assertQ(req("val_s:{* TO *}")
+ ,"//*[@numFound='3']"
+ );
+ // test rangequery within a boolean query
+
+ assertQ(req("id:44 AND val_s:[a TO z]")
+ ,"//*[@numFound='3']"
+ );
+ assertQ(req("id:44 OR val_s:[a TO z]")
+ ,"//*[@numFound='3']"
+ );
+ assertQ(req("val_s:[a TO b] OR val_s:[b TO z]")
+ ,"//*[@numFound='3']"
+ );
+ assertQ(req("+val_s:[a TO b] -val_s:[b TO z]")
+ ,"//*[@numFound='1']"
+ );
+ assertQ(req("-val_s:[a TO b] +val_s:[b TO z]")
+ ,"//*[@numFound='2']"
+ );
+ assertQ(req("val_s:[a TO c] AND val_s:[apple TO z]")
+ ,"//*[@numFound='2']"
+ );
+ assertQ(req("val_s:[a TO c] AND val_s:[a TO apple]")
+ ,"//*[@numFound='1']"
+ );
+ assertQ(req("id:44 AND (val_s:[a TO c] AND val_s:[a TO apple])")
+ ,"//*[@numFound='1']"
+ );
+ assertQ(req("(val_s:[apple TO apple] OR val_s:[a TO c]) AND (val_s:[b TO c] OR val_s:[b TO b])")
+ ,"//*[@numFound='1'] "
+ ,"//str[.='banana']"
+ );
+ assertQ(req("(val_s:[apple TO apple] AND val_s:[a TO c]) OR (val_s:[p TO z] AND val_s:[a TO z])")
+ ,"//*[@numFound='2'] "
+ ,"//str[.='apple'] "
+ ,"//str[.='pear']"
+ );
+
+ // check for docs that appear more than once in a range
+
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"val_s\">apple</field><field name=\"val_s\">banana</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("val_s:[* TO *] OR val_s:[* TO *]")
+ ,"//*[@numFound='4']"
+ );
+ assertQ(req("val_s:[* TO *] AND val_s:[* TO *]")
+ ,"//*[@numFound='4']"
+ );
+ assertQ(req("val_s:[* TO *]")
+ ,"//*[@numFound='4']"
+ );
+
+
+ // <delete><id>44</id></delete>
+
+ assertU("<add overwritePending=\"true\" overwriteCommitted=\"true\"><doc><field name=\"id\">44</field><field name=\"text\">red riding hood</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("id:44 AND red")
+ ,"//@numFound[.='1'] "
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:44 AND ride")
+ ,"//@numFound[.='1']"
+ );
+ assertQ(req("id:44 AND blue")
+ ,"//@numFound[.='0']"
+ );
+
+ // allow duplicates
+
+ assertU("<delete><id>44</id></delete>");
+ assertU("<add allowDups=\"true\" overwriteCommitted=\"false\" overwritePending=\"false\"><doc><field name=\"id\">44</field><field name=\"text\">red riding hood</field></doc></add>");
+ assertU("<add allowDups=\"true\" overwriteCommitted=\"false\" overwritePending=\"false\"><doc><field name=\"id\">44</field><field name=\"text\">big bad wolf</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("id:44")
+ ,"//@numFound[.='2']"
+ );
+ assertQ(req("id:44 AND red")
+ ,"//@numFound[.='1'] "
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:44 AND wolf")
+ ,"//@numFound[.='1'] "
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("+id:44 red wolf")
+ ,"//@numFound[.='2']"
+ );
+
+ // test removal of multiples w/o adding anything else
+
+ assertU("<delete><id>44</id></delete>");
+ assertU("<commit/>");
+ assertQ(req("id:44")
+ ,"//@numFound[.='0']"
+ );
+
+ // untokenized string type
+
+ assertU("<delete><id>44</id></delete>");
+ assertU("<add><doc><field name=\"id\">44</field><field name=\"ssto\">and a 10.4 ?</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("id:44")
+ ,"//str[.='and a 10.4 ?']"
+ );
+ assertU("<delete><id>44</id></delete>");
+ assertU("<add><doc><field name=\"id\">44</field><field name=\"sind\">abc123</field></doc></add>");
+ assertU("<commit/>");
+ // TODO: how to search for something with spaces....
+
+ assertQ(req("sind:abc123")
+ ,"//@numFound[.='1'] "
+ ,"*[count(//@name[.='sind'])=0] "
+ ,"*[count(//@name[.='id'])=1]"
+ );
+
+ assertU("<delete><id>44</id></delete>");
+ assertU("<delete><id>44</id></delete>");
+ assertU("<add><doc><field name=\"id\">44</field><field name=\"sindsto\">abc123</field></doc></add>");
+ assertU("<commit/>");
+ // TODO: how to search for something with spaces....
+
+ assertQ(req("sindsto:abc123")
+ ,"//str[.='abc123']"
+ );
+
+ // test output of multivalued fields
+
+ assertU("<delete><id>44</id></delete>");
+ assertU("<add><doc><field name=\"id\">44</field><field name=\"title\">yonik3</field><field name=\"title\" boost=\"2\">yonik4</field></doc></add>");
+ assertU("<commit></commit>");
+ assertQ(req("id:44")
+ ,"//arr[@name='title'][./str='yonik3' and ./str='yonik4'] "
+ ,"*[count(//@name[.='title'])=1]"
+ );
+ assertQ(req("title:yonik3")
+ ,"//@numFound[.>'0']"
+ );
+ assertQ(req("title:yonik4")
+ ,"//@numFound[.>'0']"
+ );
+ assertQ(req("title:yonik5")
+ ,"//@numFound[.='0']"
+ );
+ assertU("<delete><query>title:yonik4</query></delete>");
+ assertU("<commit/>");
+ assertQ(req("id:44")
+ ,"//@numFound[.='0']"
+ );
+
+
+ // not visible until commit
+
+ assertU("<delete><id>44</id></delete>");
+ assertU("<commit/>");
+ assertU("<add><doc><field name=\"id\">44</field></doc></add>");
+ assertQ(req("id:44")
+ ,"//@numFound[.='0']"
+ );
+ assertU("<commit/>");
+ assertQ(req("id:44")
+ ,"//@numFound[.='1']"
+ );
+
+ // test configurable stop words
+
+ assertU("<delete><id>44</id></delete>");
+ assertU("<add><doc><field name=\"id\">44</field><field name=\"teststop\">world stopworda view</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("+id:44 +teststop:world")
+ ,"//@numFound[.='1']"
+ );
+ assertQ(req("teststop:stopworda")
+ ,"//@numFound[.='0']"
+ );
+
+ // test ignoreCase stop words
+
+ assertU("<delete><id>44</id></delete>");
+ assertU("<add><doc><field name=\"id\">44</field><field name=\"stopfilt\">world AnD view</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("+id:44 +stopfilt:world")
+ ,"//@numFound[.='1']"
+ );
+ assertQ(req("stopfilt:\"and\"")
+ ,"//@numFound[.='0']"
+ );
+ assertQ(req("stopfilt:\"AND\"")
+ ,"//@numFound[.='0']"
+ );
+ assertQ(req("stopfilt:\"AnD\"")
+ ,"//@numFound[.='0']"
+ );
+
+ // test dynamic field types
+
+ assertU("<delete fromPending=\"true\" fromCommitted=\"true\"><id>44</id></delete>");
+ assertU("<add><doc><field name=\"id\">44</field><field name=\"gack_i\">51778</field><field name=\"t_name\">cats</field></doc></add>");
+ assertU("<commit/>");
+ // test if the dyn fields got added
+
+ assertQ(req("id:44")
+ ,"*[count(//doc/*)>=3] "
+ ,"//int[@name='gack_i'][.='51778'] "
+ ,"//str[@name='t_name'][.='cats']"
+ );
+ // now test if we can query by a dynamic field (requires analyzer support)
+
+ assertQ(req("t_name:cat")
+ ,"//str[@name='t_name' and .='cats']"
+ );
+ // check that deleteByQuery works for dynamic fields
+
+ assertU("<delete><query>t_name:cat</query></delete>");
+ assertU("<commit/>");
+ assertQ(req("t_name:cat")
+ ,"//@numFound[.='0']"
+ );
+
+ // test that longest dynamic field match happens first
+
+ assertU("<add><doc><field name=\"id\">44</field><field name=\"xaa\">mystr</field><field name=\"xaaa\">12321</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("id:44")
+ ,"//str[@name='xaa'][.='mystr'] "
+ ,"//int[@name='xaaa'][.='12321']"
+ );
+
+
+ // test integer ranges and sorting
+
+ assertU("<delete><id>44</id></delete>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_i\">1234567890</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_i\">10</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_i\">1</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_i\">2</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_i\">15</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_i\">-1</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_i\">-987654321</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_i\">2147483647</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_i\">-2147483648</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_i\">0</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("id:44")
+ ,"*[count(//doc)=10]"
+ );
+ assertQ(req("num_i:2147483647")
+ ,"//@numFound[.='1'] "
+ ,"//int[.='2147483647']"
+ );
+ assertQ(req("num_i:\"-2147483648\"")
+ ,"//@numFound[.='1'] "
+ ,"//int[.='-2147483648']"
+ );
+ assertQ(req("id:44;num_i asc;")
+ ,"//doc[1]/int[.='-2147483648'] "
+ ,"//doc[last()]/int[.='2147483647']"
+ );
+ assertQ(req("id:44;num_i desc;")
+ ,"//doc[1]/int[.='2147483647'] "
+ ,"//doc[last()]/int[.='-2147483648']"
+ );
+ assertQ(req("num_i:[0 TO 9]")
+ ,"*[count(//doc)=3]"
+ );
+ assertQ(req("num_i:[-2147483648 TO 2147483647]")
+ ,"*[count(//doc)=10]"
+ );
+ assertQ(req("num_i:[-10 TO -1]")
+ ,"*[count(//doc)=1]"
+ );
+
+ // test long ranges and sorting
+
+ assertU("<delete><id>44</id></delete>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_l\">1234567890</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_l\">10</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_l\">1</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_l\">2</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_l\">15</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_l\">-1</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_l\">-987654321</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_l\">9223372036854775807</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_l\">-9223372036854775808</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_l\">0</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("id:44")
+ ,"*[count(//doc)=10]"
+ );
+ assertQ(req("num_l:9223372036854775807")
+ ,"//@numFound[.='1'] "
+ ,"//long[.='9223372036854775807']"
+ );
+ assertQ(req("num_l:\"-9223372036854775808\"")
+ ,"//@numFound[.='1'] "
+ ,"//long[.='-9223372036854775808']"
+ );
+ assertQ(req("id:44;num_l asc;")
+ ,"//doc[1]/long[.='-9223372036854775808'] "
+ ,"//doc[last()]/long[.='9223372036854775807']"
+ );
+ assertQ(req("id:44;num_l desc;")
+ ,"//doc[1]/long[.='9223372036854775807'] "
+ ,"//doc[last()]/long[.='-9223372036854775808']"
+ );
+ assertQ(req("num_l:[-1 TO 9]")
+ ,"*[count(//doc)=4]"
+ );
+ assertQ(req("num_l:[-9223372036854775808 TO 9223372036854775807]")
+ ,"*[count(//doc)=10]"
+ );
+ assertQ(req("num_l:[-10 TO -1]")
+ ,"*[count(//doc)=1]"
+ );
+
+ // test binary float ranges and sorting
+
+ assertU("<delete><id>44</id></delete>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_f\">1.4142135</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_f\">Infinity</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_f\">-Infinity</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_f\">NaN</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_f\">2</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_f\">-1</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_f\">-987654321</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_f\">-999999.99</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_f\">-1e20</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_f\">0</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("id:44")
+ ,"*[count(//doc)=10]"
+ );
+ assertQ(req("num_f:Infinity")
+ ,"//@numFound[.='1'] "
+ ,"//float[.='Infinity']"
+ );
+ assertQ(req("num_f:\"-Infinity\"")
+ ,"//@numFound[.='1'] "
+ ,"//float[.='-Infinity']"
+ );
+ assertQ(req("num_f:\"NaN\"")
+ ,"//@numFound[.='1'] "
+ ,"//float[.='NaN']"
+ );
+ assertQ(req("num_f:\"-1e20\"")
+ ,"//@numFound[.='1']"
+ );
+ assertQ(req("id:44;num_f asc;")
+ ,"//doc[1]/float[.='-Infinity'] "
+ ,"//doc[last()]/float[.='NaN']"
+ );
+ assertQ(req("id:44;num_f desc;")
+ ,"//doc[1]/float[.='NaN'] "
+ ,"//doc[last()]/float[.='-Infinity']"
+ );
+ assertQ(req("num_f:[-1 TO 2]")
+ ,"*[count(//doc)=4]"
+ );
+ assertQ(req("num_f:[-Infinity TO Infinity]")
+ ,"*[count(//doc)=9]"
+ );
+
+
+
+ // test binary double ranges and sorting
+
+ assertU("<delete><id>44</id></delete>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_d\">1.4142135</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_d\">Infinity</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_d\">-Infinity</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_d\">NaN</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_d\">2</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_d\">-1</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_d\">1e-100</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_d\">-999999.99</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_d\">-1e100</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"num_d\">0</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("id:44")
+ ,"*[count(//doc)=10]"
+ );
+ assertQ(req("num_d:Infinity")
+ ,"//@numFound[.='1'] "
+ ,"//double[.='Infinity']"
+ );
+ assertQ(req("num_d:\"-Infinity\"")
+ ,"//@numFound[.='1'] "
+ ,"//double[.='-Infinity']"
+ );
+ assertQ(req("num_d:\"NaN\"")
+ ,"//@numFound[.='1'] "
+ ,"//double[.='NaN']"
+ );
+ assertQ(req("num_d:\"-1e100\"")
+ ,"//@numFound[.='1']"
+ );
+ assertQ(req("num_d:\"1e-100\"")
+ ,"//@numFound[.='1']"
+ );
+ assertQ(req("id:44;num_d asc;")
+ ,"//doc[1]/double[.='-Infinity'] "
+ ,"//doc[last()]/double[.='NaN']"
+ );
+ assertQ(req("id:44;num_d desc;")
+ ,"//doc[1]/double[.='NaN'] "
+ ,"//doc[last()]/double[.='-Infinity']"
+ );
+ assertQ(req("num_d:[-1 TO 2]")
+ ,"*[count(//doc)=5]"
+ );
+ assertQ(req("num_d:[-Infinity TO Infinity]")
+ ,"*[count(//doc)=9]"
+ );
+
+
+ // test sorting on multiple fields
+
+ assertU("<delete><id>44</id></delete>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"a_i\">10</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"a_i\">1</field><field name=\"b_i\">100</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"a_i\">-1</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"a_i\">15</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"a_i\">1</field><field name=\"b_i\">50</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id\">44</field><field name=\"a_i\">0</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("id:44")
+ ,"*[count(//doc)=6]"
+ );
+
+ assertQ(req("id:44; a_i asc,b_i desc")
+ ,"*[count(//doc)=6] "
+ ,"//doc[3]/int[.='100'] "
+ ,"//doc[4]/int[.='50']"
+ );
+ assertQ(req("id:44;a_i asc , b_i asc;")
+ ,"*[count(//doc)=6] "
+ ,"//doc[3]/int[.='50'] "
+ ,"//doc[4]/int[.='100']"
+ );
+ assertQ(req("id:44;a_i asc;")
+ ,"*[count(//doc)=6] "
+ ,"//doc[1]/int[.='-1'] "
+ ,"//doc[last()]/int[.='15']"
+ );
+ assertQ(req("id:44;a_i asc , score top;")
+ ,"*[count(//doc)=6] "
+ ,"//doc[1]/int[.='-1'] "
+ ,"//doc[last()]/int[.='15']"
+ );
+ assertQ(req("id:44; score top , a_i top, b_i bottom ;")
+ ,"*[count(//doc)=6] "
+ ,"//doc[last()]/int[.='-1'] "
+ ,"//doc[1]/int[.='15'] "
+ ,"//doc[3]/int[.='50'] "
+ ,"//doc[4]/int[.='100']"
+ );
+
+
+ // test sorting with some docs missing the sort field
+
+ assertU("<delete><query>id_i:[1000 TO 1010]</query></delete>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id_i\">1000</field><field name=\"a_i\">1</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id_i\">1001</field><field name=\"a_i\">10</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id_i\">1002</field><field name=\"a_i\">1</field><field name=\"b_i\">100</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id_i\">1003</field><field name=\"a_i\">-1</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id_i\">1004</field><field name=\"a_i\">15</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id_i\">1005</field><field name=\"a_i\">1</field><field name=\"b_i\">50</field></doc></add>");
+ assertU("<add allowDups=\"true\"><doc><field name=\"id_i\">1006</field><field name=\"a_i\">0</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("id_i:[1000 TO 1010]")
+ ,"*[count(//doc)=7]"
+ );
+ assertQ(req("id_i:[1000 TO 1010]; b_i asc")
+ ,"*[count(//doc)=7] "
+ ,"//doc[1]/int[.='50'] "
+ ,"//doc[2]/int[.='100']"
+ );
+ assertQ(req("id_i:[1000 TO 1010]; b_i desc")
+ ,"*[count(//doc)=7] "
+ ,"//doc[1]/int[.='100'] "
+ ,"//doc[2]/int[.='50']"
+ );
+ assertQ(req("id_i:[1000 TO 1010]; a_i asc,b_i desc")
+ ,"*[count(//doc)=7] "
+ ,"//doc[3]/int[.='100'] "
+ ,"//doc[4]/int[.='50'] "
+ ,"//doc[5]/int[.='1000']"
+ );
+ assertQ(req("id_i:[1000 TO 1010]; a_i asc,b_i asc")
+ ,"*[count(//doc)=7] "
+ ,"//doc[3]/int[.='50'] "
+ ,"//doc[4]/int[.='100'] "
+ ,"//doc[5]/int[.='1000']"
+ );
+
+
+ // test prefix query
+
+ assertU("<delete><query>val_s:[* TO *]</query></delete>");
+ assertU("<add><doc><field name=\"id\">100</field><field name=\"val_s\">apple</field></doc></add>");
+ assertU("<add><doc><field name=\"id\">101</field><field name=\"val_s\">banana</field></doc></add>");
+ assertU("<add><doc><field name=\"id\">102</field><field name=\"val_s\">apple</field></doc></add>");
+ assertU("<add><doc><field name=\"id\">103</field><field name=\"val_s\">pearing</field></doc></add>");
+ assertU("<add><doc><field name=\"id\">104</field><field name=\"val_s\">pear</field></doc></add>");
+ assertU("<add><doc><field name=\"id\">105</field><field name=\"val_s\">appalling</field></doc></add>");
+ assertU("<add><doc><field name=\"id\">106</field><field name=\"val_s\">pearson</field></doc></add>");
+ assertU("<add><doc><field name=\"id\">107</field><field name=\"val_s\">port</field></doc></add>");
+ assertU("<commit/>");
+
+ assertQ(req("val_s:a*")
+ ,"//*[@numFound='3']"
+ );
+ assertQ(req("val_s:p*")
+ ,"//*[@numFound='4']"
+ );
+ // val_s:* %//*[@numFound="8"]
+
+
+ assertU("<delete><query>id:[100 TO 110]</query></delete>");
+
+ // test copyField functionality
+
+ assertU("<add><doc><field name=\"id\">42</field><field name=\"title\">How Now4 brown Cows</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("id:42 AND title:Now")
+ ,"*[count(//doc)=0]"
+ );
+ assertQ(req("id:42 AND title_lettertok:Now")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND title:cow")
+ ,"*[count(//doc)=0]"
+ );
+ assertQ(req("id:42 AND title_stemmed:cow")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND text:cow")
+ ,"*[count(//doc)=1]"
+ );
+
+ // test slop
+
+ assertU("<add><doc><field name=\"id\">42</field><field name=\"text\">foo bar</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("id:42 AND text:\"foo bar\"")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND text:\"foo\"")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND text:\"bar\"")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND text:\"bar foo\"")
+ ,"*[count(//doc)=0]"
+ );
+ assertQ(req("id:42 AND text:\"bar foo\"~2")
+ ,"*[count(//doc)=1]"
+ );
+
+
+ // intra-word delimiter testing (WordDelimiterFilter)
+
+ assertU("<add><doc><field name=\"id\">42</field><field name=\"subword\">foo bar</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("id:42 AND subword:\"foo bar\"")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:\"foo\"")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:\"bar\"")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:\"bar foo\"")
+ ,"*[count(//doc)=0]"
+ );
+ assertQ(req("id:42 AND subword:\"bar foo\"~2")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:\"foo/bar\"")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:\"foobar\"")
+ ,"*[count(//doc)=0]"
+ );
+
+ assertU("<add><doc><field name=\"id\">42</field><field name=\"subword\">foo-bar</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("id:42 AND subword:\"foo bar\"")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:\"foo\"")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:\"bar\"")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:\"bar foo\"")
+ ,"*[count(//doc)=0]"
+ );
+ assertQ(req("id:42 AND subword:\"bar foo\"~2")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:\"foo/bar\"")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:foobar")
+ ,"*[count(//doc)=1]"
+ );
+
+ assertU("<add><doc><field name=\"id\">42</field><field name=\"subword\">Canon PowerShot SD500 7MP</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("id:42 AND subword:\"power-shot\"")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:\"power shot sd 500\"")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:\"powershot\"")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:\"SD-500\"")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:\"SD500\"")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:\"SD500-7MP\"")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:\"PowerShotSD500-7MP\"")
+ ,"*[count(//doc)=1]"
+ );
+
+ assertU("<add><doc><field name=\"id\">42</field><field name=\"subword\">Wi-Fi</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("id:42 AND subword:wifi")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:wi+=fi")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:wi+=fi")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:WiFi")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:\"wi fi\"")
+ ,"*[count(//doc)=1]"
+ );
+
+ assertU("<add><doc><field name=\"id\">42</field><field name=\"subword\">'I.B.M' A's,B's,C's</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("id:42 AND subword:\"'I.B.M.'\"")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:I.B.M")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:IBM")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:I--B--M")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:\"I B M\"")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:IBM's")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:IBM'sx")
+ ,"*[count(//doc)=0]"
+ );
+
+ // this one fails since IBM and ABC are separated by two tokens
+
+ // id:42 AND subword:IBM's-ABC's %*[count(//doc)=1]
+
+ assertQ(req("id:42 AND subword:\"IBM's-ABC's\"~2")
+ ,"*[count(//doc)=1]"
+ );
+
+ assertQ(req("id:42 AND subword:\"A's B's-C's\"")
+ ,"*[count(//doc)=1]"
+ );
+
+ assertU("<add><doc><field name=\"id\">42</field><field name=\"subword\">Sony KDF-E50A10</field></doc></add>");
+ assertU("<commit/>");
+
+ // check for exact match:
+
+ // Sony KDF E/KDFE 50 A 10 (this is how it's indexed)
+
+ // Sony KDF E 50 A 10 (and how it's queried)
+
+ assertQ(req("id:42 AND subword:\"Sony KDF-E50A10\"")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:10")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:Sony")
+ ,"*[count(//doc)=1]"
+ );
+
+ // this one fails without slop since Sony and KDFE have a token inbetween
+
+ // id:42 AND subword:SonyKDFE50A10 %*[count(//doc)=1]
+
+ assertQ(req("id:42 AND subword:\"SonyKDFE50A10\"~10")
+ ,"*[count(//doc)=1]"
+ );
+
+ assertQ(req("id:42 AND subword:\"Sony KDF E-50-A-10\"")
+ ,"*[count(//doc)=1]"
+ );
+
+ assertU("<add><doc><field name=\"id\">42</field><field name=\"subword\">http://www.yahoo.com</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("id:42 AND subword:yahoo")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:www.yahoo.com")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:http://www.yahoo.com")
+ ,"*[count(//doc)=1]"
+ );
+
+ assertU("<add><doc><field name=\"id\">42</field><field name=\"subword\">--Q 1-- W2 E-3 Ok xY 4R 5-T *6-Y- 7-8-- 10A-B</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("id:42 AND subword:Q")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:1")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:\"w 2\"")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:\"e 3\"")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:\"o k\"")
+ ,"*[count(//doc)=0]"
+ );
+ assertQ(req("id:42 AND subword:\"ok\"")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:\"x y\"")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:\"xy\"")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:\"4 r\"")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:\"5 t\"")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:\"5 t\"")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:\"6 y\"")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:\"7 8\"")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:\"78\"")
+ ,"*[count(//doc)=1]"
+ );
+ assertQ(req("id:42 AND subword:\"10 A+B\"")
+ ,"*[count(//doc)=1]"
+ );
+
+ assertU("<add><doc><field name=\"id\">42</field><field name=\"subword\">FooBarBaz</field></doc></add>");
+ assertU("<add><doc><field name=\"id\">42</field><field name=\"subword\">FooBar10</field></doc></add>");
+ assertU("<add><doc><field name=\"id\">42</field><field name=\"subword\">10FooBar</field></doc></add>");
+ assertU("<add><doc><field name=\"id\">42</field><field name=\"subword\">BAZ</field></doc></add>");
+ assertU("<add><doc><field name=\"id\">42</field><field name=\"subword\">10</field></doc></add>");
+ assertU("<add><doc><field name=\"id\">42</field><field name=\"subword\">Mark, I found what's the problem! It turns to be from the latest schema. I found tons of exceptions in the resin.stdout that prevented the builder from performing. It's all coming from the WordDelimiterFilter which was just added to the latest schema: [2005-08-29 15:11:38.375] java.lang.IndexOutOfBoundsException: Index: 3, Size: 3 673804 [2005-08-29 15:11:38.375] at java.util.ArrayList.RangeCheck(ArrayList.java:547) 673805 [2005-08-29 15:11:38.375] at java.util.ArrayList.get(ArrayList.java:322) 673806 [2005-08-29 15:11:38.375] at solr.analysis.WordDelimiterFilter.addCombos(WordDelimiterFilter.java:349) 673807 [2005-08-29 15:11:38.375] at solr.analysis.WordDelimiterFilter.next(WordDelimiterFilter.java:325) 673808 [2005-08-29 15:11:38.375] at org.apache.lucene.analysis.LowerCaseFilter.next(LowerCaseFilter.java:32) 673809 [2005-08-29 15:11:38.375] at org.apache.lucene.analysis.StopFilter.next(Stop
Filter.java:98) 673810 [2005-08-29 15:11:38.375] at solr.EnglishPorterFilter.next(TokenizerFactory.java:163) 673811 [2005-08-29 15:11:38.375] at org.apache.lucene.index.DocumentWriter.invertDocument(DocumentWriter.java:143) 673812 [2005-08-29 15:11:38.375] at org.apache.lucene.index.DocumentWriter.addDocument(DocumentWriter.java:81) 673813 [2005-08-29 15:11:38.375] at org.apache.lucene.index.IndexWriter.addDocument(IndexWriter.java:307) 673814 [2005-08-29 15:11:38.375] at org.apache.lucene.index.IndexWriter.addDocument(IndexWriter.java:294) 673815 [2005-08-29 15:11:38.375] at solr.DirectUpdateHandler2.doAdd(DirectUpdateHandler2.java:170) 673816 [2005-08-29 15:11:38.375] at solr.DirectUpdateHandler2.overwriteBoth(DirectUpdateHandler2.java:317) 673817 [2005-08-29 15:11:38.375] at solr.DirectUpdateHandler2.addDoc(DirectUpdateHandler2.java:191) 673818 [2005-08-29 15:11:38.375] at solr.SolrCore.update(SolrCore.java:795) 673819 [2005-08-29 15:11:38.375] at solrserver.Sol
rServlet.doPost(SolrServlet.java:71) 673820 [2005-08-29 15:11:38.375] at javax.servlet.http.HttpServlet.service(HttpServlet.java:154) 673821 [2005-08-29 15:11:38.375] at javax.servlet.http.HttpServlet.service(HttpServlet.java:92) 673822 [2005-08-29 15:11:38.375] at com.caucho.server.dispatch.ServletFilterChain.doFilter(ServletFilterChain.java:99) 673823 [2005-08-29 15:11:38.375] at com.caucho.server.cache.CacheFilterChain.doFilter(CacheFilterChain.java:188) 673824 [2005-08-29 15:11:38.375] at com.caucho.server.webapp.WebAppFilterChain.doFilter(WebAppFilterChain.java:163) 673825 [2005-08-29 15:11:38.375] at com.caucho.server.dispatch.ServletInvocation.service(ServletInvocation.java:208) 673826 [2005-08-29 15:11:38.375] at com.caucho.server.http.HttpRequest.handleRequest(HttpRequest.java:259) 673827 [2005-08-29 15:11:38.375] at com.caucho.server.port.TcpConnection.run(TcpConnection.java:363) 673828 [2005-08-29 15:11:38.375] at com.caucho.util.ThreadPool.runTasks(Threa
dPool.java:490) 673829 [2005-08-29 15:11:38.375] at com.caucho.util.ThreadPool.run(ThreadPool.java:423) 673830 [2005-08-29 15:11:38.375] at java.lang.Thread.run(Thread.java:595) With the previous schema I'm able to perform a successful full build: http://c12-ssa-dev40-so-mas1.cnet.com:5078/select/?stylesheet=q=docTypeversion=2.0start=0rows=10indent=on Do you want to rollback to the previous schema version</field></doc></add>");
+
+
+ //
+
+ assertU("<delete fromPending=\"true\" fromCommitted=\"true\"><id>44</id></delete>");
+ assertU("<add><doc><field name=\"id\">44</field><field name=\"fname_s\">Yonik</field><field name=\"here_b\">true</field><field name=\"iq_l\">10000000000</field><field name=\"description_t\">software engineer</field><field name=\"ego_d\">1e100</field><field name=\"pi_f\">3.1415962</field><field name=\"when_dt\">2005-03-18T01:14:34Z</field><field name=\"arr_f\">1.414213562</field><field name=\"arr_f\">.999</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("id:44")
+ );
+ args = new HashMap<String,String>();
+ args.put("version","2.0");
+ args.put("fl","fname_s,arr_f ");
+ req = new LocalSolrQueryRequest(h.getCore(), "id:44",
+ "standard", 0, 10, args);
+ assertQ(req
+ ,"//str[.='Yonik'] "
+ ,"//float[.='1.4142135']"
+ );
+ args = new HashMap<String,String>();
+ args.put("version","2.0");
+ args.put("fl"," ");
+ req = new LocalSolrQueryRequest(h.getCore(), "id:44",
+ "standard", 0, 10, args);
+ assertQ(req
+ ,"//str[.='Yonik'] "
+ ,"//float[.='1.4142135']"
+ );
+
+ // test addition of score field
+
+ args = new HashMap<String,String>();
+ args.put("version","2.0");
+ args.put("fl","score ");
+ req = new LocalSolrQueryRequest(h.getCore(), "id:44",
+ "standard", 0, 10, args);
+ assertQ(req
+ ,"//str[.='Yonik'] "
+ ,"//float[.='1.4142135'] "
+ ,"//float[@name='score'] "
+ ,"*[count(//doc/*)=10]"
+ );
+ args = new HashMap<String,String>();
+ args.put("version","2.0");
+ args.put("fl","*,score ");
+ req = new LocalSolrQueryRequest(h.getCore(), "id:44",
+ "standard", 0, 10, args);
+ assertQ(req
+ ,"//str[.='Yonik'] "
+ ,"//float[.='1.4142135'] "
+ ,"//float[@name='score'] "
+ ,"*[count(//doc/*)=10]"
+ );
+ args = new HashMap<String,String>();
+ args.put("version","2.0");
+ args.put("fl","* ");
+ req = new LocalSolrQueryRequest(h.getCore(), "id:44",
+ "standard", 0, 10, args);
+ assertQ(req
+ ,"//str[.='Yonik'] "
+ ,"//float[.='1.4142135'] "
+ ,"*[count(//doc/*)>=9]"
+ );
+
+ // test maxScore
+
+ args = new HashMap<String,String>();
+ args.put("version","2.0");
+ args.put("fl","score ");
+ req = new LocalSolrQueryRequest(h.getCore(), "id:44",
+ "standard", 0, 10, args);
+ assertQ(req
+ ,"//result[@maxScore>0]"
+ );
+ args = new HashMap<String,String>();
+ args.put("version","2.0");
+ args.put("fl","score ");
+ req = new LocalSolrQueryRequest(h.getCore(), "id:44;id desc;",
+ "standard", 0, 10, args);
+ assertQ(req
+ ,"//result[@maxScore>0]"
+ );
+ args = new HashMap<String,String>();
+ args.put("version","2.0");
+ args.put("fl","score ");
+ req = new LocalSolrQueryRequest(h.getCore(), "id:44;",
+ "standard", 0, 10, args);
+ assertQ(req
+ ,"//@maxScore = //doc/float[@name='score']"
+ );
+ args = new HashMap<String,String>();
+ args.put("version","2.0");
+ args.put("fl","score ");
+ req = new LocalSolrQueryRequest(h.getCore(), "id:44;id desc;",
+ "standard", 0, 10, args);
+ assertQ(req
+ ,"//@maxScore = //doc/float[@name='score']"
+ );
+ args = new HashMap<String,String>();
+ args.put("version","2.0");
+ args.put("fl","score");
+ req = new LocalSolrQueryRequest(h.getCore(), "id:44;id desc;",
+ "standard", 0, 0 , args);
+ assertQ(req
+ ,"//result[@maxScore>0]"
+ );
+
+
+ // test schema field attribute inheritance and overriding
+
+ assertU("<delete><id>44</id></delete>");
+ assertU("<add><doc><field name=\"id\">44</field><field name=\"shouldbestored\">hi</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("id:44")
+ ,"//*[@name='shouldbestored']"
+ );
+ assertQ(req("+id:44 +shouldbestored:hi")
+ ,"//*[@numFound='1']"
+ );
+
+ assertU("<delete><id>44</id></delete>");
+ assertU("<add><doc><field name=\"id\">44</field><field name=\"shouldbeunstored\">hi</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("id:44")
+ ,"not(//*[@name='shouldbeunstored'])"
+ );
+ assertQ(req("+id:44 +shouldbeunstored:hi")
+ ,"//*[@numFound='1']"
+ );
+
+ assertU("<delete><id>44</id></delete>");
+ assertU("<add><doc><field name=\"id\">44</field><field name=\"shouldbeunindexed\">hi</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("id:44")
+ ,"//*[@name='shouldbeunindexed']"
+ );
+ // this should result in an error... how to check for that?
+
+ // +id:44 +shouldbeunindexed:hi %//*[@numFound="0"]
+
+
+ // test spaces between XML elements because that can introduce extra XML events that
+
+ // can mess up parsing (and it has in the past)
+
+ assertU(" <delete> <id>44</id> </delete>");
+ assertU(" <add> <doc> <field name=\"id\">44</field> <field name=\"shouldbestored\">hi</field> </doc> </add>");
+ assertU(" <commit />");
+
+ // test adding multiple docs per add command
+
+ // assertU("<delete><query>id:[0 TO 99]</query></delete>");
+ // assertU("<add><doc><field name=\"id\">1</field></doc><doc><field name=\"id\">2</field></doc></add>");
+ // assertU("<commit/>");
+ // assertQ(req("id:[0 TO 99]")
+ // ,"//*[@numFound='2']"
+ // );
+
+ // test synonym filter
+
+ assertU("<delete><query>id:[10 TO 100]</query></delete>");
+ assertU("<add><doc><field name=\"id\">10</field><field name=\"syn\">a</field></doc></add>");
+ assertU("<add><doc><field name=\"id\">11</field><field name=\"syn\">b</field></doc></add>");
+ assertU("<add><doc><field name=\"id\">12</field><field name=\"syn\">c</field></doc></add>");
+ assertU("<add><doc><field name=\"id\">13</field><field name=\"syn\">foo</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("id:10 AND syn:a")
+ ,"//*[@numFound='1']"
+ );
+ assertQ(req("id:10 AND syn:aa")
+ ,"//*[@numFound='1']"
+ );
+ assertQ(req("id:11 AND syn:b")
+ ,"//*[@numFound='1']"
+ );
+ assertQ(req("id:11 AND syn:b1")
+ ,"//*[@numFound='1']"
+ );
+ assertQ(req("id:11 AND syn:b2")
+ ,"//*[@numFound='1']"
+ );
+ assertQ(req("id:12 AND syn:c")
+ ,"//*[@numFound='1']"
+ );
+ assertQ(req("id:12 AND syn:c1")
+ ,"//*[@numFound='1']"
+ );
+ assertQ(req("id:12 AND syn:c2")
+ ,"//*[@numFound='1']"
+ );
+ assertQ(req("id:13 AND syn:foo")
+ ,"//*[@numFound='1']"
+ );
+ assertQ(req("id:13 AND syn:bar")
+ ,"//*[@numFound='1']"
+ );
+ assertQ(req("id:13 AND syn:baz")
+ ,"//*[@numFound='1']"
+ );
+
+
+ // test position increment gaps between field values
+
+ assertU("<delete><id>44</id></delete>");
+ assertU("<delete><id>45</id></delete>");
+ assertU("<add><doc><field name=\"id\">44</field><field name=\"textgap\">aa bb cc</field><field name=\"textgap\">dd ee ff</field></doc></add>");
+ assertU("<add><doc><field name=\"id\">45</field><field name=\"text\">aa bb cc</field><field name=\"text\">dd ee ff</field></doc></add>");
+ assertU("<commit/>");
+ assertQ(req("+id:44 +textgap:\"aa bb cc\"")
+ ,"//*[@numFound='1']"
+ );
+ assertQ(req("+id:44 +textgap:\"dd ee ff\"")
+ ,"//*[@numFound='1']"
+ );
+ assertQ(req("+id:44 +textgap:\"cc dd\"")
+ ,"//*[@numFound='0']"
+ );
+ assertQ(req("+id:44 +textgap:\"cc dd\"~100")
+ ,"//*[@numFound='1']"
+ );
+ assertQ(req("+id:44 +textgap:\"bb cc dd ee\"~90")
+ ,"//*[@numFound='0']"
+ );
+ assertQ(req("+id:44 +textgap:\"bb cc dd ee\"~100")
+ ,"//*[@numFound='1']"
+ );
+ assertQ(req("+id:45 +text:\"cc dd\"")
+ ,"//*[@numFound='1']"
+ );
+
+
+ // trigger output of custom value test
+
+ args = new HashMap<String,String>();
+ args.put("version","2.0");
+ req = new LocalSolrQueryRequest(h.getCore(), "values",
+ "test", 0, 10, args);
+ assertQ(req
+ );
+
+ }
+}