Class PooledDriverProvider
- All Implemented Interfaces:
DriverProvider
This provider works correctly with virtual threads where each task gets a new thread ID. Drivers are pooled and reused across scenarios regardless of which thread executes them.
The pool size automatically matches the Suite's parallelism (threadCount), ensuring exactly the right number of drivers are created.
// Usage - pool size auto-detected from Runner.parallel(N)
Runner.path("features/")
.driverProvider(new PooledDriverProvider())
.parallel(4); // Pool will have 4 drivers
// Or with Testcontainers - override createDriver()
Runner.path("features/")
.driverProvider(new PooledDriverProvider() {
protected Driver createDriver(Map<String, Object> config) {
return CdpDriver.connect(container.getCdpUrl(), options);
}
})
.parallel(4);
-
Constructor Summary
ConstructorsConstructorDescriptionCreate a pooled driver provider with auto-detected pool size.PooledDriverProvider(int poolSize) Create a pooled driver provider with explicit pool size. -
Method Summary
Modifier and TypeMethodDescriptionacquire(ScenarioRuntime runtime, Map<String, Object> config) Acquire a driver instance for a scenario.protected voidcleanScenarioState(Driver driver) Tear down scenario-scoped driver state at owner-scenario exit.protected DrivercreateDriver(Map<String, Object> config) Create a new driver from config.intGet current pool size (may be -1 if not yet initialized).getStats()Get current pool statistics for monitoring.voidrelease(ScenarioRuntime runtime, Driver driver) Release a driver instance after scenario completion.protected booleanresetDriver(Driver driver) Reset driver state between scenarios.voidshutdown()Shutdown the provider and close all managed drivers.
-
Constructor Details
-
PooledDriverProvider
public PooledDriverProvider()Create a pooled driver provider with auto-detected pool size. Pool size will match the Suite's parallelism (threadCount). -
PooledDriverProvider
public PooledDriverProvider(int poolSize) Create a pooled driver provider with explicit pool size. Use this when you need to override the auto-detected size.- Parameters:
poolSize- maximum number of drivers to create
-
-
Method Details
-
acquire
Description copied from interface:DriverProviderAcquire a driver instance for a scenario.Called when a scenario first accesses the driver (lazy initialization). The provider may create a new driver, return one from a pool, or return a thread-local cached instance.
- Specified by:
acquirein interfaceDriverProvider- Parameters:
runtime- the scenario runtime requesting the driverconfig- driver configuration fromconfigure driver = {...}- Returns:
- a driver instance
-
release
Description copied from interface:DriverProviderRelease a driver instance after scenario completion.Called when a scenario ends. The provider may close the driver, return it to a pool, or keep it cached for the thread.
- Specified by:
releasein interfaceDriverProvider- Parameters:
runtime- the scenario runtime that used the driverdriver- the driver to release
-
cleanScenarioState
Tear down scenario-scoped driver state at owner-scenario exit. Called fromrelease(io.karatelabs.core.ScenarioRuntime, io.karatelabs.driver.Driver)before the driver is offered back to the pool.Only state that belongs to the scenario's scope should be cleaned here — NOT cookies or page state, those belong in
resetDriver(io.karatelabs.driver.Driver)at acquire time (per-scenario setup vs per-scenario teardown).Subclasses overriding this should call
super.cleanScenarioState(driver)to preserve intercept/dialog teardown. -
shutdown
public void shutdown()Description copied from interface:DriverProviderShutdown the provider and close all managed drivers.Called when the Suite completes. All drivers should be closed.
- Specified by:
shutdownin interfaceDriverProvider
-
resetDriver
Reset driver state between scenarios. Override to customize reset behavior.Returns
trueif the driver is healthy and safe to return to the pool,falseif it should be discarded and replaced. Callers (seerelease(ScenarioRuntime, Driver)) MUST honor the false return — otherwise a poisoned driver can pollute every subsequent scenario.Context for the health-check + discard logic: without this, observed in CI as deterministic "CDP timeout for: Page.navigate" failures after tab-switch.feature — that scenario's repeated activateTarget/attachToTarget calls leave the driver's CDP channel stuck on navigation commands. The pool kept handing the stuck driver back out and every other cookie/keys scenario timed out at 30s. The fix is to probe liveness (see
Driver.isResponsive()) and recycle drivers that fail the probe. Subclasses overriding this should preserve the boolean contract. -
createDriver
Create a new driver from config. Subclasses should override for custom driver creation (e.g., Testcontainers).With no
webSocketUrleach pooled driver launches its own browser process, so slots are isolated by construction. Against a SHARED browser the isolation has to be asked for: a browser-level endpoint gets each slot its own incognito context viaCdpDriver.connectNewContext(java.lang.String, io.karatelabs.driver.cdp.CdpDriverOptions), because pooled slots sharing one browser context share its cookie jar, and the per-acquireclearCookies()inresetDriver(io.karatelabs.driver.Driver)is context-wide — one slot resetting would wipe the cookies of every other slot mid-scenario.A page-level endpoint is taken at face value and attached to directly: the caller named a specific tab, so it owns that tab's lifetime and isolation. Pointing a pool of more than one slot at a single page endpoint means every slot drives the SAME tab — that is inherent to the request, not something this method can fix.
-
getPoolSize
public int getPoolSize()Get current pool size (may be -1 if not yet initialized). -
getStats
Get current pool statistics for monitoring.
-