diff --git a/hibernate-core/src/main/java/org/hibernate/integrator/spi/Integrator.java b/hibernate-core/src/main/java/org/hibernate/integrator/spi/Integrator.java index 35cca9f962..31c2147f3d 100644 --- a/hibernate-core/src/main/java/org/hibernate/integrator/spi/Integrator.java +++ b/hibernate-core/src/main/java/org/hibernate/integrator/spi/Integrator.java @@ -45,8 +45,6 @@ public interface Integrator { * @param metadata The fully initialized boot-time mapping model * @param bootstrapContext The context for bootstrapping of the SessionFactory * @param sessionFactory The SessionFactory being created - * - * todo (6.0) : why pass the `serviceRegistry`? Why not just grab it from the SessionFactory? */ @Incubating default void integrate( diff --git a/hibernate-testing/README.adoc b/hibernate-testing/README.adoc new file mode 100644 index 0000000000..4d8f4000cc --- /dev/null +++ b/hibernate-testing/README.adoc @@ -0,0 +1,4 @@ +The `hibernate-testing` module of Hibernate ORM defines utilities for writing +tests easier.... + +// todo : write more (duh) \ No newline at end of file diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/DomainModelExtension.java b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/DomainModelExtension.java index 804271c99c..fa56aa5adc 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/DomainModelExtension.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/DomainModelExtension.java @@ -99,7 +99,7 @@ public class DomainModelExtension } private static ExtensionContext.Store locateExtensionStore(Object testInstance, ExtensionContext context) { - return JUnitHelper.locateExtensionStore( ServiceRegistryExtension.class, context, testInstance ); + return JUnitHelper.locateExtensionStore( DomainModelExtension.class, context, testInstance ); } private static DomainModelScope createDomainModelScope( @@ -199,27 +199,13 @@ public class DomainModelExtension } public static DomainModelScope findDomainModelScope(Object testInstance, ExtensionContext context) { - // todo : allow for method-level - final ExtensionContext.Store store = locateExtensionStore( testInstance, context ); final DomainModelScope existing = (DomainModelScope) store.get( MODEL_KEY ); if ( existing != null ) { return existing; } - final Optional domainModelAnnRef = AnnotationSupport.findAnnotation( - context.getElement().get(), - DomainModel.class - ); - - if ( domainModelAnnRef.isEmpty() ) { - throw new RuntimeException( "Could not locate @DomainModel annotation : " + context.getDisplayName() ); - } - - final DomainModelScope created = createDomainModelScope( testInstance, domainModelAnnRef, context ); - locateExtensionStore( testInstance, context ).put( MODEL_KEY, created ); - - return created; + throw new RuntimeException( "Could not locate @DomainModel annotation : " + context.getDisplayName() ); } protected static void applyCacheSettings(Metadata metadata, boolean overrideCacheStrategy, String cacheConcurrencyStrategy) { diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/ServiceRegistryExtension.java b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/ServiceRegistryExtension.java index af64ea4594..6ce6b6070e 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/ServiceRegistryExtension.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/ServiceRegistryExtension.java @@ -22,7 +22,7 @@ import org.hibernate.service.spi.ServiceContributor; import org.hibernate.testing.boot.ExtraJavaServicesClassLoaderService; import org.hibernate.testing.boot.ExtraJavaServicesClassLoaderService.JavaServiceDescriptor; -import org.junit.jupiter.api.extension.AfterAllCallback; +import org.junit.jupiter.api.extension.BeforeEachCallback; import org.junit.jupiter.api.extension.ExtensionContext; import org.junit.jupiter.api.extension.TestExecutionExceptionHandler; import org.junit.jupiter.api.extension.TestInstancePostProcessor; @@ -37,14 +37,84 @@ import org.jboss.logging.Logger; * @author Steve Ebersole */ public class ServiceRegistryExtension - implements TestInstancePostProcessor, AfterAllCallback, TestExecutionExceptionHandler { + implements TestInstancePostProcessor, BeforeEachCallback, TestExecutionExceptionHandler { private static final Logger log = Logger.getLogger( ServiceRegistryExtension.class ); private static final String REGISTRY_KEY = ServiceRegistryScope.class.getName(); - public static StandardServiceRegistry findServiceRegistry( - Object testInstance, - ExtensionContext context) { - return findServiceRegistryScope( testInstance, context ).getRegistry(); + @Override + public void postProcessTestInstance(Object testInstance, ExtensionContext context) { + log.tracef( "#postProcessTestInstance(%s, %s)", testInstance, context.getDisplayName() ); + + assert context.getTestClass().isPresent(); + + final Optional bsrAnnRef = AnnotationSupport.findAnnotation( + context.getElement().get(), + BootstrapServiceRegistry.class + ); + final Optional ssrAnnRef = AnnotationSupport.findAnnotation( + context.getElement().get(), + ServiceRegistry.class + ); + + final ServiceRegistryScope created = createServiceRegistryScope( testInstance, bsrAnnRef, ssrAnnRef, context ); + locateExtensionStore( testInstance, context ).put( REGISTRY_KEY, created ); + } + + @Override + public void beforeEach(ExtensionContext context) throws Exception { + assert context.getTestMethod().isPresent(); + assert context.getRequiredTestMethod() == context.getElement().get(); + + Optional bsrAnnRef = AnnotationSupport.findAnnotation( + context.getElement().get(), + BootstrapServiceRegistry.class + ); + Optional ssrAnnRef = AnnotationSupport.findAnnotation( + context.getElement().get(), + ServiceRegistry.class + ); + + if ( bsrAnnRef.isEmpty() && ssrAnnRef.isEmpty() ) { + // assume the annotations are defined on the class-level... + // will be validated by the parameter-resolver or consuming extension + return; + } + else if ( bsrAnnRef.isPresent() && ssrAnnRef.isPresent() ) { + // the method has both - use them -> fall through + } + else if ( bsrAnnRef.isPresent() ) { + // the method has BootstrapServiceRegistry but not ServiceRegistry + // + // see if there is a ServiceRegistry at the class-level: + // yes -> use this class-level one + // no -> treat it as implicit + + ssrAnnRef = AnnotationSupport.findAnnotation( + context.getRequiredTestClass(), + ServiceRegistry.class + ); + } + else if ( ssrAnnRef.isPresent() ) { + // the method has ServiceRegistry but not BootstrapServiceRegistry + // + // see if there is a BootstrapServiceRegistry at the class-level: + // yes -> use this class-level one + // no -> treat it as implicit + + bsrAnnRef = AnnotationSupport.findAnnotation( + context.getRequiredTestClass(), + BootstrapServiceRegistry.class + ); + } + else { + throw new RuntimeException( "Some clever text" ); + } + + final Object testInstance = context.getRequiredTestInstance(); + + final ServiceRegistryScope created = createServiceRegistryScope( testInstance, bsrAnnRef, ssrAnnRef, context ); + final ExtensionContext.Store extensionStore = locateExtensionStore( testInstance, context ); + extensionStore.put( REGISTRY_KEY, created ); } private static ExtensionContext.Store locateExtensionStore( @@ -57,62 +127,62 @@ public class ServiceRegistryExtension log.tracef( "#findServiceRegistryScope(%s, %s)", testInstance, context.getDisplayName() ); final ExtensionContext.Store store = locateExtensionStore( testInstance, context ); - - ServiceRegistryScopeImpl existingScope = (ServiceRegistryScopeImpl) store.get( REGISTRY_KEY ); + final ServiceRegistryScopeImpl existingScope = (ServiceRegistryScopeImpl) store.get( REGISTRY_KEY ); if ( existingScope == null ) { - log.debugf( "Creating ServiceRegistryScope - %s", context.getDisplayName() ); - - final BootstrapServiceRegistryProducer bsrProducer; - - final Optional bsrAnnWrapper = AnnotationSupport.findAnnotation( - context.getElement().get(), - BootstrapServiceRegistry.class - ); - - if ( bsrAnnWrapper.isPresent() ) { - bsrProducer = bsrBuilder -> { - final BootstrapServiceRegistry bsrAnn = bsrAnnWrapper.get(); - configureJavaServices( bsrAnn, bsrBuilder ); - configureIntegrators( bsrAnn, bsrBuilder ); - - return bsrBuilder.enableAutoClose().build(); - }; - } - else { - bsrProducer = BootstrapServiceRegistryBuilder::build; - } - - final ServiceRegistryProducer ssrProducer; - - if ( testInstance instanceof ServiceRegistryProducer ) { - ssrProducer = (ServiceRegistryProducer) testInstance; - } - else { - ssrProducer = new ServiceRegistryProducerImpl(context); - } - - final ServiceRegistryScopeImpl scope = new ServiceRegistryScopeImpl( bsrProducer, ssrProducer ); - scope.getRegistry(); - - locateExtensionStore( testInstance, context ).put( REGISTRY_KEY, scope ); - - if ( testInstance instanceof ServiceRegistryScopeAware ) { - ( (ServiceRegistryScopeAware) testInstance ).injectServiceRegistryScope( scope ); - } - return scope; + throw new RuntimeException( "No ServiceRegistryScope known in context" ); } return existingScope; } + private static ServiceRegistryScopeImpl createServiceRegistryScope( + Object testInstance, + Optional bsrAnnRef, + Optional ssrAnnRef, + ExtensionContext context) { + log.debugf( "Creating ServiceRegistryScope - %s", context.getDisplayName() ); + + final BootstrapServiceRegistryProducer bsrProducer; + + //noinspection OptionalIsPresent + if ( bsrAnnRef.isPresent() ) { + bsrProducer = bsrBuilder -> { + final BootstrapServiceRegistry bsrAnn = bsrAnnRef.get(); + configureJavaServices( bsrAnn, bsrBuilder ); + configureIntegrators( bsrAnn, bsrBuilder ); + + return bsrBuilder.enableAutoClose().build(); + }; + } + else { + bsrProducer = BootstrapServiceRegistryBuilder::build; + } + + final ServiceRegistryProducer ssrProducer; + + if ( testInstance instanceof ServiceRegistryProducer ) { + ssrProducer = (ServiceRegistryProducer) testInstance; + } + else { + ssrProducer = new ServiceRegistryProducerImpl( ssrAnnRef ); + } + + final ServiceRegistryScopeImpl scope = new ServiceRegistryScopeImpl( bsrProducer, ssrProducer ); + scope.getRegistry(); + + if ( testInstance instanceof ServiceRegistryScopeAware ) { + ( (ServiceRegistryScopeAware) testInstance ).injectServiceRegistryScope( scope ); + } + + return scope; + } + private static class ServiceRegistryProducerImpl implements ServiceRegistryProducer{ - private final ExtensionContext context; - public ServiceRegistryProducerImpl(ExtensionContext context) { - this.context = context; - if ( !context.getElement().isPresent() ) { - throw new RuntimeException( "Unable to determine how to handle given ExtensionContext : " + context.getDisplayName() ); - } + private final Optional ssrAnnRef; + + public ServiceRegistryProducerImpl(Optional ssrAnnRef) { + this.ssrAnnRef = ssrAnnRef; } @Override @@ -120,13 +190,8 @@ public class ServiceRegistryExtension // set some baseline test settings ssrb.applySetting( AvailableSettings.STATEMENT_INSPECTOR, org.hibernate.testing.jdbc.SQLStatementInspector.class ); - final Optional ssrAnnWrapper = AnnotationSupport.findAnnotation( - context.getElement().get(), - ServiceRegistry.class - ); - - if ( ssrAnnWrapper.isPresent() ) { - final ServiceRegistry serviceRegistryAnn = ssrAnnWrapper.get(); + if ( ssrAnnRef.isPresent() ) { + final ServiceRegistry serviceRegistryAnn = ssrAnnRef.get(); configureServices( serviceRegistryAnn, ssrb ); } @@ -218,28 +283,22 @@ public class ServiceRegistryExtension } } - @Override - public void postProcessTestInstance(Object testInstance, ExtensionContext context) { - log.tracef( "#postProcessTestInstance(%s, %s)", testInstance, context.getDisplayName() ); - findServiceRegistryScope( testInstance, context ); - } - - @Override - public void afterAll(ExtensionContext context) { - log.tracef( "#afterAll(%s)", context.getDisplayName() ); - - final Object testInstance = context.getRequiredTestInstance(); - - if ( testInstance instanceof ServiceRegistryScopeAware ) { - ( (ServiceRegistryScopeAware) testInstance ).injectServiceRegistryScope( null ); - } - - final ExtensionContext.Store store = locateExtensionStore( testInstance, context ); - final ServiceRegistryScopeImpl scope = (ServiceRegistryScopeImpl) store.remove( REGISTRY_KEY ); - if ( scope != null ) { - scope.close(); - } - } +// @Override +// public void afterAll(ExtensionContext context) { +// log.tracef( "#afterAll(%s)", context.getDisplayName() ); +// +// final Object testInstance = context.getRequiredTestInstance(); +// +// if ( testInstance instanceof ServiceRegistryScopeAware ) { +// ( (ServiceRegistryScopeAware) testInstance ).injectServiceRegistryScope( null ); +// } +// +// final ExtensionContext.Store store = locateExtensionStore( testInstance, context ); +// final ServiceRegistryScopeImpl scope = (ServiceRegistryScopeImpl) store.remove( REGISTRY_KEY ); +// if ( scope != null ) { +// scope.close(); +// } +// } @Override public void handleTestExecutionException(ExtensionContext context, Throwable throwable) throws Throwable { diff --git a/hibernate-testing/src/test/java/org/hibernate/testing/annotations/methods/ServiceRegistryTesting.java b/hibernate-testing/src/test/java/org/hibernate/testing/annotations/methods/ServiceRegistryTesting.java new file mode 100644 index 0000000000..200fbc04fe --- /dev/null +++ b/hibernate-testing/src/test/java/org/hibernate/testing/annotations/methods/ServiceRegistryTesting.java @@ -0,0 +1,87 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html. + */ +package org.hibernate.testing.annotations.methods; + +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.engine.config.spi.ConfigurationService; +import org.hibernate.service.spi.ServiceContributor; + +import org.hibernate.testing.orm.junit.BootstrapServiceRegistry; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.ServiceRegistryScope; +import org.hibernate.testing.orm.junit.Setting; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Steve Ebersole + */ +@BootstrapServiceRegistry(javaServices = @BootstrapServiceRegistry.JavaService( + role = ServiceContributor.class, + impl = ServiceRegistryTesting.ServiceContributor1.class +)) +@ServiceRegistry( settings = @Setting( name = "setting", value = "class-level")) +public class ServiceRegistryTesting { + + @Test + public void testClassLevel(ServiceRegistryScope scope) { + scope.withService( ConfigurationService.class, (configurationService) -> { + assertThat( configurationService.getSettings().get( "setting" ) ).isEqualTo( "class-level" ); + assertThat( configurationService.getSettings().get( "contributed" ) ).isEqualTo( "contributed-1" ); + } ); + } + + @Test + @BootstrapServiceRegistry(javaServices = @BootstrapServiceRegistry.JavaService( + role = ServiceContributor.class, + impl = ServiceRegistryTesting.ServiceContributor2.class + )) + @ServiceRegistry( settings = @Setting( name = "setting", value = "method-level")) + public void testMethodLevel(ServiceRegistryScope scope) { + scope.withService( ConfigurationService.class, (configurationService) -> { + assertThat( configurationService.getSettings().get( "setting" ) ).isEqualTo( "method-level" ); + assertThat( configurationService.getSettings().get( "contributed" ) ).isEqualTo( "contributed-2" ); + } ); + } + + @Test + @ServiceRegistry( settings = @Setting( name = "setting", value = "mixed")) + public void testMethodLevelImplicitBootstrap(ServiceRegistryScope scope) { + scope.withService( ConfigurationService.class, (configurationService) -> { + assertThat( configurationService.getSettings().get( "setting" ) ).isEqualTo( "mixed" ); + assertThat( configurationService.getSettings().get( "contributed" ) ).isEqualTo( "contributed-1" ); + } ); + + } + + @Test + @BootstrapServiceRegistry(javaServices = @BootstrapServiceRegistry.JavaService( + role = ServiceContributor.class, + impl = ServiceRegistryTesting.ServiceContributor2.class + )) + public void testMethodLevelImplicitStandard(ServiceRegistryScope scope) { + scope.withService( ConfigurationService.class, (configurationService) -> { + assertThat( configurationService.getSettings().get( "setting" ) ).isEqualTo( "class-level" ); + assertThat( configurationService.getSettings().get( "contributed" ) ).isEqualTo( "contributed-2" ); + } ); + } + + public static class ServiceContributor1 implements ServiceContributor { + @Override + public void contribute(StandardServiceRegistryBuilder serviceRegistryBuilder) { + serviceRegistryBuilder.getSettings().put( "contributed", "contributed-1" ); + } + } + + public static class ServiceContributor2 implements ServiceContributor { + @Override + public void contribute(StandardServiceRegistryBuilder serviceRegistryBuilder) { + serviceRegistryBuilder.getSettings().put( "contributed", "contributed-2" ); + } + } +}