You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@grails.apache.org by jd...@apache.org on 2026/04/10 18:18:29 UTC
(grails-core) 01/01: fix testcontainer harness
This is an automated email from the ASF dual-hosted git repository.
jdaugherty pushed a commit to branch 8.0.x-hibernate7-dev
in repository https://gitbox.apache.org/repos/asf/grails-core.git
commit 1896fbcee53c34e25d187c20c6e42464d7961ec1
Author: Walter Duque de Estrada <wb...@mac.com>
AuthorDate: Fri Apr 10 13:15:18 2026 -0400
fix testcontainer harness
# Conflicts:
# grails-data-mongodb/core/src/test/groovy/org/apache/grails/data/mongo/core/GrailsDataMongoTckManager.groovy
---
.../apache/grails/buildsrc/GrailsTestPlugin.groovy | 14 +-
.../mongo/core/GrailsDataMongoTckManager.groovy | 182 ++++++++-------------
2 files changed, 71 insertions(+), 125 deletions(-)
diff --git a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsTestPlugin.groovy b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsTestPlugin.groovy
index a1414a6eab..1e7f251ff9 100644
--- a/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsTestPlugin.groovy
+++ b/build-logic/plugins/src/main/groovy/org/apache/grails/buildsrc/GrailsTestPlugin.groovy
@@ -36,7 +36,7 @@ class GrailsTestPlugin implements Plugin<Project> {
project.tasks.register('aggregateTestFailures') { task ->
task.group = 'verification'
- task.description = 'Aggregates all test failures into a single Markdown report'
+ task.description = 'Aggregates all test failures across all modules into TEST_FAILURES.md'
project.subprojects.each { subproject ->
subproject.tasks.withType(Test).configureEach { testTask ->
@@ -78,21 +78,15 @@ class GrailsTestPlugin implements Plugin<Project> {
}
}
- // 1. All subprojects
project.subprojects.each { subproject ->
def testResultsDir = subproject.layout.buildDirectory.dir("test-results").get().asFile
processTestResults(testResultsDir, subproject.name)
}
- // 2. Any other directory in root that might have test results (like grails-docs or build-logic)
project.layout.projectDirectory.asFile.eachDir { dir ->
if (!dir.name.startsWith('.') && dir.name != 'build' && dir.name != 'node_modules') {
- def testResultsDir = new File(dir, "build/test-results")
- processTestResults(testResultsDir, dir.name)
-
- // Also check for results in the directory itself (if it's a build output)
- def directTestResultsDir = new File(dir, "test-results")
- processTestResults(directTestResultsDir, dir.name)
+ processTestResults(new File(dir, "build/test-results"), dir.name)
+ processTestResults(new File(dir, "test-results"), dir.name)
}
}
@@ -124,6 +118,6 @@ class GrailsTestPlugin implements Plugin<Project> {
}
}
reportFile.text = out.toString()
- project.logger.lifecycle("Aggregated test failures report generated: ${reportFile.absolutePath}")
+ project.logger.lifecycle("Test failure report: ${reportFile.absolutePath}")
}
}
diff --git a/grails-data-mongodb/core/src/test/groovy/org/apache/grails/data/mongo/core/GrailsDataMongoTckManager.groovy b/grails-data-mongodb/core/src/test/groovy/org/apache/grails/data/mongo/core/GrailsDataMongoTckManager.groovy
index 9ed75cf991..022637f6c0 100644
--- a/grails-data-mongodb/core/src/test/groovy/org/apache/grails/data/mongo/core/GrailsDataMongoTckManager.groovy
+++ b/grails-data-mongodb/core/src/test/groovy/org/apache/grails/data/mongo/core/GrailsDataMongoTckManager.groovy
@@ -18,43 +18,43 @@
*/
package org.apache.grails.data.mongo.core
-import groovy.util.logging.Slf4j
-
import com.mongodb.BasicDBObject
import com.mongodb.client.MongoClient
-import org.bson.Document
-import org.testcontainers.containers.MongoDBContainer
-
-import org.springframework.context.support.GenericApplicationContext
-import org.springframework.context.support.StaticMessageSource
-import org.springframework.validation.Validator
-
import grails.core.DefaultGrailsApplication
import grails.core.GrailsApplication
import grails.gorm.validation.PersistentEntityValidator
+import groovy.util.logging.Slf4j
import org.apache.grails.data.testing.tck.base.GrailsDataTckManager
import org.apache.grails.testing.mongo.AbstractMongoGrailsExtension
+import org.bson.Document
import org.grails.datastore.bson.query.BsonQuery
import org.grails.datastore.gorm.GormEnhancer
import org.grails.datastore.gorm.mongo.Birthday
import org.grails.datastore.gorm.validation.constraints.eval.DefaultConstraintEvaluator
import org.grails.datastore.gorm.validation.constraints.registry.DefaultConstraintRegistry
-import org.grails.datastore.mapping.core.DatastoreUtils
import org.grails.datastore.mapping.core.Session
+import org.grails.datastore.mapping.multitenancy.MultiTenancySettings
+import org.grails.datastore.mapping.multitenancy.resolvers.SystemPropertyTenantResolver
import org.grails.datastore.mapping.engine.types.AbstractMappingAwareCustomTypeMarshaller
import org.grails.datastore.mapping.model.MappingContext
import org.grails.datastore.mapping.model.PersistentEntity
import org.grails.datastore.mapping.model.PersistentProperty
+import org.grails.datastore.mapping.mongo.AbstractMongoSession
+import org.grails.datastore.mapping.core.DatastoreUtils
import org.grails.datastore.mapping.mongo.MongoDatastore
import org.grails.datastore.mapping.mongo.config.MongoSettings
-import org.grails.datastore.mapping.multitenancy.MultiTenancySettings
-import org.grails.datastore.mapping.multitenancy.resolvers.SystemPropertyTenantResolver
import org.grails.datastore.mapping.query.Query
+import org.slf4j.LoggerFactory
+import org.springframework.context.support.GenericApplicationContext
+import org.springframework.context.support.StaticMessageSource
+import org.springframework.validation.Validator
+import org.testcontainers.containers.MongoDBContainer
+import org.testcontainers.containers.output.Slf4jLogConsumer
@Slf4j
class GrailsDataMongoTckManager extends GrailsDataTckManager {
- static MongoDBContainer mongoDBContainer
+ MongoDBContainer mongoDBContainer
MongoDatastore mongoDatastore
MongoClient mongoClient
@@ -68,19 +68,16 @@ class GrailsDataMongoTckManager extends GrailsDataTckManager {
@Override
void setupSpec() {
super.setupSpec()
- if (isDockerAvailable()) {
- if (mongoDBContainer == null) {
- mongoDBContainer = new MongoDBContainer(AbstractMongoGrailsExtension.desiredMongoDockerName)
- mongoDBContainer.start()
- // mongoDBContainer.followOutput(new Slf4jLogConsumer(LoggerFactory.getLogger("testcontainers")))
- }
-
- configuration = [
- (MongoSettings.SETTING_DATABASE_NAME): 'test',
- (MongoSettings.SETTING_HOST) : mongoDBContainer.host,
- (MongoSettings.SETTING_PORT) : mongoDBContainer.getMappedPort(AbstractMongoGrailsExtension.DEFAULT_MONGO_PORT) as String,
- ]
- }
+ mongoDBContainer = new MongoDBContainer(AbstractMongoGrailsExtension.desiredMongoDockerName)
+ mongoDBContainer.start()
+ mongoDBContainer.followOutput(new Slf4jLogConsumer(LoggerFactory.getLogger("testcontainers")))
+
+ configuration = [
+ (MongoSettings.SETTING_DATABASE_NAME): 'test',
+ (MongoSettings.SETTING_HOST) : mongoDBContainer.host,
+ (MongoSettings.SETTING_PORT) : mongoDBContainer.getMappedPort(AbstractMongoGrailsExtension.DEFAULT_MONGO_PORT) as String,
+ //TODO: 'grails.mongodb.url': "mongodb://${host}:${port as String}/myDb" as String
+ ]
}
@Override
@@ -91,10 +88,6 @@ class GrailsDataMongoTckManager extends GrailsDataTckManager {
@Override
Session createSession() {
- if (mongoDBContainer == null || !mongoDBContainer.isRunning()) {
- return null
- }
- System.setProperty('mongodb.gorm.suite', 'true')
def allClasses = getDomainClasses() as Class[]
def ctx = new GenericApplicationContext()
ctx.refresh()
@@ -102,7 +95,6 @@ class GrailsDataMongoTckManager extends GrailsDataTckManager {
mongoDatastore = new MongoDatastore(configuration)
mappingContext = mongoDatastore.mappingContext
mappingContext.mappingFactory.registerCustomType(new AbstractMappingAwareCustomTypeMarshaller<Birthday, Document, Document>(Birthday) {
-
@Override
protected Object writeInternal(PersistentProperty property, String key, Birthday value, Document nativeTarget) {
@@ -144,58 +136,38 @@ class GrailsDataMongoTckManager extends GrailsDataTckManager {
@Override
void destroy() {
- if (mongoDatastore != null) {
- mongoDatastore.getMongoClient().listDatabaseNames().findAll { !(it in ['admin', 'config', 'local']) }.each {
- try {
- mongoDatastore?.mongoClient?.listDatabaseNames()
- ?.findAll { !(it in ['admin', 'config', 'local']) }
- ?.each {
- try {
- mongoDatastore.mongoClient.getDatabase(it as String).drop()
- }
- catch (ignored) {
- log.warn("Could not drop ${it}")
- }
- }
- for (cls in domainClasses) {
- GormEnhancer.findValidationApi(cls).validator = null
- }
- }
- finally {
- try {
- mongoDatastore?.close()
- }
- catch (ignored) {
- }
- mongoDatastore = null
- mongoClient = null
- grailsApplication = null
- mappingContext = null
- }
+ mongoDatastore.getMongoClient().listDatabaseNames().findAll {!(it in ['admin', 'config', 'local']) }.each {
+ try {
+ mongoDatastore.getMongoClient().getDatabase(it).drop()
+ }
+ catch(e) {
+ log.warn("Could not drop ${it}")
}
}
+ mongoDatastore.buildIndex()
+ for (cls in getDomainClasses()) {
+ GormEnhancer.findValidationApi(cls).setValidator(null)
+ }
super.destroy()
}
@Override
boolean supportsMultipleDataSources() {
- mongoDBContainer != null && mongoDBContainer.isRunning()
+ true
}
@Override
void setupMultiDataSource(Class... domainClasses) {
- if (mongoDBContainer != null && mongoDBContainer.isRunning()) {
- String host = mongoDBContainer.host
- int port = mongoDBContainer.getMappedPort(AbstractMongoGrailsExtension.DEFAULT_MONGO_PORT)
- Map config = [
- 'grails.mongodb.url' : "mongodb://${host}:${port}/tckDefaultDB" as String,
- 'grails.mongodb.connections': [
- 'secondary': ['url': "mongodb://${host}:${port}/tckSecondaryDB" as String],
- ],
- ]
- multiDataSourceDatastore = new MongoDatastore(DatastoreUtils.createPropertyResolver(config), domainClasses)
- }
+ String host = mongoDBContainer.host
+ int port = mongoDBContainer.getMappedPort(AbstractMongoGrailsExtension.DEFAULT_MONGO_PORT)
+ Map config = [
+ 'grails.mongodb.url' : "mongodb://${host}:${port}/tckDefaultDB" as String,
+ 'grails.mongodb.connections': [
+ 'secondary': ['url': "mongodb://${host}:${port}/tckSecondaryDB" as String],
+ ],
+ ]
+ multiDataSourceDatastore = new MongoDatastore(DatastoreUtils.createPropertyResolver(config), domainClasses)
}
@Override
@@ -212,32 +184,30 @@ class GrailsDataMongoTckManager extends GrailsDataTckManager {
@Override
def getServiceForConnection(Class serviceType, String connectionName) {
multiDataSourceDatastore
- ?.getDatastoreForConnection(connectionName)
- ?.getService(serviceType)
+ .getDatastoreForConnection(connectionName)
+ .getService(serviceType)
}
@Override
boolean supportsMultiTenantMultiDataSource() {
- mongoDBContainer != null && mongoDBContainer.isRunning()
+ true
}
@Override
void setupMultiTenantMultiDataSource(Class... domainClasses) {
- if (mongoDBContainer != null && mongoDBContainer.isRunning()) {
- String host = mongoDBContainer.host
- int port = mongoDBContainer.getMappedPort(AbstractMongoGrailsExtension.DEFAULT_MONGO_PORT)
- Map config = [
- 'grails.gorm.multiTenancy.mode' : MultiTenancySettings.MultiTenancyMode.DISCRIMINATOR,
- 'grails.gorm.multiTenancy.tenantResolverClass': SystemPropertyTenantResolver,
- 'grails.mongodb.url' : "mongodb://${host}:${port}/tckMtDefaultDB" as String,
- 'grails.mongodb.connections' : [
- 'secondary': ['url': "mongodb://${host}:${port}/tckMtSecondaryDB" as String],
- ],
- ]
- multiTenantMultiDataSourceDatastore = new MongoDatastore(
- DatastoreUtils.createPropertyResolver(config), domainClasses
- )
- }
+ String host = mongoDBContainer.host
+ int port = mongoDBContainer.getMappedPort(AbstractMongoGrailsExtension.DEFAULT_MONGO_PORT)
+ Map config = [
+ 'grails.gorm.multiTenancy.mode' : MultiTenancySettings.MultiTenancyMode.DISCRIMINATOR,
+ 'grails.gorm.multiTenancy.tenantResolverClass' : SystemPropertyTenantResolver,
+ 'grails.mongodb.url' : "mongodb://${host}:${port}/tckMtDefaultDB" as String,
+ 'grails.mongodb.connections' : [
+ 'secondary': ['url': "mongodb://${host}:${port}/tckMtSecondaryDB" as String],
+ ],
+ ]
+ multiTenantMultiDataSourceDatastore = new MongoDatastore(
+ DatastoreUtils.createPropertyResolver(config), domainClasses
+ )
}
@Override
@@ -254,35 +224,17 @@ class GrailsDataMongoTckManager extends GrailsDataTckManager {
@Override
def getServiceForMultiTenantConnection(Class serviceType, String connectionName) {
multiTenantMultiDataSourceDatastore
- ?.getDatastoreForConnection(connectionName)
- ?.getService(serviceType)
+ .getDatastoreForConnection(connectionName)
+ .getService(serviceType)
}
void setupValidator(Class entityClass, Validator validator = null) {
- if (mappingContext != null) {
- PersistentEntity entity = mappingContext.persistentEntities.find { PersistentEntity e -> e.javaClass == entityClass }
- def messageSource = new StaticMessageSource()
- def evaluator = new DefaultConstraintEvaluator(new DefaultConstraintRegistry(messageSource), mappingContext, Collections.emptyMap())
- if (entity) {
- mappingContext.addEntityValidator(entity, validator ?:
- new PersistentEntityValidator(entity, messageSource, evaluator))
- }
- }
- }
-
- static boolean isDockerAvailable() {
- def candidates = [
- System.getProperty('user.home') + '/.docker/run/docker.sock',
- '/var/run/docker.sock',
- System.getenv('DOCKER_HOST') ?: ''
- ]
- if (candidates.any { it && new File(it).exists() }) {
- try {
- return org.testcontainers.DockerClientFactory.instance().isDockerAvailable()
- } catch (Throwable e) {
- return false
- }
+ PersistentEntity entity = mappingContext.persistentEntities.find { PersistentEntity e -> e.javaClass == entityClass }
+ def messageSource = new StaticMessageSource()
+ def evaluator = new DefaultConstraintEvaluator(new DefaultConstraintRegistry(messageSource), mappingContext, Collections.emptyMap())
+ if (entity) {
+ mappingContext.addEntityValidator(entity, validator ?:
+ new PersistentEntityValidator(entity, messageSource, evaluator))
}
- return false
}
}