use of com.carrotsearch.ant.tasks.junit4.events.BootstrapEvent in project randomizedtesting by randomizedtesting.
the class LocalSlaveStreamHandler method pumpEvents.
/**
* Pump events from event stream.
*/
void pumpEvents(InputStream eventStream) {
try {
Deserializer deserializer = new Deserializer(eventStream, refLoader);
IEvent event = null;
while ((event = deserializer.deserialize()) != null) {
switch(event.getType()) {
case APPEND_STDERR:
case APPEND_STDOUT:
// Ignore these two on activity heartbeats. GH-117
break;
default:
lastActivity = System.currentTimeMillis();
break;
}
try {
switch(event.getType()) {
case QUIT:
eventBus.post(event);
return;
case IDLE:
eventBus.post(new SlaveIdle(stdinWriter));
break;
case BOOTSTRAP:
clientCharset = Charset.forName(((BootstrapEvent) event).getDefaultCharsetName());
stdinWriter = new OutputStreamWriter(stdin, clientCharset);
eventBus.post(event);
break;
case APPEND_STDERR:
case APPEND_STDOUT:
assert streamsBuffer.getFilePointer() == streamsBuffer.length();
final long bufferStart = streamsBuffer.getFilePointer();
IStreamEvent streamEvent = (IStreamEvent) event;
streamEvent.copyTo(streamsBufferWrapper);
final long bufferEnd = streamsBuffer.getFilePointer();
event = new OnDiskStreamEvent(event.getType(), streamsBuffer, bufferStart, bufferEnd);
eventBus.post(event);
break;
default:
eventBus.post(event);
}
} catch (Throwable t) {
warnStream.println("Event bus dispatch error: " + t.toString());
t.printStackTrace(warnStream);
}
}
lastActivity = null;
} catch (Throwable e) {
if (!stopping) {
warnStream.println("Event stream error: " + e.toString());
e.printStackTrace(warnStream);
}
}
}
use of com.carrotsearch.ant.tasks.junit4.events.BootstrapEvent in project randomizedtesting by randomizedtesting.
the class SlaveMain method main.
/**
* Console entry point.
*/
@SuppressWarnings("resource")
public static void main(String[] allArgs) {
int exitStatus = 0;
Serializer serializer = null;
try {
final ArrayDeque<String> args = new ArrayDeque<String>(Arrays.asList(allArgs));
// Options.
boolean debugStream = false;
boolean flushFrequently = false;
File eventsFile = null;
boolean suitesOnStdin = false;
List<String> testClasses = new ArrayList<>();
while (!args.isEmpty()) {
String option = args.pop();
if (option.equals(OPTION_FREQUENT_FLUSH)) {
flushFrequently = true;
} else if (option.equals(OPTION_STDIN)) {
suitesOnStdin = true;
} else if (option.equals(OPTION_SYSOUTS)) {
multiplexStdStreams = true;
} else if (option.equals(OPTION_EVENTSFILE)) {
eventsFile = new File(args.pop());
if (eventsFile.isFile() && eventsFile.length() > 0) {
RandomAccessFile raf = new RandomAccessFile(eventsFile, "rw");
raf.setLength(0);
raf.close();
}
} else if (option.startsWith(OPTION_DEBUGSTREAM)) {
debugStream = true;
} else if (option.startsWith("@")) {
// Append arguments file, one line per option.
args.addAll(Arrays.asList(readArgsFile(option.substring(1))));
} else {
// The default expectation is a test class.
testClasses.add(option);
}
}
// Set up events channel and events serializer.
if (eventsFile == null) {
throw new IOException("You must specify communication channel for events.");
}
// Send bootstrap package.
serializer = new Serializer(new EventsOutputStream(eventsFile)).serialize(new BootstrapEvent()).flush();
// Redirect original streams and start running tests.
redirectStreams(serializer, flushFrequently);
final SlaveMain main = new SlaveMain(serializer);
main.flushFrequently = flushFrequently;
main.debugMessagesFile = debugStream ? new File(eventsFile.getAbsolutePath() + ".debug") : null;
final Iterator<String> stdInput;
if (suitesOnStdin) {
stdInput = new StdInLineIterator(main.serializer);
} else {
stdInput = Collections.<String>emptyList().iterator();
}
main.execute(Iterators.concat(testClasses.iterator(), stdInput));
// For unhandled exceptions tests.
if (System.getProperty(SYSPROP_FIRERUNNERFAILURE) != null) {
throw new Exception(System.getProperty(SYSPROP_FIRERUNNERFAILURE));
}
} catch (Throwable t) {
lastResortMemory = null;
tryWaitingForGC();
if (t.getClass() == oomClass) {
exitStatus = ERR_OOM;
warn("JVM out of memory.", t);
} else {
exitStatus = ERR_EXCEPTION;
warn("Exception at main loop level.", t);
}
}
try {
if (serializer != null) {
try {
serializer.close();
} catch (Throwable t) {
warn("Exception closing serializer.", t);
}
}
} finally {
JvmExit.halt(exitStatus);
}
}
use of com.carrotsearch.ant.tasks.junit4.events.BootstrapEvent in project randomizedtesting by randomizedtesting.
the class JUnit4 method executeSlave.
/**
* Attach listeners and execute a slave process.
*/
private void executeSlave(final ForkedJvmInfo slave, final EventBus aggregatedBus) throws Exception {
final String uniqueSeed = new SimpleDateFormat("yyyyMMdd_HHmmss_SSS", Locale.ROOT).format(new Date());
final Path classNamesFile = tempFile(uniqueSeed, "junit4-J" + slave.id, ".suites", getTempDir());
temporaryFiles.add(classNamesFile);
final Path classNamesDynamic = tempFile(uniqueSeed, "junit4-J" + slave.id, ".dynamic-suites", getTempDir());
final Path streamsBufferFile = tempFile(uniqueSeed, "junit4-J" + slave.id, ".spill", getTempDir());
// Dump all test class names to a temporary file.
String testClassPerLine = Joiner.on("\n").join(slave.testSuites);
log("Test class names:\n" + testClassPerLine, Project.MSG_VERBOSE);
Files.write(classNamesFile, testClassPerLine.getBytes(StandardCharsets.UTF_8));
// Prepare command line for java execution.
CommandlineJava commandline;
commandline = (CommandlineJava) getCommandline().clone();
commandline.createClasspath(getProject()).add(addSlaveClasspath());
commandline.setClassname(SlaveMainSafe.class.getName());
if (slave.slaves == 1) {
commandline.createArgument().setValue(SlaveMain.OPTION_FREQUENT_FLUSH);
}
// Set up full output files.
Path sysoutFile = tempFile(uniqueSeed, "junit4-J" + slave.id, ".sysout", getTempDir());
Path syserrFile = tempFile(uniqueSeed, "junit4-J" + slave.id, ".syserr", getTempDir());
// Set up communication channel.
Path eventFile = tempFile(uniqueSeed, "junit4-J" + slave.id, ".events", getTempDir());
temporaryFiles.add(eventFile);
commandline.createArgument().setValue(SlaveMain.OPTION_EVENTSFILE);
commandline.createArgument().setFile(eventFile.toFile());
if (sysouts) {
commandline.createArgument().setValue(SlaveMain.OPTION_SYSOUTS);
}
if (debugStream) {
commandline.createArgument().setValue(SlaveMain.OPTION_DEBUGSTREAM);
}
InputStream eventStream = new TailInputStream(eventFile);
// Set up input suites file.
commandline.createArgument().setValue("@" + classNamesFile.toAbsolutePath().normalize());
// not using it.
if (dynamicAssignmentRatio > 0) {
commandline.createArgument().setValue(SlaveMain.OPTION_STDIN);
}
final EventBus eventBus = new EventBus("slave-" + slave.id);
final DiagnosticsListener diagnosticsListener = new DiagnosticsListener(slave, this);
eventBus.register(diagnosticsListener);
eventBus.register(new AggregatingListener(aggregatedBus, slave));
final AtomicReference<Charset> clientCharset = new AtomicReference<Charset>();
final AtomicBoolean clientWithLimitedCharset = new AtomicBoolean();
final PrintWriter w = new PrintWriter(Files.newBufferedWriter(classNamesDynamic, StandardCharsets.UTF_8));
eventBus.register(new Object() {
@Subscribe
public void onIdleSlave(final SlaveIdle idleSlave) {
aggregatedBus.post(new SlaveIdle() {
@Override
public void finished() {
idleSlave.finished();
}
@Override
public void newSuite(String suiteName) {
if (!clientCharset.get().newEncoder().canEncode(suiteName)) {
clientWithLimitedCharset.set(true);
log("Forked JVM J" + slave.id + " skipped suite (cannot encode suite name in charset " + clientCharset.get() + "): " + suiteName, Project.MSG_WARN);
return;
}
log("Forked JVM J" + slave.id + " stole suite: " + suiteName, Project.MSG_VERBOSE);
w.println(suiteName);
w.flush();
idleSlave.newSuite(suiteName);
}
});
}
@Subscribe
public void onBootstrap(final BootstrapEvent e) {
Charset cs = Charset.forName(((BootstrapEvent) e).getDefaultCharsetName());
clientCharset.set(cs);
slave.start = System.currentTimeMillis();
slave.setBootstrapEvent(e);
aggregatedBus.post(new ChildBootstrap(slave));
}
@Subscribe
public void receiveQuit(QuitEvent e) {
slave.end = System.currentTimeMillis();
}
});
Closer closer = Closer.create();
closer.register(eventStream);
closer.register(w);
try {
OutputStream sysout = closer.register(new BufferedOutputStream(Files.newOutputStream(sysoutFile)));
OutputStream syserr = closer.register(new BufferedOutputStream(Files.newOutputStream(syserrFile)));
RandomAccessFile streamsBuffer = closer.register(new RandomAccessFile(streamsBufferFile.toFile(), "rw"));
Execute execute = forkProcess(slave, eventBus, commandline, eventStream, sysout, syserr, streamsBuffer);
log("Forked JVM J" + slave.id + " finished with exit code: " + execute.getExitValue(), Project.MSG_DEBUG);
if (execute.isFailure()) {
final int exitStatus = execute.getExitValue();
switch(exitStatus) {
case SlaveMain.ERR_NO_JUNIT:
throw new BuildException("Forked JVM's classpath must include a junit4 JAR.");
case SlaveMain.ERR_OLD_JUNIT:
throw new BuildException("Forked JVM's classpath must use JUnit 4.10 or newer.");
default:
Closeables.close(sysout, false);
Closeables.close(syserr, false);
StringBuilder message = new StringBuilder();
if (exitStatus == SlaveMain.ERR_OOM) {
message.append("Forked JVM ran out of memory.");
} else {
message.append("Forked process returned with error code: ").append(exitStatus).append(".");
}
if (Files.size(sysoutFile) > 0 || Files.size(syserrFile) > 0) {
if (exitStatus != SlaveMain.ERR_OOM) {
message.append(" Very likely a JVM crash. ");
}
if (jvmOutputAction.contains(JvmOutputAction.PIPE)) {
message.append(" Process output piped in logs above.");
} else if (!jvmOutputAction.contains(JvmOutputAction.IGNORE)) {
if (Files.size(sysoutFile) > 0) {
message.append(" See process stdout at: " + sysoutFile.toAbsolutePath());
}
if (Files.size(syserrFile) > 0) {
message.append(" See process stderr at: " + syserrFile.toAbsolutePath());
}
}
}
throw new BuildException(message.toString());
}
}
} catch (Throwable t) {
throw closer.rethrow(t);
} finally {
try {
closer.close();
} finally {
com.google.common.io.Files.asByteSource(classNamesDynamic.toFile()).copyTo(com.google.common.io.Files.asByteSink(classNamesFile.toFile(), FileWriteMode.APPEND));
Files.delete(classNamesDynamic);
Files.delete(streamsBufferFile);
// Check sysout/syserr lengths.
checkJvmOutput(aggregatedBus, sysoutFile, slave, "stdout");
checkJvmOutput(aggregatedBus, syserrFile, slave, "stderr");
}
}
if (!diagnosticsListener.quitReceived()) {
throw new BuildException("Quit event not received from the forked process? This may indicate JVM crash or runner bugs.");
}
if (clientWithLimitedCharset.get() && dynamicAssignmentRatio > 0) {
throw new BuildException("Forked JVM J" + slave.id + " was not be able to decode class names when using" + " charset: " + clientCharset + ". Do not use " + "dynamic suite balancing to work around this problem (-DdynamicAssignmentRatio=0).");
}
}
Aggregations