Clover coverage report -
Coverage timestamp: Sat Jul 7 2007 16:41:13 CEST
file stats: LOC: 325   Methods: 12
NCLOC: 203   Classes: 1
 
 Source file Conditionals Statements Methods TOTAL
TestRunManager.java 85% 83.8% 100% 85.3%
coverage coverage
 1    /**
 2    * JTRunner is free software; you can redistribute it and/or modify it under the
 3    * terms of the GNU General Public License as published by the Free Software
 4    * Foundation; either version 2, or (at your option) any later version.
 5    */
 6   
 7    package jtr.test;
 8   
 9    import java.rmi.registry.Registry;
 10    import java.util.List;
 11    import jtr.remote.test.DistributionError;
 12    import jtr.test.ITestCompletionListener;
 13    import jtr.remote.test.TestOutcomeCollector;
 14    import jtr.remote.test.impl.TestOutcomeCollectorImpl;
 15   
 16    import static jtr.test.SystemProperties.*;
 17    import jtr.config.Factories;
 18    import jtr.config.Factory;
 19    import jtr.config.RegisteredFactories;
 20    import jtr.config.RegistrationFailedException;
 21    import jtr.config.remote.Node;
 22    import jtr.config.remote.Nodes;
 23    import jtr.pool.IPoolManager;
 24    import jtr.config.TestConfig;
 25    import jtr.remote.cl.JtrRmiClassLoaderServerLauncher;
 26    import jtr.remote.test.NodeInfo;
 27    import jtr.remote.utils.RmiUtil;
 28    import jtr.runners.IRunnerCreationException;
 29    import jtr.assigner.UnknownAssignmentPolicyException;
 30    import jtr.assigner.MissingStdParameterException;
 31    import jtr.runners.IRunnerPooled;
 32    import jtr.pool.RunnerPool;
 33    import jtr.pool.RunnerPoolFiller;
 34    import jtr.runners.IRunnerParameterized;
 35   
 36    import jtr.ui.swing.TestRunningFrame;
 37    import org.apache.log4j.Logger;
 38   
 39    /**
 40    * This class is the manager of a JTR test. <br>
 41    * Its responsabilites are: <br>
 42    * 1. creating a thread group within which all the <code>IRunner</code>s will
 43    * execute<br>
 44    * 2. initializing the pool of <code>IRunner</code>s accoding to the
 45    * content of the <code>jtr.xml</code> file<br>
 46    * 3. starting all the <code>IRunner</code>s<br>
 47    * 4. managing the pooling of the <code>IRunners</code> after each epoch<br>
 48    *
 49    * @author Francesco Russo (frusso@dev.java.net)
 50    * @version 4.0
 51    * @since 1.0
 52    *
 53    * @see jtr.runners.IRunnerPooled
 54    * @see jtr.pool.RunnerPool
 55    * @see jtr.pool.RunnerPoolFiller
 56    */
 57    public class TestRunManager implements IPoolManager {
 58    /**
 59    * Costructor.
 60    *
 61    * @param testConfig
 62    * The test configuration obtained from the <code>jtr.xml</code>
 63    * file
 64    */
 65  2 public TestRunManager(TestConfig testConfig) {
 66  2 logger.info("TestRunManager initialization...");
 67  2 this.testConfig = testConfig;
 68  2 configureFactories();
 69  2 runnersThreadGroup = new ThreadGroup(TH_GRP_NAME);
 70  2 epochs = testConfig.getEpochs();
 71  2 testOutcomeTable = new TestOutcomeTable(NodeInfo.newLocalNodeInfo());
 72  2 testCompletionListener = (ITestCompletionListener) RegisteredFactories.getFactory(RegisteredFactories.ITEST_COMPLETION_LISTENER);
 73  2 logger.info("... done");
 74    }
 75   
 76  2 private void configureFactories() throws RegistrationFailedException {
 77  2 Factories fs = testConfig.getFactories();
 78  2 if(fs!=null) {
 79  2 List<Factory> lfs = fs.getFactories();
 80  2 for(Factory f : lfs) {
 81  12 RegisteredFactories.registerFactory(f.getKey(),f.getFqn());
 82    }
 83    } else {
 84  0 throw new RegistrationFailedException("No JTR factories have been defined. Test cannot proceede. Aborting.");
 85    }
 86    }
 87   
 88    /**
 89    * Launches the test.
 90    *
 91    * @throws TestFailedException
 92    */
 93  1 public void startTest() throws TestFailedException {
 94  1 try {
 95  1 logger.debug("Starting test...");
 96  1 testCompletionListener.addNode(NodeInfo.newLocalNodeInfo());
 97  1 distributeTest(testConfig);
 98   
 99  1 pool = initializePool(testConfig, testCompletionListener);
 100  1 logger.debug("Pool initialized...");
 101  1 initialPoolSize = pool.size();
 102  1 logger.debug("Initial pool size is " + initialPoolSize + ", starting the threads...");
 103   
 104  1 testOutcomeTable.setStartTime();
 105  1 provideFeedBack();
 106  1 startThreads();
 107  1 logger.debug("... threads all started");
 108    } catch (IRunnerCreationException e) {
 109  0 String msg = "The test failed at run " + partialCount + " due to an IRunnerCreationException";
 110  0 TestFailedException tfe = new TestFailedException(msg, e);
 111  0 logger.fatal(msg, tfe);
 112  0 throw tfe;
 113    } catch (UnknownAssignmentPolicyException e) {
 114  0 String msg = "The test failed at run " + partialCount + " due to an UnknownAssignmentPolicyException";
 115  0 TestFailedException tfe = new TestFailedException(msg, e);
 116  0 logger.fatal(msg, tfe);
 117  0 throw tfe;
 118    } catch (MissingStdParameterException e) {
 119  0 String msg = "The test failed at run " + partialCount + " due to a MissingStdParameterException";
 120  0 TestFailedException tfe = new TestFailedException(msg, e);
 121  0 logger.fatal(msg, tfe);
 122  0 throw tfe;
 123    }
 124    }
 125   
 126    /**
 127    * This method is in charge of distributing to the set of configured JTR-nodes
 128    * the current test-configuration.
 129    *
 130    * @param tc The test-configuration to distribute
 131    */
 132  1 private void distributeTest(TestConfig tc) {
 133  1 Nodes nodes = tc.getNodes();
 134  1 if(nodes!=null) {
 135  1 logger.info("Distributing test to remote nodes...");
 136  1 List<Node> nodesList = nodes.getNodes();
 137  1 if(nodesList!=null && !nodesList.isEmpty()) {
 138  1 JtrRmiClassLoaderServerLauncher.launch();
 139  1 launchTestOutcomeCollector();
 140  1 remoteNodesNumber = nodesList.size();
 141  1 for(Node node : nodesList) {
 142  1 NodeInfo passiveNode = null;
 143  1 try {
 144  1 passiveNode = new NodeInfo(node.getHost(),node.getPort(),SystemProperties.TEST_GW_SERVICE_NAME);
 145  1 TestSender.sendTest(tc, passiveNode);
 146  1 testCompletionListener.addNode(passiveNode);
 147  1 logger.info("Test successfully sent to node "+node);
 148    } catch(TestSender.TestSenderException e) {
 149  0 String msg = "Unable to send test configuration to node "+node+" due to the following error:\n"+e;
 150  0 logger.error(msg,e);
 151  0 DistributionError error = new DistributionError(passiveNode,e);
 152  0 testOutcomeTable.addDistributionError(error);
 153    }
 154    }
 155    } else {
 156  0 logger.info("Any remote JTR node has been configured, the test is going to be lauched only locally");
 157    }
 158    }
 159    }
 160   
 161    /**
 162    * This method locally launches the default RMI-based implementation of the <i>TestOutcomeCollector</i>
 163    * service.
 164    */
 165  1 private void launchTestOutcomeCollector() {
 166  1 String host = System.getProperty(RMI_REGISTRY_HOST, DEF_RMI_REGISTRY_HOST);
 167  1 int port = new Integer(System.getProperty(RMI_REGISTRY_PORT, DEF_RMI_REGISTRY_PORT.toString()));
 168   
 169  1 Registry registry = RmiUtil.launchRegistry(host,port);
 170  1 TestOutcomeCollector collector = (TestOutcomeCollector) RmiUtil.registerService(registry,TestOutcomeCollectorImpl.class,TEST_OUTCOME_COLLECTOR_SERVICE_NAME);
 171   
 172  1 ((TestOutcomeCollectorImpl)collector).setRemoteTestCompletionListener(testCompletionListener);
 173   
 174  1 logger.info(TEST_OUTCOME_COLLECTOR_SERVICE_NAME+" launched");
 175  1 RmiUtil.logRegistryContent(registry);
 176    }
 177   
 178    /**
 179    * Initialize the pool of <code>IRunner</code>s.
 180    *
 181    * @param testConfig
 182    * The test configuration
 183    * @throws IRunnerCreationException
 184    * @throws UnknownAssignmentPolicyException
 185    * @return RunnerPool The pool of <code>IRunnerPooled</code>
 186    */
 187  1 protected RunnerPool initializePool(TestConfig testConfig, ITestCompletionListener testCmplLsnr) throws IRunnerCreationException, UnknownAssignmentPolicyException {
 188  1 RunnerPool pool = new RunnerPool(this);
 189  1 logger.debug("Pool of IRunners created...");
 190  1 RunnerPoolFiller.fillPool(testConfig, pool, testCmplLsnr);
 191  1 logger.debug("... and filled in");
 192  1 return pool;
 193    }
 194   
 195    /**
 196    * Starts all the <code>IRunner</code>s for the current epoch of the
 197    * current test
 198    */
 199  50 protected synchronized void startThreads() {
 200  50 logger.info("Starting run # " + partialCount);
 201  50 logger.info("ThreadGroup " + runnersThreadGroup.getName() + " active-threads count before run " + partialCount + " is: " + runnersThreadGroup.activeCount());
 202   
 203  50 IRunnerPooled[] runners = pool.removeAll();
 204  50 for (int i = 0; i < runners.length; i++) {
 205    /**
 206    * @todo TO BE IMPROVED!
 207    */
 208  2450 if (partialCount == 0) {
 209  49 runners[i].setTestOutcomeTable(testOutcomeTable);
 210  49 logger.info("Set outcomeTable for IRunner " + runners[i].getName());
 211    }
 212  2450 runners[i].setEpoch(partialCount);
 213  2450 Thread thRunner = new Thread(runnersThreadGroup, runners[i], runners[i].getName());
 214  2450 thRunner.start();
 215  2450 logger.debug("Created & started thread [" + i + "] " + thRunner.getName());
 216    }
 217   
 218  50 updateLocalEpochsFeedBack();
 219   
 220  50 logger.debug("ThreadGroup " + runnersThreadGroup.getName() + " active-threads count after starting run " + partialCount + " is: " + runnersThreadGroup.activeCount());
 221  50 partialCount++;
 222  50 runners = null;
 223    }
 224   
 225    /**
 226    * Once an <code>IRunner</code> has consumed its runs for a given epoch it
 227    * has to be put back into the pool waiting for the next epoch to come. <br>
 228    * Before being added to the pool it has to be reinitialized according to
 229    * what has been specified inside the <code>jtr.xml</code> configuration
 230    * file. <br>
 231    * Once all the <code>IRunner</code>s are back into the pool, the test
 232    * will start againg until the last epoch is reached.
 233    *
 234    * @param pRunner
 235    * The <code>IRunner</code> to be put back into the pool
 236    */
 237  2450 public synchronized void backIntoPool(IRunnerParameterized pRunner) {
 238  2450 if (partialCount < epochs) {
 239    // we have (epochs-partialCount) epochs left...
 240  2401 synchronized (pool) {
 241  2401 logger.debug("Received a request for putting an IRunner back into the pool for the next global run");
 242  2401 pool.add(handleReinitialization(pRunner));
 243  2401 logger.debug("Put back into the pool");
 244  2401 if (pool.size() == initialPoolSize) {
 245    // all the irunner-threads are back into the pool, let's
 246    // start the new epoch
 247  49 logger.info("Pool size has grown to " + initialPoolSize + " (the initial pool size)" + "Total run number not reached yet (" + partialCount + " of " + epochs
 248    + "): starting the next one...");
 249  49 startThreads();
 250    }
 251    }
 252    } else {
 253    // epochs are over
 254    // let's put the runner back into the pool without reinitializing
 255    // its parameters
 256  49 pool.add(pRunner);
 257  49 if (++completedRunners != initialPoolSize) {
 258  48 logger.info("Total run number reached (" + partialCount + " of " + epochs + "). Test not completed: " + completedRunners + "/" + initialPoolSize
 259    + " threads are back into the pool, waiting for other " + (initialPoolSize - completedRunners) + " threads");
 260    } else {
 261  1 testOutcomeTable.setEndTime();
 262  1 logger.info("Total run number reached (" + partialCount + " of " + epochs + "): test completed!\n\n");
 263  1 testCompletionListener.notifyTestCompletion(NodeInfo.newLocalNodeInfo(),testOutcomeTable);
 264  1 disposeResources();
 265    }
 266    }
 267    }
 268   
 269    /**
 270    * The reinitialization of an <code>IRunnerParameterized</code> is
 271    * delegated to its associated <code>IParamsAssigner</code>.
 272    *
 273    * @param pRunner
 274    * IRunnerParameterized
 275    * @return IRunnerParameterized
 276    */
 277  4802 protected IRunnerParameterized handleReinitialization(IRunnerParameterized pRunner) {
 278  4802 if (pRunner.getParamsAssigner().requiresReinitialization()) {
 279  1470 logger.debug("Reinitialization required");
 280  1470 return pRunner.clean().getParamsAssigner().backToFirstAssignment(pRunner);
 281    } else {
 282  3332 return (IRunnerParameterized) pRunner;
 283    }
 284    }
 285   
 286  2 protected void disposeResources() {
 287  2 IRunnerPooled[] runners = pool.removeAll();
 288  2 for (int i = 0; i < runners.length; i++) {
 289  98 logger.debug("Cleaning up resources held by runner " + runners[i].getName() + "...");
 290  98 runners[i].cleanupResources();
 291  98 logger.debug("... done");
 292    }
 293    }
 294   
 295    /**
 296    * This method tells the current <code>ITestCompletionListener</code> to show
 297    * to the user a feedback about the execution of the test
 298    */
 299  1 private void provideFeedBack() {
 300  1 testCompletionListener.provideFeedback(epochs, remoteNodesNumber, testConfig.getOverallRuns());
 301    }
 302   
 303    /**
 304    * This method updates the feedback provided to the user.
 305    */
 306  50 private void updateLocalEpochsFeedBack() {
 307  50 testCompletionListener.updateLocalEpochs(partialCount+1);
 308    }
 309   
 310    protected TestConfig testConfig;
 311    protected ThreadGroup runnersThreadGroup;
 312    protected String TH_GRP_NAME = "JTR-TestThreadGroup";
 313    protected RunnerPool pool;
 314    protected int initialPoolSize;
 315    // number of epochs
 316    protected int epochs;
 317    // current epoch
 318    protected int partialCount = 0;
 319    protected int completedRunners = 0;
 320    protected TestOutcomeTable testOutcomeTable;
 321    protected static Logger logger = Logger.getLogger(TestRunManager.class);
 322    private ITestCompletionListener testCompletionListener;
 323    private TestRunningFrame feedbacker;
 324    private int remoteNodesNumber;
 325    }