Skip to content

GORM: Shared Mapping Registry O(M+N) Scaling (clean rebuild)#15678

Closed
borinquenkid wants to merge 43 commits into
8.0.xfrom
8.0.x-hibernate7.gorm-scaling-clean
Closed

GORM: Shared Mapping Registry O(M+N) Scaling (clean rebuild)#15678
borinquenkid wants to merge 43 commits into
8.0.xfrom
8.0.x-hibernate7.gorm-scaling-clean

Conversation

@borinquenkid

Copy link
Copy Markdown
Member

Description

This PR replaces #15656, which was rebuilt on a clean branch to remove a corruption commit from the history.

Problem: In multi-tenant GORM environments with many tenants (M) and domain classes (N), the previous implementation instantiated a full set of static API, instance API, and validation API objects per tenant per entity, producing O(M × N) object allocations. This caused excessive memory consumption and degraded startup performance as tenant counts scaled.

Solution: Refactor GormRegistry to use a single shared registry keyed by entity class name and qualifier (datasource/tenant), with the GORM API objects created once per entity per qualifier and reused across tenants. This reduces the allocation profile to O(M + N).

This rebuild also fixes two regression classes exposed by the new registry:

  1. Multi-tenancy resolution regressionsGormApiResolver and GormRegistry.registerEntityDatastores were routing DISCRIMINATOR/SCHEMA tenant IDs through the datasource connection lookup path, causing child datastores to be overwritten by the parent and PartitionedMultiTenancySpec.count() to NPE. Fixed by detecting multi-tenancy mode before delegating to getDatastoreForConnection, and by skipping non-DEFAULT qualifier registration when the qualifier resolves back to the parent (i.e., it's a runtime tenant ID, not a datasource name).

  2. Child datastore initialization orderHibernateDatastore (H5) and ChildHibernateDatastore (H7) were throwing ConfigurationException when getDatastoreForConnection was called for a sibling during initialization before all children were registered. Fixed to return null during the initialization phase so GormRegistry falls back gracefully and re-registers once initialization completes.

Test infrastructure: Added forkEvery = 1 to gradle/hibernate5-test-config.gradle and gradle/hibernate7-test-config.gradle. The root config uses forkEvery = 50/100 for speed, but with a shared GormRegistry singleton, TCK specs running in the same JVM before PartitionedMultiTenancySpec were clearing datastoresByQualifier["default"] and causing the NPE described above. Each test class now gets its own JVM.

Verified: H5 — 669 tests / 0 failures. H7 — 2960 tests / 0 failures.

Contributor Checklist

Issue and Scope

  • This PR is linked to an existing issue that has been acknowledged or approved by the project team. (Replaces GORM: Shared Mapping Registry O(M+N) Scaling #15656, which tracks the approved O(M+N) scaling work.)
  • This PR addresses the complete scope of the linked issue.
  • This PR contains a single, focused change.
  • This PR targets the correct branch (8.0.x-hibernate7 — major release branch; breaking API changes permitted).

Code Quality

  • I have added or updated tests that cover the changes introduced in this PR.
  • I have verified that all existing tests pass (H5: 669/0 failures, H7: 2960/0 failures).
  • My code follows the project's code style guidelines. ./gradlew codeStyle has been run and violations resolved.
  • This PR does not include unsolicited reformatting or unrelated refactoring.
  • Generative AI tooling was used in preparing this contribution with a quality model, consistent with the project's quality standards.

Licensing and Attribution

  • All contributed code is provided under the Apache License 2.0, and new source files include the appropriate Apache license header.
  • I have the necessary rights to submit this contribution and confirm it is my own original work.
  • Generative AI tooling use follows the ASF policy on generative tooling and is properly attributed.

Documentation

  • No new user-facing APIs are introduced; this is a performance/correctness fix to the internal registry.
  • The PR description explains what was changed and why.

borinquenkid and others added 7 commits May 25, 2026 10:27
Introduces shared-registry architecture to eliminate per-tenant API wrapper
duplication in multi-tenant environments with high entity/tenant cardinality.

Core changes:
- GormRegistry: normalization caches (entity keys, qualifiers), O(1) lookup paths
- GormApiResolver: simplified fallback chains, qualified API caching
- AbstractGormApiRegistry/sub-registries: normalized key/qualifier registration
- GormEnhancer: delegates API resolution through GormRegistry

Datastore integrations:
- Hibernate 7 and Hibernate 5: aligned to shared registry model
- MongoDB, Neo4j, SimpleMap, GraphQL: registry-pattern integration

Adjacent migrations:
- AsyncEntity: GormEnhancer.findStaticApi -> GormRegistry.instance.findStaticApi
- ByDatasourceDomainClassFetcher: GormEnhancer.findDatastore -> GormRegistry apiResolver
- TCK: added transaction-capable datastore support in GrailsDataTckManager

This commit excludes all collateral CodeNarc reformat changes (2,835 files
from commit 4add87e) and agent experiments, containing only the
optimization-specific module changes.

Agent collaboration note: Claude Sonnet 4.6 assisted with branch archaeology
and rebuild strategy; borinquenkid is the primary author and remains
responsible for the final changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Includes SessionResolver and ThreadLocalSessionResolver (new interfaces/classes
introduced by the O(M+N) scaling refactor), plus updates to AbstractDatastore,
AbstractMappingContext, and related core classes that the datastore modules
(SimpleMap, Hibernate 5/7) depend on at compile time.

Missed from initial clean rebuild commit.

Agent collaboration note: Claude Sonnet 4.6 assisted; borinquenkid is the
primary author and remains responsible for the final changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
During child datastore construction, GormRegistry.registerEntityDatastores
calls getDatastoreForConnection() before the parent's datastoresByConnectionSource
map is populated, throwing ConfigurationException for multi-datasource setups.

H5 anonymous child: add self-reference check so the child returns itself when
asked for its own connection name, rather than delegating to the parent map.

H7 ChildHibernateDatastore: use PARENT_HOLDER ThreadLocal to pass the parent
reference through the super() call before the parent field is assigned; also
pass the parent's datastoresByConnectionSource map to HibernateGormEnhancer
so it can resolve sibling datastores during initialize().

Fixes DataSource not found for name [secondary/schemaA] ConfigurationException
in multi-datasource and schema-per-tenant multi-tenancy test suites.

Agent collaboration note: Claude Sonnet 4.6 assisted; borinquenkid is the
primary author and remains responsible for the final changes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
The O(M+N) GormRegistry refactor exposed two classes of regression in
multi-tenancy and multi-datasource scenarios. This commit addresses both.

Production fixes:

GormApiResolver: Move the DISCRIMINATOR mode check before the
MultipleConnectionSourceCapableDatastore delegation so that tenant IDs are
never mistaken for datasource connection names. For the DEFAULT qualifier,
return the preferred (active-transaction) datastore directly rather than
re-routing through getDatastoreForConnection, which would return the parent
and mismatch the session factory already bound to the transaction.

GormRegistry.registerEntityDatastores: Stop overwriting child datastores with
the parent for non-DEFAULT qualifiers that resolve back to the parent. In
SCHEMA and DISCRIMINATOR mode the qualifier is a runtime tenant ID, not a
datasource name; routing it back to the parent is correct and must not clobber
the child entries added by addTenantForSchemaInternal.

GormRegistry.findTransactionManager: Fall back through the full apiResolver
when getDatastore returns null so that DISCRIMINATOR/SCHEMA tenant IDs still
resolve to a transaction manager.

HibernateDatastore (H5) / ChildHibernateDatastore (H7): Return null instead
of throwing ConfigurationException when getDatastoreForConnection is called
for a sibling that is not yet registered during initialization. GormRegistry
will re-register all entities with the correct datastores once initialization
completes. Child datastores also delegate to the parent for unrecognized
connection names so the lookup chain stays consistent.

HibernateGormInstanceApi (H7): Always resolve the template via the datastore
registry rather than caching a DEFAULT-qualifier instance, so that
preferred-datastore switching in multi-datasource transactions picks up the
correct session factory.

GrailsHibernateTransactionManager (H7): Remove debug System.err.println
statements left over from investigation.

Test infrastructure fixes:

gradle/hibernate5-test-config.gradle, gradle/hibernate7-test-config.gradle:
Set forkEvery = 1 so each test class runs in its own JVM. The root
test-config.gradle uses forkEvery = 50 (CI) / 100 (local) for speed; with a
shared GormRegistry singleton that per-test setup/teardown mutates, TCK specs
running before PartitionedMultiTenancySpec in the same JVM were clearing
datastoresByQualifier["default"], causing a NullPointerException in count()
when PartitionedMultiTenancySpec later resolved a GormPersistentEntity. forkEvery = 1
eliminates cross-class singleton contamination at the cost of extra JVM
startup overhead, which is acceptable given the test isolation requirement.

GrailsDataHibernate5TckManager: Add grailsConfig field and populate a local
ConfigObject from it in createSession(), fixing MissingPropertyException when
test specs assign grailsConfig before calling setup().

Verified: H5 669 tests / 0 failures, H7 2960 tests / 0 failures.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Local issue-tracking files have no Apache license header and are not
source artifacts. Add **/ISSUES.md to the RAT exclusion list alongside
the existing local-tasks.gradle exclusion.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…saction routing

    - GormEnhancer: Remove generic type parameters (`<D>`) from deprecated API lookup methods (`findStaticApi`, `findInstanceApi`, `findValidationApi`). This fixes a `MissingMethodException` encountered
  when older compiled code or dynamic Groovy proxies call these methods without exact signature matches.
    - TransactionalTransform: Fix `IllegalStateException: No GORM implementations configured` in multi-tenant environments. Revert logic that incorrectly passed `tenantId` as a connection source
  qualifier to `GormRegistry`, and instead fetch the tenant-specific datastore using `getTargetDatastore().getDatastoreForTenantId(tenantId)`.
    - ServiceTransformation: Ensure the stateful `$datastore` field is properly generated for generic data services to resolve injection failures in tests.
@borinquenkid borinquenkid force-pushed the 8.0.x-hibernate7.gorm-scaling-clean branch from afa32a1 to 611e6bd Compare May 25, 2026 15:28
@borinquenkid borinquenkid requested review from matrei and sbglasius May 25, 2026 15:32
borinquenkid and others added 5 commits May 25, 2026 10:51
… artifacts

  Fixes TCK DataServiceConnectionRoutingSpec failures introduced during the O(M+N)
  scaling refactor. The decentralized API resolver changes caused getTargetDatastore(String)
  to ignore the explicitly-injected $targetDatastore and route through the API resolver
  instead, which could return a child datastore that has no knowledge of sibling connections.

  - AbstractDatastoreMethodDecoratingTransformation: getTargetDatastore(String) now checks
    $targetDatastore before falling back to the API resolver
  - ServiceTransformation: generateConnectionAwareTransactionManager uses getTargetDatastore()
    instead of getDatastore() for correct multi-datasource transaction manager resolution
  - GrailsDataHibernate7TckManager: fix setTargetDatastore array overload to use
    MultipleConnectionSourceCapableDatastore[] instead of Datastore[]
…) + entity re-registration in setup(), wired setTargetDatastore(multiDataSourceDatastore) in getServiceForConnection(), and wired

  setTargetDatastore(multiTenantMultiDataSourceDatastore) in getServiceForMultiTenantConnection(). This fixes 26 H5 failures.
  2. GrailsDataHibernate7TckManager.groovy — Wired setTargetDatastore(multiTenantMultiDataSourceDatastore) in getServiceForMultiTenantConnection(). This fixes 5 H7
  DataServiceMultiTenantConnectionRoutingSpec failures.
  3. GormApiResolver.groovy — Removed 6 residual System.out.println debug statements from ActiveSessionDatastoreSelector.
  4. ServiceTransformSpec.groovy — Added GormRegistry.reset() in setup()/cleanup() to prevent cross-spec registry pollution causing 3 flaky test failures.
  Root cause: AutoTimestampEventListener.beforeUpdate() unconditionally sets lastUpdated/dateCreated on every PreUpdate event, even when the entity has no user-intent changes. This caused
  PendingUpdate.run() to see a changed property, add it to $set, and increment the optimistic-locking version — breaking the MarkDirtyFalseSpec contract that a no-op save() must not increment version.

  Fix in MongoCodecEntityPersister.persistEntity():
  - Before cancelUpdate fires, capture a snapshot of all property values and whether the entity already had user-intent dirty state (hasPreExistingDirty).
  - After cancelUpdate, compare the snapshot to detect what changed. If the only changes are lastUpdated/dateCreated (auto-timestamp properties) with no pre-existing user-intent dirty state, restore those
  timestamps, call trackChanges(), and veto the update.
  - The veto condition requires onlyAutoTimestampChanged to be non-empty — entities without auto-timestamp properties (including those with embedded-only associations) are never incorrectly vetoed, even
  when the snapshot comparison misses embedded-object mutations (same object reference).
  - Also refactored persistEntity() to remove the unnecessary isUpdate && !session.isDirty(obj) early-return guard, which was incompatible with the snapshot logic.

  Other changes:
  - GrailsDataMongoTckManager: added GormRegistry.reset() in setup() for per-test datastore isolation (prevents stale GORM state polluting successive test features).
  - DirtyCheckingSupport: propagate dirty-checking into PersistentCollection items so collection-element mutations are visible to the parent entity's dirty check traversal.

  Tests verified: MarkDirtyFalseSpec, EmbeddedAssociationSpec, EmbeddedCollectionAndInheritanceSpec, EmbeddedCollectionWithOneToOneSpec, EmbeddedUnsetSpec, LastUpdatedSpec,
  BeforeUpdatePropertyPersistenceSpec, DirtyCheckUpdateSpec — plus full testSelected suite: 4588 tests, 0 failures.
…eDatastore

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
@borinquenkid borinquenkid force-pushed the 8.0.x-hibernate7.gorm-scaling-clean branch from c5f7c32 to 4358b70 Compare May 29, 2026 01:28
borinquenkid and others added 11 commits May 29, 2026 07:50
…resolution

- currentGorm{Instance,Static,Validation}Api() throw IllegalStateException
  when GORM is uninitialized, instead of returning null. Callers such as
  DefaultLinkGenerator.getResourceId already catch IllegalStateException and
  fall back; this restores the pre-O(M+N) contract and fixes NPEs in
  VndErrorRenderingSpec, HalJsonRendererSpec, TableSpec and others.
- GormStaticApi.getGormPersistentEntity() falls back to the mapping context
  captured at construction when registry resolution returns null. Entity
  metadata is identical across tenants, so this stable reference fixes the
  withTenant(tenantId).count() NPE for DISCRIMINATOR multi-tenancy under
  cross-spec registry state (PartitionedMultiTenancySpec in the full suite).
- SimpleMapSession.isDirty() treats an identified instance absent from the
  backing map as dirty so save() re-inserts it. Fixes the unit-test pattern of
  saving @shared instances in setup() across feature iterations after
  clearData() empties the in-memory datastore (DefaultInputRenderingSpec).
- DefaultHalViewHelper.renderEntityProperties excludes the version property from
  embedded output, consistent with top-level GORM rendering. KeyValue entities
  gained an auto-mapped version under the GORM mapping strategy (HalEmbeddedSpec).
- Remove stale @NotYetImplemented on UniqueConstraintOnHasOneSpec; unique-on-hasOne
  now works, so the spec passes and the assertion is restored.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Fixes five of the six failing Functional Tests CI tasks. Each was a core GORM
contract that regressed in the shared-GormRegistry rewrite but surfaced far
downstream; root-cause fixes are guarded by core unit tests.

- SimpleMapSession: a rolled-back transaction set a session-level rollbackOnly
  flag that was never cleared, permanently turning flush() into a no-op on the
  (long-lived, thread-bound) test session. Subsequent save(flush:true) calls
  assigned an id and populated the first-level cache but never reached the
  backing map. Clear the marker on commit/rollback and reset it when a
  transaction begins. Adds SimpleMapSessionSpec coverage. Fixes the app1
  BookControllerSpec save/delete count()==0 failures.

- DataTest harness: the single shared GormRegistry resolves a domain mapped to a
  non-default datasource to a dedicated per-connection child datastore, but the
  unit-test interceptors only bound a session for the default datastore. Entities
  on non-default datasources ran in throwaway per-call sessions, so save()
  without an explicit flush was lost before an auto-flushing query. Bind (and
  symmetrically unbind) a session for every connection source; no-op for
  single-datasource specs. Adds NonDefaultDatasourceFlushSpec. Fixes demo33
  CarSpec.

- GormStaticApi.withTransaction(Map)/withNewTransaction(Map): replaced the broken
  definition.setProperty(key, value) call (no such method on the Java bean
  DefaultTransactionDefinition) with the property-set idiom definition[key]=value,
  plus CharSequence coercion and a clear error for unknown properties. Fixes
  CrossDatasourceTransactionSpec read-only transactions.

- DefaultHalViewHelper: reverted the embedded-version exclusion. Embedded HAL
  output renders the version property for versioned entities (functional TeamSpec
  depends on it); the unit-level HalEmbeddedSpec only saw an extra version:0
  because KeyValue entities now auto-map a version under the GORM mapping
  strategy, so its expectation is updated instead.

- demo33 UniqueConstraintOnHasOneSpec: removed a stale @NotYetImplemented (a
  second copy of an already-fixed spec) that fails as "passes unexpectedly".

- Bar/FooIntegrationSpec: assert datastore persistence through public, observable
  behavior (Mongo ObjectId / Hibernate sequential id) instead of the removed
  internal org.grails.datastore.gorm.GormEnhancer.findStaticApi probe.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Removed unused imports and redundant code from ServiceTransformation and HibernateDatastore to fix linting violations.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ging capture

- Update ActiveSessionDatastoreSelector in GormApiResolver to correctly bypass the parent DEFAULT datastore when routing multi-tenant entity operations in DATABASE/SCHEMA modes, without inadvertently skipping explicitly opened child datastores. This resolves transaction auto-commit issues in DatabasePerTenantIntegrationSpec.
- Adjust GraphQL CommentIntegrationSpec StringMessagePrintStream output capture to filter out SLF4J deprecation warnings (HHH90000022: Hibernate's legacy org.hibernate.Criteria API is deprecated), preventing false-positive query over-counting.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- GormApiResolver: Ensure PreferredDatastoreSelector performs tenant validation for DEFAULT qualifier when the preferred datastore is multi-tenant capable, preventing static queries like count() from incorrectly querying the parent datastore in an active transaction.
- GrailsHibernateTransactionManager (H5): Reapply the isExistingTransaction override from H7 to ensure transactions bound to the parent SessionFactory are not mistakenly reused for tenant-specific DataSources.
The integration tests were capturing and counting all System.out logs as queries, causing Hibernate deprecation warnings to fail the assertions. Filtered capture to explicitly require 'Hibernate:'.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
In Gradle 9, ProjectDependency.getDependencyProject() has been removed.
Updated gradle/test-config.gradle to recursively identify any subprojects
depending on ':grails-datamapping-core' (GORM) using path resolution, and
force their test tasks to run with maxParallelForks = 1. This prevents
singleton GormRegistry and local resource conflicts in CI while preserving
parallel execution for all other modules.

Co-Authored-By: Gemini <noreply@google.com>
…fix Hibernate 5 schema-per-tenant resource unbinding

    - Remove Hibernate 5/7, MongoDB, and Neo4j datastores from GormRegistry upon destroy/close to prevent scalability/leak issues.
    - Unbind the tenant-specific DataSource from TransactionSynchronizationManager in Hibernate 5 schema-per-tenant setup to prevent thread connection bound state conflicts.
    - Restore previous connection holder correctly in GrailsHibernateTemplate regardless of session holder existence.

    Co-Authored-By: Gemini <noreply@google.com>
…n exists

Update Tenants.withId to check if the child datastore for the tenant
already has a current session active on the thread. If so, execute the
closure directly rather than forcing a new session, which preserves
transaction propagation for multi-tenant integrations. Also, clean up
debug print statements and use protected logger.debug statements under
the log.isDebugEnabled() check.
…ling

- Restore connection routing to use getDatastoreForConnection instead of getDatastoreForTenantId in AbstractDatastoreMethodDecoratingTransformation.
- Align SimpleMapDatastore getDatastoreForTenantId with relational/document tenancy invariants by returning this for non-DATABASE modes.
- Avoid StackOverflowError in transactional method decoration by using AttributeExpression (direct field access) to access the transactionManager field.
- Prevent duplicate transactionManager field/method weaving in subclasses when already inherited or declared on the superclass.
- Update GormRegistry lookup methods to return null instead of throwing IllegalStateException on missing qualifiers if the defaultDatastore is initialized.
- Expose defaultDatastore property in GormRegistry.
- Update ISSUES.md.
@codecov

codecov Bot commented Jun 25, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 19.0184%. Comparing base (0a334c8) to head (cd56ee0).

Additional details and impacted files

Impacted file tree graph

@@                 Coverage Diff                 @@
##                8.0.x     #15678         +/-   ##
===================================================
- Coverage     49.2583%   19.0184%   -30.2399%     
+ Complexity      16506        288      -16218     
===================================================
  Files            1941         57       -1884     
  Lines           92023       3423      -88600     
  Branches        16062        597      -15465     
===================================================
- Hits            45329        651      -44678     
+ Misses          39649       2642      -37007     
+ Partials         7045        130       -6915     

see 1884 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.

@borinquenkid borinquenkid force-pushed the 8.0.x-hibernate7.gorm-scaling-clean branch from f50cb5c to 7b08ae1 Compare June 25, 2026 13:35
borinquenkid and others added 2 commits June 25, 2026 09:40
Resolves 15 merge conflicts introduced when the PR base was automatically
changed from 8.0.x-hibernate7 to 8.0.x.

Resolution strategy: prefer 8.0.x structure; preserve O(M+N) scaling
changes from HEAD.

Files resolved by taking 8.0.x (pure infra/test changes):
- gradlew.bat — improved Windows setlocal/exit handling
- GrailsDataHibernate5TckManager.groovy — simplified cast
- HibernateDatastoreSpringInitializerSpec.groovy — simplified withNewSession calls
- DistinctProjectionSpec.groovy — correct Person domain import
- DirtyCheckingAfterListenerSpec.groovy — remove duplicate imports
- GormEnhancerSpec.groovy — new getAll test coverage from 8.0.x
- NullValueEqualSpec.groovy — add H7 @IgnoreIf condition
- OneToManySpec.groovy — improved test naming
- OptimisticLockingSpec.groovy — improved @IgnoreIf style

Files resolved by manual merge (preserve O(M+N) content):
- HibernateEntity.groovy — keep findAllWithNativeSql/findWithNativeSql (new
  public API from HEAD); adopt 8.0.x currentHibernateStaticApi() helper;
  keep findAllWithSql/findWithSql non-deprecated per 8.0.x
- HibernateGormInstanceApi.groovy — take 8.0.x's isAttached/lock/attach with
  HibernateAttachSupport; remove duplicate methods left by HEAD reorganization
- HibernateGormStaticApi.groovy — merge-both: DatastoreResolver constructors,
  withNewSession(Serializable), eachTenant, withTenant from HEAD (O(M+N)
  multi-tenancy routing); doListInternal/doSingleInternal, findAllWithNativeSql,
  findWithNativeSql, event-firing query helpers from 8.0.x
- GrailsDataTckManager.groovy — keep HEAD's TransactionCapableDatastore and
  PlatformTransactionManager (O(M+N) test infra); prefer 8.0.x domain class list
- HibernateGormEnhancerSpec.groovy — correct package for HibernateGormDatastoreSpec
  (grails.gorm.tests); keep GormRegistry import (O(M+N) assertions)
- HibernateGormStaticApiSpec.groovy — correct Club package (grails.gorm.tests);
  keep GormRegistry + AvailableHints imports (both actively used); take 8.0.x
  improved test bodies with GString injection-safety test

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@jamesfredley

Copy link
Copy Markdown
Contributor

taking a look now, I use multi-tenant in a few apps

@jamesfredley

Copy link
Copy Markdown
Contributor

@borinquenkid I am seeing a bit more than expected in the PR including routing fixes, transaction changes, test isolation changes, Mongo/Neo4j/simple datastore edits, TCK rewrites, debug specs, and deleted cross-layer tests. Can you catch me up on how these relate to Multi-tenancy resolution regressions and Child datastore initialization order ?

@borinquenkid

Copy link
Copy Markdown
Member Author

Thanks for the detailed read — happy to connect the dots.

The single root cause is commit 8f1500d, which replaced GormEnhancer's per-entity static maps (one (entityClass, qualifier) → GormApi entry per entity × per connection — O(M×N) memory) with a single process-wide GormRegistry that resolves APIs on demand using a selector chain. Every other change in this PR is a downstream ripple from that one architectural swap. The two threads you named map to the two hardest ripples:


Thread 1 — Multi-tenancy resolution regressions

The old static maps gave each entity a direct pointer to its API for a given connection at enhancement time. The registry replaces that with a runtime selector chain (ActiveSession → Preferred → Qualified → Default). Several call sites assumed the old direct-lookup contract and started resolving to the wrong (usually default) datastore for non-default connections or tenants:

  • Routing fixes (DatastoreResolver, GormApiResolver, ActiveSessionDatastoreSelector, PreferredDatastoreSelector): correct the selector chain for non-default connection/tenant resolution paths that the static maps used to short-circuit.
  • Transaction changes (GormStaticApi.withTransaction(Map), GrailsHibernateTransactionManager): the withTransaction(Map) overload called definition.setProperty(k, v) — no such method on DefaultTransactionDefinition (a Java bean), which was silently tolerated before but now hits a hot path under registry routing. Also fixed GrailsHibernateTransactionManager to see child-datastore sessions when participating in a parent transaction.
  • Mongo/Neo4j/Simple edits: each datastore previously managed its own static enhancement maps. This PR registers each with GormRegistry (registerDatastore() / registerApiFactory()) and adds the getDatastoreForTenantId fallback to MongoDatastore (the multi-tenancy tenant resolver was calling into the registry before the child datastore was registered). SimpleMapSession had a latent rollbackOnly bug (a rolled-back tx set a session-level flag that was never cleared) that the registry's new session-per-call paths surfaced.
  • Test isolation changes (DataTestSetupInterceptor / DataTestCleanupInterceptor): the harness only bound a session for the default datastore. A non-default-connection entity now resolves to a dedicated child datastore — without a bound session, save() opened a throwaway per-call session that was discarded on return. The fix binds and unbinds a session per connection source (no-op for single-datasource specs).

Thread 2 — Child datastore initialization order

ChildHibernateDatastore.initialize() returned null in the 8.0.x-hibernate7 base — the child was intentionally not enhanced. Under the registry, each child must register its own APIs (so multi-datasource entities resolve to the right child). The new initialize() calls new HibernateGormEnhancer(this, txManager, settings, datastoresByConnectionSource). The critical ordering constraint: datastoresByConnectionSource in the parent must be populated before the child is constructed (the parent builds its connection map during its own initialize(), then calls new ChildHibernateDatastore(parent, ...)). The bindParent() / PARENT_HOLDER thread-local in ChildHibernateDatastore handles the case where getPrimaryDatastore() is called during the super-constructor chain before this.parent is assigned.

  • TCK rewrites (GrailsDataTckManager): the manager now calls setTargetDatastore(childDatastore) after the parent initializes, so the TCK spec's manager.session and service lookups go to the right child. The domain-class list was changed from Set to List because entity registration order now matters for the registry's MappingContext traversal.

Two items that need explicit acknowledgment:

  • Debug specs (DebugGetSpec, DebugGeoJSONDecodeSpec, etc. in grails-data-mongodb): these were written to isolate get() failures during root-cause investigation. Their underlying test logic is sound, but the Debug prefix and println calls shouldn't be merged. I'll rename them to production spec names and remove the debug output before this lands.
  • Deleted cross-layer tests (CrossLayerMultiDataSourceSpec, CrossLayerMultiTenantMultiDataSourceSpec): these called manager.getServiceForConnection(SomeService, 'secondary') to fetch a service bean from the child datastore's Spring context — internal wiring that the registry no longer exposes that way. Rather than patching around a removed internal, the contract is now covered in two purpose-built specs: DomainMultiDataSourceSpec (domain-API routing to secondary) and DataServiceConnectionRoutingSpec (service routing via @service(datasource='secondary')). The net line count for multi-datasource coverage went up, not down. That said, I can explicitly document the equivalence in the spec Javadoc if that helps reviewers verify the coverage isn't lost.

tl;dr: The PR is wider than a typical bug-fix because the root change was architectural — every datastore (H5, H7, Mongo, Neo4j, SimpleMap), the test harness, and the TCK had local copies of the enhancement pattern that all needed updating. The scope tracks the scope of the original GormRegistry rewrite.

borinquenkid and others added 2 commits June 26, 2026 12:43
…d debug spec cleanup

- HibernateGormStaticApi: replace bare `persistentEntity` references (from
  the now-removed AbstractGormApi field) with `gormPersistentEntity` property
  calls in buildWhereHql, validateWherePropertyName, getAllInternal,
  prepareHqlQuery, firePostQueryEvent, and firePreQueryEvent; fixes 17
  @CompileStatic errors that appeared after the GormRegistry migration removed
  the field
- HibernateGormStaticApi: remove duplicate `import...Query` (was shadowing the
  aliased `import...Query as GormQuery`); update two bare Query usages to GormQuery
- HibernateEntity: replace removed GormEnhancer.findStaticApi() call with
  GormRegistry.findStaticApi() so currentHibernateStaticApi() compiles under
  @CompileStatic
- grails-data-mongodb: remove 7 debug/duplicate geo test files (DebugGeoJSONSpec,
  DebugGeoJSONDecodeSpec, DebugGeoJSONQuerySpec, DebugGetSpec, GeoPlaceTest,
  GeoRetrieveTest, SimplePlaceTest) that imported a non-existent MongoDatastoreSpec
  and whose coverage is fully provided by GeoJSONTypePersistenceSpec
- grails-datamapping-tck: add Javadoc to four replacement specs explaining why
  CrossLayerMultiDataSourceSpec and CrossLayerMultiTenantMultiDataSourceSpec were
  removed and where their coverage now lives

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
… merge

The cosmetics cleanup commit (efc250a) removed the 'as Class[]' coercions
from domainClasses when passing it to DefaultGrailsApplication and
HibernateDatastore constructors. Those constructors expect Class<?>[] but
getDomainClasses() returns Collections.unmodifiableList() (an
UnmodifiableRandomAccessList), so Groovy's MOP cannot find a matching
constructor at runtime, failing every TCK spec with:
  GroovyRuntimeException: Could not find matching constructor for:
  DefaultGrailsApplication(UnmodifiableRandomAccessList, GroovyClassLoader)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@jamesfredley

Copy link
Copy Markdown
Contributor

@borinquenkid I think something laser targeted to O(entityCount * qualifierCount) like #15771, will be much easier to get the required reviews and merged.

…nation, and test class conflicts

- Revert version property initialization from constX(0L) to null in GormEntityTransformation;
  our O(M+N) scaling commit mistakenly changed the initial value, causing DirtyCheckBindingSpec
  to assert version=null on a transient entity that actually had version=0L.

- Fix HibernateGormInstanceApi.isAttached/lock/attach to use getHibernateTemplate() lazy getter
  instead of direct hibernateTemplate field access; HibernateGormApiFactory constructs the API
  without setting that field, so direct access was an NPE for any request touching these methods.

- Fix HibernateGormStaticApi.executeQuery(query, Map) to pass the same map as both namedParams
  and querySettings (matching H5 behavior); pagination keys (max, offset) were being sent only
  to namedParams where INTERNAL_SETTINGS skips them, so no setMaxResults was applied.

- Add coerceId() helper in H7 HibernateSession.retrieveAll() to convert String IDs to the
  entity's declared identifier type before HQL lookup and result map key comparison.

- Rename local Person class to DirtyCheckPerson in HibernateDirtyCheckingSpec and
  HibernateUpdateFromListenerSpec (H5+H7) to eliminate DuplicateMappingException collision
  with the TCK's org.apache.grails.data.testing.tck.domains.Person.

- Replace reflection on removed DATASTORES/STATIC_APIS fields in H5 GormEnhancerCleanupSpec
  and HibernateGormEnhancerSpec with GormRegistry public API (matching H7 versions).

- Remove @NotYetImplemented from demo33 UniqueConstraintOnHasOneSpec — the test now passes.

- Fix MongoDB PlacePartialTest/PlaceWithExceptionTest/PlaceWithoutSphereTest compilation by
  extending GrailsDataTckSpec<GrailsDataMongoTckManager> instead of non-existent MongoDatastoreSpec.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@testlens-app

testlens-app Bot commented Jun 26, 2026

Copy link
Copy Markdown

🚨 TestLens detected 1128 failed tests 🚨

Here is what you can do:

  1. Inspect the test failures carefully.
  2. If you are convinced that some of the tests are flaky, you can mute them below.
  3. Finally, trigger a rerun by checking the rerun checkbox.

Test Summary

CI - Groovy Joint Validation Build / build_grails > :grails-data-hibernate5-core:test

Test Runs
GormEnhancerSpec > Test getAll preserves the supplied id order
GormEnhancerSpec > Test getAll returns a null slot for a missing id
HibernateGetAllConvertibleIdSpec > getAll preserves order for convertible String ids
HibernateGormEnhancerSpec > test getStaticApi, getInstanceApi, getValidationApi
UniqueWithinGroupSpec > test insert

CI - Groovy Joint Validation Build / build_grails > :grails-data-hibernate5-core:test

Test Runs
GormEnhancerSpec > Test getAll preserves the supplied id order
GormEnhancerSpec > Test getAll returns a null slot for a missing id
HibernateGetAllConvertibleIdSpec > getAll preserves order for convertible String ids
HibernateGormEnhancerSpec > test getStaticApi, getInstanceApi, getValidationApi
UniqueWithinGroupSpec > test insert

CI - Groovy Joint Validation Build / build_grails > :grails-data-hibernate7-core:test (first 40 of 46)

Test Runs
ByteBuddyGroovyInterceptorSpec > Groovy method throwing exception is handled
ByteBuddyGroovyInterceptorSpec > accessing a regular property initializes the proxy and returns the value
ByteBuddyGroovyInterceptorSpec > getIdentifier() on uninitialized proxy returns identifier without initialization
ByteBuddyGroovyInterceptorSpec > getProperty via Groovy on initialized proxy delegates via reflection
ByteBuddyGroovyInterceptorSpec > id property on uninitialized proxy returns identifier without initialization
ByteBuddyGroovyInterceptorSpec > ident() on uninitialized proxy returns identifier without initialization
ByteBuddyGroovyInterceptorSpec > invokeMethod via Groovy on initialized proxy delegates via reflection
ByteBuddyGroovyInterceptorSpec > isDirty() on uninitialized proxy returns false without initialization
ByteBuddyGroovyInterceptorSpec > metaClass on uninitialized proxy returns metaclass without initialization
ByteBuddyGroovyInterceptorSpec > setMetaClass on uninitialized proxy initializes the proxy
ByteBuddyGroovyInterceptorSpec > setProperty on uninitialized proxy initializes the proxy
ByteBuddyGroovyInterceptorSpec > toString() on uninitialized proxy returns entityName:id without initialization
CollectionBinderSpec > test bindCollection delegates configuration to property.setCollection
CollectionBinderSpec > test bindCollection for many-to-many uses calculator
GrailsHibernatePersistentEntitySpec > test buildDiscriminatorSet for simple entity
GrailsHibernatePersistentEntitySpec > test buildDiscriminatorSet with custom discriminator value
GrailsHibernatePersistentEntitySpec > test buildDiscriminatorSet with dataSourceName
GrailsHibernatePersistentEntitySpec > test buildDiscriminatorSet with hierarchy
GrailsHibernatePersistentEntitySpec > test buildDiscriminatorSet with numeric discriminator type
GrailsHibernatePersistentEntitySpec > test configureDerivedProperties
GrailsHibernatePersistentEntitySpec > test dataSourceName injection
GrailsHibernatePersistentEntitySpec > test getChildEntities
GrailsHibernatePersistentEntitySpec > test getDiscriminatorValue
GrailsHibernatePersistentEntitySpec > test getHibernateCompositeIdentity returns CompositeIdentity when conditions met
GrailsHibernatePersistentEntitySpec > test getHibernateCompositeIdentity returns empty when mapping has no composite identifier
GrailsHibernatePersistentEntitySpec > test getHibernateCompositeIdentity returns empty when mapping is null
GrailsHibernatePersistentEntitySpec > test getHibernateCompositeIdentity returns empty when mapping.getIdentity is not CompositeIdentity
GrailsHibernatePersistentEntitySpec > test getHibernateIdentity defaults to entity name if identity name is null
GrailsHibernatePersistentEntitySpec > test getHibernateIdentity returns CompositeIdentity if entity has multiple ID properties
GrailsHibernatePersistentEntitySpec > test getHibernateIdentity returns mapping identity if available
GrailsHibernatePersistentEntitySpec > test getHibernateIdentity returns synthetic Identity if no mapping or composite ID
GrailsHibernatePersistentEntitySpec > test getHibernatePersistentProperties calls validateProperty
GrailsHibernatePersistentEntitySpec > test getHibernatePropertyByPath
GrailsHibernatePersistentEntitySpec > test getHibernateRootEntity and getRootMapping
GrailsHibernatePersistentEntitySpec > test getMultiTenantFilterCondition
GrailsHibernatePersistentEntitySpec > test getPersistentPropertiesToBind
GrailsHibernatePersistentEntitySpec > test getSchema and getCatalog
GrailsHibernatePersistentEntitySpec > test getTableName
GrailsHibernatePersistentEntitySpec > test isComponentPropertyNullable
GrailsHibernatePersistentEntitySpec > test isTablePerHierarchySubclass

CI - Groovy Joint Validation Build / build_grails > :grails-data-hibernate7-core:test (first 40 of 46)

Test Runs
ByteBuddyGroovyInterceptorSpec > Groovy method throwing exception is handled
ByteBuddyGroovyInterceptorSpec > accessing a regular property initializes the proxy and returns the value
ByteBuddyGroovyInterceptorSpec > getIdentifier() on uninitialized proxy returns identifier without initialization
ByteBuddyGroovyInterceptorSpec > getProperty via Groovy on initialized proxy delegates via reflection
ByteBuddyGroovyInterceptorSpec > id property on uninitialized proxy returns identifier without initialization
ByteBuddyGroovyInterceptorSpec > ident() on uninitialized proxy returns identifier without initialization
ByteBuddyGroovyInterceptorSpec > invokeMethod via Groovy on initialized proxy delegates via reflection
ByteBuddyGroovyInterceptorSpec > isDirty() on uninitialized proxy returns false without initialization
ByteBuddyGroovyInterceptorSpec > metaClass on uninitialized proxy returns metaclass without initialization
ByteBuddyGroovyInterceptorSpec > setMetaClass on uninitialized proxy initializes the proxy
ByteBuddyGroovyInterceptorSpec > setProperty on uninitialized proxy initializes the proxy
ByteBuddyGroovyInterceptorSpec > toString() on uninitialized proxy returns entityName:id without initialization
CollectionBinderSpec > test bindCollection delegates configuration to property.setCollection
CollectionBinderSpec > test bindCollection for many-to-many uses calculator
GrailsHibernatePersistentEntitySpec > test buildDiscriminatorSet for simple entity
GrailsHibernatePersistentEntitySpec > test buildDiscriminatorSet with custom discriminator value
GrailsHibernatePersistentEntitySpec > test buildDiscriminatorSet with dataSourceName
GrailsHibernatePersistentEntitySpec > test buildDiscriminatorSet with hierarchy
GrailsHibernatePersistentEntitySpec > test buildDiscriminatorSet with numeric discriminator type
GrailsHibernatePersistentEntitySpec > test configureDerivedProperties
GrailsHibernatePersistentEntitySpec > test dataSourceName injection
GrailsHibernatePersistentEntitySpec > test getChildEntities
GrailsHibernatePersistentEntitySpec > test getDiscriminatorValue
GrailsHibernatePersistentEntitySpec > test getHibernateCompositeIdentity returns CompositeIdentity when conditions met
GrailsHibernatePersistentEntitySpec > test getHibernateCompositeIdentity returns empty when mapping has no composite identifier
GrailsHibernatePersistentEntitySpec > test getHibernateCompositeIdentity returns empty when mapping is null
GrailsHibernatePersistentEntitySpec > test getHibernateCompositeIdentity returns empty when mapping.getIdentity is not CompositeIdentity
GrailsHibernatePersistentEntitySpec > test getHibernateIdentity defaults to entity name if identity name is null
GrailsHibernatePersistentEntitySpec > test getHibernateIdentity returns CompositeIdentity if entity has multiple ID properties
GrailsHibernatePersistentEntitySpec > test getHibernateIdentity returns mapping identity if available
GrailsHibernatePersistentEntitySpec > test getHibernateIdentity returns synthetic Identity if no mapping or composite ID
GrailsHibernatePersistentEntitySpec > test getHibernatePersistentProperties calls validateProperty
GrailsHibernatePersistentEntitySpec > test getHibernatePropertyByPath
GrailsHibernatePersistentEntitySpec > test getHibernateRootEntity and getRootMapping
GrailsHibernatePersistentEntitySpec > test getMultiTenantFilterCondition
GrailsHibernatePersistentEntitySpec > test getPersistentPropertiesToBind
GrailsHibernatePersistentEntitySpec > test getSchema and getCatalog
GrailsHibernatePersistentEntitySpec > test getTableName
GrailsHibernatePersistentEntitySpec > test isComponentPropertyNullable
GrailsHibernatePersistentEntitySpec > test isTablePerHierarchySubclass

CI - Groovy Joint Validation Build / build_grails > :grails-data-mongodb-core:test (first 40 of 513)

Test Runs
AggregateMethodSpec > Test aggregate method
AssignedIdentifierSpec > Test that assigned identifiers work with property setting
AssignedIdentifierSpec > Test that assigned identifiers work with stateless domains
AssignedIdentifierSpec > Test that assigned identifiers work with the constructor
AssignedIdentifierSpec > Test that entities can be saved, retrieved and updated with assigned ids
AssignedIdentifierSpec > Test that saving a second object with an assigned identifier produces an error
AttachMethodSpec > Test attach method
AutowireServicesSpec > Test that services can be autowired
BasicArraySpec > Test that arrays are saved correctly
BasicArraySpec > Test that arrays of convertible properties are saved correctly
BasicArraySpec > Test that byte arrays are saved as binary
BasicCollectionTypeSpec > Test persist basic collection types
BasicCollectionsSpec > Test beforeInsert() and beforeUpdate() methods for collections
BasicCollectionsSpec > Test that a Locale can be used inside a collection
BasicCollectionsSpec > Test that a map of BigDecimal works.
BasicCollectionsSpec > Test that a map of Currency works.
BatchUpdateDeleteSpec > Test that batch delete works
BatchUpdateDeleteSpec > Test that batch update works
BatchUpdateDeleteSpec > Test that batch update works with domain properties
BeforeInsertUpdateSpec > Test that before insert and update events are triggered without issue
BeforeUpdatePropertyPersistenceSpec > Test that beforeUpdate is called even when no properties are explicitly modified
BeforeUpdatePropertyPersistenceSpec > Test that multiple updates continue to trigger beforeUpdate
BeforeUpdatePropertyPersistenceSpec > Test that properties set in beforeUpdate are persisted
BeforeUpdatePropertyPersistenceSpec > Test that properties set in beforeUpdate with AutoTimestamp are persisted
BigDecimalSpec > test save and retrieve big decimal value
BrokenManyToManyAssociationSpec > Perform a cascading delete on a broken many-to-many relationship
BuiltinUniqueConstraintWorksWithTargetProxiesConstraintsSpec > test unique constraint for the associated child object
BuiltinUniqueConstraintWorksWithTargetProxiesConstraintsSpec > test unique constraint on root instance
BuiltinUniqueConstraintWorksWithTargetProxiesConstraintsSpec > test unique constraint on the unmodified association loaded as initialized proxy
CascadeDeleteOneToOneSpec > Test delete doesnt cascade if no belongsTo
CascadeDeleteOneToOneSpec > Test owner deletes child in one-to-one cascade
CascadeDeleteSpec > Test that a delete cascade from owner to child
CircularBidirectionalOneToManySpec > Test store and retrieve circular one-to-many association
CircularBidirectionalOneToManySpec > Test that deleting a child doesn't not delete the parent in a circular association
CircularEmbeddedListSpec > Test CRUD operations on circular nested embedded list
CircularOneToManySpec > Test circular one-to-many
CircularOneToManySpec > Test store and retrieve circular one-to-many association
CircularOneToManySpec > Test that deleting a child doesn't not delete the parent in a circular association
ClearCollectionSpec > Test clear embedded mongo collection
CommonTypesPersistenceSpec > testPersistBasicTypes

CI - Groovy Joint Validation Build / build_grails > :grails-data-mongodb-core:test (first 40 of 513)

Test Runs
AggregateMethodSpec > Test aggregate method
AssignedIdentifierSpec > Test that assigned identifiers work with property setting
AssignedIdentifierSpec > Test that assigned identifiers work with stateless domains
AssignedIdentifierSpec > Test that assigned identifiers work with the constructor
AssignedIdentifierSpec > Test that entities can be saved, retrieved and updated with assigned ids
AssignedIdentifierSpec > Test that saving a second object with an assigned identifier produces an error
AttachMethodSpec > Test attach method
AutowireServicesSpec > Test that services can be autowired
BasicArraySpec > Test that arrays are saved correctly
BasicArraySpec > Test that arrays of convertible properties are saved correctly
BasicArraySpec > Test that byte arrays are saved as binary
BasicCollectionTypeSpec > Test persist basic collection types
BasicCollectionsSpec > Test beforeInsert() and beforeUpdate() methods for collections
BasicCollectionsSpec > Test that a Locale can be used inside a collection
BasicCollectionsSpec > Test that a map of BigDecimal works.
BasicCollectionsSpec > Test that a map of Currency works.
BatchUpdateDeleteSpec > Test that batch delete works
BatchUpdateDeleteSpec > Test that batch update works
BatchUpdateDeleteSpec > Test that batch update works with domain properties
BeforeInsertUpdateSpec > Test that before insert and update events are triggered without issue
BeforeUpdatePropertyPersistenceSpec > Test that beforeUpdate is called even when no properties are explicitly modified
BeforeUpdatePropertyPersistenceSpec > Test that multiple updates continue to trigger beforeUpdate
BeforeUpdatePropertyPersistenceSpec > Test that properties set in beforeUpdate are persisted
BeforeUpdatePropertyPersistenceSpec > Test that properties set in beforeUpdate with AutoTimestamp are persisted
BigDecimalSpec > test save and retrieve big decimal value
BrokenManyToManyAssociationSpec > Perform a cascading delete on a broken many-to-many relationship
BuiltinUniqueConstraintWorksWithTargetProxiesConstraintsSpec > test unique constraint for the associated child object
BuiltinUniqueConstraintWorksWithTargetProxiesConstraintsSpec > test unique constraint on root instance
BuiltinUniqueConstraintWorksWithTargetProxiesConstraintsSpec > test unique constraint on the unmodified association loaded as initialized proxy
CascadeDeleteOneToOneSpec > Test delete doesnt cascade if no belongsTo
CascadeDeleteOneToOneSpec > Test owner deletes child in one-to-one cascade
CascadeDeleteSpec > Test that a delete cascade from owner to child
CircularBidirectionalOneToManySpec > Test store and retrieve circular one-to-many association
CircularBidirectionalOneToManySpec > Test that deleting a child doesn't not delete the parent in a circular association
CircularEmbeddedListSpec > Test CRUD operations on circular nested embedded list
CircularOneToManySpec > Test circular one-to-many
CircularOneToManySpec > Test store and retrieve circular one-to-many association
CircularOneToManySpec > Test that deleting a child doesn't not delete the parent in a circular association
ClearCollectionSpec > Test clear embedded mongo collection
CommonTypesPersistenceSpec > testPersistBasicTypes

🏷️ Commit: 2f651c7
▶️ Tests: 60644 executed
⚪️ Checks: 91/91 completed

Test Failures (first 10 of 1128)

AggregateMethodSpec > Test aggregate method (:grails-data-mongodb-core:test in CI - Groovy Joint Validation Build / build_grails)
java.lang.IllegalArgumentException: wrong number of arguments: 26 expected: 1
	at org.apache.grails.data.mongo.core.GrailsDataMongoTckManager.createSession(GrailsDataMongoTckManager.groovy:136)
	at org.apache.grails.data.testing.tck.base.GrailsDataTckManager.setup(GrailsDataTckManager.groovy:134)
	at org.apache.grails.data.mongo.core.GrailsDataMongoTckManager.setup(GrailsDataMongoTckManager.groovy:72)
	at org.apache.grails.data.testing.tck.base.GrailsDataTckSpec.setup(GrailsDataTckSpec.groovy:65)
AggregateMethodSpec > Test aggregate method (:grails-data-mongodb-core:test in CI - Groovy Joint Validation Build / build_grails)
java.lang.IllegalArgumentException: wrong number of arguments: 26 expected: 1
	at org.apache.grails.data.mongo.core.GrailsDataMongoTckManager.createSession(GrailsDataMongoTckManager.groovy:136)
	at org.apache.grails.data.testing.tck.base.GrailsDataTckManager.setup(GrailsDataTckManager.groovy:134)
	at org.apache.grails.data.mongo.core.GrailsDataMongoTckManager.setup(GrailsDataMongoTckManager.groovy:72)
	at org.apache.grails.data.testing.tck.base.GrailsDataTckSpec.setup(GrailsDataTckSpec.groovy:65)
AssignedIdentifierSpec > Test that assigned identifiers work with property setting (:grails-data-mongodb-core:test in CI - Groovy Joint Validation Build / build_grails)
java.lang.IllegalArgumentException: wrong number of arguments: 28 expected: 1
	at org.apache.grails.data.mongo.core.GrailsDataMongoTckManager.createSession(GrailsDataMongoTckManager.groovy:136)
	at org.apache.grails.data.testing.tck.base.GrailsDataTckManager.setup(GrailsDataTckManager.groovy:134)
	at org.apache.grails.data.mongo.core.GrailsDataMongoTckManager.setup(GrailsDataMongoTckManager.groovy:72)
	at org.apache.grails.data.testing.tck.base.GrailsDataTckSpec.setup(GrailsDataTckSpec.groovy:65)
AssignedIdentifierSpec > Test that assigned identifiers work with property setting (:grails-data-mongodb-core:test in CI - Groovy Joint Validation Build / build_grails)
java.lang.IllegalArgumentException: wrong number of arguments: 28 expected: 1
	at org.apache.grails.data.mongo.core.GrailsDataMongoTckManager.createSession(GrailsDataMongoTckManager.groovy:136)
	at org.apache.grails.data.testing.tck.base.GrailsDataTckManager.setup(GrailsDataTckManager.groovy:134)
	at org.apache.grails.data.mongo.core.GrailsDataMongoTckManager.setup(GrailsDataMongoTckManager.groovy:72)
	at org.apache.grails.data.testing.tck.base.GrailsDataTckSpec.setup(GrailsDataTckSpec.groovy:65)
AssignedIdentifierSpec > Test that assigned identifiers work with stateless domains (:grails-data-mongodb-core:test in CI - Groovy Joint Validation Build / build_grails)
java.lang.IllegalArgumentException: wrong number of arguments: 28 expected: 1
	at org.apache.grails.data.mongo.core.GrailsDataMongoTckManager.createSession(GrailsDataMongoTckManager.groovy:136)
	at org.apache.grails.data.testing.tck.base.GrailsDataTckManager.setup(GrailsDataTckManager.groovy:134)
	at org.apache.grails.data.mongo.core.GrailsDataMongoTckManager.setup(GrailsDataMongoTckManager.groovy:72)
	at org.apache.grails.data.testing.tck.base.GrailsDataTckSpec.setup(GrailsDataTckSpec.groovy:65)
AssignedIdentifierSpec > Test that assigned identifiers work with stateless domains (:grails-data-mongodb-core:test in CI - Groovy Joint Validation Build / build_grails)
java.lang.IllegalArgumentException: wrong number of arguments: 28 expected: 1
	at org.apache.grails.data.mongo.core.GrailsDataMongoTckManager.createSession(GrailsDataMongoTckManager.groovy:136)
	at org.apache.grails.data.testing.tck.base.GrailsDataTckManager.setup(GrailsDataTckManager.groovy:134)
	at org.apache.grails.data.mongo.core.GrailsDataMongoTckManager.setup(GrailsDataMongoTckManager.groovy:72)
	at org.apache.grails.data.testing.tck.base.GrailsDataTckSpec.setup(GrailsDataTckSpec.groovy:65)
AssignedIdentifierSpec > Test that assigned identifiers work with the constructor (:grails-data-mongodb-core:test in CI - Groovy Joint Validation Build / build_grails)
java.lang.IllegalArgumentException: wrong number of arguments: 28 expected: 1
	at org.apache.grails.data.mongo.core.GrailsDataMongoTckManager.createSession(GrailsDataMongoTckManager.groovy:136)
	at org.apache.grails.data.testing.tck.base.GrailsDataTckManager.setup(GrailsDataTckManager.groovy:134)
	at org.apache.grails.data.mongo.core.GrailsDataMongoTckManager.setup(GrailsDataMongoTckManager.groovy:72)
	at org.apache.grails.data.testing.tck.base.GrailsDataTckSpec.setup(GrailsDataTckSpec.groovy:65)
AssignedIdentifierSpec > Test that assigned identifiers work with the constructor (:grails-data-mongodb-core:test in CI - Groovy Joint Validation Build / build_grails)
java.lang.IllegalArgumentException: wrong number of arguments: 28 expected: 1
	at org.apache.grails.data.mongo.core.GrailsDataMongoTckManager.createSession(GrailsDataMongoTckManager.groovy:136)
	at org.apache.grails.data.testing.tck.base.GrailsDataTckManager.setup(GrailsDataTckManager.groovy:134)
	at org.apache.grails.data.mongo.core.GrailsDataMongoTckManager.setup(GrailsDataMongoTckManager.groovy:72)
	at org.apache.grails.data.testing.tck.base.GrailsDataTckSpec.setup(GrailsDataTckSpec.groovy:65)
AssignedIdentifierSpec > Test that entities can be saved, retrieved and updated with assigned ids (:grails-data-mongodb-core:test in CI - Groovy Joint Validation Build / build_grails)
java.lang.IllegalArgumentException: wrong number of arguments: 28 expected: 1
	at org.apache.grails.data.mongo.core.GrailsDataMongoTckManager.createSession(GrailsDataMongoTckManager.groovy:136)
	at org.apache.grails.data.testing.tck.base.GrailsDataTckManager.setup(GrailsDataTckManager.groovy:134)
	at org.apache.grails.data.mongo.core.GrailsDataMongoTckManager.setup(GrailsDataMongoTckManager.groovy:72)
	at org.apache.grails.data.testing.tck.base.GrailsDataTckSpec.setup(GrailsDataTckSpec.groovy:65)
AssignedIdentifierSpec > Test that entities can be saved, retrieved and updated with assigned ids (:grails-data-mongodb-core:test in CI - Groovy Joint Validation Build / build_grails)
java.lang.IllegalArgumentException: wrong number of arguments: 28 expected: 1
	at org.apache.grails.data.mongo.core.GrailsDataMongoTckManager.createSession(GrailsDataMongoTckManager.groovy:136)
	at org.apache.grails.data.testing.tck.base.GrailsDataTckManager.setup(GrailsDataTckManager.groovy:134)
	at org.apache.grails.data.mongo.core.GrailsDataMongoTckManager.setup(GrailsDataMongoTckManager.groovy:72)
	at org.apache.grails.data.testing.tck.base.GrailsDataTckSpec.setup(GrailsDataTckSpec.groovy:65)

Muted Tests (first 20 of 1128)

Select tests to mute in this pull request:

  • AggregateMethodSpec > Test aggregate method
  • AssignedIdentifierSpec > Test that assigned identifiers work with property setting
  • AssignedIdentifierSpec > Test that assigned identifiers work with stateless domains
  • AssignedIdentifierSpec > Test that assigned identifiers work with the constructor
  • AssignedIdentifierSpec > Test that entities can be saved, retrieved and updated with assigned ids
  • AssignedIdentifierSpec > Test that saving a second object with an assigned identifier produces an error
  • AttachMethodSpec > Test attach method
  • AutowireServicesSpec > Test that services can be autowired
  • BasicArraySpec > Test that arrays are saved correctly
  • BasicArraySpec > Test that arrays of convertible properties are saved correctly
  • BasicArraySpec > Test that byte arrays are saved as binary
  • BasicCollectionTypeSpec > Test persist basic collection types
  • BasicCollectionsSpec > Test beforeInsert() and beforeUpdate() methods for collections
  • BasicCollectionsSpec > Test that a Locale can be used inside a collection
  • BasicCollectionsSpec > Test that a map of BigDecimal works.
  • BasicCollectionsSpec > Test that a map of Currency works.
  • BatchUpdateDeleteSpec > Test that batch delete works
  • BatchUpdateDeleteSpec > Test that batch update works
  • BatchUpdateDeleteSpec > Test that batch update works with domain properties
  • BeforeInsertUpdateSpec > Test that before insert and update events are triggered without issue

Reuse successful test results:

  • ♻️ Only rerun the tests that failed or were muted before

Click the checkbox to trigger a rerun:

  • Rerun jobs

Learn more about TestLens at testlens.app.

@jamesfredley

Copy link
Copy Markdown
Contributor

And here is a targeted stab at Child datastore initialization order: #15776

Having 456 files in this PR makes it challenging for the team to review in a reasonable timeframe.

@borinquenkid

Copy link
Copy Markdown
Member Author

Superseded by the restructured GormRegistry PR stack (feat/gorm-registry-core-impl, feat/gorm-registry-core-tests, and per-adapter PRs).

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

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

3 participants