package cookbook;
import java.util.ArrayList;
import java.util.List;
import org.junit.internal.TextListener;
import org.junit.runner.*;
import org.junit.runner.notification.Failure;
import water.H2O;
import water.TestUtil;
import water.deploy.NodeCL;
import water.util.Log;
import water.util.Utils;
/**
* Run cookbook examples.
*
* Runs all the cookbook examples.
* Does not require any arguments.
*/
public class CookbookRunner {
/**
* Number of H2O nodes to start.
*
* Note that all nodes are started within one process by this harness.
* This approach is good for unit testing. You would not want to deploy to production like this.
*
* Each H2O node is wrapped in it's own classloader. The H2O nodes communicate with each other
* using sockets even though they all live in the same process. This gives very realistic test
* behavior.
*/
public static final int NODES = 3;
/**
* Main program.
*
* No args required. Exit code 0 means all tests passed, nonzero otherwise.
* Each H2O node needs two ports, n and n+1. Start assigning ports at 54321.
*
* @param args (ignored)
* @throws Exception
*/
public static void main(String[] args) throws Exception {
int[] ports = new int[NODES];
for( int i = 0; i < ports.length; i++ )
ports[i] = 54321 + i * 2;
// Create a flatfile on the fly so nodes can find each other.
String flat = "";
for( int i = 0; i < ports.length; i++ )
flat += "127.0.0.1:" + ports[i] + "\n";
flat = Utils.writeFile(flat).getAbsolutePath();
// Start the individual nodes.
for( int i = 0; i < ports.length; i++ ) {
Class c;
if (i == 0) {
// Choose a node to be special and run the test class code.
c = UserCode.class;
}
else {
// All other nodes (second and on) need to be started but just join up and form the cloud.
c = SecondNode.class;
}
NodeCL n = new NodeCL(c, ("-ip 127.0.0.1 -port " + ports[i] + " -flatfile " + flat).split(" "));
n.start();
}
}
/**
* Start the lead node where the test driver executes.
*/
public static class UserCode {
/**
* Start method called by the new classloader for the lead node.
* Every H2O node gets its own classloader.
*
* @param args Any arguments passed to H2O main for this node.
*/
public static void userMain(String[] args) {
H2O.main(args);
TestUtil.stall_till_cloudsize(NODES);
//
// Set up the list of test classes to run.
//
List<Class> tests = new ArrayList<Class>();
// tests.add(cookbook.Cookbook.class);
tests.add(H2OCookbook.class);
tests.add(FrameCookbook.class);
tests.add(VecChunkDemo.class);
tests.add(KeyDemo.class);
tests.add(FillNAsWithMeanDemo01.class);
tests.add(FillNAsWithMeanDemo02.class);
tests.add(FillNAsWithMeanDemo03.class);
tests.add(FramDemo.class);
tests.add(VecDemo.class);
tests.add(ChunkDemo.class);
//
// Run tests.
//
JUnitCore junit = new JUnitCore();
junit.addListener(new LogListener());
Result result = junit.run(tests.toArray(new Class[0]));
//
// Report final result and exit with the correct exit value indicating pass or fail.
//
if( result.getFailures().size() == 0 ) {
Log.info("ALL TESTS PASSED");
H2O.exit(0);
}
else {
Log.err("SOME TESTS FAILED");
H2O.exit(1);
}
}
}
/**
* Start a second (or beyond) node to form a multinode cloud.
*/
public static class SecondNode {
/**
* Start method called by the new classloader for a non-lead node.
*
* @param args Any arguments passed to H2O main for this node.
*/
public static void userMain(String[] args) {
H2O.main(args);
}
}
/**
* Print out information about each test.
*/
static class LogListener extends TextListener {
LogListener() {
super(System.out);
}
@Override public void testRunFinished(Result result) {
printHeader(result.getRunTime());
printFailures(result);
printFooter(result);
}
@Override public void testStarted(Description description) {
Log.info("");
Log.info("Starting test " + description);
}
@Override public void testFailure(Failure failure) {
Log.info("Test failed " + failure);
}
@Override public void testIgnored(Description description) {
Log.info("Ignoring test " + description);
}
}
}