/**
* 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
*
*
* 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.
*/
/**
* Base class for all Lucene unit tests, Junit3 or Junit4 variant.
* <p>
* </p>
* <p>
* If you
* override either <code>setUp()</code> or
* <code>tearDown()</code> in your unit test, make sure you
* call <code>super.setUp()</code> and
* <code>super.tearDown()</code>
* </p>
*
* <code>@After</code> - replaces setup
* <code>@Before</code> - replaces teardown
* <code>@Test</code> - any public method with this annotation is a test case, regardless
* of its name
* <p>
* <p>
* See Junit4 <a href="http://junit.org/junit/javadoc/4.7/">documentation</a> for a complete list of features.
* <p>
* Import from org.junit rather than junit.framework.
* <p>
* 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)
*/
@RunWith(LuceneTestCaseRunner.class)
/**
* true iff tests are run in verbose mode. Note: if it is false, tests are not
* expected to print any messages.
*/
/** Use this constant when creating Analyzers and any other version-dependent stuff.
* <p><b>NOTE:</b> Change this when development starts for new Lucene version:
*/
/**
* If this is set, it is the only method that should run.
*/
/** Create indexes in this directory, optimally use a subdir, named after the test */
static {
if (s == null)
throw new RuntimeException("To run tests, you need to define system property 'tempDir' or 'java.io.tmpdir'.");
}
/** set of directories we created, in afterclass we try to clean these up */
private static final Map<File, StackTraceElement[]> tempDirs = Collections.synchronizedMap(new HashMap<File, StackTraceElement[]>());
// by default we randomly pick a different codec for
// each test case (non-J4 tests) and each test class (J4
// tests)
/** Gets the locale to run tests with */
/** Gets the timezone to run tests with */
/** Gets the directory to run tests with */
/** Get the number of times to run tests */
/** 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)));
/** Get the random seed for tests */
/** 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", "europarl.lines.txt.gz");
/** whether or not to clean threads between test invocations: "false", "perMethod", "perClass" */
public static final String TEST_CLEAN_THREADS = System.getProperty("tests.cleanthreads", "perClass");
/**
* A random multiplier which you should use when writing random tests:
* multiply it by the number of iterations
*/
public static final int RANDOM_MULTIPLIER = Integer.parseInt(System.getProperty("tests.multiplier", "1"));
/**
* @see SubclassSetupTeardownRule
*/
private boolean setupCalled;
/**
* @see SubclassSetupTeardownRule
*/
private boolean teardownCalled;
/**
* Restore these system property values in {@link #afterClassLuceneTestCaseJ4()}.
*/
private static void initRandom() {
assert !random.initialized;
staticSeed = "random".equals(TEST_SEED) ? seedRand.nextLong() : ThreeLongs.fromString(TEST_SEED).l1;
random.initialized = true;
}
private static boolean icuTested = false;
/**
* Stores the currently class under test.
*/
/**
* 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
*/
"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.
*/
/**
* 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.
*/
@Rule
.outerRule(new SaveThreadAndTestNameRule())
.around(new UncaughtExceptionsRule(this))
.around(new TestResultInterceptorRule())
.around(new InternalSetupTeardownRule())
.around(new SubclassSetupTeardownRule());
public static void beforeClassLuceneTestCaseJ4() {
initRandom();
stores = Collections.synchronizedMap(new IdentityHashMap<MockDirectoryWrapper,StackTraceElement[]>());
// 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
}
// this code consumes randoms where 4.0's lucenetestcase would: to make seeds work across both branches.
// TODO: doesn't completely work, because what if we get mockrandom codec?!
}
// end compatibility random-consumption
// START hack to init ICU safely before we randomize locales.
// ICU fails during classloading when a special Java7-only locale is the default
if (!icuTested) {
icuTested = true;
try {
} catch (ClassNotFoundException cnfe) {
// ignore if no ICU is in classpath
}
}
// END hack
// 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.
timeZone = TEST_TIMEZONE.equals("random") ? randomTimeZone(random) : TimeZone.getTimeZone(TEST_TIMEZONE);
testsFailed = false;
// verify assertions are enabled (do last, for smooth cleanup)
}
}
public static void afterClassLuceneTestCaseJ4() {
} else {
}
}
if (rogueThreads > 0) {
// TODO: fail here once the leaks are fixed.
}
}
try {
// now look for unclosed resources
if (!testsFailed) {
}
} catch (Throwable t) {
}
try {
// clear out any temp directories if we can
if (!testsFailed) {
}
} catch (Throwable t) {
}
// if we had afterClass failures, get some debugging information
}
testsFailed = true;
}
// if verbose or tests failed, report some information back
}
// reset seed
random.initialized = false;
throw new RuntimeException(problem);
}
}
/** print some useful debugging information about the environment */
private static void printDebuggingInformation() {
"locale=" + locale +
}
/** check that directories and their resources were closed */
private static void checkResourcesAfterClass() {
if (d.isOpen()) {
// 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.
break;
}
}
}
}
}
/** clear temp directories: this will fail if its not successful */
private static void clearTempDirectoriesAfterClass() {
try {
} catch (IOException e) {
e.printStackTrace();
// first two STE's are Java's
// print only our code's stack information
}
}
}
}
/**
* 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).
*/
// @Override
return new Statement() {
try {
} catch (AssumptionViolatedException e) {
throw e;
} catch (Throwable t) {
failed(t, description);
throw t;
}
}
};
}
if (VERBOSE) {
} else {
}
}
testsFailed = true;
assert !(e instanceof AssumptionViolatedException);
}
};
/**
* The thread executing the current test case.
* @see #isTestThread()
*/
/**
* @see LuceneTestCase#testCaseThread
*/
// @Override
return new Statement() {
try {
} finally {
}
}
};
}
}
/**
*/
// @Override
return new Statement() {
// 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.
try {
// But we will collect errors from statements below and wrap them
// into a multiple so that tearDownInternal is called.
} catch (Throwable t) {
}
try {
} catch (Throwable t) {
}
}
};
}
}
/**
* Setup before the tests.
*/
}
/**
* Forcible purges all cache entries from the FieldCache.
* <p>
* 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.
* </p>
*
* @see FieldCache#purgeAllCaches()
*/
fc.purgeAllCaches();
}
}
if (mp instanceof LogMergePolicy) {
} else if (mp instanceof TieredMergePolicy) {
} else {
}
}
if (mp instanceof LogMergePolicy) {
} else if (mp instanceof TieredMergePolicy) {
} else {
}
}
/**
* Returns true if and only if the calling thread is the primary thread
* executing the test case.
*/
protected boolean isTestThread() {
}
/**
* 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.
*/
// @Override
return new Statement() {
setupCalled = false;
teardownCalled = false;
// 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) {
}
if (!teardownCalled) {
}
}
};
}
}
/**
* For subclassing only. Overrides must call {@code super.setUp()}.
*/
setupCalled = true;
}
/**
* For subclassing only. Overrides must call {@code super.tearDown()}.
*/
teardownCalled = true;
}
/**
* Clean up after tests.
*/
// this won't throw any exceptions or fail the test
// if we change this, then change this logic
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
} catch (Throwable t) {
}
// 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() {
}
}
}
// jvm-wide list of 'rogue threads' we found, so they only get reported once.
private final static IdentityHashMap<Thread,Boolean> rogueThreads = new IdentityHashMap<Thread,Boolean>();
static {
// just a hack for things like eclipse test-runner threads
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.");
}
}
/**
* 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.
*/
// educated guess
int threadCount = 0;
int rogueCount = 0;
// truncated response
}
for (int i = 0; i < threadCount; i++) {
Thread t = stillRunning[i];
if (t.isAlive() &&
!rogueThreads.containsKey(t) &&
t != Thread.currentThread() &&
// TODO: TimeLimitingCollector starts a thread statically.... WTF?!
/* its ok to keep your searcher across test cases */
rogueThreads.put(t, true);
rogueCount++;
continue;
} else {
// wait on the thread to die of natural causes
try {
} catch (InterruptedException e) { e.printStackTrace(); }
}
// try to stop the thread:
t.interrupt();
}
}
}
return rogueCount;
}
/**
* Asserts that FieldCacheSanityChecker does not detect any
* problems with FieldCache.DEFAULT.
* <p>
* If any problems are found, they are logged to System.err
* (allong with the msg) when the Assertion is thrown.
* </p>
* <p>
* This method is called by tearDown after every test method,
* however IndexReaders scoped inside test methods may be garbage
* collected prior to this method being called, causing errors to
* be overlooked. Tests are encouraged to keep their IndexReaders
* scoped at the class level, or to explicitly call this method
* directly in the same scope as the IndexReader.
* </p>
*
* @see org.apache.lucene.util.FieldCacheSanityChecker
*/
try {
try {
} catch (RuntimeException e) {
throw e;
}
} finally {
// if no failure, then insanity will be null anyway
}
}
}
/**
* Returns a number of at least <code>i</code>
* <p>
* The actual number returned will be influenced by whether {@link #TEST_NIGHTLY}
* is active and {@link #RANDOM_MULTIPLIER}, but also with some random fudge.
*/
}
public static int atLeast(int i) {
}
/**
* Returns true if something should happen rarely,
* <p>
* The actual number returned will be influenced by whether {@link #TEST_NIGHTLY}
* is active and {@link #RANDOM_MULTIPLIER}.
*/
}
public static boolean rarely() {
}
}
public static boolean usually() {
}
// These deprecated methods should be removed soon, when all tests using no Epsilon are fixed:
}
}
}
}
}
assumeTrue(msg, !b);
}
}
}
/**
* Convenience method for logging an iterator.
*
* @param iter Each next() is toString()ed and logged on it's own line. If iter is null this is logged differnetly then an empty iterator.
* @param stream Stream to log messages to.
*/
} else {
}
}
}
/**
* Convenience method for logging an array. Wraps the array in an iterator and delegates
*
* @see #dumpIterator(String,Iterator,PrintStream)
*/
}
/** create a new index writer config with random defaults */
return newIndexWriterConfig(random, v, a);
}
/** create a new index writer config with random defaults using the specified random */
IndexWriterConfig c = new IndexWriterConfig(v, a);
if (r.nextBoolean()) {
} else if (r.nextBoolean()) {
} else {
c.setMergePolicy(new MockRandomMergePolicy(r));
}
if (r.nextBoolean()) {
c.setMergeScheduler(new SerialMergeScheduler());
}
if (r.nextBoolean()) {
if (rarely(r)) {
// crazy value
} else {
// reasonable value
}
}
if (r.nextBoolean()) {
if (rarely(r)) {
// crazy value
c.setTermIndexInterval(r.nextBoolean() ? _TestUtil.nextInt(r, 1, 31) : _TestUtil.nextInt(r, 129, 1000));
} else {
// reasonable value
}
}
if (r.nextBoolean()) {
if (rarely(r)) {
// crazy value
} else {
// reasonable value
}
}
if (rarely(r)) {
c.setMergePolicy(new MockRandomMergePolicy(r));
} else if (r.nextBoolean()) {
} else {
}
c.setReaderPooling(r.nextBoolean());
return c;
}
return newLogMergePolicy(random);
}
return newTieredMergePolicy(random);
}
if (rarely(r)) {
} else {
}
return logmp;
}
if (rarely(r)) {
} else {
}
if (rarely(r)) {
} else {
}
if (rarely(r)) {
} else {
}
return tmp;
}
return logmp;
}
return logmp;
}
return logmp;
}
/**
* Returns a new Directory instance. Use this when the test does not
* care about the specific Directory implementation (most tests).
* <p>
* The Directory is wrapped with {@link MockDirectoryWrapper}.
* By default this means it will be picky, such as ensuring that you
* properly close it and all open files in your test. It will emulate
* some features of Windows, such as not allowing open files to be
* overwritten.
*/
return newDirectory(random);
}
/**
* Returns a new Directory instance, using the specified random.
* See {@link #newDirectory()} for more information.
*/
if (VERBOSE) {
}
return dir;
}
/**
* Returns a new Directory instance, with contents copied from the
* provided directory. See {@link #newDirectory()} for more
* information.
*/
return newDirectory(random, d);
}
/** Returns a new FSDirectory instance over the given file, which must be a folder. */
return newFSDirectory(f, null);
}
/** Returns a new FSDirectory instance over the given file, which must be a folder. */
}
try {
try {
} catch (ClassCastException e) {
// TEST_DIRECTORY is not a sub-class of FSDirectory, so draw one at random
}
}
return dir;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Returns a new Directory instance, using the specified random
* with contents copied from the provided directory. See
* {@link #newDirectory()} for more information.
*/
}
return dir;
}
} else {
return directory;
}
}
/** Returns a new field instance.
* See {@link #newField(String, String, Field.Store, Field.Index, Field.TermVector)} for more information */
}
/** Returns a new field instance.
* See {@link #newField(String, String, Field.Store, Field.Index, Field.TermVector)} for more information */
}
/**
* Returns a new Field instance. Use this when the test does not
* care about some specific field settings (most tests)
* <ul>
* <li>If the store value is set to Store.NO, sometimes the field will be randomly stored.
* <li>More term vector data than you ask for might be indexed, for example if you choose YES
* it might index term vectors with offsets too.
* </ul>
*/
}
/** Returns a new field instance, using the specified random.
* See {@link #newField(String, String, Field.Store, Field.Index, Field.TermVector)} for more information */
}
/** Returns a new field instance, using the specified random.
* See {@link #newField(String, String, Field.Store, Field.Index, Field.TermVector)} for more information */
}
/** Returns a new field instance, using the specified random.
* See {@link #newField(String, String, Field.Store, Field.Index, Field.TermVector)} for more information */
public static Field newField(Random random, String name, String value, Store store, Index index, TermVector tv) {
// most of the time, don't modify the params
}
}
};
switch(minimum) {
default: return TermVector.WITH_POSITIONS_OFFSETS;
}
}
/** return a random Locale from the available locales on the system */
}
/** return a random TimeZone from the available timezones on the system */
}
/** return a Locale object equivalent to its programmatic name */
}
}
"SimpleFSDirectory",
"NIOFSDirectory",
"MMapDirectory"
};
"RAMDirectory",
};
} else {
return "RAMDirectory";
}
}
throws IOException {
FSDirectory d = null;
try {
} catch (Exception e) {
}
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.
*/
}
}
try {
// If it is a FSDirectory type, try its ctor(File)
}
// try empty ctor
return clazz.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/** create a new searcher over the reader.
* This searcher might randomly use threads. */
return newSearcher(r, true);
}
/** create a new searcher over the reader.
* This searcher might randomly use threads.
* if <code>maybeWrap</code> is true, this searcher might wrap the reader
* with one that returns null for getSequentialSubReaders.
*/
if (usually()) {
r = new SlowMultiReaderWrapper(r);
}
return new AssertingIndexSearcher(r);
} else {
int threads = 0;
new NamedThreadFactory("LuceneTestCase"));
}
return new AssertingIndexSearcher(r, ex) {
public void close() throws IOException {
super.close();
}
};
}
}
try {
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
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
* {@link Class#getResourceAsStream} using {@code this.getClass()}.
*/
try {
} catch (Exception e) {
}
}
// We get here from InterceptTestCaseEvents on the 'failed' event....
public static void reportPartialFailureInfo() {
System.err.println("NOTE: reproduce with (hopefully): ant test -Dtestcase=" + testClassesRun.get(testClassesRun.size()-1)
+ reproduceWithExtraParams());
}
// We get here from InterceptTestCaseEvents on the 'failed' event....
public void reportAdditionalFailureInfo() {
StringBuilder b = new StringBuilder();
b.append("NOTE: reproduce with: ant test -Dtestcase=")
}
b.append(" -Dtests.seed=")
}
// extra params that were overridden needed to reproduce the command
// TODO we can't randomize this yet (it drives ant crazy) but this makes tests reproduceable
// in case machines have different default charsets...
}
/**
* Return the current class being tested.
*/
return classNameRule.getTestClass();
}
// recorded seed: for beforeClass
private static long staticSeed;
// seed for individual test methods, changed in @before
private long seed;
/**
* Annotation for tests that should only be run during nightly builds.
*/
public @interface Nightly {}
@Ignore("just a hack")
public final void alwaysIgnoredTestMethod() {}
/** check if assertions are enabled */
private static boolean assertionsEnabled() {
try {
return false; // should never get here
} catch (AssertionError e) {
return true;
}
}
}