Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Core] Support parallel execution of pickles (#1389)
Adds supports for parallel execution of pickles to cucumber-jvm # Added --threads argument to runtime options Allows users of the CLI to specify the (max) number of threads to be used to run the tests. TestNG/JUnit users should consult their documentation on how to run JUnit/TestNG in parallel. Note that JUnit will only run features in parallel, not scenarios. # Concurrent Events During parallel executing events from the execution of different pickles may interleave. To avoid breaking existing Formatters, these will now receive all test events after the run is complete. Because we are unable to infer whether JUnit/TestNG run in parallel the assumption is that they are and their formatter will always get all events after the run. Formatters that can handle concurrent events can events in real time by implementing the ConcurrentEventListener. # New formatter introduced TimelineFormatter Which produces reports using vsjis.org timeline to highlight which feature was run on which Thread and when.
- Loading branch information
1 parent
88c5f16
commit f840358
Showing
87 changed files
with
3,825 additions
and
1,927 deletions.
There are no files selected for viewing
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 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
78 changes: 78 additions & 0 deletions
78
core/src/main/java/cucumber/api/event/CanonicalEventOrder.java
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
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,78 @@ | |||
package cucumber.api.event; | |||
|
|||
import java.util.Comparator; | |||
import java.util.List; | |||
|
|||
import static java.util.Arrays.asList; | |||
|
|||
final class CanonicalEventOrder implements Comparator<Event> { | |||
|
|||
private static final FixedEventOrderComparator fixedOrder = new FixedEventOrderComparator(); | |||
private static final TestCaseEventComparator testCaseOrder = new TestCaseEventComparator(); | |||
|
|||
@Override | |||
public int compare(Event a, Event b) { | |||
int fixedOrder = CanonicalEventOrder.fixedOrder.compare(a, b); | |||
if (fixedOrder != 0) { | |||
return fixedOrder; | |||
} | |||
|
|||
if (!(a instanceof TestCaseEvent && b instanceof TestCaseEvent)) { | |||
return fixedOrder; | |||
} | |||
|
|||
return testCaseOrder.compare((TestCaseEvent) a, (TestCaseEvent) b); | |||
} | |||
|
|||
private static final class FixedEventOrderComparator implements Comparator<Event> { | |||
|
|||
private final List<Class<? extends Event>> fixedOrder = asList( | |||
(Class<? extends Event>) | |||
TestRunStarted.class, | |||
TestSourceRead.class, | |||
SnippetsSuggestedEvent.class, | |||
TestCaseEvent.class, | |||
TestRunFinished.class | |||
); | |||
|
|||
@Override | |||
public int compare(final Event a, final Event b) { | |||
return Integer.compare(requireInFixOrder(a.getClass()), requireInFixOrder(b.getClass())); | |||
} | |||
|
|||
private int requireInFixOrder(Class<? extends Event> o) { | |||
int index = findInFixedOrder(o); | |||
if (index < 0) { | |||
throw new IllegalStateException(o + "was not in " + fixedOrder); | |||
} | |||
return index; | |||
} | |||
|
|||
private int findInFixedOrder(Class<? extends Event> o) { | |||
for (int i = 0; i < fixedOrder.size(); i++) { | |||
if (fixedOrder.get(i).isAssignableFrom(o)) { | |||
return i; | |||
} | |||
} | |||
return -1; | |||
} | |||
} | |||
|
|||
private static final class TestCaseEventComparator implements Comparator<TestCaseEvent> { | |||
|
|||
@Override | |||
public int compare(TestCaseEvent a, TestCaseEvent b) { | |||
int uri = a.testCase.getUri().compareTo(b.testCase.getUri()); | |||
if (uri != 0) { | |||
return uri; | |||
} | |||
|
|||
int line = Integer.compare(a.testCase.getLine(), b.testCase.getLine()); | |||
if(line != 0){ | |||
return line; | |||
} | |||
|
|||
return Long.compare(a.getTimeStamp(), b.getTimeStamp()); | |||
} | |||
} | |||
} |
37 changes: 37 additions & 0 deletions
37
core/src/main/java/cucumber/api/event/ConcurrentEventListener.java
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
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,37 @@ | |||
package cucumber.api.event; | |||
|
|||
/** | |||
* When cucumber executes test in parallel or in a framework | |||
* that supports parallel execution (e.g. JUnit or TestNG) | |||
* {@link cucumber.api.TestCase} events from different | |||
* pickles may interleave. | |||
* <p> | |||
* This interface marks an {@link EventListener} as capable of | |||
* understanding interleaved pickle events. | |||
* <p> | |||
* While running tests in parallel cucumber makes the | |||
* following guarantees. | |||
* <p> | |||
* 1. The event publisher is synchronized. Events are not | |||
* handled concurrently. | |||
* <p> | |||
* 2. For test cases executed on different threads the callbacks | |||
* registered on the event publisher will be called by | |||
* different threads. I.e. Thread.currentThread() | |||
* will return different a different thread for two test cases | |||
* executed on a different thread (but not necessarily the | |||
* executing thread). | |||
* <p> | |||
* | |||
* @see Event | |||
*/ | |||
public interface ConcurrentEventListener { | |||
|
|||
/** | |||
* Set the event publisher. The formatter can register event listeners with the publisher. | |||
* | |||
* @param publisher the event publisher | |||
*/ | |||
void setEventPublisher(EventPublisher publisher); | |||
|
|||
} |
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 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
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -1,7 +1,35 @@ | |||
package cucumber.api.event; | package cucumber.api.event; | ||
|
|
||
import java.util.Comparator; | |||
|
|||
public interface Event { | public interface Event { | ||
|
|
||
/** | |||
* When pickles are executed in parallel or random order | |||
* events can be produced with a partial ordering. | |||
* <p> | |||
* The canonical order is the order in which these events | |||
* would have been generated had cucumber executed these | |||
* pickles is executed in a serial fashion. | |||
* <p> | |||
* In canonical order events are first ordered by type: | |||
* <ol> | |||
* <li>TestRunStarted | |||
* <li>TestSourceRead | |||
* <li>SnippetsSuggestedEvent | |||
* <li>TestCaseEvent | |||
* <li>TestRunFinished | |||
* </ol> | |||
* <p> | |||
* Then TestCaseEvents are ordered by | |||
* <ol> | |||
* <li>uri | |||
* <li>line | |||
* <li>timestamp | |||
* </ol> | |||
*/ | |||
Comparator<Event> CANONICAL_ORDER = new CanonicalEventOrder(); | |||
|
|||
Long getTimeStamp(); | Long getTimeStamp(); | ||
|
|
||
} | } |
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 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
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -0,0 +1,17 @@ | |||
package cucumber.api.event; | |||
|
|||
import cucumber.api.TestCase; | |||
|
|||
public abstract class TestCaseEvent extends TimeStampedEvent { | |||
|
|||
final TestCase testCase; | |||
|
|||
TestCaseEvent(Long timeStamp, TestCase testCase) { | |||
super(timeStamp); | |||
this.testCase = testCase; | |||
} | |||
|
|||
public TestCase getTestCase() { | |||
return testCase; | |||
} | |||
} |
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 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 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
Oops, something went wrong.