TestIndexWriterOnJRECrash should work on any JRE vendor via Runtime.halt().

git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1482746 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Dawid Weiss 2013-05-15 10:08:41 +00:00
parent b5d4f778d2
commit 81ad6c6c6a
2 changed files with 71 additions and 27 deletions

View File

@ -190,6 +190,11 @@ Build
Test framework may fail internally due to overly aggresive J9 optimizations. Test framework may fail internally due to overly aggresive J9 optimizations.
(Dawid Weiss, Shai Erera) (Dawid Weiss, Shai Erera)
Tests
* LUCENE-4901: TestIndexWriterOnJRECrash should work on any
JRE vendor via Runtime.halt().
(Mike McCandless, Robert Muir, Uwe Schindler, Rodrigo Trujillo, Dawid Weiss)
======================= Lucene 4.3.1 ======================= ======================= Lucene 4.3.1 =======================

View File

@ -18,10 +18,11 @@ package org.apache.lucene.index;
* *
*/ */
import java.io.BufferedInputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.ArrayList; import java.util.ArrayList;
@ -49,10 +50,6 @@ public class TestIndexWriterOnJRECrash extends TestNRTThreads {
@Override @Nightly @Override @Nightly
public void testNRTThreads() throws Exception { public void testNRTThreads() throws Exception {
String vendor = Constants.JAVA_VENDOR;
assumeTrue(vendor + " JRE not supported.",
vendor.startsWith("Oracle") || vendor.startsWith("Sun") || vendor.startsWith("Apple"));
// if we are not the fork // if we are not the fork
if (System.getProperty("tests.crashmode") == null) { if (System.getProperty("tests.crashmode") == null) {
// try up to 10 times to create an index // try up to 10 times to create an index
@ -112,18 +109,40 @@ public class TestIndexWriterOnJRECrash extends TestNRTThreads {
pb.directory(tempDir); pb.directory(tempDir);
pb.redirectErrorStream(true); pb.redirectErrorStream(true);
Process p = pb.start(); Process p = pb.start();
InputStream is = p.getInputStream();
BufferedInputStream isl = new BufferedInputStream(is); // We pump everything to stderr.
byte buffer[] = new byte[1024]; PrintStream childOut = System.err;
int len = 0; Thread stdoutPumper = ThreadPumper.start(p.getInputStream(), childOut);
if (VERBOSE) System.err.println(">>> Begin subprocess output"); Thread stderrPumper = ThreadPumper.start(p.getErrorStream(), childOut);
while ((len = isl.read(buffer)) != -1) { if (VERBOSE) childOut.println(">>> Begin subprocess output");
if (VERBOSE) {
System.err.write(buffer, 0, len);
}
}
if (VERBOSE) System.err.println("<<< End subprocess output");
p.waitFor(); p.waitFor();
stdoutPumper.join();
stderrPumper.join();
if (VERBOSE) childOut.println("<<< End subprocess output");
}
/** A pipe thread. It'd be nice to reuse guava's implementation for this... */
static class ThreadPumper {
public static Thread start(final InputStream from, final OutputStream to) {
Thread t = new Thread() {
@Override
public void run() {
try {
byte [] buffer = new byte [1024];
int len;
while ((len = from.read(buffer)) != -1) {
if (VERBOSE) {
to.write(buffer, 0, len);
}
}
} catch (IOException e) {
System.err.println("Couldn't pipe from the forked process: " + e.toString());
}
}
};
t.start();
return t;
}
} }
/** /**
@ -155,20 +174,40 @@ public class TestIndexWriterOnJRECrash extends TestNRTThreads {
} }
return false; return false;
} }
/** /**
* currently, this only works/tested on Sun and IBM. * currently, this only works/tested on Sun and IBM.
*/ */
public void crashJRE() { public void crashJRE() {
try { final String vendor = Constants.JAVA_VENDOR;
Class<?> clazz = Class.forName("sun.misc.Unsafe"); final boolean supportsUnsafeNpeDereference =
// we should use getUnsafe instead, harmony implements it, etc. vendor.startsWith("Oracle") ||
Field field = clazz.getDeclaredField("theUnsafe"); vendor.startsWith("Sun") ||
field.setAccessible(true); vendor.startsWith("Apple");
Object o = field.get(null);
Method m = clazz.getMethod("putAddress", long.class, long.class); try {
m.invoke(o, 0L, 0L); if (supportsUnsafeNpeDereference) {
} catch (Exception e) { e.printStackTrace(); } try {
fail(); Class<?> clazz = Class.forName("sun.misc.Unsafe");
Field field = clazz.getDeclaredField("theUnsafe");
field.setAccessible(true);
Object o = field.get(null);
Method m = clazz.getMethod("putAddress", long.class, long.class);
m.invoke(o, 0L, 0L);
} catch (Throwable e) {
System.out.println("Couldn't kill the JVM via Unsafe.");
e.printStackTrace(System.out);
}
}
// Fallback attempt to Runtime.halt();
Runtime.getRuntime().halt(-1);
} catch (Exception e) {
System.out.println("Couldn't kill the JVM.");
e.printStackTrace(System.out);
}
// We couldn't get the JVM to crash for some reason.
fail();
} }
} }