Skip to content
This repository has been archived by the owner on Nov 23, 2021. It is now read-only.

Cucumber retries #109

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ ext {
}

group = 'net.serenity-bdd'
version = versionCounter.nextVersion
version = '1.2.5-SNAPSHOT'// versionCounter.nextVersion


task createNewVersionTag(type: Exec) {
Expand Down
59 changes: 59 additions & 0 deletions src/main/java/cucumber/runtime/junit/SerenityExamplesRunner.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package cucumber.runtime.junit;

import cucumber.runtime.Runtime;
import cucumber.runtime.model.CucumberExamples;
import cucumber.runtime.model.CucumberScenario;
import org.junit.runner.Runner;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.Suite;
import org.junit.runners.model.InitializationError;

import java.util.ArrayList;
import java.util.List;

public class SerenityExamplesRunner extends Suite {

private int retryCount;
private Runtime runtime;

protected SerenityExamplesRunner(
Runtime runtime,
CucumberExamples cucumberExamplesValue,
JUnitReporter jUnitReporter,
int retryCount) throws InitializationError {
super(SerenityExamplesRunner.class,
buildRunners(runtime, cucumberExamplesValue, jUnitReporter));
this.runtime = runtime;
this.retryCount = retryCount;
}

private static List<Runner> buildRunners(
Runtime runtime,
CucumberExamples cucumberExamples,
JUnitReporter jUnitReporter) {
List<Runner> runners = new ArrayList<>();
List<CucumberScenario> exampleScenarios = cucumberExamples.createExampleScenarios();
for (CucumberScenario scenario : exampleScenarios) {
try {
ExecutionUnitRunner exampleScenarioRunner
= new ExecutionUnitRunner(runtime, scenario, jUnitReporter);
runners.add(exampleScenarioRunner);
} catch (InitializationError initializationError) {
initializationError.printStackTrace();
}
}
return runners;
}

@Override
protected void runChild(Runner runner, RunNotifier notifier) {
for (int i = 0; i <= this.retryCount; i++) {
runner.run(notifier);
if(runtime.exitStatus() == 0) {
break;
} else {
runtime.getErrors().clear();
}
}
}
}
121 changes: 121 additions & 0 deletions src/main/java/cucumber/runtime/junit/SerenityFeatureRunner.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package cucumber.runtime.junit;

import cucumber.runtime.CucumberException;
import cucumber.runtime.Runtime;
import cucumber.runtime.model.CucumberFeature;
import cucumber.runtime.model.CucumberScenario;
import cucumber.runtime.model.CucumberScenarioOutline;
import cucumber.runtime.model.CucumberTagStatement;
import org.junit.runner.Description;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.ParentRunner;
import org.junit.runners.model.InitializationError;

import java.util.ArrayList;
import java.util.List;

public class SerenityFeatureRunner extends FeatureRunner {
private final List<ParentRunner> children = new ArrayList<ParentRunner>();

private int maxRetryCount = 0;
private int retries = 0;
private int scenarioCount = 0;
private Runtime runtime;
private CucumberFeature cucumberFeature;
private JUnitReporter jUnitReporter;

public SerenityFeatureRunner(
CucumberFeature cucumberFeature,
Runtime runtime,
JUnitReporter jUnitReporter,
int maxRetryCount)
throws InitializationError {
super(cucumberFeature, runtime, jUnitReporter);
this.cucumberFeature = cucumberFeature;
this.runtime = runtime;
this.jUnitReporter = jUnitReporter;
this.maxRetryCount = maxRetryCount;
buildFeatureElementRunners();
}

private void buildFeatureElementRunners() {
for (CucumberTagStatement cucumberTagStatement : cucumberFeature.getFeatureElements()) {
try {
ParentRunner featureElementRunner;
if (cucumberTagStatement instanceof CucumberScenario) {
featureElementRunner = new ExecutionUnitRunner(
runtime, (CucumberScenario) cucumberTagStatement, jUnitReporter);
} else {
featureElementRunner = new SerenityScenarioOutlineRunner(
runtime, (CucumberScenarioOutline) cucumberTagStatement, jUnitReporter, maxRetryCount);
}
children.add(featureElementRunner);
} catch (InitializationError e) {
throw new CucumberException("Failed to create scenario runner", e);
}
}
}

@Override
protected void runChild(ParentRunner child, RunNotifier notifier) {
child.run(notifier);
if(runtime.exitStatus() != 0) {
retry(notifier, child);
}
this.setScenarioCount(this.getScenarioCount() + 1);
retries = 0;
}

private CucumberScenario getCurrentScenario() {
CucumberTagStatement cucumberTagStatement
= this.cucumberFeature.getFeatureElements().get(this.getScenarioCount());
if (cucumberTagStatement instanceof CucumberScenarioOutline) {
return null;
}
return (CucumberScenario) cucumberTagStatement;
}

public void retry(RunNotifier notifier, ParentRunner child) {
ParentRunner featureElementRunner = null;
CucumberScenario scenario = getCurrentScenario();
if (scenario == null) {
return;
}
while (retries < maxRetryCount) {
try {
featureElementRunner = new ExecutionUnitRunner(runtime, scenario, jUnitReporter);
} catch (InitializationError e) {
throw new CucumberException("Failed to create scenario runner", e);
}
try {
featureElementRunner.run(notifier);
} catch(Throwable thr) {
thr.printStackTrace();
}
if(runtime.exitStatus() == 0) {
break;
} else {
retries = retries + 1;
runtime.getErrors().clear();
}
}
}

@Override
protected List<ParentRunner> getChildren() {
return children;
}

@Override
protected Description describeChild(ParentRunner child) {
return child.getDescription();
}

public int getScenarioCount() {
return scenarioCount;
}

public void setScenarioCount(int scenarioCountValue) {
this.scenarioCount = scenarioCountValue;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package cucumber.runtime.junit;

import cucumber.runtime.Runtime;
import cucumber.runtime.model.CucumberExamples;
import cucumber.runtime.model.CucumberScenarioOutline;
import org.junit.runner.Runner;
import org.junit.runners.Suite;
import org.junit.runners.model.InitializationError;

import java.util.ArrayList;
import java.util.List;

public class SerenityScenarioOutlineRunner extends Suite {

public SerenityScenarioOutlineRunner(
Runtime runtimeValue,
CucumberScenarioOutline cucumberScenarioOutlineValue,
JUnitReporter jUnitReporterValue,
int retryCount) throws InitializationError {
super(null, buildRunners(runtimeValue, cucumberScenarioOutlineValue, jUnitReporterValue, retryCount));
}

private static List<Runner> buildRunners(
Runtime runtime,
CucumberScenarioOutline cucumberScenarioOutline,
JUnitReporter jUnitReporter,
int retryCount) throws InitializationError {
List<Runner> runners = new ArrayList<Runner>();
for (CucumberExamples cucumberExamples : cucumberScenarioOutline.getCucumberExamplesList()) {
runners.add(new SerenityExamplesRunner(runtime, cucumberExamples, jUnitReporter, retryCount));
}
return runners;
}
}
110 changes: 104 additions & 6 deletions src/main/java/net/serenitybdd/cucumber/CucumberWithSerenity.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,35 +3,83 @@
import ch.lambdaj.Lambda;
import ch.lambdaj.function.convert.Converter;
import com.google.common.base.Splitter;
import cucumber.api.junit.Cucumber;
import cucumber.runtime.ClassFinder;
import cucumber.runtime.Runtime;
import cucumber.runtime.RuntimeOptions;
import cucumber.runtime.RuntimeOptionsFactory;
import cucumber.runtime.io.MultiLoader;
import cucumber.runtime.io.ResourceLoader;
import cucumber.runtime.io.ResourceLoaderClassFinder;
import cucumber.runtime.junit.JUnitOptions;
import cucumber.runtime.junit.JUnitReporter;
import cucumber.runtime.junit.SerenityFeatureRunner;
import cucumber.runtime.model.CucumberFeature;
import net.thucydides.core.ThucydidesSystemProperty;
import net.thucydides.core.guice.Injectors;
import net.thucydides.core.util.EnvironmentVariables;
import net.thucydides.core.webdriver.Configuration;
import org.junit.runner.Description;
import org.junit.runner.notification.RunNotifier;
import org.junit.runners.ParentRunner;
import org.junit.runners.model.InitializationError;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import static ch.lambdaj.Lambda.on;
import static cucumber.runtime.junit.Assertions.assertNoCucumberAnnotatedMethods;
import static net.thucydides.core.ThucydidesSystemProperty.TEST_RETRY_COUNT_CUCUMBER;


/**
* Glue code for running Cucumber via Thucydides.
* Sets the Thucydides reporter.
*
* @author L.Carausu ([email protected])
*/
public class CucumberWithSerenity extends Cucumber {
public class CucumberWithSerenity extends ParentRunner<SerenityFeatureRunner> {

public CucumberWithSerenity(Class clazz) throws InitializationError, IOException
{
private JUnitReporter jUnitReporter;
private List<SerenityFeatureRunner> children = new ArrayList<>();
private Runtime runtime;
private List<CucumberFeature> cucumberFeatures;
private int maxRetryCount = 0;

public CucumberWithSerenity(Class clazz) throws InitializationError, IOException {
super(clazz);
initialize(clazz,Injectors.getInjector().getInstance(EnvironmentVariables.class));
}

public CucumberWithSerenity(Class clazz, EnvironmentVariables environmentVariables) throws InitializationError, IOException {
super(clazz);
initialize(clazz, environmentVariables);
}

private void initialize(Class clazz,EnvironmentVariables environmentVariables) throws InitializationError, IOException {
maxRetryCount = TEST_RETRY_COUNT_CUCUMBER.integerFrom(environmentVariables, 0);
ClassLoader classLoader = clazz.getClassLoader();
assertNoCucumberAnnotatedMethods(clazz);
RuntimeOptionsFactory runtimeOptionsFactory = new RuntimeOptionsFactory(clazz);
RuntimeOptions runtimeOptions = runtimeOptionsFactory.create();
ResourceLoader resourceLoader = new MultiLoader(classLoader);
runtime = createRuntime(resourceLoader, classLoader, runtimeOptions);

RUNTIME_OPTIONS.set(runtimeOptions);

final JUnitOptions junitOptions = new JUnitOptions(runtimeOptions.getJunitOptions());
cucumberFeatures = runtimeOptions.cucumberFeatures(resourceLoader);
jUnitReporter = new JUnitReporter(runtimeOptions.reporter(classLoader), runtimeOptions.formatter(classLoader), runtimeOptions.isStrict(), junitOptions);
addChildren(cucumberFeatures,maxRetryCount);
}

public CucumberWithSerenity withOutputDirectory(File outputDirectory)
{
Configuration systemConfiguration = Injectors.getInjector().getInstance(Configuration.class);
systemConfiguration.setOutputDirectory(outputDirectory);
return this;
}

private static ThreadLocal<RuntimeOptions> RUNTIME_OPTIONS = new ThreadLocal<>();
Expand All @@ -41,7 +89,13 @@ public static RuntimeOptions currentRuntimeOptions() {
}

/**
* Create the Runtime. Sets the Serenity runtime.
* Creates the Runtime. Sets the Serenity runtime.
* @param resourceLoader
* @param classLoader
* @param runtimeOptions
* @return cucumber Runtime
* @throws InitializationError
* @throws IOException
*/
protected cucumber.runtime.Runtime createRuntime(ResourceLoader resourceLoader,
ClassLoader classLoader,
Expand All @@ -51,7 +105,9 @@ protected cucumber.runtime.Runtime createRuntime(ResourceLoader resourceLoader,
return createSerenityEnabledRuntime(resourceLoader, classLoader, runtimeOptions);
}


private Collection<String> environmentSpecifiedTags(List<Object> existingTags) {

EnvironmentVariables environmentVariables = Injectors.getInjector().getInstance(EnvironmentVariables.class);
String tagsExpression = ThucydidesSystemProperty.TAGS.from(environmentVariables,"");
List<String> newTags = Lambda.convert(Splitter.on(",").trimResults().omitEmptyStrings().splitToList(tagsExpression),
Expand Down Expand Up @@ -83,7 +139,7 @@ private Runtime createSerenityEnabledRuntime(ResourceLoader resourceLoader,
ClassLoader classLoader,
RuntimeOptions runtimeOptions) {
Configuration systemConfiguration = Injectors.getInjector().getInstance(Configuration.class);
return createSerenityEnabledRuntime(resourceLoader, classLoader, runtimeOptions, systemConfiguration);
return createSerenityEnabledRuntime(resourceLoader, classLoader, runtimeOptions, systemConfiguration,maxRetryCount);
}

public static Runtime createSerenityEnabledRuntime(ResourceLoader resourceLoader,
Expand All @@ -96,4 +152,46 @@ public static Runtime createSerenityEnabledRuntime(ResourceLoader resourceLoader
RUNTIME_OPTIONS.set(runtimeOptions);
return new Runtime(resourceLoader, classFinder, classLoader, runtimeOptions);
}

public static Runtime createSerenityEnabledRuntime(ResourceLoader resourceLoader,
ClassLoader classLoader,
RuntimeOptions runtimeOptions,
Configuration systemConfiguration,
int maxRetryCount) {
ClassFinder classFinder = new ResourceLoaderClassFinder(resourceLoader, classLoader);
SerenityReporter reporter = new SerenityReporter(systemConfiguration);
reporter.setMaxRetryCount(maxRetryCount);
runtimeOptions.addPlugin(reporter);

RUNTIME_OPTIONS.set(runtimeOptions);

return new Runtime(resourceLoader, classFinder, classLoader, runtimeOptions);
}

@Override
protected Description describeChild(SerenityFeatureRunner child) {
return child.getDescription();
}

@Override
protected void runChild(SerenityFeatureRunner child, RunNotifier notifier) {
child.run(notifier);
}

private void addChildren(List<CucumberFeature> cucumberFeatures,int retryCount) throws InitializationError {
children.clear();
for (CucumberFeature cucumberFeature : cucumberFeatures) {
children.add(new SerenityFeatureRunner(cucumberFeature, runtime, jUnitReporter,retryCount));
}
}

@Override
public List<SerenityFeatureRunner> getChildren() {
return children;
}

public Runtime getRuntime() {
return runtime;
}

}
Loading