Coverage Report - org.jbehave.mojo.AbstractEmbedderMojo
 
Classes in this File Line Coverage Branch Coverage Complexity
AbstractEmbedderMojo
92%
72/78
83%
25/30
1.522
AbstractEmbedderMojo$MavenEmbedderMonitor
39%
34/87
12%
1/8
1.522
 
 1  
 package org.jbehave.mojo;
 2  
 
 3  
 import static org.apache.commons.lang.ArrayUtils.isNotEmpty;
 4  
 
 5  
 import java.io.File;
 6  
 import java.net.MalformedURLException;
 7  
 import java.net.URL;
 8  
 import java.util.ArrayList;
 9  
 import java.util.List;
 10  
 import java.util.Properties;
 11  
 import java.util.concurrent.ExecutorService;
 12  
 
 13  
 import org.apache.maven.plugin.AbstractMojo;
 14  
 import org.jbehave.core.ConfigurableEmbedder;
 15  
 import org.jbehave.core.InjectableEmbedder;
 16  
 import org.jbehave.core.embedder.Embedder;
 17  
 import org.jbehave.core.embedder.EmbedderClassLoader;
 18  
 import org.jbehave.core.embedder.EmbedderControls;
 19  
 import org.jbehave.core.embedder.EmbedderMonitor;
 20  
 import org.jbehave.core.embedder.MetaFilter;
 21  
 import org.jbehave.core.embedder.NullEmbedderMonitor;
 22  
 import org.jbehave.core.embedder.UnmodifiableEmbedderControls;
 23  
 import org.jbehave.core.embedder.executors.ExecutorServiceFactory;
 24  
 import org.jbehave.core.failures.BatchFailures;
 25  
 import org.jbehave.core.io.StoryFinder;
 26  
 import org.jbehave.core.junit.AnnotatedEmbedderRunner;
 27  
 import org.jbehave.core.model.Meta;
 28  
 import org.jbehave.core.model.Scenario;
 29  
 import org.jbehave.core.model.Story;
 30  
 import org.jbehave.core.model.StoryDuration;
 31  
 import org.jbehave.core.model.StoryMaps;
 32  
 import org.jbehave.core.reporters.ReportsCount;
 33  
 
 34  
 /**
 35  
  * Abstract mojo that holds all the configuration parameters to specify and load
 36  
  * stories.
 37  
  * 
 38  
  * @requiresDependencyResolution test
 39  
  */
 40  28
 public abstract class AbstractEmbedderMojo extends AbstractMojo {
 41  
 
 42  
     static final String TEST_SCOPE = "test";
 43  
 
 44  
     /**
 45  
      * @parameter expression="${project.build.sourceDirectory}"
 46  
      * @required
 47  
      */
 48  
     String sourceDirectory;
 49  
 
 50  
     /**
 51  
      * @parameter expression="${project.build.testSourceDirectory}"
 52  
      * @required
 53  
      */
 54  
     String testSourceDirectory;
 55  
 
 56  
     /**
 57  
      * @parameter expression="${project.build.outputDirectory}"
 58  
      * @required
 59  
      */
 60  
     String outputDirectory;
 61  
 
 62  
     /**
 63  
      * @parameter expression="${project.build.testOutputDirectory}"
 64  
      * @required
 65  
      */
 66  
     String testOutputDirectory;
 67  
 
 68  
     /**
 69  
      * The scope of the mojo classpath, either "compile" or "test"
 70  
      * 
 71  
      * @parameter default-value="compile"
 72  
      */
 73  
     String scope;
 74  
 
 75  
     /**
 76  
      * Include filters, relative to the root source directory determined by the
 77  
      * scope
 78  
      * 
 79  
      * @parameter
 80  
      */
 81  
     List<String> includes;
 82  
 
 83  
     /**
 84  
      * Exclude filters, relative to the root source directory determined by the
 85  
      * scope
 86  
      * 
 87  
      * @parameter
 88  
      */
 89  
     List<String> excludes;
 90  
 
 91  
     /**
 92  
      * Compile classpath.
 93  
      * 
 94  
      * @parameter expression="${project.compileClasspathElements}"
 95  
      * @required
 96  
      * @readonly
 97  
      */
 98  
     List<String> compileClasspathElements;
 99  
 
 100  
     /**
 101  
      * Test classpath.
 102  
      * 
 103  
      * @parameter expression="${project.testClasspathElements}"
 104  
      * @required
 105  
      * @readonly
 106  
      */
 107  
     List<String> testClasspathElements;
 108  
 
 109  
     /**
 110  
      * The boolean flag to skip stories
 111  
      * 
 112  
      * @parameter default-value="false"
 113  
      */
 114  28
     boolean skip = false;
 115  
 
 116  
     /**
 117  
      * The boolean flag to run in batch mode
 118  
      * 
 119  
      * @parameter default-value="false"
 120  
      */
 121  28
     boolean batch = false;
 122  
 
 123  
     /**
 124  
      * The boolean flag to ignore failure in stories
 125  
      * 
 126  
      * @parameter default-value="false"
 127  
      */
 128  28
     boolean ignoreFailureInStories = false;
 129  
 
 130  
     /**
 131  
      * The boolean flag to ignore failure in view
 132  
      * 
 133  
      * @parameter default-value="false"
 134  
      */
 135  28
     boolean ignoreFailureInView = false;
 136  
 
 137  
     /**
 138  
      * The boolean flag to generate view after stories are run
 139  
      * 
 140  
      * @parameter default-value="true"
 141  
      */
 142  28
     boolean generateViewAfterStories = true;
 143  
 
 144  
     /**
 145  
      * The boolean flag to output failures in verbose mode
 146  
      * 
 147  
      * @parameter default-value="false"
 148  
      */
 149  28
     boolean verboseFailures = false;
 150  
 
 151  
     /**
 152  
      * The boolean flag to output filtering in verbose mode
 153  
      * 
 154  
      * @parameter default-value="false"
 155  
      */
 156  28
     boolean verboseFiltering = false;
 157  
 
 158  
     /**
 159  
      * The story timeouts
 160  
      * 
 161  
      * @parameter
 162  
      */
 163  
     String storyTimeouts;
 164  
 
 165  
     /**
 166  
      * The story timeout in secs
 167  
      * 
 168  
      * @parameter
 169  
      * @deprecated Use storyTimeouts
 170  
      */
 171  
     long storyTimeoutInSecs;
 172  
     
 173  
     /**
 174  
      * The story timeout in secs by path
 175  
      * 
 176  
      * @parameter
 177  
      * @deprecated Use storyTimeouts
 178  
      */
 179  
     String storyTimeoutInSecsByPath;
 180  
 
 181  
     /**
 182  
      * The boolean flag to fail on story timeout
 183  
      * 
 184  
      * @parameter default-value="false"
 185  
      */
 186  28
     boolean failOnStoryTimeout = false;
 187  
 
 188  
     /**
 189  
      * The number of threads
 190  
      * 
 191  
      * @parameter default-value="1"
 192  
      */
 193  28
     int threads = 1;
 194  
 
 195  
     /**
 196  
      * The embedder class
 197  
      * 
 198  
      * @parameter default-value="org.jbehave.core.embedder.Embedder"
 199  
      */
 200  28
     String embedderClass = Embedder.class.getName();
 201  
 
 202  
     /**
 203  
      * The implementation class of the {@link ExecutorServiceFactory}
 204  
      * 
 205  
      * @parameter
 206  
      */
 207  
     String executorsClass;
 208  
 
 209  
     /**
 210  
      * The class that is injected with the embedder
 211  
      * 
 212  
      * @parameter
 213  
      */
 214  
     String injectableEmbedderClass;
 215  
 
 216  
     /**
 217  
      * The annotated embedder runner class
 218  
      * 
 219  
      * @parameter default-value="org.jbehave.core.junit.AnnotatedEmbedderRunner"
 220  
      * @deprecated Obsolete
 221  
      */
 222  28
     String annotatedEmbedderRunnerClass = AnnotatedEmbedderRunner.class.getName();
 223  
 
 224  
     /**
 225  
      * Used to find story paths and class names
 226  
      * 
 227  
      * @parameter
 228  
      */
 229  28
     String storyFinderClass = StoryFinder.class.getName();
 230  
 
 231  
     /**
 232  
      * The meta filter
 233  
      * 
 234  
      * @parameter
 235  
      */
 236  
     String[] metaFilters;
 237  
 
 238  
     /**
 239  
      * The system properties
 240  
      * 
 241  
      * @parameter
 242  
      */
 243  28
     Properties systemProperties = new Properties();
 244  
 
 245  
     /**
 246  
      * The class loader
 247  
      */
 248  
     private EmbedderClassLoader classLoader;
 249  
 
 250  
     /**
 251  
      * Determines if the scope of the mojo classpath is "test"
 252  
      * 
 253  
      * @return A boolean <code>true</code> if test scoped
 254  
      */
 255  
     boolean isTestScope() {
 256  32
         return TEST_SCOPE.equals(scope);
 257  
     }
 258  
 
 259  
     String searchDirectory() {
 260  11
         if (isTestScope()) {
 261  1
             return testSourceDirectory;
 262  
         }
 263  10
         return sourceDirectory;
 264  
     }
 265  
 
 266  
     String outputDirectory() {
 267  10
         if (isTestScope()) {
 268  0
             return testOutputDirectory;
 269  
         }
 270  10
         return outputDirectory;
 271  
     }
 272  
 
 273  
     URL codeLocation() {
 274  10
         String outputDirectory = outputDirectory();
 275  
         try {
 276  10
             return outputDirectory != null ? new File(outputDirectory).toURI().toURL() : null;
 277  0
         } catch (MalformedURLException e) {
 278  0
             throw new IllegalArgumentException("Failed to create code location from " + outputDirectory, e);
 279  
         }
 280  
     }
 281  
 
 282  
     /**
 283  
      * Returns the EmbedderClassLoader with the classpath element of the
 284  
      * selected scope.
 285  
      * 
 286  
      * @return An EmbedderClassLoader
 287  
      */
 288  
     protected EmbedderClassLoader classLoader() {
 289  10
         if (classLoader == null) {
 290  10
             classLoader = new EmbedderClassLoader(classpathElements());
 291  
         }
 292  10
         return classLoader;
 293  
     }
 294  
 
 295  
     List<String> classpathElements() {
 296  11
         List<String> classpathElements = compileClasspathElements;
 297  11
         if (isTestScope()) {
 298  1
             classpathElements = testClasspathElements;
 299  
         }
 300  11
         return classpathElements;
 301  
     }
 302  
 
 303  
     /**
 304  
      * Finds story paths, using the {@link #newStoryFinder()}, in the
 305  
      * {@link #searchDirectory()} given specified {@link #includes} and
 306  
      * {@link #excludes}.
 307  
      * 
 308  
      * @return A List of story paths found
 309  
      */
 310  
     protected List<String> storyPaths() {
 311  4
         getLog().debug("Searching for story paths including " + includes + " and excluding " + excludes);
 312  4
         List<String> storyPaths = newStoryFinder().findPaths(searchDirectory(), includes, excludes);
 313  4
         getLog().info("Found story paths: " + storyPaths);
 314  4
         return storyPaths;
 315  
     }
 316  
 
 317  
     /**
 318  
      * Finds class names, using the {@link #newStoryFinder()}, in the
 319  
      * {@link #searchDirectory()} given specified {@link #includes} and
 320  
      * {@link #excludes}.
 321  
      * 
 322  
      * @return A List of class names found
 323  
      */
 324  
     protected List<String> classNames() {
 325  6
         getLog().debug("Searching for class names including " + includes + " and excluding " + excludes);
 326  6
         List<String> classNames = newStoryFinder().findClassNames(searchDirectory(), includes, excludes);
 327  6
         getLog().info("Found class names: " + classNames);
 328  6
         return classNames;
 329  
     }
 330  
 
 331  
     /**
 332  
      * Creates an instance of StoryFinder, using the {@link #storyFinderClass}
 333  
      * 
 334  
      * @return A StoryFinder
 335  
      */
 336  
     protected StoryFinder newStoryFinder() {
 337  11
         return classLoader().newInstance(StoryFinder.class, storyFinderClass);
 338  
     }
 339  
 
 340  
     /**
 341  
      * Creates an instance of Embedder, either using
 342  
      * {@link #injectableEmbedderClass} (if set) or defaulting to
 343  
      * {@link #embedderClass}.
 344  
      * 
 345  
      * @return An Embedder
 346  
      */
 347  
     protected Embedder newEmbedder() {
 348  9
         Embedder embedder = null;
 349  9
         EmbedderClassLoader classLoader = classLoader();
 350  9
         if (injectableEmbedderClass != null) {
 351  1
             embedder = classLoader.newInstance(InjectableEmbedder.class, injectableEmbedderClass).injectedEmbedder();
 352  
         } else {
 353  8
             embedder = classLoader.newInstance(Embedder.class, embedderClass);
 354  
         }
 355  
         
 356  9
         URL codeLocation = codeLocation();
 357  9
         if (codeLocation != null) {
 358  0
             embedder.configuration().storyReporterBuilder().withCodeLocation(codeLocation);
 359  
         }
 360  
 
 361  9
         embedder.useClassLoader(classLoader);
 362  9
         embedder.useEmbedderControls(embedderControls());
 363  9
         if ( executorsClass != null ){
 364  1
             ExecutorServiceFactory executorServiceFactory = classLoader.newInstance(ExecutorServiceFactory.class, executorsClass);
 365  1
             embedder.useExecutorService(executorServiceFactory.create(embedder.embedderControls()));
 366  
         }
 367  9
         embedder.useEmbedderMonitor(embedderMonitor());
 368  9
         if (isNotEmpty(metaFilters)) {
 369  2
             List<String> filters = new ArrayList<String>();
 370  6
             for (String filter : metaFilters) {
 371  4
                 if (filter != null) {
 372  3
                     filters.add(filter);
 373  
                 }
 374  
             }
 375  2
             embedder.useMetaFilters(filters);
 376  
         }
 377  9
         if (!systemProperties.isEmpty()) {
 378  1
             embedder.useSystemProperties(systemProperties);
 379  
         }
 380  9
         return embedder;
 381  
     }
 382  
 
 383  
     protected EmbedderMonitor embedderMonitor() {
 384  9
         return new MavenEmbedderMonitor();
 385  
     }
 386  
 
 387  
     protected EmbedderControls embedderControls() {
 388  9
         EmbedderControls embedderControls = new EmbedderControls().doBatch(batch).doSkip(skip)
 389  9
                 .doGenerateViewAfterStories(generateViewAfterStories).doIgnoreFailureInStories(ignoreFailureInStories)
 390  9
                 .doIgnoreFailureInView(ignoreFailureInView).doVerboseFailures(verboseFailures)
 391  9
                 .doVerboseFiltering(verboseFiltering)
 392  9
                 .doFailOnStoryTimeout(failOnStoryTimeout).useThreads(threads);
 393  9
         if ( storyTimeoutInSecs != 0 ){
 394  0
                 embedderControls.useStoryTimeoutInSecs(storyTimeoutInSecs);
 395  
         }
 396  9
         if ( storyTimeoutInSecsByPath != null ){
 397  0
                 embedderControls.useStoryTimeoutInSecsByPath(storyTimeoutInSecsByPath);
 398  
         }
 399  9
         if ( storyTimeouts != null ){
 400  1
                 embedderControls.useStoryTimeouts(storyTimeouts);
 401  
         }        
 402  9
                 return new UnmodifiableEmbedderControls(embedderControls);
 403  
     }
 404  
 
 405  28
     protected class MavenEmbedderMonitor extends NullEmbedderMonitor {
 406  
 
 407  
         public void batchFailed(BatchFailures failures) {
 408  1
             getLog().warn("Failed to run batch " + failures);
 409  1
         }
 410  
 
 411  
         public void beforeOrAfterStoriesFailed() {
 412  0
             getLog().warn("Failed to run before or after stories steps");
 413  0
         }
 414  
 
 415  
         public void embeddableFailed(String name, Throwable cause) {
 416  1
             getLog().warn("Failed to run embeddable " + name, cause);
 417  1
         }
 418  
 
 419  
         public void embeddableNotConfigurable(String name) {
 420  0
             getLog().warn("Embeddable " + name + " must be an instance of " + ConfigurableEmbedder.class);
 421  0
         }
 422  
 
 423  
         public void embeddablesSkipped(List<String> classNames) {
 424  1
             getLog().info("Skipped embeddables " + classNames);
 425  1
         }
 426  
 
 427  
         public void metaNotAllowed(Meta meta, MetaFilter filter) {
 428  0
             getLog().debug(meta + " excluded by filter '" + filter.asString() + "'");
 429  0
         }
 430  
 
 431  
         public void runningEmbeddable(String name) {
 432  1
             getLog().info("Running embeddable " + name);
 433  1
         }
 434  
 
 435  
         public void runningStory(String path) {
 436  1
             getLog().info("Running story " + path);
 437  1
         }
 438  
 
 439  
         public void storyFailed(String path, Throwable cause) {
 440  1
             getLog().warn("Failed to run story " + path, cause);
 441  1
         }
 442  
 
 443  
         public void storiesSkipped(List<String> storyPaths) {
 444  1
             getLog().info("Skipped stories " + storyPaths);
 445  1
         }
 446  
 
 447  
         public void storiesNotAllowed(List<Story> stories, MetaFilter filter, boolean verbose) {
 448  0
             StringBuffer sb = new StringBuffer();
 449  0
             sb.append(stories.size() + " stories excluded by filter: " + filter.asString() + "\n");
 450  0
             if (verbose) {
 451  0
                 for (Story story : stories) {
 452  0
                     sb.append(story.getPath()).append("\n");
 453  0
                 }
 454  
             }
 455  0
             getLog().info(sb.toString());
 456  0
         }
 457  
 
 458  
             public void scenarioNotAllowed(Scenario scenario, MetaFilter filter) {
 459  0
             StringBuffer sb = new StringBuffer();
 460  0
             sb.append("Scenario '"+scenario.getTitle()+"' excluded by filter: " + filter.asString() + "\n");
 461  0
             getLog().info(sb.toString());
 462  0
             }
 463  
 
 464  
         public void runningWithAnnotatedEmbedderRunner(String className) {
 465  0
             getLog().info("Running with AnnotatedEmbedderRunner '" + className + "'");
 466  0
         }
 467  
 
 468  
         public void annotatedInstanceNotOfType(Object annotatedInstance, Class<?> type) {
 469  1
             getLog().warn("Annotated instance " + annotatedInstance + " not of type " + type);
 470  1
         }
 471  
 
 472  
         public void generatingReportsView(File outputDirectory, List<String> formats, Properties viewProperties) {
 473  1
             getLog().info(
 474  
                     "Generating reports view to '" + outputDirectory + "' using formats '" + formats + "'"
 475  
                             + " and view properties '" + viewProperties + "'");
 476  1
         }
 477  
 
 478  
         public void reportsViewGenerationFailed(File outputDirectory, List<String> formats, Properties viewProperties,
 479  
                 Throwable cause) {
 480  1
             String message = "Failed to generate reports view to '" + outputDirectory + "' using formats '" + formats
 481  
                     + "'" + " and view properties '" + viewProperties + "'";
 482  1
             getLog().warn(message, cause);
 483  1
         }
 484  
 
 485  
         public void reportsViewGenerated(ReportsCount count) {
 486  2
             getLog().info(
 487  1
                     "Reports view generated with " + count.getStories() + " stories (of which "
 488  1
                             + count.getStoriesPending() + " pending) containing " + count.getScenarios()
 489  1
                             + " scenarios (of which " + count.getScenariosPending() + " pending)");
 490  1
             if (count.getStoriesNotAllowed() > 0 || count.getScenariosNotAllowed() > 0) {
 491  2
                 getLog().info(
 492  1
                         "Meta filters excluded " + count.getStoriesNotAllowed() + " stories and  "
 493  1
                                 + count.getScenariosNotAllowed() + " scenarios");
 494  
             }
 495  1
         }
 496  
 
 497  
         public void reportsViewFailures(ReportsCount count) {
 498  0
             getLog().warn("Failures in reports view: " + count.getScenariosFailed() + " scenarios failed");
 499  0
         }
 500  
 
 501  
         public void reportsViewNotGenerated() {
 502  1
             getLog().info("Reports view not generated");
 503  1
         }
 504  
 
 505  
         public void mappingStory(String storyPath, List<String> metaFilters) {
 506  0
             getLog().info("Mapping story " + storyPath + " with meta filters " + metaFilters);
 507  0
         }
 508  
 
 509  
         public void generatingMapsView(File outputDirectory, StoryMaps storyMaps, Properties viewProperties) {
 510  0
             getLog().info(
 511  
                     "Generating maps view to '" + outputDirectory + "' using story maps '" + storyMaps + "'"
 512  
                             + " and view properties '" + viewProperties + "'");
 513  0
         }
 514  
 
 515  
         public void mapsViewGenerationFailed(File outputDirectory, StoryMaps storyMaps, Properties viewProperties,
 516  
                 Throwable cause) {
 517  0
             getLog().warn(
 518  
                     "Failed to generate maps view to '" + outputDirectory + "' using story maps '" + storyMaps + "'"
 519  
                             + " and view properties '" + viewProperties + "'", cause);
 520  0
         }
 521  
 
 522  
         public void generatingNavigatorView(File outputDirectory, Properties viewProperties) {
 523  0
             getLog().info(
 524  
                     "Generating navigator view to '" + outputDirectory + "' using view properties '" + viewProperties
 525  
                             + "'");
 526  0
         }
 527  
 
 528  
         public void navigatorViewGenerationFailed(File outputDirectory, Properties viewProperties, Throwable cause) {
 529  0
             getLog().warn(
 530  
                     "Failed to generate navigator view to '" + outputDirectory + "' using view properties '"
 531  
                             + viewProperties + "'", cause);
 532  0
         }
 533  
 
 534  
         public void navigatorViewNotGenerated() {
 535  0
             getLog().warn(
 536  
                     "Navigator view not generated, as the CrossReference has not been declared in the StoryReporterBuilder");
 537  0
         }
 538  
 
 539  
         public void processingSystemProperties(Properties properties) {
 540  0
             getLog().info("Processing system properties " + properties);
 541  0
         }
 542  
 
 543  
         public void systemPropertySet(String name, String value) {
 544  0
             getLog().info("System property '" + name + "' set to '" + value + "'");
 545  0
         }
 546  
 
 547  
         public void storyTimeout(Story story, StoryDuration storyDuration) {
 548  0
             getLog().warn(
 549  0
                     "Story " + story.getPath() + " duration of " + storyDuration.getDurationInSecs()
 550  0
                             + " seconds has exceeded timeout of " + storyDuration.getTimeoutInSecs() + " seconds");
 551  0
         }
 552  
 
 553  
         public void usingThreads(int threads) {
 554  0
             getLog().info("Using " + threads + " threads");
 555  0
         }
 556  
 
 557  
         public void usingExecutorService(ExecutorService executorService) {
 558  0
             getLog().info("Using executor service " + executorService);
 559  0
         }
 560  
 
 561  
         public void usingControls(EmbedderControls embedderControls) {
 562  0
             getLog().info("Using controls " + embedderControls);
 563  0
         }
 564  
         
 565  
         public void invalidTimeoutFormat(String path) {
 566  0
                 getLog().warn("Failed to set specific story timeout for story " + path + " because 'storyTimeoutInSecsByPath' has incorrect format");
 567  0
                 getLog().warn("'storyTimeoutInSecsByPath' must be a CSV of regex expressions matching story paths. E.g. \"*/long/*.story:5000,*/short/*.story:200\"");
 568  0
             }
 569  
 
 570  
             public void usingTimeout(String path, long timeout) {
 571  0
                 getLog().info("Using timeout for story " + path + " of "+timeout+" secs.");
 572  0
             }
 573  
 
 574  
         @Override
 575  
         public String toString() {
 576  1
             return this.getClass().getSimpleName();
 577  
         }
 578  
 
 579  
     }
 580  
 }