This is an automated email from the ASF dual-hosted git repository.

asf-gitbox-commits pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git

commit 551609e6586b841b2081cd4e04fe9d0660a0ce79
Author: Andrus Adamchik <[email protected]>
AuthorDate: Thu May 14 10:40:24 2026 -0400

    tests cleanup - unwinding DI
---
 .../unit/di/runtime/CayenneRuntimeProvider.java    | 103 ---------------------
 .../cayenne/unit/di/runtime/CayenneTestsEnv.java   |  91 +++++++++++++++---
 .../runtime/RuntimeCaseDataChannelInterceptor.java |   9 +-
 .../cayenne/unit/di/runtime/RuntimeCaseModule.java |  21 +----
 4 files changed, 82 insertions(+), 142 deletions(-)

diff --git 
a/cayenne/src/test/java/org/apache/cayenne/unit/di/runtime/CayenneRuntimeProvider.java
 
b/cayenne/src/test/java/org/apache/cayenne/unit/di/runtime/CayenneRuntimeProvider.java
deleted file mode 100644
index 21c4c91f2..000000000
--- 
a/cayenne/src/test/java/org/apache/cayenne/unit/di/runtime/CayenneRuntimeProvider.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*****************************************************************
- *   Licensed to the Apache Software Foundation (ASF) under one
- *  or more contributor license agreements.  See the NOTICE file
- *  distributed with this work for additional information
- *  regarding copyright ownership.  The ASF licenses this file
- *  to you under the Apache License, Version 2.0 (the
- *  "License"); you may not use this file except in compliance
- *  with the License.  You may obtain a copy of the License at
- *
- *    https://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing,
- *  software distributed under the License is distributed on an
- *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- *  KIND, either express or implied.  See the License for the
- *  specific language governing permissions and limitations
- *  under the License.
- ****************************************************************/
-package org.apache.cayenne.unit.di.runtime;
-
-import org.apache.cayenne.ConfigurationException;
-import org.apache.cayenne.access.DataDomain;
-import org.apache.cayenne.configuration.Constants;
-import org.apache.cayenne.configuration.runtime.CoreModule;
-import org.apache.cayenne.configuration.runtime.DataNodeFactory;
-import org.apache.cayenne.dba.DbAdapter;
-import org.apache.cayenne.di.Binder;
-import org.apache.cayenne.di.Inject;
-import org.apache.cayenne.di.Module;
-import org.apache.cayenne.di.Provider;
-import org.apache.cayenne.runtime.CayenneRuntime;
-import org.apache.cayenne.unit.UnitDbAdapter;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-
-public class CayenneRuntimeProvider implements Provider<CayenneRuntime> {
-
-    private RuntimeCaseProperties properties;
-    private RuntimeCaseExtraModules extraModules;
-    private RuntimeCaseDataSourceFactory dataSourceFactory;
-    private UnitDbAdapter unitDbAdapter;
-    private Provider<DbAdapter> dbAdapterProvider;
-
-    public CayenneRuntimeProvider(@Inject RuntimeCaseDataSourceFactory 
dataSourceFactory,
-                                  @Inject RuntimeCaseProperties properties,
-                                  @Inject RuntimeCaseExtraModules extraModules,
-                                  @Inject Provider<DbAdapter> 
dbAdapterProvider,
-                                  @Inject UnitDbAdapter unitDbAdapter) {
-
-        this.dataSourceFactory = dataSourceFactory;
-        this.properties = properties;
-        this.extraModules = extraModules;
-        this.dbAdapterProvider = dbAdapterProvider;
-        this.unitDbAdapter = unitDbAdapter;
-    }
-
-    @Override
-    public CayenneRuntime get() throws ConfigurationException {
-
-        String configurationLocation = properties.getConfigurationLocation();
-        if (configurationLocation == null) {
-            throw new NullPointerException("Null 'configurationLocation', "
-                    + "annotate your test case with @UseCayenneRuntime");
-        }
-
-        Collection<Module> modules = new ArrayList<>(getExtraModules());
-        modules.addAll(extraModules.getExtraModules());
-
-        return CayenneRuntime.builder()
-                        .addConfig(configurationLocation)
-                        .addModules(modules)
-                        .build();
-    }
-
-    protected Collection<? extends Module> getExtraModules() {
-        return Collections.singleton(new ExtraModule());
-    }
-
-    class ExtraModule implements Module {
-
-        @Override
-        public void configure(Binder binder) {
-
-            // these are the objects overriding standard CoreModule 
definitions or
-            // dependencies needed by such overrides
-
-            binder.bind(DbAdapter.class).toProviderInstance(dbAdapterProvider);
-            
binder.bind(DataDomain.class).toProvider(RuntimeCaseDataDomainProvider.class);
-            
binder.bind(DataNodeFactory.class).to(RuntimeCaseDataNodeFactory.class);
-            binder.bind(UnitDbAdapter.class).toInstance(unitDbAdapter);
-
-            CoreModule.extend(binder)
-                    // Use soft references instead of default weak.
-                    // Should remove problems with random-failing tests (those 
that are GC-sensitive).
-                    .setProperty(Constants.OBJECT_RETAIN_STRATEGY_PROPERTY, 
"soft");
-
-            // map DataSources for all test DataNode names
-            
binder.bind(RuntimeCaseDataSourceFactory.class).toInstance(dataSourceFactory);
-        }
-    }
-}
diff --git 
a/cayenne/src/test/java/org/apache/cayenne/unit/di/runtime/CayenneTestsEnv.java 
b/cayenne/src/test/java/org/apache/cayenne/unit/di/runtime/CayenneTestsEnv.java
index a19a6972e..8af819bde 100644
--- 
a/cayenne/src/test/java/org/apache/cayenne/unit/di/runtime/CayenneTestsEnv.java
+++ 
b/cayenne/src/test/java/org/apache/cayenne/unit/di/runtime/CayenneTestsEnv.java
@@ -25,13 +25,14 @@ import org.apache.cayenne.configuration.Constants;
 import org.apache.cayenne.configuration.DataMapLoader;
 import org.apache.cayenne.configuration.DataSourceDescriptor;
 import org.apache.cayenne.configuration.runtime.CoreModule;
+import org.apache.cayenne.configuration.runtime.DataNodeFactory;
 import org.apache.cayenne.dba.DbAdapter;
 import org.apache.cayenne.di.AdhocObjectFactory;
 import org.apache.cayenne.di.Binder;
 import org.apache.cayenne.di.DIBootstrap;
 import org.apache.cayenne.di.Injector;
 import org.apache.cayenne.di.Module;
-import org.apache.cayenne.di.spi.DefaultScope;
+import org.apache.cayenne.di.Provider;
 import org.apache.cayenne.log.JdbcEventLogger;
 import org.apache.cayenne.map.DataMap;
 import org.apache.cayenne.map.EntityResolver;
@@ -45,6 +46,8 @@ import org.junit.jupiter.api.extension.AfterEachCallback;
 import org.junit.jupiter.api.extension.BeforeEachCallback;
 import org.junit.jupiter.api.extension.ExtensionContext;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.stream.Collectors;
 
 /**
@@ -52,13 +55,11 @@ import java.util.stream.Collectors;
  */
 public class CayenneTestsEnv implements BeforeEachCallback, AfterEachCallback {
 
-    private static final DefaultScope TEST_SCOPE;
     private static final Injector INJECTOR;
     public static final AllTestsSchemaManager SCHEMA_MANAGER;
 
     static {
-        TEST_SCOPE = new DefaultScope();
-        INJECTOR = DIBootstrap.createInjector(new 
RuntimeCaseModule(TEST_SCOPE));
+        INJECTOR = DIBootstrap.createInjector(new RuntimeCaseModule());
         SCHEMA_MANAGER = new AllTestsSchemaManager(
                 INJECTOR.getInstance(RuntimeCaseDataSourceFactory.class),
                 INJECTOR.getInstance(UnitDbAdapter.class),
@@ -73,6 +74,7 @@ public class CayenneTestsEnv implements BeforeEachCallback, 
AfterEachCallback {
     private final boolean autoClean;
     private final boolean weakReferenceStrategy;
 
+    // single-test scoped vars
     private DataContext context;
     private DbHelper dbHelper;
     private DbCleaner dbCleaner;
@@ -116,17 +118,11 @@ public class CayenneTestsEnv implements 
BeforeEachCallback, AfterEachCallback {
 
     @Override
     public void beforeEach(ExtensionContext ctx) {
-        
INJECTOR.getInstance(RuntimeCaseProperties.class).setConfigurationLocation(project);
-
-        Class<?>[] effectiveExtras = extraModules;
-        if (weakReferenceStrategy) {
-            effectiveExtras = new Class<?>[extraModules.length + 1];
-            System.arraycopy(extraModules, 0, effectiveExtras, 0, 
extraModules.length);
-            effectiveExtras[extraModules.length] = 
WeakReferenceStrategyModule.class;
+        if (project == null) {
+            throw new NullPointerException("Null 'project', annotate your test 
case with @UseCayenneRuntime");
         }
-        
INJECTOR.getInstance(RuntimeCaseExtraModules.class).setExtraModules(effectiveExtras);
 
-        this.runtime = INJECTOR.getInstance(CayenneRuntime.class);
+        this.runtime = buildRuntime();
         this.context = (DataContext) runtime.newContext();
 
         DataNode node = 
runtime.getDataDomain().getDataNodes().iterator().next();
@@ -148,13 +144,44 @@ public class CayenneTestsEnv implements 
BeforeEachCallback, AfterEachCallback {
 
     @Override
     public void afterEach(ExtensionContext ctx) {
-        TEST_SCOPE.shutdown();
+        if (runtime != null) {
+            runtime.shutdown();
+        }
         this.context = null;
         this.dbHelper = null;
         this.dbCleaner = null;
         this.runtime = null;
     }
 
+    private CayenneRuntime buildRuntime() {
+        RuntimeCaseDataSourceFactory dataSourceFactory = 
INJECTOR.getInstance(RuntimeCaseDataSourceFactory.class);
+        UnitDbAdapter unitDbAdapter = 
INJECTOR.getInstance(UnitDbAdapter.class);
+        // a fresh DbAdapter per call — RuntimeCaseDbAdapterProvider is 
unscoped in the test injector
+        Provider<DbAdapter> dbAdapterProvider = () -> 
INJECTOR.getInstance(DbAdapter.class);
+
+        List<Module> modules = new ArrayList<>();
+        modules.add(new TestRuntimeOverridesModule(dataSourceFactory, 
unitDbAdapter, dbAdapterProvider));
+        for (Class<?> moduleType : extraModules) {
+            modules.add(instantiateModule(moduleType));
+        }
+        if (weakReferenceStrategy) {
+            modules.add(new WeakReferenceStrategyModule());
+        }
+
+        return CayenneRuntime.builder()
+                .addConfig(project)
+                .addModules(modules)
+                .build();
+    }
+
+    private static Module instantiateModule(Class<?> moduleType) {
+        try {
+            return (Module) moduleType.getConstructor().newInstance();
+        } catch (ReflectiveOperationException e) {
+            throw new RuntimeException("Failed to instantiate extra module: " 
+ moduleType.getName(), e);
+        }
+    }
+
     public DataContext context() {
         return context;
     }
@@ -185,7 +212,7 @@ public class CayenneTestsEnv implements BeforeEachCallback, 
AfterEachCallback {
     }
 
     public DataChannelInterceptor dataChannelInterceptor() {
-        return INJECTOR.getInstance(DataChannelInterceptor.class);
+        return new RuntimeCaseDataChannelInterceptor(() -> runtime);
     }
 
     public AdhocObjectFactory adhocObjectFactory() {
@@ -214,4 +241,38 @@ public class CayenneTestsEnv implements 
BeforeEachCallback, AfterEachCallback {
             
CoreModule.extend(binder).setProperty(Constants.OBJECT_RETAIN_STRATEGY_PROPERTY,
 "weak");
         }
     }
+
+    /**
+     * Wires test-specific overrides into the per-test {@link CayenneRuntime} 
injector:
+     * shares the {@link RuntimeCaseDataSourceFactory} and {@link 
UnitDbAdapter} held by the
+     * static test injector, swaps in the test {@link DbAdapter} and 
data-domain/node
+     * implementations, and sets the soft-reference retain strategy.
+     */
+    private static class TestRuntimeOverridesModule implements Module {
+
+        private final RuntimeCaseDataSourceFactory dataSourceFactory;
+        private final UnitDbAdapter unitDbAdapter;
+        private final Provider<DbAdapter> dbAdapterProvider;
+
+        TestRuntimeOverridesModule(RuntimeCaseDataSourceFactory 
dataSourceFactory,
+                                   UnitDbAdapter unitDbAdapter,
+                                   Provider<DbAdapter> dbAdapterProvider) {
+            this.dataSourceFactory = dataSourceFactory;
+            this.unitDbAdapter = unitDbAdapter;
+            this.dbAdapterProvider = dbAdapterProvider;
+        }
+
+        @Override
+        public void configure(Binder binder) {
+            binder.bind(DbAdapter.class).toProviderInstance(dbAdapterProvider);
+            
binder.bind(DataDomain.class).toProvider(RuntimeCaseDataDomainProvider.class);
+            
binder.bind(DataNodeFactory.class).to(RuntimeCaseDataNodeFactory.class);
+            binder.bind(UnitDbAdapter.class).toInstance(unitDbAdapter);
+            
binder.bind(RuntimeCaseDataSourceFactory.class).toInstance(dataSourceFactory);
+
+            CoreModule.extend(binder)
+                    // Soft refs instead of weak — avoids GC-sensitive test 
flakiness.
+                    .setProperty(Constants.OBJECT_RETAIN_STRATEGY_PROPERTY, 
"soft");
+        }
+    }
 }
diff --git 
a/cayenne/src/test/java/org/apache/cayenne/unit/di/runtime/RuntimeCaseDataChannelInterceptor.java
 
b/cayenne/src/test/java/org/apache/cayenne/unit/di/runtime/RuntimeCaseDataChannelInterceptor.java
index 4efe8434e..729cb1144 100644
--- 
a/cayenne/src/test/java/org/apache/cayenne/unit/di/runtime/RuntimeCaseDataChannelInterceptor.java
+++ 
b/cayenne/src/test/java/org/apache/cayenne/unit/di/runtime/RuntimeCaseDataChannelInterceptor.java
@@ -19,7 +19,6 @@
 package org.apache.cayenne.unit.di.runtime;
 
 import org.apache.cayenne.access.UnitTestDomain;
-import org.apache.cayenne.di.Inject;
 import org.apache.cayenne.di.Provider;
 import org.apache.cayenne.runtime.CayenneRuntime;
 import org.apache.cayenne.unit.di.DataChannelInterceptor;
@@ -28,9 +27,11 @@ import org.apache.cayenne.unit.di.UnitTestClosure;
 
 public class RuntimeCaseDataChannelInterceptor implements 
DataChannelInterceptor {
 
-    @Inject
-    // injecting provider to make this provider independent from scoping of 
CayenneRuntime
-    protected Provider<CayenneRuntime> runtimeProvider;
+    private final Provider<CayenneRuntime> runtimeProvider;
+
+    public RuntimeCaseDataChannelInterceptor(Provider<CayenneRuntime> 
runtimeProvider) {
+        this.runtimeProvider = runtimeProvider;
+    }
 
     public void runWithQueriesBlocked(UnitTestClosure closure) {
 
diff --git 
a/cayenne/src/test/java/org/apache/cayenne/unit/di/runtime/RuntimeCaseModule.java
 
b/cayenne/src/test/java/org/apache/cayenne/unit/di/runtime/RuntimeCaseModule.java
index c7708fe33..f2697948c 100644
--- 
a/cayenne/src/test/java/org/apache/cayenne/unit/di/runtime/RuntimeCaseModule.java
+++ 
b/cayenne/src/test/java/org/apache/cayenne/unit/di/runtime/RuntimeCaseModule.java
@@ -76,14 +76,12 @@ import org.apache.cayenne.di.Module;
 import org.apache.cayenne.di.Provider;
 import org.apache.cayenne.di.spi.DefaultAdhocObjectFactory;
 import org.apache.cayenne.di.spi.DefaultClassLoaderManager;
-import org.apache.cayenne.di.spi.DefaultScope;
 import org.apache.cayenne.log.JdbcEventLogger;
 import org.apache.cayenne.log.Slf4jJdbcEventLogger;
 import 
org.apache.cayenne.reflect.generic.DefaultValueComparisonStrategyFactory;
 import org.apache.cayenne.reflect.generic.ValueComparisonStrategyFactory;
 import org.apache.cayenne.resource.ClassLoaderResourceLocator;
 import org.apache.cayenne.resource.ResourceLocator;
-import org.apache.cayenne.runtime.CayenneRuntime;
 import org.apache.cayenne.unit.DB2UnitDbAdapter;
 import org.apache.cayenne.unit.DerbyUnitDbAdapter;
 import org.apache.cayenne.unit.FirebirdUnitDbAdapter;
@@ -99,7 +97,6 @@ import org.apache.cayenne.unit.SQLiteUnitDbAdapter;
 import org.apache.cayenne.unit.SybaseUnitDbAdapter;
 import org.apache.cayenne.unit.UnitDataSourceDescriptor;
 import org.apache.cayenne.unit.UnitDbAdapter;
-import org.apache.cayenne.unit.di.DataChannelInterceptor;
 import org.apache.cayenne.unit.testcontainers.Db2ContainerProvider;
 import org.apache.cayenne.unit.testcontainers.MariaDbContainerProvider;
 import org.apache.cayenne.unit.testcontainers.MysqlContainerProvider;
@@ -115,19 +112,9 @@ import java.util.GregorianCalendar;
 
 public class RuntimeCaseModule implements Module {
 
-    protected DefaultScope testScope;
-
-    public RuntimeCaseModule(DefaultScope testScope) {
-        this.testScope = testScope;
-    }
-
     public void configure(Binder binder) {
 
-        // these are the objects injectable in unit tests that subclass from
-        // RuntimeCase. Note that CayenneRuntimeProvider creates CayenneRuntime
-        // instances complete with their own DI injectors, independent of the
-        // unit test injector. CayenneRuntime injector contents are customized
-        // inside CayenneRuntimeProvider.
+        // these are the objects injectable in unit tests that subclass from 
RuntimeCase.
 
         binder.bindMap(String.class, UnitDbAdapterProvider.TEST_ADAPTERS_MAP)
                 .put(FirebirdAdapter.class.getName(), 
FirebirdUnitDbAdapter.class.getName())
@@ -231,7 +218,6 @@ public class RuntimeCaseModule implements Module {
         // server runtime... BatchQueryBuilderFactory is hardcoded and 
whatever is placed
         // in the CoreModule is ignored
         
binder.bind(BatchTranslatorFactory.class).toProvider(RuntimeCaseBatchQueryBuilderFactoryProvider.class);
-        
binder.bind(DataChannelInterceptor.class).to(RuntimeCaseDataChannelInterceptor.class);
         
binder.bind(SQLTemplateCustomizer.class).toProvider(SQLTemplateCustomizerProvider.class);
         
binder.bind(RuntimeCaseDataSourceFactory.class).to(RuntimeCaseDataSourceFactory.class);
         
binder.bind(ClassLoaderManager.class).to(DefaultClassLoaderManager.class);
@@ -245,11 +231,6 @@ public class RuntimeCaseModule implements Module {
         
binder.bind(DataChannelMetaData.class).to(NoopDataChannelMetaData.class);
 
         binder.bind(XMLReader.class).toProviderInstance(new 
XMLReaderProvider(false)).withoutScope();
-
-        // test-scoped objects
-        
binder.bind(RuntimeCaseProperties.class).to(RuntimeCaseProperties.class).in(testScope);
-        
binder.bind(RuntimeCaseExtraModules.class).to(RuntimeCaseExtraModules.class).in(testScope);
-        
binder.bind(CayenneRuntime.class).toProvider(CayenneRuntimeProvider.class).in(testScope);
     }
 
     // this class exists so that ToolsModule can call "initAllExtensions()" 
that is protected in CoreModuleExtender.

Reply via email to