Skip to content

Commit 2caea1f

Browse files
committed
[Core] Support custom UUID generators in test runners
With #2703 a faster UUID generator was introduced. And while the configuration options were added, they were not actually used by `cucumber-junit`, `cucumber-junit-platform-engine` and `cucumber-testng`.
1 parent 493220d commit 2caea1f

File tree

7 files changed

+36
-24
lines changed

7 files changed

+36
-24
lines changed

cucumber-core/README.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,8 @@ cucumber.plugin= # comma separated plugin strings.
5353
cucumber.object-factory= # object factory class name.
5454
# example: com.example.MyObjectFactory
5555
56-
cucumber.uuid-generator= # UUID generator class name.
56+
cucumber.uuid-generator # uuid generator class name of a registered service provider.
57+
# default: io.cucumber.core.eventbus.RandomUuidGenerator
5758
# example: com.example.MyUuidGenerator
5859
5960
cucumber.publish.enabled # true or false. default: false
@@ -89,12 +90,13 @@ Cucumber emits events on an event bus in many cases:
8990
- during the feature file parsing
9091
- when the test scenarios are executed
9192

92-
An event has a UUID. The UUID generator can be configured using the `cucumber.uuid-generator` property:
93+
An event has a UUID. The UUID generator can be configured using the
94+
`cucumber.uuid-generator` property:
9395

9496
| UUID generator | Features | Performance [Millions UUID/second] | Typical usage example |
9597
|-----------------------------------------------------|-----------------------------------------|------------------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
9698
| io.cucumber.core.eventbus.RandomUuidGenerator | Thread-safe, collision-free, multi-jvm | ~1 | Reports may be generated on different JVMs at the same time. A typical example would be one suite that tests against Firefox and another against Safari. The exact browser is configured through a property. These are then executed concurrently on different Gitlab runners. |
97-
| io.cucumber.core.eventbus.IncrementingUuidGenerator | Thread-safe, collision-free, single-jvm | ~130 | Reports are generated on a single JVM |
99+
| io.cucumber.core.eventbus.IncrementingUuidGenerator | Thread-safe, collision-free, single-jvm | ~130 | Reports are generated on a single JVM in a single execution of Cucumber. |
98100

99101
The performance gain on real projects depends on the feature size.
100102

cucumber-core/src/main/java/io/cucumber/core/eventbus/IncrementingUuidGenerator.java

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -10,20 +10,20 @@
1010
* Thread-safe and collision-free UUID generator for single JVM. This is a
1111
* sequence generator and each instance has its own counter. This generator is
1212
* about 100 times faster than #RandomUuidGenerator.
13-
*
14-
* Properties:
15-
* - thread-safe
16-
* - collision-free in the same classloader
17-
* - almost collision-free in different classloaders / JVMs
18-
* - UUIDs generated using the instances from the same classloader are sortable
19-
*
20-
* UUID version 8 (custom) / variant 2 <a href=
21-
* "https://www.ietf.org/archive/id/draft-peabody-dispatch-new-uuid-format-04.html#name-uuid-version-8">...</a>
22-
* <!-- @formatter:off -->
13+
* <p>
14+
* Properties: - thread-safe - collision-free in the same classloader - almost
15+
* collision-free in different classloaders / JVMs - UUIDs generated using the
16+
* instances from the same classloader are sortable
17+
* <p>
18+
* <a href=
19+
* "https://www.ietf.org/archive/id/draft-peabody-dispatch-new-uuid-format-04.html#name-uuid-version-8">UUID
20+
* version 8 (custom) / variant 2 </a>
21+
*
22+
* <pre>
2323
* | 40 bits | 8 bits | 4 bits | 12 bits | 2 bits | 62 bits |
2424
* | -------------------| -------------- | ------- | ------------- | ------- | ------- |
2525
* | LSBs of epoch-time | sessionCounter | version | classloaderId | variant | counter |
26-
* <!-- @formatter:on -->
26+
* </pre>
2727
*/
2828
public class IncrementingUuidGenerator implements UuidGenerator {
2929
/**
@@ -84,7 +84,7 @@ public class IncrementingUuidGenerator implements UuidGenerator {
8484
* classloaderId which produces about 1% collision rate on the
8585
* classloaderId, and thus can have UUID collision if the epoch-time,
8686
* session counter and counter have the same values).
87-
*
87+
*
8888
* @param classloaderId the new classloaderId (only the least significant 12
8989
* bits are used)
9090
* @see IncrementingUuidGenerator#classloaderId

cucumber-core/src/main/java/io/cucumber/core/runtime/UuidGeneratorServiceLoader.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public UuidGeneratorServiceLoader(Supplier<ClassLoader> classLoaderSupplier, Opt
3838
this.options = requireNonNull(options);
3939
}
4040

41-
UuidGenerator loadUuidGenerator() {
41+
public UuidGenerator loadUuidGenerator() {
4242
Class<? extends UuidGenerator> objectFactoryClass = options.getUuidGeneratorClass();
4343
ClassLoader classLoader = classLoaderSupplier.get();
4444
ServiceLoader<UuidGenerator> loader = ServiceLoader.load(UuidGenerator.class, classLoader);

cucumber-junit-platform-engine/README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,10 @@ cucumber.junit-platform.naming-strategy.long.example-name= # number or pickl
373373
374374
cucumber.plugin= # comma separated plugin strings.
375375
# example: pretty, json:path/to/report.json
376+
377+
cucumber.uuid-generator # uuid generator class name of a registered service provider.
378+
# default: io.cucumber.core.eventbus.RandomUuidGenerator
379+
# example: com.example.MyUuidGenerator
376380
377381
cucumber.object-factory= # object factory class name.
378382
# example: com.example.MyObjectFactory

cucumber-junit-platform-engine/src/main/java/io/cucumber/junit/platform/engine/CucumberEngineExecutionContext.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,12 @@
1919
import io.cucumber.core.runtime.ThreadLocalObjectFactorySupplier;
2020
import io.cucumber.core.runtime.ThreadLocalRunnerSupplier;
2121
import io.cucumber.core.runtime.TimeServiceEventBus;
22+
import io.cucumber.core.runtime.UuidGeneratorServiceLoader;
2223
import org.apiguardian.api.API;
2324
import org.junit.platform.engine.ConfigurationParameters;
2425
import org.junit.platform.engine.support.hierarchical.EngineExecutionContext;
2526

2627
import java.time.Clock;
27-
import java.util.UUID;
2828
import java.util.function.Supplier;
2929

3030
import static io.cucumber.core.runtime.SynchronizedEventBus.synchronize;
@@ -48,8 +48,10 @@ CucumberEngineOptions getOptions() {
4848

4949
private CucumberExecutionContext createCucumberExecutionContext() {
5050
Supplier<ClassLoader> classLoader = CucumberEngineExecutionContext.class::getClassLoader;
51+
UuidGeneratorServiceLoader uuidGeneratorServiceLoader = new UuidGeneratorServiceLoader(classLoader, options);
52+
EventBus bus = synchronize(
53+
new TimeServiceEventBus(Clock.systemUTC(), uuidGeneratorServiceLoader.loadUuidGenerator()));
5154
ObjectFactoryServiceLoader objectFactoryServiceLoader = new ObjectFactoryServiceLoader(classLoader, options);
52-
EventBus bus = synchronize(new TimeServiceEventBus(Clock.systemUTC(), UUID::randomUUID));
5355
Plugins plugins = new Plugins(new PluginFactory(), options);
5456
ExitStatus exitStatus = new ExitStatus(options);
5557
plugins.addPlugin(exitStatus);

cucumber-junit/src/main/java/io/cucumber/junit/Cucumber.java

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import io.cucumber.core.runtime.ThreadLocalObjectFactorySupplier;
2424
import io.cucumber.core.runtime.ThreadLocalRunnerSupplier;
2525
import io.cucumber.core.runtime.TimeServiceEventBus;
26+
import io.cucumber.core.runtime.UuidGeneratorServiceLoader;
2627
import org.apiguardian.api.API;
2728
import org.junit.AfterClass;
2829
import org.junit.BeforeClass;
@@ -38,7 +39,6 @@
3839
import java.util.List;
3940
import java.util.Map;
4041
import java.util.Optional;
41-
import java.util.UUID;
4242
import java.util.function.Predicate;
4343
import java.util.function.Supplier;
4444

@@ -146,11 +146,14 @@ public Cucumber(Class<?> clazz) throws InitializationError {
146146
.parse(CucumberProperties.fromSystemProperties())
147147
.build(junitEnvironmentOptions);
148148

149-
this.bus = synchronize(new TimeServiceEventBus(Clock.systemUTC(), UUID::randomUUID));
149+
Supplier<ClassLoader> classLoader = ClassLoaders::getDefaultClassLoader;
150+
UuidGeneratorServiceLoader uuidGeneratorServiceLoader = new UuidGeneratorServiceLoader(classLoader,
151+
runtimeOptions);
152+
this.bus = synchronize(
153+
new TimeServiceEventBus(Clock.systemUTC(), uuidGeneratorServiceLoader.loadUuidGenerator()));
150154

151155
// Parse the features early. Don't proceed when there are lexer errors
152156
FeatureParser parser = new FeatureParser(bus::generateId);
153-
Supplier<ClassLoader> classLoader = ClassLoaders::getDefaultClassLoader;
154157
FeaturePathFeatureSupplier featureSupplier = new FeaturePathFeatureSupplier(classLoader, runtimeOptions,
155158
parser);
156159
List<Feature> features = featureSupplier.get();

cucumber-testng/src/main/java/io/cucumber/testng/TestNGCucumberRunner.java

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,11 @@
2323
import io.cucumber.core.runtime.ThreadLocalObjectFactorySupplier;
2424
import io.cucumber.core.runtime.ThreadLocalRunnerSupplier;
2525
import io.cucumber.core.runtime.TimeServiceEventBus;
26+
import io.cucumber.core.runtime.UuidGeneratorServiceLoader;
2627
import org.apiguardian.api.API;
2728

2829
import java.time.Clock;
2930
import java.util.List;
30-
import java.util.UUID;
3131
import java.util.function.Predicate;
3232
import java.util.function.Supplier;
3333

@@ -98,9 +98,10 @@ public TestNGCucumberRunner(Class<?> clazz, CucumberPropertiesProvider propertie
9898
.enablePublishPlugin()
9999
.build(environmentOptions);
100100

101-
EventBus bus = synchronize(new TimeServiceEventBus(Clock.systemUTC(), UUID::randomUUID));
102-
103101
Supplier<ClassLoader> classLoader = ClassLoaders::getDefaultClassLoader;
102+
UuidGeneratorServiceLoader uuidGeneratorServiceLoader = new UuidGeneratorServiceLoader(classLoader, runtimeOptions);
103+
EventBus bus = synchronize(new TimeServiceEventBus(Clock.systemUTC(), uuidGeneratorServiceLoader.loadUuidGenerator()));
104+
104105
FeatureParser parser = new FeatureParser(bus::generateId);
105106
FeaturePathFeatureSupplier featureSupplier = new FeaturePathFeatureSupplier(classLoader, runtimeOptions,
106107
parser);

0 commit comments

Comments
 (0)