package com.github.markusbernhardt.selenium2library.keywords; import org.python.util.PythonInterpreter; import org.robotframework.javalib.annotation.ArgumentNames; import org.robotframework.javalib.annotation.Autowired; import org.robotframework.javalib.annotation.RobotKeyword; import org.robotframework.javalib.annotation.RobotKeywords; import com.github.markusbernhardt.selenium2library.RunOnFailureKeywordsAdapter; @RobotKeywords public class RunOnFailure extends RunOnFailureKeywordsAdapter { /** * The keyword to run an failure */ protected String runOnFailureKeyword = "Capture Page Screenshot"; /** * Only run keyword on failure if true */ protected boolean runningOnFailureRoutine; /** * Instantiated Logging keyword bean */ @Autowired protected Logging logging; // ############################## // Keywords // ############################## /** * Sets the actual and returns the previous keyword to execute when a * Selenium2Library keyword fails.<br> * <br> * The <b>keyword</b> is the name of a keyword (from any available * libraries) that will be executed, if a Selenium2Library keyword fails. It * is not possible to use a keyword that requires arguments. Using the value * <b>Nothing</b> will disable this feature altogether.<br> * <br> * The initial keyword to use is set at importing the library and the * keyword that is used by default is `Capture Page Screenshot`. Taking a * screenshot when something failed is a very useful feature, but notice * that it can slow down the execution.<br> * <br> * This keyword returns the name of the previously registered failure * keyword. It can be used to restore the original value later.<br> * <br> * Example: * <table border="1" cellspacing="0" summary=""> * <tr> * <td>Register Keyword To Run On Failure</td> * <td>Log Source</td> * <td></td> * <td># Run `Log Source` on failure.</td> * </tr> * <tr> * <td>${previous kw}=</td> * <td>Register Keyword To Run On Failure</td> * <td>Nothing</td> * <td># Disable run-on-failure functionality and stors the previous kw name * in a variable.</td> * </tr> * <tr> * <td>Register Keyword To Run On Failure</td> * <td>${previous kw}</td> * <td></td> * <td># Restore to the previous keyword.</td> * </tr> * </table> * * @param keyword * The keyword to execute on failure * @return The previous keyword */ @RobotKeyword @ArgumentNames({ "keyword" }) public String registerKeywordToRunOnFailure(String keyword) { String oldKeyword = runOnFailureKeyword; String oldKeywordText = oldKeyword != null ? oldKeyword : "No keyword"; String newKeyword = !keyword.trim().toLowerCase().equals("nothing") ? keyword : null; String newKeywordText = newKeyword != null ? newKeyword : "No keyword"; runOnFailureKeyword = newKeyword; logging.info(String.format("%s will be run on failure.", newKeywordText)); return oldKeywordText; } // ############################## // Internal Methods // ############################## protected static ThreadLocal<PythonInterpreter> runOnFailurePythonInterpreter = new ThreadLocal<PythonInterpreter>() { @Override protected PythonInterpreter initialValue() { PythonInterpreter pythonInterpreter = new PythonInterpreter(); pythonInterpreter.exec("from robot.libraries.BuiltIn import BuiltIn; from robot.running.context import EXECUTION_CONTEXTS; BIN = BuiltIn();"); return pythonInterpreter; } }; public void runOnFailure() { if (runOnFailureKeyword == null) { return; } if (runningOnFailureRoutine) { return; } if(runOnFailurePythonInterpreter.get().eval("EXECUTION_CONTEXTS.current").toString().equals("None")) { return; } try { runOnFailurePythonInterpreter.get().exec( String.format("BIN.run_keyword('%s')", runOnFailureKeyword.replace("'", "\\'").replace("\n", "\\n"))); } catch (RuntimeException r) { logging.warn(String.format("Keyword '%s' could not be run on failure%s", runOnFailureKeyword, r.getMessage() != null ? " '" + r.getMessage() + "'" : "")); } finally { runningOnFailureRoutine = false; } } }