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