LUCENE-6405: add infos exc unit tests. fix TestTransactions to handle exceptions on openInput and let MDW do it

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1671995 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Robert Muir 2015-04-08 02:47:11 +00:00
parent 1780ea3488
commit d64899ff18
4 changed files with 335 additions and 16 deletions

View File

@ -28,6 +28,7 @@ import org.apache.lucene.store.Directory;
import org.apache.lucene.store.MockDirectoryWrapper;
import org.apache.lucene.store.RAMDirectory;
import org.apache.lucene.util.English;
import org.apache.lucene.util.IOUtils;
import org.apache.lucene.util.LuceneTestCase;
public class TestTransactions extends LuceneTestCase {
@ -127,15 +128,25 @@ public class TestTransactions extends LuceneTestCase {
try {
writer1.prepareCommit();
} catch (Throwable t) {
writer1.rollback();
writer2.rollback();
// release resources
try {
writer1.rollback();
} catch (Throwable ignore) {}
try {
writer2.rollback();
} catch (Throwable ignore) {}
return;
}
try {
writer2.prepareCommit();
} catch (Throwable t) {
writer1.rollback();
writer2.rollback();
// release resources
try {
writer1.rollback();
} catch (Throwable ignore) {}
try {
writer2.rollback();
} catch (Throwable ignore) {}
return;
}
@ -190,24 +201,20 @@ public class TestTransactions extends LuceneTestCase {
try {
r1 = DirectoryReader.open(dir1);
r2 = DirectoryReader.open(dir2);
} catch (IOException e) {
} catch (Exception e) {
// can be rethrown as RuntimeException if it happens during a close listener
if (!e.getMessage().contains("on purpose")) {
throw e;
}
if (r1 != null) {
r1.close();
}
if (r2 != null) {
r2.close();
}
// release resources
IOUtils.closeWhileHandlingException(r1, r2);
return;
}
}
if (r1.numDocs() != r2.numDocs()) {
throw new RuntimeException("doc counts differ: r1=" + r1.numDocs() + " r2=" + r2.numDocs());
}
r1.close();
r2.close();
IOUtils.closeWhileHandlingException(r1, r2);
}
}

View File

@ -32,6 +32,9 @@ import org.apache.lucene.document.StoredField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.IOContext;
import org.apache.lucene.store.MockDirectoryWrapper;
import org.apache.lucene.store.MockDirectoryWrapper.Failure;
import org.apache.lucene.store.MockDirectoryWrapper.FakeIOException;
import org.apache.lucene.util.StringHelper;
import org.apache.lucene.util.TestUtil;
import org.apache.lucene.util.Version;
@ -94,6 +97,164 @@ public abstract class BaseFieldInfoFormatTestCase extends BaseIndexFileFormatTes
dir.close();
}
/**
* Test field infos write that hits exception immediately on open.
* make sure we get our exception back, no file handle leaks, etc.
*/
public void testExceptionOnCreateOutput() throws Exception {
Failure fail = new Failure() {
@Override
public void eval(MockDirectoryWrapper dir) throws IOException {
for (StackTraceElement e : Thread.currentThread().getStackTrace()) {
if (doFail && "createOutput".equals(e.getMethodName())) {
throw new FakeIOException();
}
}
}
};
MockDirectoryWrapper dir = newMockDirectory();
dir.failOn(fail);
Codec codec = getCodec();
SegmentInfo segmentInfo = newSegmentInfo(dir, "_123");
FieldInfos.Builder builder = new FieldInfos.Builder();
FieldInfo fi = builder.getOrAdd("field");
fi.setIndexOptions(TextField.TYPE_STORED.indexOptions());
addAttributes(fi);
FieldInfos infos = builder.finish();
fail.setDoFail();
try {
codec.fieldInfosFormat().write(dir, segmentInfo, "", infos, IOContext.DEFAULT);
fail("didn't get expected exception");
} catch (FakeIOException expected) {
// ok
} finally {
fail.clearDoFail();
}
dir.close();
}
/**
* Test field infos write that hits exception on close.
* make sure we get our exception back, no file handle leaks, etc.
*/
public void testExceptionOnCloseOutput() throws Exception {
Failure fail = new Failure() {
@Override
public void eval(MockDirectoryWrapper dir) throws IOException {
for (StackTraceElement e : Thread.currentThread().getStackTrace()) {
if (doFail && "close".equals(e.getMethodName())) {
throw new FakeIOException();
}
}
}
};
MockDirectoryWrapper dir = newMockDirectory();
dir.failOn(fail);
Codec codec = getCodec();
SegmentInfo segmentInfo = newSegmentInfo(dir, "_123");
FieldInfos.Builder builder = new FieldInfos.Builder();
FieldInfo fi = builder.getOrAdd("field");
fi.setIndexOptions(TextField.TYPE_STORED.indexOptions());
addAttributes(fi);
FieldInfos infos = builder.finish();
fail.setDoFail();
try {
codec.fieldInfosFormat().write(dir, segmentInfo, "", infos, IOContext.DEFAULT);
fail("didn't get expected exception");
} catch (FakeIOException expected) {
// ok
} finally {
fail.clearDoFail();
}
dir.close();
}
/**
* Test field infos read that hits exception immediately on open.
* make sure we get our exception back, no file handle leaks, etc.
*/
public void testExceptionOnOpenInput() throws Exception {
Failure fail = new Failure() {
@Override
public void eval(MockDirectoryWrapper dir) throws IOException {
for (StackTraceElement e : Thread.currentThread().getStackTrace()) {
if (doFail && "openInput".equals(e.getMethodName())) {
throw new FakeIOException();
}
}
}
};
MockDirectoryWrapper dir = newMockDirectory();
dir.failOn(fail);
Codec codec = getCodec();
SegmentInfo segmentInfo = newSegmentInfo(dir, "_123");
FieldInfos.Builder builder = new FieldInfos.Builder();
FieldInfo fi = builder.getOrAdd("field");
fi.setIndexOptions(TextField.TYPE_STORED.indexOptions());
addAttributes(fi);
FieldInfos infos = builder.finish();
codec.fieldInfosFormat().write(dir, segmentInfo, "", infos, IOContext.DEFAULT);
fail.setDoFail();
try {
codec.fieldInfosFormat().read(dir, segmentInfo, "", IOContext.DEFAULT);
fail("didn't get expected exception");
} catch (FakeIOException expected) {
// ok
} finally {
fail.clearDoFail();
}
dir.close();
}
/**
* Test field infos read that hits exception on close.
* make sure we get our exception back, no file handle leaks, etc.
*/
public void testExceptionOnCloseInput() throws Exception {
Failure fail = new Failure() {
@Override
public void eval(MockDirectoryWrapper dir) throws IOException {
for (StackTraceElement e : Thread.currentThread().getStackTrace()) {
if (doFail && "close".equals(e.getMethodName())) {
throw new FakeIOException();
}
}
}
};
MockDirectoryWrapper dir = newMockDirectory();
dir.failOn(fail);
Codec codec = getCodec();
SegmentInfo segmentInfo = newSegmentInfo(dir, "_123");
FieldInfos.Builder builder = new FieldInfos.Builder();
FieldInfo fi = builder.getOrAdd("field");
fi.setIndexOptions(TextField.TYPE_STORED.indexOptions());
addAttributes(fi);
FieldInfos infos = builder.finish();
codec.fieldInfosFormat().write(dir, segmentInfo, "", infos, IOContext.DEFAULT);
fail.setDoFail();
try {
codec.fieldInfosFormat().read(dir, segmentInfo, "", IOContext.DEFAULT);
fail("didn't get expected exception");
} catch (FakeIOException expected) {
// ok
} finally {
fail.clearDoFail();
}
dir.close();
}
// TODO: more tests
/** Test field infos read/write with random fields, with different values. */

View File

@ -27,8 +27,12 @@ import java.util.Set;
import org.apache.lucene.codecs.Codec;
import org.apache.lucene.document.Document;
import org.apache.lucene.document.StoredField;
import org.apache.lucene.document.TextField;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.IOContext;
import org.apache.lucene.store.MockDirectoryWrapper;
import org.apache.lucene.store.MockDirectoryWrapper.Failure;
import org.apache.lucene.store.MockDirectoryWrapper.FakeIOException;
import org.apache.lucene.util.StringHelper;
import org.apache.lucene.util.TestUtil;
import org.apache.lucene.util.Version;
@ -159,6 +163,155 @@ public abstract class BaseSegmentInfoFormatTestCase extends BaseIndexFileFormatT
}
}
/**
* Test segment infos write that hits exception immediately on open.
* make sure we get our exception back, no file handle leaks, etc.
*/
public void testExceptionOnCreateOutput() throws Exception {
Failure fail = new Failure() {
@Override
public void eval(MockDirectoryWrapper dir) throws IOException {
for (StackTraceElement e : Thread.currentThread().getStackTrace()) {
if (doFail && "createOutput".equals(e.getMethodName())) {
throw new FakeIOException();
}
}
}
};
MockDirectoryWrapper dir = newMockDirectory();
dir.failOn(fail);
Codec codec = getCodec();
byte id[] = StringHelper.randomId();
SegmentInfo info = new SegmentInfo(dir, getVersions()[0], "_123", 1, false, codec,
Collections.<String,String>emptyMap(), id, new HashMap<>());
info.setFiles(Collections.<String>emptySet());
fail.setDoFail();
try {
codec.segmentInfoFormat().write(dir, info, IOContext.DEFAULT);
fail("didn't get expected exception");
} catch (FakeIOException expected) {
// ok
} finally {
fail.clearDoFail();
}
dir.close();
}
/**
* Test segment infos write that hits exception on close.
* make sure we get our exception back, no file handle leaks, etc.
*/
public void testExceptionOnCloseOutput() throws Exception {
Failure fail = new Failure() {
@Override
public void eval(MockDirectoryWrapper dir) throws IOException {
for (StackTraceElement e : Thread.currentThread().getStackTrace()) {
if (doFail && "close".equals(e.getMethodName())) {
throw new FakeIOException();
}
}
}
};
MockDirectoryWrapper dir = newMockDirectory();
dir.failOn(fail);
Codec codec = getCodec();
byte id[] = StringHelper.randomId();
SegmentInfo info = new SegmentInfo(dir, getVersions()[0], "_123", 1, false, codec,
Collections.<String,String>emptyMap(), id, new HashMap<>());
info.setFiles(Collections.<String>emptySet());
fail.setDoFail();
try {
codec.segmentInfoFormat().write(dir, info, IOContext.DEFAULT);
fail("didn't get expected exception");
} catch (FakeIOException expected) {
// ok
} finally {
fail.clearDoFail();
}
dir.close();
}
/**
* Test segment infos read that hits exception immediately on open.
* make sure we get our exception back, no file handle leaks, etc.
*/
public void testExceptionOnOpenInput() throws Exception {
Failure fail = new Failure() {
@Override
public void eval(MockDirectoryWrapper dir) throws IOException {
for (StackTraceElement e : Thread.currentThread().getStackTrace()) {
if (doFail && "openInput".equals(e.getMethodName())) {
throw new FakeIOException();
}
}
}
};
MockDirectoryWrapper dir = newMockDirectory();
dir.failOn(fail);
Codec codec = getCodec();
byte id[] = StringHelper.randomId();
SegmentInfo info = new SegmentInfo(dir, getVersions()[0], "_123", 1, false, codec,
Collections.<String,String>emptyMap(), id, new HashMap<>());
info.setFiles(Collections.<String>emptySet());
codec.segmentInfoFormat().write(dir, info, IOContext.DEFAULT);
fail.setDoFail();
try {
codec.segmentInfoFormat().read(dir, "_123", id, IOContext.DEFAULT);
fail("didn't get expected exception");
} catch (FakeIOException expected) {
// ok
} finally {
fail.clearDoFail();
}
dir.close();
}
/**
* Test segment infos read that hits exception on close
* make sure we get our exception back, no file handle leaks, etc.
*/
public void testExceptionOnCloseInput() throws Exception {
Failure fail = new Failure() {
@Override
public void eval(MockDirectoryWrapper dir) throws IOException {
for (StackTraceElement e : Thread.currentThread().getStackTrace()) {
if (doFail && "close".equals(e.getMethodName())) {
throw new FakeIOException();
}
}
}
};
MockDirectoryWrapper dir = newMockDirectory();
dir.failOn(fail);
Codec codec = getCodec();
byte id[] = StringHelper.randomId();
SegmentInfo info = new SegmentInfo(dir, getVersions()[0], "_123", 1, false, codec,
Collections.<String,String>emptyMap(), id, new HashMap<>());
info.setFiles(Collections.<String>emptySet());
codec.segmentInfoFormat().write(dir, info, IOContext.DEFAULT);
fail.setDoFail();
try {
codec.segmentInfoFormat().read(dir, "_123", id, IOContext.DEFAULT);
fail("didn't get expected exception");
} catch (FakeIOException expected) {
// ok
} finally {
fail.clearDoFail();
}
dir.close();
}
/**
* Sets some otherwise hard-to-test properties:
* random segment names, ID values, document count, etc and round-trips

View File

@ -44,9 +44,6 @@ public class MockIndexInputWrapper extends IndexInput {
@Override
public void close() throws IOException {
// TODO turn on the following to look for leaks closing inputs,
// after fixing TestTransactions
// dir.maybeThrowDeterministicException();
if (closed) {
delegate.close(); // don't mask double-close bugs
return;
@ -61,6 +58,7 @@ public class MockIndexInputWrapper extends IndexInput {
if (!isClone) {
dir.removeIndexInput(this, name);
}
dir.maybeThrowDeterministicException();
}
}