jdaugherty commented on code in PR #16399:
URL: https://github.com/apache/grails-core/pull/16399#discussion_r4106626393


##########
grails-testing-support-core/src/main/groovy/org/grails/testing/GrailsApplicationBuilder.groovy:
##########
@@ -170,9 +178,18 @@ class GrailsApplicationBuilder {
         beanFactory.allowCircularReferences = 
environment.getProperty(Settings.SPRING_MAIN_ALLOW_CIRCULAR_REFERENCES, 
Boolean, Boolean.TRUE)
 
         def classLoader = this.class.classLoader
+        // The test's own configuration first, as an application's comes 
before auto-configuration:
+        // parsed ahead of them, its beans are what an auto-configuration's 
@ConditionalOnMissingBean sees.
+        configurationClasses?.each { Class<?> configurationClass ->

Review Comment:
   Thanks, the harness defaults now behave as an application's would. On names 
you're right: I ran the early phase the way 
`EarlyPluginRegistrationOrderingSpec` does, with `IncludedBeansGrailsPlugin` 
discovered and its generated auto-configuration registered after it, and an 
application `@Bean` named `registeredGreeting` loses to the plugin's 
`beanRegistrar()` bean there too. The test and the application agree on name 
precedence.
   
   Conditions still differ, and not only the test's own. The harness registers 
included plugins' `doWithSpring` and `beanRegistrar` beans after the 
configuration classes are parsed, so an included plugin's 
`conditionalOnMissingBean()` beans cannot back off from them either. The 
fixture shows this now. `IncludedBeansGrailsPlugin`'s registrar registers 
`registeredGreeting`, an `IncludedGreeting`, and its `beans` block declares 
`bean(IncludedGreeting).conditionalOnMissingBean()`:
   
   | Context | `getBeansOfType(IncludedGreeting)` |
   |---|---|
   | Application (early phase, then the plugin's auto-configuration) | 
`[registeredGreeting]` |
   | Unit test including `includedBeans` | `[includedGreeting, 
registeredGreeting]` |
   
   So `IncludedPluginBeansSpec` passes on a bean the plugin would not register 
in an application. A test that includes such a plugin and asks for the type 
(`getBean(IncludedGreeting)`, say) gets `NoUniqueBeanDefinitionException`, 
where the application has a single bean. This is the back-off the upgrade guide 
describes under "Plugin beans win `@ConditionalOnMissingBean` races". The 
limitation the guide now states for a test's own conditions is the same gap, 
since an application's configuration does see plugin beans.
   
   Could the harness register included plugins' `doWithSpring` and 
`beanRegistrar` beans before the configuration classes are parsed, as the early 
phase does? That would close both gaps. If that is out of scope, "Spring 
configuration from plugins" should say that an included plugin's conditional 
beans do not back off from plugin beans in a unit test. 
`IncludedPluginBeansSpec` should then stop depending on that: give 
`registeredGreeting` a type of its own, and pin the difference in a spec named 
for it.



##########
grails-doc/src/en/guide/upgrading/upgrading80x.adoc:
##########
@@ -1695,6 +1695,12 @@ class MyGrailsPlugin extends Plugin {
 
 Both hooks may be used on the same plugin during migration; when a registrar 
and the DSL register a bean under the same name, the registrar's definition 
wins.
 
+**Unit tests follow.** `doWithSpring()` on the `GrailsUnitTest` trait — and so 
on every testing trait — is deprecated too. A test now declares its beans in a 
`beans` block with the `beans` DSL, as an application or plugin does; overrides 
`beanRegistrar()`, applied where an application's is; or declares a static 
nested `@Configuration` class, which its context registers ahead of the 
framework's auto-configurations. A `beans` block compiles into one such class, 
named `BeansConfiguration`, so a test that already declares a nested class of 
that name must rename it. A test that includes a plugin through 
`getIncludePlugins()` also gets the beans the plugin's `beans` block declares, 
which `defineBeans(plugin)` cannot apply. See <<unitTesting,Unit Testing>>.
+
+A test that already has a static nested `@Configuration` class meant for 
something other than its own context — one built for an 
`ApplicationContextRunner`, say — now has it registered there as well; override 
`getConfigurationClasses()` to leave it out.
+
+**A `beans` block names a nested type's bean by its simple name.** In earlier 
8.0 milestones `bean(Outer.Helper)`, with no name given, registered a bean 
named `outer$Helper`. It is now `helper`, the type's decapitalized simple name, 
as documented. Name it explicitly, `bean('outer$Helper', Outer.Helper)`, if 
anything looks it up by the old name.

Review Comment:
   The `beans` DSL first shipped in 8.0.0-RC1, so "earlier 8.0 milestones" may 
not register with someone upgrading from the RC:
   
   ```suggestion
   **A `beans` block names a nested type's bean by its simple name.** In 
8.0.0-RC1 `bean(Outer.Helper)`, with no name given, registered a bean named 
`outer$Helper`. It is now `helper`, the type's decapitalized simple name, as 
documented. Name it explicitly, `bean('outer$Helper', Outer.Helper)`, if 
anything looks it up by the old name.
   ```



##########
grails-testing-support-core/src/test/resources/META-INF/grails-plugin.xml:
##########
@@ -0,0 +1,3 @@
+<plugin name='includedBeans' version='1.0'>

Review Comment:
   Confirmed: the resource is gone, and all 31 of the module's tests pass on 
the descriptor the transform generates.



##########
grails-core/src/main/groovy/org/grails/compiler/injection/GlobalGrailsClassInjectorTransformation.groovy:
##########
@@ -387,6 +391,8 @@ class GlobalGrailsClassInjectorTransformation implements 
ASTTransformation, Comp
         if (beansProperty == null || 
!classNode.getAnnotations(GRAILS_BEANS_ANNOTATION).isEmpty()) {

Review Comment:
   Verified at 58b99742f1: the convention and `@GrailsBeans` paths both report 
a `@Shared` block with the new message, and an unrelated `@Shared` `beans` map 
compiles as before.



-- 
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]

Reply via email to