All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.thucydides.core.steps.StepEventBus Maven / Gradle / Ivy

There is a newer version: 0.9.275
Show newest version
package net.thucydides.core.steps;

import com.google.common.collect.ImmutableList;
import com.google.inject.internal.Lists;
import net.thucydides.core.model.Story;
import sun.misc.Service;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.Stack;

/**
 * An event bus for Step-related notifications.
 * Use this to integrate Thucydides listeners with testing tools.
 * You create a listener (e.g. an instance of BaseStepListener, or your own), register it using
 * 'registerListener', and then implement the various methods (testStarted(), stepStarted()). Thucydides
 * will call these events on your listener as they occur.
 *
 * You can register a new Thucydides listener by implementing the StepListener interface and
 * placing your class in the classpath. Thucydides will automatically detect the listener and add it to the
 * registered listeners. It will load custom listeners automatically when a test starts for the first time.
 *
 */
public class StepEventBus {

    private static ThreadLocal stepEventBusThreadLocal = new ThreadLocal();
    private static final String CORE_THUCYDIDES_PACKAGE = "net.thucydides.core";

    /**
     * The event bus used to inform listening classes about when tests and test steps start and finish.
     */
    public static StepEventBus getEventBus() {
        if (stepEventBusThreadLocal.get() == null) {
            stepEventBusThreadLocal.set(new StepEventBus());
        }
        return stepEventBusThreadLocal.get();
    }

    //private static Iterator listenerImplementations = Service.providers(StepListener.class);

    private List registeredListeners = new ArrayList();

    private TestStepResult resultTally;

    private Stack stepStack = new Stack();
    private Stack webdriverSuspensions = new Stack();

    private Set customListeners;

    private boolean stepFailed;

    private boolean pendingTest;

    /**
     * Register a listener to receive notification at different points during a test's execution.
     * If you are writing your own listener, you shouldn't need to call this method - just set up your
     * listener implementation as a service (see http://download.oracle.com/javase/6/docs/api/java/util/ServiceLoader.html),
     * place the listener class on the classpath and it will be detected automatically.
     */
    public StepEventBus registerListener(final StepListener listener) {
        registeredListeners.add(listener);
        return this;
    }

    public void testStarted(final String testName) {

        clear();

        for(StepListener stepListener : getAllListeners()) {
            stepListener.testStarted(testName);
        }
    }

    protected List getAllListeners() {
        List allListeners = Lists.newArrayList(registeredListeners);
        allListeners.addAll(getCustomListeners());
        return ImmutableList.copyOf(allListeners);
    }

    private Set getCustomListeners() {

        if (customListeners == null) {
            customListeners = Collections.synchronizedSet(new HashSet());
            Iterator listenerImplementations = Service.providers(StepListener.class);

            while (listenerImplementations.hasNext()) {
                StepListener listener = (StepListener) listenerImplementations.next();
                if (!isACore(listener)) {
                    customListeners.add(listener);
                }
            }
        }
        return customListeners;
    }

    private boolean isACore(final StepListener listener) {
        return listener.getClass().getPackage().getName().startsWith(CORE_THUCYDIDES_PACKAGE);
    }

    public void testSuiteStarted(final Class testClass) {
        for(StepListener stepListener : getAllListeners()) {
            stepListener.testSuiteStarted(testClass);
        }
    }

    public void testSuiteStarted(final Story story) {
        for(StepListener stepListener : getAllListeners()) {
            stepListener.testSuiteStarted(story);
        }
    }

    public void clear() {

        stepStack.clear();
        clearStepFailures();
        currentTestIsNotPending();
        this.resultTally = new TestStepResult();
        webdriverSuspensions.clear();
    }

    private void currentTestIsNotPending() {
        pendingTest = false;
    }

    private TestStepResult getResultTally() {
        if (resultTally == null) {
            resultTally = new TestStepResult();
        }
        return resultTally;
    }

    public void testFinished() {
        for(StepListener stepListener : getAllListeners()) {
            stepListener.testFinished(getResultTally());
        }
        clear();
    }

    private void pushStep(String stepName) {
        stepStack.push(stepName);
    }

    private void popStep() {
        stepStack.pop();
    }

    private void clearStepFailures() {
        stepFailed = false;
    }

    public boolean aStepInTheCurrentTestHasFailed() {
        return stepFailed;
    }

    public boolean isCurrentTestDataDriven() {
        return DataDrivenStep.inProgress();
    }

    public void stepStarted(final ExecutedStepDescription executedStepDescription) {

        pushStep(executedStepDescription.getName());

        for(StepListener stepListener : getAllListeners()) {
            stepListener.stepStarted(executedStepDescription);
        }
    }

    public void stepFinished() {
        stepDone();
        getResultTally().logExecutedTest();
        for(StepListener stepListener : getAllListeners()) {
            stepListener.stepFinished();
        }
    }

    private void stepDone() {
        popStep();
    }

    public void stepFailed(final StepFailure failure) {

        stepDone();
        getResultTally().logFailure(failure);

        for(StepListener stepListener : getAllListeners()) {
            stepListener.stepFailed(failure);
        }
        stepFailed = true;
    }

    public void stepIgnored() {

        stepDone();
        getResultTally().logIgnoredTest();

        for(StepListener stepListener : getAllListeners()) {
            stepListener.stepIgnored();
        }
    }

    public void stepPending() {

        stepDone();
        getResultTally().logIgnoredTest();

        for(StepListener stepListener : getAllListeners()) {
            stepListener.stepPending();
        }
    }

    public void dropListener(final StepListener stepListener) {
        registeredListeners.remove(stepListener);
    }

    public void dropAllListeners() {
        registeredListeners.clear();
    }

    public boolean webdriverCallsAreSuspended() {
        return aStepInTheCurrentTestHasFailed() || !webdriverSuspensions.isEmpty();
    }

    public void reenableWebdriverCalls() {
        webdriverSuspensions.pop();
    }

    public void temporarilySuspendWebdriverCalls() {
        webdriverSuspensions.push(true);
    }

    /**
     * The test failed, but not during the execution of a step.
     * @param cause the underlying cause of the failure.
     */
    public void testFailed(final Throwable cause) {
        for(StepListener stepListener : getAllListeners()) {
            stepListener.testFailed(cause);
        }
    }

    /**
     * Mark the current test method as pending.
     * The test will stil be executed to record the steps, but any webdriver calls will be skipped.
     */
    public void testPending() {
        pendingTest = true;
    }

    public boolean currentTestIsPending() {
        return pendingTest;
    }

    public void testIgnored() {
        for(StepListener stepListener : getAllListeners()) {
            stepListener.testIgnored();
        }
    }

    public boolean areStepsRunning() {
        return !stepStack.isEmpty();
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy