package autograder;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintStream;
import java.io.StringReader;
import java.util.Calendar;
import java.util.concurrent.locks.Lock;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import kvstore.KVCache;
import kvstore.KVException;
import kvstore.KeyValueInterface;
import org.junit.runner.Request;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import autograder.AGCategories.AGSuite;
import autograder.AGException.ErrCat;
public class TestUtils {
public static final int kTimeoutQuick = 3 * 1000;
public static final int kTimeoutDefault = 10 * 1000;
public static final int kTimeoutSlow = 25 * 1000;
// TODO: Use dynamic port within a range for all tests
public static final int basePort = getEnvInt("AG_PORT_BASE", 8100);
public static final String testHost = getEnvString("AG_HOST", "localhost");
// Try to avoid colision (separate ports just in case one dangles)
public static final int PORT_Client = basePort + 0;
public static final int PORT_Server = basePort + 1;
public static final int PORT_StudentEnds = basePort + 2;
public static final int PORT_STU = basePort + 3;
public static final int PORT_REF = basePort + 4;
public static final int PORT_MSG = basePort + 5;
// Ideally would impose "localhost"...but might require submission hacking.
public static final int PORT_MasterServer = 8080;
public static final int PORT_Registration = 9090;
public static String getEnvString(String name, String def) {
String ret = null;
try {
ret = System.getProperty(name);
} catch (Exception e) {}
if (ret == null) {
try {
ret = System.getenv(name);
} catch (Exception e) {
System.err.format("EXCEPTION reading env %s: %s%n", name, e);
}
}
return (ret == null) ? def : ret;
}
public static int getEnvInt(String name, int def) {
String s = null;
try {
s = getEnvString(name, null);
if (s != null) return Integer.parseInt(s);
} catch (NumberFormatException e) {
System.err.format("ERROR parsing value of env %s='%s'%n", name, s);
}
return def;
}
public static String readWholeFile(String fileName) {
BufferedReader br = null;
try {
String curr;
String ret = "";
br = new BufferedReader(new FileReader(fileName));
while ((curr = br.readLine()) != null) {
ret += curr;
}
return ret;
} catch (IOException ioe) {
throw new AGException(ErrCat.INTERNAL, "Unable to read a test file", ioe);
} finally {
if (br != null) {
try {
br.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
public static Element parseXMLFile(String fileName) throws FileNotFoundException {
InputStream istream = new FileInputStream(fileName);
try {
InputSource isource = new InputSource(istream);
// TODO: Grab into string first...or add a filter to capture contents in parallel
return parseXMLSource(isource);
} finally {
try {
istream.close();
} catch (IOException e) {
// Ignore
}
}
}
public static Element parseXMLString(String inXML) {
InputSource is = new InputSource();
is.setCharacterStream(new StringReader(inXML));
return parseXMLSource(is);
}
public static Element parseXMLSource(InputSource is) {
DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
dbf.setValidating(false);
dbf.setCoalescing(true);
dbf.setIgnoringComments(true);
dbf.setIgnoringElementContentWhitespace(true); // Useless (only active in validating mode)
try {
DocumentBuilder db = dbf.newDocumentBuilder();
Document doc = db.parse(is);
return doc.getDocumentElement();
} catch (ParserConfigurationException e) {
throw new AGException(ErrCat.INTERNAL, "Unable to create XML parser", e);
} catch (IOException e) {
throw new AGException(ErrCat.INTERNAL, "Unable to read XML string", e);
} catch (SAXException e) {
throw new AGException(ErrCat.INTERNAL, "Unable to parse XML string", e);
}
}
public static String getTextValue(Element ele, String tagName) {
NodeList nl = ele.getElementsByTagName(tagName);
if ((nl != null) && (nl.getLength() == 1)) return nl.item(0).getTextContent();
return null;
}
public static class KVCacheLockWrapper extends KVCache {
public KVCacheLockWrapper(int numSets, int maxElemsPerSet) {
super(numSets, maxElemsPerSet);
// System.out.printf("new KVCacheLockWrapper(%d, %d)%n", numSets, maxElemsPerSet);
}
@Override
public void put(String key, String value) {
Lock lock = getLock(key);
if (lock != null) {
lock.lock();
}
try {
super.put(key, value);
} finally {
if (lock != null) {
lock.unlock();
}
}
}
@Override
public String get(String key) {
Lock lock = getLock(key);
if (lock != null) {
lock.lock();
}
try {
return super.get(key);
} finally {
if (lock != null) {
lock.unlock();
}
}
}
@Override
public void del(String key) {
Lock lock = getLock(key);
if (lock != null) {
lock.lock();
}
try {
super.del(key);
} finally {
if (lock != null) {
lock.unlock();
}
}
}
}
// This can help precipitate failures in == vs String.equals()
public static class KVInternHurter implements KeyValueInterface {
KeyValueInterface delegate;
public KVInternHurter(KeyValueInterface d) {
delegate = d;
System.out.printf("new KVInternHurter(%s)%n", d);
}
@Override
public void put(String key, String value) throws KVException {
delegate.put(internifunker(key), internifunker(value));
}
@Override
public String get(String key) throws KVException {
return internifunker(delegate.get(internifunker(key)));
}
@Override
public void del(String key) throws KVException {
delegate.del(internifunker(key));
}
public static String internifunker(String s) {
return (s == null) ? null : new String(s); // Hopefully reliable
}
}
// This may or may-not be reliable (hard to say)
public static class KVInternHelper implements KeyValueInterface {
KeyValueInterface delegate;
public KVInternHelper(KeyValueInterface d) {
delegate = d;
System.out.printf("new KVInternHelper(%s)%n", d);
}
@Override
public void put(String key, String value) throws KVException {
delegate.put(internifier(key), internifier(value));
}
@Override
public String get(String key) throws KVException {
return internifier(delegate.get(internifier(key)));
}
@Override
public void del(String key) throws KVException {
delegate.del(internifier(key));
}
public static String internifier(String s) {
return (s == null) ? null : s.intern(); // Uncertain reliability
}
}
public static Calendar elapsedTime(Calendar start, Calendar finish) {
int elapsedMS = (int) (finish.getTimeInMillis() - start.getTimeInMillis());
Calendar elapsedCal = Calendar.getInstance();
elapsedCal.set(Calendar.HOUR_OF_DAY, 0);
elapsedCal.set(Calendar.MINUTE, 0);
elapsedCal.set(Calendar.SECOND, 0);
elapsedCal.set(Calendar.MILLISECOND, 0);
elapsedCal.add(Calendar.MILLISECOND, elapsedMS);
return elapsedCal;
}
public static String indentStr(int num, String ident) {
return new String(new char[num]).replace("\0", ident);
}
public static void main(String[] args) {
int status = 1;
AGSuite testSuite = null;
if (args.length >= 1) {
try {
testSuite = AGSuite.valueOf(args[0].replace("-", "_"));
} catch (Exception e) {
System.err.format("Unknown test suite: %s%n", args[0]);
System.exit(status);
return;
}
} else {
System.err.println("Specify test suite as argument.");
System.exit(status);
}
PrintStream origErr = System.err;
try {
Request req = testSuite.getJUnitRequest();
if (args.length > 1) {
if (args[1].equalsIgnoreCase("list")) {
AGCategories.listTests(req.getRunner().getDescription(), -1);
} else if (args[1].equalsIgnoreCase("tree")) {
AGCategories.listTests(req.getRunner().getDescription(), 1);
} else if (args[1].equalsIgnoreCase("weights")) {
AGCategories.listTests(req.getRunner().getDescription(), 0);
} else {
origErr.format("Unrecognized command: %s%n", args[1]);
System.exit(status);
}
System.exit(0);
}
boolean perfect = AGCategories.runJUnitTests(req);
status = perfect ? 0 : 1;
} catch (Throwable e) {
e.printStackTrace(origErr);
}
System.exit(status);
}
}