Last active
December 17, 2015 06:28
-
-
Save sethrylan/5565452 to your computer and use it in GitHub Desktop.
A PaxExam and Cucumber JUnit Test Runner
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* This class allows for running Cucumber features tests using PaxExam in-container testing. | |
* | |
* When added as a RunWith annotation to a test class | |
* @RunWith(PaxCucumber.class) | |
* this effectively means that | |
* @RunWith(PaxCucumber.class) and @RunWith(Cucumber.class) | |
* are used as test runners for that class. Cucumber and PaxExam are run | |
* in parallel, and any Cucumber tasks must manually verify that any PaxExam | |
* dependencies have been satisfied. | |
* | |
* @author sethrylan | |
*/ | |
public class PaxCucumber extends BlockJUnit4ClassRunner { | |
private PaxExam paxExamRunner; | |
private Cucumber cucumberRunner; | |
private final ExecutorService executorService = Executors.newCachedThreadPool(); | |
private static Logger logger = LoggerFactory.getLogger(PaxCucumber.class); | |
public PaxCucumber(Class<?> klass) throws InitializationError, Exception { | |
super(klass); | |
paxExamRunner = new PaxExam(klass); | |
cucumberRunner = new Cucumber(klass); | |
} | |
@Override | |
public void run(RunNotifier rn) { | |
PaxExamTask paxExamTask = new PaxExamTask(rn, paxExamRunner); | |
executorService.submit(paxExamTask); | |
CucumberTask cucumberTask = new CucumberTask(rn, cucumberRunner); | |
executorService.submit(cucumberTask); | |
executorService.shutdown() ; | |
try { | |
executorService.awaitTermination(1, TimeUnit.DAYS); | |
} catch (InterruptedException e) { | |
e.printStackTrace(); | |
} | |
} | |
public class PaxExamTask implements Callable<RunNotifier> { | |
private RunNotifier rn; | |
private PaxExam paxExamRunner; | |
public PaxExamTask(RunNotifier rn, PaxExam paxExamRunner) { | |
this.rn = rn; | |
this.paxExamRunner = paxExamRunner; | |
} | |
@Override | |
public RunNotifier call() throws Exception { | |
AbsoluteSingleton.getInstance().setValue(true); | |
this.paxExamRunner.run(this.rn); | |
logger.debug("PaxExamTask finished"); | |
return null; | |
} | |
} | |
public class CucumberTask implements Callable<RunNotifier> { | |
private RunNotifier rn; | |
private Cucumber cucumberRunner; | |
public CucumberTask(RunNotifier rn, Cucumber cucumberRunner) { | |
this.rn = rn; | |
this.cucumberRunner = cucumberRunner; | |
} | |
@Override | |
public RunNotifier call() throws Exception { | |
this.cucumberRunner.run(this.rn); | |
logger.debug("CucumberTask finished"); | |
AbsoluteSingleton.getInstance().setValue(false); | |
return null; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public abstract class PaxExamBaseIntegrationTest { | |
private static final String PROP_FRAGMENTS = "iehr.osgi.integrationTest.fragments"; | |
private static final String PROP_BUNDLES = "iehr.osgi.integrationTest.bundles"; | |
private static final String PROP_TIMEOUT = "iehr.osgi.integrationTest.paxexam.systemTimeout"; | |
private static final String PROP_CONFIG_DIR = "iehr.osgi.integrationTest.configDir"; | |
private Logger logger = LoggerFactory.getLogger(PaxExamBaseIntegrationTest.class); | |
@Inject | |
protected BundleContext ctx; | |
@Configuration | |
public Option[] config() { | |
List<Option> opts = new ArrayList<Option>(); | |
String fragments = System.getProperty(PROP_FRAGMENTS); | |
String bundles = System.getProperty(PROP_BUNDLES); | |
String timeout = System.getProperty(PROP_TIMEOUT); | |
String configDir = System.getProperty(PROP_CONFIG_DIR); | |
// Load the systemTimeout value, if specified. | |
opts.add(getTimeoutOption(System.getProperty(PROP_TIMEOUT))); | |
// Load the jUnit bundles | |
opts.add(junitBundles()); | |
// Load all bundle dependencies that are specified in the system | |
// property. | |
opts.addAll(getITestBundles(bundles)); | |
opts.addAll(getITestFragments(fragments)); | |
// Set the fileinstall directory to load Configuration Admin data | |
opts.add(getFileInstallConfigOption(configDir)); | |
return opts.toArray(new Option[opts.size()]); | |
} | |
private Option getTimeoutOption(String timeout) { | |
Option opt = null; | |
if ((timeout != null) && !"".equals(timeout)) | |
opt = systemTimeout(Integer.parseInt(timeout)); | |
return opt; | |
} | |
private Option getFileInstallConfigOption(String configDir) { | |
Option opt = null; | |
if ((configDir != null) && !"".equals(configDir)) | |
opt = frameworkProperty("felix.fileinstall.dir").value(configDir); | |
return opt; | |
} | |
private Collection<Option> getITestBundles(String bundleList) { | |
Collection<Option> opts = new HashSet<Option>(); | |
if ((bundleList != null) && !"".equals(bundleList)) { | |
// TODO: validate the string | |
for (String bundle : bundleList.split("::")) { | |
if (opts.contains(bundle)) | |
logger.debug("Loading Bundle --> " + bundle); | |
opts.add(bundle("file:" + bundle)); | |
} | |
} | |
return opts; | |
} | |
private Collection<Option> getITestFragments(String fragmentList) { | |
Collection<Option> opts = new HashSet<Option>(); | |
if ((fragmentList != null) && !"".equals(fragmentList)) { | |
// TODO: validate the string | |
for (String fragment : fragmentList.split("::")) { | |
if (opts.contains(fragment)) | |
logger.debug("Loading fragment --> " + fragment); | |
opts.add(bundle("file:" + fragment).noStart()); | |
} | |
} | |
return opts; | |
} | |
public void logOSGIBundles() { | |
assertNotNull(ctx); | |
int maxLen = 0; | |
for (Bundle bundle : ctx.getBundles()) { | |
if (bundle.getSymbolicName() != null) { | |
String name = bundle.getSymbolicName() + " (" | |
+ bundle.getVersion() + ")"; | |
if (maxLen < name.length()) | |
maxLen = name.length(); | |
} | |
} | |
StringBuffer dashes = new StringBuffer(); | |
for (int i = 0; i < maxLen; i++) | |
dashes.append("-"); | |
logger.info("INSTALLED BUNDLES"); | |
logger.info("-----------------"); | |
logger.info("Level | Bundle | Bundle State"); | |
logger.info("--------" + dashes + "------------"); | |
String format = "%1$5s | %2$-" + maxLen + "s | "; | |
for (Bundle bundle : ctx.getBundles()) { | |
BundleStartLevel bsl = bundle.adapt(BundleStartLevel.class); | |
String b = bundle.getSymbolicName() + " (" + bundle.getVersion() | |
+ ")"; | |
String msg = String.format(format, bsl.getStartLevel(), b) | |
+ getBundleStateString(bundle); | |
logger.info(msg); | |
} | |
} | |
private String getBundleStateString(Bundle bundle) { | |
int state = bundle.getState(); | |
if (state == Bundle.ACTIVE) { | |
return "Active"; | |
} else if (state == Bundle.INSTALLED) { | |
return "Installed"; | |
} else if (state == Bundle.RESOLVED) { | |
return "Resolved"; | |
} else if (state == Bundle.STARTING) { | |
return "Starting"; | |
} else if (state == Bundle.STOPPING) { | |
return "Stopping"; | |
} else { | |
return "Unknown"; | |
} | |
} | |
public void logOSGIServices(){ | |
try { | |
ServiceReference<?>[] refs = ctx.getAllServiceReferences(null, null); | |
List<String> serviceNames = new ArrayList<String>(); | |
if (refs != null) { | |
logger.info("OSGi Services (" + refs.length + ")"); | |
logger.info("-------------------------------"); | |
for (ServiceReference<?> r : refs) { | |
Object o = ctx.getService(r); | |
Class<?> c = o.getClass(); | |
logger.info("Service: " + c.getName()); | |
Type[] intfs = c.getGenericInterfaces(); | |
if (intfs.length != 0) { | |
for (Type intf : intfs) | |
logger.info(" - interface: " + intfs.toString()); | |
} | |
serviceNames.add(o.getClass().getName()); | |
ctx.ungetService(r); | |
} | |
/* | |
logger.info("OSGi Services (" + refs.length + ")"); | |
logger.info("-------------------------------"); | |
for (String name : serviceNames) { | |
logger.info("Service: " + name); | |
} | |
*/ | |
} | |
} | |
catch (InvalidSyntaxException e) { | |
logger.error("logOSGIServices() exception thrown: " + e.getCause()); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* An acceptance test which uses PaxExam in-container testing | |
* | |
* Cucumber.Options documentation at: | |
* http://cukes.info/api/cucumber/jvm/javadoc/cucumber/api/junit/Cucumber.Options.html | |
* http://emprovisetech.blogspot.com/2012/11/acceptance-testing-cucumber-jvm.html | |
* | |
*/ | |
@RunWith(PaxCucumber.class) | |
@ExamReactorStrategy(PerClass.class) | |
@Options( features = {"src/test/features"}, | |
glue = {"classpath:"}, | |
monochrome = false, | |
dryRun = false, | |
strict = false, | |
tags = {"~@WIP"}, | |
format = { "pretty", | |
"html:build/cucumber", | |
"junit:build/cucumber/junit.xml", | |
"json-pretty:build/cucumber-json-report.json"}) | |
public class RunCucumberTests extends PaxExamBaseIntegrationTest { | |
private static Logger logger = LoggerFactory.getLogger(RunCucumberTests.class); | |
static volatile Boolean keepRunning = true; | |
@Before | |
public void before() { | |
logOSGIBundles(); | |
} | |
@Test | |
public void runAcceptanceTests() throws Exception { | |
logger.debug("System-under-test created. Running acceptance tests."); | |
// wait until Cucumber finishes | |
while(AbsoluteSingleton.getInstance().getValue()) { | |
Thread.sleep(1000); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment