Skip to content

Commit 1f90854

Browse files
authored
[Core] Rework backend (#1776)
Introduces the backend module. With this module backend implementations only need to use dependencies from `io.cucumber.core.backend`. This will allow us to introduce the module system later on The implementation is not yet perfect. Classpath scanning and resource loading is located in other modules. Removing this depends on #1526 and removal of type registry configurer which depends on #1768 . Fixes #1386 because steps can now see if an exception came from user code or actual backend. Removes timeout which would close #1695 earlier then expected.
1 parent 14e6ffd commit 1f90854

File tree

113 files changed

+1081
-1593
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

113 files changed

+1081
-1593
lines changed

CHANGELOG.md

+5-8
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ Please see [CONTRIBUTING.md](https://github.com/cucumber/cucumber/blob/master/CO
2525
- cucumber.execution.dry-run
2626
- cucumber.execution.limit
2727
- cucumber.execution.order
28-
- cucumber.execution.parallel.config.fixed.parallelism
2928
- cucumber.execution.strict
3029
- cucumber.execution.wip
3130
- cucumber.feature
@@ -74,18 +73,16 @@ Please see [CONTRIBUTING.md](https://github.com/cucumber/cucumber/blob/master/CO
7473
- Adds dedicated `io.cucumber.docstring.DocString` object to use in step definitions
7574
- Adds `TypeRegistry.defineDocStringType`
7675
- Adds `@DocStringType` alternative for `TypeRegistry.defineDocStringType`
77-
78-
### Deprecated
79-
* [Core] Deprecate `timeout` ([#1506](https://github.com/cucumber/cucumber-jvm/issues/1506), [#1694](https://github.com/cucumber/cucumber-jvm/issues/1694) M.P. Korstanje)
80-
- Prefer using library based solutions
81-
* [JUnit 5 `Assertions.assertTimeout*`](https://junit.org/junit5/docs/5.0.1/api/org/junit/jupiter/api/Assertions.html#assertTimeout-java.time.Duration-org.junit.jupiter.api.function.Executable-)
82-
* [Awaitility](https://github.com/awaitility/awaitility)
83-
* [Guava `TimeLimiter`](https://github.com/google/guava/blob/master/guava/src/com/google/common/util/concurrent/TimeLimiter.java)
8476

8577
### Removed
8678
- [Core] Remove deprecated tag syntax.
8779
- [Core] Remove `StepDefinitionReporter` ([#1635](https://github.com/cucumber/cucumber-jvm/issues/1635) M.P. Korstanje, Tim te Beek)
8880
- Listen `StepDefined` events instead
81+
* [Core] Remove `timeout` ([#1506](https://github.com/cucumber/cucumber-jvm/issues/1506), [#1694](https://github.com/cucumber/cucumber-jvm/issues/1694) M.P. Korstanje)
82+
- Prefer using library based solutions
83+
* [JUnit 5 `Assertions.assertTimeout*`](https://junit.org/junit5/docs/5.0.1/api/org/junit/jupiter/api/Assertions.html#assertTimeout-java.time.Duration-org.junit.jupiter.api.function.Executable-)
84+
* [Awaitility](https://github.com/awaitility/awaitility)
85+
* [Guava `TimeLimiter`](https://github.com/google/guava/blob/master/guava/src/com/google/common/util/concurrent/TimeLimiter.java)
8986

9087
### Fixed
9188
- [Java8] Set default before hook order to the same after hook (1000)

core/src/main/java/io/cucumber/core/backend/Backend.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public interface Backend {
1919
* Invoked before a new scenario starts. Implementations should do any necessary
2020
* setup of new, isolated state here. Additional scenario scoped step definitions
2121
* can be loaded here. These step definitions should implement
22-
* {@link io.cucumber.core.runner.ScenarioScoped}
22+
* {@link ScenarioScoped}
2323
*/
2424
void buildWorld();
2525

Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
package io.cucumber.core.backend;
22

3-
import io.cucumber.core.io.ResourceLoader;
43
import org.apiguardian.api.API;
54

5+
import java.util.function.Supplier;
6+
67
@API(status = API.Status.STABLE)
78
public interface BackendProviderService {
89

9-
Backend create(Lookup lookup, Container container, ResourceLoader resourceLoader);
10+
Backend create(Lookup lookup, Container container, Supplier<ClassLoader> classLoader);
1011

1112
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package io.cucumber.core.backend;
2+
3+
public class CucumberBackendException extends RuntimeException {
4+
5+
public CucumberBackendException(String message) {
6+
super(message);
7+
}
8+
9+
public CucumberBackendException(String message, Throwable cause) {
10+
super(message, cause);
11+
}
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package io.cucumber.core.backend;
2+
3+
import java.lang.reflect.InvocationTargetException;
4+
5+
public class CucumberInvocationTargetException extends RuntimeException {
6+
7+
private final Located located;
8+
private final InvocationTargetException invocationTargetException;
9+
10+
public CucumberInvocationTargetException(Located located, InvocationTargetException invocationTargetException) {
11+
this.located = located;
12+
this.invocationTargetException = invocationTargetException;
13+
}
14+
15+
public Throwable getInvocationTargetExceptionCause() {
16+
return invocationTargetException.getCause();
17+
}
18+
19+
public Located getLocated() {
20+
return located;
21+
}
22+
}

core/src/main/java/io/cucumber/core/backend/DataTableTypeDefinition.java

+1-9
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,7 @@
44
import org.apiguardian.api.API;
55

66
@API(status = API.Status.STABLE)
7-
public interface DataTableTypeDefinition {
7+
public interface DataTableTypeDefinition extends Located {
88

99
DataTableType dataTableType();
10-
11-
/**
12-
* The source line where the data table type is defined.
13-
* Example: com/example/app/Cucumber.test():42
14-
*
15-
* @return The source line of the step definition.
16-
*/
17-
String getLocation();
1810
}

core/src/main/java/io/cucumber/core/backend/DefaultDataTableCellTransformerDefinition.java

+1-9
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,8 @@
44
import org.apiguardian.api.API;
55

66
@API(status = API.Status.STABLE)
7-
public interface DefaultDataTableCellTransformerDefinition {
7+
public interface DefaultDataTableCellTransformerDefinition extends Located {
88

99
TableCellByTypeTransformer tableCellByTypeTransformer();
1010

11-
/**
12-
* The source line where the default data table cell is defined.
13-
* Example: com/example/app/Cucumber.test():42
14-
*
15-
* @return The source line of the step definition.
16-
*/
17-
String getLocation();
18-
1911
}

core/src/main/java/io/cucumber/core/backend/DefaultDataTableEntryTransformerDefinition.java

+1-8
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,10 @@
44
import org.apiguardian.api.API;
55

66
@API(status = API.Status.STABLE)
7-
public interface DefaultDataTableEntryTransformerDefinition {
7+
public interface DefaultDataTableEntryTransformerDefinition extends Located {
88

99
boolean headersToProperties();
1010

1111
TableEntryByTypeTransformer tableEntryByTypeTransformer();
1212

13-
/**
14-
* The source line where the default table entry transformer is defined.
15-
* Example: com/example/app/Cucumber.test():42
16-
*
17-
* @return The source line of the step definition.
18-
*/
19-
String getLocation();
2013
}

core/src/main/java/io/cucumber/core/backend/DefaultParameterTransformerDefinition.java

+1-9
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,7 @@
44
import org.apiguardian.api.API;
55

66
@API(status = API.Status.STABLE)
7-
public interface DefaultParameterTransformerDefinition {
7+
public interface DefaultParameterTransformerDefinition extends Located{
88

99
ParameterByTypeTransformer parameterByTypeTransformer();
10-
11-
/**
12-
* The source line where the default parameter transformer is defined.
13-
* Example: com/example/app/Cucumber.test():42
14-
*
15-
* @return The source line of the step definition.
16-
*/
17-
String getLocation();
1810
}

core/src/main/java/io/cucumber/core/backend/DocStringTypeDefinition.java

+1-8
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,8 @@
44
import org.apiguardian.api.API;
55

66
@API(status = API.Status.EXPERIMENTAL)
7-
public interface DocStringTypeDefinition {
7+
public interface DocStringTypeDefinition extends Located{
88

99
DocStringType docStringType();
1010

11-
/**
12-
* The source line where the parameter type is defined.
13-
* Example: com/example/app/Cucumber.test():42
14-
*
15-
* @return The source line of the step definition.
16-
*/
17-
String getLocation();
1811
}

core/src/main/java/io/cucumber/core/backend/HookDefinition.java

+2-9
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,9 @@
33
import org.apiguardian.api.API;
44

55
@API(status = API.Status.STABLE)
6-
public interface HookDefinition {
7-
/**
8-
* The source line where the step definition is defined.
9-
* Example: com/example/app/Cucumber.test():42
10-
*
11-
* @return The source line where the step definition is defined.
12-
*/
13-
String getLocation();
6+
public interface HookDefinition extends Located {
147

15-
void execute(Scenario scenario) throws Throwable;
8+
void execute(Scenario scenario);
169

1710
String getTagExpression();
1811

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package io.cucumber.core.backend;
2+
3+
import org.apiguardian.api.API;
4+
5+
@API(status = API.Status.STABLE)
6+
public interface Located {
7+
8+
/**
9+
* @param stackTraceElement The location of the step.
10+
* @return Return true if this matches the location. This is used to filter
11+
* stack traces.
12+
*/
13+
boolean isDefinedAt(StackTraceElement stackTraceElement);
14+
15+
/**
16+
* The source line where the step definition is defined.
17+
* Example: com/example/app/Cucumber.test():42
18+
*
19+
* @return The source line of the step definition.
20+
*/
21+
String getLocation();
22+
23+
}

core/src/main/java/io/cucumber/core/backend/ParameterTypeDefinition.java

+1-8
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,8 @@
44
import org.apiguardian.api.API;
55

66
@API(status = API.Status.EXPERIMENTAL)
7-
public interface ParameterTypeDefinition {
7+
public interface ParameterTypeDefinition extends Located {
88

99
ParameterType<?> parameterType();
1010

11-
/**
12-
* The source line where the parameter type is defined.
13-
* Example: com/example/app/Cucumber.test():42
14-
*
15-
* @return The source line of the step definition.
16-
*/
17-
String getLocation();
1811
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package io.cucumber.core.backend;
2+
3+
/**
4+
* Marks a glue class as being scenario scoped.
5+
* <p>
6+
* Instances of scenario scoped glue can not be used between scenarios and will
7+
* be removed from the glue. This is useful when the glue holds a reference to
8+
* a scenario scoped object (e.g. a method closure).
9+
*/
10+
public interface ScenarioScoped {
11+
12+
}

core/src/main/java/io/cucumber/core/backend/Status.java

-17
Original file line numberDiff line numberDiff line change
@@ -11,21 +11,4 @@ public enum Status {
1111
AMBIGUOUS,
1212
FAILED,
1313
UNUSED;
14-
15-
public boolean is(Status status) {
16-
return this == status;
17-
}
18-
19-
public boolean isOk(boolean isStrict) {
20-
return hasAlwaysOkStatus() || !isStrict && hasOkWhenNotStrictStatus();
21-
}
22-
23-
private boolean hasAlwaysOkStatus() {
24-
return is(PASSED) || is(SKIPPED);
25-
}
26-
27-
private boolean hasOkWhenNotStrictStatus() {
28-
return is(UNDEFINED) || is(PENDING);
29-
}
30-
3114
}

core/src/main/java/io/cucumber/core/backend/StepDefinition.java

+4-18
Original file line numberDiff line numberDiff line change
@@ -5,37 +5,23 @@
55
import java.util.List;
66

77
@API(status = API.Status.STABLE)
8-
public interface StepDefinition {
8+
public interface StepDefinition extends Located {
99

1010
/**
1111
* Invokes the step definition. The method should raise a Throwable
1212
* if the invocation fails, which will cause the step to fail.
1313
*
1414
* @param args The arguments for the step
15-
* @throws Throwable in case of step failure.
15+
* @throws CucumberBackendException of a failure to invoke the step
16+
* @throws CucumberInvocationTargetException in case of a failure in the step.
1617
*/
17-
void execute(Object[] args) throws Throwable;
18-
19-
/**
20-
* @param stackTraceElement The location of the step.
21-
* @return Return true if this matches the location. This is used to filter
22-
* stack traces.
23-
*/
24-
boolean isDefinedAt(StackTraceElement stackTraceElement);
18+
void execute(Object[] args) throws CucumberBackendException, CucumberInvocationTargetException;
2519

2620
/**
2721
* @return parameter information or null when the language does not provide parameter information
2822
*/
2923
List<ParameterInfo> parameterInfos();
3024

31-
/**
32-
* The source line where the step definition is defined.
33-
* Example: com/example/app/Cucumber.test():42
34-
*
35-
* @return The source line of the step definition.
36-
*/
37-
String getLocation();
38-
3925
/**
4026
* @return the pattern associated with this instance. Used for error reporting only.
4127
*/

core/src/main/java/io/cucumber/core/options/Constants.java

-8
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,6 @@ public final class Constants {
4444
*/
4545
public static final String EXECUTION_ORDER_PROPERTY_NAME = "cucumber.execution.order";
4646

47-
/**
48-
* Property name used to determine the desired parallelism for the
49-
* {@link Runtime} configuration: {@value}
50-
* <p>
51-
* No default value; must be an integer.
52-
*/
53-
public static final String EXECUTION_PARALLEL_CONFIG_FIXED_PARALLELISM_PROPERTY_NAME = "cucumber.execution.parallel.config.fixed.parallelism";
54-
5547
/**
5648
* Property name used to enable strict execution: {@value}
5749
* <p>

core/src/main/java/io/cucumber/core/options/CucumberPropertiesParser.java

-7
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919
import static io.cucumber.core.options.Constants.EXECUTION_DRY_RUN_PROPERTY_NAME;
2020
import static io.cucumber.core.options.Constants.EXECUTION_LIMIT_PROPERTY_NAME;
2121
import static io.cucumber.core.options.Constants.EXECUTION_ORDER_PROPERTY_NAME;
22-
import static io.cucumber.core.options.Constants.EXECUTION_PARALLEL_CONFIG_FIXED_PARALLELISM_PROPERTY_NAME;
2322
import static io.cucumber.core.options.Constants.EXECUTION_STRICT_PROPERTY_NAME;
2423
import static io.cucumber.core.options.Constants.FEATURES_PROPERTY_NAME;
2524
import static io.cucumber.core.options.Constants.FILTER_NAME_PROPERTY_NAME;
@@ -85,12 +84,6 @@ public RuntimeOptionsBuilder parse(Map<String, String> properties) {
8584
builder::setPickleOrder
8685
);
8786

88-
parse(properties,
89-
EXECUTION_PARALLEL_CONFIG_FIXED_PARALLELISM_PROPERTY_NAME,
90-
Integer::parseInt,
91-
builder::setThreads
92-
);
93-
9487
parse(properties,
9588
EXECUTION_STRICT_PROPERTY_NAME,
9689
Boolean::parseBoolean,

core/src/main/java/io/cucumber/core/reflection/Reflections.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
package io.cucumber.core.reflection;
22

3-
import io.cucumber.core.io.ClassFinder;
43
import io.cucumber.core.exception.CucumberException;
4+
import io.cucumber.core.io.ClassFinder;
55

66
import java.lang.reflect.Constructor;
7-
import java.net.URI;
87
import java.lang.reflect.Modifier;
8+
import java.net.URI;
99
import java.util.Arrays;
1010
import java.util.Collection;
1111
import java.util.HashSet;
@@ -18,7 +18,7 @@ public Reflections(ClassFinder classFinder) {
1818
this.classFinder = classFinder;
1919
}
2020

21-
public static boolean isInstantiable(Class<?> clazz) {
21+
static boolean isInstantiable(Class<?> clazz) {
2222
boolean isNonStaticInnerClass = !Modifier.isStatic(clazz.getModifiers()) && clazz.getEnclosingClass() != null;
2323
return Modifier.isPublic(clazz.getModifiers()) && !Modifier.isAbstract(clazz.getModifiers()) && !isNonStaticInnerClass;
2424
}
@@ -28,7 +28,7 @@ public <T> T instantiateExactlyOneSubclass(Class<T> parentType, List<URI> packag
2828
if (instances.size() == 1) {
2929
return instances.iterator().next();
3030
} else if (instances.isEmpty()) {
31-
if(fallback != null) {
31+
if (fallback != null) {
3232
return fallback;
3333
}
3434
throw new NoInstancesException(parentType);

core/src/main/java/io/cucumber/core/runner/AmbiguousPickleStepDefinitionsMatch.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,12 @@ final class AmbiguousPickleStepDefinitionsMatch extends PickleStepDefinitionMatc
1313
}
1414

1515
@Override
16-
public void runStep(Scenario scenario) {
16+
public void runStep(Scenario scenario) throws AmbiguousStepDefinitionsException {
1717
throw exception;
1818
}
1919

2020
@Override
21-
public void dryRunStep(Scenario scenario) {
21+
public void dryRunStep(Scenario scenario) throws AmbiguousStepDefinitionsException {
2222
runStep(scenario);
2323
}
2424

0 commit comments

Comments
 (0)