Files
Flash5/flash-testing/docs/limits.md
T
Zakaria El OrcheandClaude Opus 5 58bae41f7a docs(testing): document flash-testing and the limits it deliberately keeps
README covers the application handle, requests and assertions, service
replacement, multi-server wiring, scope, WebSockets, configuration and the
teardown ordering.

limits.md records the seven things the harness cannot do and what to use for
each: TLS, HTTP/2, WebSocket over HTTP/2, malformed requests, response framing,
the flash core module's dependency cycle, and scoped services. Each is a
consequence of a real constraint rather than an unfinished feature, so writing
them down stops the next person rediscovering them one at a time.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-09 12:07:55 +00:00

80 lines
3.7 KiB
Markdown

# Limits
What `flash-testing` deliberately cannot do, why, and what to use instead. Each of these is a
consequence of a real constraint, not an unfinished feature.
## TLS
`profile(cfg -> cfg.tls(...))` is rejected. The harness serves plaintext on loopback and hands you
a client bound to `http://127.0.0.1:<port>`; a TLS listener would leave that base URI pointing at
the wrong scheme, and the client would need the test certificate in a trust store.
**Instead:** build the app directly with `FlashApp.create(...)` and a raw `SSLSocket`, as
`HttpServerTlsTest` does. `port(0)` plus `FlashApp.port()` still removes the free-port dance.
Lifting this is the only limit here worth reconsidering, and only if application-level TLS testing
is actually wanted — transport-level TLS is already covered by the core suite.
## HTTP/2
`java.net.http` reaches cleartext h2 through an `Upgrade:` handshake. Flash implements HTTP/2
cleartext by **prior knowledge only** — a deliberate choice recorded in the root README — so the
harness client cannot negotiate h2 against a plaintext Flash listener. Over TLS it would work
through ALPN, but TLS is unavailable per the section above.
**Instead:** the `flash/src/test/.../http2/` suites drive h2 frames over raw sockets. That is the
right tool for protocol behaviour anyway.
## WebSocket over HTTP/2
`java.net.http.WebSocket` does not negotiate RFC 8441 extended CONNECT, so `FlashWebSocket` always
speaks the HTTP/1.1 upgrade. Flash supports both, but this client can only exercise one.
**Instead:** `WebSocketOverH2Test` and `WebSocketParityTest` frame extended CONNECT by hand.
## Malformed requests
Every request goes through `java.net.http`, which structurally cannot emit an invalid request
line, a bad header block, a smuggled `Content-Length`, or a chunked *request* body on demand. That
is a feature for application testing and a blocker for parser testing.
**Instead:** `RequestParserSecurityTest`, `RequestParserFuzzTest` and the raw-socket half of
`HttpServerTest` write bytes directly. A harness that could send malformed requests would just be
a socket.
## Response framing
`java.net.http` transparently decodes chunked responses and hides connection reuse, so
`Transfer-Encoding: chunked` and `Connection: keep-alive` are not observable through
`FlashResponse`.
**Instead:** `HttpServerTest` keeps raw sockets for exactly those assertions, taking its port from
a `FlashTest` field so the class still boots once. Mixing the two styles in one class is the
intended pattern, not a workaround.
## The `flash` core module
`flash-testing` depends on `flash`, so `flash`'s own tests cannot depend on `flash-testing`
Maven rejects module cycles regardless of scope.
**Instead:** core tests use `FlashApp.create(...)` with `port(0)` and read `port()` back. Every
core suite already does this. Unblocking it would need a third module depending on both, which is
not worth it for the two suites that would benefit.
## Scoped services
`mock` writes to the app's root `FlashContext`. `FlashContext.require` checks its own bindings
before its parent's, so a service declared inside a `mount(...)` scope's child context shadows the
root and is **not** reachable from `mock`.
**Instead:** declare the service on the app rather than inside the scope, or assert against the
real one. Child-context targeting would be a small addition if a scoped service ever needs faking.
## Shutdown draining
The harness pins `shutdownDrainTimeoutMs` to 250ms after any profile runs, so a test cannot
exercise graceful-drain behaviour through it.
**Instead:** `ServerLifecycleGracefulShutdownTest` builds its app directly. A profile escape hatch
would be easy to add if this ever comes up twice.