Skip to content

Characterize plugin registry load order and lookup contract#16004

Open
jamesfredley wants to merge 1 commit into
8.0.xfrom
test/plugin-registry-contract
Open

Characterize plugin registry load order and lookup contract#16004
jamesfredley wants to merge 1 commit into
8.0.xfrom
test/plugin-registry-contract

Conversation

@jamesfredley

Copy link
Copy Markdown
Contributor

Summary

  • add a test-only characterization spec that pins the public plugin-registry contract a future load/registry optimization must preserve
  • asserts the two DISTINCT public observables separately: the actual load sequence consumed by loadPlugins() / getPluginsInLoadOrder() and the getAllPlugins() topological order
  • covers repeated-build determinism, duplicate-registration dedup, and name/class-name/version lookup identity (each resolves the same non-null tail instance)

Scope note

Test-only; no production changes. Exercises only public GrailsPluginManager APIs and deliberately does not duplicate the existing GrailsPluginSorterSpec sorter coverage - it characterizes end-to-end manager registry output instead.

Verification

  • :grails-core:test --tests DefaultGrailsPluginManagerRegistryContractSpec
  • :grails-core:test
  • git diff --check

This is an AI-generated starting point pinning the plugin-registry/load-order contract.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new characterization-style Spock spec to pin down the publicly observable GrailsPluginManager registry behavior around plugin load order vs topological order, including determinism across repeated builds, deduplication, and consistent lookup identity across name/class-name/version APIs. This helps protect expected behavior ahead of future plugin discovery/registry optimizations.

Changes:

  • Introduces DefaultGrailsPluginManagerRegistryContractSpec to assert deterministic plugin discovery load order and deterministic topological registry order for the same dependency graph.
  • Adds coverage for duplicate-registration deduplication and consistent lookup resolution (getGrailsPlugin, getGrailsPluginForClassName, versioned lookup) returning the same instance.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +81 to +83
def tailPlugins = manager.getAllPlugins().findAll { it.name == 'registryOrderingTail' }
def expectedTailPlugin = tailPlugins.first()
def pluginByName = manager.getGrailsPlugin('registryOrderingTail')
@bito-code-review

Copy link
Copy Markdown

To make the selection safe and avoid NoSuchElementException when the list is empty, you can use .find() or .first() with a default value, or check the size before accessing. Given the context of the test, using find { true } or checking the list size is appropriate to ensure the then: block handles the failure reporting correctly.

Here is the suggested update for the test:

        when:
        def tailPlugins = manager.getAllPlugins().findAll { it.name == 'registryOrderingTail' }
        def expectedTailPlugin = tailPlugins ? tailPlugins.first() : null
        def pluginByName = manager.getGrailsPlugin('registryOrderingTail')

This change ensures that expectedTailPlugin is null if the list is empty, allowing the subsequent assertions in the then: block to fail gracefully with descriptive messages rather than throwing an exception.

grails-core/src/test/groovy/grails/plugins/DefaultGrailsPluginManagerRegistryContractSpec.groovy

when:
        def tailPlugins = manager.getAllPlugins().findAll { it.name == 'registryOrderingTail' }
        def expectedTailPlugin = tailPlugins ? tailPlugins.first() : null
        def pluginByName = manager.getGrailsPlugin('registryOrderingTail')

@codecov

codecov Bot commented Jul 17, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 51.1200%. Comparing base (0c63c26) to head (44d5cfa).

Additional details and impacted files

Impacted file tree graph

@@                Coverage Diff                 @@
##                8.0.x     #16004        +/-   ##
==================================================
+ Coverage     51.1168%   51.1200%   +0.0031%     
- Complexity      17597      17601         +4     
==================================================
  Files            2041       2041                
  Lines           95493      95493                
  Branches        16587      16587                
==================================================
+ Hits            48813      48816         +3     
+ Misses          39394      39391         -3     
  Partials         7286       7286                

see 3 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@testlens-app

testlens-app Bot commented Jul 17, 2026

Copy link
Copy Markdown

✅ All tests passed ✅

🏷️ Commit: 44d5cfa
▶️ Tests: 18994 executed
⚪️ Checks: 61/61 completed


Learn more about TestLens at testlens.app.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

Status: No status

Development

Successfully merging this pull request may close these issues.

3 participants