();
+ 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 extends FSDirectory> 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 extends Directory> 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 extends Annotation> 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 extends ZipEntry> 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");
}