Coverage Report - org.jbehave.core.embedder.Embedder
 
Classes in this File Line Coverage Branch Coverage Complexity
Embedder
85%
215/252
83%
67/80
2.187
Embedder$AnnotatedEmbedderRunFailed
100%
2/2
N/A
2.187
Embedder$AnnotatedEmbedderRunnerInstantiationFailed
100%
2/2
N/A
2.187
Embedder$ClassLoadingFailed
100%
2/2
N/A
2.187
Embedder$EnqueuedStory
100%
22/22
100%
4/4
2.187
Embedder$NonThreadingExecutorService
26%
5/19
N/A
2.187
Embedder$NonThreadingExecutorService$1
50%
3/6
N/A
2.187
Embedder$RunningEmbeddablesFailed
100%
4/4
N/A
2.187
Embedder$RunningStoriesFailed
100%
6/6
N/A
2.187
Embedder$ThrowableStory
83%
5/6
N/A
2.187
Embedder$ViewGenerationFailed
50%
2/4
N/A
2.187
 
 1  
 package org.jbehave.core.embedder;
 2  
 
 3  
 import java.io.File;
 4  
 import java.util.ArrayList;
 5  
 import java.util.Arrays;
 6  
 import java.util.Collection;
 7  
 import java.util.List;
 8  
 import java.util.Properties;
 9  
 import java.util.concurrent.Callable;
 10  
 import java.util.concurrent.CancellationException;
 11  
 import java.util.concurrent.ExecutionException;
 12  
 import java.util.concurrent.ExecutorService;
 13  
 import java.util.concurrent.Executors;
 14  
 import java.util.concurrent.Future;
 15  
 import java.util.concurrent.ThreadPoolExecutor;
 16  
 import java.util.concurrent.TimeUnit;
 17  
 import java.util.concurrent.TimeoutException;
 18  
 
 19  
 import org.apache.commons.lang.StringUtils;
 20  
 import org.apache.commons.lang.builder.ToStringBuilder;
 21  
 import org.apache.commons.lang.builder.ToStringStyle;
 22  
 import org.jbehave.core.ConfigurableEmbedder;
 23  
 import org.jbehave.core.Embeddable;
 24  
 import org.jbehave.core.configuration.Configuration;
 25  
 import org.jbehave.core.configuration.MostUsefulConfiguration;
 26  
 import org.jbehave.core.failures.BatchFailures;
 27  
 import org.jbehave.core.junit.AnnotatedEmbedderRunner;
 28  
 import org.jbehave.core.model.Story;
 29  
 import org.jbehave.core.model.StoryMaps;
 30  
 import org.jbehave.core.reporters.ReportsCount;
 31  
 import org.jbehave.core.reporters.StepdocReporter;
 32  
 import org.jbehave.core.reporters.StoryReporterBuilder;
 33  
 import org.jbehave.core.reporters.ViewGenerator;
 34  
 import org.jbehave.core.steps.CandidateSteps;
 35  
 import org.jbehave.core.steps.StepCollector.Stage;
 36  
 import org.jbehave.core.steps.StepFinder;
 37  
 import org.jbehave.core.steps.Stepdoc;
 38  
 
 39  
 /**
 40  
  * Represents an entry point to all of JBehave's functionality that is
 41  
  * embeddable into other launchers, such as IDEs or CLIs.
 42  
  */
 43  
 public class Embedder {
 44  
 
 45  76
     private Configuration configuration = new MostUsefulConfiguration();
 46  76
     private List<CandidateSteps> candidateSteps = new ArrayList<CandidateSteps>();
 47  76
     private EmbedderClassLoader classLoader = new EmbedderClassLoader(this.getClass().getClassLoader());
 48  76
     private EmbedderControls embedderControls = new EmbedderControls();
 49  76
     private List<String> metaFilters = Arrays.asList();
 50  76
     private Properties systemProperties = new Properties();
 51  
     private StoryMapper storyMapper;
 52  
     private StoryRunner storyRunner;
 53  
     private EmbedderMonitor embedderMonitor;
 54  
     private ExecutorService executorService;
 55  
 
 56  
     public Embedder() {
 57  49
         this(new StoryMapper(), new StoryRunner(), new PrintStreamEmbedderMonitor());
 58  49
     }
 59  
 
 60  76
     public Embedder(StoryMapper storyMapper, StoryRunner storyRunner, EmbedderMonitor embedderMonitor) {
 61  76
         this.storyMapper = storyMapper;
 62  76
         this.storyRunner = storyRunner;
 63  76
         this.embedderMonitor = embedderMonitor;
 64  76
     }
 65  
 
 66  
     public void mapStoriesAsPaths(List<String> storyPaths) {
 67  1
         EmbedderControls embedderControls = embedderControls();
 68  1
         if (embedderControls.skip()) {
 69  0
             embedderMonitor.storiesSkipped(storyPaths);
 70  0
             return;
 71  
         }
 72  
 
 73  1
         processSystemProperties();
 74  
 
 75  1
         for (String storyPath : storyPaths) {
 76  2
             Story story = storyRunner.storyOfPath(configuration, storyPath);
 77  2
             embedderMonitor.mappingStory(storyPath, metaFilters);
 78  2
             storyMapper.map(story, new MetaFilter(""));
 79  2
             for (String filter : metaFilters) {
 80  0
                 storyMapper.map(story, new MetaFilter(filter));
 81  
             }
 82  2
         }
 83  
 
 84  1
         generateMapsView(storyMapper.getStoryMaps());
 85  
 
 86  1
     }
 87  
 
 88  
     private void generateMapsView(StoryMaps storyMaps) {
 89  1
         Configuration configuration = configuration();
 90  1
         StoryReporterBuilder builder = configuration.storyReporterBuilder();
 91  1
         File outputDirectory = builder.outputDirectory();
 92  1
         Properties viewResources = builder.viewResources();
 93  1
         ViewGenerator viewGenerator = configuration.viewGenerator();
 94  
         try {
 95  1
             embedderMonitor.generatingMapsView(outputDirectory, storyMaps, viewResources);
 96  1
             viewGenerator.generateMapsView(outputDirectory, storyMaps, viewResources);
 97  0
         } catch (RuntimeException e) {
 98  0
             embedderMonitor.mapsViewGenerationFailed(outputDirectory, storyMaps, viewResources, e);
 99  0
             throw new ViewGenerationFailed(outputDirectory, storyMaps, viewResources, e);
 100  1
         }
 101  1
     }
 102  
 
 103  
     public void runAsEmbeddables(List<String> classNames) {
 104  10
         EmbedderControls embedderControls = embedderControls();
 105  10
         if (embedderControls.skip()) {
 106  1
             embedderMonitor.embeddablesSkipped(classNames);
 107  1
             return;
 108  
         }
 109  
 
 110  9
         BatchFailures batchFailures = new BatchFailures();
 111  9
         for (Embeddable embeddable : embeddables(classNames, classLoader())) {
 112  15
             String name = embeddable.getClass().getName();
 113  
             try {
 114  15
                 embedderMonitor.runningEmbeddable(name);
 115  15
                 embeddable.useEmbedder(this);
 116  15
                 embeddable.run();
 117  4
             } catch (Throwable e) {
 118  4
                 if (embedderControls.batch()) {
 119  
                     // collect and postpone decision to throw exception
 120  2
                     batchFailures.put(name, e);
 121  
                 } else {
 122  2
                     if (embedderControls.ignoreFailureInStories()) {
 123  1
                         embedderMonitor.embeddableFailed(name, e);
 124  
                     } else {
 125  1
                         throw new RunningEmbeddablesFailed(name, e);
 126  
                     }
 127  
                 }
 128  11
             }
 129  14
         }
 130  
 
 131  8
         if (embedderControls.batch() && batchFailures.size() > 0) {
 132  2
             if (embedderControls.ignoreFailureInStories()) {
 133  1
                 embedderMonitor.batchFailed(batchFailures);
 134  
             } else {
 135  1
                 throw new RunningEmbeddablesFailed(batchFailures);
 136  
             }
 137  
         }
 138  
 
 139  7
     }
 140  
 
 141  
     private List<Embeddable> embeddables(List<String> classNames, EmbedderClassLoader classLoader) {
 142  9
         List<Embeddable> embeddables = new ArrayList<Embeddable>();
 143  9
         for (String className : classNames) {
 144  17
             if (!classLoader.isAbstract(className)) {
 145  16
                 embeddables.add(classLoader.newInstance(Embeddable.class, className));
 146  
             }
 147  
         }
 148  9
         return embeddables;
 149  
     }
 150  
 
 151  
     public void runStoriesWithAnnotatedEmbedderRunner(String runnerClass, List<String> classNames) {
 152  4
         List<AnnotatedEmbedderRunner> runners = annotatedEmbedderRunners(runnerClass, classNames, classLoader());
 153  3
         for (AnnotatedEmbedderRunner runner : runners) {
 154  
             try {
 155  3
                 Object annotatedInstance = runner.createTest();
 156  3
                 if (annotatedInstance instanceof Embeddable) {
 157  2
                     ((Embeddable) annotatedInstance).run();
 158  
                 } else {
 159  1
                     embedderMonitor.annotatedInstanceNotOfType(annotatedInstance, Embeddable.class);
 160  
                 }
 161  1
             } catch (Throwable e) {
 162  1
                 throw new AnnotatedEmbedderRunFailed(runner, e);
 163  2
             }
 164  
         }
 165  2
     }
 166  
 
 167  
     private List<AnnotatedEmbedderRunner> annotatedEmbedderRunners(String runnerClassName, List<String> classNames,
 168  
             EmbedderClassLoader classLoader) {
 169  4
         Class<?> runnerClass = loadClass(runnerClassName, classLoader);
 170  4
         List<AnnotatedEmbedderRunner> runners = new ArrayList<AnnotatedEmbedderRunner>();
 171  4
         for (String annotatedClassName : classNames) {
 172  4
             runners.add(newAnnotatedEmbedderRunner(runnerClass, annotatedClassName, classLoader));
 173  
         }
 174  3
         return runners;
 175  
     }
 176  
 
 177  
     private AnnotatedEmbedderRunner newAnnotatedEmbedderRunner(Class<?> runnerClass, String annotatedClassName,
 178  
             EmbedderClassLoader classLoader) {
 179  
         try {
 180  4
             Class<?> annotatedClass = loadClass(annotatedClassName, classLoader);
 181  3
             return (AnnotatedEmbedderRunner) runnerClass.getConstructor(Class.class).newInstance(annotatedClass);
 182  1
         } catch (Exception e) {
 183  1
             throw new AnnotatedEmbedderRunnerInstantiationFailed(runnerClass, annotatedClassName, classLoader, e);
 184  
         }
 185  
     }
 186  
 
 187  
     private Class<?> loadClass(String className, EmbedderClassLoader classLoader) {
 188  
         try {
 189  8
             return classLoader.loadClass(className);
 190  1
         } catch (ClassNotFoundException e) {
 191  1
             throw new ClassLoadingFailed(className, classLoader, e);
 192  
         }
 193  
     }
 194  
 
 195  
     public void runStoriesAsPaths(List<String> storyPaths) {
 196  
 
 197  19
         processSystemProperties();
 198  
 
 199  19
         final EmbedderControls embedderControls = embedderControls();
 200  19
         if (embedderControls.skip()) {
 201  1
             embedderMonitor.storiesSkipped(storyPaths);
 202  1
             return;
 203  
         }
 204  
 
 205  18
         final Configuration configuration = configuration();
 206  18
         final List<CandidateSteps> candidateSteps = candidateSteps();
 207  
 
 208  18
         storyRunner.runBeforeOrAfterStories(configuration, candidateSteps, Stage.BEFORE);
 209  
 
 210  18
         final BatchFailures batchFailures = new BatchFailures();
 211  18
         configureReporterBuilder(configuration);
 212  18
         final MetaFilter filter = new MetaFilter(StringUtils.join(metaFilters, " "), embedderMonitor);
 213  
 
 214  18
         List<Future<ThrowableStory>> futures = new ArrayList<Future<ThrowableStory>>();
 215  
 
 216  18
         for (final String storyPath : storyPaths) {
 217  26
             enqueueStory(batchFailures, filter, futures, storyPath, storyRunner.storyOfPath(configuration, storyPath));
 218  
         }
 219  
 
 220  18
         waitUntilAllDone(futures);
 221  
 
 222  18
         checkForFailures(futures);
 223  
 
 224  17
         storyRunner.runBeforeOrAfterStories(configuration, candidateSteps, Stage.AFTER);
 225  
 
 226  17
         if (embedderControls.batch() && batchFailures.size() > 0) {
 227  2
             if (embedderControls.ignoreFailureInStories()) {
 228  1
                 embedderMonitor.batchFailed(batchFailures);
 229  
             } else {
 230  1
                 throw new RunningStoriesFailed(batchFailures);
 231  
             }
 232  
         }
 233  
 
 234  16
         if (embedderControls.generateViewAfterStories()) {
 235  13
             generateReportsView();
 236  
         }
 237  16
     }
 238  
 
 239  
     public Future<ThrowableStory> enqueueStory(BatchFailures batchFailures, MetaFilter filter,
 240  
             List<Future<ThrowableStory>> futures, String storyPath, Story story) {
 241  26
         EnqueuedStory enqueuedStory = enqueuedStory(embedderControls, configuration, candidateSteps, batchFailures,
 242  
                 filter, storyPath, story);
 243  26
         return submit(futures, enqueuedStory);
 244  
     }
 245  
 
 246  
     private synchronized Future<ThrowableStory> submit(List<Future<ThrowableStory>> futures, EnqueuedStory enqueuedStory) {
 247  26
         if (executorService == null) {
 248  15
             executorService = createExecutorService();
 249  
         }
 250  26
         Future<ThrowableStory> submit = executorService.submit(enqueuedStory);
 251  26
         futures.add(submit);
 252  26
         return submit;
 253  
     }
 254  
 
 255  
     protected EnqueuedStory enqueuedStory(EmbedderControls embedderControls, Configuration configuration,
 256  
             List<CandidateSteps> candidateSteps, BatchFailures batchFailures, MetaFilter filter, String storyPath,
 257  
             Story story) {
 258  26
         return new EnqueuedStory(storyPath, configuration, candidateSteps, story, filter, embedderControls,
 259  
                 batchFailures, embedderMonitor, storyRunner);
 260  
     }
 261  
 
 262  
     /**
 263  
      * Creates a {@link ThreadPoolExecutor} using the number of threads defined
 264  
      * in the {@link EmbedderControls#threads()}
 265  
      * 
 266  
      * @return An ExecutorService
 267  
      */
 268  
     protected ExecutorService createExecutorService() {
 269  15
         int threads = embedderControls.threads();
 270  15
         embedderMonitor.usingThreads(threads);
 271  15
         if (threads == 1) {
 272  
             // this is necessary for situations where people use the
 273  
             // PerStoriesWebDriverSteps class.
 274  15
             return new NonThreadingExecutorService();
 275  
         } else {
 276  0
             return Executors.newFixedThreadPool(threads);
 277  
         }
 278  
     }
 279  
 
 280  
     private void waitUntilAllDone(List<Future<ThrowableStory>> futures) {
 281  
 
 282  18
         long start = System.currentTimeMillis();
 283  18
         boolean allDone = false;
 284  36
         while (!allDone) {
 285  18
             allDone = true;
 286  18
             for (Future<ThrowableStory> future : futures) {
 287  26
                 if (!future.isDone()) {
 288  0
                     allDone = false;
 289  0
                     long durationInSecs = (System.currentTimeMillis() - start)/1000;
 290  0
                     if ( durationInSecs > embedderControls.storyTimeoutInSecs()) {
 291  0
                         Story story = null;
 292  
                         try {
 293  0
                             story = future.get().getStory();
 294  0
                         } catch (Throwable e) {
 295  0
                         }
 296  0
                         embedderMonitor.storyTimeout(durationInSecs, story);
 297  0
                         future.cancel(true);
 298  
                     }
 299  
                     try {
 300  0
                         Thread.sleep(100);
 301  0
                     } catch (InterruptedException e) {
 302  0
                     }
 303  0
                     break;
 304  
                 }
 305  
             }
 306  
         }
 307  18
     }
 308  
 
 309  
     private void checkForFailures(List<Future<ThrowableStory>> futures) {
 310  
         try {
 311  18
             BatchFailures failures = new BatchFailures();
 312  18
             for (Future<ThrowableStory> future : futures) {
 313  
                 try {
 314  26
                     ThrowableStory throwableStory = future.get();
 315  26
                     if (throwableStory.throwable != null) {
 316  2
                         failures.put(future.toString(), throwableStory.throwable);
 317  
                     }
 318  0
                 } catch (CancellationException e) {
 319  0
                     failures.put(future.toString(), e);
 320  52
                 }
 321  
             }
 322  18
             if (failures.size() > 0) {
 323  1
                 throw new RunningStoriesFailed(failures);
 324  
             }
 325  0
         } catch (InterruptedException e) {
 326  0
             throw new RuntimeException(e);
 327  0
         } catch (ExecutionException e) {
 328  0
             throw new RuntimeException(e);
 329  17
         }
 330  17
     }
 331  
 
 332  
     private void configureReporterBuilder(Configuration configuration) {
 333  18
         StoryReporterBuilder reporterBuilder = configuration.storyReporterBuilder();
 334  18
         reporterBuilder.withMultiThreading(embedderControls.threads() > 1);
 335  18
         configuration.useStoryReporterBuilder(reporterBuilder);
 336  18
     }
 337  
 
 338  
     public void generateReportsView() {
 339  13
         StoryReporterBuilder builder = configuration().storyReporterBuilder();
 340  13
         File outputDirectory = builder.outputDirectory();
 341  13
         List<String> formatNames = builder.formatNames(true);
 342  13
         generateReportsView(outputDirectory, formatNames, builder.viewResources());
 343  13
     }
 344  
 
 345  
     public void generateReportsView(File outputDirectory, List<String> formats, Properties viewResources) {
 346  18
         EmbedderControls embedderControls = embedderControls();
 347  
 
 348  18
         if (embedderControls.skip()) {
 349  1
             embedderMonitor.reportsViewNotGenerated();
 350  1
             return;
 351  
         }
 352  17
         ViewGenerator viewGenerator = configuration().viewGenerator();
 353  
         try {
 354  17
             embedderMonitor.generatingReportsView(outputDirectory, formats, viewResources);
 355  17
             viewGenerator.generateReportsView(outputDirectory, formats, viewResources);
 356  1
         } catch (RuntimeException e) {
 357  1
             embedderMonitor.reportsViewGenerationFailed(outputDirectory, formats, viewResources, e);
 358  1
             throw new ViewGenerationFailed(outputDirectory, formats, viewResources, e);
 359  16
         }
 360  16
         ReportsCount count = viewGenerator.getReportsCount();
 361  16
         embedderMonitor.reportsViewGenerated(count);
 362  16
         if (!embedderControls.ignoreFailureInView() && count.getScenariosFailed() > 0) {
 363  1
             throw new RunningStoriesFailed(count);
 364  
         }
 365  
 
 366  15
     }
 367  
 
 368  
     public void generateCrossReference() {
 369  11
         StoryReporterBuilder builder = configuration().storyReporterBuilder();
 370  11
         if (builder.hasCrossReference()){
 371  1
             builder.crossReference().outputToFiles(builder);
 372  
         }
 373  11
     }
 374  
 
 375  
     public void reportStepdocs() {
 376  1
         reportStepdocs(configuration(), candidateSteps());
 377  1
     }
 378  
 
 379  
     public void reportStepdocsAsEmbeddables(List<String> classNames) {
 380  0
         EmbedderControls embedderControls = embedderControls();
 381  0
         if (embedderControls.skip()) {
 382  0
             embedderMonitor.embeddablesSkipped(classNames);
 383  0
             return;
 384  
         }
 385  
 
 386  0
         for (Embeddable embeddable : embeddables(classNames, classLoader())) {
 387  0
             if (embeddable instanceof ConfigurableEmbedder) {
 388  0
                 ConfigurableEmbedder configurableEmbedder = (ConfigurableEmbedder) embeddable;
 389  0
                 reportStepdocs(configurableEmbedder.configuration(), configurableEmbedder.candidateSteps());
 390  0
             } else {
 391  0
                 embedderMonitor.embeddableNotConfigurable(embeddable.getClass().getName());
 392  
             }
 393  
         }
 394  0
     }
 395  
 
 396  
     public void reportStepdocs(Configuration configuration, List<CandidateSteps> candidateSteps) {
 397  1
         StepFinder finder = configuration.stepFinder();
 398  1
         StepdocReporter reporter = configuration.stepdocReporter();
 399  1
         List<Object> stepsInstances = finder.stepsInstances(candidateSteps);
 400  1
         reporter.stepdocs(finder.stepdocs(candidateSteps), stepsInstances);
 401  1
     }
 402  
 
 403  
     public void reportMatchingStepdocs(String stepAsString) {
 404  3
         Configuration configuration = configuration();
 405  3
         List<CandidateSteps> candidateSteps = candidateSteps();
 406  3
         StepFinder finder = configuration.stepFinder();
 407  3
         StepdocReporter reporter = configuration.stepdocReporter();
 408  3
         List<Stepdoc> matching = finder.findMatching(stepAsString, candidateSteps);
 409  3
         List<Object> stepsInstances = finder.stepsInstances(candidateSteps);
 410  3
         reporter.stepdocsMatching(stepAsString, matching, stepsInstances);
 411  3
     }
 412  
 
 413  
     public void processSystemProperties() {
 414  22
         Properties properties = systemProperties();
 415  22
         embedderMonitor.processingSystemProperties(properties);
 416  22
         if (!properties.isEmpty()) {
 417  1
             for (Object key : properties.keySet()) {
 418  2
                 String name = (String) key;
 419  2
                 String value = properties.getProperty(name);
 420  2
                 System.setProperty(name, value);
 421  2
                 embedderMonitor.systemPropertySet(name, value);
 422  2
             }
 423  
         }
 424  22
     }
 425  
 
 426  
     public EmbedderClassLoader classLoader() {
 427  13
         return classLoader;
 428  
     }
 429  
 
 430  
     public Configuration configuration() {
 431  103
         return configuration;
 432  
     }
 433  
 
 434  
     public List<CandidateSteps> candidateSteps() {
 435  34
         return candidateSteps;
 436  
     }
 437  
 
 438  
     public EmbedderControls embedderControls() {
 439  57
         return embedderControls;
 440  
     }
 441  
 
 442  
     public EmbedderMonitor embedderMonitor() {
 443  2
         return embedderMonitor;
 444  
     }
 445  
 
 446  
     public List<String> metaFilters() {
 447  2
         return metaFilters;
 448  
     }
 449  
 
 450  
     public StoryRunner storyRunner() {
 451  2
         return storyRunner;
 452  
     }
 453  
 
 454  
     public Properties systemProperties() {
 455  23
         return systemProperties;
 456  
     }
 457  
 
 458  
     public void useClassLoader(EmbedderClassLoader classLoader) {
 459  14
         this.classLoader = classLoader;
 460  14
     }
 461  
 
 462  
     public void useConfiguration(Configuration configuration) {
 463  23
         this.configuration = configuration;
 464  23
     }
 465  
 
 466  
     public void useCandidateSteps(List<CandidateSteps> candidateSteps) {
 467  23
         this.candidateSteps = candidateSteps;
 468  23
     }
 469  
 
 470  
     public void useEmbedderControls(EmbedderControls embedderControls) {
 471  27
         this.embedderControls = embedderControls;
 472  27
     }
 473  
 
 474  
     public void useEmbedderMonitor(EmbedderMonitor embedderMonitor) {
 475  1
         this.embedderMonitor = embedderMonitor;
 476  1
     }
 477  
 
 478  
     public void useMetaFilters(List<String> metaFilters) {
 479  2
         this.metaFilters = metaFilters;
 480  2
     }
 481  
 
 482  
     public void useStoryRunner(StoryRunner storyRunner) {
 483  1
         this.storyRunner = storyRunner;
 484  1
     }
 485  
 
 486  
     public void useSystemProperties(Properties systemProperties) {
 487  1
         this.systemProperties = systemProperties;
 488  1
     }
 489  
 
 490  
     @Override
 491  
     public String toString() {
 492  1
         return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE);
 493  
     }
 494  
 
 495  
     @SuppressWarnings("serial")
 496  
     public static class ClassLoadingFailed extends RuntimeException {
 497  
 
 498  
         public ClassLoadingFailed(String className, EmbedderClassLoader classLoader, Throwable cause) {
 499  1
             super("Failed to load class " + className + " with classLoader " + classLoader, cause);
 500  1
         }
 501  
 
 502  
     }
 503  
 
 504  
     @SuppressWarnings("serial")
 505  
     public static class AnnotatedEmbedderRunnerInstantiationFailed extends RuntimeException {
 506  
 
 507  
         public AnnotatedEmbedderRunnerInstantiationFailed(Class<?> runnerClass, String annotatedClassName,
 508  
                 EmbedderClassLoader classLoader, Throwable cause) {
 509  1
             super("Failed to instantiate annotated embedder runner " + runnerClass + " with annotatedClassName "
 510  
                     + annotatedClassName + " and classLoader " + classLoader, cause);
 511  1
         }
 512  
 
 513  
     }
 514  
 
 515  
     @SuppressWarnings("serial")
 516  
     public static class AnnotatedEmbedderRunFailed extends RuntimeException {
 517  
 
 518  
         public AnnotatedEmbedderRunFailed(AnnotatedEmbedderRunner runner, Throwable cause) {
 519  1
             super("Annotated embedder run failed with runner " + runner.toString(), cause);
 520  1
         }
 521  
 
 522  
     }
 523  
 
 524  
     @SuppressWarnings("serial")
 525  
     public static class RunningEmbeddablesFailed extends RuntimeException {
 526  
 
 527  
         public RunningEmbeddablesFailed(String name, Throwable cause) {
 528  1
             super("Failures in running embeddable " + name, cause);
 529  1
         }
 530  
 
 531  
         public RunningEmbeddablesFailed(BatchFailures batchFailures) {
 532  1
             super("Failures in running embeddables in batch: " + batchFailures);
 533  1
         }
 534  
 
 535  
     }
 536  
 
 537  
     @SuppressWarnings("serial")
 538  
     public static class RunningStoriesFailed extends RuntimeException {
 539  
 
 540  
         public RunningStoriesFailed(ReportsCount count) {
 541  1
             super("Failures in running " + count.getStories() + " stories containing " + count.getScenarios() + " scenarios (of which "
 542  
                     + count.getScenariosFailed() + " failed)");
 543  1
         }
 544  
 
 545  
         public RunningStoriesFailed(BatchFailures failures) {
 546  2
             super("Failures in running stories in batch: " + failures);
 547  2
         }
 548  
 
 549  
         public RunningStoriesFailed(String name, Throwable cause) {
 550  2
             super("Failures in running stories " + name, cause);
 551  2
         }
 552  
     }
 553  
 
 554  
     @SuppressWarnings("serial")
 555  
     public static class ViewGenerationFailed extends RuntimeException {
 556  
         public ViewGenerationFailed(File outputDirectory, List<String> formats, Properties viewResources,
 557  
                 RuntimeException cause) {
 558  1
             super("View generation failed to " + outputDirectory + " for formats " + formats + " and resources "
 559  
                     + viewResources, cause);
 560  1
         }
 561  
 
 562  
         public ViewGenerationFailed(File outputDirectory, StoryMaps storyMaps, Properties viewResources,
 563  
                 RuntimeException cause) {
 564  0
             super("View generation failed to " + outputDirectory + " for story maps " + storyMaps + " for resources "
 565  
                     + viewResources, cause);
 566  0
         }
 567  
     }
 568  
 
 569  
     /**
 570  
      * Non-threading ExecutorService for situations where thread count = 1
 571  
      */
 572  15
     public static class NonThreadingExecutorService implements ExecutorService {
 573  
         public void shutdown() {
 574  0
             throw new UnsupportedOperationException();
 575  
         }
 576  
 
 577  
         public List<Runnable> shutdownNow() {
 578  0
             throw new UnsupportedOperationException();
 579  
         }
 580  
 
 581  
         public boolean isShutdown() {
 582  0
             throw new UnsupportedOperationException();
 583  
         }
 584  
 
 585  
         public boolean isTerminated() {
 586  0
             throw new UnsupportedOperationException();
 587  
         }
 588  
 
 589  
         public boolean awaitTermination(long l, TimeUnit timeUnit) throws InterruptedException {
 590  0
             throw new UnsupportedOperationException();
 591  
         }
 592  
 
 593  
         public <T> Future<T> submit(Callable<T> callable) {
 594  26
             final Object[] rc = new Object[1];
 595  
             try {
 596  26
                 rc[0] = callable.call();
 597  0
             } catch (Exception e) {
 598  0
                 rc[0] = e;
 599  26
             }
 600  26
             return new Future<T>() {
 601  
 
 602  
                 public boolean cancel(boolean b) {
 603  0
                     throw new UnsupportedOperationException();
 604  
                 }
 605  
 
 606  
                 public boolean isCancelled() {
 607  0
                     throw new UnsupportedOperationException();
 608  
                 }
 609  
 
 610  
                 public boolean isDone() {
 611  26
                     return true;
 612  
                 }
 613  
 
 614  
                 @SuppressWarnings("unchecked")
 615  
                 public T get() throws InterruptedException, ExecutionException {
 616  26
                     return (T) rc[0];
 617  
                 }
 618  
 
 619  
                 public T get(long l, TimeUnit timeUnit) throws InterruptedException, ExecutionException,
 620  
                         TimeoutException {
 621  0
                     return get();
 622  
                 }
 623  
             };
 624  
         }
 625  
 
 626  
         public <T> Future<T> submit(Runnable runnable, T t) {
 627  0
             throw new UnsupportedOperationException();
 628  
         }
 629  
 
 630  
         public Future<?> submit(Runnable runnable) {
 631  0
             throw new UnsupportedOperationException();
 632  
         }
 633  
 
 634  
         public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> callables) throws InterruptedException {
 635  0
             throw new UnsupportedOperationException();
 636  
         }
 637  
 
 638  
         public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> callables, long l, TimeUnit timeUnit)
 639  
                 throws InterruptedException {
 640  0
             throw new UnsupportedOperationException();
 641  
         }
 642  
 
 643  
         public <T> T invokeAny(Collection<? extends Callable<T>> callables) throws InterruptedException,
 644  
                 ExecutionException {
 645  0
             throw new UnsupportedOperationException();
 646  
         }
 647  
 
 648  
         public <T> T invokeAny(Collection<? extends Callable<T>> callables, long l, TimeUnit timeUnit)
 649  
                 throws InterruptedException, ExecutionException, TimeoutException {
 650  0
             throw new UnsupportedOperationException();
 651  
         }
 652  
 
 653  
         public void execute(Runnable runnable) {
 654  0
             throw new UnsupportedOperationException();
 655  
         }
 656  
     }
 657  
 
 658  26
     public static class EnqueuedStory implements Callable<ThrowableStory> {
 659  
         private final String storyPath;
 660  
         private final Configuration configuration;
 661  
         private final List<CandidateSteps> candidateSteps;
 662  
         private final Story story;
 663  
         private final MetaFilter filter;
 664  
         private final EmbedderControls embedderControls;
 665  
         private final BatchFailures batchFailures;
 666  
         private final EmbedderMonitor embedderMonitor;
 667  
         private final StoryRunner storyRunner;
 668  
 
 669  
         public EnqueuedStory(String storyPath, Configuration configuration, List<CandidateSteps> candidateSteps,
 670  
                 Story story, MetaFilter filter, EmbedderControls embedderControls, BatchFailures batchFailures,
 671  26
                 EmbedderMonitor embedderMonitor, StoryRunner storyRunner) {
 672  26
             this.storyPath = storyPath;
 673  26
             this.configuration = configuration;
 674  26
             this.candidateSteps = candidateSteps;
 675  26
             this.story = story;
 676  26
             this.filter = filter;
 677  26
             this.embedderControls = embedderControls;
 678  26
             this.batchFailures = batchFailures;
 679  26
             this.embedderMonitor = embedderMonitor;
 680  26
             this.storyRunner = storyRunner;
 681  26
         }
 682  
 
 683  
         public ThrowableStory call() throws Exception {
 684  
             try {
 685  26
                 embedderMonitor.runningStory(storyPath);
 686  26
                 storyRunner.run(configuration, candidateSteps, story, filter);
 687  8
             } catch (Throwable e) {
 688  8
                 if (embedderControls.batch()) {
 689  
                     // collect and postpone decision to throw exception
 690  4
                     batchFailures.put(storyPath, e);
 691  
                 } else {
 692  4
                     if (embedderControls.ignoreFailureInStories()) {
 693  2
                         embedderMonitor.storyFailed(storyPath, e);
 694  
                     } else {
 695  2
                         return new ThrowableStory(new RunningStoriesFailed(storyPath, e), story);
 696  
                     }
 697  
                 }
 698  18
             }
 699  24
             return new ThrowableStory(null, story);
 700  
         }
 701  
     }
 702  28
     public static class ThrowableStory {
 703  
         private Throwable throwable;
 704  
         private Story story;
 705  
 
 706  26
         public ThrowableStory(Throwable throwable, Story story) {
 707  26
             this.throwable = throwable;
 708  26
             this.story = story;
 709  26
         }
 710  
 
 711  
         public Story getStory() {
 712  0
             return story;
 713  
         }
 714  
     }
 715  
 }