com.canoo.webtest.extension.ScriptStep.java Source code

Java tutorial

Introduction

Here is the source code for com.canoo.webtest.extension.ScriptStep.java

Source

// Copyright  2004-2005 ASERT. Released under the Canoo Webtest license.
package com.canoo.webtest.extension;

import java.io.File;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.Project;

import com.canoo.webtest.boundary.ResetScriptRunner;
import com.canoo.webtest.engine.Context;
import com.canoo.webtest.engine.StepExecutionException;
import com.canoo.webtest.engine.StepFailedException;
import com.canoo.webtest.steps.Step;
import com.canoo.webtest.util.ConversionUtil;
import com.canoo.webtest.util.FileUtil;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import com.gargoylesoftware.htmlunit.xml.XmlPage;

/**
 * Wrapper class for the ant script command.<p>
 *
 * @author Paul King
 * @webtest.step
 *    category="Extension"
 *    name="scriptStep"
 *    description="Provides the ability to use scripting code in your tests."
 */
public class ScriptStep extends Step {
    private static final Logger LOG = Logger.getLogger(ScriptStep.class);
    private String fLanguage;
    private String fKeep;
    private File fSrc;
    private String fScriptText = "";

    /**
     * Perform the step's actual work.
     *
     * @throws Exception if a problem occurred
     */
    public void doExecute() throws Exception {
        final ResetScriptRunner runner; // delegate pattern
        final Context context = getContext();
        if (context.getRunner() == null) {
            runner = new ResetScriptRunner();
            runner.setLanguage(getLanguage());
            context.setRunner(runner);
            LOG.debug("Creating new Script Runner with language: " + fLanguage);
        } else {
            runner = context.getRunner();
            runner.reset();
        }
        buildScript();
        getProject().addReference("step", this);
        if (context.getCurrentResponse() == null) {
            LOG.warn("No response found. Previous invoke missing? Related scripting variables not created");
        } else {
            setupResponseScriptingVariables(context);
        }

        try {
            executeByRunner(runner, getProject().replaceProperties(fScriptText), this, getProject());
            // languages like groovy can throw assert errors which are useful to fail test
            // but what about an assert in groovy's implementation that has failed - this should
            // probably be configurable to potentially throw StepExecutionError
        } catch (AssertionError ae) {
            final String msg = "Assertion error during scriptStep: " + ae.getMessage();
            LOG.debug(msg, ae);
            throw new StepFailedException(msg, this);
        } catch (BuildException be) {
            LOG.debug(be.getMessage(), be);
            throw new StepExecutionException("Error invoking script: " + be.getMessage(), this);
        } finally {
            if (!isKeep()) {
                context.setRunner(null);
            }
        }
    }

    public static String evalScriptExpression(final Context context, final String expression, final Step step) {
        final ResetScriptRunner runner = context.getRunner();
        if (runner == null) {
            throw new StepExecutionException(
                    "Can't evaluate script property because no previous <scriptStep> with keep=true.", step);
        }
        runner.reset();
        try {
            return evalByRunner(runner, expression, step);
        } catch (BuildException be) {
            throw new StepExecutionException("Error invoking script: " + be.getMessage(), step);
        }
    }

    public static void executeByRunner(final ResetScriptRunner runner, final String script, final Step step,
            final Project project) throws BuildException {
        runner.addText(script);
        runner.addBeans(project.getProperties());
        runner.addBeans(project.getUserProperties());
        runner.addBeans(project.getTargets());
        runner.addBeans(project.getReferences());
        runner.addBean("project", project);
        runner.addBean("self", step);
        runner.executeScript("WebTest");
    }

    public static String evalByRunner(final ResetScriptRunner runner, final String script, final Step step)
            throws BuildException {
        runner.addText(script);
        runner.addBean("self", step);
        return runner.evalScript("WebTest");
    }

    private void buildScript() {
        if (fSrc != null) {
            fScriptText += FileUtil.readFileToString(fSrc, this);
        }
    }

    private void setupResponseScriptingVariables(final Context context) {
        getProject().addReference("response", context.getCurrentResponse().getWebResponse());
        if (context.getCurrentResponse() instanceof HtmlPage) {
            getProject().addReference("document", ((HtmlPage) context.getCurrentResponse()).getDocumentElement());
        } else if (context.getCurrentResponse() instanceof XmlPage) {
            getProject().addReference("document", ((XmlPage) context.getCurrentResponse()).getXmlDocument());
        }
    }

    /**
     * Verify that language is set
     *
     * @throws StepExecutionException if a mandatory attribute is not set
     */
    protected void verifyParameters() {
        super.verifyParameters();
        final ResetScriptRunner runner = getContext().getRunner();
        if (runner == null) {
            emptyParamCheck(fLanguage, "language");
        } else {
            paramCheck(fLanguage != null && !fLanguage.equals(runner.getLanguage()),
                    "You may not change 'language' to '" + fLanguage
                            + "' after previously using the 'keep' attribute (was: " + runner.getLanguage() + ")");
        }
        paramCheck(fSrc == null && StringUtils.isEmpty(fScriptText),
                "Either \"src\" attribute or nested script text must be given.");
    }

    /**
     * override to add actual attribute values to the reporting
     */
    protected void addComputedParameters(final Map map) {
        map.put("language", fLanguage); // cannot be null (mandatory)
        if (fSrc == null) {
            map.put("script", fScriptText);
        } else {
            map.put("src", fSrc); // (optional)
        }
    }

    /**
     * Defines the language (required).
     *
     * @param language Sets the scripting language.
     * @webtest.parameter
     *     required="yes/no"
     *   description="The scripting language to use. Required unless using the <em>keep</em> attribute in which case the value is optional but must agree with the original language if used. The value can be any language supported by the <key>BSF</key>, e.g. javascript, jacl, netrexx, java, javaclass, bml, vbscript, jscript, perlscript, perl, jpython, jython, lotusscript, xslt, pnuts, beanbasic, beanshell, ruby, judoscript, groovy."
     */
    public void setLanguage(final String language) {
        fLanguage = language;
    }

    public String getLanguage() {
        return fLanguage;
    }

    /**
     * Defines the src file containing scripting code (optional).
     *
     * @param fileName Sets the name of the file containing script code.
     * @webtest.parameter
     *    required="yes/no"
     *  description="The name of the file containing the scripting code. You may omit this parameter if you have embedded script code."
     */
    public void setSrc(final File fileName) {
        fSrc = fileName;
    }

    public File getSrc() {
        return fSrc;
    }

    /**
     * Flag to indicate that the scripting engine should be kept after the step completes and re-used for future script steps.
     *
     * @param keep Indicates that the script engine should be kept for future steps.
     * @webtest.parameter
     *     required="no"
     *   default="false"
     *   description="Indicates that the script engine should be kept for future steps. Variables created during one script step will remain available."
     */
    public void setKeep(final String keep) {
        fKeep = keep;
    }

    public String getKeep() {
        return fKeep;
    }

    public boolean isKeep() {
        return ConversionUtil.convertToBoolean(fKeep, false);
    }

    /**
     * The script text if inlined.
     *
     * @param text The nested scripting code.
      * @webtest.nested.parameter
      *    required="yes/no"
      *    description="The nested script code. You may omit this if you use the parameter src."
      */
    public void addText(final String text) {
        fScriptText += text;
    }

}