jdaugherty opened a new pull request, #15937:
URL: https://github.com/apache/grails-core/pull/15937
## Description
Adds a new testing support library, `grails-testing-support-latency`, that
injects artificial
latency into a running Grails application so that requests randomly take
longer.
**Why:** Functional tests are prone to timing bugs — assertions that race a
click-triggered
navigation, missing waits, response-ordering assumptions. These pass
reliably on fast local
machines and fail intermittently on slower CI infrastructure (see the recent
`User1FunctionalSpec.'edit report 20'` flake in the spring-security ACL
functional test app,
which only reproduced when the server response was slow). Slowing responses
down widens the
window in which these bugs occur, turning rare flakes into deterministic
failures that can be
found and fixed locally.
**What:**
- New module `grails-testing-support-latency`
(`org.apache.grails:grails-testing-support-latency`):
- `LatencyFilter` — a `OncePerRequestFilter` that delays each matched
request by a random
amount between a configurable minimum and maximum, for a configurable
fraction of requests,
with an optional fixed seed for reproducible delay sequences. Invalid
configuration
(negative delays, `max-delay` < `min-delay`, probability outside 0..1)
fails fast at startup.
- `LatencyProperties` — bound from the `grails.testing.latency` prefix
(`enabled`, `min-delay`,
`max-delay`, `probability`, `url-patterns`, `seed`) with Spring
`Duration` binding.
- `LatencyAutoConfiguration` — conditional on
`grails.testing.latency.enabled=true`, so the
library is completely inert unless explicitly switched on; registers the
filter at highest
precedence so the delay covers the entire request pipeline.
- New example app `grails-test-examples/latency` that enables latency for
`/slow/*` only and
confirms end-to-end behavior against the running application: matched
requests take at least
the configured minimum, unmatched requests do not.
- Documentation: a new "Simulating Latency" section in the Functional
Testing guide (dependency,
activation, full property table, YAML example, CI usage pattern,
production warning) and a
"Latency Testing Support" entry in the What's New section.
- Module registered in `settings.gradle` and
`gradle/publish-root-config.gradle`; the BOM picks
it up automatically via the subprojects constraint loop.
**Verification performed:**
- `./gradlew :grails-testing-support-latency:build` — 10 unit tests passing
(delay bounds,
zero-probability passthrough, configuration validation, conditional
auto-configuration)
- `./gradlew :grails-test-examples-latency:integrationTest` — 2 end-to-end
tests passing
- `./gradlew :grails-testing-support-latency:codeStyle` — clean
- `./gradlew :grails-doc:publishGuide -x aggregateGroovydoc` — docs build
clean, new sections render
## Contributor Checklist
### Issue and Scope
- [ ] This PR is linked to an existing issue — **no issue exists yet**;
background is provided in
the Description above. Happy to open a ticket for the release
changelog if preferred.
- [x] This PR addresses the **complete scope** of the change: library,
tests, example app, and
documentation are all included.
- [x] This PR contains a **single, focused change**.
- [x] This PR targets the **correct branch**: it is a new feature (new
module, no changes to any
existing API) targeting `8.0.x`.
### Code Quality
- [x] I have **added or updated tests**: unit tests for the filter and
auto-configuration, plus a
dedicated example app with integration tests confirming runtime
behavior.
- [ ] I have verified that all existing tests pass by running `./gradlew
build --rerun-tasks`.
*(Targeted builds above are green; full rerun not yet executed.)*
- [x] My code follows the project's **code style** guidelines (`codeStyle`
passes on the new module).
- [x] This PR does **not** include mass reformatting, style-only changes, or
refactoring.
- [x] Generative AI tooling was used (Claude Code with Claude Fable 5); all
output was reviewed,
and verified against the project's quality standards via the test and
style checks above.
### Licensing and Attribution
- [x] All contributed code is provided under the Apache License 2.0, and
every new source file
(Groovy, Gradle, YAML, XML, AsciiDoc) includes the Apache license
header.
- [x] I have the necessary rights to submit this contribution.
- [x] Generative AI use is disclosed per the ASF generative tooling policy:
this contribution was
prepared with assistance from Claude Code (Anthropic), with human
review of all changes.
### Documentation
- [x] User-facing documentation added: "Simulating Latency" section in the
Functional Testing guide.
- [x] **What's New** section updated with a "Latency Testing Support" entry.
- [x] No breaking changes or upgrade actions — the module is new, opt-in,
and inert by default, so
no Upgrade Notes changes are needed.
- [x] The PR description explains **what** was changed and **why**.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]