/* This file is part of VoltDB.
* Copyright (C) 2008-2017 VoltDB Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
* OTHER DEALINGS IN THE SOFTWARE.
*/
package org.voltdb;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.PrintStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import org.junit.runner.Description;
import org.junit.runner.JUnitCore;
import org.junit.runner.Result;
import org.junit.runner.notification.Failure;
import org.junit.runner.notification.RunListener;
public class VoltTestRunner extends RunListener {
class MultiFileOutputStream extends OutputStream {
HashMap<String, OutputStream> m_streamMap = new HashMap<String, OutputStream>();;
volatile OutputStream[] m_streams = new OutputStream[0];
void rebuildStreamArray() {
OutputStream[] streams = new OutputStream[m_streamMap.size()];
int i = 0;
for (OutputStream s : m_streamMap.values()) {
streams[i++] = s;
}
m_streams = streams;
}
public void addOutputStream(File f) throws IOException {
FileOutputStream fos = new FileOutputStream(f);
m_streamMap.put(f.getCanonicalPath(), fos);
rebuildStreamArray();
}
public void removeOutputStream(File f) throws IOException {
OutputStream os = m_streamMap.get(f.getCanonicalPath());
if (os == null) return;
os.flush();
os.close();
m_streamMap.remove(f.getCanonicalPath());
rebuildStreamArray();
}
@Override
public void close() throws IOException {
for (int i = 0; i < m_streams.length; i++) {
m_streams[i].close();
}
}
@Override
public void flush() throws IOException {
for (int i = 0; i < m_streams.length; i++) {
m_streams[i].flush();
}
}
@Override
public void write(byte[] b, int off, int len) throws IOException {
for (int i = 0; i < m_streams.length; i++) {
m_streams[i].write(b, off, len);
}
}
@Override
public void write(int arg0) throws IOException {
for (int i = 0; i < m_streams.length; i++) {
m_streams[i].write(arg0);
}
}
}
PrintStream STDOUT = System.out;
PrintStream STDERR = System.err;
final MultiFileOutputStream m_out = new MultiFileOutputStream();
final Class<?> m_testClazz;
final String m_timestamp;
String m_dir = null;
public VoltTestRunner(Class<?> testClazz, String timestamp) {
super();
m_testClazz = testClazz;
m_timestamp = timestamp;
}
public boolean run() throws IOException {
try {
m_dir = "testout/junit-" + m_timestamp + "/" + m_testClazz.getCanonicalName() + "/";
new File(m_dir).mkdirs();
// redirect std out/err to files
m_out.addOutputStream(new File(m_dir + "fulloutput.txt"));
System.setOut(new PrintStream(m_out, true));
System.setErr(new PrintStream(m_out, true));
JUnitCore junit = new JUnitCore();
junit.addListener(this);
Result r = junit.run(m_testClazz);
STDOUT.printf("RESULTS: %d/%d\n", r.getRunCount() - r.getFailureCount(), r.getRunCount());
return true;
}
catch (Exception e) {
return false;
}
finally {
m_out.flush();
System.setOut(STDOUT);
System.setErr(STDERR);
m_out.close();
}
}
@Override
public void testFailure(Failure failure) throws Exception {
STDOUT.println("FAILED: " + failure.getDescription().getMethodName());
}
@Override
public void testFinished(Description description) throws Exception {
STDOUT.println("FINISHED: " + description.getMethodName());
m_out.removeOutputStream(new File(m_dir + description.getMethodName() + ".txt"));
}
@Override
public void testStarted(Description description) throws Exception {
STDOUT.println("STARTED: " + description.getMethodName());
m_out.addOutputStream(new File(m_dir + description.getMethodName() + ".txt"));
}
static void configLog4J() {
File log4jFile = new File("tests/runner/log4j.properties");
if (log4jFile.exists() == false) {
log4jFile = new File("log4j.properties");
if (log4jFile.exists() == false) {
System.err.println("Unable to locate log4j properties file. Exiting.");
System.exit(-1);
}
}
URL url = null;
try {
url = new URL("file://" + log4jFile.getAbsolutePath());
} catch (MalformedURLException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.setProperty("log4j.configuration", url.toString());
}
/**
*
* @param args The class to test, followed by the timestamp of the test
*/
public static void main(String[] args) {
configLog4J();
if (args.length == 0) {
System.out.println("TESTERROR: No Arguments");
System.exit(-1);
}
String className = args[0].trim();
DateFormat df = new SimpleDateFormat("yyyy.MM.dd-HH.mm.ss");
String timestamp = df.format(new Date());
if (args.length >= 2) {
// format of the timestamp is "yyyy.MM.dd-HH.mm.ss"
timestamp = args[1].trim();
}
try {
Class<?> testClazz = Class.forName(className);
VoltTestRunner vtr = new VoltTestRunner(testClazz, timestamp);
vtr.run();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}