nl.hsac.fitnesse.junit.HsacFitNesseRunner Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hsac-fitnesse-fixtures Show documentation
Show all versions of hsac-fitnesse-fixtures Show documentation
Fixtures to assist in testing via FitNesse
package nl.hsac.fitnesse.junit;
import fitnesse.ContextConfigurator;
import fitnesse.FitNesseContext;
import fitnesse.components.PluginsClassLoaderFactory;
import fitnesse.junit.DescriptionFactory;
import fitnesse.junit.FitNesseRunner;
import fitnesse.reporting.RerunSuiteFormatter;
import fitnesse.testrunner.MultipleTestsRunner;
import fitnesse.testrunner.run.TestRun;
import nl.hsac.fitnesse.fixture.Environment;
import nl.hsac.fitnesse.fixture.slim.web.LayoutTest;
import nl.hsac.fitnesse.fixture.slim.web.SeleniumDriverSetup;
import nl.hsac.fitnesse.fixture.util.FileUtil;
import nl.hsac.fitnesse.fixture.util.selenium.driverfactory.DriverFactory;
import nl.hsac.fitnesse.junit.selenium.LocalSeleniumDriverClassFactoryFactory;
import nl.hsac.fitnesse.junit.selenium.LocalSeleniumDriverFactoryFactory;
import nl.hsac.fitnesse.junit.selenium.SeleniumDriverFactoryFactory;
import nl.hsac.fitnesse.junit.selenium.SeleniumGridDriverFactoryFactory;
import nl.hsac.fitnesse.junit.selenium.SeleniumJsonGridDriverFactoryFactory;
import nl.hsac.fitnesse.junit.selenium.SimpleSeleniumGridDriverFactoryFactory;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.filefilter.NotFileFilter;
import org.apache.commons.io.filefilter.WildcardFileFilter;
import org.apache.commons.lang3.StringUtils;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.model.InitializationError;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* JUnit Runner to run a FitNesse suite or page as JUnit test.
*
* The suite/page to run must be specified either via the Java property
* 'fitnesseSuiteToRun', or by adding a {@link FitNesseRunner.Suite} annotation to the test class.
* If both are present the system property is used.
*
* The Selenium driver used for tests may be overridden (from what is configured in the wiki)
* by specifying the property 'seleniumGridUrl' and either 'seleniumBrowser' or 'seleniumCapabilities'.
* The default timeout (in seconds) for Selenium tests may be overridden by specifying the property
* 'seleniumDefaultTimeout'.
*
* The HTML generated for each page is saved in the location specified by the system property 'fitnesseResultsDir',
* or in the location configured using the {@link FitNesseRunner.OutputDir} annotation, or in target/fitnesse-results.
*/
public class HsacFitNesseRunner extends FitNesseRunner {
/**
* The FilesSectionCopy
annotation specifies which directories in the FitNesseRoot files
* section to exclude from tests output (which makes them available in tests and in the generated test reports).
* Each excludes can use wildcards.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FilesSectionCopy {
List DEFAULT_EXCLUDES = Arrays.asList(
"testResults", "testProgress", // FitNesse
"screenshots", "pagesources", "downloads", // BrowserTest
"galen-reports", // LayoutTest
"fileFixture", // FileFixture
"test", // HsacExamples.SlimTests.UtilityFixtures.FileFixture
"galenExamples", // HsacExamples.SlimTests.BrowserTest.LayoutTest
"httpPostExamples", // HsacExamples.SlimTests.HttpTest.HttpPostFileTest
"Desktop.ini", // Windows
".DS_Store", // macOS
".svn"); // Subversion
String[] exclude() default {};
boolean addDefaultExcludes() default true;
}
/** Output path for HTML results */
public final static String FITNESSE_RESULTS_PATH_OVERRIDE_VARIABLE_NAME = "fitnesseResultsDir";
public final static String FITNESSE_RESULTS_PATH = "target/fitnesse-results";
/** Property to override suite to run */
public final static String SUITE_OVERRIDE_VARIABLE_NAME = "fitnesseSuiteToRun";
public final static String SUITE_FILTER_STRATEGY_OVERRIDE_VARIABLE_NAME = "suiteFilterStrategy";
public final static String SUITE_FILTER_OVERRIDE_VARIABLE_NAME = "suiteFilter";
public final static String EXCLUDE_SUITE_FILTER_OVERRIDE_VARIABLE_NAME = "excludeSuiteFilter";
public final static String SELENIUM_DEFAULT_TIMEOUT_PROP = "seleniumDefaultTimeout";
public final static String RE_RUN_SUITE_LOCATION_OVERRIDE_VARIABLE_NAME = "reRunSuiteLocation";
protected final List factoryFactories = new ArrayList<>();
public HsacFitNesseRunner(Class> suiteClass) throws InitializationError {
super(suiteClass);
try {
factoryFactories.add(new SimpleSeleniumGridDriverFactoryFactory());
factoryFactories.add(new SeleniumGridDriverFactoryFactory());
factoryFactories.add(new SeleniumJsonGridDriverFactoryFactory());
factoryFactories.add(new LocalSeleniumDriverFactoryFactory());
factoryFactories.add(new LocalSeleniumDriverClassFactoryFactory());
Environment environment = Environment.getInstance();
// we include images in output so build server will have single
// directory containing both HTML results and the images created by the tests
// we must ensure any files present in the wiki's files section are also present there, so tests
// can use them
String outputDir = getOutputDir(suiteClass);
new File(outputDir).mkdirs();
String fitNesseDir = getFitNesseDir(suiteClass);
environment.setFitNesseDir(fitNesseDir);
String srcRootDir = fitNesseDir + "/" + getFitNesseRoot(suiteClass);
environment.setFitNesseRoot(srcRootDir);
String srcFilesDir = environment.getFitNesseFilesSectionDir();
environment.setFitNesseRoot(outputDir);
String targetFilesDir = environment.getFitNesseFilesSectionDir();
copyFilesToOutputDir(suiteClass, srcFilesDir, targetFilesDir);
} catch (Exception e) {
throw new InitializationError(e);
}
}
protected void copyFilesToOutputDir(Class> suiteClass, String srcFilesDir, String targetFilesDir) throws IOException {
File srcDir = new File(srcFilesDir);
if (srcDir.exists()) {
FileFilter fileSectionFilter = getFileSectionCopyFilter(suiteClass);
FileUtils.copyDirectory(srcDir, new File(targetFilesDir), fileSectionFilter);
}
}
protected FileFilter getFileSectionCopyFilter(Class> suiteClass) {
List excludes = getFileSectionCopyExcludes(suiteClass);
return new NotFileFilter(new WildcardFileFilter.Builder().setWildcards(excludes).get());
}
protected List getFileSectionCopyExcludes(Class> suiteClass) {
List excludes = FilesSectionCopy.DEFAULT_EXCLUDES;
FilesSectionCopy fsAnn = suiteClass.getAnnotation(FilesSectionCopy.class);
if (fsAnn != null) {
excludes = new ArrayList<>();
String[] explicitExcludes = fsAnn.exclude();
if (explicitExcludes.length > 0) {
excludes.addAll(Arrays.asList(explicitExcludes));
}
if (fsAnn.addDefaultExcludes()) {
excludes.addAll(FilesSectionCopy.DEFAULT_EXCLUDES);
}
}
return excludes;
}
@Override
protected String getSuiteName(Class> klass) throws InitializationError {
String name = System.getProperty(SUITE_OVERRIDE_VARIABLE_NAME);
if (StringUtils.isEmpty(name)) {
Suite nameAnnotation = klass.getAnnotation(Suite.class);
if (nameAnnotation == null) {
throw new InitializationError("There must be a @Suite annotation");
}
name = nameAnnotation.value();
}
return name;
}
@Override
protected String getFitNesseDir(Class> suiteClass) throws InitializationError {
String dir = "wiki";
if (suiteClass.isAnnotationPresent(FitnesseDir.class)) {
dir = super.getFitNesseDir(suiteClass);
}
return dir;
}
@Override
protected String getOutputDir(Class> klass) throws InitializationError {
String dir = System.getProperty(FITNESSE_RESULTS_PATH_OVERRIDE_VARIABLE_NAME);
if (StringUtils.isEmpty(dir)) {
dir = FITNESSE_RESULTS_PATH;
if (klass.isAnnotationPresent(OutputDir.class)) {
dir = super.getOutputDir(klass);
}
}
return dir;
}
@Override
protected String getFitNesseRoot(Class> suiteClass) {
String root = ContextConfigurator.DEFAULT_ROOT;
if (suiteClass.isAnnotationPresent(FitnesseDir.class)) {
root = super.getFitNesseRoot(suiteClass);
}
return root;
}
@Override
protected FitNesseContext createContext(Class> suiteClass) throws Exception {
// disable maven-classpath-plugin, we expect all jars to be loaded as part of this jUnit run
System.setProperty("fitnesse.wikitext.widgets.MavenClasspathSymbolType.Disable", "true");
ClassLoader cl = PluginsClassLoaderFactory.getClassLoader(getFitNesseDir(suiteClass));
ContextConfigurator configurator = initContextConfigurator().withClassLoader(cl);
return configurator.makeFitNesseContext();
}
@Override
protected void runPages(TestRun run, RunNotifier notifier) {
boolean seleniumConfigOverridden = configureSeleniumIfNeeded();
try {
super.runPages(run, notifier);
} finally {
if (seleniumConfigOverridden) {
try {
shutdownSelenium();
}
catch (Exception e) {
System.err.println("Error shutting down selenium");
e.printStackTrace();
}
}
try {
Class> suiteClass = getTestClass().getJavaClass();
String outputDir = getOutputDir(suiteClass);
String suiteName = getSuiteName(suiteClass);
String filename = suiteName + ".html";
File overviewFile = new File(outputDir, filename);
if (overviewFile.exists()) {
String path = overviewFile.getAbsolutePath();
String overviewHtml = FileUtil.streamToString(new FileInputStream(path), path);
if (overviewHtml != null) {
String indexHtml = getIndexHtmlContent(overviewHtml);
FileUtil.writeFile(new File(outputDir, "index.html").getAbsolutePath(), indexHtml);
}
}
} catch (Exception e) {
System.err.println("Unable to create index.html for top level suite");
e.printStackTrace();
}
}
}
@Override
protected void addTestSystemListeners(RunNotifier notifier, MultipleTestsRunner testRunner, Class> suiteClass, DescriptionFactory descriptionFactory) {
super.addTestSystemListeners(notifier, testRunner, suiteClass, descriptionFactory);
try {
String fitNesseRootDir = getReRunSuiteLocation(suiteClass);
testRunner.addTestSystemListener(new RerunSuiteFormatter(new File(fitNesseRootDir, "ReRunLastFailures.wiki")));
} catch (Exception e) {
System.err.println("Unable to create re-run suite generator: " + e);
}
}
protected String getReRunSuiteLocation(Class> suiteClass) throws InitializationError {
String reRunSuiteLocation = System.getProperty(RE_RUN_SUITE_LOCATION_OVERRIDE_VARIABLE_NAME);
if (StringUtils.isEmpty(reRunSuiteLocation)) {
reRunSuiteLocation = getFitNesseDir(suiteClass) + "/" + getFitNesseRoot(suiteClass);
}
return reRunSuiteLocation;
}
@Override
protected boolean getSuiteFilterAndStrategy(Class> klass) throws Exception {
String strategy = System.getProperty(SUITE_FILTER_STRATEGY_OVERRIDE_VARIABLE_NAME);
if (StringUtils.isEmpty(strategy)) {
return super.getSuiteFilterAndStrategy(klass);
} else {
return strategy.equalsIgnoreCase("and");
}
}
@Override
protected String getSuiteFilter(Class> klass) throws Exception {
String suiteFilter = System.getProperty(SUITE_FILTER_OVERRIDE_VARIABLE_NAME);
if (StringUtils.isEmpty(suiteFilter)) {
suiteFilter = super.getSuiteFilter(klass);
}
return suiteFilter;
}
@Override
protected String getExcludeSuiteFilter(Class> klass) throws Exception {
String excludeSuiteFilter = System.getProperty(EXCLUDE_SUITE_FILTER_OVERRIDE_VARIABLE_NAME);
if (StringUtils.isEmpty(excludeSuiteFilter)) {
excludeSuiteFilter = super.getExcludeSuiteFilter(klass);
}
return excludeSuiteFilter;
}
/**
* Determines whether system properties should override Selenium configuration in wiki.
* If so Selenium will be configured according to property values, and locked so that wiki pages
* no longer control Selenium setup.
* @return true if Selenium was configured.
*/
protected boolean configureSeleniumIfNeeded() {
setSeleniumDefaultTimeOut();
try {
DriverFactory factory = null;
SeleniumDriverFactoryFactory factoryFactory = getSeleniumDriverFactoryFactory();
if (factoryFactory != null) {
factory = factoryFactory.getDriverFactory();
if (factory != null) {
SeleniumDriverSetup.lockConfig();
Environment.getInstance().getSeleniumDriverManager().setFactory(factory);
}
}
return factory != null;
} catch (Exception e) {
throw new RuntimeException("Error overriding Selenium config", e);
}
}
protected void setSeleniumDefaultTimeOut() {
String propValue = System.getProperty(SELENIUM_DEFAULT_TIMEOUT_PROP);
if (StringUtils.isNotEmpty(propValue)) {
try {
int timeoutSeconds = Integer.parseInt(propValue);
Environment.getInstance().getSeleniumDriverManager().setDefaultTimeoutSeconds(timeoutSeconds);
} catch (NumberFormatException e) {
throw new RuntimeException("Bad " + SELENIUM_DEFAULT_TIMEOUT_PROP + " system property: " + propValue, e);
}
}
}
protected SeleniumDriverFactoryFactory getSeleniumDriverFactoryFactory() {
SeleniumDriverFactoryFactory result = null;
for (SeleniumDriverFactoryFactory factory : factoryFactories) {
if (factory.willOverride()) {
result = factory;
break;
}
}
return result;
}
protected void shutdownSelenium() {
SeleniumDriverSetup.unlockConfig();
new SeleniumDriverSetup().stopDriver();
}
protected String getIndexHtmlContent(String overviewHtml) {
String result = overviewHtml;
String runSummary = getRunSummary();
if (!"".equals(runSummary)) {
result = overviewHtml.replaceFirst("
© 2015 - 2025 Weber Informatics LLC | Privacy Policy