AbstractEmbedderMojo.java
- package org.jbehave.mojo;
- import static org.apache.commons.lang3.ArrayUtils.isNotEmpty;
- import java.io.File;
- import java.net.MalformedURLException;
- import java.net.URL;
- import java.util.ArrayList;
- import java.util.List;
- import java.util.Properties;
- import java.util.concurrent.ExecutorService;
- import org.apache.maven.plugin.AbstractMojo;
- import org.apache.maven.plugins.annotations.Parameter;
- import org.jbehave.core.ConfigurableEmbedder;
- import org.jbehave.core.InjectableEmbedder;
- import org.jbehave.core.embedder.Embedder;
- import org.jbehave.core.embedder.EmbedderClassLoader;
- import org.jbehave.core.embedder.EmbedderControls;
- import org.jbehave.core.embedder.EmbedderMonitor;
- import org.jbehave.core.embedder.MetaFilter;
- import org.jbehave.core.embedder.UnmodifiableEmbedderControls;
- import org.jbehave.core.embedder.executors.ExecutorServiceFactory;
- import org.jbehave.core.failures.BatchFailures;
- import org.jbehave.core.io.StoryFinder;
- import org.jbehave.core.model.Meta;
- import org.jbehave.core.model.Scenario;
- import org.jbehave.core.model.Story;
- import org.jbehave.core.model.StoryDuration;
- import org.jbehave.core.model.StoryMaps;
- import org.jbehave.core.reporters.ReportsCount;
- /**
- * Abstract mojo that holds all the configuration parameters to specify and load
- * stories.
- */
- public abstract class AbstractEmbedderMojo extends AbstractMojo {
- static final String TEST_SCOPE = "test";
- @Parameter(defaultValue = "${project.build.sourceDirectory}", required = true)
- String sourceDirectory;
- @Parameter(defaultValue = "${project.build.testSourceDirectory}", required = true)
- String testSourceDirectory;
- @Parameter(defaultValue = "${project.build.outputDirectory}", required = true)
- String outputDirectory;
- @Parameter(defaultValue = "${project.build.testOutputDirectory}", required = true)
- String testOutputDirectory;
- /**
- * The scope of the mojo classpath, either "compile" or "test"
- */
- @Parameter(defaultValue = "compile")
- String scope;
- /**
- * Include filters, relative to the root source directory determined by the
- * scope
- */
- @Parameter
- List<String> includes;
- /**
- * Exclude filters, relative to the root source directory determined by the
- * scope
- */
- @Parameter
- List<String> excludes;
- /**
- * Compile classpath.
- */
- @Parameter(defaultValue = "${project.compileClasspathElements}", required = true, readonly = true)
- List<String> compileClasspathElements;
- /**
- * Test classpath.
- */
- @Parameter(defaultValue = "${project.testClasspathElements}", required = true, readonly = true)
- List<String> testClasspathElements;
- /**
- * The boolean flag to skip stories
- */
- @Parameter(defaultValue = "false")
- boolean skip = false;
- /**
- * The boolean flag to run in batch mode
- */
- @Parameter(defaultValue = "false")
- boolean batch = false;
- /**
- * The boolean flag to ignore failure in stories
- */
- @Parameter(defaultValue = "false")
- boolean ignoreFailureInStories = false;
- /**
- * The boolean flag to ignore failure in view
- */
- @Parameter(defaultValue = "false")
- boolean ignoreFailureInView = false;
- /**
- * The boolean flag to generate view after stories are run
- */
- @Parameter(defaultValue = "true")
- boolean generateViewAfterStories = true;
- /**
- * The boolean flag to output failures in verbose mode
- */
- @Parameter(defaultValue = "false")
- boolean verboseFailures = false;
- /**
- * The boolean flag to output filtering in verbose mode
- */
- @Parameter(defaultValue = "false")
- boolean verboseFiltering = false;
- /**
- * The story timeouts
- */
- @Parameter
- String storyTimeouts;
- /**
- * The boolean flag to fail on story timeout
- */
- @Parameter(defaultValue = "false")
- boolean failOnStoryTimeout = false;
- /**
- * The number of threads
- */
- @Parameter(defaultValue = "1")
- int threads = 1;
- /**
- * The embedder class
- */
- @Parameter(defaultValue = "org.jbehave.core.embedder.Embedder")
- String embedderClass = Embedder.class.getName();
- /**
- * The implementation class of the {@link ExecutorServiceFactory}
- */
- @Parameter
- String executorsClass;
- /**
- * The class that is injected with the embedder
- */
- @Parameter
- String injectableEmbedderClass;
- /**
- * The story finder used to retrieve story paths and class names
- */
- @Parameter
- String storyFinderClass = StoryFinder.class.getName();
- /**
- * The meta filters
- */
- @Parameter
- String[] metaFilters;
- /**
- * The system properties
- */
- @Parameter
- Properties systemProperties = new Properties();
- /**
- * The class loader
- */
- private EmbedderClassLoader classLoader;
- /**
- * Determines if the scope of the mojo classpath is "test"
- *
- * @return A boolean <code>true</code> if test scoped
- */
- boolean isTestScope() {
- return TEST_SCOPE.equals(scope);
- }
- String searchDirectory() {
- if (isTestScope()) {
- return testSourceDirectory;
- }
- return sourceDirectory;
- }
- String outputDirectory() {
- if (isTestScope()) {
- return testOutputDirectory;
- }
- return outputDirectory;
- }
- URL codeLocation() {
- String outputDirectory = outputDirectory();
- try {
- return outputDirectory != null ? new File(outputDirectory).toURI().toURL() : null;
- } catch (MalformedURLException e) {
- throw new IllegalArgumentException("Failed to create code location from " + outputDirectory, e);
- }
- }
- /**
- * Returns the EmbedderClassLoader with the classpath element of the
- * selected scope.
- *
- * @return An EmbedderClassLoader
- */
- protected EmbedderClassLoader classLoader() {
- if (classLoader == null) {
- classLoader = new EmbedderClassLoader(classpathElements());
- }
- return classLoader;
- }
- List<String> classpathElements() {
- List<String> classpathElements = compileClasspathElements;
- if (isTestScope()) {
- classpathElements = testClasspathElements;
- }
- return classpathElements;
- }
- /**
- * Finds story paths, using the {@link #newStoryFinder()}, in the
- * {@link #searchDirectory()} given specified {@link #includes} and
- * {@link #excludes}.
- *
- * @return A List of story paths found
- */
- protected List<String> storyPaths() {
- getLog().debug("Searching for story paths including " + includes + " and excluding " + excludes);
- List<String> storyPaths = newStoryFinder().findPaths(searchDirectory(), includes, excludes);
- getLog().info("Found story paths: " + storyPaths);
- return storyPaths;
- }
- /**
- * Finds class names, using the {@link #newStoryFinder()}, in the
- * {@link #searchDirectory()} given specified {@link #includes} and
- * {@link #excludes}.
- *
- * @return A List of class names found
- */
- protected List<String> classNames() {
- getLog().debug("Searching for class names including " + includes + " and excluding " + excludes);
- List<String> classNames = newStoryFinder().findClassNames(searchDirectory(), includes, excludes);
- getLog().info("Found class names: " + classNames);
- return classNames;
- }
- /**
- * Creates an instance of StoryFinder, using the {@link #storyFinderClass}
- *
- * @return A StoryFinder
- */
- protected StoryFinder newStoryFinder() {
- return classLoader().newInstance(StoryFinder.class, storyFinderClass);
- }
- /**
- * Creates an instance of Embedder, either using
- * {@link #injectableEmbedderClass} (if set) or defaulting to
- * {@link #embedderClass}.
- *
- * @return An Embedder
- */
- protected Embedder newEmbedder() {
- Embedder embedder = null;
- EmbedderClassLoader classLoader = classLoader();
- if (injectableEmbedderClass != null) {
- embedder = classLoader.newInstance(InjectableEmbedder.class, injectableEmbedderClass).injectedEmbedder();
- } else {
- embedder = classLoader.newInstance(Embedder.class, embedderClass);
- }
-
- URL codeLocation = codeLocation();
- if (codeLocation != null) {
- embedder.configuration().storyReporterBuilder().withCodeLocation(codeLocation);
- }
- embedder.useClassLoader(classLoader);
- embedder.useEmbedderControls(embedderControls());
- if (executorsClass != null) {
- ExecutorServiceFactory executorServiceFactory = classLoader.newInstance(ExecutorServiceFactory.class,
- executorsClass);
- embedder.useExecutorService(executorServiceFactory.create(embedder.embedderControls()));
- }
- embedder.useEmbedderMonitor(embedderMonitor());
- if (isNotEmpty(metaFilters)) {
- List<String> filters = new ArrayList<>();
- for (String filter : metaFilters) {
- if (filter != null) {
- filters.add(filter);
- }
- }
- embedder.useMetaFilters(filters);
- }
- if (!systemProperties.isEmpty()) {
- embedder.useSystemProperties(systemProperties);
- }
- return embedder;
- }
- protected EmbedderMonitor embedderMonitor() {
- return new MavenEmbedderMonitor();
- }
- protected EmbedderControls embedderControls() {
- EmbedderControls embedderControls = new EmbedderControls().doBatch(batch).doSkip(skip)
- .doGenerateViewAfterStories(generateViewAfterStories).doIgnoreFailureInStories(ignoreFailureInStories)
- .doIgnoreFailureInView(ignoreFailureInView).doVerboseFailures(verboseFailures)
- .doVerboseFiltering(verboseFiltering)
- .doFailOnStoryTimeout(failOnStoryTimeout).useThreads(threads);
- if (storyTimeouts != null) {
- embedderControls.useStoryTimeouts(storyTimeouts);
- }
- return new UnmodifiableEmbedderControls(embedderControls);
- }
- protected class MavenEmbedderMonitor implements EmbedderMonitor {
- @Override
- public void batchFailed(BatchFailures failures) {
- getLog().warn("Failed to run batch " + failures);
- }
- @Override
- public void beforeOrAfterStoriesFailed() {
- getLog().warn("Failed to run before or after stories steps");
- }
- @Override
- public void embeddableFailed(String name, Throwable cause) {
- getLog().warn("Failed to run embeddable " + name, cause);
- }
- @Override
- public void embeddableNotConfigurable(String name) {
- getLog().warn("Embeddable " + name + " must be an instance of " + ConfigurableEmbedder.class);
- }
- @Override
- public void embeddablesSkipped(List<String> classNames) {
- getLog().info("Skipped embeddables " + classNames);
- }
- @Override
- public void metaExcluded(Meta meta, MetaFilter filter) {
- getLog().debug(meta + " excluded by filter '" + filter.asString() + "'");
- }
- @Override
- public void runningEmbeddable(String name) {
- getLog().info("Running embeddable " + name);
- }
- @Override
- public void runningStory(String path) {
- getLog().info("Running story " + path);
- }
- @Override
- public void storyFailed(String path, Throwable cause) {
- getLog().warn("Failed to run story " + path, cause);
- }
- @Override
- public void storiesSkipped(List<String> storyPaths) {
- getLog().info("Skipped stories " + storyPaths);
- }
- @Override
- public void storiesExcluded(List<Story> excluded, MetaFilter filter, boolean verbose) {
- StringBuilder sb = new StringBuilder();
- sb.append(excluded.size() + " stories excluded by filter: " + filter.asString() + "\n");
- if (verbose) {
- for (Story story : excluded) {
- sb.append(story.getPath()).append("\n");
- }
- }
- getLog().info(sb.toString());
- }
- @Override
- public void scenarioExcluded(Scenario scenario, MetaFilter filter) {
- getLog().info("Scenario '" + scenario.getTitle() + "' excluded by filter: " + filter.asString() + "\n");
- }
- @Override
- public void runningWithAnnotatedEmbedderRunner(String className) {
- getLog().info("Running with AnnotatedEmbedderRunner '" + className + "'");
- }
- @Override
- public void annotatedInstanceNotOfType(Object annotatedInstance, Class<?> type) {
- getLog().warn("Annotated instance " + annotatedInstance + " not of type " + type);
- }
- @Override
- public void generatingReportsView(File outputDirectory, List<String> formats, Properties viewProperties) {
- getLog().info(
- "Generating reports view to '" + outputDirectory + "' using formats '" + formats + "'"
- + " and view properties '" + viewProperties + "'");
- }
- @Override
- public void reportsViewGenerationFailed(File outputDirectory, List<String> formats, Properties viewProperties,
- Throwable cause) {
- String message = "Failed to generate reports view to '" + outputDirectory + "' using formats '" + formats
- + "'" + " and view properties '" + viewProperties + "'";
- getLog().warn(message, cause);
- }
- @Override
- public void reportsViewGenerated(ReportsCount count) {
- getLog().info(
- "Reports view generated with " + count.getStories() + " stories (of which "
- + count.getStoriesPending() + " pending) containing " + count.getScenarios()
- + " scenarios (of which " + count.getScenariosPending() + " pending)");
- if (count.getStoriesExcluded() > 0 || count.getScenariosExcluded() > 0) {
- getLog().info(
- "Meta filters excluded " + count.getStoriesExcluded() + " stories and "
- + count.getScenariosExcluded() + " scenarios");
- }
- }
- @Override
- public void reportsViewFailures(ReportsCount count) {
- getLog().warn("Failures in reports view: " + count.getScenariosFailed() + " scenarios failed");
- }
- @Override
- public void reportsViewNotGenerated() {
- getLog().info("Reports view not generated");
- }
- @Override
- public void mappingStory(String storyPath, List<String> metaFilters) {
- getLog().info("Mapping story " + storyPath + " with meta filters " + metaFilters);
- }
- @Override
- public void generatingMapsView(File outputDirectory, StoryMaps storyMaps, Properties viewProperties) {
- getLog().info(
- "Generating maps view to '" + outputDirectory + "' using story maps '" + storyMaps + "'"
- + " and view properties '" + viewProperties + "'");
- }
- @Override
- public void mapsViewGenerationFailed(File outputDirectory, StoryMaps storyMaps, Properties viewProperties,
- Throwable cause) {
- getLog().warn(
- "Failed to generate maps view to '" + outputDirectory + "' using story maps '" + storyMaps + "'"
- + " and view properties '" + viewProperties + "'", cause);
- }
- @Override
- public void processingSystemProperties(Properties properties) {
- getLog().info("Processing system properties " + properties);
- }
- @Override
- public void systemPropertySet(String name, String value) {
- getLog().info("System property '" + name + "' set to '" + value + "'");
- }
- @Override
- public void storyTimeout(Story story, StoryDuration storyDuration) {
- getLog().warn(
- "Story " + story.getPath() + " duration of " + storyDuration.getDurationInSecs()
- + " seconds has exceeded timeout of " + storyDuration.getTimeoutInSecs() + " seconds");
- }
- @Override
- public void usingThreads(int threads) {
- getLog().info("Using " + threads + " threads");
- }
- @Override
- public void usingExecutorService(ExecutorService executorService) {
- getLog().info("Using executor service " + executorService);
- }
- @Override
- public void usingControls(EmbedderControls embedderControls) {
- getLog().info("Using controls " + embedderControls);
- }
-
- @Override
- public void invalidTimeoutFormat(String path) {
- getLog().warn("Failed to set specific story timeout for story " + path
- + " because 'storyTimeoutInSecsByPath' has incorrect format");
- getLog().warn("'storyTimeoutInSecsByPath' must be a CSV of regex expressions matching story paths. "
- + "E.g. \"*/long/*.story:5000,*/short/*.story:200\"");
- }
- @Override
- public void usingTimeout(String path, long timeout) {
- getLog().info("Using timeout for story " + path + " of " + timeout + " secs.");
- }
- @Override
- public String toString() {
- return this.getClass().getSimpleName();
- }
- }
- }