diff --git a/dev-tools/eclipse/dot.classpath b/dev-tools/eclipse/dot.classpath index 776f13d..46ab697 100644 --- a/dev-tools/eclipse/dot.classpath +++ b/dev-tools/eclipse/dot.classpath @@ -170,6 +170,6 @@ - + diff --git a/dev-tools/idea/.idea/libraries/JUnit.xml b/dev-tools/idea/.idea/libraries/JUnit.xml index f985ed0..1494e44 100644 --- a/dev-tools/idea/.idea/libraries/JUnit.xml +++ b/dev-tools/idea/.idea/libraries/JUnit.xml @@ -2,7 +2,7 @@ - + diff --git a/dev-tools/maven/pom.xml.template b/dev-tools/maven/pom.xml.template index 2007caf..14ffae8 100644 --- a/dev-tools/maven/pom.xml.template +++ b/dev-tools/maven/pom.xml.template @@ -383,7 +383,7 @@ com.carrotsearch.randomizedtesting randomizedtesting-runner - 1.4.0 + 1.5.0 diff --git a/lucene/benchmark/src/test/org/apache/lucene/benchmark/byTask/feeds/DocMakerTest.java b/lucene/benchmark/src/test/org/apache/lucene/benchmark/byTask/feeds/DocMakerTest.java index 10465b3..47133b0 100644 --- a/lucene/benchmark/src/test/org/apache/lucene/benchmark/byTask/feeds/DocMakerTest.java +++ b/lucene/benchmark/src/test/org/apache/lucene/benchmark/byTask/feeds/DocMakerTest.java @@ -86,7 +86,7 @@ public class DocMakerTest extends BenchmarkTestCase { Config config = new Config(props); PerfRunData runData = new PerfRunData(config); - TaskSequence tasks = new TaskSequence(runData, getName(), null, false); + TaskSequence tasks = new TaskSequence(runData, getTestName(), null, false); tasks.addTask(new CreateIndexTask(runData)); tasks.addTask(new AddDocTask(runData)); tasks.addTask(new CloseIndexTask(runData)); diff --git a/lucene/core/src/test/org/apache/lucene/document/TestDateTools.java b/lucene/core/src/test/org/apache/lucene/document/TestDateTools.java index 7f2afa4..83d40fb 100644 --- a/lucene/core/src/test/org/apache/lucene/document/TestDateTools.java +++ b/lucene/core/src/test/org/apache/lucene/document/TestDateTools.java @@ -2,18 +2,15 @@ package org.apache.lucene.document; import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.Calendar; -import java.util.Date; -import java.util.GregorianCalendar; -import java.util.TimeZone; -import java.util.Locale; +import java.util.*; import org.apache.lucene.util.LuceneTestCase; -import org.apache.lucene.util.SystemPropertiesRestoreRule; import org.junit.Rule; import org.junit.rules.RuleChain; import org.junit.rules.TestRule; +import com.carrotsearch.randomizedtesting.rules.SystemPropertiesRestoreRule; + /** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with diff --git a/lucene/core/src/test/org/apache/lucene/index/TestDuelingCodecs.java b/lucene/core/src/test/org/apache/lucene/index/TestDuelingCodecs.java index 2fae593..e89358d 100644 --- a/lucene/core/src/test/org/apache/lucene/index/TestDuelingCodecs.java +++ b/lucene/core/src/test/org/apache/lucene/index/TestDuelingCodecs.java @@ -70,7 +70,7 @@ public class TestDuelingCodecs extends LuceneTestCase { // so this would make assertEquals complicated. leftCodec = Codec.forName("SimpleText"); - rightCodec = new RandomCodec(random(), null); + rightCodec = new RandomCodec(random()); leftDir = newDirectory(); rightDir = newDirectory(); diff --git a/lucene/core/src/test/org/apache/lucene/index/TestPostingsOffsets.java b/lucene/core/src/test/org/apache/lucene/index/TestPostingsOffsets.java index 5d8dbe8..5a6d863 100644 --- a/lucene/core/src/test/org/apache/lucene/index/TestPostingsOffsets.java +++ b/lucene/core/src/test/org/apache/lucene/index/TestPostingsOffsets.java @@ -53,12 +53,17 @@ public class TestPostingsOffsets extends LuceneTestCase { public void setUp() throws Exception { super.setUp(); + // Currently only SimpleText and Lucene40 can index offsets into postings: - assumeTrue("codec does not support offsets", Codec.getDefault().getName().equals("SimpleText") || Codec.getDefault().getName().equals("Lucene40")); + String codecName = Codec.getDefault().getName(); + assumeTrue("Codec does not support offsets: " + codecName, + codecName.equals("SimpleText") || + codecName.equals("Lucene40")); + iwc = newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random())); - if (Codec.getDefault().getName().equals("Lucene40")) { - // sep etc are not implemented + if (codecName.equals("Lucene40")) { + // Sep etc are not implemented switch(random().nextInt(4)) { case 0: iwc.setCodec(_TestUtil.alwaysPostingsFormat(new Lucene40PostingsFormat())); break; case 1: iwc.setCodec(_TestUtil.alwaysPostingsFormat(new MemoryPostingsFormat())); break; diff --git a/lucene/core/src/test/org/apache/lucene/search/TestBooleanMinShouldMatch.java b/lucene/core/src/test/org/apache/lucene/search/TestBooleanMinShouldMatch.java index 707bd73..a6cf1cd 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestBooleanMinShouldMatch.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestBooleanMinShouldMatch.java @@ -84,7 +84,7 @@ public class TestBooleanMinShouldMatch extends LuceneTestCase { public void verifyNrHits(Query q, int expected) throws Exception { ScoreDoc[] h = s.search(q, null, 1000).scoreDocs; if (expected != h.length) { - printHits(getName(), h, s); + printHits(getTestName(), h, s); } assertEquals("result count", expected, h.length); //System.out.println("TEST: now check"); diff --git a/lucene/core/src/test/org/apache/lucene/search/TestPrefixInBooleanQuery.java b/lucene/core/src/test/org/apache/lucene/search/TestPrefixInBooleanQuery.java index f24a88e..727a6a6 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestPrefixInBooleanQuery.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestPrefixInBooleanQuery.java @@ -17,7 +17,6 @@ package org.apache.lucene.search; * limitations under the License. */ -import org.apache.lucene.util.LuceneTestCase; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.document.StringField; @@ -25,9 +24,12 @@ import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.RandomIndexWriter; import org.apache.lucene.index.Term; import org.apache.lucene.store.Directory; +import org.apache.lucene.util.LuceneTestCase; import org.junit.AfterClass; import org.junit.BeforeClass; +import com.carrotsearch.randomizedtesting.annotations.ThreadLeaks; + /** * https://issues.apache.org/jira/browse/LUCENE-1974 * @@ -36,7 +38,6 @@ import org.junit.BeforeClass; * BooleanScorer.score(Collector collector, int max, int firstDocID) * * Line 273, end=8192, subScorerDocID=11378, then more got false? - * */ public class TestPrefixInBooleanQuery extends LuceneTestCase { diff --git a/lucene/core/src/test/org/apache/lucene/search/TestSort.java b/lucene/core/src/test/org/apache/lucene/search/TestSort.java index 84c55af..759ad15 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestSort.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestSort.java @@ -603,7 +603,7 @@ public class TestSort extends LuceneTestCase { } }), SortField.FIELD_DOC ); assertMatches (full, queryA, sort, "JIHGFEDCBA"); - assertSaneFieldCaches(getName() + " IntParser"); + assertSaneFieldCaches(getTestName() + " IntParser"); fc.purgeAllCaches(); sort.setSort (new SortField ("parser", new FieldCache.FloatParser(){ @@ -612,7 +612,7 @@ public class TestSort extends LuceneTestCase { } }), SortField.FIELD_DOC ); assertMatches (full, queryA, sort, "JIHGFEDCBA"); - assertSaneFieldCaches(getName() + " FloatParser"); + assertSaneFieldCaches(getTestName() + " FloatParser"); fc.purgeAllCaches(); sort.setSort (new SortField ("parser", new FieldCache.LongParser(){ @@ -621,7 +621,7 @@ public class TestSort extends LuceneTestCase { } }), SortField.FIELD_DOC ); assertMatches (full, queryA, sort, "JIHGFEDCBA"); - assertSaneFieldCaches(getName() + " LongParser"); + assertSaneFieldCaches(getTestName() + " LongParser"); fc.purgeAllCaches(); sort.setSort (new SortField ("parser", new FieldCache.DoubleParser(){ @@ -630,7 +630,7 @@ public class TestSort extends LuceneTestCase { } }), SortField.FIELD_DOC ); assertMatches (full, queryA, sort, "JIHGFEDCBA"); - assertSaneFieldCaches(getName() + " DoubleParser"); + assertSaneFieldCaches(getTestName() + " DoubleParser"); fc.purgeAllCaches(); sort.setSort (new SortField ("parser", new FieldCache.ByteParser(){ @@ -639,7 +639,7 @@ public class TestSort extends LuceneTestCase { } }), SortField.FIELD_DOC ); assertMatches (full, queryA, sort, "JIHGFEDCBA"); - assertSaneFieldCaches(getName() + " ByteParser"); + assertSaneFieldCaches(getTestName() + " ByteParser"); fc.purgeAllCaches(); sort.setSort (new SortField ("parser", new FieldCache.ShortParser(){ @@ -648,7 +648,7 @@ public class TestSort extends LuceneTestCase { } }), SortField.FIELD_DOC ); assertMatches (full, queryA, sort, "JIHGFEDCBA"); - assertSaneFieldCaches(getName() + " ShortParser"); + assertSaneFieldCaches(getTestName() + " ShortParser"); fc.purgeAllCaches(); } @@ -1229,7 +1229,7 @@ public class TestSort extends LuceneTestCase { // up to this point, all of the searches should have "sane" // FieldCache behavior, and should have reused hte cache in several cases - assertSaneFieldCaches(getName() + " various"); + assertSaneFieldCaches(getTestName() + " various"); // next we'll check Locale based (String[]) for 'string', so purge first FieldCache.DEFAULT.purgeAllCaches(); } diff --git a/lucene/core/src/test/org/apache/lucene/search/TestTermRangeFilter.java b/lucene/core/src/test/org/apache/lucene/search/TestTermRangeFilter.java index e1d55a2..3f44ca0 100644 --- a/lucene/core/src/test/org/apache/lucene/search/TestTermRangeFilter.java +++ b/lucene/core/src/test/org/apache/lucene/search/TestTermRangeFilter.java @@ -36,7 +36,6 @@ public class TestTermRangeFilter extends BaseTestRangeFilter { @Test public void testRangeFilterId() throws IOException { - IndexReader reader = signedIndexReader; IndexSearcher search = newSearcher(reader); diff --git a/lucene/core/src/test/org/apache/lucene/store/TestDirectory.java b/lucene/core/src/test/org/apache/lucene/store/TestDirectory.java index 16e4689..b4c8ef5 100644 --- a/lucene/core/src/test/org/apache/lucene/store/TestDirectory.java +++ b/lucene/core/src/test/org/apache/lucene/store/TestDirectory.java @@ -25,9 +25,13 @@ import java.io.IOException; import java.util.Arrays; public class TestDirectory extends LuceneTestCase { - public void testDetectClose() throws Throwable { - Directory[] dirs = new Directory[] { new RAMDirectory(), new SimpleFSDirectory(TEMP_DIR), new NIOFSDirectory(TEMP_DIR) }; + Directory[] dirs = new Directory[] { + new RAMDirectory(), + new SimpleFSDirectory(TEMP_DIR), + new NIOFSDirectory(TEMP_DIR) + }; + for (Directory dir : dirs) { dir.close(); try { diff --git a/lucene/core/src/test/org/apache/lucene/store/TestWindowsMMap.java b/lucene/core/src/test/org/apache/lucene/store/TestWindowsMMap.java index e523837..7819929 100644 --- a/lucene/core/src/test/org/apache/lucene/store/TestWindowsMMap.java +++ b/lucene/core/src/test/org/apache/lucene/store/TestWindowsMMap.java @@ -60,14 +60,11 @@ public class TestWindowsMMap extends LuceneTestCase { return fb.toString(); } - private final static String storePathname = - _TestUtil.getTempDir("testLuceneMmap").getAbsolutePath(); - public void testMmapIndex() throws Exception { // sometimes the directory is not cleaned by rmDir, because on Windows it // may take some time until the files are finally dereferenced. So clean the // directory up front, or otherwise new IndexWriter will fail. - File dirPath = new File(storePathname); + File dirPath = _TestUtil.getTempDir("testLuceneMmap"); rmDir(dirPath); MMapDirectory dir = new MMapDirectory(dirPath, null); diff --git a/lucene/core/src/test/org/apache/lucene/util/TestFieldCacheSanityChecker.java b/lucene/core/src/test/org/apache/lucene/util/TestFieldCacheSanityChecker.java index fb9d668..33b9541 100644 --- a/lucene/core/src/test/org/apache/lucene/util/TestFieldCacheSanityChecker.java +++ b/lucene/core/src/test/org/apache/lucene/util/TestFieldCacheSanityChecker.java @@ -108,7 +108,8 @@ public class TestFieldCacheSanityChecker extends LuceneTestCase { FieldCacheSanityChecker.checkSanity(cache.getCacheEntries()); if (0 < insanity.length) - dumpArray(getTestLabel() + " INSANITY", insanity, System.err); + dumpArray(getTestClass().getName() + "#" + getTestName() + + " INSANITY", insanity, System.err); assertEquals("shouldn't be any cache insanity", 0, insanity.length); cache.purgeAllCaches(); diff --git a/lucene/core/src/test/org/apache/lucene/util/junitcompat/TestBeforeAfterOverrides.java b/lucene/core/src/test/org/apache/lucene/util/junitcompat/TestBeforeAfterOverrides.java new file mode 100644 index 0000000..611e68c --- /dev/null +++ b/lucene/core/src/test/org/apache/lucene/util/junitcompat/TestBeforeAfterOverrides.java @@ -0,0 +1,65 @@ +package org.apache.lucene.util.junitcompat; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.JUnitCore; +import org.junit.runner.Result; + +/** + * 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. + */ + +public class TestBeforeAfterOverrides extends WithNestedTests { + public TestBeforeAfterOverrides() { + super(true); + } + + public static class Before1 extends WithNestedTests.AbstractNestedTest { + @Before + public void before() {} + } + public static class Before2 extends Before1 {} + public static class Before3 extends Before2 { + @Before + public void before() {} + } + + public static class After1 extends WithNestedTests.AbstractNestedTest { + @After + public void after() {} + } + public static class After2 extends Before1 {} + public static class After3 extends Before2 { + @After + public void after() {} + } + + @Test + public void testBefore() { + Result result = JUnitCore.runClasses(Before3.class); + Assert.assertEquals(1, result.getFailureCount()); + Assert.assertTrue(result.getFailures().get(0).getTrace().contains("There are overridden methods")); + } + + @Test + public void testAfter() { + Result result = JUnitCore.runClasses(Before3.class); + Assert.assertEquals(1, result.getFailureCount()); + Assert.assertTrue(result.getFailures().get(0).getTrace().contains("There are overridden methods")); + } +} diff --git a/lucene/core/src/test/org/apache/lucene/util/junitcompat/TestReproduceMessage.java b/lucene/core/src/test/org/apache/lucene/util/junitcompat/TestReproduceMessage.java index 26c2e3b..a7e79ae 100644 --- a/lucene/core/src/test/org/apache/lucene/util/junitcompat/TestReproduceMessage.java +++ b/lucene/core/src/test/org/apache/lucene/util/junitcompat/TestReproduceMessage.java @@ -25,7 +25,6 @@ import org.junit.AfterClass; import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; -import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TestRule; @@ -119,14 +118,14 @@ public class TestReproduceMessage extends WithNestedTests { super(true); } - @Test @Ignore + @Test public void testAssumeBeforeClass() throws Exception { type = SoreType.ASSUMPTION; where = SorePoint.BEFORE_CLASS; Assert.assertTrue(runAndReturnSyserr().isEmpty()); } - @Test @Ignore + @Test public void testAssumeInitializer() throws Exception { type = SoreType.ASSUMPTION; where = SorePoint.INITIALIZER; @@ -161,7 +160,7 @@ public class TestReproduceMessage extends WithNestedTests { Assert.assertTrue(runAndReturnSyserr().isEmpty()); } - @Test @Ignore + @Test public void testAssumeAfterClass() throws Exception { type = SoreType.ASSUMPTION; where = SorePoint.AFTER_CLASS; @@ -172,14 +171,14 @@ public class TestReproduceMessage extends WithNestedTests { * FAILURES */ - @Test @Ignore + @Test public void testFailureBeforeClass() throws Exception { type = SoreType.FAILURE; where = SorePoint.BEFORE_CLASS; Assert.assertTrue(runAndReturnSyserr().contains("NOTE: reproduce with:")); } - @Test @Ignore + @Test public void testFailureInitializer() throws Exception { type = SoreType.FAILURE; where = SorePoint.INITIALIZER; @@ -228,7 +227,7 @@ public class TestReproduceMessage extends WithNestedTests { Assert.assertTrue(Arrays.asList(syserr.split("\\s")).contains("-Dtestcase=" + Nested.class.getSimpleName())); } - @Test @Ignore + @Test public void testFailureAfterClass() throws Exception { type = SoreType.FAILURE; where = SorePoint.AFTER_CLASS; @@ -239,14 +238,14 @@ public class TestReproduceMessage extends WithNestedTests { * ERRORS */ - @Test @Ignore + @Test public void testErrorBeforeClass() throws Exception { type = SoreType.ERROR; where = SorePoint.BEFORE_CLASS; Assert.assertTrue(runAndReturnSyserr().contains("NOTE: reproduce with:")); } - @Test @Ignore + @Test public void testErrorInitializer() throws Exception { type = SoreType.ERROR; where = SorePoint.INITIALIZER; @@ -293,7 +292,7 @@ public class TestReproduceMessage extends WithNestedTests { Assert.assertTrue(Arrays.asList(syserr.split("\\s")).contains("-Dtestcase=" + Nested.class.getSimpleName())); } - @Test @Ignore + @Test public void testErrorAfterClass() throws Exception { type = SoreType.ERROR; where = SorePoint.AFTER_CLASS; diff --git a/lucene/core/src/test/org/apache/lucene/util/junitcompat/TestSameRandomnessLocalePassedOrNot.java b/lucene/core/src/test/org/apache/lucene/util/junitcompat/TestSameRandomnessLocalePassedOrNot.java index fccfa2c..4575b5a 100644 --- a/lucene/core/src/test/org/apache/lucene/util/junitcompat/TestSameRandomnessLocalePassedOrNot.java +++ b/lucene/core/src/test/org/apache/lucene/util/junitcompat/TestSameRandomnessLocalePassedOrNot.java @@ -1,22 +1,16 @@ package org.apache.lucene.util.junitcompat; -import java.util.Locale; -import java.util.Random; -import java.util.TimeZone; +import java.util.*; -import org.apache.lucene.util.SystemPropertiesRestoreRule; import org.apache.lucene.util._TestUtil; -import org.junit.Assert; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.Test; +import org.junit.*; import org.junit.rules.RuleChain; import org.junit.rules.TestRule; import org.junit.runner.JUnitCore; import org.junit.runner.Result; import com.carrotsearch.randomizedtesting.RandomizedContext; +import com.carrotsearch.randomizedtesting.rules.SystemPropertiesRestoreRule; /** * Licensed to the Apache Software Foundation (ASF) under one or more diff --git a/lucene/core/src/test/org/apache/lucene/util/junitcompat/TestSystemPropertiesInvariantRule.java b/lucene/core/src/test/org/apache/lucene/util/junitcompat/TestSystemPropertiesInvariantRule.java index 76c8cb2..0f0a348 100644 --- a/lucene/core/src/test/org/apache/lucene/util/junitcompat/TestSystemPropertiesInvariantRule.java +++ b/lucene/core/src/test/org/apache/lucene/util/junitcompat/TestSystemPropertiesInvariantRule.java @@ -19,14 +19,15 @@ package org.apache.lucene.util.junitcompat; import java.util.Properties; -import org.apache.lucene.util.SystemPropertiesInvariantRule; -import org.apache.lucene.util.SystemPropertiesRestoreRule; import org.junit.*; import org.junit.rules.TestRule; import org.junit.runner.JUnitCore; import org.junit.runner.Result; import org.junit.runner.notification.Failure; +import com.carrotsearch.randomizedtesting.rules.SystemPropertiesInvariantRule; +import com.carrotsearch.randomizedtesting.rules.SystemPropertiesRestoreRule; + /** * @see SystemPropertiesRestoreRule * @see SystemPropertiesInvariantRule diff --git a/lucene/test-framework/ivy.xml b/lucene/test-framework/ivy.xml index 6fbb80f..d457de7 100644 --- a/lucene/test-framework/ivy.xml +++ b/lucene/test-framework/ivy.xml @@ -23,8 +23,8 @@ - - + + diff --git a/lucene/test-framework/lib/junit4-ant-1.4.0.jar.sha1 b/lucene/test-framework/lib/junit4-ant-1.4.0.jar.sha1 deleted file mode 100644 index 25b8eb5..0000000 --- a/lucene/test-framework/lib/junit4-ant-1.4.0.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -b086d1665504ac99c6cdb2340044f0de94753eed diff --git a/lucene/test-framework/lib/junit4-ant-1.5.0.jar.sha1 b/lucene/test-framework/lib/junit4-ant-1.5.0.jar.sha1 new file mode 100644 index 0000000..05060d2 --- /dev/null +++ b/lucene/test-framework/lib/junit4-ant-1.5.0.jar.sha1 @@ -0,0 +1 @@ +4e920288c2d2cd39b7e15f3abcaa3c5e2213ec9c diff --git a/lucene/test-framework/lib/randomizedtesting-runner-1.4.0.jar.sha1 b/lucene/test-framework/lib/randomizedtesting-runner-1.4.0.jar.sha1 deleted file mode 100644 index 67656ee..0000000 --- a/lucene/test-framework/lib/randomizedtesting-runner-1.4.0.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -2af8c132f3f65e0f09a2ce59cbc5c649ff12ab1c diff --git a/lucene/test-framework/lib/randomizedtesting-runner-1.5.0.jar.sha1 b/lucene/test-framework/lib/randomizedtesting-runner-1.5.0.jar.sha1 new file mode 100644 index 0000000..380e2fe --- /dev/null +++ b/lucene/test-framework/lib/randomizedtesting-runner-1.5.0.jar.sha1 @@ -0,0 +1 @@ +378731cc7f26d45b68a6e5f600d4c7d071d165b1 diff --git a/lucene/test-framework/src/java/org/apache/lucene/index/RandomCodec.java b/lucene/test-framework/src/java/org/apache/lucene/index/RandomCodec.java index be16076..1a8f1a5 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/index/RandomCodec.java +++ b/lucene/test-framework/src/java/org/apache/lucene/index/RandomCodec.java @@ -50,15 +50,14 @@ import org.apache.lucene.util._TestUtil; * and reproducable. */ public class RandomCodec extends Lucene40Codec { - /** shuffled list of postingsformats to use for new mappings */ + /** Shuffled list of postings formats to use for new mappings */ private List formats = new ArrayList(); + /** memorized field->postingsformat mappings */ // note: we have to sync this map even though its just for debugging/toString, // otherwise DWPT's .toString() calls that iterate over the map can // cause concurrentmodificationexception if indexwriter's infostream is on private Map previousMappings = Collections.synchronizedMap(new HashMap()); - /** set of codec names to avoid */ - private final Set avoidCodecs; private final int perFieldSeed; @Override @@ -78,35 +77,42 @@ public class RandomCodec extends Lucene40Codec { } public RandomCodec(Random random, Set avoidCodecs) { - this.avoidCodecs = avoidCodecs; this.perFieldSeed = random.nextInt(); // TODO: make it possible to specify min/max iterms per // block via CL: int minItemsPerBlock = _TestUtil.nextInt(random, 2, 100); int maxItemsPerBlock = 2*(Math.max(2, minItemsPerBlock-1)) + random.nextInt(100); - add(new Lucene40PostingsFormat(minItemsPerBlock, maxItemsPerBlock)); - // TODO: make it possible to specify min/max iterms per - // block via CL: + + // TODO: make it possible to specify min/max iterms per block via CL: minItemsPerBlock = _TestUtil.nextInt(random, 2, 100); maxItemsPerBlock = 2*(Math.max(1, minItemsPerBlock-1)) + random.nextInt(100); - add(new Pulsing40PostingsFormat(1 + random.nextInt(20), minItemsPerBlock, maxItemsPerBlock)); - add(new MockSepPostingsFormat()); - add(new MockFixedIntBlockPostingsFormat(_TestUtil.nextInt(random, 1, 2000))); - add(new MockVariableIntBlockPostingsFormat( _TestUtil.nextInt(random, 1, 127))); - add(new MockRandomPostingsFormat(random)); - add(new NestedPulsingPostingsFormat()); - add(new Lucene40WithOrds()); - add(new SimpleTextPostingsFormat()); - add(new MemoryPostingsFormat(random.nextBoolean())); + add(avoidCodecs, + new Lucene40PostingsFormat(minItemsPerBlock, maxItemsPerBlock), + new Pulsing40PostingsFormat(1 + random.nextInt(20), minItemsPerBlock, maxItemsPerBlock), + new MockSepPostingsFormat(), + new MockFixedIntBlockPostingsFormat(_TestUtil.nextInt(random, 1, 2000)), + new MockVariableIntBlockPostingsFormat( _TestUtil.nextInt(random, 1, 127)), + new MockRandomPostingsFormat(random), + new NestedPulsingPostingsFormat(), + new Lucene40WithOrds(), + new SimpleTextPostingsFormat(), + new MemoryPostingsFormat(random.nextBoolean())); + Collections.shuffle(formats, random); } - - private final void add(PostingsFormat p) { - if (avoidCodecs == null || !avoidCodecs.contains(p.getName())) { - formats.add(p); + + public RandomCodec(Random random) { + this(random, Collections. emptySet()); + } + + private final void add(Set avoidCodecs, PostingsFormat... postings) { + for (PostingsFormat p : postings) { + if (!avoidCodecs.contains(p.getName())) { + formats.add(p); + } } } - + @Override public String toString() { return super.toString() + ": " + previousMappings.toString(); diff --git a/lucene/test-framework/src/java/org/apache/lucene/util/AbstractBeforeAfterRule.java b/lucene/test-framework/src/java/org/apache/lucene/util/AbstractBeforeAfterRule.java new file mode 100644 index 0000000..141892c --- /dev/null +++ b/lucene/test-framework/src/java/org/apache/lucene/util/AbstractBeforeAfterRule.java @@ -0,0 +1,63 @@ +package org.apache.lucene.util; + +import java.util.ArrayList; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.rules.RuleChain; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.MultipleFailureException; +import org.junit.runners.model.Statement; + +/** + * 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. + */ + +/** + * A {@link TestRule} that guarantees the execution of {@link #after} even + * if an exception has been thrown from delegate {@link Statement}. This is much + * like {@link AfterClass} or {@link After} annotations but can be used with + * {@link RuleChain} to guarantee the order of execution. + */ +abstract class AbstractBeforeAfterRule implements TestRule { + @Override + public Statement apply(final Statement s, final Description d) { + return new Statement() { + public void evaluate() throws Throwable { + before(); + + final ArrayList errors = new ArrayList(); + try { + s.evaluate(); + } catch (Throwable t) { + errors.add(t); + } + + try { + after(); + } catch (Throwable t) { + errors.add(t); + } + + MultipleFailureException.assertEmpty(errors); + } + }; + } + + protected void before() throws Exception {} + protected void after() throws Exception {} +} diff --git a/lucene/test-framework/src/java/org/apache/lucene/util/DirectoryCloseable.java b/lucene/test-framework/src/java/org/apache/lucene/util/DirectoryCloseable.java new file mode 100644 index 0000000..412a929 --- /dev/null +++ b/lucene/test-framework/src/java/org/apache/lucene/util/DirectoryCloseable.java @@ -0,0 +1,45 @@ +package org.apache.lucene.util; + +import java.io.Closeable; +import java.io.IOException; + +import org.apache.lucene.store.MockDirectoryWrapper; +import org.junit.Assert; + +/** + * 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. + */ + +public class DirectoryCloseable implements Closeable { + private MockDirectoryWrapper dir; + + public DirectoryCloseable(MockDirectoryWrapper dir) { + this.dir = dir; + } + + @Override + public void close() throws IOException { + if (dir.isOpen()) { + try { + dir.close(); + } catch (Throwable t) { + // Ignore any exceptions that might have occurred here. + } + + Assert.fail("Directory not closed: " + dir); + } + } +} diff --git a/lucene/test-framework/src/java/org/apache/lucene/util/FieldCacheSanityRule.java b/lucene/test-framework/src/java/org/apache/lucene/util/FieldCacheSanityRule.java new file mode 100644 index 0000000..f0083ea --- /dev/null +++ b/lucene/test-framework/src/java/org/apache/lucene/util/FieldCacheSanityRule.java @@ -0,0 +1,61 @@ +package org.apache.lucene.util; + +import org.apache.lucene.search.FieldCache; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +/** + * 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. + */ + +public class FieldCacheSanityRule implements TestRule { + + @Override + public Statement apply(final Statement s, final Description d) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + s.evaluate(); + + Throwable problem = null; + try { + // calling assertSaneFieldCaches here isn't as useful as having test + // classes call it directly from the scope where the index readers + // are used, because they could be gc'ed just before this tearDown + // method is called. + // + // But it's better then nothing. + // + // If you are testing functionality that you know for a fact + // "violates" FieldCache sanity, then you should either explicitly + // call purgeFieldCache at the end of your test method, or refactor + // your Test class so that the inconsistent FieldCache usages are + // isolated in distinct test methods + LuceneTestCase.assertSaneFieldCaches(d.getDisplayName()); + } catch (Throwable t) { + problem = t; + } + + FieldCache.DEFAULT.purgeAllCaches(); + + if (problem != null) { + Rethrow.rethrow(problem); + } + } + }; + } +} diff --git a/lucene/test-framework/src/java/org/apache/lucene/util/FileCloseable.java b/lucene/test-framework/src/java/org/apache/lucene/util/FileCloseable.java new file mode 100644 index 0000000..d9d783d --- /dev/null +++ b/lucene/test-framework/src/java/org/apache/lucene/util/FileCloseable.java @@ -0,0 +1,48 @@ +package org.apache.lucene.util; + +import java.io.*; + +/** + * 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. + */ + +/** + * A {@link Closeable} that attempts to remove a given file/folder. + */ +final class FileCloseable implements Closeable { + private final File file; + + public FileCloseable(File file) { + this.file = file; + } + + @Override + public void close() throws IOException { + if (file.exists()) { + try { + _TestUtil.rmDir(file); + } catch (IOException e) { + // Ignore the exception from rmDir. + } + + // Re-check. + if (file.exists()) { + throw new IOException( + "Could not remove: " + file.getAbsolutePath()); + } + } + } +} \ No newline at end of file diff --git a/lucene/test-framework/src/java/org/apache/lucene/util/IcuHackRule.java b/lucene/test-framework/src/java/org/apache/lucene/util/IcuHackRule.java new file mode 100644 index 0000000..1c201b6 --- /dev/null +++ b/lucene/test-framework/src/java/org/apache/lucene/util/IcuHackRule.java @@ -0,0 +1,55 @@ +package org.apache.lucene.util; + +import java.util.Locale; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +/** + * 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. + */ + +final class IcuHackRule implements TestRule { + /** Globally only check hack once. */ + private static volatile AtomicBoolean icuTested = new AtomicBoolean(false); + + @Override + public Statement apply(final Statement s, Description d) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + // START hack to init ICU safely before we randomize locales. + // ICU fails during classloading when a special Java7-only locale is the default + // see: http://bugs.icu-project.org/trac/ticket/8734 + if (!icuTested.getAndSet(true)) { + Locale previous = Locale.getDefault(); + try { + Locale.setDefault(Locale.US); + Class.forName("com.ibm.icu.util.ULocale"); + } catch (ClassNotFoundException cnfe) { + // ignore if no ICU is in classpath + } finally { + Locale.setDefault(previous); + } + } + + s.evaluate(); + } + }; + } +} diff --git a/lucene/test-framework/src/java/org/apache/lucene/util/LineFileDocs.java b/lucene/test-framework/src/java/org/apache/lucene/util/LineFileDocs.java index cb0869f..6b3ee26 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/util/LineFileDocs.java +++ b/lucene/test-framework/src/java/org/apache/lucene/util/LineFileDocs.java @@ -27,7 +27,6 @@ import java.io.InputStreamReader; import java.io.RandomAccessFile; import java.nio.channels.Channels; import java.nio.channels.FileChannel; -import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CodingErrorAction; import java.util.Random; diff --git a/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java b/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java index fe6b657..e4b01c9 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java +++ b/lucene/test-framework/src/java/org/apache/lucene/util/LuceneTestCase.java @@ -17,129 +17,89 @@ package org.apache.lucene.util; * limitations under the License. */ -import java.io.File; -import java.io.IOException; -import java.io.PrintStream; -import java.lang.annotation.Documented; -import java.lang.annotation.ElementType; -import java.lang.annotation.Inherited; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; +import static com.carrotsearch.randomizedtesting.RandomizedTest.systemPropertyAsBoolean; +import static com.carrotsearch.randomizedtesting.RandomizedTest.systemPropertyAsInt; + +import java.io.*; +import java.lang.annotation.*; import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.IdentityHashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map.Entry; -import java.util.Map; -import java.util.Random; -import java.util.Set; -import java.util.TimeZone; +import java.util.*; import java.util.concurrent.*; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.codecs.Codec; -import org.apache.lucene.codecs.PostingsFormat; -import org.apache.lucene.codecs.appending.AppendingCodec; -import org.apache.lucene.codecs.lucene3x.PreFlexRWCodec; -import org.apache.lucene.codecs.lucene40.Lucene40Codec; -import org.apache.lucene.codecs.simpletext.SimpleTextCodec; import org.apache.lucene.document.Field; import org.apache.lucene.document.FieldType; -import org.apache.lucene.index.AtomicReader; -import org.apache.lucene.index.CompositeReader; -import org.apache.lucene.index.DirectoryReader; -import org.apache.lucene.index.FieldFilterAtomicReader; -import org.apache.lucene.index.FieldInfo; +import org.apache.lucene.index.*; import org.apache.lucene.index.IndexReader.ReaderClosedListener; -import org.apache.lucene.index.AlcoholicMergePolicy; -import org.apache.lucene.index.IndexReader; -import org.apache.lucene.index.IndexWriterConfig; -import org.apache.lucene.index.LogByteSizeMergePolicy; -import org.apache.lucene.index.LogDocMergePolicy; -import org.apache.lucene.index.LogMergePolicy; -import org.apache.lucene.index.MockRandomMergePolicy; -import org.apache.lucene.index.ParallelAtomicReader; -import org.apache.lucene.index.ParallelCompositeReader; -import org.apache.lucene.index.RandomCodec; -import org.apache.lucene.index.RandomDocumentsWriterPerThreadPool; -import org.apache.lucene.index.SegmentReader; -import org.apache.lucene.index.SerialMergeScheduler; -import org.apache.lucene.index.SlowCompositeReaderWrapper; -import org.apache.lucene.index.TieredMergePolicy; -import org.apache.lucene.search.AssertingIndexSearcher; -import org.apache.lucene.search.BooleanQuery; +import org.apache.lucene.search.*; import org.apache.lucene.search.FieldCache.CacheEntry; -import org.apache.lucene.search.FieldCache; -import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.QueryUtils.FCInvisibleMultiReader; -import org.apache.lucene.search.RandomSimilarityProvider; -import org.apache.lucene.search.similarities.DefaultSimilarity; -import org.apache.lucene.search.similarities.Similarity; -import org.apache.lucene.store.Directory; -import org.apache.lucene.store.FSDirectory; -import org.apache.lucene.store.FlushInfo; -import org.apache.lucene.store.IOContext; -import org.apache.lucene.store.LockFactory; -import org.apache.lucene.store.MergeInfo; +import org.apache.lucene.store.*; import org.apache.lucene.store.MockDirectoryWrapper.Throttling; -import org.apache.lucene.store.MockDirectoryWrapper; -import org.apache.lucene.store.NRTCachingDirectory; import org.apache.lucene.util.FieldCacheSanityChecker.Insanity; -import org.junit.After; -import org.junit.AfterClass; -import org.junit.Assert; -import org.junit.Assume; -import org.junit.Before; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Rule; -import org.junit.internal.AssumptionViolatedException; +import org.junit.*; import org.junit.rules.RuleChain; import org.junit.rules.TestRule; -import org.junit.runner.Description; import org.junit.runner.RunWith; -import org.junit.runner.Runner; -import org.junit.runner.notification.RunListener; -import org.junit.runners.model.MultipleFailureException; -import org.junit.runners.model.Statement; -import com.carrotsearch.randomizedtesting.JUnit4MethodProvider; -import com.carrotsearch.randomizedtesting.MixWithSuiteName; -import com.carrotsearch.randomizedtesting.RandomizedContext; -import com.carrotsearch.randomizedtesting.RandomizedRunner; + +import com.carrotsearch.randomizedtesting.*; import com.carrotsearch.randomizedtesting.annotations.*; +import com.carrotsearch.randomizedtesting.generators.RandomPicks; +import com.carrotsearch.randomizedtesting.rules.SystemPropertiesInvariantRule; /** * Base class for all Lucene unit tests, Junit3 or Junit4 variant. + * + *

Class and instance setup.

+ * *

- *

- *

- * If you - * override either setUp() or - * tearDown() in your unit test, make sure you - * call super.setUp() and - * super.tearDown() - *

- * - * @After - replaces setup - * @Before - replaces teardown - * @Test - any public method with this annotation is a test case, regardless - * of its name - *

+ * The preferred way to specify class (suite-level) setup/cleanup is to use + * static methods annotated with {@link BeforeClass} and {@link AfterClass}. Any + * code in these methods us executed withing the test framework's control and + * ensure proper setup has been made. Try not to use static initializers + * (including complex final field initializers). Static initializers are + * executed before any setup rules can be executed and may cause you (or + * somebody else) headaches. + * *

- * See Junit4 documentation for a complete list of features. + * For instance-level setup, use {@link Before} and {@link After} annotated + * methods. If you override either {@link #setUp()} or {@link #tearDown()} in + * your subclass, make sure you call super.setUp() and + * super.tearDown(). This is detected and enforced. + * + *

Specifying test cases

+ * *

- * Import from org.junit rather than junit.framework. + * Any test method with a testXXX prefix is considered a test case. + * Any test method annotated with {@link Test} is considered a test case. + * + *

Randomized execution and test facilities

+ * *

- * You should be able to use this class anywhere you used LuceneTestCase - * if you annotate your derived class correctly with the annotations above - * @see #assertSaneFieldCaches(String) + * {@link LuceneTestCase} uses {@link RandomizedRunner} to execute test cases. + * {@link RandomizedRunner} has built-in support for tests randomization + * including access to a repeatable {@link Random} instance. See + * {@link #random()} method. Any test using {@link Random} acquired from + * {@link #random()} should be fully reproducible (assuming no race conditions + * between threads etc.). The initial seed for a test case is reported in many + * ways: + *

    + *
  • as part of any exception thrown from its body (inserted as a dummy stack + * trace entry),
  • + *
  • as part of the main thread executing the test case (if your test hangs, + * just dump the stack trace of all threads and you'll see the seed),
  • + *
  • the master seed can also be accessed manually by getting the current + * context ({@link RandomizedContext#current()}) and then calling + * {@link RandomizedContext#getRunnerSeedAsString()}. + *
+ * + *

There is a number of other facilities tests can use, like: + *

    + *
  • {@link #closeAfterTest(Closeable)} and {@link #closeAfterSuite(Closeable)} to + * register resources to be closed after each scope (if close fails, the scope + * will fail too). + *
*/ @RunWith(RandomizedRunner.class) @TestMethodProviders({ @@ -148,123 +108,245 @@ import com.carrotsearch.randomizedtesting.annotations.*; }) @Validators({ RequireAssertions.class, - NoStaticHooksShadowing.class + NoStaticHooksShadowing.class, + NoInstanceHooksOverrides.class +}) +@Listeners({ + PrintReproduceInfoListener.class }) @SeedDecorators({MixWithSuiteName.class}) // See LUCENE-3995 for rationale. @ThreadLeaks(failTestIfLeaking = false) public abstract class LuceneTestCase extends Assert { + + // ----------------------------------------------------------------- + // Test groups and other annotations modifying tests' behavior. + // ----------------------------------------------------------------- + /** - * true if and only if tests are run in verbose mode. Note: if it is false, tests are not - * expected to print any messages. + * Annotation for tests that should only be run during nightly builds. */ - public static final boolean VERBOSE = Boolean.getBoolean("tests.verbose"); + @Documented + @Inherited + @Retention(RetentionPolicy.RUNTIME) + @TestGroup(enabled = false, sysProperty = "tests.nightly") + public @interface Nightly {} - public static final boolean INFOSTREAM = Boolean.parseBoolean(System.getProperty("tests.infostream", Boolean.toString(VERBOSE))); + /** + * Annotation for tests that should only be run during weekly builds + */ + @Documented + @Inherited + @Retention(RetentionPolicy.RUNTIME) + @TestGroup(enabled = false, sysProperty = "tests.weekly") + public @interface Weekly {} - /** Use this constant when creating Analyzers and any other version-dependent stuff. + /** + * Annotation for tests which exhibit a known issue and are temporarily disabled. + */ + @Documented + @Inherited + @Retention(RetentionPolicy.RUNTIME) + @TestGroup(enabled = false, sysProperty = "tests.awaitsfix") + public @interface AwaitsFix { + /** Point to JIRA entry. */ + public String bugUrl(); + } + + /** + * Annotation for tests that are really slow and should be run only when specifically + * asked to run. + */ + @Documented + @Inherited + @Retention(RetentionPolicy.RUNTIME) + @TestGroup(enabled = false, sysProperty = "tests.slow") + public @interface Slow {} + + /** + * Annotation for test classes that should avoid certain codec types + * (because they are expensive, for example). + */ + @Documented + @Inherited + @Retention(RetentionPolicy.RUNTIME) + @Target(ElementType.TYPE) + public @interface SuppressCodecs { + String[] value(); + } + + + // ----------------------------------------------------------------- + // Truly immutable fields and constants, initialized once and valid + // for all suites ever since. + // ----------------------------------------------------------------- + + /** + * Use this constant when creating Analyzers and any other version-dependent stuff. *

NOTE: Change this when development starts for new Lucene version: */ public static final Version TEST_VERSION_CURRENT = Version.LUCENE_40; - /** Create indexes in this directory, optimally use a subdir, named after the test */ - public static final File TEMP_DIR; - static { - String s = System.getProperty("tempDir", System.getProperty("java.io.tmpdir")); - if (s == null) - throw new RuntimeException("To run tests, you need to define system property 'tempDir' or 'java.io.tmpdir'."); - TEMP_DIR = new File(s); - TEMP_DIR.mkdirs(); - } + /** + * True if and only if tests are run in verbose mode. If this flag is false + * tests are not expected to print any messages. + */ + public static final boolean VERBOSE = systemPropertyAsBoolean("tests.verbose", false); - /** set of directories we created, in afterclass we try to clean these up */ - private static final Map tempDirs = Collections.synchronizedMap(new HashMap()); + /** TODO: javadoc? */ + public static final boolean INFOSTREAM = systemPropertyAsBoolean("tests.infostream", VERBOSE); - private static String DEFAULT_LINE_DOCS_FILE = "europarl.lines.txt.gz"; - private static String JENKINS_LARGE_LINE_DOCS_FILE = "enwiki.random.lines.txt"; + /** + * A random multiplier which you should use when writing random tests: + * multiply it by the number of iterations to scale your tests (for nightly builds). + */ + public static final int RANDOM_MULTIPLIER = systemPropertyAsInt("tests.multiplier", 1); - // TODO: the fact these are static final means they're initialized on class load and they should - // be reinitialized on before suite hooks (to allow proper tests). + /** TODO: javadoc? */ + public static final String DEFAULT_LINE_DOCS_FILE = "europarl.lines.txt.gz"; + + /** TODO: javadoc? */ + public static final String JENKINS_LARGE_LINE_DOCS_FILE = "enwiki.random.lines.txt"; - // by default we randomly pick a different codec for - // each test case (non-J4 tests) and each test class (J4 - // tests) /** Gets the codec to run tests with. */ public static final String TEST_CODEC = System.getProperty("tests.codec", "random"); + /** Gets the postingsFormat to run tests with. */ public static final String TEST_POSTINGSFORMAT = System.getProperty("tests.postingsformat", "random"); + /** Gets the directory to run tests with */ public static final String TEST_DIRECTORY = System.getProperty("tests.directory", "random"); - /** Get the number of times to run tests */ - public static final int TEST_ITER = Integer.parseInt(System.getProperty("tests.iter", "1")); - /** Get the minimum number of times to run tests until a failure happens */ - public static final int TEST_ITER_MIN = Integer.parseInt(System.getProperty("tests.iter.min", Integer.toString(TEST_ITER))); - /** whether or not @nightly tests should run */ - public static final boolean TEST_NIGHTLY = Boolean.parseBoolean(System.getProperty("tests.nightly", "false")); + /** the line file used by LineFileDocs */ public static final String TEST_LINE_DOCS_FILE = System.getProperty("tests.linedocsfile", DEFAULT_LINE_DOCS_FILE); - /** whether or not to clean threads between test invocations: "false", "perMethod", "perClass" */ - public static final String TEST_CLEAN_THREADS = System.getProperty("tests.cleanthreads", "perClass"); - /** whether or not to clean threads between test invocations: "false", "perMethod", "perClass" */ + + /** Whether or not @nightly tests should run. */ + public static final boolean TEST_NIGHTLY = systemPropertyAsBoolean("tests.nightly", false); + + /** Throttling, see {@link MockDirectoryWrapper#setThrottling(Throttling)}. */ public static final Throttling TEST_THROTTLING = TEST_NIGHTLY ? Throttling.SOMETIMES : Throttling.NEVER; - /** Gets the locale to run tests with */ - public static String TEST_LOCALE; - /** Gets the timezone to run tests with */ - public static String TEST_TIMEZONE; + /** Create indexes in this directory, optimally use a subdir, named after the test */ + public static final File TEMP_DIR; + static { + String s = System.getProperty("tempDir", System.getProperty("java.io.tmpdir")); + if (s == null) + throw new RuntimeException("To run tests, you need to define system property 'tempDir' or 'java.io.tmpdir'."); + TEMP_DIR = new File(s); + TEMP_DIR.mkdirs(); + } /** - * A random multiplier which you should use when writing random tests: - * multiply it by the number of iterations + * These property keys will be ignored in verification of altered properties. + * @see SystemPropertiesInvariantRule + * @see #ruleChain + * @see #classRules */ - public static final int RANDOM_MULTIPLIER = Integer.parseInt(System.getProperty("tests.multiplier", "1")); + private static final String [] IGNORED_INVARIANT_PROPERTIES = { + "user.timezone" + }; + + /** Filesystem-based {@link Directory} implementations. */ + private static final List FS_DIRECTORIES = Arrays.asList( + "SimpleFSDirectory", + "NIOFSDirectory", + "MMapDirectory" + ); - /** @lucene.internal */ + /** All {@link Directory} implementations. */ + private static final List CORE_DIRECTORIES; + static { + CORE_DIRECTORIES = new ArrayList(FS_DIRECTORIES); + CORE_DIRECTORIES.add("RAMDirectory"); + }; + + + // ----------------------------------------------------------------- + // Fields initialized in class or instance rules. + // ----------------------------------------------------------------- + + /** + * @lucene.internal + */ public static boolean PREFLEX_IMPERSONATION_IS_ACTIVE; + + // ----------------------------------------------------------------- + // Class level (suite) rules. + // ----------------------------------------------------------------- + /** - * @see SubclassSetupTeardownRule + * Stores the currently class under test. */ - private boolean setupCalled; + private static final StoreClassNameRule classNameRule; /** - * @see SubclassSetupTeardownRule + * Class environment setup rule. + */ + public static final SetupAndRestoreClassEnvRule classEnvRule; + + /** + * This controls how suite-level rules are nested. It is important that _all_ rules declared + * in {@link LuceneTestCase} are executed in proper order if they depend on each + * other. */ - private boolean teardownCalled; + @ClassRule + public static TestRule classRules = RuleChain + .outerRule(new SystemPropertiesInvariantRule(IGNORED_INVARIANT_PROPERTIES)) + .around(new IcuHackRule()) + .around(classNameRule = new StoreClassNameRule()) + .around(new UncaughtExceptionsRule()) + .around(classEnvRule = new SetupAndRestoreClassEnvRule()); + + + // ----------------------------------------------------------------- + // Test level rules. + // ----------------------------------------------------------------- + + /** Enforces {@link #setUp()} and {@link #tearDown()} calls are chained. */ + private SubclassSetupTeardownRule parentChainCallRule = new SubclassSetupTeardownRule(); - private int savedBoolMaxClauseCount = BooleanQuery.getMaxClauseCount(); + /** Save test thread and name. */ + private ThreadNameAndTestNameRule threadAndTestNameRule = new ThreadNameAndTestNameRule(); /** - * Some tests expect the directory to contain a single segment, and want to do tests on that segment's reader. - * This is an utility method to help them. + * This controls how individual test rules are nested. It is important that + * _all_ rules declared in {@link LuceneTestCase} are executed in proper order + * if they depend on each other. */ - public static SegmentReader getOnlySegmentReader(DirectoryReader reader) { - IndexReader[] subReaders = reader.getSequentialSubReaders(); - if (subReaders.length != 1) - throw new IllegalArgumentException(reader + " has " + subReaders.length + " segments instead of exactly one"); - assertTrue(subReaders[0] instanceof SegmentReader); - return (SegmentReader) subReaders[0]; - } + @Rule + public final TestRule ruleChain = RuleChain + .outerRule(threadAndTestNameRule) + .around(new UncaughtExceptionsRule()) + .around(new SystemPropertiesInvariantRule(IGNORED_INVARIANT_PROPERTIES)) + .around(new SetupAndRestoreInstanceEnvRule()) + .around(new FieldCacheSanityRule()) + .around(parentChainCallRule); - // default codec - private static Codec savedCodec; - - private static InfoStream savedInfoStream; - private static Similarity similarity; + // ----------------------------------------------------------------- + // Suite and test case setup/ cleanup. + // ----------------------------------------------------------------- - private static Locale locale; - private static Locale savedLocale; - private static TimeZone timeZone; - private static TimeZone savedTimeZone; + /** + * For subclasses to override. Overrides must call {@code super.setUp()}. + */ + @Before + public void setUp() throws Exception { + parentChainCallRule.setupCalled = true; + } /** - * Restore these system property values in {@link #afterClassLuceneTestCaseJ4()}. + * For subclasses to override. Overrides must call {@code super.tearDown()}. */ - private static HashMap restoreProperties = new HashMap(); + @After + public void tearDown() throws Exception { + parentChainCallRule.teardownCalled = true; + } - protected static Map stores; - private static List testClassesRun = new ArrayList(); + // ----------------------------------------------------------------- + // Test facilities and facades for subclasses. + // ----------------------------------------------------------------- /** * Access to the current {@link RandomizedContext}'s Random instance. It is safe to use @@ -282,7 +364,7 @@ public abstract class LuceneTestCase extends Assert { * invocations are present or create a derivative local {@link Random} for millions of calls * like this: *

-   * Random random = random();
+   * Random random = new Random(random().nextLong());
    * // tight loop with many invocations. 
    * 
*/ @@ -290,464 +372,50 @@ public abstract class LuceneTestCase extends Assert { return RandomizedContext.current().getRandom(); } - @Deprecated - private static boolean icuTested = false; - - /** - * Stores the currently class under test. - */ - private static final StoreClassNameRule classNameRule = new StoreClassNameRule(); - - /** - * Catch any uncaught exceptions on threads within the suite scope and fail the test/ - * suite if they happen. - */ - private static final UncaughtExceptionsRule uncaughtExceptionsRule = new UncaughtExceptionsRule(null); - /** - * These property keys will be ignored in verification of altered properties. - * @see SystemPropertiesInvariantRule - * @see #ruleChain - * @see #classRules - */ - private static final String [] ignoredInvariantProperties = { - "user.timezone" - }; - - /** - * This controls how suite-level rules are nested. It is important that _all_ rules declared - * in {@link LuceneTestCase} are executed in proper order if they depend on each - * other. - */ - @ClassRule - public static TestRule classRules = RuleChain - .outerRule(new SystemPropertiesInvariantRule(ignoredInvariantProperties)) - .around(classNameRule) - .around(uncaughtExceptionsRule); - - /** - * This controls how individual test rules are nested. It is important that _all_ rules declared - * in {@link LuceneTestCase} are executed in proper order if they depend on each - * other. + * Registers a {@link Closeable} resource that should be closed after the test + * completes. + * + * @return resource (for call chaining). */ - @Rule - public final TestRule ruleChain = RuleChain - .outerRule(new SaveThreadAndTestNameRule()) - .around(new UncaughtExceptionsRule(this)) - .around(new TestResultInterceptorRule()) - .around(new SystemPropertiesInvariantRule(ignoredInvariantProperties)) - .around(new InternalSetupTeardownRule()) - .around(new SubclassSetupTeardownRule()); - - @BeforeClass - static void beforeClassLuceneTestCaseJ4() { - testClassesRun.add(getTestClass().getSimpleName()); - - tempDirs.clear(); - stores = Collections.synchronizedMap(new IdentityHashMap()); - - // enable this by default, for IDE consistency with ant tests (as its the default from ant) - // TODO: really should be in solr base classes, but some extend LTC directly. - // we do this in beforeClass, because some tests currently disable it - restoreProperties.put("solr.directoryFactory", System.getProperty("solr.directoryFactory")); - if (System.getProperty("solr.directoryFactory") == null) { - System.setProperty("solr.directoryFactory", "org.apache.solr.core.MockDirectoryFactory"); - } - - // enable the Lucene 3.x PreflexRW codec explicitly, to work around bugs in IBM J9 / Harmony ServiceLoader: - try { - final java.lang.reflect.Field spiLoaderField = Codec.class.getDeclaredField("loader"); - spiLoaderField.setAccessible(true); - final Object spiLoader = spiLoaderField.get(null); - final java.lang.reflect.Field modifiableServicesField = NamedSPILoader.class.getDeclaredField("modifiableServices"); - modifiableServicesField.setAccessible(true); - @SuppressWarnings({"unchecked","rawtypes"}) final Map serviceMap = - (Map) modifiableServicesField.get(spiLoader); - if (!(Codec.forName("Lucene3x") instanceof PreFlexRWCodec)) { - if (Constants.JAVA_VENDOR.startsWith("IBM")) { - // definitely a buggy version - System.err.println("ERROR: Your VM's java.util.ServiceLoader implementation is buggy"+ - " and does not respect classpath order, please report this to the vendor."); - } else { - // could just be a classpath issue - System.err.println("ERROR: fix your classpath to have tests-framework.jar before lucene-core.jar!"+ - " If you have already done this, then your VM's java.util.ServiceLoader implementation is buggy"+ - " and does not respect classpath order, please report this to the vendor."); - } - serviceMap.put("Lucene3x", new PreFlexRWCodec()); - } - } catch (Exception e) { - throw new RuntimeException("Cannot access internals of Codec and NamedSPILoader classes", e); - } - - // if verbose: print some debugging stuff about which codecs are loaded - if (VERBOSE) { - Set codecs = Codec.availableCodecs(); - for (String codec : codecs) { - System.out.println("Loaded codec: '" + codec + "': " + Codec.forName(codec).getClass().getName()); - } - - Set postingsFormats = PostingsFormat.availablePostingsFormats(); - for (String postingsFormat : postingsFormats) { - System.out.println("Loaded postingsFormat: '" + postingsFormat + "': " + PostingsFormat.forName(postingsFormat).getClass().getName()); - } - } - - savedInfoStream = InfoStream.getDefault(); - final boolean v = random().nextBoolean(); - if (INFOSTREAM) { - InfoStream.setDefault(new PrintStreamInfoStream(System.out)); - } else { - if (v) { - InfoStream.setDefault(new NullInfoStream()); - } - } - - Class targetClass = RandomizedContext.current().getTargetClass(); - if (targetClass.isAnnotationPresent(SuppressCodecs.class)) { - SuppressCodecs a = targetClass.getAnnotation(SuppressCodecs.class); - avoidCodecs = new HashSet(Arrays.asList(a.value())); - System.err.println("NOTE: Suppressing codecs " + Arrays.toString(a.value()) - + " for " + targetClass.getSimpleName() + "."); - } else { - avoidCodecs = null; - } - - - PREFLEX_IMPERSONATION_IS_ACTIVE = false; - savedCodec = Codec.getDefault(); - final Codec codec; - int randomVal = random().nextInt(10); - - if ("Lucene3x".equals(TEST_CODEC) || ("random".equals(TEST_CODEC) && randomVal < 2 && !shouldAvoidCodec("Lucene3x"))) { // preflex-only setup - codec = Codec.forName("Lucene3x"); - assert (codec instanceof PreFlexRWCodec) : "fix your classpath to have tests-framework.jar before lucene-core.jar"; - PREFLEX_IMPERSONATION_IS_ACTIVE = true; - } else if ("SimpleText".equals(TEST_CODEC) || ("random".equals(TEST_CODEC) && randomVal == 9 && !shouldAvoidCodec("SimpleText"))) { - codec = new SimpleTextCodec(); - } else if ("Appending".equals(TEST_CODEC) || ("random".equals(TEST_CODEC) && randomVal == 8 && !shouldAvoidCodec("Appending"))) { - codec = new AppendingCodec(); - } else if (!"random".equals(TEST_CODEC)) { - codec = Codec.forName(TEST_CODEC); - } else if ("random".equals(TEST_POSTINGSFORMAT)) { - codec = new RandomCodec(random(), avoidCodecs); - } else { - codec = new Lucene40Codec() { - private final PostingsFormat format = PostingsFormat.forName(TEST_POSTINGSFORMAT); - - @Override - public PostingsFormat getPostingsFormatForField(String field) { - return format; - } - - @Override - public String toString() { - return super.toString() + ": " + format.toString(); - } - }; - } - - Codec.setDefault(codec); - - savedLocale = Locale.getDefault(); - - // START hack to init ICU safely before we randomize locales. - // ICU fails during classloading when a special Java7-only locale is the default - // see: http://bugs.icu-project.org/trac/ticket/8734 - if (!icuTested) { - icuTested = true; - try { - Locale.setDefault(Locale.US); - Class.forName("com.ibm.icu.util.ULocale"); - } catch (ClassNotFoundException cnfe) { - // ignore if no ICU is in classpath - } - } - // END hack - - // Initialize locale/ timezone. - TEST_LOCALE = System.getProperty("tests.locale", "random"); - TEST_TIMEZONE = System.getProperty("tests.timezone", "random"); - - // Always pick a random one for consistency (whether TEST_LOCALE was specified or not). - Locale randomLocale = randomLocale(random()); - locale = TEST_LOCALE.equals("random") ? randomLocale : localeForName(TEST_LOCALE); - Locale.setDefault(locale); - // TimeZone.getDefault will set user.timezone to the default timezone of the user's locale. - // So store the original property value and restore it at end. - restoreProperties.put("user.timezone", System.getProperty("user.timezone")); - savedTimeZone = TimeZone.getDefault(); - TimeZone randomTimeZone = randomTimeZone(random()); - timeZone = TEST_TIMEZONE.equals("random") ? randomTimeZone : TimeZone.getTimeZone(TEST_TIMEZONE); - TimeZone.setDefault(timeZone); - similarity = random().nextBoolean() ? new DefaultSimilarity() : new RandomSimilarityProvider(random()); - testsFailed = false; + public T closeAfterTest(T resource) { + return RandomizedContext.current().closeAtEnd(resource, LifecycleScope.TEST); } - @AfterClass - static void afterClassLuceneTestCaseJ4() { - for (Map.Entry e : restoreProperties.entrySet()) { - if (e.getValue() == null) { - System.clearProperty(e.getKey()); - } else { - System.setProperty(e.getKey(), e.getValue()); - } - } - restoreProperties.clear(); - - Throwable problem = null; - - if (!"false".equals(TEST_CLEAN_THREADS)) { - int rogueThreads = threadCleanup("test class"); - if (rogueThreads > 0) { - // TODO: fail here once the leaks are fixed. - System.err.println("RESOURCE LEAK: test class left " + rogueThreads + " thread(s) running"); - } - } - - String codecDescription = Codec.getDefault().toString(); - Codec.setDefault(savedCodec); - InfoStream.setDefault(savedInfoStream); - Locale.setDefault(savedLocale); - TimeZone.setDefault(savedTimeZone); - System.clearProperty("solr.solr.home"); - System.clearProperty("solr.data.dir"); - - try { - // now look for unclosed resources - if (!testsFailed) { - checkResourcesAfterClass(); - } - } catch (Throwable t) { - if (problem == null) problem = t; - } - - stores = null; - - try { - // clear out any temp directories if we can - if (!testsFailed) { - clearTempDirectoriesAfterClass(); - } - } catch (Throwable t) { - if (problem == null) problem = t; - } - - // if we had afterClass failures, get some debugging information - if (problem != null) { - reportPartialFailureInfo(); - } - - if (uncaughtExceptionsRule.hasUncaughtExceptions()) { - testsFailed = true; - } - - // if verbose or tests failed, report some information back - if (VERBOSE || testsFailed || problem != null) { - printDebuggingInformation(codecDescription); - } - - if (problem != null) { - throw new RuntimeException(problem); - } - } - - /** print some useful debugging information about the environment */ - private static void printDebuggingInformation(String codecDescription) { - System.err.println("NOTE: test params are: codec=" + codecDescription + - ", sim=" + similarity + - ", locale=" + locale + - ", timezone=" + (timeZone == null ? "(null)" : timeZone.getID())); - System.err.println("NOTE: all tests run in this JVM:"); - System.err.println(Arrays.toString(testClassesRun.toArray())); - System.err.println("NOTE: " + System.getProperty("os.name") + " " - + System.getProperty("os.version") + " " - + System.getProperty("os.arch") + "/" - + System.getProperty("java.vendor") + " " - + System.getProperty("java.version") + " " - + (Constants.JRE_IS_64BIT ? "(64-bit)" : "(32-bit)") + "/" - + "cpus=" + Runtime.getRuntime().availableProcessors() + "," - + "threads=" + Thread.activeCount() + "," - + "free=" + Runtime.getRuntime().freeMemory() + "," - + "total=" + Runtime.getRuntime().totalMemory()); - } - - /** check that directories and their resources were closed */ - private static void checkResourcesAfterClass() { - for (MockDirectoryWrapper d : stores.keySet()) { - if (d.isOpen()) { - StackTraceElement elements[] = stores.get(d); - // Look for the first class that is not LuceneTestCase that requested - // a Directory. The first two items are of Thread's, so skipping over - // them. - StackTraceElement element = null; - for (int i = 2; i < elements.length; i++) { - StackTraceElement ste = elements[i]; - if (ste.getClassName().indexOf("LuceneTestCase") == -1) { - element = ste; - break; - } - } - fail("directory of test was not closed, opened from: " + element); - } - } - } - - /** clear temp directories: this will fail if its not successful */ - private static void clearTempDirectoriesAfterClass() { - for (Entry entry : tempDirs.entrySet()) { - try { - _TestUtil.rmDir(entry.getKey()); - } catch (IOException e) { - e.printStackTrace(); - System.err.println("path " + entry.getKey() + " allocated from"); - // first two STE's are Java's - StackTraceElement[] elements = entry.getValue(); - for (int i = 2; i < elements.length; i++) { - StackTraceElement ste = elements[i]; - // print only our code's stack information - if (ste.getClassName().indexOf("org.apache.lucene") == -1) break; - System.err.println("\t" + ste); - } - fail("could not remove temp dir: " + entry.getKey()); - } - } - } - - protected static boolean testsFailed; /* true if any tests failed */ - /** - * Control the outcome of each test's output status (failure, assumption-failure). This - * would ideally be handled by attaching a {@link RunListener} to a {@link Runner} (because - * then we would be notified about static block failures). - * TODO: make this a test listener. - */ - private class TestResultInterceptorRule implements TestRule { - @Override - public Statement apply(final Statement base, final Description description) { - return new Statement() { - @Override - public void evaluate() throws Throwable { - try { - base.evaluate(); - } catch (AssumptionViolatedException t) { - throw t; - } catch (Throwable t) { - failed(t, description); - throw t; - } - } - }; - } - - private void failed(Throwable e, Description description) { - testsFailed = true; - reportAdditionalFailureInfo(); - assert !(e instanceof AssumptionViolatedException); - } - }; - - /** - * The thread executing the current test case. - * @see #isTestThread() - */ - volatile Thread testCaseThread; - - /** - * @see LuceneTestCase#testCaseThread + * Registers a {@link Closeable} resource that should be closed after the suite + * completes. + * + * @return resource (for call chaining). */ - private class SaveThreadAndTestNameRule implements TestRule { - private String previousName; - - @Override - public Statement apply(final Statement base, final Description description) { - return new Statement() { - public void evaluate() throws Throwable { - try { - Thread current = Thread.currentThread(); - previousName = current.getName(); - LuceneTestCase.this.testCaseThread = current; - LuceneTestCase.this.name = description.getMethodName(); - base.evaluate(); - } finally { - LuceneTestCase.this.testCaseThread.setName(previousName); - LuceneTestCase.this.testCaseThread = null; - LuceneTestCase.this.name = null; - } - } - }; - } + public static T closeAfterSuite(T resource) { + return RandomizedContext.current().closeAtEnd(resource, LifecycleScope.SUITE); } /** - * Internal {@link LuceneTestCase} setup before/after each test. + * Return the current class being tested. */ - private class InternalSetupTeardownRule implements TestRule { - @Override - public Statement apply(final Statement base, Description description) { - return new Statement() { - @Override - public void evaluate() throws Throwable { - // We simulate the previous behavior of @Before in that - // if any statement below us fails, we just propagate the original - // exception and do not call tearDownInternal. - setUpInternal(); - final ArrayList errors = new ArrayList(); - try { - // But we will collect errors from statements below and wrap them - // into a multiple so that tearDownInternal is called. - base.evaluate(); - } catch (Throwable t) { - errors.add(t); - } - - try { - tearDownInternal(); - } catch (Throwable t) { - errors.add(t); - } - - MultipleFailureException.assertEmpty(errors); - } - }; - } + public static Class getTestClass() { + return classNameRule.getTestClass(); } /** - * Setup before the tests. + * Return the name of the currently executing test case. */ - private final void setUpInternal() throws Exception { - Thread.currentThread().setName("LTC-main#seed=" + - RandomizedContext.current().getRunnerSeedAsString()); - - savedBoolMaxClauseCount = BooleanQuery.getMaxClauseCount(); - - if (avoidCodecs != null) { - String defFormat = _TestUtil.getPostingsFormat("thisCodeMakesAbsolutelyNoSenseCanWeDeleteIt"); - if (avoidCodecs.contains(defFormat)) { - assumeTrue("NOTE: A test method in " + getClass().getSimpleName() - + " was ignored, as it is not allowed to use " + defFormat + ".", false); - } - } + public String getTestName() { + return threadAndTestNameRule.testMethodName; } /** - * Forcible purges all cache entries from the FieldCache. - *

- * This method will be called by tearDown to clean up FieldCache.DEFAULT. - * If a (poorly written) test has some expectation that the FieldCache - * will persist across test methods (ie: a static IndexReader) this - * method can be overridden to do nothing. - *

- * - * @see FieldCache#purgeAllCaches() + * Some tests expect the directory to contain a single segment, and want to + * do tests on that segment's reader. This is an utility method to help them. */ - protected void purgeFieldCache(final FieldCache fc) { - fc.purgeAllCaches(); - } - - protected String getTestLabel() { - return getClass().getName() + "." + getName(); + public static SegmentReader getOnlySegmentReader(DirectoryReader reader) { + IndexReader[] subReaders = reader.getSequentialSubReaders(); + if (subReaders.length != 1) + throw new IllegalArgumentException(reader + " has " + subReaders.length + " segments instead of exactly one"); + assertTrue(subReaders[0] instanceof SegmentReader); + return (SegmentReader) subReaders[0]; } /** @@ -755,170 +423,8 @@ public abstract class LuceneTestCase extends Assert { * executing the test case. */ protected boolean isTestThread() { - assertNotNull("Test case thread not set?", testCaseThread); - return Thread.currentThread() == testCaseThread; - } - - /** - * Make sure {@link #setUp()} and {@link #tearDown()} were invoked even if they - * have been overriden. We assume nobody will call these out of non-overriden - * methods (they have to be public by contract, unfortunately). The top-level - * methods just set a flag that is checked upon successful execution of each test - * case. - */ - private class SubclassSetupTeardownRule implements TestRule { - @Override - public Statement apply(final Statement base, Description description) { - return new Statement() { - @Override - public void evaluate() throws Throwable { - setupCalled = false; - teardownCalled = false; - base.evaluate(); - - // I assume we don't want to check teardown chaining if something happens in the - // test because this would obscure the original exception? - if (!setupCalled) { - Assert.fail("One of the overrides of setUp does not propagate the call."); - } - if (!teardownCalled) { - Assert.fail("One of the overrides of tearDown does not propagate the call."); - } - } - }; - } - } - - /** - * For subclassing only. Overrides must call {@code super.setUp()}. - */ - @Before - public void setUp() throws Exception { - setupCalled = true; - } - - /** - * For subclassing only. Overrides must call {@code super.tearDown()}. - */ - @After - public void tearDown() throws Exception { - teardownCalled = true; - } - - /** - * Clean up after tests. - */ - private final void tearDownInternal() throws Exception { - Throwable problem = null; - BooleanQuery.setMaxClauseCount(savedBoolMaxClauseCount); - - // this won't throw any exceptions or fail the test - // if we change this, then change this logic - checkRogueThreadsAfter(); - - try { - // calling assertSaneFieldCaches here isn't as useful as having test - // classes call it directly from the scope where the index readers - // are used, because they could be gc'ed just before this tearDown - // method is called. - // - // But it's better then nothing. - // - // If you are testing functionality that you know for a fact - // "violates" FieldCache sanity, then you should either explicitly - // call purgeFieldCache at the end of your test method, or refactor - // your Test class so that the inconsistant FieldCache usages are - // isolated in distinct test methods - assertSaneFieldCaches(getTestLabel()); - } catch (Throwable t) { - if (problem == null) problem = t; - } - - purgeFieldCache(FieldCache.DEFAULT); - - if (problem != null) { - reportAdditionalFailureInfo(); - // TODO: simply rethrow problem, without wrapping? - throw new RuntimeException(problem); - } - } - - /** check if the test still has threads running, we don't want them to - * fail in a subsequent test and pass the blame to the wrong test */ - private void checkRogueThreadsAfter() { - if ("perMethod".equals(TEST_CLEAN_THREADS)) { - int rogueThreads = threadCleanup("test method: '" + getName() + "'"); - if (!testsFailed && rogueThreads > 0) { - System.err.println("RESOURCE LEAK: test method: '" + getName() - + "' left " + rogueThreads + " thread(s) running"); - } - } - } - - private final static int THREAD_STOP_GRACE_MSEC = 10; - // jvm-wide list of 'rogue threads' we found, so they only get reported once. - private final static IdentityHashMap rogueThreads = new IdentityHashMap(); - - static { - // just a hack for things like eclipse test-runner threads - for (Thread t : Thread.getAllStackTraces().keySet()) { - rogueThreads.put(t, true); - } - - if (TEST_ITER > 1) { - System.out.println("WARNING: you are using -Dtests.iter=n where n > 1, not all tests support this option."); - System.out.println("Some may crash or fail: this is not a bug."); - } - } - - /** - * Looks for leftover running threads, trying to kill them off, - * so they don't fail future tests. - * returns the number of rogue threads that it found. - */ - private static int threadCleanup(String context) { - // educated guess - Thread[] stillRunning = new Thread[Thread.activeCount()+1]; - int threadCount = 0; - int rogueCount = 0; - - if ((threadCount = Thread.enumerate(stillRunning)) > 1) { - while (threadCount == stillRunning.length) { - // truncated response - stillRunning = new Thread[stillRunning.length*2]; - threadCount = Thread.enumerate(stillRunning); - } - - for (int i = 0; i < threadCount; i++) { - Thread t = stillRunning[i]; - - if (t.isAlive() && - !rogueThreads.containsKey(t) && - t != Thread.currentThread() && - /* its ok to keep your searcher across test cases */ - (t.getName().startsWith("LuceneTestCase") && context.startsWith("test method")) == false) { - System.err.println("WARNING: " + context + " left thread running: " + t); - rogueThreads.put(t, true); - rogueCount++; - if (t.getName().startsWith("LuceneTestCase")) { - // TODO: should we fail here now? really test should be failing? - System.err.println("PLEASE CLOSE YOUR INDEXREADERS IN YOUR TEST!!!!"); - continue; - } else { - // wait on the thread to die of natural causes - try { - t.join(THREAD_STOP_GRACE_MSEC); - } catch (InterruptedException e) { e.printStackTrace(); } - } - // try to stop the thread: - t.setUncaughtExceptionHandler(null); - Thread.setDefaultUncaughtExceptionHandler(null); - if (!t.getName().startsWith("SyncThread")) // avoid zookeeper jre crash - t.interrupt(); - } - } - } - return rogueCount; + assertNotNull("Test case thread not set?", threadAndTestNameRule.testCaseThread); + return Thread.currentThread() == threadAndTestNameRule.testCaseThread; } /** @@ -939,7 +445,7 @@ public abstract class LuceneTestCase extends Assert { * * @see org.apache.lucene.util.FieldCacheSanityChecker */ - protected void assertSaneFieldCaches(final String msg) { + protected static void assertSaneFieldCaches(final String msg) { final CacheEntry[] entries = FieldCache.DEFAULT.getCacheEntries(); Insanity[] insanity = null; try { @@ -960,10 +466,9 @@ public abstract class LuceneTestCase extends Assert { if (null != insanity) { dumpArray(msg + ": Insane FieldCache usage(s)", insanity, System.err); } - } } - + /** * Returns a number of at least i *

@@ -1017,6 +522,10 @@ public abstract class LuceneTestCase extends Assert { Assume.assumeNoException(e == null ? null : new InternalAssumptionViolatedException(msg, e)); } + /** + * Return args as a {@link Set} instance. The order of elements is not + * preserved in iterators. + */ public static Set asSet(T... args) { return new HashSet(Arrays.asList(args)); } @@ -1060,7 +569,7 @@ public abstract class LuceneTestCase extends Assert { /** create a new index writer config with random defaults using the specified random */ public static IndexWriterConfig newIndexWriterConfig(Random r, Version v, Analyzer a) { IndexWriterConfig c = new IndexWriterConfig(v, a); - c.setSimilarity(similarity); + c.setSimilarity(classEnvRule.similarity); if (r.nextBoolean()) { c.setMergeScheduler(new SerialMergeScheduler()); } @@ -1141,16 +650,15 @@ public abstract class LuceneTestCase extends Assert { public static TieredMergePolicy newTieredMergePolicy() { return newTieredMergePolicy(random()); } - + public static AlcoholicMergePolicy newAlcoholicMergePolicy() { - return newAlcoholicMergePolicy(random(), timeZone); + return newAlcoholicMergePolicy(random(), classEnvRule.timeZone); } public static AlcoholicMergePolicy newAlcoholicMergePolicy(Random r, TimeZone tz) { return new AlcoholicMergePolicy(tz, new Random(r.nextLong())); } - public static LogMergePolicy newLogMergePolicy(Random r) { LogMergePolicy logmp = r.nextBoolean() ? new LogDocMergePolicy() : new LogByteSizeMergePolicy(); logmp.setUseCompoundFile(r.nextBoolean()); @@ -1230,7 +738,8 @@ public abstract class LuceneTestCase extends Assert { public static MockDirectoryWrapper newDirectory(Random r) throws IOException { Directory impl = newDirectoryImpl(r, TEST_DIRECTORY); MockDirectoryWrapper dir = new MockDirectoryWrapper(r, maybeNRTWrap(r, impl)); - stores.put(dir, Thread.currentThread().getStackTrace()); + closeAfterSuite(new DirectoryCloseable(dir)); + dir.setThrottling(TEST_THROTTLING); if (VERBOSE) { System.out.println("NOTE: LuceneTestCase.newDirectory: returning " + dir); @@ -1256,7 +765,7 @@ public abstract class LuceneTestCase extends Assert { public static MockDirectoryWrapper newFSDirectory(File f, LockFactory lf) throws IOException { String fsdirClass = TEST_DIRECTORY; if (fsdirClass.equals("random")) { - fsdirClass = FS_DIRECTORIES[random().nextInt(FS_DIRECTORIES.length)]; + fsdirClass = RandomPicks.randomFrom(random(), FS_DIRECTORIES); } Class clazz; @@ -1265,17 +774,17 @@ public abstract class LuceneTestCase extends Assert { clazz = CommandLineUtil.loadFSDirectoryClass(fsdirClass); } catch (ClassCastException e) { // TEST_DIRECTORY is not a sub-class of FSDirectory, so draw one at random - fsdirClass = FS_DIRECTORIES[random().nextInt(FS_DIRECTORIES.length)]; + fsdirClass = RandomPicks.randomFrom(random(), FS_DIRECTORIES); clazz = CommandLineUtil.loadFSDirectoryClass(fsdirClass); } - + Directory fsdir = newFSDirectoryImpl(clazz, f); MockDirectoryWrapper dir = new MockDirectoryWrapper( random(), maybeNRTWrap(random(), fsdir)); if (lf != null) { dir.setLockFactory(lf); } - stores.put(dir, Thread.currentThread().getStackTrace()); + closeAfterSuite(new DirectoryCloseable(dir)); dir.setThrottling(TEST_THROTTLING); return dir; } catch (Exception e) { @@ -1294,7 +803,7 @@ public abstract class LuceneTestCase extends Assert { d.copy(impl, file, file, newIOContext(r)); } MockDirectoryWrapper dir = new MockDirectoryWrapper(r, maybeNRTWrap(r, impl)); - stores.put(dir, Thread.currentThread().getStackTrace()); + closeAfterSuite(new DirectoryCloseable(dir)); dir.setThrottling(TEST_THROTTLING); return dir; } @@ -1378,23 +887,8 @@ public abstract class LuceneTestCase extends Assert { } } - private static final String FS_DIRECTORIES[] = { - "SimpleFSDirectory", - "NIOFSDirectory", - "MMapDirectory" - }; - - private static final String CORE_DIRECTORIES[] = { - "RAMDirectory", - FS_DIRECTORIES[0], FS_DIRECTORIES[1], FS_DIRECTORIES[2] - }; - - public static String randomDirectory(Random random) { - if (rarely(random)) { - return CORE_DIRECTORIES[random.nextInt(CORE_DIRECTORIES.length)]; - } else { - return "RAMDirectory"; - } + public static boolean defaultCodecSupportsDocValues() { + return !Codec.getDefault().getName().equals("Lucene3x"); } private static Directory newFSDirectoryImpl( @@ -1409,21 +903,15 @@ public abstract class LuceneTestCase extends Assert { return d; } - /** - * Registers a temp directory that will be deleted when tests are done. This - * is used by {@link _TestUtil#getTempDir(String)} and - * {@link _TestUtil#unzip(File, File)}, so you should call these methods when - * possible. - */ - static void registerTempDir(File tmpFile) { - tempDirs.put(tmpFile.getAbsoluteFile(), Thread.currentThread().getStackTrace()); - } - static Directory newDirectoryImpl(Random random, String clazzName) { if (clazzName.equals("random")) { - clazzName = randomDirectory(random); + if (rarely(random)) { + clazzName = RandomPicks.randomFrom(random, CORE_DIRECTORIES); + } else { + clazzName = "RAMDirectory"; + } } - + try { final Class clazz = CommandLineUtil.loadDirectoryClass(clazzName); // If it is a FSDirectory type, try its ctor(File) @@ -1440,7 +928,10 @@ public abstract class LuceneTestCase extends Assert { } } - /** Sometimes wrap the IndexReader as slow, parallel or filter reader (or combinations of that) */ + /** + * Sometimes wrap the IndexReader as slow, parallel or filter reader (or + * combinations of that) + */ public static IndexReader maybeWrapReader(IndexReader r) throws IOException { Random random = random(); if (rarely()) { @@ -1495,16 +986,45 @@ public abstract class LuceneTestCase extends Assert { return r; } - /** create a new searcher over the reader. - * This searcher might randomly use threads. */ + /** TODO: javadoc */ + public static IOContext newIOContext(Random random) { + final int randomNumDocs = random.nextInt(4192); + final int size = random.nextInt(512) * randomNumDocs; + final IOContext context; + switch (random.nextInt(5)) { + case 0: + context = IOContext.DEFAULT; + break; + case 1: + context = IOContext.READ; + break; + case 2: + context = IOContext.READONCE; + break; + case 3: + context = new IOContext(new MergeInfo(randomNumDocs, size, true, -1)); + break; + case 4: + context = new IOContext(new FlushInfo(randomNumDocs, size)); + break; + default: + context = IOContext.DEFAULT; + } + return context; + } + + /** + * Create a new searcher over the reader. This searcher might randomly use + * threads. + */ public static IndexSearcher newSearcher(IndexReader r) throws IOException { return newSearcher(r, true); } - /** create a new searcher over the reader. - * This searcher might randomly use threads. - * if maybeWrap is true, this searcher might wrap the reader - * with one that returns null for getSequentialSubReaders. + /** + * Create a new searcher over the reader. This searcher might randomly use + * threads. if maybeWrap is true, this searcher might wrap the + * reader with one that returns null for getSequentialSubReaders. */ public static IndexSearcher newSearcher(IndexReader r, boolean maybeWrap) throws IOException { Random random = random(); @@ -1513,7 +1033,7 @@ public abstract class LuceneTestCase extends Assert { r = maybeWrapReader(r); } IndexSearcher ret = random.nextBoolean() ? new AssertingIndexSearcher(random, r) : new AssertingIndexSearcher(random, r.getTopReaderContext()); - ret.setSimilarity(similarity); + ret.setSimilarity(classEnvRule.similarity); return ret; } else { int threads = 0; @@ -1535,38 +1055,23 @@ public abstract class LuceneTestCase extends Assert { r.addReaderClosedListener(new ReaderClosedListener() { @Override public void onClose(IndexReader reader) { - shutdownExecutorService(ex); + _TestUtil.shutdownExecutorService(ex); } }); } IndexSearcher ret = random.nextBoolean() ? new AssertingIndexSearcher(random, r, ex) : new AssertingIndexSearcher(random, r.getTopReaderContext(), ex); - ret.setSimilarity(similarity); + ret.setSimilarity(classEnvRule.similarity); return ret; } } - static void shutdownExecutorService(ExecutorService ex) { - if (ex != null) { - ex.shutdown(); - try { - ex.awaitTermination(1000, TimeUnit.MILLISECONDS); - } catch (InterruptedException e) { - e.printStackTrace(); - } - } - } - - public String getName() { - return this.name; - } - - /** Gets a resource from the classpath as {@link File}. This method should only be used, - * if a real file is needed. To get a stream, code should prefer + /** + * Gets a resource from the classpath as {@link File}. This method should only + * be used, if a real file is needed. To get a stream, code should prefer * {@link Class#getResourceAsStream} using {@code this.getClass()}. */ - protected File getDataFile(String name) throws IOException { try { return new File(this.getClass().getResource(name).toURI()); @@ -1575,141 +1080,10 @@ public abstract class LuceneTestCase extends Assert { } } - // We get here from InterceptTestCaseEvents on the 'failed' event.... - public static void reportPartialFailureInfo() { - System.err.println("NOTE: reproduce with (hopefully): ant test " + - "-Dtestcase=" + getTestClass().getSimpleName() + - " -Dtests.seed=" + RandomizedContext.current().getRunnerSeedAsString() + - reproduceWithExtraParams()); - } - - // We get here from InterceptTestCaseEvents on the 'failed' event.... - public void reportAdditionalFailureInfo() { - StringBuilder b = new StringBuilder(); - b.append("NOTE: reproduce with: ant test ") - .append("-Dtestcase=").append(getTestClass().getSimpleName()); - if (getName() != null) { - b.append(" -Dtests.method=").append(getName()); - } - b.append(" -Dtests.seed=") - .append(RandomizedContext.current().getRunnerSeedAsString()) - .append(reproduceWithExtraParams()); - System.err.println(b.toString()); - if (TEST_LINE_DOCS_FILE.endsWith(JENKINS_LARGE_LINE_DOCS_FILE)) { - System.err.println("NOTE: download the large Jenkins line-docs file by running 'ant get-jenkins-line-docs' in the lucene directory"); - } - } - - // extra params that were overridden needed to reproduce the command - private static String reproduceWithExtraParams() { - StringBuilder sb = new StringBuilder(); - if (locale != null) sb.append(" -Dtests.locale=").append(locale); - if (timeZone != null) sb.append(" -Dtests.timezone=").append(timeZone.getID()); - if (!TEST_CODEC.equals("random")) sb.append(" -Dtests.codec=").append(TEST_CODEC); - if (!TEST_POSTINGSFORMAT.equals("random")) sb.append(" -Dtests.postingsformat=").append(TEST_POSTINGSFORMAT); - if (!TEST_DIRECTORY.equals("random")) sb.append(" -Dtests.directory=").append(TEST_DIRECTORY); - if (RANDOM_MULTIPLIER > 1) sb.append(" -Dtests.multiplier=").append(RANDOM_MULTIPLIER); - if (TEST_NIGHTLY) sb.append(" -Dtests.nightly=true"); - if (!TEST_LINE_DOCS_FILE.equals(DEFAULT_LINE_DOCS_FILE)) sb.append(" -Dtests.linedocsfile=" + TEST_LINE_DOCS_FILE); - // TODO we can't randomize this yet (it drives ant crazy) but this makes tests reproduceable - // in case machines have different default charsets... - sb.append(" -Dargs=\"-Dfile.encoding=" + System.getProperty("file.encoding") + "\""); - return sb.toString(); - } - - public static IOContext newIOContext(Random random) { - final int randomNumDocs = random.nextInt(4192); - final int size = random.nextInt(512) * randomNumDocs; - final IOContext context; - switch (random.nextInt(5)) { - case 0: - context = IOContext.DEFAULT; - break; - case 1: - context = IOContext.READ; - break; - case 2: - context = IOContext.READONCE; - break; - case 3: - context = new IOContext(new MergeInfo(randomNumDocs, size, true, -1)); - break; - case 4: - context = new IOContext(new FlushInfo(randomNumDocs, size)); - break; - default: - context = IOContext.DEFAULT; - } - return context; - } - /** - * Return the current class being tested. + * @see SuppressCodecs */ - public static Class getTestClass() { - return classNameRule.getTestClass(); - } - - // initialized by the TestRunner - static HashSet avoidCodecs; - static boolean shouldAvoidCodec(String codec) { - return avoidCodecs != null && avoidCodecs.contains(codec); - } - - private String name = ""; - - /** - * Annotation for tests that should only be run during nightly builds. - */ - @Documented - @Inherited - @Retention(RetentionPolicy.RUNTIME) - @TestGroup(enabled = false, sysProperty = "tests.nightly") - public @interface Nightly {} - - /** - * Annotation for tests that should only be run during weekly builds - */ - @Documented - @Inherited - @Retention(RetentionPolicy.RUNTIME) - @TestGroup(enabled = false, sysProperty = "tests.weekly") - public @interface Weekly{} - - /** - * Annotation for tests which exhibit a known issue and are temporarily disabled. - */ - @Documented - @Inherited - @Retention(RetentionPolicy.RUNTIME) - @TestGroup(enabled = false, sysProperty = "tests.awaitsfix") - public @interface AwaitsFix { - /** Point to JIRA entry. */ - public String bugUrl(); - } - - /** - * Annotation for tests that are slow and should be run only when specifically asked to run - */ - @Documented - @Inherited - @Retention(RetentionPolicy.RUNTIME) - @TestGroup(enabled = false, sysProperty = "tests.slow") - public @interface Slow{} - - /** - * Annotation for test classes that should only use codecs that are not memory expensive (avoid SimpleText, MemoryCodec). - */ - @Documented - @Inherited - @Retention(RetentionPolicy.RUNTIME) - @Target(ElementType.TYPE) - public @interface SuppressCodecs { - String[] value(); - } - - protected static boolean defaultCodecSupportsDocValues() { - return !Codec.getDefault().getName().equals("Lucene3x"); + return classEnvRule.shouldAvoidCodec(codec); } } diff --git a/lucene/test-framework/src/java/org/apache/lucene/util/NoInstanceHooksOverrides.java b/lucene/test-framework/src/java/org/apache/lucene/util/NoInstanceHooksOverrides.java new file mode 100644 index 0000000..3ac059b --- /dev/null +++ b/lucene/test-framework/src/java/org/apache/lucene/util/NoInstanceHooksOverrides.java @@ -0,0 +1,89 @@ +package org.apache.lucene.util; + +/** + * 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. + */ + +import static com.carrotsearch.randomizedtesting.MethodCollector.*; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.junit.After; +import org.junit.Before; + +import com.carrotsearch.randomizedtesting.ClassValidator; + +/** + * Don't allow {@link Before} and {@link After} hook overrides as it is most + * likely a user error and will result in superclass methods not being called + * (requires manual chaining). + */ +public class NoInstanceHooksOverrides implements ClassValidator { + @Override + public void validate(Class clazz) throws Throwable { + List> all = allDeclaredMethods(clazz); + + checkNoShadows(clazz, all, Before.class); + checkNoShadows(clazz, all, After.class); + } + + private void checkNoShadows(Class clazz, List> all, Class ann) { + List> methodHierarchy = filterIgnored(annotatedWith(all, ann)); + List> noOverrides = removeOverrides(methodHierarchy); + if (!noOverrides.equals(methodHierarchy)) { + Set shadowed = new HashSet(flatten(methodHierarchy)); + shadowed.removeAll(flatten(noOverrides)); + + StringBuilder b = new StringBuilder(); + for (Method m : shadowed) { + String sig = signature(m); + for (Method other : flatten(methodHierarchy)) { + if (other != m && sig.equals(signature(other))) { + b.append("Method: " + m.toString() + + "#" + sig + " possibly overriden by " + + other.toString() + "#" + signature(other) + "\n"); + } + } + } + + throw new RuntimeException("There are overridden methods annotated with " + + ann.getName() + ". These methods would not be executed by JUnit and need to manually chain themselves which can lead to" + + " maintenance problems. Consider using different method names or make hook methods private.\n" + b.toString().trim()); + } + } + + private List> filterIgnored(List> methods) { + Set ignored = new HashSet(Arrays.asList("setUp", "tearDown")); + List> copy = new ArrayList>(); + for (List m : methods) { + if (!ignored.contains(m.get(0).getName())) { + copy.add(m); + } + } + return copy; + } + + private String signature(Method m) { + return m.getName() + Arrays.toString(m.getParameterTypes()); + } +} + diff --git a/lucene/test-framework/src/java/org/apache/lucene/util/NoStaticHooksShadowing.java b/lucene/test-framework/src/java/org/apache/lucene/util/NoStaticHooksShadowing.java index 28ba26b..5ab702b 100755 --- a/lucene/test-framework/src/java/org/apache/lucene/util/NoStaticHooksShadowing.java +++ b/lucene/test-framework/src/java/org/apache/lucene/util/NoStaticHooksShadowing.java @@ -34,6 +34,10 @@ import org.junit.BeforeClass; import com.carrotsearch.randomizedtesting.ClassValidator; +/** + * Don't allow shadowing of {@link BeforeClass} or {@link AfterClass} hooks + * as it is very likely a user error and will prevent execution of shadowed hooks. + */ public class NoStaticHooksShadowing implements ClassValidator { @Override public void validate(Class clazz) throws Throwable { diff --git a/lucene/test-framework/src/java/org/apache/lucene/util/PrintReproduceInfoListener.java b/lucene/test-framework/src/java/org/apache/lucene/util/PrintReproduceInfoListener.java new file mode 100644 index 0000000..59ee7cb --- /dev/null +++ b/lucene/test-framework/src/java/org/apache/lucene/util/PrintReproduceInfoListener.java @@ -0,0 +1,174 @@ +package org.apache.lucene.util; + +import static org.apache.lucene.util.LuceneTestCase.DEFAULT_LINE_DOCS_FILE; +import static org.apache.lucene.util.LuceneTestCase.JENKINS_LARGE_LINE_DOCS_FILE; +import static org.apache.lucene.util.LuceneTestCase.RANDOM_MULTIPLIER; +import static org.apache.lucene.util.LuceneTestCase.TEST_CODEC; +import static org.apache.lucene.util.LuceneTestCase.TEST_DIRECTORY; +import static org.apache.lucene.util.LuceneTestCase.TEST_LINE_DOCS_FILE; +import static org.apache.lucene.util.LuceneTestCase.TEST_NIGHTLY; +import static org.apache.lucene.util.LuceneTestCase.TEST_POSTINGSFORMAT; +import static org.apache.lucene.util.LuceneTestCase.classEnvRule; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.lucene.codecs.Codec; +import org.junit.runner.Description; +import org.junit.runner.Result; +import org.junit.runner.notification.Failure; +import org.junit.runner.notification.RunListener; + +import com.carrotsearch.randomizedtesting.LifecycleScope; +import com.carrotsearch.randomizedtesting.RandomizedContext; + +/** + * 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. + */ + +/** + * A suite listener printing a "reproduce string". This ensures test result + * events are always captured properly even if exceptions happen at + * initialization or suite/ hooks level. + */ +public final class PrintReproduceInfoListener extends RunListener { + /** + * A list of all test suite classes executed so far in this JVM (ehm, + * under this class's classloader). + */ + private static List testClassesRun = new ArrayList(); + + /** + * The currently executing scope. + */ + private LifecycleScope scope; + + /** Current test failed. */ + private boolean testFailed; + + /** Suite-level code (initialization, rule, hook) failed. */ + private boolean suiteFailed; + + /** A marker to print full env. diagnostics after the suite. */ + private boolean printDiagnosticsAfterClass; + + + @Override + public void testRunStarted(Description description) throws Exception { + suiteFailed = false; + testFailed = false; + scope = LifecycleScope.SUITE; + + Class targetClass = RandomizedContext.current().getTargetClass(); + testClassesRun.add(targetClass.getSimpleName()); + } + + @Override + public void testStarted(Description description) throws Exception { + this.testFailed = false; + this.scope = LifecycleScope.TEST; + } + + @Override + public void testFailure(Failure failure) throws Exception { + if (scope == LifecycleScope.TEST) { + testFailed = true; + } else { + suiteFailed = true; + } + printDiagnosticsAfterClass = true; + } + + @Override + public void testFinished(Description description) throws Exception { + if (testFailed) { + reportAdditionalFailureInfo(description.getMethodName()); + } + scope = LifecycleScope.SUITE; + testFailed = false; + } + + @Override + public void testRunFinished(Result result) throws Exception { + if (printDiagnosticsAfterClass || LuceneTestCase.VERBOSE) { + PrintReproduceInfoListener.printDebuggingInformation(); + } + + if (suiteFailed) { + reportAdditionalFailureInfo(null); + } + } + + /** print some useful debugging information about the environment */ + static void printDebuggingInformation() { + if (classEnvRule != null) { + System.err.println("NOTE: test params are: codec=" + Codec.getDefault() + + ", sim=" + classEnvRule.similarity + + ", locale=" + classEnvRule.locale + + ", timezone=" + (classEnvRule.timeZone == null ? "(null)" : classEnvRule.timeZone.getID())); + } + System.err.println("NOTE: " + System.getProperty("os.name") + " " + + System.getProperty("os.version") + " " + + System.getProperty("os.arch") + "/" + + System.getProperty("java.vendor") + " " + + System.getProperty("java.version") + " " + + (Constants.JRE_IS_64BIT ? "(64-bit)" : "(32-bit)") + "/" + + "cpus=" + Runtime.getRuntime().availableProcessors() + "," + + "threads=" + Thread.activeCount() + "," + + "free=" + Runtime.getRuntime().freeMemory() + "," + + "total=" + Runtime.getRuntime().totalMemory()); + System.err.println("NOTE: All tests run in this JVM: " + Arrays.toString(testClassesRun.toArray())); + } + + // We get here from InterceptTestCaseEvents on the 'failed' event.... + public void reportAdditionalFailureInfo(final String testName) { + if (TEST_LINE_DOCS_FILE.endsWith(JENKINS_LARGE_LINE_DOCS_FILE)) { + System.err.println("NOTE: download the large Jenkins line-docs file by running 'ant get-jenkins-line-docs' in the lucene directory."); + } + + StringBuilder b = new StringBuilder(); + b.append("NOTE: reproduce with: ant test ") + .append("-Dtestcase=").append(RandomizedContext.current().getTargetClass().getSimpleName()); + if (testName != null) { + b.append(" -Dtests.method=").append(testName); + } + b.append(" -Dtests.seed=") + .append(RandomizedContext.current().getRunnerSeedAsString()) + .append(reproduceWithExtraParams()); + System.err.println(b.toString()); + } + + // extra params that were overridden needed to reproduce the command + private static String reproduceWithExtraParams() { + StringBuilder sb = new StringBuilder(); + if (classEnvRule != null) { + if (classEnvRule.locale != null) sb.append(" -Dtests.locale=").append(classEnvRule.locale); + if (classEnvRule.timeZone != null) sb.append(" -Dtests.timezone=").append(classEnvRule.timeZone.getID()); + } + if (!TEST_CODEC.equals("random")) sb.append(" -Dtests.codec=").append(TEST_CODEC); + if (!TEST_POSTINGSFORMAT.equals("random")) sb.append(" -Dtests.postingsformat=").append(TEST_POSTINGSFORMAT); + if (!TEST_DIRECTORY.equals("random")) sb.append(" -Dtests.directory=").append(TEST_DIRECTORY); + if (RANDOM_MULTIPLIER > 1) sb.append(" -Dtests.multiplier=").append(RANDOM_MULTIPLIER); + if (TEST_NIGHTLY) sb.append(" -Dtests.nightly=true"); + if (!TEST_LINE_DOCS_FILE.equals(DEFAULT_LINE_DOCS_FILE)) sb.append(" -Dtests.linedocsfile=" + TEST_LINE_DOCS_FILE); + + // TODO we can't randomize this yet (it drives ant crazy) but this makes tests reproduce + // in case machines have different default charsets... + sb.append(" -Dargs=\"-Dfile.encoding=" + System.getProperty("file.encoding") + "\""); + return sb.toString(); + } +} diff --git a/lucene/test-framework/src/java/org/apache/lucene/util/SetupAndRestoreClassEnvRule.java b/lucene/test-framework/src/java/org/apache/lucene/util/SetupAndRestoreClassEnvRule.java new file mode 100644 index 0000000..5806d85 --- /dev/null +++ b/lucene/test-framework/src/java/org/apache/lucene/util/SetupAndRestoreClassEnvRule.java @@ -0,0 +1,225 @@ +package org.apache.lucene.util; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Locale; +import java.util.Map; +import java.util.Random; +import java.util.Set; +import java.util.TimeZone; + +import org.apache.lucene.codecs.Codec; +import org.apache.lucene.codecs.PostingsFormat; +import org.apache.lucene.codecs.appending.AppendingCodec; +import org.apache.lucene.codecs.lucene3x.PreFlexRWCodec; +import org.apache.lucene.codecs.lucene40.Lucene40Codec; +import org.apache.lucene.codecs.simpletext.SimpleTextCodec; +import org.apache.lucene.index.RandomCodec; +import org.apache.lucene.search.RandomSimilarityProvider; +import org.apache.lucene.search.similarities.DefaultSimilarity; +import org.apache.lucene.search.similarities.Similarity; +import org.apache.lucene.util.LuceneTestCase.SuppressCodecs; + +import com.carrotsearch.randomizedtesting.RandomizedContext; + +import static org.apache.lucene.util.LuceneTestCase.VERBOSE; +import static org.apache.lucene.util.LuceneTestCase.INFOSTREAM; +import static org.apache.lucene.util.LuceneTestCase.TEST_CODEC; + +import static org.apache.lucene.util.LuceneTestCase.*; + + + +/** + * 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. + */ + +/** + * Setup and restore suite-level environment (fine grained junk that + * doesn't fit anywhere else). + */ +final class SetupAndRestoreClassEnvRule extends AbstractBeforeAfterRule { + /** + * Restore these system property values. + */ + private HashMap restoreProperties = new HashMap(); + + private Codec savedCodec; + private Locale savedLocale; + private TimeZone savedTimeZone; + private InfoStream savedInfoStream; + + Locale locale; + TimeZone timeZone; + Similarity similarity; + + /** + * @see SuppressCodecs + */ + HashSet avoidCodecs; + + + @Override + protected void before() throws Exception { + // enable this by default, for IDE consistency with ant tests (as its the default from ant) + // TODO: really should be in solr base classes, but some extend LTC directly. + // we do this in beforeClass, because some tests currently disable it + restoreProperties.put("solr.directoryFactory", System.getProperty("solr.directoryFactory")); + if (System.getProperty("solr.directoryFactory") == null) { + System.setProperty("solr.directoryFactory", "org.apache.solr.core.MockDirectoryFactory"); + } + + // enable the Lucene 3.x PreflexRW codec explicitly, to work around bugs in IBM J9 / Harmony ServiceLoader: + try { + final java.lang.reflect.Field spiLoaderField = Codec.class.getDeclaredField("loader"); + spiLoaderField.setAccessible(true); + final Object spiLoader = spiLoaderField.get(null); + final java.lang.reflect.Field modifiableServicesField = NamedSPILoader.class.getDeclaredField("modifiableServices"); + modifiableServicesField.setAccessible(true); + @SuppressWarnings({"unchecked","rawtypes"}) final Map serviceMap = + (Map) modifiableServicesField.get(spiLoader); + if (!(Codec.forName("Lucene3x") instanceof PreFlexRWCodec)) { + if (Constants.JAVA_VENDOR.startsWith("IBM")) { + // definitely a buggy version + System.err.println("ERROR: Your VM's java.util.ServiceLoader implementation is buggy"+ + " and does not respect classpath order, please report this to the vendor."); + } else { + // could just be a classpath issue + System.err.println("ERROR: fix your classpath to have tests-framework.jar before lucene-core.jar!"+ + " If you have already done this, then your VM's java.util.ServiceLoader implementation is buggy"+ + " and does not respect classpath order, please report this to the vendor."); + } + serviceMap.put("Lucene3x", new PreFlexRWCodec()); + } + } catch (Exception e) { + throw new RuntimeException("Cannot access internals of Codec and NamedSPILoader classes", e); + } + + // if verbose: print some debugging stuff about which codecs are loaded + if (VERBOSE) { + Set codecs = Codec.availableCodecs(); + for (String codec : codecs) { + System.out.println("Loaded codec: '" + codec + "': " + Codec.forName(codec).getClass().getName()); + } + + Set postingsFormats = PostingsFormat.availablePostingsFormats(); + for (String postingsFormat : postingsFormats) { + System.out.println("Loaded postingsFormat: '" + postingsFormat + "': " + PostingsFormat.forName(postingsFormat).getClass().getName()); + } + } + + savedInfoStream = InfoStream.getDefault(); + final Random random = RandomizedContext.current().getRandom(); + final boolean v = random.nextBoolean(); + if (INFOSTREAM) { + InfoStream.setDefault(new PrintStreamInfoStream(System.out)); + } else if (v) { + InfoStream.setDefault(new NullInfoStream()); + } + + Class targetClass = RandomizedContext.current().getTargetClass(); + avoidCodecs = new HashSet(); + if (targetClass.isAnnotationPresent(SuppressCodecs.class)) { + SuppressCodecs a = targetClass.getAnnotation(SuppressCodecs.class); + avoidCodecs.addAll(Arrays.asList(a.value())); + System.err.println("NOTE: Suppressing codecs " + Arrays.toString(a.value()) + + " for " + targetClass.getSimpleName() + "."); + } + + PREFLEX_IMPERSONATION_IS_ACTIVE = false; + savedCodec = Codec.getDefault(); + final Codec codec; + int randomVal = random.nextInt(10); + if ("Lucene3x".equals(TEST_CODEC) || ("random".equals(TEST_CODEC) && randomVal < 2 && !shouldAvoidCodec("Lucene3x"))) { // preflex-only setup + codec = Codec.forName("Lucene3x"); + assert (codec instanceof PreFlexRWCodec) : "fix your classpath to have tests-framework.jar before lucene-core.jar"; + PREFLEX_IMPERSONATION_IS_ACTIVE = true; + } else if ("SimpleText".equals(TEST_CODEC) || ("random".equals(TEST_CODEC) && randomVal == 9 && !shouldAvoidCodec("SimpleText"))) { + codec = new SimpleTextCodec(); + } else if ("Appending".equals(TEST_CODEC) || ("random".equals(TEST_CODEC) && randomVal == 8 && !shouldAvoidCodec("Appending"))) { + codec = new AppendingCodec(); + } else if (!"random".equals(TEST_CODEC)) { + codec = Codec.forName(TEST_CODEC); + } else if ("random".equals(TEST_POSTINGSFORMAT)) { + codec = new RandomCodec(random, avoidCodecs); + } else { + codec = new Lucene40Codec() { + private final PostingsFormat format = PostingsFormat.forName(TEST_POSTINGSFORMAT); + + @Override + public PostingsFormat getPostingsFormatForField(String field) { + return format; + } + + @Override + public String toString() { + return super.toString() + ": " + format.toString(); + } + }; + } + Codec.setDefault(codec); + + // Initialize locale/ timezone. + String testLocale = System.getProperty("tests.locale", "random"); + String testTimeZone = System.getProperty("tests.timezone", "random"); + + // Always pick a random one for consistency (whether tests.locale was specified or not). + savedLocale = Locale.getDefault(); + Locale randomLocale = randomLocale(random); + locale = testLocale.equals("random") ? randomLocale : localeForName(testLocale); + Locale.setDefault(locale); + + // TimeZone.getDefault will set user.timezone to the default timezone of the user's locale. + // So store the original property value and restore it at end. + restoreProperties.put("user.timezone", System.getProperty("user.timezone")); + savedTimeZone = TimeZone.getDefault(); + TimeZone randomTimeZone = randomTimeZone(random()); + timeZone = testTimeZone.equals("random") ? randomTimeZone : TimeZone.getTimeZone(testTimeZone); + TimeZone.setDefault(timeZone); + similarity = random().nextBoolean() ? new DefaultSimilarity() : new RandomSimilarityProvider(random()); + } + + /** + * After suite cleanup (always invoked). + */ + @Override + protected void after() throws Exception { + for (Map.Entry e : restoreProperties.entrySet()) { + if (e.getValue() == null) { + System.clearProperty(e.getKey()); + } else { + System.setProperty(e.getKey(), e.getValue()); + } + } + restoreProperties.clear(); + + Codec.setDefault(savedCodec); + InfoStream.setDefault(savedInfoStream); + Locale.setDefault(savedLocale); + TimeZone.setDefault(savedTimeZone); + + System.clearProperty("solr.solr.home"); + System.clearProperty("solr.data.dir"); + } + + /** + * Should a given codec be avoided for the currently executing suite? + */ + public boolean shouldAvoidCodec(String codec) { + return !avoidCodecs.isEmpty() && avoidCodecs.contains(codec); + } +} diff --git a/lucene/test-framework/src/java/org/apache/lucene/util/SetupAndRestoreInstanceEnvRule.java b/lucene/test-framework/src/java/org/apache/lucene/util/SetupAndRestoreInstanceEnvRule.java new file mode 100644 index 0000000..ef26b9d --- /dev/null +++ b/lucene/test-framework/src/java/org/apache/lucene/util/SetupAndRestoreInstanceEnvRule.java @@ -0,0 +1,43 @@ +package org.apache.lucene.util; + +import org.apache.lucene.search.BooleanQuery; +import org.junit.internal.AssumptionViolatedException; + +/** + * 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. + */ + +/** + * Prepares and restores {@link LuceneTestCase} at instance level + * (fine grained junk that doesn't fit anywhere else). + */ +final class SetupAndRestoreInstanceEnvRule extends AbstractBeforeAfterRule { + private int savedBoolMaxClauseCount; + + protected void before() { + savedBoolMaxClauseCount = BooleanQuery.getMaxClauseCount(); + + final String defFormat = _TestUtil.getPostingsFormat("thisCodeMakesAbsolutelyNoSenseCanWeDeleteIt"); + if (LuceneTestCase.shouldAvoidCodec(defFormat)) { + throw new AssumptionViolatedException( + "Method not allowed to use codec: " + defFormat + "."); + } + } + + protected void after() { + BooleanQuery.setMaxClauseCount(savedBoolMaxClauseCount); + } +} diff --git a/lucene/test-framework/src/java/org/apache/lucene/util/SubclassSetupTeardownRule.java b/lucene/test-framework/src/java/org/apache/lucene/util/SubclassSetupTeardownRule.java new file mode 100644 index 0000000..dcd1ec2 --- /dev/null +++ b/lucene/test-framework/src/java/org/apache/lucene/util/SubclassSetupTeardownRule.java @@ -0,0 +1,63 @@ +package org.apache.lucene.util; + +import org.junit.Assert; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +/** + * 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. + */ + +/** + * Make sure {@link LuceneTestCase#setUp()} and {@link LuceneTestCase#tearDown()} were invoked even if they + * have been overriden. We assume nobody will call these out of non-overriden + * methods (they have to be public by contract, unfortunately). The top-level + * methods just set a flag that is checked upon successful execution of each test + * case. + */ +class SubclassSetupTeardownRule implements TestRule { + /** + * @see SubclassSetupTeardownRule + */ + public boolean setupCalled; + + /** + * @see SubclassSetupTeardownRule + */ + public boolean teardownCalled; + + @Override + public Statement apply(final Statement base, Description description) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + setupCalled = false; + teardownCalled = false; + base.evaluate(); + + // I assume we don't want to check teardown chaining if something happens in the + // test because this would obscure the original exception? + if (!setupCalled) { + Assert.fail("One of the overrides of setUp does not propagate the call."); + } + if (!teardownCalled) { + Assert.fail("One of the overrides of tearDown does not propagate the call."); + } + } + }; + } +} \ No newline at end of file diff --git a/lucene/test-framework/src/java/org/apache/lucene/util/SystemPropertiesInvariantRule.java b/lucene/test-framework/src/java/org/apache/lucene/util/SystemPropertiesInvariantRule.java deleted file mode 100644 index 5d8079e..0000000 --- a/lucene/test-framework/src/java/org/apache/lucene/util/SystemPropertiesInvariantRule.java +++ /dev/null @@ -1,146 +0,0 @@ -package org.apache.lucene.util; - -/** - * 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. - */ - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashSet; -import java.util.Iterator; -import java.util.Set; -import java.util.TreeMap; -import java.util.TreeSet; - -import org.junit.rules.TestRule; -import org.junit.runner.Description; -import org.junit.runners.model.MultipleFailureException; -import org.junit.runners.model.Statement; - -public class SystemPropertiesInvariantRule implements TestRule { - /** - * Ignored property keys. - */ - private final HashSet ignoredProperties; - - /** - * Cares about all properties. - */ - public SystemPropertiesInvariantRule() { - this(Collections.emptySet()); - } - - /** - * Don't care about the given set of properties. - */ - public SystemPropertiesInvariantRule(String... ignoredProperties) { - this.ignoredProperties = new HashSet(Arrays.asList(ignoredProperties)); - } - - /** - * Don't care about the given set of properties. - */ - public SystemPropertiesInvariantRule(Set ignoredProperties) { - this.ignoredProperties = new HashSet(ignoredProperties); - } - - @Override - public Statement apply(final Statement s, Description d) { - return new Statement() { - @Override - public void evaluate() throws Throwable { - TreeMap before = SystemPropertiesRestoreRule.cloneAsMap(System.getProperties()); - ArrayList errors = new ArrayList(); - try { - s.evaluate(); - } catch (Throwable t) { - errors.add(t); - } finally { - final TreeMap after = SystemPropertiesRestoreRule.cloneAsMap(System.getProperties()); - - // Remove ignored if they exist. - before.keySet().removeAll(ignoredProperties); - after.keySet().removeAll(ignoredProperties); - - if (!after.equals(before)) { - errors.add( - new AssertionError("System properties invariant violated.\n" + - collectErrorMessage(before, after))); - } - - // Restore original properties. - SystemPropertiesRestoreRule.restore(before, after, ignoredProperties); - } - - MultipleFailureException.assertEmpty(errors); - } - - private StringBuilder collectErrorMessage( - TreeMap before, TreeMap after) { - TreeSet newKeys = new TreeSet(after.keySet()); - newKeys.removeAll(before.keySet()); - - TreeSet missingKeys = new TreeSet(before.keySet()); - missingKeys.removeAll(after.keySet()); - - TreeSet differentKeyValues = new TreeSet(before.keySet()); - differentKeyValues.retainAll(after.keySet()); - for (Iterator i = differentKeyValues.iterator(); i.hasNext();) { - String key = i.next(); - String valueBefore = before.get(key); - String valueAfter = after.get(key); - if ((valueBefore == null && valueAfter == null) || - (valueBefore.equals(valueAfter))) { - i.remove(); - } - } - - final StringBuilder b = new StringBuilder(); - if (!missingKeys.isEmpty()) { - b.append("Missing keys:\n"); - for (String key : missingKeys) { - b.append(" ").append(key) - .append("=") - .append(before.get(key)) - .append("\n"); - } - } - if (!newKeys.isEmpty()) { - b.append("New keys:\n"); - for (String key : newKeys) { - b.append(" ").append(key) - .append("=") - .append(after.get(key)) - .append("\n"); - } - } - if (!differentKeyValues.isEmpty()) { - b.append("Different values:\n"); - for (String key : differentKeyValues) { - b.append(" [old]").append(key) - .append("=") - .append(before.get(key)).append("\n"); - b.append(" [new]").append(key) - .append("=") - .append(after.get(key)).append("\n"); - } - } - return b; - } - }; - } -} \ No newline at end of file diff --git a/lucene/test-framework/src/java/org/apache/lucene/util/SystemPropertiesRestoreRule.java b/lucene/test-framework/src/java/org/apache/lucene/util/SystemPropertiesRestoreRule.java deleted file mode 100644 index cf2e4ca..0000000 --- a/lucene/test-framework/src/java/org/apache/lucene/util/SystemPropertiesRestoreRule.java +++ /dev/null @@ -1,120 +0,0 @@ -package org.apache.lucene.util; - -/** - * 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. - */ - -import java.util.*; - -import org.junit.rules.TestRule; -import org.junit.runner.Description; -import org.junit.runners.model.Statement; - -/** - * Restore system properties from before the nested {@link Statement}. - */ -public class SystemPropertiesRestoreRule implements TestRule { - /** - * Ignored property keys. - */ - private final HashSet ignoredProperties; - - /** - * Restores all properties. - */ - public SystemPropertiesRestoreRule() { - this(Collections.emptySet()); - } - - /** - * @param ignoredProperties Properties that will be ignored (and will not be restored). - */ - public SystemPropertiesRestoreRule(Set ignoredProperties) { - this.ignoredProperties = new HashSet(ignoredProperties); - } - - /** - * @param ignoredProperties Properties that will be ignored (and will not be restored). - */ - public SystemPropertiesRestoreRule(String... ignoredProperties) { - this.ignoredProperties = new HashSet(Arrays.asList(ignoredProperties)); - } - - @Override - public Statement apply(final Statement s, Description d) { - return new Statement() { - @Override - public void evaluate() throws Throwable { - TreeMap before = cloneAsMap(System.getProperties()); - try { - s.evaluate(); - } finally { - TreeMap after = cloneAsMap(System.getProperties()); - if (!after.equals(before)) { - // Restore original properties. - restore(before, after, ignoredProperties); - } - } - } - }; - } - - static TreeMap cloneAsMap(Properties properties) { - TreeMap result = new TreeMap(); - for (Enumeration e = properties.propertyNames(); e.hasMoreElements();) { - final Object key = e.nextElement(); - // Skip non-string properties or values, they're abuse of Properties object. - if (key instanceof String) { - String value = properties.getProperty((String) key); - if (value == null) { - Object ovalue = properties.get(key); - if (ovalue != null) { - // ovalue has to be a non-string object. Skip the property because - // System.clearProperty won't be able to cast back the existing value. - continue; - } - } - result.put((String) key, value); - } - } - return result; - } - - static void restore( - TreeMap before, - TreeMap after, - Set ignoredKeys) { - - // Clear anything that is present after but wasn't before. - after.keySet().removeAll(before.keySet()); - for (String key : after.keySet()) { - if (!ignoredKeys.contains(key)) - System.clearProperty(key); - } - - // Restore original property values unless they are ignored (then leave). - for (Map.Entry e : before.entrySet()) { - String key = e.getValue(); - if (!ignoredKeys.contains(key)) { - if (key == null) { - System.clearProperty(e.getKey()); // Can this happen? - } else { - System.setProperty(e.getKey(), key); - } - } - } - } -} \ No newline at end of file diff --git a/lucene/test-framework/src/java/org/apache/lucene/util/ThreadNameAndTestNameRule.java b/lucene/test-framework/src/java/org/apache/lucene/util/ThreadNameAndTestNameRule.java new file mode 100644 index 0000000..02093dc --- /dev/null +++ b/lucene/test-framework/src/java/org/apache/lucene/util/ThreadNameAndTestNameRule.java @@ -0,0 +1,57 @@ +package org.apache.lucene.util; + +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +/** + * 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. + */ + +/** + * Saves the executing thread and method name of the test case. Replaces + * the current thread's name with the seed and test name. + */ +final class ThreadNameAndTestNameRule implements TestRule { + /** + * The thread executing the current test case. + * @see LuceneTestCase#isTestThread() + */ + public volatile Thread testCaseThread; + + /** + * Test method name. + */ + public volatile String testMethodName = ""; + + @Override + public Statement apply(final Statement base, final Description description) { + return new Statement() { + public void evaluate() throws Throwable { + try { + Thread current = Thread.currentThread(); + testCaseThread = current; + testMethodName = description.getMethodName(); + + base.evaluate(); + } finally { + testCaseThread = null; + testMethodName = null; + } + } + }; + } +} \ No newline at end of file diff --git a/lucene/test-framework/src/java/org/apache/lucene/util/UncaughtExceptionsRule.java b/lucene/test-framework/src/java/org/apache/lucene/util/UncaughtExceptionsRule.java index c9ba803..913f153 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/util/UncaughtExceptionsRule.java +++ b/lucene/test-framework/src/java/org/apache/lucene/util/UncaughtExceptionsRule.java @@ -23,7 +23,6 @@ import java.lang.Thread.UncaughtExceptionHandler; import java.util.ArrayList; import java.util.List; -import org.junit.internal.AssumptionViolatedException; import org.junit.rules.TestRule; import org.junit.runner.Description; import org.junit.runners.model.MultipleFailureException; @@ -39,12 +38,6 @@ public class UncaughtExceptionsRule implements TestRule { // thread accessing it, always. private UncaughtExceptionHandler savedUncaughtExceptionHandler; - private final LuceneTestCase ltc; - - public UncaughtExceptionsRule(LuceneTestCase ltc) { - this.ltc = ltc; - } - public static class UncaughtExceptionEntry { public final Thread thread; public final Throwable exception; @@ -86,29 +79,11 @@ public class UncaughtExceptionsRule implements TestRule { uncaughtExceptions.clear(); } - if (hasNonAssumptionErrors(errors)) { - if (ltc == null) { - // class level failure (e.g. afterclass) - LuceneTestCase.reportPartialFailureInfo(); - } else { - // failure in a method - ltc.reportAdditionalFailureInfo(); - } - } MultipleFailureException.assertEmpty(errors); } }; } - private boolean hasNonAssumptionErrors(ArrayList errors) { - for (Throwable t : errors) { - if (!(t instanceof AssumptionViolatedException)) { - return true; - } - } - return false; - } - /** * Just a check if anything's been caught. */ diff --git a/lucene/test-framework/src/java/org/apache/lucene/util/_TestUtil.java b/lucene/test-framework/src/java/org/apache/lucene/util/_TestUtil.java index 28bfc7b..5e39d84 100644 --- a/lucene/test-framework/src/java/org/apache/lucene/util/_TestUtil.java +++ b/lucene/test-framework/src/java/org/apache/lucene/util/_TestUtil.java @@ -28,6 +28,8 @@ import java.io.PrintStream; import java.lang.reflect.Method; import java.nio.CharBuffer; import java.util.*; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.TimeUnit; import java.util.zip.ZipEntry; import java.util.zip.ZipFile; @@ -80,7 +82,7 @@ public class _TestUtil { try { File f = createTempFile(desc, "tmp", LuceneTestCase.TEMP_DIR); f.delete(); - LuceneTestCase.registerTempDir(f); + LuceneTestCase.closeAfterSuite(new FileCloseable(f)); return f; } catch (IOException e) { throw new RuntimeException(e); @@ -120,10 +122,10 @@ public class _TestUtil { Enumeration entries = zipFile.entries(); rmDir(destDir); - + destDir.mkdir(); - LuceneTestCase.registerTempDir(destDir); - + LuceneTestCase.closeAfterSuite(new FileCloseable(destDir)); + while (entries.hasMoreElements()) { ZipEntry entry = entries.nextElement(); @@ -881,7 +883,21 @@ public class _TestUtil { default: return ref.utf8ToString(); } - } - + + /** + * Shutdown {@link ExecutorService} and wait for its. + */ + public static void shutdownExecutorService(ExecutorService ex) { + if (ex != null) { + try { + ex.shutdown(); + ex.awaitTermination(1, TimeUnit.SECONDS); + } catch (InterruptedException e) { + // Just report it on the syserr. + System.err.println("Could not properly shutdown executor service."); + e.printStackTrace(System.err); + } + } + } } diff --git a/solr/core/src/test/org/apache/solr/TestDistributedSearch.java b/solr/core/src/test/org/apache/solr/TestDistributedSearch.java index 1e02049..a5c14bc 100755 --- a/solr/core/src/test/org/apache/solr/TestDistributedSearch.java +++ b/solr/core/src/test/org/apache/solr/TestDistributedSearch.java @@ -364,7 +364,7 @@ public class TestDistributedSearch extends BaseDistributedSearchTestCase { // Thread.sleep(10000000000L); - purgeFieldCache(FieldCache.DEFAULT); // avoid FC insanity + FieldCache.DEFAULT.purgeAllCaches(); // avoid FC insanity } protected void queryPartialResults(final List upShards, diff --git a/solr/core/src/test/org/apache/solr/TestGroupingSearch.java b/solr/core/src/test/org/apache/solr/TestGroupingSearch.java index c0ce1e2..402aa0c 100644 --- a/solr/core/src/test/org/apache/solr/TestGroupingSearch.java +++ b/solr/core/src/test/org/apache/solr/TestGroupingSearch.java @@ -440,7 +440,7 @@ public class TestGroupingSearch extends SolrTestCaseJ4 { ,"/grouped/"+f+"/matches==10" ,"/facet_counts/facet_fields/"+f+"==['1',3, '2',3, '3',2, '4',1, '5',1]" ); - purgeFieldCache(FieldCache.DEFAULT); // avoid FC insanity + FieldCache.DEFAULT.purgeAllCaches(); // avoid FC insanity // test that grouping works with highlighting assertJQ(req("fq",filt, "q","{!func}"+f2, "group","true", "group.field",f, "fl","id" diff --git a/solr/core/src/test/org/apache/solr/TestRandomFaceting.java b/solr/core/src/test/org/apache/solr/TestRandomFaceting.java index b4b1fa2..fc7e271 100644 --- a/solr/core/src/test/org/apache/solr/TestRandomFaceting.java +++ b/solr/core/src/test/org/apache/solr/TestRandomFaceting.java @@ -130,7 +130,7 @@ public class TestRandomFaceting extends SolrTestCaseJ4 { } } } finally { - purgeFieldCache(FieldCache.DEFAULT); // avoid FC insanity + FieldCache.DEFAULT.purgeAllCaches(); // avoid FC insanity } } diff --git a/solr/core/src/test/org/apache/solr/cloud/AbstractDistributedZkTestCase.java b/solr/core/src/test/org/apache/solr/cloud/AbstractDistributedZkTestCase.java index b4f48cc..8191d72 100644 --- a/solr/core/src/test/org/apache/solr/cloud/AbstractDistributedZkTestCase.java +++ b/solr/core/src/test/org/apache/solr/cloud/AbstractDistributedZkTestCase.java @@ -42,7 +42,6 @@ public abstract class AbstractDistributedZkTestCase extends BaseDistributedSearc @Override public void setUp() throws Exception { super.setUp(); - log.info("####SETUP_START " + getName()); createTempDir(); String zkDir = testDir.getAbsolutePath() + File.separator diff --git a/solr/core/src/test/org/apache/solr/cloud/CloudStateUpdateTest.java b/solr/core/src/test/org/apache/solr/cloud/CloudStateUpdateTest.java index 7de69b8..57f1b51 100644 --- a/solr/core/src/test/org/apache/solr/cloud/CloudStateUpdateTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/CloudStateUpdateTest.java @@ -91,7 +91,7 @@ public class CloudStateUpdateTest extends SolrTestCaseJ4 { AbstractZkTestCase.buildZooKeeper(zkServer.getZkHost(), zkServer .getZkAddress(), "solrconfig.xml", "schema.xml"); - log.info("####SETUP_START " + getName()); + log.info("####SETUP_START " + getTestName()); dataDir1 = new File(dataDir + File.separator + "data1"); dataDir1.mkdirs(); @@ -129,7 +129,7 @@ public class CloudStateUpdateTest extends SolrTestCaseJ4 { System.clearProperty("hostPort"); System.clearProperty("solr.solr.home"); - log.info("####SETUP_END " + getName()); + log.info("####SETUP_END " + getTestName()); } diff --git a/solr/core/src/test/org/apache/solr/cloud/LeaderElectionIntegrationTest.java b/solr/core/src/test/org/apache/solr/cloud/LeaderElectionIntegrationTest.java index f98a89f..4d54dc3 100644 --- a/solr/core/src/test/org/apache/solr/cloud/LeaderElectionIntegrationTest.java +++ b/solr/core/src/test/org/apache/solr/cloud/LeaderElectionIntegrationTest.java @@ -88,7 +88,7 @@ public class LeaderElectionIntegrationTest extends SolrTestCaseJ4 { AbstractZkTestCase.buildZooKeeper(zkServer.getZkHost(), zkServer.getZkAddress(), "solrconfig.xml", "schema.xml"); - log.info("####SETUP_START " + getName()); + log.info("####SETUP_START " + getTestName()); // set some system properties for use by tests System.setProperty("solr.test.sys.prop1", "propone"); @@ -129,7 +129,7 @@ public class LeaderElectionIntegrationTest extends SolrTestCaseJ4 { if (!initSuccessful) { fail("Init was not successful!"); } - log.info("####SETUP_END " + getName()); + log.info("####SETUP_END " + getTestName()); } private void setupContainer(int port, String shard) throws IOException, diff --git a/solr/core/src/test/org/apache/solr/schema/TestBinaryField.java b/solr/core/src/test/org/apache/solr/schema/TestBinaryField.java index ec1f630..f4112bf 100644 --- a/solr/core/src/test/org/apache/solr/schema/TestBinaryField.java +++ b/solr/core/src/test/org/apache/solr/schema/TestBinaryField.java @@ -23,21 +23,19 @@ import java.util.List; import org.apache.commons.io.IOUtils; import org.apache.lucene.util.LuceneTestCase; -import org.apache.lucene.util.SystemPropertiesRestoreRule; import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.beans.Field; import org.apache.solr.client.solrj.embedded.JettySolrRunner; import org.apache.solr.client.solrj.impl.HttpSolrServer; import org.apache.solr.client.solrj.response.QueryResponse; -import org.apache.solr.common.SolrDocument; -import org.apache.solr.common.SolrDocumentList; -import org.apache.solr.common.SolrInputDocument; +import org.apache.solr.common.*; import org.apache.solr.core.SolrResourceLoader; -import org.apache.commons.io.IOUtils; import org.junit.Rule; import org.junit.rules.RuleChain; import org.junit.rules.TestRule; +import com.carrotsearch.randomizedtesting.rules.SystemPropertiesRestoreRule; + public class TestBinaryField extends LuceneTestCase { HttpSolrServer server; JettySolrRunner jetty; diff --git a/solr/core/src/test/org/apache/solr/search/function/TestFunctionQuery.java b/solr/core/src/test/org/apache/solr/search/function/TestFunctionQuery.java index 4b0b8d4..9ef9067 100755 --- a/solr/core/src/test/org/apache/solr/search/function/TestFunctionQuery.java +++ b/solr/core/src/test/org/apache/solr/search/function/TestFunctionQuery.java @@ -198,7 +198,7 @@ public class TestFunctionQuery extends SolrTestCaseJ4 { Arrays.asList("v1","\0:[* TO *]"), 88,12 ); - purgeFieldCache(FieldCache.DEFAULT); // avoid FC insanity + FieldCache.DEFAULT.purgeAllCaches(); // avoid FC insanity } @Test @@ -281,7 +281,7 @@ public class TestFunctionQuery extends SolrTestCaseJ4 { // System.out.println("Done test "+i); } - purgeFieldCache(FieldCache.DEFAULT); // avoid FC insanity + FieldCache.DEFAULT.purgeAllCaches(); // avoid FC insanity } @Test @@ -421,7 +421,7 @@ public class TestFunctionQuery extends SolrTestCaseJ4 { ); - purgeFieldCache(FieldCache.DEFAULT); // avoid FC insanity + FieldCache.DEFAULT.purgeAllCaches(); // avoid FC insanity } /** @@ -642,7 +642,7 @@ public class TestFunctionQuery extends SolrTestCaseJ4 { singleTest(fieldAsFunc, "sqrt(\0)"); assertTrue(orig != FileFloatSource.onlyForTesting); - purgeFieldCache(FieldCache.DEFAULT); // avoid FC insanity + FieldCache.DEFAULT.purgeAllCaches(); // avoid FC insanity } /** @@ -669,7 +669,7 @@ public class TestFunctionQuery extends SolrTestCaseJ4 { 100,10, 25,5, 0,0, 1,1); singleTest(fieldAsFunc, "log(\0)", 1,0); - purgeFieldCache(FieldCache.DEFAULT); // avoid FC insanity + FieldCache.DEFAULT.purgeAllCaches(); // avoid FC insanity } @Test diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/TestLBHttpSolrServer.java b/solr/solrj/src/test/org/apache/solr/client/solrj/TestLBHttpSolrServer.java index bb8ba7f..b1e9e2a 100644 --- a/solr/solrj/src/test/org/apache/solr/client/solrj/TestLBHttpSolrServer.java +++ b/solr/solrj/src/test/org/apache/solr/client/solrj/TestLBHttpSolrServer.java @@ -43,7 +43,6 @@ import java.util.Set; /** * Test for LBHttpSolrServer * - * * @since solr 1.4 */ public class TestLBHttpSolrServer extends LuceneTestCase { @@ -52,11 +51,13 @@ public class TestLBHttpSolrServer extends LuceneTestCase { // TODO: fix this test to not require FSDirectory static String savedFactory; + @BeforeClass public static void beforeClass() throws Exception { savedFactory = System.getProperty("solr.DirectoryFactory"); System.setProperty("solr.directoryFactory", "org.apache.solr.core.MockFSDirectoryFactory"); } + @AfterClass public static void afterClass() throws Exception { if (savedFactory == null) { @@ -100,6 +101,7 @@ public class TestLBHttpSolrServer extends LuceneTestCase { for (SolrInstance aSolr : solr) { aSolr.tearDown(); } + httpClient.getConnectionManager().shutdown(); super.tearDown(); } diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/embedded/JettyWebappTest.java b/solr/solrj/src/test/org/apache/solr/client/solrj/embedded/JettyWebappTest.java index 6fa8166..c20c3a1 100644 --- a/solr/solrj/src/test/org/apache/solr/client/solrj/embedded/JettyWebappTest.java +++ b/solr/solrj/src/test/org/apache/solr/client/solrj/embedded/JettyWebappTest.java @@ -23,7 +23,6 @@ import java.util.Random; import org.apache.commons.io.IOUtils; import org.apache.lucene.util.LuceneTestCase; -import org.apache.lucene.util.SystemPropertiesRestoreRule; import org.apache.solr.util.ExternalPaths; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Server; @@ -34,6 +33,8 @@ import org.junit.Rule; import org.junit.rules.RuleChain; import org.junit.rules.TestRule; +import com.carrotsearch.randomizedtesting.rules.SystemPropertiesRestoreRule; + /** * * @since solr 1.3 diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/embedded/TestEmbeddedSolrServer.java b/solr/solrj/src/test/org/apache/solr/client/solrj/embedded/TestEmbeddedSolrServer.java index 489bf34..a691384 100644 --- a/solr/solrj/src/test/org/apache/solr/client/solrj/embedded/TestEmbeddedSolrServer.java +++ b/solr/solrj/src/test/org/apache/solr/client/solrj/embedded/TestEmbeddedSolrServer.java @@ -17,8 +17,12 @@ package org.apache.solr.client.solrj.embedded; * limitations under the License. */ +import java.io.File; +import java.util.ArrayList; +import java.util.List; + import junit.framework.Assert; -import org.apache.lucene.util.SystemPropertiesRestoreRule; + import org.apache.solr.core.SolrCore; import org.junit.Rule; import org.junit.rules.RuleChain; @@ -26,9 +30,7 @@ import org.junit.rules.TestRule; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.File; -import java.util.ArrayList; -import java.util.List; +import com.carrotsearch.randomizedtesting.rules.SystemPropertiesRestoreRule; public class TestEmbeddedSolrServer extends AbstractEmbeddedSolrServerTestCase { diff --git a/solr/solrj/src/test/org/apache/solr/client/solrj/embedded/TestSolrProperties.java b/solr/solrj/src/test/org/apache/solr/client/solrj/embedded/TestSolrProperties.java index 7be9118..4a2271d 100644 --- a/solr/solrj/src/test/org/apache/solr/client/solrj/embedded/TestSolrProperties.java +++ b/solr/solrj/src/test/org/apache/solr/client/solrj/embedded/TestSolrProperties.java @@ -17,19 +17,23 @@ package org.apache.solr.client.solrj.embedded; +import java.io.File; +import java.io.FileInputStream; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.xpath.*; + import org.apache.commons.io.IOUtils; -import org.apache.lucene.util.SystemPropertiesRestoreRule; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.client.solrj.SolrQuery; import org.apache.solr.client.solrj.SolrServer; import org.apache.solr.client.solrj.request.AbstractUpdateRequest.ACTION; -import org.apache.solr.client.solrj.request.CoreAdminRequest; -import org.apache.solr.client.solrj.request.QueryRequest; -import org.apache.solr.client.solrj.request.UpdateRequest; +import org.apache.solr.client.solrj.request.*; import org.apache.solr.client.solrj.response.CoreAdminResponse; import org.apache.solr.common.SolrInputDocument; -import org.apache.solr.util.FileUtils; import org.apache.solr.core.CoreContainer; +import org.apache.solr.util.FileUtils; import org.junit.Rule; import org.junit.Test; import org.junit.rules.RuleChain; @@ -39,14 +43,7 @@ import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Node; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.xpath.XPath; -import javax.xml.xpath.XPathConstants; -import javax.xml.xpath.XPathExpressionException; -import javax.xml.xpath.XPathFactory; -import java.io.File; -import java.io.FileInputStream; +import com.carrotsearch.randomizedtesting.rules.SystemPropertiesRestoreRule; /** * diff --git a/solr/test-framework/src/java/org/apache/solr/BaseDistributedSearchTestCase.java b/solr/test-framework/src/java/org/apache/solr/BaseDistributedSearchTestCase.java index 3f43280..0915db9 100644 --- a/solr/test-framework/src/java/org/apache/solr/BaseDistributedSearchTestCase.java +++ b/solr/test-framework/src/java/org/apache/solr/BaseDistributedSearchTestCase.java @@ -184,7 +184,7 @@ public abstract class BaseDistributedSearchTestCase extends SolrTestCaseJ4 { if (!AbstractSolrTestCase.recurseDelete(testDir)) { System.err.println("!!!! WARNING: best effort to remove " + testDir.getAbsolutePath() + " FAILED !!!!!"); } - purgeFieldCache(FieldCache.DEFAULT); // avoid FC insanity + FieldCache.DEFAULT.purgeAllCaches(); // avoid FC insanity super.tearDown(); } diff --git a/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java b/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java index 8001b00..baaaae4 100755 --- a/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java +++ b/solr/test-framework/src/java/org/apache/solr/SolrTestCaseJ4.java @@ -17,62 +17,41 @@ package org.apache.solr; -import java.io.File; -import java.io.IOException; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; -import java.util.logging.ConsoleHandler; -import java.util.logging.Handler; -import java.util.logging.Level; +import java.io.*; +import java.util.*; +import java.util.logging.*; import javax.xml.xpath.XPathExpressionException; import org.apache.lucene.util.LuceneTestCase; -import org.apache.lucene.util.SystemPropertiesRestoreRule; -import org.apache.noggit.CharArr; -import org.apache.noggit.JSONUtil; -import org.apache.noggit.ObjectBuilder; -import org.apache.solr.common.SolrException; -import org.apache.solr.common.SolrInputDocument; -import org.apache.solr.common.SolrInputField; +import org.apache.noggit.*; +import org.apache.solr.common.*; import org.apache.solr.common.cloud.SolrZkClient; -import org.apache.solr.common.params.CommonParams; -import org.apache.solr.common.params.ModifiableSolrParams; -import org.apache.solr.common.params.SolrParams; +import org.apache.solr.common.params.*; import org.apache.solr.common.util.XML; import org.apache.solr.core.SolrConfig; import org.apache.solr.core.SolrCore; import org.apache.solr.handler.JsonUpdateRequestHandler; -import org.apache.solr.request.LocalSolrQueryRequest; -import org.apache.solr.request.SolrQueryRequest; -import org.apache.solr.request.SolrRequestHandler; +import org.apache.solr.request.*; import org.apache.solr.schema.IndexSchema; import org.apache.solr.schema.SchemaField; import org.apache.solr.search.SolrIndexSearcher; import org.apache.solr.servlet.DirectSolrConnection; +import org.apache.solr.util.AbstractSolrTestCase; import org.apache.solr.util.TestHarness; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Rule; +import org.junit.*; import org.junit.rules.RuleChain; import org.junit.rules.TestRule; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xml.sax.SAXException; -import com.carrotsearch.randomizedtesting.RandomizedContext; +import com.carrotsearch.randomizedtesting.annotations.ThreadLeaks; +import com.carrotsearch.randomizedtesting.rules.SystemPropertiesRestoreRule; /** * A junit4 Solr test harness that extends LuceneTestCaseJ4. - * Unlike AbstractSolrTestCase, a new core is not created for each test method. - * + * Unlike {@link AbstractSolrTestCase}, a new core is not created for each test method. */ public abstract class SolrTestCaseJ4 extends LuceneTestCase { public static int DEFAULT_CONNECTION_TIMEOUT = 500; // default socket connection timeout in ms @@ -86,8 +65,9 @@ public abstract class SolrTestCaseJ4 extends LuceneTestCase { public TestRule solrTestRules = RuleChain.outerRule(new SystemPropertiesRestoreRule()); - @BeforeClass - public static void beforeClassSolrTestCase() throws Exception { + @BeforeClass + @SuppressWarnings("unused") + private static void beforeClass() throws Exception { setupLogging(); startTrackingSearchers(); startTrackingZkClients(); @@ -95,7 +75,8 @@ public abstract class SolrTestCaseJ4 extends LuceneTestCase { } @AfterClass - public static void afterClassSolrTestCase() throws Exception { + @SuppressWarnings("unused") + private static void afterClass() throws Exception { deleteCore(); resetExceptionIgnores(); endTrackingSearchers(); @@ -105,12 +86,12 @@ public abstract class SolrTestCaseJ4 extends LuceneTestCase { @Override public void setUp() throws Exception { super.setUp(); - log.info("###Starting " + getName()); // returns ??? + log.info("###Starting " + getTestName()); // returns ??? } @Override public void tearDown() throws Exception { - log.info("###Ending " + getName()); + log.info("###Ending " + getTestName()); super.tearDown(); } @@ -201,15 +182,7 @@ public abstract class SolrTestCaseJ4 extends LuceneTestCase { if (endNumOpens-numOpens != endNumCloses-numCloses) { String msg = "ERROR: SolrIndexSearcher opens=" + (endNumOpens-numOpens) + " closes=" + (endNumCloses-numCloses); log.error(msg); - testsFailed = true; - - // For debugging -// Set> coreEntries = SolrCore.openHandles.entrySet(); -// for (Entry entry : coreEntries) { -// entry.getValue().printStackTrace(); -// } - - fail(msg); + fail(msg); } } @@ -220,11 +193,9 @@ public abstract class SolrTestCaseJ4 extends LuceneTestCase { SolrZkClient.numOpens.getAndSet(0); SolrZkClient.numCloses.getAndSet(0); - if (endNumOpens-zkClientNumOpens != endNumCloses-zkClientNumCloses) { String msg = "ERROR: SolrZkClient opens=" + (endNumOpens-zkClientNumOpens) + " closes=" + (endNumCloses-zkClientNumCloses); log.error(msg); - testsFailed = true; fail(msg); } } @@ -259,6 +230,7 @@ public abstract class SolrTestCaseJ4 extends LuceneTestCase { protected static String schemaString; protected static SolrConfig solrConfig; + /** * Harness initialized by initTestHarness. * @@ -267,6 +239,7 @@ public abstract class SolrTestCaseJ4 extends LuceneTestCase { *

*/ protected static TestHarness h; + /** * LocalRequestFactory initialized by initTestHarness using sensible * defaults. @@ -282,17 +255,17 @@ public abstract class SolrTestCaseJ4 extends LuceneTestCase { * Subclasses must define this method to return the name of the * schema.xml they wish to use. */ - public static String getSchemaFile() { + public static String getSchemaFile() { return schemaString; - }; + } /** * Subclasses must define this method to return the name of the * solrconfig.xml they wish to use. */ - public static String getSolrConfigFile() { + public static String getSolrConfigFile() { return configString; - }; + } /** * The directory used to story the index managed by the TestHarness h @@ -358,7 +331,7 @@ public abstract class SolrTestCaseJ4 extends LuceneTestCase { * to log the fact that their setUp process has ended. */ public void postSetUp() { - log.info("####POSTSETUP " + getName()); + log.info("####POSTSETUP " + getTestName()); } @@ -368,7 +341,7 @@ public abstract class SolrTestCaseJ4 extends LuceneTestCase { * tearDown method. */ public void preTearDown() { - log.info("####PRETEARDOWN " + getName()); + log.info("####PRETEARDOWN " + getTestName()); } /** diff --git a/solr/test-framework/src/java/org/apache/solr/util/AbstractSolrTestCase.java b/solr/test-framework/src/java/org/apache/solr/util/AbstractSolrTestCase.java index 2dd8a5e..5d8c5bf 100644 --- a/solr/test-framework/src/java/org/apache/solr/util/AbstractSolrTestCase.java +++ b/solr/test-framework/src/java/org/apache/solr/util/AbstractSolrTestCase.java @@ -19,35 +19,28 @@ package org.apache.solr.util; -import java.io.File; -import java.io.IOException; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; +import java.io.*; +import java.util.*; import javax.xml.xpath.XPathExpressionException; import org.apache.lucene.util.LuceneTestCase; -import org.apache.lucene.util.SystemPropertiesRestoreRule; import org.apache.solr.SolrTestCaseJ4; -import org.apache.solr.common.SolrException; -import org.apache.solr.common.SolrInputDocument; -import org.apache.solr.common.SolrInputField; +import org.apache.solr.common.*; import org.apache.solr.common.params.CommonParams; import org.apache.solr.common.util.XML; import org.apache.solr.core.SolrConfig; import org.apache.solr.request.SolrQueryRequest; -import org.junit.AfterClass; -import org.junit.BeforeClass; -import org.junit.ClassRule; -import org.junit.Rule; +import org.junit.*; import org.junit.rules.RuleChain; import org.junit.rules.TestRule; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xml.sax.SAXException; +import com.carrotsearch.randomizedtesting.annotations.ThreadLeaks; +import com.carrotsearch.randomizedtesting.rules.SystemPropertiesRestoreRule; + /** * An Abstract base class that makes writing Solr JUnit tests "easier" * @@ -72,6 +65,7 @@ public abstract class AbstractSolrTestCase extends LuceneTestCase { *

*/ protected TestHarness h; + /** * LocalRequestFactory initialized by initTestHarness using sensible * defaults. @@ -124,7 +118,11 @@ public abstract class AbstractSolrTestCase extends LuceneTestCase { * The directory used to story the index managed by the TestHarness h */ protected File dataDir; - + + public static Logger log = LoggerFactory.getLogger(AbstractSolrTestCase.class); + + private String factoryProp; + /** * Initializes things your test might need * @@ -133,16 +131,11 @@ public abstract class AbstractSolrTestCase extends LuceneTestCase { *
  • initializes the TestHarness h using this data directory, and getSchemaPath()
  • *
  • initializes the LocalRequestFactory lrf using sensible defaults.
  • * - * */ - - public static Logger log = LoggerFactory.getLogger(AbstractSolrTestCase.class); - - private String factoryProp; @Override public void setUp() throws Exception { super.setUp(); - log.info("####SETUP_START " + getName()); + log.info("####SETUP_START " + getTestName()); ignoreException("ignore_exception"); factoryProp = System.getProperty("solr.directoryFactory"); if (factoryProp == null) { @@ -162,7 +155,7 @@ public abstract class AbstractSolrTestCase extends LuceneTestCase { lrf = h.getRequestFactory ("standard",0,20,CommonParams.VERSION,"2.2"); } - log.info("####SETUP_END " + getName()); + log.info("####SETUP_END " + getTestName()); } /** Causes an exception matching the regex pattern to not be logged. */ @@ -181,7 +174,7 @@ public abstract class AbstractSolrTestCase extends LuceneTestCase { * to log the fact that their setUp process has ended. */ public void postSetUp() { - log.info("####POSTSETUP " + getName()); + log.info("####POSTSETUP " + getTestName()); } @@ -191,7 +184,7 @@ public abstract class AbstractSolrTestCase extends LuceneTestCase { * tearDown method. */ public void preTearDown() { - log.info("####PRETEARDOWN " + getName()); + log.info("####PRETEARDOWN " + getTestName()); } /** @@ -201,7 +194,7 @@ public abstract class AbstractSolrTestCase extends LuceneTestCase { */ @Override public void tearDown() throws Exception { - log.info("####TEARDOWN_START " + getName()); + log.info("####TEARDOWN_START " + getTestName()); if (factoryProp == null) { System.clearProperty("solr.directoryFactory"); }