Interface HttpClientFactory
- All Known Implementing Classes:
DefaultHttpClientFactory
This interface allows external modules (such as karate-gatling) to provide custom HttpClient implementations, for example with a shared connection pool for performance testing scenarios.
The default implementation DefaultHttpClientFactory creates a new
ApacheHttpClient instance for each call, which is the standard
behavior for functional tests where isolation is preferred.
- See Also:
-
Method Summary
Modifier and TypeMethodDescriptioncreate()Creates a new HttpClient instance.default voidrelease(HttpClient client) Called when the scenario that ownsclienthas finished with it.
-
Method Details
-
create
HttpClient create()Creates a new HttpClient instance.- Returns:
- a new HttpClient instance
-
release
Called when the scenario that ownsclienthas finished with it.The default does nothing, and that is the conservative choice rather than the obvious one. A factory exists so a caller can supply its own policy — this interface's own javadoc offers "a shared connection pool for performance testing scenarios" — and a factory handing out one shared instance is the common shape, including the
() -> clientlambda form. Closing that at the end of one scenario would break every other scenario using it, so a custom factory keeps today's behaviour unless it opts in.DefaultHttpClientFactoryoverrides this to close, because it mints one client per scenario that nothing else can reach — and until this existed, not one of them was ever closed. Each abandoned its connection manager and pooled sockets to the collector, released at a time no test controlled; a file descriptor is not heap, so no heap-based check could see them accumulate.What this does and does not guarantee, stated because an implementation that assumes more will break:
- Not exactly-once per
create(). A client is minted eagerly when a scenario runtime is constructed, and a few runtimes never run a scenario at all — a dynamic-outline template, the synthetic runtime behind config-only loading, a mock's cached per-feature runtime. Those release where they can, but a factory that counts checkouts must tolerate a create with no matching release rather than deadlock. - A released client may still be used. An
afterFeaturehook runs after the last scenario released its client, and a closure returned from a called feature can outlive the scenario that made it.DefaultHttpClientFactory's client tolerates this by rebuilding lazily; a pooled implementation must decide what a late request should do rather than assume it cannot happen. - Called from the scenario's own thread, and scenarios run in parallel, so an implementation holding shared state needs its own synchronization.
Pool underneath, one wrapper per scenario — do not return one client instance to concurrent scenarios. This is the rule for the pooling case this interface exists to enable, and it is not merely stylistic.
HttpClient.apply(io.karatelabs.core.KarateConfig)is invoked on the returned instance whenever configuration changes and unconditionally after a shared-scope call, andApacheHttpClientimplements that by closing its transport and rebuilding lazily. A second scenario holding the same instance therefore has its in-flight request killed —SocketException: Socket closed— by the first scenario'sconfigurestep. Independently of that,ApacheHttpClientkeeps per-request state in instance fields, so concurrent callers already attach one request's headers to another's response. Give each scenario its own lightweight wrapper and share the connection manager beneath it, which is where the pooling win actually is.- Parameters:
client- a client previously returned bycreate()
- Not exactly-once per
-