Skip to content

Commit 2a74b02

Browse files
committed
[Core] Add TestRunStarted event, let Stats handle the exit code
Add the TestRunStarted event and present the duration between the TestRunStarted and TestRunFinished events in the summary print out. Move the handling of exit code and errors to the summary print out to the Stats class.
1 parent 4fd209f commit 2a74b02

File tree

6 files changed

+138
-177
lines changed

6 files changed

+138
-177
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package cucumber.api.event;
2+
3+
public final class TestRunStarted extends TimeStampedEvent {
4+
5+
public TestRunStarted(Long timeStamp) {
6+
super(timeStamp);
7+
}
8+
}

core/src/main/java/cucumber/runtime/Runtime.java

+5-101
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,8 @@
11
package cucumber.runtime;
22

3-
import cucumber.api.Pending;
4-
import cucumber.api.Result;
53
import cucumber.api.StepDefinitionReporter;
64
import cucumber.api.SummaryPrinter;
7-
import cucumber.api.event.EventHandler;
8-
import cucumber.api.event.TestCaseFinished;
95
import cucumber.api.event.TestRunFinished;
10-
import cucumber.api.event.TestStepFinished;
11-
import cucumber.api.formatter.Formatter;
126
import cucumber.runner.EventBus;
137
import cucumber.runner.Runner;
148
import cucumber.runner.TimeService;
@@ -22,7 +16,6 @@
2216
import java.io.IOException;
2317
import java.io.PrintStream;
2418
import java.util.ArrayList;
25-
import java.util.Arrays;
2619
import java.util.Collection;
2720
import java.util.List;
2821
import java.util.Map;
@@ -33,50 +26,17 @@
3326
*/
3427
public class Runtime {
3528

36-
private static final String[] ASSUMPTION_VIOLATED_EXCEPTIONS = {
37-
"org.junit.AssumptionViolatedException",
38-
"org.junit.internal.AssumptionViolatedException"
39-
};
40-
41-
static {
42-
Arrays.sort(ASSUMPTION_VIOLATED_EXCEPTIONS);
43-
}
44-
45-
private static final byte ERRORS = 0x1;
46-
47-
private final Stats stats;
48-
UndefinedStepsTracker undefinedStepsTracker = new UndefinedStepsTracker(); // package private to be avaiable for tests.
29+
final Stats stats; // package private to be avaiable for tests.
30+
private final UndefinedStepsTracker undefinedStepsTracker = new UndefinedStepsTracker();
4931

5032
private final RuntimeOptions runtimeOptions;
5133

52-
private final List<Throwable> errors = new ArrayList<Throwable>();
5334
private final ResourceLoader resourceLoader;
5435
private final ClassLoader classLoader;
5536
private final Runner runner;
5637
private final List<PicklePredicate> filters;
5738
private final EventBus bus;
5839
private final Compiler compiler = new Compiler();
59-
private final EventHandler<TestStepFinished> stepFinishedHandler = new EventHandler<TestStepFinished>() {
60-
@Override
61-
public void receive(TestStepFinished event) {
62-
Result result = event.result;
63-
if (result.getError() != null) {
64-
addError(result.getError());
65-
}
66-
if (event.testStep.isHook()) {
67-
addHookToCounterAndResult(result);
68-
} else {
69-
addStepToCounterAndResult(result);
70-
}
71-
}
72-
};
73-
private final EventHandler<TestCaseFinished> testCaseFinishedHandler = new EventHandler<TestCaseFinished>() {
74-
@Override
75-
public void receive(TestCaseFinished event) {
76-
stats.addScenario(event.result.getStatus(), event.testCase.getScenarioDesignation());
77-
}
78-
};
79-
8040
public Runtime(ResourceLoader resourceLoader, ClassFinder classFinder, ClassLoader classLoader, RuntimeOptions runtimeOptions) {
8141
this(resourceLoader, classLoader, loadBackends(resourceLoader, classFinder), runtimeOptions);
8242
}
@@ -116,8 +76,7 @@ public Runtime(ResourceLoader resourceLoader, ClassLoader classLoader, Collectio
11676
this.filters.add(new LinePredicate(lineFilters));
11777
}
11878

119-
bus.registerHandlerFor(TestStepFinished.class, stepFinishedHandler);
120-
bus.registerHandlerFor(TestCaseFinished.class, testCaseFinishedHandler);
79+
stats.setEventPublisher(bus);
12180
undefinedStepsTracker.setEventPublisher(bus);
12281
runtimeOptions.setEventBus(bus);
12382
}
@@ -127,10 +86,6 @@ private static Collection<? extends Backend> loadBackends(ResourceLoader resourc
12786
return reflections.instantiateSubclasses(Backend.class, "cucumber.runtime", new Class[]{ResourceLoader.class}, new Object[]{resourceLoader});
12887
}
12988

130-
public void addError(Throwable error) {
131-
errors.add(error);
132-
}
133-
13489
/**
13590
* This is the main entry point. Used from CLI, but not from JUnit.
13691
*/
@@ -192,40 +147,11 @@ void printStats(PrintStream out) {
192147
}
193148

194149
public List<Throwable> getErrors() {
195-
return errors;
150+
return stats.getErrors();
196151
}
197152

198153
public byte exitStatus() {
199-
byte result = 0x0;
200-
if (hasErrors() || hasUndefinedOrPendingStepsAndIsStrict()) {
201-
result |= ERRORS;
202-
}
203-
return result;
204-
}
205-
206-
private boolean hasUndefinedOrPendingStepsAndIsStrict() {
207-
return runtimeOptions.isStrict() && hasUndefinedOrPendingSteps();
208-
}
209-
210-
private boolean hasUndefinedOrPendingSteps() {
211-
return hasUndefinedSteps() || hasPendingSteps();
212-
}
213-
214-
private boolean hasUndefinedSteps() {
215-
return undefinedStepsTracker.hasUndefinedSteps();
216-
}
217-
218-
private boolean hasPendingSteps() {
219-
return !errors.isEmpty() && !hasErrors();
220-
}
221-
222-
private boolean hasErrors() {
223-
for (Throwable error : errors) {
224-
if (!isPending(error) && !isAssumptionViolated(error)) {
225-
return true;
226-
}
227-
}
228-
return false;
154+
return stats.exitStatus(runtimeOptions.isStrict());
229155
}
230156

231157
public List<String> getSnippets() {
@@ -236,28 +162,6 @@ public Glue getGlue() {
236162
return runner.getGlue();
237163
}
238164

239-
public static boolean isPending(Throwable t) {
240-
if (t == null) {
241-
return false;
242-
}
243-
return t.getClass().isAnnotationPresent(Pending.class);
244-
}
245-
246-
public static boolean isAssumptionViolated(Throwable t) {
247-
if (t == null) {
248-
return false;
249-
}
250-
return Arrays.binarySearch(ASSUMPTION_VIOLATED_EXCEPTIONS, t.getClass().getName()) >= 0;
251-
}
252-
253-
private void addStepToCounterAndResult(Result result) {
254-
stats.addStep(result);
255-
}
256-
257-
private void addHookToCounterAndResult(Result result) {
258-
stats.addHookTime(result.getDuration());
259-
}
260-
261165
public EventBus getEventBus() {
262166
return bus;
263167
}

core/src/main/java/cucumber/runtime/RuntimeOptions.java

+2
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import cucumber.api.SnippetType;
44
import cucumber.api.StepDefinitionReporter;
55
import cucumber.api.SummaryPrinter;
6+
import cucumber.api.event.TestRunStarted;
67
import cucumber.api.formatter.ColorAware;
78
import cucumber.api.formatter.Formatter;
89
import cucumber.api.formatter.StrictAware;
@@ -308,6 +309,7 @@ private void addKeywordRow(List<List<String>> table, String key, List<String> ke
308309
public List<CucumberFeature> cucumberFeatures(ResourceLoader resourceLoader, EventBus bus) {
309310
List<CucumberFeature> features = load(resourceLoader, featurePaths, System.out);
310311
getPlugins(); // to create the formatter objects
312+
bus.send(new TestRunStarted(bus.startTime()));
311313
for (CucumberFeature feature : features) {
312314
feature.sendTestSourceRead(bus);
313315
}

core/src/main/java/cucumber/runtime/Stats.java

+74-14
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
package cucumber.runtime;
22

33
import cucumber.api.Result;
4+
import cucumber.api.event.EventHandler;
5+
import cucumber.api.event.EventListener;
6+
import cucumber.api.event.EventPublisher;
7+
import cucumber.api.event.TestCaseFinished;
8+
import cucumber.api.event.TestRunFinished;
9+
import cucumber.api.event.TestRunStarted;
10+
import cucumber.api.event.TestStepFinished;
411
import cucumber.runtime.formatter.AnsiFormats;
512
import cucumber.runtime.formatter.Format;
613
import cucumber.runtime.formatter.Formats;
@@ -13,17 +20,50 @@
1320
import java.util.List;
1421
import java.util.Locale;
1522

16-
class Stats {
23+
class Stats implements EventListener {
1724
public static final long ONE_SECOND = 1000000000;
1825
public static final long ONE_MINUTE = 60 * ONE_SECOND;
26+
private static final byte ERRORS = 0x1;
1927
private SubCounts scenarioSubCounts = new SubCounts();
2028
private SubCounts stepSubCounts = new SubCounts();
29+
private long startTime = 0;
2130
private long totalDuration = 0;
2231
private Formats formats;
2332
private Locale locale;
24-
private List<String> failedScenarios = new ArrayList<String>();
25-
private List<String> pendingScenarios = new ArrayList<String>();
26-
private List<String> undefinedScenarios = new ArrayList<String>();
33+
private final List<String> failedScenarios = new ArrayList<String>();
34+
private final List<String> pendingScenarios = new ArrayList<String>();
35+
private final List<String> undefinedScenarios = new ArrayList<String>();
36+
private final List<Throwable> errors = new ArrayList<Throwable>();
37+
private final EventHandler<TestRunStarted> testRunStartedHandler = new EventHandler<TestRunStarted>() {
38+
@Override
39+
public void receive(TestRunStarted event) {
40+
setStartTime(event.getTimeStamp());
41+
}
42+
};
43+
private final EventHandler<TestStepFinished> stepFinishedHandler = new EventHandler<TestStepFinished>() {
44+
@Override
45+
public void receive(TestStepFinished event) {
46+
Result result = event.result;
47+
if (result.getError() != null) {
48+
addError(result.getError());
49+
}
50+
if (!event.testStep.isHook()) {
51+
addStep(result.getStatus());
52+
}
53+
}
54+
};
55+
private final EventHandler<TestCaseFinished> testCaseFinishedHandler = new EventHandler<TestCaseFinished>() {
56+
@Override
57+
public void receive(TestCaseFinished event) {
58+
addScenario(event.result.getStatus(), event.testCase.getScenarioDesignation());
59+
}
60+
};
61+
private final EventHandler<TestRunFinished> testRunFinishedHandler = new EventHandler<TestRunFinished>() {
62+
@Override
63+
public void receive(TestRunFinished event) {
64+
setFinishTime(event.getTimeStamp());
65+
}
66+
};
2767

2868
public Stats(boolean monochrome) {
2969
this(monochrome, Locale.getDefault());
@@ -38,6 +78,27 @@ public Stats(boolean monochrome, Locale locale) {
3878
}
3979
}
4080

81+
82+
@Override
83+
public void setEventPublisher(EventPublisher publisher) {
84+
publisher.registerHandlerFor(TestRunStarted.class, testRunStartedHandler);
85+
publisher.registerHandlerFor(TestStepFinished.class, stepFinishedHandler);
86+
publisher.registerHandlerFor(TestCaseFinished.class, testCaseFinishedHandler);
87+
publisher.registerHandlerFor(TestRunFinished.class, testRunFinishedHandler);
88+
}
89+
90+
public List<Throwable> getErrors() {
91+
return errors;
92+
}
93+
94+
public byte exitStatus(boolean isStrict) {
95+
byte result = 0x0;
96+
if (!failedScenarios.isEmpty() || (isStrict && (!pendingScenarios.isEmpty() || !undefinedScenarios.isEmpty()))) {
97+
result |= ERRORS;
98+
}
99+
return result;
100+
}
101+
41102
public void printStats(PrintStream out, boolean isStrict) {
42103
printNonZeroResultScenarios(out, isStrict);
43104
if (stepSubCounts.getTotal() == 0) {
@@ -116,21 +177,20 @@ private void printScenarios(PrintStream out, List<String> scenarios, Result.Type
116177
}
117178
}
118179

119-
public void addStep(Result result) {
120-
addResultToSubCount(stepSubCounts, result.getStatus());
121-
addTime(result.getDuration());
180+
void addStep(Result.Type resultStatus) {
181+
addResultToSubCount(stepSubCounts, resultStatus);
122182
}
123183

124-
public void addScenario(Result.Type resultStatus) {
125-
addResultToSubCount(scenarioSubCounts, resultStatus);
184+
private void addError(Throwable error) {
185+
errors.add(error);
126186
}
127187

128-
public void addHookTime(Long duration) {
129-
addTime(duration);
188+
void setStartTime(Long startTime) {
189+
this.startTime = startTime;
130190
}
131191

132-
private void addTime(Long duration) {
133-
totalDuration += duration != null ? duration : 0;
192+
void setFinishTime(Long finishTime) {
193+
this.totalDuration = finishTime - startTime;
134194
}
135195

136196
private void addResultToSubCount(SubCounts subCounts, Result.Type resultStatus) {
@@ -152,7 +212,7 @@ private void addResultToSubCount(SubCounts subCounts, Result.Type resultStatus)
152212
}
153213
}
154214

155-
public void addScenario(Result.Type resultStatus, String scenarioDesignation) {
215+
void addScenario(Result.Type resultStatus, String scenarioDesignation) {
156216
addResultToSubCount(scenarioSubCounts, resultStatus);
157217
switch (resultStatus) {
158218
case FAILED:

0 commit comments

Comments
 (0)