package edu.stanford.nlp.ie;
import edu.stanford.nlp.io.IOUtils;
import junit.framework.TestCase;
import java.io.*;
import java.util.Properties;
import edu.stanford.nlp.ie.crf.CRFClassifier;
import edu.stanford.nlp.net.Ports;
/**
* Tests several operations on the NERServer.
* <br>
* First, it tests that you can start a server without something
* horrible happening.
* <br>
* Then it tests that you can send it a simple query and get the
* correct result. This result could change, breaking the test, but
* it's a pretty simple query that should work.
* <br>
* Then it tests that if the server goes wrong somehow, the client
* doesn't blow up or hang.
* <br>
* Finally, it tests that two clients accessing the server in multiple
* threads get the same results, ie testing the server is thread safe.
* <br>
* @author John Bauer
*/
public class NERServerITest extends TestCase {
private static CRFClassifier crf = null;
private static final String englishCRFPath =
"/u/nlp/data/ner/goodClassifiers/english.all.3class.nodistsim.crf.ser.gz";
private static final String englishTestFile =
"/u/nlp/data/ner/column_data/conll.testa";
private static String loadedQueryFile = null;
private static final String CHARSET = "UTF-8";
private static final String QUERY = "John Bauer was born in New Jersey";
private static final String EXPECTED_ANSWER =
"John/PERSON Bauer/PERSON was/O born/O in/O New/LOCATION Jersey/LOCATION";
public Thread startNERServer(int port,
AbstractSequenceClassifier classifier,
String charset, boolean daemon)
throws IOException
{
final NERServer server = new NERServer(port, classifier, charset);
Thread thread = new Thread() {
public void run() {
server.run();
}
};
thread.setDaemon(daemon);
thread.start();
return thread;
}
public void setUp()
throws IOException
{
if (crf == null) {
synchronized(NERServerITest.class) {
if (crf == null) {
Properties props = new Properties();
props.setProperty("outputFormat", "slashTags");
crf = new CRFClassifier(props);
crf.loadClassifierNoExceptions(englishCRFPath, props);
}
}
}
if (loadedQueryFile == null) {
synchronized(NERServerITest.class) {
if (loadedQueryFile == null) {
BufferedReader br = IOUtils.readerFromString(englishTestFile);
String line;
StringBuilder query = new StringBuilder();
StringBuilder allQueries = new StringBuilder();
while ((line = br.readLine()) != null) {
line = line.trim();
if (line.length() == 0) {
if (query.length() > 0) {
allQueries.append(query.toString());
allQueries.append("\n");
query = new StringBuilder();
}
continue;
}
String queryWord = line.split("\\s+")[0];
if (query.length() > 0) {
query.append(" ");
}
query.append(queryWord);
}
loadedQueryFile = allQueries.toString();
}
}
}
}
public void testStartServer()
throws IOException
{
int port = Ports.findAvailable(2000, 10000);
System.err.println("testStartServer: starting on port " + port);
startNERServer(port, crf, CHARSET, true);
}
public void testQueryServer()
throws IOException
{
int port = Ports.findAvailable(2000, 10000);
System.err.println("testQueryServer: starting on port " + port);
startNERServer(port, crf, CHARSET, true);
StringReader sin = new StringReader(QUERY);
BufferedReader bin = new BufferedReader(sin);
StringWriter sout = new StringWriter();
BufferedWriter bout = new BufferedWriter(sout);
NERServer.NERClient.communicateWithNERServer("localhost", port, CHARSET,
bin, bout, false);
bout.flush();
assertEquals(EXPECTED_ANSWER, sout.toString().trim());
}
/**
* This test would hang forever for some various kinds of bugs in
* the server/client read/write code
*/
public void testServerDoesntHang()
throws IOException
{
int port = Ports.findAvailable(2000, 10000);
System.err.println("testServerDoesntHang: starting on port " + port);
startNERServer(port, null, CHARSET, true);
StringReader sin = new StringReader(QUERY);
BufferedReader bin = new BufferedReader(sin);
StringWriter sout = new StringWriter();
BufferedWriter bout = new BufferedWriter(sout);
NERServer.NERClient.communicateWithNERServer("localhost", port, CHARSET,
bin, bout, false);
bout.flush();
assertEquals("", sout.toString().trim());
}
public void testThreadedServer()
throws IOException, InterruptedException
{
int port = Ports.findAvailable(2000, 10000);
System.err.println("testThreadedServer: starting on port " + port);
startNERServer(port, crf, CHARSET, true);
StringReader sin = new StringReader(loadedQueryFile);
BufferedReader bin = new BufferedReader(sin);
StringWriter sout = new StringWriter();
BufferedWriter bout = new BufferedWriter(sout);
NERServer.NERClient.communicateWithNERServer("localhost", port, CHARSET,
bin, bout, false);
bout.flush();
String results = sout.toString();
// this should happen regardless of the outputs
System.out.println("Got first results, length " + results.length());
assertTrue(results.length() >= loadedQueryFile.length());
// rerun the results in case the "transductive learning" of the
// NER causes the results to be different the second time through
sin = new StringReader(loadedQueryFile);
bin = new BufferedReader(sin);
sout = new StringWriter();
bout = new BufferedWriter(sout);
NERServer.NERClient.communicateWithNERServer("localhost", port, CHARSET,
bin, bout, false);
bout.flush();
results = sout.toString();
// this should happen regardless of the outputs
System.out.println("Reran results, length " + results.length());
assertTrue(results.length() >= loadedQueryFile.length());
NERClientThread t1 = new NERClientThread("localhost", port, CHARSET,
loadedQueryFile);
NERClientThread t2 = new NERClientThread("localhost", port, CHARSET,
loadedQueryFile);
t1.start();
t2.start();
t1.join();
t2.join();
assertEquals(results, t1.results());
System.out.println("Results from simul client 1 matched");
assertEquals(results, t2.results());
System.out.println("Results from simul client 2 matched");
}
private class NERClientThread extends Thread {
final String host;
final int port;
final String charset;
final String queryText;
String results;
public NERClientThread(String host, int port, String charset,
String queryText) {
this.host = host;
this.port = port;
this.charset = charset;
this.queryText = queryText;
}
public String results() { return results; }
public void run() {
try {
StringReader sin = new StringReader(queryText);
BufferedReader bin = new BufferedReader(sin);
StringWriter sout = new StringWriter();
BufferedWriter bout = new BufferedWriter(sout);
NERServer.NERClient.communicateWithNERServer(host, port, charset,
bin, bout, false);
bout.flush();
results = sout.toString();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
}