2
* Licensed to the Apache Software Foundation (ASF) under one or more
3
* contributor license agreements. See the NOTICE file distributed with
4
* this work for additional information regarding copyright ownership.
5
* The ASF licenses this file to You under the Apache License, Version 2.0
6
* (the "License"); you may not use this file except in compliance with
7
* the License. You may obtain a copy of the License at
9
* http://www.apache.org/licenses/LICENSE-2.0
11
* Unless required by applicable law or agreed to in writing, software
12
* distributed under the License is distributed on an "AS IS" BASIS,
13
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
* See the License for the specific language governing permissions and
15
* limitations under the License.
18
package org.apache.solr;
20
import java.io.ByteArrayInputStream;
21
import java.io.IOException;
22
import java.io.StringWriter;
23
import java.util.HashMap;
26
import javax.xml.parsers.DocumentBuilder;
27
import javax.xml.parsers.DocumentBuilderFactory;
29
import org.apache.lucene.document.Field;
30
import org.apache.lucene.document.Fieldable;
31
import org.apache.lucene.index.LogMergePolicy;
32
import org.apache.lucene.search.BooleanQuery;
33
import org.apache.lucene.search.Query;
35
import org.apache.solr.common.SolrException;
36
import org.apache.solr.common.SolrException.ErrorCode;
37
import org.apache.solr.common.params.AppendedSolrParams;
38
import org.apache.solr.common.params.CommonParams;
39
import org.apache.solr.common.params.DefaultSolrParams;
40
import org.apache.solr.common.params.MapSolrParams;
41
import org.apache.solr.common.params.SolrParams;
42
import org.apache.solr.common.util.NamedList;
43
import org.apache.solr.core.SolrCore;
44
import org.apache.solr.handler.RequestHandlerBase;
45
import org.apache.solr.request.LocalSolrQueryRequest;
46
import org.apache.solr.request.SolrQueryRequest;
47
import org.apache.solr.request.SolrRequestHandler;
48
import org.apache.solr.response.SolrQueryResponse;
49
import org.apache.solr.response.XMLWriter;
50
import org.apache.solr.schema.IndexSchema;
51
import org.apache.solr.schema.SchemaField;
52
import org.apache.solr.search.DocIterator;
53
import org.apache.solr.search.DocList;
54
import org.apache.solr.search.QueryParsing;
55
import org.apache.solr.update.SolrIndexWriter;
58
import org.junit.BeforeClass;
59
import org.junit.Test;
62
* Tests some basic functionality of Solr while demonstrating good
63
* Best Practices for using AbstractSolrTestCase
65
public class BasicFunctionalityTest extends SolrTestCaseJ4 {
68
public String getCoreName() { return "basic"; }
71
public static void beforeTests() throws Exception {
72
initCore("solrconfig.xml","schema.xml");
74
// tests the performance of dynamic field creation and
75
// field property testing.
77
public void testFieldPerf() {
78
IndexSchema schema = h.getCore().getSchema();
79
SchemaField[] fields = schema.getDynamicFieldPrototypes();
80
boolean createNew = false;
82
long start = System.currentTimeMillis();
84
for (int i=0; i<10000000; i++) {
85
for (SchemaField f : fields) {
86
if (createNew) f = new SchemaField(f, "fakename");
87
if (f.indexed()) ret += 1;
88
if (f.isCompressed()) ret += 2;
89
if (f.isRequired()) ret += 3;
90
if (f.multiValued()) ret += 4;
91
if (f.omitNorms()) ret += 5;
92
if (f.sortMissingFirst()) ret += 6;
93
if (f.sortMissingLast())ret += 7;
94
if (f.stored()) ret += 8;
95
if (f.storeTermOffsets()) ret += 9;
96
if (f.storeTermPositions()) ret += 10;
97
if (f.storeTermVector()) ret += 11;
100
long end = System.currentTimeMillis();
101
System.out.println("ret=" + ret + " time="+ (end-start));
106
public void testIgnoredFields() throws Exception {
107
lrf.args.put("version","2.0");
108
assertU("adding doc with ignored field",
109
adoc("id", "42", "foo_ignored", "blah blah"));
113
// :TODO: the behavior of querying on an unindexed field should be better specified in the future.
114
assertQ("query with ignored field",
115
req("bar_ignored:yo id:42")
116
,"//*[@numFound='1']"
117
,"//int[@name='id'][.='42']"
122
public void testSomeStuff() throws Exception {
123
// test merge factor picked up
124
SolrCore core = h.getCore();
126
SolrIndexWriter writer = new SolrIndexWriter("testWriter",core.getNewIndexDir(), core.getDirectoryFactory(), false, core.getSchema(), core.getSolrConfig().mainIndexConfig, core.getDeletionPolicy());
127
assertEquals("Mergefactor was not picked up", ((LogMergePolicy) writer.getConfig().getMergePolicy()).getMergeFactor(), 8);
130
lrf.args.put("version","2.0");
131
assertQ("test query on empty index",
132
req("qlkciyopsbgzyvkylsjhchghjrdf")
133
,"//result[@numFound='0']"
136
// test escaping of ";"
137
assertU("deleting 42 for no reason at all",
139
assertU("adding doc#42",
140
adoc("id", "42", "val_s", "aa;bb"));
141
assertU("does commit work?",
144
assertQ("backslash escaping semicolon",
145
req("id:42 AND val_s:aa\\;bb")
146
,"//*[@numFound='1']"
147
,"//int[@name='id'][.='42']"
150
assertQ("quote escaping semicolon",
151
req("id:42 AND val_s:\"aa;bb\"")
152
,"//*[@numFound='1']"
153
,"//int[@name='id'][.='42']"
156
assertQ("no escaping semicolon",
157
req("id:42 AND val_s:aa")
158
,"//*[@numFound='0']"
164
,"//*[@numFound='0']"
167
// test allowDups default of false
169
assertU(adoc("id", "42", "val_s", "AAA"));
170
assertU(adoc("id", "42", "val_s", "BBB"));
173
,"//*[@numFound='1']"
176
assertU(adoc("id", "42", "val_s", "CCC"));
177
assertU(adoc("id", "42", "val_s", "DDD"));
180
,"//*[@numFound='1']"
185
String [] adds = new String[] {
186
add( doc("id","101"), "allowDups", "false" ),
187
add( doc("id","101"), "allowDups", "false" ),
188
add( doc("id","105"), "allowDups", "true" ),
189
add( doc("id","102"), "allowDups", "false" ),
190
add( doc("id","103"), "allowDups", "true" ),
191
add( doc("id","101"), "allowDups", "false" ),
193
for (String a : adds) {
199
assertQ(req("q","id:[100 TO 110]", "rows","2147483647")
200
,"//*[@numFound='4']"
204
assertQ(req("q","id:[100 TO 111]", "rows","1147483647")
205
,"//*[@numFound='4']"
208
assertQ(req("id:[100 TO 110]")
209
,"//*[@numFound='4']"
211
assertU(delI("102"));
213
assertQ(req("id:[100 TO 110]")
214
,"//*[@numFound='3']"
216
assertU(delI("105"));
218
assertQ(req("id:[100 TO 110]")
219
,"//*[@numFound='2']"
221
assertU(delQ("id:[100 TO 110]"));
223
assertQ(req("id:[100 TO 110]")
224
,"//*[@numFound='0']"
229
public void testRequestHandlerBaseException() {
230
final String tmp = "BOO! ignore_exception";
231
SolrRequestHandler handler = new RequestHandlerBase() {
233
public String getDescription() { return tmp; }
235
public String getSourceId() { return tmp; }
237
public String getSource() { return tmp; }
239
public String getVersion() { return tmp; }
241
public void handleRequestBody
242
( SolrQueryRequest req, SolrQueryResponse rsp ) {
243
throw new RuntimeException(tmp);
246
handler.init(new NamedList());
247
SolrQueryResponse rsp = new SolrQueryResponse();
248
SolrQueryRequest req = req();
249
h.getCore().execute(handler,
252
assertNotNull("should have found an exception", rsp.getException());
257
public void testMultipleUpdatesPerAdd() {
259
// big freaking kludge since the response is currently not well formed.
260
String res = h.update("<add><doc><field name=\"id\">1</field></doc><doc><field name=\"id\">2</field></doc></add>");
261
assertEquals("<result status=\"0\"></result>", res);
262
assertU("<commit/>");
263
assertQ(req("id:[0 TO 99]")
264
,"//*[@numFound='2']"
270
public void testDocBoost() throws Exception {
271
String res = h.update("<add>" + "<doc><field name=\"id\">1</field>"+
272
"<field name=\"text\">hello</field></doc>" +
273
"<doc boost=\"2.0\"><field name=\"id\">2</field>" +
274
"<field name=\"text\">hello</field></doc>" +
277
assertEquals("<result status=\"0\"></result>", res);
278
assertU("<commit/>");
279
assertQ(req("text:hello")
280
,"//*[@numFound='2']"
282
String resp = h.query(lrf.makeRequest("q", "text:hello", "debugQuery", "true"));
283
//System.out.println(resp);
284
// second doc ranked first
285
assertTrue( resp.indexOf("\"2\"") < resp.indexOf("\"1\"") );
289
public void testFieldBoost() throws Exception {
290
String res = h.update("<add>" + "<doc><field name=\"id\">1</field>"+
291
"<field name=\"text\">hello</field></doc>" +
292
"<doc><field name=\"id\">2</field>" +
293
"<field boost=\"2.0\" name=\"text\">hello</field></doc>" +
296
assertEquals("<result status=\"0\"></result>", res);
297
assertU("<commit/>");
298
assertQ(req("text:hello"),
301
String resp = h.query(lrf.makeRequest("q", "text:hello", "debugQuery", "true"));
302
//System.out.println(resp);
303
// second doc ranked first
304
assertTrue( resp.indexOf("\"2\"") < resp.indexOf("\"1\"") );
308
public void testXMLWriter() throws Exception {
310
SolrQueryResponse rsp = new SolrQueryResponse();
311
rsp.add("\"quoted\"", "\"value\"");
313
StringWriter writer = new StringWriter(32000);
314
SolrQueryRequest req = req("foo");
315
XMLWriter.writeResponse(writer,req,rsp);
317
DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
318
builder.parse(new ByteArrayInputStream
319
(writer.toString().getBytes("UTF-8")));
324
public void testLocalSolrQueryRequestParams() {
325
HashMap args = new HashMap();
326
args.put("string", "string value");
327
args.put("array", new String[] {"array", "value"});
328
SolrQueryRequest req = new LocalSolrQueryRequest(null, null, null, 0, 20, args);
329
assertEquals("string value", req.getParams().get("string"));
330
assertEquals("array", req.getParams().get("array"));
332
String[] stringParams = req.getParams().getParams("string");
333
assertEquals(1, stringParams.length);
334
assertEquals("string value", stringParams[0]);
336
String[] arrayParams = req.getParams().getParams("array");
337
assertEquals(2, arrayParams.length);
338
assertEquals("array", arrayParams[0]);
339
assertEquals("value", arrayParams[1]);
344
public void testKeywordTokenizerFactory() {
346
assertU(adoc("id", "42",
347
"keywordtok", "How nOw broWn-ish C.o.w. ?"));
349
assertQ("stored value matches?",
351
,"//str[.='How nOw broWn-ish C.o.w. ?']"
353
assertQ("query on exact matches?",
354
req("keywordtok:\"How nOw broWn-ish C.o.w. ?\"")
355
,"//str[.='How nOw broWn-ish C.o.w. ?']"
359
/** @see org.apache.solr.analysis.TestRemoveDuplicatesTokenFilter */
361
public void testRemoveDuplicatesTokenFilter() {
362
Query q = QueryParsing.parseQuery("TV", "dedup",
363
h.getCore().getSchema());
364
assertTrue("not boolean?", q instanceof BooleanQuery);
365
assertEquals("unexpected number of stemmed synonym tokens",
366
2, ((BooleanQuery) q).clauses().size());
370
public void testTermVectorFields() {
372
IndexSchema ischema = new IndexSchema(solrConfig, getSchemaFile(), null);
373
SchemaField f; // Solr field type
374
Fieldable luf; // Lucene field
376
f = ischema.getField("test_basictv");
377
luf = f.createField("test", 0f);
378
assertTrue(f.storeTermVector());
379
assertTrue(luf.isTermVectorStored());
381
f = ischema.getField("test_notv");
382
luf = f.createField("test", 0f);
383
assertTrue(!f.storeTermVector());
384
assertTrue(!luf.isTermVectorStored());
386
f = ischema.getField("test_postv");
387
luf = f.createField("test", 0f);
388
assertTrue(f.storeTermVector() && f.storeTermPositions());
389
assertTrue(luf.isStorePositionWithTermVector());
391
f = ischema.getField("test_offtv");
392
luf = f.createField("test", 0f);
393
assertTrue(f.storeTermVector() && f.storeTermOffsets());
394
assertTrue(luf.isStoreOffsetWithTermVector());
396
f = ischema.getField("test_posofftv");
397
luf = f.createField("test", 0f);
398
assertTrue(f.storeTermVector() && f.storeTermPositions() && f.storeTermOffsets());
399
assertTrue(luf.isStoreOffsetWithTermVector() && luf.isStorePositionWithTermVector());
404
public void testSolrParams() throws Exception {
405
NamedList nl = new NamedList();
409
nl.add("bf","false");
411
Map<String,String> m = new HashMap<String,String>();
412
m.put("f.field1.i", "1000");
416
LocalSolrQueryRequest req = new LocalSolrQueryRequest(null,nl);
417
SolrParams p = req.getParams();
419
assertEquals(p.get("i"), "555");
420
assertEquals(p.getInt("i").intValue(), 555);
421
assertEquals(p.getInt("i",5), 555);
422
assertEquals(p.getInt("iii",5), 5);
423
assertEquals(p.getFieldParam("field1","i"), "555");
425
req.setParams(new DefaultSolrParams(p, new MapSolrParams(m)));
427
assertEquals(req.getOriginalParams().get("s"), "bbb");
428
assertEquals(p.get("i"), "555");
429
assertEquals(p.getInt("i").intValue(), 555);
430
assertEquals(p.getInt("i",5), 555);
431
assertEquals(p.getInt("iii",5), 5);
433
assertEquals(p.getFieldParam("field1","i"), "1000");
434
assertEquals(p.get("s"), "bbb");
435
assertEquals(p.get("ss"), "SSS");
437
assertEquals(!!p.getBool("bt"), !p.getBool("bf"));
438
assertEquals(p.getBool("foo",true), true);
439
assertEquals(p.getBool("foo",false), false);
440
assertEquals(!!p.getBool("bt"), !p.getBool("bf"));
442
NamedList more = new NamedList();
443
more.add("s", "aaa");
444
more.add("s", "ccc");
445
more.add("ss","YYY");
446
more.add("xx","XXX");
447
p = new AppendedSolrParams(p, SolrParams.toSolrParams(more));
448
assertEquals(3, p.getParams("s").length);
449
assertEquals("bbb", p.getParams("s")[0]);
450
assertEquals("aaa", p.getParams("s")[1]);
451
assertEquals("ccc", p.getParams("s")[2]);
452
assertEquals(3, p.getParams("s").length);
453
assertEquals("SSS", p.get("ss"));
454
assertEquals("XXX", p.get("xx"));
460
public void testDefaultFieldValues() {
462
lrf.args.put("version","2.1");
463
assertU(adoc("id", "4055",
464
"subject", "Hoss the Hoss man Hostetter"));
465
assertU(adoc("id", "4056",
467
"subject", "Some Other Guy"));
468
assertU(adoc("id", "4057",
471
"subject", "The Dude"));
474
assertQ("everthing should have recent timestamp",
475
req("timestamp:[NOW-10MINUTES TO NOW]")
477
,"//date[@name='timestamp']"
480
assertQ("2 docs should have the default for multiDefault",
481
req("multiDefault:muLti-Default")
483
,"//arr[@name='multiDefault']"
485
assertQ("1 doc should have it's explicit multiDefault",
486
req("multiDefault:a")
490
assertQ("2 docs should have the default for intDefault",
494
assertQ("1 doc should have it's explicit intDefault",
495
req("intDefault:[3 TO 5]")
502
public void testTokenizer() {
504
assertU(adoc("id", "4055",
505
"patterntok", "Hello,There"));
506
assertU(adoc("id", "4056",
507
"patterntok", "Goodbye,Now"));
510
assertQ("make sure it split ok",
511
req("patterntok:Hello")
514
assertQ("make sure it split ok",
515
req("patterntok:Goodbye")
521
public void testConfigDefaults() {
522
assertU(adoc("id", "42",
523
"name", "Zapp Brannigan"));
524
assertU(adoc("id", "43",
525
"title", "Democratic Order of Planets"));
526
assertU(adoc("id", "44",
527
"name", "The Zapper"));
528
assertU(adoc("id", "45",
529
"title", "25 star General"));
530
assertU(adoc("id", "46",
531
"subject", "Defeated the pacifists of the Gandhi nebula"));
532
assertU(adoc("id", "47",
533
"text", "line up and fly directly at the enemy death cannons, clogging them with wreckage!"));
536
assertQ("standard request handler returns all matches",
537
req("id:[42 TO 47]"),
541
assertQ("defaults handler returns fewer matches",
542
req("q", "id:[42 TO 47]", "qt","defaults"),
546
assertQ("defaults handler includes highlighting",
547
req("q", "name:Zapp OR title:General", "qt","defaults"),
548
"//lst[@name='highlighting']"
553
private String mkstr(int len) {
554
StringBuilder sb = new StringBuilder(len);
555
for (int i = 0; i < len; i++) {
556
sb.append((char)(65 + i%26));
558
return new String(sb);
562
public void testNotLazyField() throws IOException {
563
for(int i = 0; i < 10; i++) {
564
assertU(adoc("id", new Integer(i).toString(),
566
"test_hlt", mkstr(20000)));
569
SolrCore core = h.getCore();
571
SolrQueryRequest req = req("q", "title:keyword", "fl", "id,title,test_hlt");
572
SolrQueryResponse rsp = new SolrQueryResponse();
573
core.execute(core.getRequestHandler(req.getParams().get(CommonParams.QT)), req, rsp);
575
DocList dl = (DocList) rsp.getValues().get("response");
576
org.apache.lucene.document.Document d = req.getSearcher().doc(dl.iterator().nextDoc());
577
// ensure field is not lazy, only works for Non-Numeric fields currently (if you change schema behind test, this may fail)
578
assertTrue( d.getFieldable("test_hlt") instanceof Field );
579
assertTrue( d.getFieldable("title") instanceof Field );
584
public void testLazyField() throws IOException {
585
for(int i = 0; i < 10; i++) {
586
assertU(adoc("id", new Integer(i).toString(),
588
"test_hlt", mkstr(20000)));
591
SolrCore core = h.getCore();
593
SolrQueryRequest req = req("q", "title:keyword", "fl", "id,title");
594
SolrQueryResponse rsp = new SolrQueryResponse();
595
core.execute(core.getRequestHandler(req.getParams().get(CommonParams.QT)), req, rsp);
597
DocList dl = (DocList) rsp.getValues().get("response");
598
DocIterator di = dl.iterator();
599
org.apache.lucene.document.Document d = req.getSearcher().doc(di.nextDoc());
600
// ensure field is lazy
601
assertTrue( !( d.getFieldable("test_hlt") instanceof Field ) );
602
assertTrue( d.getFieldable("title") instanceof Field );
607
/** @see org.apache.solr.util.DateMathParserTest */
609
public void testDateMath() {
612
// testing everything from query level is hard because
613
// time marches on ... and there is no easy way to reach into the
614
// bowels of DateField and muck with the definition of "now"
616
// BUT: we can test that crazy combinations of "NOW" all work correctly,
617
// assuming the test doesn't take too long to run...
619
final String july4 = "1976-07-04T12:08:56.235Z";
620
assertU(adoc("id", "1", "bday", july4));
621
assertU(adoc("id", "2", "bday", "NOW"));
622
assertU(adoc("id", "3", "bday", "NOW/HOUR"));
623
assertU(adoc("id", "4", "bday", "NOW-30MINUTES"));
624
assertU(adoc("id", "5", "bday", "NOW+30MINUTES"));
625
assertU(adoc("id", "6", "bday", "NOW+2YEARS"));
628
assertQ("check math on absolute date#1",
629
req("q", "bday:[* TO "+july4+"/SECOND]"),
630
"*[count(//doc)=0]");
631
assertQ("check math on absolute date#2",
632
req("q", "bday:[* TO "+july4+"/SECOND+1SECOND]"),
633
"*[count(//doc)=1]");
634
assertQ("check math on absolute date#3",
635
req("q", "bday:["+july4+"/SECOND TO "+july4+"/SECOND+1SECOND]"),
636
"*[count(//doc)=1]");
637
assertQ("check math on absolute date#4",
638
req("q", "bday:["+july4+"/MINUTE+1MINUTE TO *]"),
639
"*[count(//doc)=5]");
641
assertQ("check count for before now",
642
req("q", "bday:[* TO NOW]"), "*[count(//doc)=4]");
644
assertQ("check count for after now",
645
req("q", "bday:[NOW TO *]"), "*[count(//doc)=2]");
647
assertQ("check count for old stuff",
648
req("q", "bday:[* TO NOW-2YEARS]"), "*[count(//doc)=1]");
650
assertQ("check count for future stuff",
651
req("q", "bday:[NOW+1MONTH TO *]"), "*[count(//doc)=1]");
653
assertQ("check count for near stuff",
654
req("q", "bday:[NOW-1MONTH TO NOW+2HOURS]"), "*[count(//doc)=4]");
658
public void testDateRoundtrip() {
659
assertU(adoc("id", "99", "bday", "99-01-01T12:34:56.789Z"));
661
assertQ("year should be canonicallized to 4 digits",
663
"//date[@name='bday'][.='0099-01-01T12:34:56.789Z']");
664
assertU(adoc("id", "99", "bday", "1999-01-01T12:34:56.900Z"));
666
assertQ("millis should be canonicallized to no trailing zeros",
668
"//date[@name='bday'][.='1999-01-01T12:34:56.9Z']");
672
public void testPatternReplaceFilter() {
674
assertU(adoc("id", "1",
675
"patternreplacefilt", "My fine-feathered friend!"));
676
assertU(adoc("id", "2",
677
"patternreplacefilt", " What's Up Doc?"));
680
assertQ("don't find Up",
681
req("q", "patternreplacefilt:Up"),
682
"*[count(//doc)=0]");
685
req("q", "patternreplacefilt:__What_s_Up_Doc_"),
686
"*[count(//doc)=1]");
688
assertQ("find birds",
689
req("q", "patternreplacefilt:My__fine_feathered_friend_"),
690
"*[count(//doc)=1]");
694
public void testAbuseOfSort() {
696
assertU(adoc("id", "9999991",
697
"sortabuse_b", "true",
698
"sortabuse_t", "zzz xxx ccc vvv bbb nnn aaa sss ddd fff ggg"));
699
assertU(adoc("id", "9999992",
700
"sortabuse_b", "true",
701
"sortabuse_t", "zzz xxx ccc vvv bbb nnn qqq www eee rrr ttt"));
706
ignoreException("can not sort on multivalued field: sortabuse_t");
707
assertQ("sort on something that shouldn't work",
708
req("q", "sortabuse_b:true",
709
"sort", "sortabuse_t asc"),
710
"*[count(//doc)=2]");
711
fail("no error encountered when sorting on sortabuse_t");
712
} catch (Exception outer) {
714
Throwable root = getRootCause(outer);
715
assertEquals("sort exception root cause",
716
SolrException.class, root.getClass());
717
SolrException e = (SolrException) root;
718
assertEquals("incorrect error type",
719
SolrException.ErrorCode.BAD_REQUEST,
720
SolrException.ErrorCode.getErrorCode(e.code()));
721
assertTrue("exception doesn't contain field name",
722
-1 != e.getMessage().indexOf("sortabuse_t"));
727
// /** this doesn't work, but if it did, this is how we'd test it. */
728
// public void testOverwriteFalse() {
730
// assertU(adoc("id", "overwrite", "val_s", "AAA"));
731
// assertU(commit());
733
// assertU(add(doc("id", "overwrite", "val_s", "BBB")
734
// ,"allowDups", "false"
735
// ,"overwriteCommitted","false"
736
// ,"overwritePending","false"
738
// assertU(commit());
739
// assertQ(req("id:overwrite")
740
// ,"//*[@numFound='1']"