##### Coverage Report - org.jbehave.mojo.AbstractEmbedderMojo

Classes in this File | Line Coverage | Branch Coverage | Complexity
AbstractEmbedderMojo |
94% | 63/67
87% | 21/24
| 1.4883720930232558;1.488
AbstractEmbedderMojo$MavenEmbedderMonitor |
41% | 29/70
12% | 1/8
| 1.4883720930232558;1.488

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