Skip to content

adding rerun functionality #1356

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
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: 2 additions & 0 deletions android/src/main/java/cucumber/runtime/android/Arguments.java
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,8 @@ private String getCucumberOptionsString(final Bundle bundle) {
appendOption(sb, "--plugin", bundle.getString(key));
} else if ("tags".equals(key)) {
appendOption(sb, "--tags", bundle.getString(key));
} else if ("rerun".equals(key)) {
appendOption(sb, "--rerun", bundle.getString(key));
} else if ("name".equals(key)) {
appendOption(sb, "--name", bundle.getString(key));
} else if ("dryRun".equals(key) && getBooleanArgument(bundle, key)) {
Expand Down
42 changes: 33 additions & 9 deletions core/src/main/java/cucumber/api/TestCase.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package cucumber.api;

import java.util.List;

import cucumber.api.event.TestCaseFinished;
import cucumber.api.event.TestCaseStarted;
import cucumber.runner.EventBus;
Expand All @@ -8,12 +10,12 @@
import gherkin.pickles.PickleLocation;
import gherkin.pickles.PickleTag;

import java.util.List;

public class TestCase {
private final PickleEvent pickleEvent;
private final List<TestStep> testSteps;
private final boolean dryRun;
private int rerun_count = 1;
private String testCaseId = "";

/**
* Creates a new instance of a test case.
Expand All @@ -24,7 +26,7 @@ public class TestCase {
*/
@Deprecated
public TestCase(List<TestStep> testSteps, PickleEvent pickleEvent) {
this(testSteps, pickleEvent, false);
this(testSteps, pickleEvent, false, 1);
}

/**
Expand All @@ -36,10 +38,11 @@ public TestCase(List<TestStep> testSteps, PickleEvent pickleEvent) {
* @deprecated not part of the public api
*/
@Deprecated
public TestCase(List<TestStep> testSteps, PickleEvent pickleEvent, boolean dryRun) {
public TestCase(List<TestStep> testSteps, PickleEvent pickleEvent, boolean dryRun, int rerun_count) {
this.testSteps = testSteps;
this.pickleEvent = pickleEvent;
this.dryRun = dryRun;
this.rerun_count = rerun_count;
}

/**
Expand All @@ -54,12 +57,24 @@ public void run(EventBus bus) {
Long startTime = bus.getTime();
bus.send(new TestCaseStarted(startTime, this));
ScenarioImpl scenarioResult = new ScenarioImpl(bus, pickleEvent);
for (TestStep step : testSteps) {
Result stepResult = step.run(bus, pickleEvent.pickle.getLanguage(), scenarioResult, skipNextStep);
if (!stepResult.is(Result.Type.PASSED)) {
skipNextStep = true;
int counter = 0;
while (counter < rerun_count && (scenarioResult.getStatus() != Result.Type.PASSED ||
scenarioResult.getStatus() == Result.Type.UNDEFINED)) {
if (!this.dryRun) {
skipNextStep = false;
}
scenarioResult = new ScenarioImpl(bus, pickleEvent);
scenarioResult.setScenarioId(this.testCaseId);
boolean reRunTest = true;
for (TestStep step : testSteps) {
Result stepResult = step.run(bus, pickleEvent.pickle.getLanguage(), scenarioResult, skipNextStep, reRunTest);
if (!stepResult.is(Result.Type.PASSED)) {
skipNextStep = true;
}
scenarioResult.add(stepResult);
reRunTest = false;
}
scenarioResult.add(stepResult);
counter++;
}
Long stopTime = bus.getTime();
bus.send(new TestCaseFinished(stopTime, this, new Result(scenarioResult.getStatus(), stopTime - startTime, scenarioResult.getError())));
Expand Down Expand Up @@ -92,4 +107,13 @@ private String fileColonLine(PickleLocation location) {
public List<PickleTag> getTags() {
return pickleEvent.pickle.getTags();
}


public String getTestCaseId() {
return testCaseId;
}

public void setTestCaseId(String testCaseId) {
this.testCaseId = testCaseId;
}
}
11 changes: 6 additions & 5 deletions core/src/main/java/cucumber/api/TestStep.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package cucumber.api;

import java.util.Arrays;
import java.util.List;

import cucumber.api.event.TestStepFinished;
import cucumber.api.event.TestStepStarted;
import cucumber.runner.EventBus;
Expand All @@ -9,9 +12,6 @@
import gherkin.pickles.Argument;
import gherkin.pickles.PickleStep;

import java.util.Arrays;
import java.util.List;

public abstract class TestStep {
private static final String[] ASSUMPTION_VIOLATED_EXCEPTIONS = {
"org.junit.AssumptionViolatedException",
Expand Down Expand Up @@ -75,11 +75,12 @@ public List<cucumber.runtime.Argument> getDefinitionArgument() {
* @deprecated not part of the public api
*/
@Deprecated
public Result run(EventBus bus, String language, Scenario scenario, boolean skipSteps) {
public Result run(EventBus bus, String language, Scenario scenario, boolean skipSteps, boolean reRunTestCase) {
Long startTime = bus.getTime();
bus.send(new TestStepStarted(startTime, this));
bus.send(new TestStepStarted(startTime, this, reRunTestCase));
Result.Type status;
Throwable error = null;

try {
status = executeStep(language, scenario, skipSteps);
} catch (Throwable t) {
Expand Down
4 changes: 3 additions & 1 deletion core/src/main/java/cucumber/api/event/TestStepStarted.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@

public final class TestStepStarted extends TimeStampedEvent {
public final TestStep testStep;
public boolean reRunTestCase;

public TestStepStarted(Long timeStamp, TestStep testStep) {
public TestStepStarted(Long timeStamp, TestStep testStep, boolean reRunTestCase) {
super(timeStamp);
this.testStep = testStep;
this.reRunTestCase = reRunTestCase;
}

}
2 changes: 1 addition & 1 deletion core/src/main/java/cucumber/runner/Runner.java
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ private TestCase createTestCaseForPickle(PickleEvent pickleEvent) {
addTestStepsForAfterHooks(testSteps, pickleEvent.pickle.getTags());
}
}
return new TestCase(testSteps, pickleEvent, runtimeOptions.isDryRun());
return new TestCase(testSteps, pickleEvent, runtimeOptions.isDryRun(), runtimeOptions.getReRunCounter());
}

private void addTestStepsForPickleSteps(List<TestStep> testSteps, PickleEvent pickleEvent) {
Expand Down
16 changes: 8 additions & 8 deletions core/src/main/java/cucumber/runtime/Runtime.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,13 @@
package cucumber.runtime;

import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

import cucumber.api.StepDefinitionReporter;
import cucumber.api.SummaryPrinter;
import cucumber.api.event.TestRunFinished;
Expand All @@ -13,14 +21,6 @@
import gherkin.pickles.Compiler;
import gherkin.pickles.Pickle;

import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;

/**
* This is the main entry point for running Cucumber features.
*/
Expand Down
36 changes: 23 additions & 13 deletions core/src/main/java/cucumber/runtime/RuntimeOptions.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,17 @@
package cucumber.runtime;

import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.regex.Pattern;

import cucumber.api.Plugin;
import cucumber.api.SnippetType;
import cucumber.api.StepDefinitionReporter;
Expand All @@ -8,8 +20,8 @@
import cucumber.api.formatter.ColorAware;
import cucumber.api.formatter.Formatter;
import cucumber.api.formatter.StrictAware;
import cucumber.runner.EventBus;
import cucumber.deps.com.thoughtworks.xstream.annotations.XStreamConverter;
import cucumber.runner.EventBus;
import cucumber.runtime.formatter.PluginFactory;
import cucumber.runtime.io.ResourceLoader;
import cucumber.runtime.model.CucumberFeature;
Expand All @@ -21,18 +33,6 @@
import gherkin.GherkinDialectProvider;
import gherkin.IGherkinDialectProvider;

import java.io.InputStreamReader;
import java.io.Reader;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.regex.Pattern;

import static cucumber.runtime.model.CucumberFeature.load;
import static cucumber.util.FixJava.join;
import static cucumber.util.FixJava.map;
Expand Down Expand Up @@ -77,6 +77,7 @@ public String map(String keyword) {
private SnippetType snippetType = SnippetType.UNDERSCORE;
private boolean pluginNamesInstantiated;
private EventBus bus;
private int reRunCounter=1;

/**
* Create a new instance from a string of options, for example:
Expand Down Expand Up @@ -155,6 +156,11 @@ private void parse(List<String> args) {
parsedTagFilters.add(args.remove(0));
} else if (arg.equals("--plugin") || arg.equals("--add-plugin") || arg.equals("-p")) {
parsedPluginData.addPluginName(args.remove(0), arg.equals("--add-plugin"));
} else if (arg.equals("--rerun") || arg.equals("-r")) {
reRunCounter = new Integer(args.remove(0));
} else if (arg.equals("--format") || arg.equals("-f")) {
System.err.println("WARNING: Cucumber-JVM's --format option is deprecated. Please use --plugin instead.");
parsedPluginData.addPluginName(args.remove(0), true);
} else if (arg.equals("--no-dry-run") || arg.equals("--dry-run") || arg.equals("-d")) {
dryRun = !arg.startsWith("--no-");
} else if (arg.equals("--no-strict") || arg.equals("--strict") || arg.equals("-s")) {
Expand Down Expand Up @@ -513,4 +519,8 @@ public void updateNameList(List<String> nameList) {
void setEventBus(EventBus bus) {
this.bus = bus;
}

public int getReRunCounter() {
return reRunCounter;
}
}
20 changes: 12 additions & 8 deletions core/src/main/java/cucumber/runtime/ScenarioImpl.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
package cucumber.runtime;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import cucumber.api.Result;
import cucumber.api.Scenario;
import cucumber.api.event.EmbedEvent;
Expand All @@ -10,13 +17,6 @@
import gherkin.pickles.PickleLocation;
import gherkin.pickles.PickleTag;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import static java.util.Arrays.asList;

public class ScenarioImpl implements Scenario {
Expand All @@ -25,7 +25,7 @@ public class ScenarioImpl implements Scenario {
private final List<PickleTag> tags;
private final String uri;
private final String scenarioName;
private final String scenarioId;
private String scenarioId;
private final List<Integer> scenarioLines;
private final EventBus bus;

Expand Down Expand Up @@ -99,6 +99,10 @@ public String getId() {
return scenarioId;
}

public void setScenarioId(String id) {
this.scenarioId = id;
}

@Override
public String getUri() {
return uri;
Expand Down
21 changes: 16 additions & 5 deletions core/src/main/java/cucumber/runtime/formatter/JSONFormatter.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
package cucumber.runtime.formatter;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import cucumber.api.HookType;
import cucumber.api.Result;
import cucumber.api.TestCase;
Expand Down Expand Up @@ -30,11 +35,6 @@
import gherkin.pickles.PickleTable;
import gherkin.pickles.PickleTag;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

final class JSONFormatter implements Formatter {
private String currentFeatureFile;
private List<Map<String, Object>> featureMaps = new ArrayList<Map<String, Object>>();
Expand Down Expand Up @@ -128,7 +128,17 @@ private void handleTestCaseStarted(TestCaseStarted event) {
currentStepsList = (List<Map<String, Object>>) currentElementMap.get("steps");
}

private void handleRerunTestCase() {
this.currentElementMap.put("steps", new ArrayList<Map<String, Object>>());
currentStepsList = (List<Map<String, Object>>) currentElementMap.get("steps");
this.currentElementMap.put("before", new ArrayList<Map<String, Object>>());
this.currentElementMap.put("after", new ArrayList<Map<String, Object>>());
}

private void handleTestStepStarted(TestStepStarted event) {
if (event.reRunTestCase) {
handleRerunTestCase();
}
if (!event.testStep.isHook()) {
if (isFirstStepAfterBackground(event.testStep)) {
currentElementMap = currentTestCaseMap;
Expand Down Expand Up @@ -185,6 +195,7 @@ private Map<String, Object> createTestCase(TestCase testCase) {
TestSourcesModel.AstNode astNode = testSources.getAstNode(currentFeatureFile, testCase.getLine());
if (astNode != null) {
testCaseMap.put("id", TestSourcesModel.calculateId(astNode));
testCase.setTestCaseId(TestSourcesModel.calculateId(astNode));
ScenarioDefinition scenarioDefinition = TestSourcesModel.getScenarioDefinition(astNode);
testCaseMap.put("keyword", scenarioDefinition.getKeyword());
testCaseMap.put("description", scenarioDefinition.getDescription() != null ? scenarioDefinition.getDescription() : "");
Expand Down
Loading