jamesfredley commented on PR #16067:
URL: https://github.com/apache/grails-core/pull/16067#issuecomment-5124138929
Heads up - #16011 was merged (`301b40c20a`), and it carried its own fix for
these same two specs, so this PR is now `CONFLICTING` against `8.0.x`.
On `8.0.x` today, `GrailsUtilStackFiltererSpec` and
`GrailsBootstrapRegistryInitializerSpec` already capture via the shared
`LogCapture` test fixture
(`grails-core/src/testFixtures/groovy/org/apache/grails/core/testing/support/LogCapture.groovy`)
rather than the inline `attachRecordingAppender()` / `detachAppender()`
helpers proposed here. Both approaches were correct; `LogCapture` won on the
tiebreak that it already existed and is already the house pattern
(`StackTraceFiltererSpec`, `DefaultGrailsPluginManagerSpec`,
`PluginDiscoverySpec`, `GlobalGrailsClassInjectorTransformationSpec`), and it
additionally forces the logger to `TRACE`, sets `additive = false`, and
restores both on `close()` - which is what makes it independent of whatever
root level and appender set a given module happens to configure.
Rather than close this, I'd like to repurpose it as the **definitive
cleanup** for this failure mode. It has now surfaced two or three separate
times, and there is still a live latent instance.
### 1. Diagnosis is slightly off, and the correction matters
The description attributes the failure to `STACK_LOG` resolving to a
jcl-over-slf4j binding so the message "never reaches `System.err` at all." That
is true as far as it goes, but it is not the proximate trigger. The actual
trigger is `d1c8d0e439` ("test: add deterministic test logging configuration"),
which added `grails-core/src/test/resources/logback-test.xml`:
```xml
<configuration>
<root level="WARN" />
</configuration>
```
Root at `WARN` with **zero appenders** - so the event is not merely routed
away from `System.err`, it is written nowhere at all.
The evidence that this is the real cause: `GrailsExceptionResolverSpec` in
`grails-web-mvc` uses the *identical* `System.setErr` +
`captured.contains('Full Stack Trace:')` pattern against the same `STACK_LOG`,
and it **passes today**. `grails-web-mvc` has no `src/test/resources` at all,
so it falls through to a default console configuration and the capture happens
to work. Same binding, same logger, opposite result - the difference is purely
the per-module logback test config.
### 2. Remaining latent instance
`grails-web-mvc/src/test/groovy/org/grails/web/errors/GrailsExceptionResolverSpec.groovy`
still has three `System.setErr` capture sites (L59, L84, L270), two of which
assert on `StackTrace` logger output including `'Full Stack Trace:'` and the
literal `'ERROR StackTrace '` console prefix. That last assertion is coupled to
a console appender's *layout pattern*, which is about as brittle as it gets. It
will break the same way the moment `grails-web-mvc` gets the same deterministic
`logback-test.xml` treatment `grails-core` received.
### 3. Suggested scope for this PR
1. Convert those three sites in `GrailsExceptionResolverSpec` to
`LogCapture`, keyed on `DefaultStackTraceFilterer.STACK_LOG_NAME` and the
resolver's own logger, asserting on `formattedMessage` / `level` instead of a
rendered console line.
2. Switch the two already-merged specs from the `'StackTrace'` string
literal to `DefaultStackTraceFilterer.STACK_LOG_NAME` - this PR had that right
and #16011 did not.
3. Once no test in the module asserts on incidental console output, roll the
deterministic `logback-test.xml` out to `grails-web-mvc` (and ideally the other
test modules) so this cannot regress a fourth time. That converts "it happens
to pass because this module has no logging config" into "it passes because the
test attaches its own appender."
Optionally, a short note in the `LogCapture` javadoc stating that tests must
never assert on `System.out`/`System.err` for anything emitted through a logger
would give reviewers something concrete to point at.
### 4. Re: the logging changes that just merged
#15757 (stop scaffolding `logback-spring.xml`, add the opt-in Forge feature)
and the earlier content fixes in #15973 are app-generation scope only - they do
not touch any module's test classpath, so there is no direct collision with
this work. But they do reinforce the same direction: rely on the framework's
default logging configuration rather than a checked-in file, and
correspondingly stop writing tests that depend on what that default
configuration happens to render to a stream.
### Rebase note
Since the two specs already changed on `8.0.x`, the cleanest path is to
rebase onto current `8.0.x` and drop the parts of this diff that #16011 already
covers, keeping the constant-vs-literal fix, then add the `grails-web-mvc`
conversion and the config rollout on top.
--
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]