/* * Created on 11/06/2006 * * Copyright 2005-2010 Ignis Software Tools Ltd. All rights reserved. */ package jsystem.runner.remote; import java.io.File; import java.io.FileOutputStream; import java.util.Properties; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JOptionPane; import jsystem.framework.FrameworkOptions; import jsystem.framework.JSystemProperties; import jsystem.framework.RunProperties; import jsystem.framework.GeneralEnums.RunMode; import jsystem.framework.report.ExecutionListener; import jsystem.framework.report.JSystemListeners; import jsystem.framework.report.ListenerstManager; import jsystem.framework.report.RunnerListenersManager; import jsystem.framework.report.TestInfo; import jsystem.framework.scenario.JTest; import jsystem.framework.scenario.JTestContainer; import jsystem.framework.scenario.RunnerFixture; import jsystem.framework.scenario.RunnerTest; import jsystem.framework.scenario.RunningProperties; import jsystem.framework.scenario.Scenario; import jsystem.framework.scenario.ScenarioHelpers; import jsystem.framework.scenario.ScenariosManager; import jsystem.framework.scenario.flow_control.AntForLoop; import jsystem.runner.ErrorLevel; import junit.framework.AssertionFailedError; import junit.framework.Test; public class ScenarioExecutor implements ExecutionListener { /** * signals if current run should stop */ volatile private boolean stop = false; volatile private boolean paused = false; volatile boolean runEnd = false; volatile private boolean remoteExit = false; volatile private boolean running = false; private RunMode executeMode = RunMode.DROP_EVERY_RUN; private String scenarioFile = null; private RemoteExecutor executor; private JSystemListeners executionListener; /** * is the execution marked as repeat */ volatile private boolean isRepeat; /** * the amount of loops for the current run, 0 is loop forever */ volatile private int repeatNumber; /** * the amount of loops remaining for current execution */ volatile private int repeatLeftNumber; /** * signals if a test was started in current execution */ volatile private boolean testStarted; private static Logger log = Logger.getLogger(ScenarioExecutor.class.getName()); public ScenarioExecutor() { } /** * Executes test/scenario with UUID <code>uuid</code> in the context of the current scenario.<br> * In case that <code>uuid</code> points to a scenario, the scenario is executed in run.mode 1. */ public void execute(String uuid) throws Exception { JTest test = ScenarioHelpers.getTestById(ScenariosManager.getInstance().getCurrentScenario(),uuid); if (test == null){ throw new Exception("Test with id " + uuid + " was not found in the system"); } if (test.getParent() == null){ throw new Exception("Only internal tests/scenarios can be executed with this method"); } executionListener = RunnerListenersManager.getInstance(); createEmptyPropsFile(); executor = null; if ("false".equalsIgnoreCase(JSystemProperties.getInstance().getPreference(FrameworkOptions.SAVE_RUN_PROPERTIES))) { RunProperties.getInstance().resetRunProperties(); } try { Properties commandProps = new Properties(); Scenario scenario; if (test instanceof Scenario){ scenario = test.getParent().getMyScenario(); }else { scenario = test.getMyScenario(); } commandProps.setProperty(RunningProperties.UUID_PARENT_TAG, scenario.getParentFullUUID()); commandProps.setProperty(RunningProperties.UUID_TAG, scenario.getUUID()); commandProps.setProperty(RunningProperties.PARENT_NAME, ScenarioHelpers.buildFullPathName(scenario.getParent())); getExecutor().run(scenario.getScenarioFile().getAbsolutePath(), new String[] { test.getTestId() }, commandProps); waitForRunEnd(); getExecutor().exit(); waitForRemoteExit(); }finally{ cycleEnded(); executionEnded(); } } /*************************************************************************** * * Methods called by UI * */ public void execute() throws Exception { executionListener = RunnerListenersManager.getInstance(); parseRunMode(); createEmptyPropsFile(); executor = null; scenarioFile = ScenariosManager.getInstance().getCurrentScenario().getScenarioFile().getAbsolutePath(); log.log(Level.INFO, "Execute count: " + ScenariosManager.getInstance().getCurrentScenario().countTestCases()); setRepeatLeftNumber(getRepeatNumber()); testStarted = false; try { while (true) { // deleting run.properties file before a new cycle. if ("false".equalsIgnoreCase(JSystemProperties.getInstance().getPreference(FrameworkOptions.SAVE_RUN_PROPERTIES))) { RunProperties.getInstance().resetRunProperties(); } runRound(); cycleEnded(); if (stop) { return; } if (getRepeatNumber() == 0 && isRepeat()) { continue; } if (!(getRepeatLeftNumber() > 0) || !isRepeat()) { break; } } } finally { executionEnded(); if (!testStarted && !stop){ ListenerstManager.getInstance().showConfirmDialog("No tests were executed!", "There was an error with the tests execution.\n please look at the JSystem console for more info.", JOptionPane.CLOSED_OPTION, JOptionPane.WARNING_MESSAGE); } } } public synchronized void pause() throws Exception { if (!running) { return; } paused = true; ((RunnerListenersManager)RunnerListenersManager.getInstance()).flushReporters(); getExecutor().pause(); } public synchronized void gracefulStop(){ if(!running){ return; } stop = true; if (!runEnd) { if(executor != null){ executor.gracefulStop(); } } runEnd = true; } public synchronized void stop() throws Exception { if (!running) { return; } stop = true; if (getExecutor() != null) { getExecutor().interruptTest(); } try { Thread.sleep(500); } catch (InterruptedException e) { // ignored } ListenerstManager.getInstance().report("The test was interrupted by the user", false); ListenerstManager.getInstance().endTest(null); remoteExit = true; runEnd = true; notifyAll(); } public synchronized void resume() throws Exception { paused = false; getExecutor().resume(); } /** * ********************************************************************************8 * * Methods called by remote executor * */ public synchronized void endRun() { /* * If the run ended and the pause was pressed set the gui to running */ if (paused) { paused = false; } runEnd = true; notifyAll(); } /** * */ public synchronized void remoteExit() { remoteExit = true; notifyAll(); } public synchronized void executionEnded(String scenarioName) { remoteExit = true; notifyAll(); executionListener.executionEnded(scenarioName); } /** * update repeat counter and signal run end (cycle end) to execution listener */ private void cycleEnded() { executionListener.endRun(); repeatLeftNumber--; } /** * reset repeat counter, signal to execution listener that execution ended */ private void executionEnded() { setRepeat(false); setRepeatNumber(0); executionListener.executionEnded(ScenariosManager.getInstance().getCurrentScenario().getName()); } /** * Runs a round of the current scenario. Please read the documentation of * RunnerTest.getPropertiesInAntCanonicalFormat to understand how test * parameters are passed to the tests and to understand the differences * between the run modes */ private void runRound() throws Exception { stop = false; paused = false; int[] testsIndexes; switch (executeMode) { case DROP_EVERY_RUN: getExecutor().run(scenarioFile, null, null); waitForRunEnd(); getExecutor().exit(); waitForRemoteExit(); break; case DROP_EVERY_TEST: // TODO: Ant flow control won't work ! testsIndexes = ScenariosManager.getInstance().getCurrentScenario().getEnabledTestsIndexes(); Scenario currentScenario = ScenariosManager.getInstance().getCurrentScenario(); for (int i = 0; i < testsIndexes.length; i++) { RunnerTest test = currentScenario.getTest(testsIndexes[i]); if (test instanceof RunnerFixture) { continue; } Properties commandProps = new Properties(); Scenario scenario = (Scenario)test.getParent(); commandProps.setProperty(RunningProperties.UUID_PARENT_TAG, scenario.getParentFullUUID()); commandProps.setProperty(RunningProperties.UUID_TAG, scenario.getUUID()); commandProps.setProperty(RunningProperties.PARENT_NAME, ScenarioHelpers.buildFullPathName(scenario.getParent())); try { getExecutor().run(scenario.getScenarioFile().getAbsolutePath(), new String[] { test.getTestId() }, commandProps); waitForRunEnd(); getExecutor().exit(); waitForRemoteExit(); } finally { } if (stop) { return; } } break; case DROP_EVERY_SCENARIO: /* * get all the tests indexes to execute */ testsIndexes = ScenariosManager.getInstance().getCurrentScenario().getEnabledTestsIndexes(); int i = 0; Scenario curreScenario = null; while (i != testsIndexes.length) { /* * Get the scenario of the first test in the list */ RunnerTest startTest = ScenariosManager.getInstance().getCurrentScenario().getTest(testsIndexes[i]); curreScenario = ScenarioHelpers.getFirstScenarioAncestor(startTest); StringBuffer testsToRun = new StringBuffer(); Properties props = new Properties(); for (; i < testsIndexes.length; i++) { RunnerTest test = ScenariosManager.getInstance().getCurrentScenario().getTest(testsIndexes[i]); /* * As long as the test scenario is the same as the first * test add it to the list of tests to run. */ if (test.getParent().equals(curreScenario)) { if (testsToRun.length() > 0) { testsToRun.append(','); } testsToRun.append(test.getTestId()); props.putAll(test.getPropertiesInAntCanonicalFormat()); } else { break; } } Properties commandProps = new Properties(); commandProps.setProperty(RunningProperties.UUID_PARENT_TAG, curreScenario.getParentFullUUID()); commandProps.setProperty(RunningProperties.UUID_TAG, curreScenario.getUUID()); commandProps.setProperty(RunningProperties.PARENT_NAME, ScenarioHelpers.buildFullPathName(curreScenario.getParent())); /* * Execute tests if tests were found */ if (testsToRun.length() > 0) { try { /* * execute the sub scenario */ getExecutor().run(curreScenario.getScenarioFile().getAbsolutePath(), testsToRun.toString().split(","), commandProps); waitForRunEnd(); getExecutor().exit(); waitForRemoteExit(); } finally { } if (stop) { return; } } } } } private synchronized RemoteExecutor getExecutor() { if (executor == null) { executor = new RemoteExecutorImpl(); executor.setRunEndListener(this); } return executor; } private synchronized void waitForRunEnd() { running = true; runEnd = false; while (!runEnd) { try { wait(); } catch (InterruptedException e) { // ignored } } runEnd = false; running = false; } private synchronized void waitForRemoteExit() { while (!remoteExit) { try { wait(); } catch (InterruptedException e) { // ignroed } } remoteExit = false; testStarted = testStarted || executor.isTestStarted(); executor = null; } /*************************************************************************** * Methods for creating tests parameters properties file Please read * runRound doc. */ @SuppressWarnings("unused") private File saveTestsPropertiesToPropertyFile(Properties props) throws Exception { File file = generatePropertiesFileName(); FileOutputStream outStream = new FileOutputStream(file); try { props.store(outStream, "tests parameters file"); } finally { outStream.close(); } return file; } @SuppressWarnings("unused") private Properties createCommandProps(File file) { Properties commandProps = new Properties(); commandProps.put(RunningProperties.TEST_PARAMETERS_FILE_NAME_PARAMETER, file.getName()); return commandProps; } private File generatePropertiesFileName() { File f = new File(RunningProperties.TEST_PARAMETERS_FILE_NAME_PREFIX + System.currentTimeMillis() + ".properties"); int i = 0; while (f.exists()) { f = new File(RunningProperties.TEST_PARAMETERS_FILE_NAME_PREFIX + System.currentTimeMillis() + i + ".properties"); i++; } return f; } /** * Creates an empty test parameters properties file. please read * Scenario class documentation */ private void createEmptyPropsFile() { File f = new File(RunningProperties.TEST_PARAMETERS_EMPTY_FILE); try { f.createNewFile(); } catch (Exception e) { log.warning("Failed creating empty properties file for tests parameters" + e.getMessage()); } } /** * print the current run mode to the logger */ private void parseRunMode() { String runMode = JSystemProperties.getInstance().getPreference(FrameworkOptions.RUN_MODE); if (runMode != null) { try { executeMode = RunMode.valueOf(runMode.toUpperCase()); } catch (Exception ex) { try{ // backward compatibility and users who are used to old system int runModeAsNumber = Integer.parseInt(runMode); executeMode = RunMode.enumFromNum(runModeAsNumber); }catch (NumberFormatException e) { JSystemProperties.getInstance().setPreference(FrameworkOptions.RUN_MODE,RunMode.DROP_EVERY_RUN.toString()); log.warning("Found incompetible value in Run Mode, replaced to "+RunMode.DROP_EVERY_RUN); } } if (executeMode == null) { executeMode = RunMode.DROP_EVERY_RUN; } } log.log(Level.INFO, "Execute mode: "); log.log(Level.INFO, executeMode.toString()); } public void startTest(Test test) { // ignored } public void addWarning(Test test) { // ignored } public void startTest(TestInfo testinfo) { // ignored } public void addError(Test test, Throwable t) { // ignored } public void addFailure(Test test, AssertionFailedError t) { // ignored } public synchronized void endTest(Test test) { // ignored } public boolean isRepeat() { return isRepeat; } public void setRepeat(boolean isRepeat) { this.isRepeat = isRepeat; } public int getRepeatLeftNumber() { return repeatLeftNumber; } public void setRepeatLeftNumber(int repeatLeftNumber) { this.repeatLeftNumber = repeatLeftNumber; } public int getRepeatNumber() { return repeatNumber; } public void setRepeatNumber(int repeatNumber) { this.repeatNumber = repeatNumber; } public void errorOccured(String title, String message, ErrorLevel level) { executionListener.errorOccured(title, message, level); } public void remotePause() { executionListener.remotePause(); } @Override public void endContainer(JTestContainer container) { // TODO Auto-generated method stub } @Override public void endLoop(AntForLoop loop, int count) { // TODO Auto-generated method stub } @Override public void startContainer(JTestContainer container) { // TODO Auto-generated method stub } @Override public void startLoop(AntForLoop loop, int count) { // TODO Auto-generated method stub } }