SOLR-1371: LukeRequestHandler/schema.jsp errored if schema had no uniqueKey field. The new test for this also (hopefully) adds some future proofing against similar bugs in the future. As a side effect QueryElevationComponentTest was refactored, and a bug in that test was found.

git-svn-id: https://svn.apache.org/repos/asf/lucene/solr/trunk@806289 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Chris M. Hostetter 2009-08-20 18:23:36 +00:00
parent e1f8e33cd9
commit 48109b3dc6
7 changed files with 404 additions and 19 deletions

View File

@ -482,6 +482,12 @@ Bug Fixes
57. SOLR-1360: Prevent PhoneticFilter from producing duplicate tokens. (yonik) 57. SOLR-1360: Prevent PhoneticFilter from producing duplicate tokens. (yonik)
58. SOLR-1371: LukeRequestHandler/schema.jsp errored if schema had no
uniqueKey field. The new test for this also (hopefully) adds some
future proofing against similar bugs in the future. As a side
effect QueryElevationComponentTest was refactored, and a bug in
that test was found. (hossman)
Other Changes Other Changes
---------------------- ----------------------
1. Upgraded to Lucene 2.4.0 (yonik) 1. Upgraded to Lucene 2.4.0 (yonik)

View File

@ -370,7 +370,8 @@ public class LukeRequestHandler extends RequestHandlerBase
SimpleOrderedMap<Object> finfo = new SimpleOrderedMap<Object>(); SimpleOrderedMap<Object> finfo = new SimpleOrderedMap<Object>();
finfo.add("fields", fields); finfo.add("fields", fields);
finfo.add("dynamicFields", dynamicFields); finfo.add("dynamicFields", dynamicFields);
finfo.add("uniqueKeyField", uniqueField.getName()); finfo.add("uniqueKeyField",
null == uniqueField ? null : uniqueField.getName());
finfo.add("defaultSearchField", schema.getDefaultSearchFieldName()); finfo.add("defaultSearchField", schema.getDefaultSearchFieldName());
finfo.add("types", types); finfo.add("types", types);
return finfo; return finfo;

View File

@ -0,0 +1,129 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.Set;
/**
* A test of basic features using the minial legal solr schema.
*/
public class MinimalSchemaTest extends AbstractSolrTestCase {
public String getSchemaFile() { return "solr/conf/schema-minimal.xml"; }
/**
* NOTE: we explicilty use the general 'solrconfig.xml' file here, in
* an attempt to test as many braod features as possible.
*
* Do not change this to point at some other "simpler" solrconfig.xml
* just because you want to add a new test case using solrconfig.xml,
* but your new testcase adds a feature that breaks this test.
*/
public String getSolrConfigFile() { return "solr/conf/solrconfig.xml"; }
public void setUp() throws Exception {
super.setUp();
/* make sure some missguided soul doesn't inadvertantly give us
a uniqueKey field and defeat the point of hte tests
*/
assertNull("UniqueKey Field isn't null",
h.getCore().getSchema().getUniqueKeyField());
lrf.args.put("version","2.0");
assertU("Simple assertion that adding a document works",
adoc("id", "4055",
"subject", "Hoss",
"project", "Solr"));
assertU(adoc("id", "4056",
"subject", "Yonik",
"project", "Solr"));
assertU(commit());
assertU(optimize());
}
public void testSimpleQueries() {
assertQ("couldn't find subject hoss",
req("subject:Hoss")
,"//result[@numFound=1]"
,"//str[@name='id'][.='4055']"
);
assertQ("couldn't find subject Yonik",
req("subject:Yonik")
,"//result[@numFound=1]"
,"//str[@name='id'][.='4056']"
);
}
/** SOLR-1371 */
public void testLuke() {
assertQ("basic luke request failed",
req("qt", "/admin/luke")
,"//int[@name='numDocs'][.='2']"
,"//int[@name='numTerms'][.='5']"
);
assertQ("luke show schema failed",
req("qt", "/admin/luke",
"show","schema")
,"//int[@name='numDocs'][.='2']"
,"//int[@name='numTerms'][.='5']"
,"//null[@name='uniqueKeyField']"
,"//null[@name='defaultSearchField']"
);
}
/**
* Iterates over all (non "/update/*") handlers in the core and hits
* them with a request (using some simple params) to verify that they
* don't generate an error against the minimal schema
*/
public void testAllConfiguredHandlers() {
Set<String> handlerNames = h.getCore().getRequestHandlers().keySet();
for (String handler : handlerNames) {
try {
if (handler.startsWith("/update")) {
continue;
}
assertQ("failure w/handler: '" + handler + "'",
req("qt", handler,
// this should be fairly innoculous for any type of query
"q", "foo:bar")
,"//lst[@name='responseHeader']"
);
} catch (Exception e) {
throw new RuntimeException("exception w/handler: '" + handler + "'",
e);
}
}
}
}

View File

@ -40,7 +40,7 @@ import org.apache.solr.util.AbstractSolrTestCase;
public class QueryElevationComponentTest extends AbstractSolrTestCase { public class QueryElevationComponentTest extends AbstractSolrTestCase {
@Override public String getSchemaFile() { return "schema12.xml"; } @Override public String getSchemaFile() { return "schema12.xml"; }
@Override public String getSolrConfigFile() { return "solrconfig.xml"; } @Override public String getSolrConfigFile() { return "solrconfig-elevate.xml"; }
public void testInterface() throws Exception public void testInterface() throws Exception
{ {
@ -89,13 +89,12 @@ public class QueryElevationComponentTest extends AbstractSolrTestCase {
public void testEmptyQuery() throws Exception { public void testEmptyQuery() throws Exception {
SolrCore core = h.getCore(); SolrCore core = h.getCore();
//String query = "title:ipod"; //String query = "title:ipod";
Map<String,String> args = new HashMap<String, String>(); Map<String,String> args = new HashMap<String, String>();
args.put( "q.alt", "*:*" ); args.put( "q.alt", "*:*" );
args.put( "defType", "dismax"); args.put( "defType", "dismax");
args.put( CommonParams.QT, "/elevate" );
//args.put( CommonParams.FL, "id,title,score" ); //args.put( CommonParams.FL, "id,title,score" );
SolrQueryRequest req = new LocalSolrQueryRequest( core, new MapSolrParams( args) ); SolrQueryRequest req = new LocalSolrQueryRequest( core, new MapSolrParams( args) );
assertQ("Make sure QEC handles null queries", req, "//*[@numFound='0']"); assertQ("Make sure QEC handles null queries", req, "//*[@numFound='0']");

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You 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.
-->
<schema name="minimal" version="1.1">
<types>
<fieldType name="string" class="solr.StrField"/>
</types>
<fields>
<dynamicField name="*" type="string" indexed="true" stored="true" />
</fields>
</schema>

View File

@ -0,0 +1,223 @@
<?xml version="1.0" ?>
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You 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.
-->
<!-- $Id: solrconfig.xml 382610 2006-03-03 01:43:03Z yonik $
$Source$
$Name$
-->
<config>
<jmx />
<!-- Used to specify an alternate directory to hold all index data.
It defaults to "index" if not present, and should probably
not be changed if replication is in use. -->
<dataDir>${solr.data.dir:./solr/data}</dataDir>
<indexDefaults>
<!-- Values here affect all index writers and act as a default
unless overridden. -->
<!-- Values here affect all index writers and act as a default unless overridden. -->
<useCompoundFile>false</useCompoundFile>
<mergeFactor>10</mergeFactor>
<!-- If both ramBufferSizeMB and maxBufferedDocs is set, then Lucene will flush based on whichever limit is hit first.
-->
<!--<maxBufferedDocs>1000</maxBufferedDocs>-->
<!-- Tell Lucene when to flush documents to disk.
Giving Lucene more memory for indexing means faster indexing at the cost of more RAM
If both ramBufferSizeMB and maxBufferedDocs is set, then Lucene will flush based on whichever limit is hit first.
-->
<ramBufferSizeMB>32</ramBufferSizeMB>
<maxMergeDocs>2147483647</maxMergeDocs>
<maxFieldLength>10000</maxFieldLength>
<writeLockTimeout>1000</writeLockTimeout>
<commitLockTimeout>10000</commitLockTimeout>
<!--
Expert: Turn on Lucene's auto commit capability.
NOTE: Despite the name, this value does not have any relation to Solr's autoCommit functionality
-->
<luceneAutoCommit>false</luceneAutoCommit>
<!--
Expert:
The Merge Policy in Lucene controls how merging is handled by Lucene. The default in 2.3 is the LogByteSizeMergePolicy, previous
versions used LogDocMergePolicy.
LogByteSizeMergePolicy chooses segments to merge based on their size. The Lucene 2.2 default, LogDocMergePolicy chose when
to merge based on number of documents
Other implementations of MergePolicy must have a no-argument constructor
-->
<mergePolicy>org.apache.lucene.index.LogByteSizeMergePolicy</mergePolicy>
<!--
Expert:
The Merge Scheduler in Lucene controls how merges are performed. The ConcurrentMergeScheduler (Lucene 2.3 default)
can perform merges in the background using separate threads. The SerialMergeScheduler (Lucene 2.2 default) does not.
-->
<mergeScheduler>org.apache.lucene.index.ConcurrentMergeScheduler</mergeScheduler>
<!-- these are global... can't currently override per index -->
<writeLockTimeout>1000</writeLockTimeout>
<commitLockTimeout>10000</commitLockTimeout>
<lockType>single</lockType>
</indexDefaults>
<mainIndex>
<!-- lucene options specific to the main on-disk lucene index -->
<useCompoundFile>false</useCompoundFile>
<mergeFactor>10</mergeFactor>
<!-- for better multi-segment testing, we are using slower
indexing properties of maxBufferedDocs=10 and LogDocMergePolicy.
-->
<maxBufferedDocs>10</maxBufferedDocs>
<maxMergeDocs>2147483647</maxMergeDocs>
<maxFieldLength>10000</maxFieldLength>
<mergePolicy>org.apache.lucene.index.LogDocMergePolicy</mergePolicy>
<unlockOnStartup>true</unlockOnStartup>
</mainIndex>
<updateHandler class="solr.DirectUpdateHandler2">
<!-- autocommit pending docs if certain criteria are met
<autoCommit>
<maxDocs>10000</maxDocs>
<maxTime>3600000</maxTime>
</autoCommit>
-->
<!-- represents a lower bound on the frequency that commits may
occur (in seconds). NOTE: not yet implemented
<commitIntervalLowerBound>0</commitIntervalLowerBound>
-->
<!-- The RunExecutableListener executes an external command.
exe - the name of the executable to run
dir - dir to use as the current working directory. default="."
wait - the calling thread waits until the executable returns. default="true"
args - the arguments to pass to the program. default=nothing
env - environment variables to set. default=nothing
-->
<!-- A postCommit event is fired after every commit
<listener event="postCommit" class="solr.RunExecutableListener">
<str name="exe">/var/opt/resin3/__PORT__/scripts/solr/snapshooter</str>
<str name="dir">/var/opt/resin3/__PORT__</str>
<bool name="wait">true</bool>
<arr name="args"> <str>arg1</str> <str>arg2</str> </arr>
<arr name="env"> <str>MYVAR=val1</str> </arr>
</listener>
-->
</updateHandler>
<query>
<!-- Maximum number of clauses in a boolean query... can affect
range or wildcard queries that expand to big boolean
queries. An exception is thrown if exceeded.
-->
<maxBooleanClauses>1024</maxBooleanClauses>
<!-- Cache specification for Filters or DocSets - unordered set of *all* documents
that match a particular query.
-->
<filterCache
class="solr.search.FastLRUCache"
size="512"
initialSize="512"
autowarmCount="256"/>
<queryResultCache
class="solr.search.LRUCache"
size="512"
initialSize="512"
autowarmCount="1024"/>
<documentCache
class="solr.search.LRUCache"
size="512"
initialSize="512"
autowarmCount="0"/>
<!-- If true, stored fields that are not requested will be loaded lazily.
-->
<enableLazyFieldLoading>true</enableLazyFieldLoading>
<queryResultWindowSize>10</queryResultWindowSize>
<!-- set maxSize artificially low to exercise both types of sets -->
<HashDocSet maxSize="3" loadFactor="0.75"/>
<!-- boolToFilterOptimizer converts boolean clauses with zero boost
into cached filters if the number of docs selected by the clause exceeds
the threshold (represented as a fraction of the total index)
-->
<boolTofilterOptimizer enabled="false" cacheSize="32" threshold=".05"/>
</query>
<requestHandler name="/update" class="solr.XmlUpdateRequestHandler" />
<!-- test elevation -->
<searchComponent name="elevate" class="org.apache.solr.handler.component.QueryElevationComponent" >
<str name="queryFieldType">string</str>
<str name="config-file">elevate.xml</str>
</searchComponent>
<requestHandler name="/elevate" class="org.apache.solr.handler.component.SearchHandler">
<lst name="defaults">
<str name="echoParams">explicit</str>
</lst>
<arr name="last-components">
<str>elevate</str>
</arr>
</requestHandler>
<!-- enable streaming for testing... -->
<requestDispatcher handleSelect="true" >
<requestParsers enableRemoteStreaming="true" multipartUploadLimitInKB="2048" />
<httpCaching lastModifiedFrom="openTime" etagSeed="Solr" never304="false">
<cacheControl>max-age=30, public</cacheControl>
</httpCaching>
</requestDispatcher>
<admin>
<defaultQuery>solr</defaultQuery>
<gettableFiles>solrconfig.xml scheam.xml admin-extra.html</gettableFiles>
</admin>
<!-- test getting system property -->
<propTest attr1="${solr.test.sys.prop1}-$${literal}"
attr2="${non.existent.sys.prop:default-from-config}">prefix-${solr.test.sys.prop2}-suffix</propTest>
<queryParser name="foo" class="FooQParserPlugin"/>
</config>

View File

@ -20,6 +20,20 @@
<!-- $Id: solrconfig.xml 382610 2006-03-03 01:43:03Z yonik $ <!-- $Id: solrconfig.xml 382610 2006-03-03 01:43:03Z yonik $
$Source$ $Source$
$Name$ $Name$
This is a "kitchen sink" config file that tests can use.
When writting a new test, feel free to add *new* items (plugins,
config options, etc...) as long as they don't break any existing
tests. if you need to test something esoteric please add a new
"solrconfig-your-esoteric-purpose.xml" config file.
Note in particular that this test is used by MinimalSchemaTest so
Anything added to this file needs to work correctly even if there
is now uniqueKey or defaultSearch Field.
--> -->
<config> <config>
@ -244,6 +258,7 @@
it's init params as "defaults" if there is no "defaults" list it's init params as "defaults" if there is no "defaults" list
specified specified
--> -->
<str name="q.alt">*:*</str>
<float name="tie">0.01</float> <float name="tie">0.01</float>
<str name="qf"> <str name="qf">
text^0.5 features_t^1.0 subject^1.4 title_stemmed^2.0 text^0.5 features_t^1.0 subject^1.4 title_stemmed^2.0
@ -289,6 +304,8 @@
<lst name="lst2"> <str name="op">log</str> <float name="val">10</float> </lst> <lst name="lst2"> <str name="op">log</str> <float name="val">10</float> </lst>
</requestHandler> </requestHandler>
<requestHandler name="/admin/" class="org.apache.solr.handler.admin.AdminHandlers" />
<requestHandler name="test" class="solr.tst.TestRequestHandler" /> <requestHandler name="test" class="solr.tst.TestRequestHandler" />
<!-- test query parameter defaults --> <!-- test query parameter defaults -->
@ -314,21 +331,6 @@
<bool name="httpCaching">false</bool> <bool name="httpCaching">false</bool>
</requestHandler> </requestHandler>
<!-- test elevation -->
<searchComponent name="elevate" class="org.apache.solr.handler.component.QueryElevationComponent" >
<str name="queryFieldType">string</str>
<str name="config-file">elevate.xml</str>
</searchComponent>
<requestHandler name="/elevate" class="org.apache.solr.handler.component.SearchHandler">
<lst name="defaults">
<str name="echoParams">explicit</str>
</lst>
<arr name="last-components">
<str>elevate</str>
</arr>
</requestHandler>
<searchComponent name="spellcheck" class="org.apache.solr.handler.component.SpellCheckComponent"> <searchComponent name="spellcheck" class="org.apache.solr.handler.component.SpellCheckComponent">
<str name="queryAnalyzerFieldType">lowerfilt</str> <str name="queryAnalyzerFieldType">lowerfilt</str>