From 17b4cc5024cad7ebb82aa670d397d1e87a55b61a Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Mon, 10 Nov 2025 11:13:15 -0700 Subject: [PATCH] HHH-19916 - Drop JUnit 4 usage --- .../test/boot/cfgXml/CfgXmlParsingTest.java | 36 +- ...HibernateSearchExtendedCdiSupportTest.java | 283 ++++++------ .../OrderByEmbeddableToOneTest.java | 43 +- .../embeddable/OrderByEmbeddableX2Test.java | 43 +- .../EntityNameFromSubClassTest.java | 63 ++- .../BatchFetchStrategyHelperTest.java | 170 +++---- .../FetchStrategyDeterminationTests.java | 73 ++- .../PostgreSQLFunctionSelectClauseTest.java | 165 +++---- .../PostgreSQLFunctionWhereClauseTest.java | 161 +++---- .../id/ReSaveReferencedDeletedEntityJPA.java | 122 ----- ...eSQLMultipleTypesOtherContributorTest.java | 159 ------- .../inet/PostgreSQLInetTypeTests.java | 95 ++++ ...stgreSQLInetTypesOtherContributorTest.java | 65 --- .../inet/PostgreSQLInetTypesOtherTest.java | 99 ---- ...ostgreSQLMultipleTypesContributorTest.java | 152 +++++++ .../HiloOptimizerConcurrencyTest.java | 268 ++--------- .../inheritance/MultipleInheritanceTest.java | 38 +- .../orm/test/interceptor/InterceptorTest.java | 400 ++++++++-------- .../InterceptorTransactionEventTest.java | 34 +- .../nulliteral/NullLiteralExpression.java | 30 +- .../locking/warning/LockNoneWarningTest.java | 84 ++-- .../schemaupdate/ConnectionsReleaseTest.java | 73 ++- ...hemaMigrationTargetScriptCreationTest.java | 285 +++++++----- .../MixedFieldPropertyAnnotationTest.java | 65 ++- .../derivedid/ColumnLengthTest.java | 86 ++-- .../foreignkeys/ForeignKeyDropTest.java | 134 +++--- .../foreignkeys/ForeignKeyGenerationTest.java | 179 ++++---- .../foreignkeys/ForeignKeyMigrationTest.java | 54 +-- .../JoinedInheritanceForeignKeyTest.java | 151 +++---- ...dateWithKeywordAutoQuotingEnabledTest.java | 82 ++-- .../CrossSchemaForeignKeyGenerationTest.java | 194 ++++---- .../AbstractForeignKeyDefinitionTest.java | 75 ++- .../ForeignKeyDefinitionManyToOneTest.java | 23 +- ...gnKeyDefinitionOneToManyJoinTableTest.java | 25 +- .../ForeignKeyDefinitionOneToOneTest.java | 23 +- ...oreignKeyDefinitionSecondaryTableTest.java | 25 +- .../schemaupdate/idbag/IdBagSequenceTest.java | 82 ++-- .../idgenerator/SequenceGenerationTest.java | 89 ++-- .../idgenerator/SequenceGeneratorsTest.java | 89 ++-- .../idgenerator/TableGeneratorTest.java | 107 ++--- .../idgenerator/TableGeneratorsTest.java | 125 ++--- .../index/ComponentIndexTest.java | 57 +-- .../index/IndexesCreationTest.java | 60 +-- .../inheritance/ForeignKeyNameTest.java | 118 +++-- .../hhh_x/InheritanceSchemaUpdateTest.java | 48 +- .../tableperclass/SchemaCreationTest.java | 82 ++-- .../manytomany/ForeignKeyNameTest.java | 76 ++-- .../UniqueConstraintDropTest.java | 202 ++++----- .../UniqueConstraintGenerationTest.java | 110 ++--- .../DurationValidationTest.java | 10 +- .../schemavalidation/EnumValidationTest.java | 212 ++++----- ...istingVarcharEnumColumnValidationTest.java | 102 +++-- .../H2ExistingEnumColumnValidationTest.java | 85 ++-- .../IdentityGenerationValidationTest.java | 45 +- .../InstantValidationTest.java | 208 ++++----- .../JoinTableWithDefaultSchemaTest.java | 53 +-- .../LongVarcharValidationTest.java | 193 +++----- .../MariaDbJsonColumnValidationTest.java | 71 +-- ...MySqlExistingEnumColumnValidationTest.java | 92 ++-- .../NumericValidationTest.java | 192 ++++---- .../schemavalidation/ViewValidationTest.java | 133 +++--- .../TableNamesWithUnderscoreTest.java | 35 +- .../test/type/AbstractJavaTimeTypeTest.java | 426 ------------------ .../hibernate/orm/test/type/InstantTest.java | 200 -------- .../orm/test/type/LocalTimeTest.java | 237 ---------- .../java/StringArrayDescriptorTest.java | 7 +- .../temporal/AbstractJavaTimeTypeTests.java | 159 +++++++ .../temporal/AbstractParametersBuilder.java | 120 +++++ .../temporal/AbstractRemappingH2Dialect.java | 37 ++ .../orm/test/type/temporal/Data.java | 12 + .../orm/test/type/temporal/Environment.java | 32 ++ .../orm/test/type/temporal/InstantTests.java | 272 +++++++++++ .../{ => temporal}/Java8DateTimeTests.java | 2 +- .../type/{ => temporal}/LocalDateTest.java | 129 ++++-- .../{ => temporal}/LocalDateTimeTest.java | 141 +++--- .../orm/test/type/temporal/LocalTimeTest.java | 278 ++++++++++++ .../{ => temporal}/OffsetDateTimeTest.java | 172 ++++--- .../type/{ => temporal}/OffsetTimeTest.java | 232 +++++----- .../orm/test/type/temporal/Parameter.java | 11 + .../orm/test/type/temporal/Timezones.java | 92 ++++ .../{ => temporal}/ZonedDateTimeTest.java | 181 ++++---- ...appingMappedSuperclassWithVersionTest.java | 36 +- .../orm/test/version/sybase/Group.java | 15 +- .../orm/test/version/sybase/Permission.java | 9 +- ...aseTimestampComparisonAnnotationsTest.java | 95 ++-- .../sybase/SybaseTimestampVersioningTest.java | 354 +++++---------- .../orm/test/version/sybase/User.java | 21 +- .../orm/test/version/sybase/User.hbm.xml | 12 +- .../org/hibernate/testing/jdbc/JdbcUtils.java | 58 +++ .../orm/junit/LoggingInspectionsScope.java | 11 + .../orm/junit/SessionFactoryExtension.java | 9 + .../orm/junit/SessionFactoryScope.java | 1 + .../testing/util/ServiceRegistryUtil.java | 2 +- 93 files changed, 4684 insertions(+), 5412 deletions(-) delete mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/id/ReSaveReferencedDeletedEntityJPA.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/PostgreSQLMultipleTypesOtherContributorTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/inet/PostgreSQLInetTypeTests.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/inet/PostgreSQLInetTypesOtherContributorTest.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/inet/PostgreSQLInetTypesOtherTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/json/PostgreSQLMultipleTypesContributorTest.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/type/AbstractJavaTimeTypeTest.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/type/InstantTest.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/type/LocalTimeTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/AbstractJavaTimeTypeTests.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/AbstractParametersBuilder.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/AbstractRemappingH2Dialect.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/Data.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/Environment.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/InstantTests.java rename hibernate-core/src/test/java/org/hibernate/orm/test/type/{ => temporal}/Java8DateTimeTests.java (99%) rename hibernate-core/src/test/java/org/hibernate/orm/test/type/{ => temporal}/LocalDateTest.java (51%) rename hibernate-core/src/test/java/org/hibernate/orm/test/type/{ => temporal}/LocalDateTimeTest.java (61%) create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/LocalTimeTest.java rename hibernate-core/src/test/java/org/hibernate/orm/test/type/{ => temporal}/OffsetDateTimeTest.java (66%) rename hibernate-core/src/test/java/org/hibernate/orm/test/type/{ => temporal}/OffsetTimeTest.java (55%) create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/Parameter.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/Timezones.java rename hibernate-core/src/test/java/org/hibernate/orm/test/type/{ => temporal}/ZonedDateTimeTest.java (67%) create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/jdbc/JdbcUtils.java diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/boot/cfgXml/CfgXmlParsingTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/cfgXml/CfgXmlParsingTest.java index 409ca254f2a8..e48e8cc7f3c9 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/boot/cfgXml/CfgXmlParsingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/boot/cfgXml/CfgXmlParsingTest.java @@ -4,45 +4,37 @@ */ package org.hibernate.orm.test.boot.cfgXml; -import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.engine.config.spi.ConfigurationService; import org.hibernate.internal.util.config.ConfigurationException; - -import org.hibernate.testing.junit4.BaseUnitTestCase; +import org.hibernate.testing.orm.junit.ExpectedException; import org.hibernate.testing.util.ServiceRegistryUtil; -import org.junit.Test; - -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.fail; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; /** * @author Steve Ebersole */ -public class CfgXmlParsingTest extends BaseUnitTestCase { +public class CfgXmlParsingTest { @Test public void testCfgXmlWithSchemaLocation() { - StandardServiceRegistry ssr = ServiceRegistryUtil.serviceRegistryBuilder() + try (var ssr = ServiceRegistryUtil.serviceRegistryBuilder() .configure( "org/hibernate/orm/test/boot/cfgXml/hibernate.cfg.xml" ) - .build(); - try { + .build()) { final ConfigurationService cs = ssr.getService( ConfigurationService.class ); // augmented form - assertNotNull( cs.getSettings().get( "hibernate.cache.provider_class" ) ); + Assertions.assertNotNull( cs.getSettings().get( "hibernate.cache.provider_class" ) ); // original form - assertNotNull( cs.getSettings().get( "cache.provider_class" ) ); - } - finally { - StandardServiceRegistryBuilder.destroy( ssr ); + Assertions.assertNotNull( cs.getSettings().get( "cache.provider_class" ) ); } } - @Test(expected = ConfigurationException.class ) + @Test + @ExpectedException(ConfigurationException.class) public void testCfgXmlWithBadNamespaceAndSchemaLocation() { - StandardServiceRegistry ssr = ServiceRegistryUtil.serviceRegistryBuilder() + try (var ssr = ServiceRegistryUtil.serviceRegistryBuilder() .configure( "org/hibernate/orm/test/boot/cfgXml/badnamespace.cfg.xml" ) - .build(); - StandardServiceRegistryBuilder.destroy( ssr ); - fail( "Expecting the bad namespace to fail" ); + .build()) { + Assertions.fail( "Expecting the bad namespace to fail" ); + } } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/cdi/general/hibernatesearch/extended/HibernateSearchExtendedCdiSupportTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/cdi/general/hibernatesearch/extended/HibernateSearchExtendedCdiSupportTest.java index b4b8d14a2088..fdf982049fd4 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/cdi/general/hibernatesearch/extended/HibernateSearchExtendedCdiSupportTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/cdi/general/hibernatesearch/extended/HibernateSearchExtendedCdiSupportTest.java @@ -7,21 +7,14 @@ import jakarta.enterprise.inject.Instance; import jakarta.enterprise.inject.se.SeContainer; import jakarta.enterprise.inject.se.SeContainerInitializer; - import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.BootstrapServiceRegistry; import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.cfg.AvailableSettings; +import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.tool.schema.Action; - -import org.hibernate.testing.junit4.BaseUnitTestCase; -import org.hibernate.testing.util.ServiceRegistryUtil; - -import org.hibernate.orm.test.cdi.general.hibernatesearch.Monitor; import org.hibernate.orm.test.cdi.general.hibernatesearch.HibernateSearchSimulatedIntegrator; +import org.hibernate.orm.test.cdi.general.hibernatesearch.Monitor; import org.hibernate.orm.test.cdi.general.hibernatesearch.TheAlternativeNamedApplicationScopedBeanImpl; import org.hibernate.orm.test.cdi.general.hibernatesearch.TheAlternativeNamedDependentBeanImpl; import org.hibernate.orm.test.cdi.general.hibernatesearch.TheApplicationScopedBean; @@ -36,9 +29,14 @@ import org.hibernate.orm.test.cdi.general.hibernatesearch.TheNonHibernateBeanConsumer; import org.hibernate.orm.test.cdi.general.hibernatesearch.TheSharedApplicationScopedBean; import org.hibernate.orm.test.cdi.testsupport.TestingExtendedBeanManager; -import org.junit.Test; +import org.hibernate.testing.orm.junit.BaseUnitTest; +import org.hibernate.testing.util.ServiceRegistryUtil; +import org.hibernate.tool.schema.Action; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertEquals; +import static org.hibernate.cfg.ManagedBeanSettings.JAKARTA_CDI_BEAN_MANAGER; +import static org.hibernate.cfg.SchemaToolingSettings.HBM2DDL_AUTO; /** * Tests support for requesting CDI beans in Hibernate Search @@ -57,144 +55,149 @@ * * @see HibernateSearchSimulatedIntegrator */ -public class HibernateSearchExtendedCdiSupportTest extends BaseUnitTestCase { +@BaseUnitTest +public class HibernateSearchExtendedCdiSupportTest { @Test public void test() { - doTest( TestingExtendedBeanManager.create() ); - } - - private void doTest(TestingExtendedBeanManager beanManager) { Monitor.reset(); - final TheFallbackBeanInstanceProducer fallbackBeanInstanceProducer = - new TheFallbackBeanInstanceProducer(); - final HibernateSearchSimulatedIntegrator beanConsumingIntegrator = - new HibernateSearchSimulatedIntegrator( fallbackBeanInstanceProducer ); - - try (SessionFactoryImplementor sessionFactory = buildSessionFactory( beanManager, beanConsumingIntegrator )) { - final SeContainerInitializer cdiInitializer = SeContainerInitializer.newInstance() - .disableDiscovery() - .addBeanClasses( TheApplicationScopedBean.class ) - .addBeanClasses( TheNamedApplicationScopedBean.class, TheMainNamedApplicationScopedBeanImpl.class, - TheAlternativeNamedApplicationScopedBeanImpl.class ) - .addBeanClasses( TheSharedApplicationScopedBean.class ) - .addBeanClasses( TheDependentBean.class ) - .addBeanClasses( TheNamedDependentBean.class, TheMainNamedDependentBeanImpl.class, - TheAlternativeNamedDependentBeanImpl.class ) - .addBeanClasses( TheNestedDependentBean.class ) - .addBeanClasses( TheNonHibernateBeanConsumer.class ); - try (final SeContainer cdiContainer = cdiInitializer.initialize()) { - // Simulate CDI bean consumers outside of Hibernate ORM - Instance nonHibernateBeanConsumerInstance = - cdiContainer.getBeanManager().createInstance().select( TheNonHibernateBeanConsumer.class ); - nonHibernateBeanConsumerInstance.get(); - - // Here, the HibernateSearchSimulatedIntegrator has just been integrated and has requested beans - // BUT it has not fetched instances of beans yet, so non-shared beans should not have been instantiated yet. - assertEquals( 0, Monitor.theApplicationScopedBean().currentInstantiationCount() ); - assertEquals( 0, Monitor.theMainNamedApplicationScopedBean().currentInstantiationCount() ); - assertEquals( 0, Monitor.theAlternativeNamedApplicationScopedBean().currentInstantiationCount() ); - assertEquals( 1, Monitor.theSharedApplicationScopedBean().currentInstantiationCount() ); - assertEquals( 0, Monitor.theDependentBean().currentInstantiationCount() ); - assertEquals( 0, Monitor.theMainNamedDependentBean().currentInstantiationCount() ); - assertEquals( 0, Monitor.theAlternativeNamedDependentBean().currentInstantiationCount() ); - assertEquals( 0, fallbackBeanInstanceProducer.currentInstantiationCount() ); - assertEquals( 0, fallbackBeanInstanceProducer.currentNamedInstantiationCount() ); - // Nested dependent bean: 1 instance per bean that depends on it - assertEquals( 1, Monitor.theNestedDependentBean().currentInstantiationCount() ); - - beanManager.notifyListenerReady( cdiContainer.getBeanManager() ); - - beanConsumingIntegrator.ensureInstancesInitialized(); - - // Here the HibernateSearchSimulatedIntegrator *did* fetch an instance of each bean, - // so all beans should have been instantiated. - // See HibernateSearchSimulatedIntegrator for a detailed list of requested beans - - // Application scope: maximum 1 instance as soon as at least one was requested - assertEquals( 1, Monitor.theApplicationScopedBean().currentInstantiationCount() ); - assertEquals( 1, Monitor.theMainNamedApplicationScopedBean().currentInstantiationCount() ); - assertEquals( 0, Monitor.theAlternativeNamedApplicationScopedBean().currentInstantiationCount() ); - assertEquals( 1, Monitor.theSharedApplicationScopedBean().currentInstantiationCount() ); - - // Dependent scope: 1 instance per bean we requested explicitly - assertEquals( 2, Monitor.theDependentBean().currentInstantiationCount() ); - assertEquals( 2, Monitor.theMainNamedDependentBean().currentInstantiationCount() ); - assertEquals( 0, Monitor.theAlternativeNamedDependentBean().currentInstantiationCount() ); - - // Reflection-instantiated: 1 instance per bean we requested explicitly - assertEquals( 2, fallbackBeanInstanceProducer.currentInstantiationCount() ); - assertEquals( 2, fallbackBeanInstanceProducer.currentNamedInstantiationCount() ); - - // Nested dependent bean: 1 instance per bean that depends on it - assertEquals( 7, Monitor.theNestedDependentBean().currentInstantiationCount() ); - - // Expect one PostConstruct call per CDI bean instance - assertEquals( 1, Monitor.theApplicationScopedBean().currentPostConstructCount() ); - assertEquals( 1, Monitor.theMainNamedApplicationScopedBean().currentPostConstructCount() ); - assertEquals( 0, Monitor.theAlternativeNamedApplicationScopedBean().currentPostConstructCount() ); - assertEquals( 1, Monitor.theSharedApplicationScopedBean().currentPostConstructCount() ); - assertEquals( 2, Monitor.theDependentBean().currentPostConstructCount() ); - assertEquals( 2, Monitor.theMainNamedDependentBean().currentPostConstructCount() ); - assertEquals( 0, Monitor.theAlternativeNamedDependentBean().currentPostConstructCount() ); - assertEquals( 7, Monitor.theNestedDependentBean().currentPostConstructCount() ); - - // Expect no PreDestroy call yet - assertEquals( 0, Monitor.theApplicationScopedBean().currentPreDestroyCount() ); - assertEquals( 0, Monitor.theMainNamedApplicationScopedBean().currentPreDestroyCount() ); - assertEquals( 0, Monitor.theAlternativeNamedApplicationScopedBean().currentPreDestroyCount() ); - assertEquals( 0, Monitor.theSharedApplicationScopedBean().currentPreDestroyCount() ); - assertEquals( 0, Monitor.theDependentBean().currentPreDestroyCount() ); - assertEquals( 0, Monitor.theMainNamedDependentBean().currentPreDestroyCount() ); - assertEquals( 0, Monitor.theAlternativeNamedDependentBean().currentPreDestroyCount() ); - assertEquals( 0, Monitor.theNestedDependentBean().currentPreDestroyCount() ); - } + final TestingExtendedBeanManager extendedBeanManager = TestingExtendedBeanManager.create(); + + final TheFallbackBeanInstanceProducer fallbackBeanInstanceProducer = new TheFallbackBeanInstanceProducer(); + final HibernateSearchSimulatedIntegrator beanConsumingIntegrator = new HibernateSearchSimulatedIntegrator( fallbackBeanInstanceProducer ); - // After the CDI context has ended, PreDestroy should have been called on every "normal-scoped" CDI bean - // (i.e. all CDI beans excepting the dependent ones we requested explicitly and haven't released yet) - assertEquals( 1, Monitor.theApplicationScopedBean().currentPreDestroyCount() ); - assertEquals( 1, Monitor.theMainNamedApplicationScopedBean().currentPreDestroyCount() ); - assertEquals( 0, Monitor.theAlternativeNamedApplicationScopedBean().currentPreDestroyCount() ); - assertEquals( 1, Monitor.theSharedApplicationScopedBean().currentPreDestroyCount() ); - assertEquals( 0, Monitor.theDependentBean().currentPreDestroyCount() ); - assertEquals( 0, Monitor.theMainNamedDependentBean().currentPreDestroyCount() ); - assertEquals( 0, Monitor.theAlternativeNamedDependentBean().currentPreDestroyCount() ); - assertEquals( 3, Monitor.theNestedDependentBean().currentPreDestroyCount() ); + try (BootstrapServiceRegistry bsr = new BootstrapServiceRegistryBuilder() + .applyIntegrator( beanConsumingIntegrator ) + .build()) { + + try (StandardServiceRegistry ssr = ServiceRegistryUtil.serviceRegistryBuilder( bsr ) + .applySetting( HBM2DDL_AUTO, Action.CREATE_DROP ) + .applySetting( JAKARTA_CDI_BEAN_MANAGER, extendedBeanManager ) + .build()) { + + final MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr ) + .addAnnotatedClass( TheEntity.class ) + .buildMetadata(); + + try (SessionFactoryImplementor sessionFactory = metadata.buildSessionFactory()) { + final SeContainerInitializer cdiInitializer = SeContainerInitializer.newInstance() + .disableDiscovery() + .addBeanClasses( TheApplicationScopedBean.class ) + .addBeanClasses( TheNamedApplicationScopedBean.class, TheMainNamedApplicationScopedBeanImpl.class, + TheAlternativeNamedApplicationScopedBeanImpl.class ) + .addBeanClasses( TheSharedApplicationScopedBean.class ) + .addBeanClasses( TheDependentBean.class ) + .addBeanClasses( TheNamedDependentBean.class, TheMainNamedDependentBeanImpl.class, + TheAlternativeNamedDependentBeanImpl.class ) + .addBeanClasses( TheNestedDependentBean.class ) + .addBeanClasses( TheNonHibernateBeanConsumer.class ); + try (final SeContainer cdiContainer = cdiInitializer.initialize()) { + // Simulate CDI bean consumers outside of Hibernate ORM + Instance nonHibernateBeanConsumerInstance = + cdiContainer.getBeanManager().createInstance().select( TheNonHibernateBeanConsumer.class ); + nonHibernateBeanConsumerInstance.get(); + + // Here, the HibernateSearchSimulatedIntegrator has just been integrated and has requested beans + // BUT it has not fetched instances of beans yet, so non-shared beans should not have been instantiated yet. + Assertions.assertEquals( 0, Monitor.theApplicationScopedBean().currentInstantiationCount() ); + Assertions.assertEquals( 0, + Monitor.theMainNamedApplicationScopedBean().currentInstantiationCount() ); + Assertions.assertEquals( 0, + Monitor.theAlternativeNamedApplicationScopedBean().currentInstantiationCount() ); + Assertions.assertEquals( 1, + Monitor.theSharedApplicationScopedBean().currentInstantiationCount() ); + Assertions.assertEquals( 0, Monitor.theDependentBean().currentInstantiationCount() ); + Assertions.assertEquals( 0, Monitor.theMainNamedDependentBean().currentInstantiationCount() ); + Assertions.assertEquals( 0, + Monitor.theAlternativeNamedDependentBean().currentInstantiationCount() ); + Assertions.assertEquals( 0, fallbackBeanInstanceProducer.currentInstantiationCount() ); + Assertions.assertEquals( 0, fallbackBeanInstanceProducer.currentNamedInstantiationCount() ); + // Nested dependent bean: 1 instance per bean that depends on it + Assertions.assertEquals( 1, Monitor.theNestedDependentBean().currentInstantiationCount() ); + + extendedBeanManager.notifyListenerReady( cdiContainer.getBeanManager() ); + + beanConsumingIntegrator.ensureInstancesInitialized(); + + // Here the HibernateSearchSimulatedIntegrator *did* fetch an instance of each bean, + // so all beans should have been instantiated. + // See HibernateSearchSimulatedIntegrator for a detailed list of requested beans + + // Application scope: maximum 1 instance as soon as at least one was requested + Assertions.assertEquals( 1, Monitor.theApplicationScopedBean().currentInstantiationCount() ); + Assertions.assertEquals( 1, + Monitor.theMainNamedApplicationScopedBean().currentInstantiationCount() ); + Assertions.assertEquals( 0, + Monitor.theAlternativeNamedApplicationScopedBean().currentInstantiationCount() ); + Assertions.assertEquals( 1, + Monitor.theSharedApplicationScopedBean().currentInstantiationCount() ); + + // Dependent scope: 1 instance per bean we requested explicitly + Assertions.assertEquals( 2, Monitor.theDependentBean().currentInstantiationCount() ); + Assertions.assertEquals( 2, Monitor.theMainNamedDependentBean().currentInstantiationCount() ); + Assertions.assertEquals( 0, + Monitor.theAlternativeNamedDependentBean().currentInstantiationCount() ); + + // Reflection-instantiated: 1 instance per bean we requested explicitly + Assertions.assertEquals( 2, fallbackBeanInstanceProducer.currentInstantiationCount() ); + Assertions.assertEquals( 2, fallbackBeanInstanceProducer.currentNamedInstantiationCount() ); + + // Nested dependent bean: 1 instance per bean that depends on it + Assertions.assertEquals( 7, Monitor.theNestedDependentBean().currentInstantiationCount() ); + + // Expect one PostConstruct call per CDI bean instance + Assertions.assertEquals( 1, Monitor.theApplicationScopedBean().currentPostConstructCount() ); + Assertions.assertEquals( 1, + Monitor.theMainNamedApplicationScopedBean().currentPostConstructCount() ); + Assertions.assertEquals( 0, + Monitor.theAlternativeNamedApplicationScopedBean().currentPostConstructCount() ); + Assertions.assertEquals( 1, + Monitor.theSharedApplicationScopedBean().currentPostConstructCount() ); + Assertions.assertEquals( 2, Monitor.theDependentBean().currentPostConstructCount() ); + Assertions.assertEquals( 2, Monitor.theMainNamedDependentBean().currentPostConstructCount() ); + Assertions.assertEquals( 0, + Monitor.theAlternativeNamedDependentBean().currentPostConstructCount() ); + Assertions.assertEquals( 7, Monitor.theNestedDependentBean().currentPostConstructCount() ); + + // Expect no PreDestroy call yet + Assertions.assertEquals( 0, Monitor.theApplicationScopedBean().currentPreDestroyCount() ); + Assertions.assertEquals( 0, + Monitor.theMainNamedApplicationScopedBean().currentPreDestroyCount() ); + Assertions.assertEquals( 0, + Monitor.theAlternativeNamedApplicationScopedBean().currentPreDestroyCount() ); + Assertions.assertEquals( 0, Monitor.theSharedApplicationScopedBean().currentPreDestroyCount() ); + Assertions.assertEquals( 0, Monitor.theDependentBean().currentPreDestroyCount() ); + Assertions.assertEquals( 0, Monitor.theMainNamedDependentBean().currentPreDestroyCount() ); + Assertions.assertEquals( 0, + Monitor.theAlternativeNamedDependentBean().currentPreDestroyCount() ); + Assertions.assertEquals( 0, Monitor.theNestedDependentBean().currentPreDestroyCount() ); + } + + // After the CDI context has ended, PreDestroy should have been called on every "normal-scoped" CDI bean + // (i.e. all CDI beans excepting the dependent ones we requested explicitly and haven't released yet) + Assertions.assertEquals( 1, Monitor.theApplicationScopedBean().currentPreDestroyCount() ); + Assertions.assertEquals( 1, Monitor.theMainNamedApplicationScopedBean().currentPreDestroyCount() ); + Assertions.assertEquals( 0, + Monitor.theAlternativeNamedApplicationScopedBean().currentPreDestroyCount() ); + Assertions.assertEquals( 1, Monitor.theSharedApplicationScopedBean().currentPreDestroyCount() ); + Assertions.assertEquals( 0, Monitor.theDependentBean().currentPreDestroyCount() ); + Assertions.assertEquals( 0, Monitor.theMainNamedDependentBean().currentPreDestroyCount() ); + Assertions.assertEquals( 0, Monitor.theAlternativeNamedDependentBean().currentPreDestroyCount() ); + Assertions.assertEquals( 3, Monitor.theNestedDependentBean().currentPreDestroyCount() ); + } + } } // Here, the HibernateSearchSimulatedIntegrator has just been disintegrated and has released beans // The dependent beans should now have been released as well. - assertEquals( 1, Monitor.theApplicationScopedBean().currentPreDestroyCount() ); - assertEquals( 1, Monitor.theMainNamedApplicationScopedBean().currentPreDestroyCount() ); - assertEquals( 0, Monitor.theAlternativeNamedApplicationScopedBean().currentPreDestroyCount() ); - assertEquals( 1, Monitor.theSharedApplicationScopedBean().currentPreDestroyCount() ); - assertEquals( 2, Monitor.theDependentBean().currentPreDestroyCount() ); - assertEquals( 2, Monitor.theMainNamedDependentBean().currentPreDestroyCount() ); - assertEquals( 0, Monitor.theAlternativeNamedDependentBean().currentPreDestroyCount() ); - assertEquals( 7, Monitor.theNestedDependentBean().currentPreDestroyCount() ); + Assertions.assertEquals( 1, Monitor.theApplicationScopedBean().currentPreDestroyCount() ); + Assertions.assertEquals( 1, Monitor.theMainNamedApplicationScopedBean().currentPreDestroyCount() ); + Assertions.assertEquals( 0, Monitor.theAlternativeNamedApplicationScopedBean().currentPreDestroyCount() ); + Assertions.assertEquals( 1, Monitor.theSharedApplicationScopedBean().currentPreDestroyCount() ); + Assertions.assertEquals( 2, Monitor.theDependentBean().currentPreDestroyCount() ); + Assertions.assertEquals( 2, Monitor.theMainNamedDependentBean().currentPreDestroyCount() ); + Assertions.assertEquals( 0, Monitor.theAlternativeNamedDependentBean().currentPreDestroyCount() ); + Assertions.assertEquals( 7, Monitor.theNestedDependentBean().currentPreDestroyCount() ); } - private SessionFactoryImplementor buildSessionFactory(TestingExtendedBeanManager beanManager, - HibernateSearchSimulatedIntegrator beanConsumingIntegrator) { - BootstrapServiceRegistry bsr = new BootstrapServiceRegistryBuilder() - .applyIntegrator( beanConsumingIntegrator ) - .build(); - - final StandardServiceRegistry ssr = ServiceRegistryUtil.serviceRegistryBuilder( bsr ) - .applySetting( AvailableSettings.HBM2DDL_AUTO, Action.CREATE_DROP ) - .applySetting( AvailableSettings.CDI_BEAN_MANAGER, beanManager ) - .build(); - - try { - return (SessionFactoryImplementor) new MetadataSources( ssr ) - .addAnnotatedClass( TheEntity.class ) - .buildMetadata() - .getSessionFactoryBuilder() - .build(); - } - catch (Exception e) { - StandardServiceRegistryBuilder.destroy( ssr ); - throw e; - } - } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/embeddable/OrderByEmbeddableToOneTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/embeddable/OrderByEmbeddableToOneTest.java index 1dcf5e11b6fb..5e05c715136e 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/embeddable/OrderByEmbeddableToOneTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/embeddable/OrderByEmbeddableToOneTest.java @@ -4,8 +4,6 @@ */ package org.hibernate.orm.test.embeddable; -import java.util.ArrayList; -import java.util.List; import jakarta.persistence.Basic; import jakarta.persistence.ElementCollection; import jakarta.persistence.Embeddable; @@ -13,40 +11,41 @@ import jakarta.persistence.Id; import jakarta.persistence.ManyToOne; import jakarta.persistence.OrderBy; - import org.hibernate.Session; -import org.hibernate.cfg.Configuration; -import org.hibernate.metamodel.CollectionClassification; import org.hibernate.query.Query; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.junit.Test; +import java.util.ArrayList; +import java.util.List; import static org.assertj.core.api.Assertions.assertThat; -import static org.hibernate.cfg.AvailableSettings.DEFAULT_LIST_SEMANTICS; - -public class OrderByEmbeddableToOneTest extends BaseCoreFunctionalTestCase { - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { Containing.class, Embed.class, Contained.class }; - } - @Override - protected void configure(Configuration configuration) { - super.configure( configuration ); - configuration.setProperty( DEFAULT_LIST_SEMANTICS, CollectionClassification.BAG ); +@SuppressWarnings("JUnitMalformedDeclaration") +@DomainModel(annotatedClasses = { + OrderByEmbeddableToOneTest.Containing.class, + OrderByEmbeddableToOneTest.Embed.class, + OrderByEmbeddableToOneTest.Contained.class +}) +@SessionFactory +public class OrderByEmbeddableToOneTest { + @AfterEach + void tearDown(SessionFactoryScope factoryScope) { + factoryScope.dropData(); } @Test - public void test() { - inTransaction( session -> { + public void test(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( session -> { saveComposition( session, 1 ); saveComposition( session, 11 ); saveComposition( session, 21 ); } ); - inTransaction( session -> { + factoryScope.inTransaction( session -> { Query query = session.createQuery( "select c from containing c order by c.id asc", Containing.class ); List resultList = query.getResultList(); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/embeddable/OrderByEmbeddableX2Test.java b/hibernate-core/src/test/java/org/hibernate/orm/test/embeddable/OrderByEmbeddableX2Test.java index cac34ce1e1fa..6e1907fc8bd7 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/embeddable/OrderByEmbeddableX2Test.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/embeddable/OrderByEmbeddableX2Test.java @@ -4,8 +4,6 @@ */ package org.hibernate.orm.test.embeddable; -import java.util.ArrayList; -import java.util.List; import jakarta.persistence.Basic; import jakarta.persistence.ElementCollection; import jakarta.persistence.Embeddable; @@ -13,40 +11,41 @@ import jakarta.persistence.Entity; import jakarta.persistence.Id; import jakarta.persistence.OrderBy; - import org.hibernate.Session; -import org.hibernate.cfg.Configuration; -import org.hibernate.metamodel.CollectionClassification; import org.hibernate.query.Query; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.junit.Test; +import java.util.ArrayList; +import java.util.List; import static org.assertj.core.api.Assertions.assertThat; -import static org.hibernate.cfg.AvailableSettings.DEFAULT_LIST_SEMANTICS; - -public class OrderByEmbeddableX2Test extends BaseCoreFunctionalTestCase { - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { Containing.class, Embed.class, Contained.class }; - } - @Override - protected void configure(Configuration configuration) { - super.configure( configuration ); - configuration.setProperty( DEFAULT_LIST_SEMANTICS, CollectionClassification.BAG ); +@SuppressWarnings("JUnitMalformedDeclaration") +@DomainModel(annotatedClasses = { + OrderByEmbeddableX2Test.Containing.class, + OrderByEmbeddableX2Test.Embed.class, + OrderByEmbeddableX2Test.Contained.class +}) +@SessionFactory +public class OrderByEmbeddableX2Test { + @AfterEach + void tearDown(SessionFactoryScope factoryScope) { + factoryScope.dropData(); } @Test - public void test() { - inTransaction( session -> { + public void test(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( session -> { saveComposition( session, 1 ); saveComposition( session, 11 ); saveComposition( session, 21 ); } ); - inTransaction( session -> { + factoryScope.inTransaction( session -> { Query query = session.createQuery( "select c from containing c order by c.id asc", Containing.class ); List resultList = query.getResultList(); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/entityname/EntityNameFromSubClassTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/entityname/EntityNameFromSubClassTest.java index 5c77d24bac41..1492cb610446 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/entityname/EntityNameFromSubClassTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/entityname/EntityNameFromSubClassTest.java @@ -3,49 +3,42 @@ * Copyright Red Hat Inc. and Hibernate Authors */ package org.hibernate.orm.test.entityname; -import org.junit.Test; -import org.hibernate.Session; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; - -import static org.junit.Assert.assertEquals; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; /** * @author stliu */ -public class EntityNameFromSubClassTest extends BaseCoreFunctionalTestCase { - - @Override - protected String getBaseForMappings() { - return "org/hibernate/orm/test/"; +@SuppressWarnings("JUnitMalformedDeclaration") +@DomainModel(xmlMappings = "org/hibernate/orm/test/entityname/Vehicle.hbm.xml") +@SessionFactory +public class EntityNameFromSubClassTest { + @AfterEach + void tearDown(SessionFactoryScope factoryScope) { + factoryScope.dropData(); } - @Override - public String[] getMappings() { - return new String[] { "entityname/Vehicle.hbm.xml" }; - } - - @SuppressWarnings( {"unchecked"}) @Test - public void testEntityName() { - Session s = openSession(); - s.beginTransaction(); - Person stliu = new Person(); - stliu.setName("stliu"); - Car golf = new Car(); - golf.setOwner("stliu"); - stliu.getCars().add(golf); - s.persist(stliu); - s.getTransaction().commit(); - s.close(); - - s=openSession(); - s.beginTransaction(); - Person p = (Person)s.get(Person.class, stliu.getId()); - assertEquals(1, p.getCars().size()); - assertEquals(Car.class, p.getCars().iterator().next().getClass()); - s.getTransaction().commit(); - s.close(); + public void testEntityName(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (s) -> { + Person stliu = new Person(); + stliu.setName("stliu"); + Car golf = new Car(); + golf.setOwner("stliu"); + stliu.getCars().add(golf); + s.persist(stliu); + } ); + + factoryScope.inTransaction( (s) -> { + Person p = s.find( Person.class, 1 ); + Assertions.assertEquals( 1, p.getCars().size() ); + Assertions.assertEquals( Car.class, p.getCars().iterator().next().getClass() ); + } ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/fetchstrategyhelper/BatchFetchStrategyHelperTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/fetchstrategyhelper/BatchFetchStrategyHelperTest.java index b32d5c8aa320..32d42fae805c 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/fetchstrategyhelper/BatchFetchStrategyHelperTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/fetchstrategyhelper/BatchFetchStrategyHelperTest.java @@ -4,191 +4,193 @@ */ package org.hibernate.orm.test.fetchstrategyhelper; -import java.util.HashSet; -import java.util.Set; - +import jakarta.persistence.ElementCollection; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; import org.hibernate.annotations.BatchSize; import org.hibernate.annotations.Fetch; import org.hibernate.annotations.FetchMode; import org.hibernate.engine.FetchStyle; import org.hibernate.engine.FetchTiming; +import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.metamodel.mapping.internal.FetchOptionsHelper; import org.hibernate.persister.entity.AbstractEntityPersister; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; import org.hibernate.type.AssociationType; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.junit.Test; - -import jakarta.persistence.ElementCollection; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.Id; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.Table; - -import static org.junit.Assert.assertSame; +import java.util.Set; /** * @author Gail Badner */ -public class BatchFetchStrategyHelperTest extends BaseCoreFunctionalTestCase { +@SuppressWarnings("JUnitMalformedDeclaration") +@DomainModel(annotatedClasses = { + BatchFetchStrategyHelperTest.AnEntity.class, + BatchFetchStrategyHelperTest.OtherEntity.class +}) +@SessionFactory +public class BatchFetchStrategyHelperTest { @Test - public void testManyToOneDefaultFetch() { - final AssociationType associationType = determineAssociationType( AnEntity.class, "otherEntityDefault" ); - final org.hibernate.FetchMode fetchMode = determineFetchMode( AnEntity.class, "otherEntityDefault" ); - assertSame( org.hibernate.FetchMode.JOIN, fetchMode ); + public void testManyToOneDefaultFetch(SessionFactoryScope factoryScope) { + final AssociationType associationType = determineAssociationType( AnEntity.class, "otherEntityDefault", factoryScope.getSessionFactory() ); + final org.hibernate.FetchMode fetchMode = determineFetchMode( AnEntity.class, "otherEntityDefault", factoryScope.getSessionFactory() ); + Assertions.assertSame( org.hibernate.FetchMode.JOIN, fetchMode ); final FetchStyle fetchStyle = FetchOptionsHelper.determineFetchStyleByMetadata( fetchMode, associationType, - sessionFactory() + factoryScope.getSessionFactory() ); // batch size is ignored with org.hibernate.FetchMode.JOIN - assertSame( FetchStyle.JOIN, fetchStyle ); + Assertions.assertSame( FetchStyle.JOIN, fetchStyle ); final FetchTiming fetchTiming = FetchOptionsHelper.determineFetchTiming( fetchStyle, associationType, - sessionFactory() + factoryScope.getSessionFactory() ); - assertSame( FetchTiming.IMMEDIATE, fetchTiming ); + Assertions.assertSame( FetchTiming.IMMEDIATE, fetchTiming ); } @Test - public void testManyToOneJoinFetch() { - final AssociationType associationType = determineAssociationType( AnEntity.class, "otherEntityJoin" ); - final org.hibernate.FetchMode fetchMode = determineFetchMode( AnEntity.class, "otherEntityJoin" ); - assertSame( org.hibernate.FetchMode.JOIN, fetchMode ); + public void testManyToOneJoinFetch(SessionFactoryScope factoryScope) { + final AssociationType associationType = determineAssociationType( AnEntity.class, "otherEntityJoin", factoryScope.getSessionFactory() ); + final org.hibernate.FetchMode fetchMode = determineFetchMode( AnEntity.class, "otherEntityJoin", factoryScope.getSessionFactory() ); + Assertions.assertSame( org.hibernate.FetchMode.JOIN, fetchMode ); final FetchStyle fetchStyle = FetchOptionsHelper.determineFetchStyleByMetadata( fetchMode, associationType, - sessionFactory() + factoryScope.getSessionFactory() ); // batch size is ignored with org.hibernate.FetchMode.JOIN - assertSame( FetchStyle.JOIN, fetchStyle ); + Assertions.assertSame( FetchStyle.JOIN, fetchStyle ); final FetchTiming fetchTiming = FetchOptionsHelper.determineFetchTiming( fetchStyle, associationType, - sessionFactory() + factoryScope.getSessionFactory() ); - assertSame( FetchTiming.IMMEDIATE, fetchTiming ); + Assertions.assertSame( FetchTiming.IMMEDIATE, fetchTiming ); } @Test - public void testManyToOneSelectFetch() { - final AssociationType associationType = determineAssociationType( AnEntity.class, "otherEntitySelect" ); - final org.hibernate.FetchMode fetchMode = determineFetchMode( AnEntity.class, "otherEntitySelect" ); - assertSame( org.hibernate.FetchMode.SELECT, fetchMode ); + public void testManyToOneSelectFetch(SessionFactoryScope factoryScope) { + final AssociationType associationType = determineAssociationType( AnEntity.class, "otherEntitySelect", factoryScope.getSessionFactory() ); + final org.hibernate.FetchMode fetchMode = determineFetchMode( AnEntity.class, "otherEntitySelect", factoryScope.getSessionFactory() ); + Assertions.assertSame( org.hibernate.FetchMode.SELECT, fetchMode ); final FetchStyle fetchStyle = FetchOptionsHelper.determineFetchStyleByMetadata( fetchMode, associationType, - sessionFactory() + factoryScope.getSessionFactory() ); - assertSame( FetchStyle.BATCH, fetchStyle ); + Assertions.assertSame( FetchStyle.BATCH, fetchStyle ); final FetchTiming fetchTiming = FetchOptionsHelper.determineFetchTiming( fetchStyle, associationType, - sessionFactory() + factoryScope.getSessionFactory() ); - assertSame( FetchTiming.DELAYED, fetchTiming ); + Assertions.assertSame( FetchTiming.DELAYED, fetchTiming ); } @Test - public void testCollectionDefaultFetch() { - final AssociationType associationType = determineAssociationType( AnEntity.class, "colorsDefault" ); - final org.hibernate.FetchMode fetchMode = determineFetchMode( AnEntity.class, "colorsDefault" ); - assertSame( org.hibernate.FetchMode.SELECT, fetchMode ); + public void testCollectionDefaultFetch(SessionFactoryScope factoryScope) { + final AssociationType associationType = determineAssociationType( AnEntity.class, "colorsDefault", factoryScope.getSessionFactory() ); + final org.hibernate.FetchMode fetchMode = determineFetchMode( AnEntity.class, "colorsDefault", factoryScope.getSessionFactory() ); + Assertions.assertSame( org.hibernate.FetchMode.SELECT, fetchMode ); final FetchStyle fetchStyle = FetchOptionsHelper.determineFetchStyleByMetadata( fetchMode, associationType, - sessionFactory() + factoryScope.getSessionFactory() ); - assertSame( FetchStyle.BATCH, fetchStyle ); + Assertions.assertSame( FetchStyle.BATCH, fetchStyle ); final FetchTiming fetchTiming = FetchOptionsHelper.determineFetchTiming( fetchStyle, associationType, - sessionFactory() + factoryScope.getSessionFactory() ); - assertSame( FetchTiming.DELAYED, fetchTiming ); + Assertions.assertSame( FetchTiming.DELAYED, fetchTiming ); } @Test - public void testCollectionJoinFetch() { - final AssociationType associationType = determineAssociationType( AnEntity.class, "colorsJoin" ); - final org.hibernate.FetchMode fetchMode = determineFetchMode( AnEntity.class, "colorsJoin" ); - assertSame( org.hibernate.FetchMode.JOIN, fetchMode ); + public void testCollectionJoinFetch(SessionFactoryScope factoryScope) { + final AssociationType associationType = determineAssociationType( AnEntity.class, "colorsJoin", factoryScope.getSessionFactory() ); + final org.hibernate.FetchMode fetchMode = determineFetchMode( AnEntity.class, "colorsJoin", factoryScope.getSessionFactory() ); + Assertions.assertSame( org.hibernate.FetchMode.JOIN, fetchMode ); final FetchStyle fetchStyle = FetchOptionsHelper.determineFetchStyleByMetadata( fetchMode, associationType, - sessionFactory() + factoryScope.getSessionFactory() ); // batch size is ignored with org.hibernate.FetchMode.JOIN - assertSame( FetchStyle.JOIN, fetchStyle ); + Assertions.assertSame( FetchStyle.JOIN, fetchStyle ); final FetchTiming fetchTiming = FetchOptionsHelper.determineFetchTiming( fetchStyle, associationType, - sessionFactory() + factoryScope.getSessionFactory() ); - assertSame( FetchTiming.IMMEDIATE, fetchTiming ); + Assertions.assertSame( FetchTiming.IMMEDIATE, fetchTiming ); } @Test - public void testCollectionSelectFetch() { - final AssociationType associationType = determineAssociationType( AnEntity.class, "colorsSelect" ); - final org.hibernate.FetchMode fetchMode = determineFetchMode( AnEntity.class, "colorsSelect" ); - assertSame( org.hibernate.FetchMode.SELECT, fetchMode ); + public void testCollectionSelectFetch(SessionFactoryScope factoryScope) { + final AssociationType associationType = determineAssociationType( AnEntity.class, "colorsSelect", factoryScope.getSessionFactory() ); + final org.hibernate.FetchMode fetchMode = determineFetchMode( AnEntity.class, "colorsSelect", factoryScope.getSessionFactory() ); + Assertions.assertSame( org.hibernate.FetchMode.SELECT, fetchMode ); final FetchStyle fetchStyle = FetchOptionsHelper.determineFetchStyleByMetadata( fetchMode, associationType, - sessionFactory() + factoryScope.getSessionFactory() ); - assertSame( FetchStyle.BATCH, fetchStyle ); + Assertions.assertSame( FetchStyle.BATCH, fetchStyle ); final FetchTiming fetchTiming = FetchOptionsHelper.determineFetchTiming( fetchStyle, associationType, - sessionFactory() + factoryScope.getSessionFactory() ); - assertSame( FetchTiming.DELAYED, fetchTiming ); + Assertions.assertSame( FetchTiming.DELAYED, fetchTiming ); } @Test - public void testCollectionSubselectFetch() { - final AssociationType associationType = determineAssociationType( AnEntity.class, "colorsSubselect" ); - final org.hibernate.FetchMode fetchMode = determineFetchMode( AnEntity.class, "colorsSubselect" ); - assertSame( org.hibernate.FetchMode.SELECT, fetchMode ); + public void testCollectionSubselectFetch(SessionFactoryScope factoryScope) { + final AssociationType associationType = determineAssociationType( AnEntity.class, "colorsSubselect", factoryScope.getSessionFactory() ); + final org.hibernate.FetchMode fetchMode = determineFetchMode( AnEntity.class, "colorsSubselect", factoryScope.getSessionFactory() ); + Assertions.assertSame( org.hibernate.FetchMode.SELECT, fetchMode ); final FetchStyle fetchStyle = FetchOptionsHelper.determineFetchStyleByMetadata( fetchMode, associationType, - sessionFactory() + factoryScope.getSessionFactory() ); // Batch size is ignored with FetchMode.SUBSELECT - assertSame( FetchStyle.SUBSELECT, fetchStyle ); + Assertions.assertSame( FetchStyle.SUBSELECT, fetchStyle ); final FetchTiming fetchTiming = FetchOptionsHelper.determineFetchTiming( fetchStyle, associationType, - sessionFactory() + factoryScope.getSessionFactory() ); - assertSame( FetchTiming.DELAYED, fetchTiming ); + Assertions.assertSame( FetchTiming.DELAYED, fetchTiming ); } - private org.hibernate.FetchMode determineFetchMode(Class entityClass, String path) { + private org.hibernate.FetchMode determineFetchMode(Class entityClass, String path, SessionFactoryImplementor sessionFactory) { AbstractEntityPersister entityPersister = (AbstractEntityPersister) - sessionFactory().getMappingMetamodel().getEntityDescriptor(entityClass.getName()); + sessionFactory.getMappingMetamodel().getEntityDescriptor(entityClass.getName()); int index = entityPersister.getPropertyIndex( path ); return entityPersister.getFetchMode( index ); } - private AssociationType determineAssociationType(Class entityClass, String path) { + private AssociationType determineAssociationType( + Class entityClass, + String path, + SessionFactoryImplementor sessionFactory) { AbstractEntityPersister entityPersister = (AbstractEntityPersister) - sessionFactory().getMappingMetamodel().getEntityDescriptor(entityClass.getName()); + sessionFactory.getMappingMetamodel().getEntityDescriptor(entityClass.getName()); int index = entityPersister.getPropertyIndex( path ); return (AssociationType) entityPersister.getSubclassPropertyType( index ); } - protected Class[] getAnnotatedClasses() { - return new Class[] { - AnEntity.class, - OtherEntity.class - }; - } @jakarta.persistence.Entity @Table(name="entity") public static class AnEntity { @@ -211,22 +213,22 @@ public static class AnEntity { @ElementCollection @BatchSize( size = 5) - private Set colorsDefault = new HashSet(); + private Set colorsDefault; @ElementCollection @Fetch(FetchMode.JOIN) @BatchSize( size = 5) - private Set colorsJoin = new HashSet(); + private Set colorsJoin; @ElementCollection @Fetch(FetchMode.SELECT) @BatchSize( size = 5) - private Set colorsSelect = new HashSet(); + private Set colorsSelect; @ElementCollection @Fetch(FetchMode.SUBSELECT) @BatchSize( size = 5) - private Set colorsSubselect = new HashSet(); + private Set colorsSubselect; } @jakarta.persistence.Entity diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/fetchstrategyhelper/FetchStrategyDeterminationTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/fetchstrategyhelper/FetchStrategyDeterminationTests.java index 6369efb5377d..af2e5fd23436 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/fetchstrategyhelper/FetchStrategyDeterminationTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/fetchstrategyhelper/FetchStrategyDeterminationTests.java @@ -4,6 +4,11 @@ */ package org.hibernate.orm.test.fetchstrategyhelper; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.Id; +import jakarta.persistence.ManyToOne; +import jakarta.persistence.Table; import org.hibernate.annotations.Fetch; import org.hibernate.annotations.FetchMode; import org.hibernate.engine.FetchStyle; @@ -11,70 +16,50 @@ import org.hibernate.metamodel.mapping.AttributeMapping; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.sql.results.graph.FetchOptions; - -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.junit.Test; - -import jakarta.persistence.Entity; -import jakarta.persistence.GeneratedValue; -import jakarta.persistence.Id; -import jakarta.persistence.ManyToOne; -import jakarta.persistence.Table; - -import static org.junit.Assert.assertEquals; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; /** * @author Gail Badner */ -public class FetchStrategyDeterminationTests extends BaseCoreFunctionalTestCase { +@SuppressWarnings("JUnitMalformedDeclaration") +@DomainModel(annotatedClasses = { + FetchStrategyDeterminationTests.AnEntity.class, + FetchStrategyDeterminationTests.OtherEntity.class +}) +@SessionFactory +public class FetchStrategyDeterminationTests { @Test - public void testManyToOneDefaultFetch() { - final EntityPersister entityDescriptor = sessionFactory().getMappingMetamodel().getEntityDescriptor( AnEntity.class ); + public void testManyToOneDefaultFetch(SessionFactoryScope factoryScope) { + final EntityPersister entityDescriptor = factoryScope.getSessionFactory().getMappingMetamodel().getEntityDescriptor( AnEntity.class ); final AttributeMapping attributeMapping = entityDescriptor.findAttributeMapping( "otherEntityDefault" ); final FetchOptions mappedFetchOptions = attributeMapping.getMappedFetchOptions(); - assertEquals( mappedFetchOptions.getTiming(), FetchTiming.IMMEDIATE ); - assertEquals( mappedFetchOptions.getStyle(), FetchStyle.JOIN ); + Assertions.assertEquals( FetchTiming.IMMEDIATE, mappedFetchOptions.getTiming() ); + Assertions.assertEquals( FetchStyle.JOIN, mappedFetchOptions.getStyle() ); } @Test - public void testManyToOneJoinFetch() { - final EntityPersister entityDescriptor = sessionFactory().getMappingMetamodel().getEntityDescriptor( AnEntity.class ); + public void testManyToOneJoinFetch(SessionFactoryScope factoryScope) { + final EntityPersister entityDescriptor = factoryScope.getSessionFactory().getMappingMetamodel().getEntityDescriptor( AnEntity.class ); final AttributeMapping attributeMapping = entityDescriptor.findAttributeMapping( "otherEntityJoin" ); final FetchOptions mappedFetchOptions = attributeMapping.getMappedFetchOptions(); - assertEquals( mappedFetchOptions.getTiming(), FetchTiming.IMMEDIATE ); - assertEquals( mappedFetchOptions.getStyle(), FetchStyle.JOIN ); + Assertions.assertEquals( FetchTiming.IMMEDIATE, mappedFetchOptions.getTiming() ); + Assertions.assertEquals( FetchStyle.JOIN, mappedFetchOptions.getStyle() ); } @Test - public void testManyToOneSelectFetch() { - final EntityPersister entityDescriptor = sessionFactory().getMappingMetamodel().getEntityDescriptor( AnEntity.class ); + public void testManyToOneSelectFetch(SessionFactoryScope factoryScope) { + final EntityPersister entityDescriptor = factoryScope.getSessionFactory().getMappingMetamodel().getEntityDescriptor( AnEntity.class ); final AttributeMapping attributeMapping = entityDescriptor.findAttributeMapping( "otherEntitySelect" ); final FetchOptions mappedFetchOptions = attributeMapping.getMappedFetchOptions(); - assertEquals( mappedFetchOptions.getTiming(), FetchTiming.IMMEDIATE ); - assertEquals( mappedFetchOptions.getStyle(), FetchStyle.SELECT ); + Assertions.assertEquals( FetchTiming.IMMEDIATE, mappedFetchOptions.getTiming() ); + Assertions.assertEquals( FetchStyle.SELECT, mappedFetchOptions.getStyle() ); } -// -// private org.hibernate.FetchMode determineFetchMode(Class entityClass, String path) { -// AbstractEntityPersister entityPersister = (AbstractEntityPersister) -// sessionFactory().getMappingMetamodel().getEntityDescriptor(entityClass.getName()); -// int index = entityPersister.getPropertyIndex( path ); -// return entityPersister.getFetchMode( index ); -// } -// -// private AssociationType determineAssociationType(Class entityClass, String path) { -// AbstractEntityPersister entityPersister = (AbstractEntityPersister) -// sessionFactory().getMappingMetamodel().getEntityDescriptor(entityClass.getName()); -// int index = entityPersister.getPropertyIndex( path ); -// return (AssociationType) entityPersister.getSubclassPropertyType( index ); -// } - protected Class[] getAnnotatedClasses() { - return new Class[] { - AnEntity.class, - OtherEntity.class - }; - } @Entity @Table(name="entity") public static class AnEntity { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/PostgreSQLFunctionSelectClauseTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/PostgreSQLFunctionSelectClauseTest.java index c447dc38aa4a..b980683b51eb 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/PostgreSQLFunctionSelectClauseTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/PostgreSQLFunctionSelectClauseTest.java @@ -4,120 +4,93 @@ */ package org.hibernate.orm.test.hql; -import java.sql.Statement; -import java.util.List; -import java.util.Map; import jakarta.persistence.Entity; import jakarta.persistence.Id; import jakarta.persistence.Tuple; - -import org.hibernate.Session; -import org.hibernate.boot.spi.MetadataBuilderContributor; +import org.hibernate.boot.model.FunctionContributions; +import org.hibernate.boot.model.FunctionContributor; import org.hibernate.dialect.PostgreSQLDialect; -import org.hibernate.dialect.function.StandardSQLFunction; -import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase; +import org.hibernate.query.sqm.produce.function.StandardArgumentsValidators; +import org.hibernate.testing.orm.junit.BootstrapServiceRegistry; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; import org.hibernate.type.StandardBasicTypes; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import org.hibernate.testing.RequiresDialect; -import org.junit.After; -import org.junit.Test; - -import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; -import static org.junit.Assert.assertEquals; +import java.sql.Statement; /** * @author Vlad Mihalcea */ +@SuppressWarnings("JUnitMalformedDeclaration") @RequiresDialect(PostgreSQLDialect.class) -public class PostgreSQLFunctionSelectClauseTest extends BaseEntityManagerFunctionalTestCase { - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { - Book.class - }; - } - - @Override - protected void addMappings(Map settings) { - //tag::hql-user-defined-functions-register-metadata-builder-example[] - settings.put("hibernate.metadata_builder_contributor", - (MetadataBuilderContributor) metadataBuilder -> - metadataBuilder.applySqlFunction( - "apply_vat", - new StandardSQLFunction( - "apply_vat", - StandardBasicTypes.INTEGER - ) - ) - ); - //end::hql-user-defined-functions-register-metadata-builder-example[] - } - - @Override - protected void afterEntityManagerFactoryBuilt() { - doInJPA(this::entityManagerFactory, entityManager -> { - entityManager.unwrap(Session.class).doWork( - connection -> { - try(Statement statement = connection.createStatement()) { - statement.executeUpdate( - "CREATE OR REPLACE FUNCTION apply_vat(integer) RETURNS integer " + - " AS 'select cast(($1 * 1.2) as integer);' " + - " LANGUAGE SQL " + - " IMMUTABLE " + - " RETURNS NULL ON NULL INPUT;" - ); - } - } - ); - }); - - doInJPA(this::entityManagerFactory, entityManager -> { - Book book = new Book(); - +@BootstrapServiceRegistry( javaServices = @BootstrapServiceRegistry.JavaService( + role = FunctionContributor.class, + impl = PostgreSQLFunctionSelectClauseTest.FunctionContributorImpl.class +) ) +@DomainModel(annotatedClasses = PostgreSQLFunctionSelectClauseTest.Book.class) +@SessionFactory +public class PostgreSQLFunctionSelectClauseTest { + @BeforeEach + void setUp(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (session) -> session.doWork( (connection) -> { + try(Statement statement = connection.createStatement()) { + statement.executeUpdate( + "CREATE OR REPLACE FUNCTION apply_vat(integer) RETURNS integer " + + " AS 'select cast(($1 * 1.2) as integer);' " + + " LANGUAGE SQL " + + " IMMUTABLE " + + " RETURNS NULL ON NULL INPUT;" + ); + } + } ) ); + + factoryScope.inTransaction( (session) -> { + var book = new Book(); book.setIsbn("978-9730228236"); book.setTitle("High-Performance Java Persistence"); book.setAuthor("Vlad Mihalcea"); book.setPriceCents(4500); - - entityManager.persist(book); - }); + session.persist(book); + } ); } - @After - public void destroy() { - doInJPA(this::entityManagerFactory, entityManager -> { - entityManager.unwrap(Session.class).doWork( - connection -> { - try(Statement statement = connection.createStatement()) { - statement.executeUpdate( - "DROP FUNCTION apply_vat(integer)" - ); - } - } - ); - }); + @AfterEach + public void tearDown(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (session) -> session.doWork( (connection) -> { + try(Statement statement = connection.createStatement()) { + statement.executeUpdate( + "DROP FUNCTION apply_vat(integer)" + ); + } + } ) ); + + factoryScope.dropData(); } @Test - public void testHibernateSelectClauseFunction() { - doInJPA(this::entityManagerFactory, entityManager -> { + public void testHibernateSelectClauseFunction(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (entityManager) -> { //tag::hql-user-defined-function-postgresql-select-clause-example[] - List books = entityManager.createQuery( - "select b.title as title, apply_vat(b.priceCents) as price " + - "from Book b " + - "where b.author = :author ", Tuple.class) - .setParameter("author", "Vlad Mihalcea") - .getResultList(); + var books = entityManager.createQuery( + "select b.title as title, apply_vat(b.priceCents) as price " + + "from Book b " + + "where b.author = :author ", Tuple.class) + .setParameter("author", "Vlad Mihalcea") + .getResultList(); + //end::hql-user-defined-function-postgresql-select-clause-example[] - assertEquals(1, books.size()); + Assertions.assertEquals( 1, books.size() ); Tuple book = books.get(0); - assertEquals("High-Performance Java Persistence", book.get("title")); - assertEquals(5400, ((Number) book.get("price")).intValue()); - - //end::hql-user-defined-function-postgresql-select-clause-example[] - }); + Assertions.assertEquals( "High-Performance Java Persistence", book.get("title") ); + Assertions.assertEquals( 4500 * 1.2, ((Number) book.get("price")).intValue() ); + } ); } @Entity(name = "Book") @@ -164,4 +137,16 @@ public void setPriceCents(Integer priceCents) { this.priceCents = priceCents; } } + + public static class FunctionContributorImpl implements FunctionContributor { + @Override + public void contributeFunctions(FunctionContributions functionContributions) { + //tag::hql-user-defined-functions-register-metadata-builder-example[] + functionContributions.getFunctionRegistry().namedDescriptorBuilder( "apply_vat" ) + .setInvariantType( functionContributions.getTypeConfiguration().getBasicTypeRegistry().resolve( StandardBasicTypes.INTEGER ) ) + .setArgumentsValidator( StandardArgumentsValidators.of( Integer.class ) ) + .register(); + //end::hql-user-defined-functions-register-metadata-builder-example[] + } + } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/PostgreSQLFunctionWhereClauseTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/PostgreSQLFunctionWhereClauseTest.java index b9ab63c434e0..3258011790b6 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/hql/PostgreSQLFunctionWhereClauseTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/hql/PostgreSQLFunctionWhereClauseTest.java @@ -4,56 +4,51 @@ */ package org.hibernate.orm.test.hql; -import java.sql.Statement; -import java.util.List; import jakarta.persistence.Entity; import jakarta.persistence.Id; - -import org.hibernate.Session; +import org.hibernate.boot.model.FunctionContributor; import org.hibernate.dialect.PostgreSQLDialect; -import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase; +import org.hibernate.testing.orm.junit.BootstrapServiceRegistry; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import org.hibernate.testing.RequiresDialect; -import org.junit.After; -import org.junit.Test; - -import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; -import static org.junit.Assert.assertTrue; +import java.sql.Statement; /** * @author Vlad Mihalcea */ +@SuppressWarnings("JUnitMalformedDeclaration") @RequiresDialect(PostgreSQLDialect.class) -public class PostgreSQLFunctionWhereClauseTest extends BaseEntityManagerFunctionalTestCase { - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { - Book.class - }; - } - - @Override - protected void afterEntityManagerFactoryBuilt() { - doInJPA(this::entityManagerFactory, entityManager -> { - entityManager.unwrap(Session.class).doWork( - connection -> { - try(Statement statement = connection.createStatement()) { - //tag::hql-user-defined-function-postgresql-example[] - statement.executeUpdate( - "CREATE OR REPLACE FUNCTION apply_vat(integer) RETURNS integer " + - " AS 'select cast(($1 * 1.2) as integer);' " + - " LANGUAGE SQL " + - " IMMUTABLE " + - " RETURNS NULL ON NULL INPUT;" - ); - //end::hql-user-defined-function-postgresql-example[] - } - } - ); - }); - - doInJPA(this::entityManagerFactory, entityManager -> { +@BootstrapServiceRegistry( javaServices = @BootstrapServiceRegistry.JavaService( + role = FunctionContributor.class, + impl = PostgreSQLFunctionSelectClauseTest.FunctionContributorImpl.class +) ) +@DomainModel( annotatedClasses = PostgreSQLFunctionWhereClauseTest.Book.class ) +@SessionFactory +public class PostgreSQLFunctionWhereClauseTest { + @BeforeEach + void setUp(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (entityManager) -> entityManager.doWork( (connection) -> { + try(Statement statement = connection.createStatement()) { + //tag::hql-user-defined-function-postgresql-example[] + statement.executeUpdate( + "CREATE OR REPLACE FUNCTION apply_vat(integer) RETURNS integer " + + " AS 'select cast(($1 * 1.2) as integer);' " + + " LANGUAGE SQL " + + " IMMUTABLE " + + " RETURNS NULL ON NULL INPUT;" + ); + //end::hql-user-defined-function-postgresql-example[] + } + } ) ); + + factoryScope.inTransaction( (entityManager) -> { //tag::hql-user-defined-function-postgresql-entity-example[] Book book = new Book(); @@ -64,64 +59,56 @@ protected void afterEntityManagerFactoryBuilt() { entityManager.persist(book); //end::hql-user-defined-function-postgresql-entity-example[] - }); + } ); } - @After - public void destroy() { - doInJPA(this::entityManagerFactory, entityManager -> { - entityManager.unwrap(Session.class).doWork( - connection -> { - try(Statement statement = connection.createStatement()) { - statement.executeUpdate( - "DROP FUNCTION apply_vat(integer)" - ); - } - } - ); - }); + @AfterEach + public void tearDown(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (session) -> session.doWork( (connection) -> { + try(Statement statement = connection.createStatement()) { + statement.executeUpdate( + "DROP FUNCTION apply_vat(integer)" + ); + } + } ) ); + + factoryScope.dropData(); } @Test - public void testHibernatePassThroughFunction() { - doInJPA(this::entityManagerFactory, entityManager -> { + public void testHibernatePassThroughFunction(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (entityManager) -> { //tag::hql-user-defined-function-postgresql-where-clause-example[] - List books = entityManager.createQuery( - "select b " + - "from Book b " + - "where apply_vat(b.priceCents) = :price ", Book.class) - .setParameter("price", 5400) - .getResultList(); - - assertTrue(books - .stream() - .filter(book -> "High-Performance Java Persistence".equals(book.getTitle())) - .findAny() - .isPresent() - ); + var books = entityManager.createQuery( + "select b " + + "from Book b " + + "where apply_vat(b.priceCents) = :price ", Book.class) + .setParameter("price", 5400) + .getResultList(); + + Assertions.assertTrue( books + .stream() + .anyMatch( book -> "High-Performance Java Persistence".equals(book.getTitle())) ); //end::hql-user-defined-function-postgresql-where-clause-example[] - }); + } ); } @Test - public void testCustomFunction() { - doInJPA(this::entityManagerFactory, entityManager -> { + public void testCustomFunction(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (entityManager) -> { //tag::hql-user-defined-function-postgresql-jpql-example[] - List books = entityManager.createQuery( - "select b " + - "from Book b " + - "where function('apply_vat', b.priceCents) = :price ", Book.class) - .setParameter("price", 5400) - .getResultList(); - - assertTrue(books - .stream() - .filter(book -> "High-Performance Java Persistence".equals(book.getTitle())) - .findAny() - .isPresent() - ); + var books = entityManager.createQuery( + "select b " + + "from Book b " + + "where function('apply_vat', b.priceCents) = :price ", Book.class) + .setParameter("price", 5400) + .getResultList(); + + Assertions.assertTrue( books + .stream() + .anyMatch( book -> "High-Performance Java Persistence".equals(book.getTitle())) ); //end::hql-user-defined-function-postgresql-jpql-example[] - }); + } ); } @Entity(name = "Book") diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/id/ReSaveReferencedDeletedEntityJPA.java b/hibernate-core/src/test/java/org/hibernate/orm/test/id/ReSaveReferencedDeletedEntityJPA.java deleted file mode 100644 index 88f1bb5c44a9..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/id/ReSaveReferencedDeletedEntityJPA.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.test.id; - -import org.hibernate.cfg.AvailableSettings; -import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase; -import org.junit.Test; - -import jakarta.persistence.*; - -import java.util.Map; - -public class ReSaveReferencedDeletedEntityJPA extends BaseEntityManagerFunctionalTestCase { - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { Child.class, Parent.class }; - } - - @Override - protected Map buildSettings() { - Map settings = super.buildSettings(); - settings.put( AvailableSettings.USE_IDENTIFIER_ROLLBACK, "true" ); - return settings; - } - - @Test - @ JiraKey("HHH-14416") - public void testRefreshUnDeletedEntityWithReferencesJPA() { - EntityManager em = getOrCreateEntityManager(); - em.getTransaction().begin(); - - Parent parent = new Parent(); - parent.setId(1); - - Child child = new Child(); - child.setId(2); - parent.setChild( child ); - - em.persist( parent ); - - em.flush(); - - em.remove( parent ); - - em.flush(); - - em.detach( parent ); - - em.persist( parent ); - - em.flush(); - - em.refresh( child ); - - em.getTransaction().commit(); - } - - @Test - @JiraKey("HHH-14416") - public void testReSaveDeletedEntityWithReferencesJPA() { - EntityManager em = getOrCreateEntityManager(); - em.getTransaction().begin(); - - Parent parent = new Parent(); - parent.setId(1); - - Child child = new Child(); - child.setId(2); - parent.setChild( child ); - - em.persist( parent ); - - parent.setChild( null ); - em.remove( child ); - - em.persist( child ); - - em.getTransaction().commit(); - } - - @Entity(name = "Child") - public static class Child { - @Id - private Integer id; - - public Integer getId() { - return id; - } - - public void setId(Integer id) { - this.id = id; - } - } - - @Entity(name = "Parent") - public static class Parent { - @Id - private Integer id; - - @OneToOne(cascade = CascadeType.ALL) - private Child child; - - public Integer getId() { - return id; - } - - public void setId(Integer id) { - this.id = id; - } - - public Child getChild() { - return child; - } - - public void setChild(Child child) { - this.child = child; - } - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/PostgreSQLMultipleTypesOtherContributorTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/PostgreSQLMultipleTypesOtherContributorTest.java deleted file mode 100644 index ef1fb59790e8..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/PostgreSQLMultipleTypesOtherContributorTest.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.test.id.usertype; - -import java.util.List; -import java.util.Map; - -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.Table; - -import org.hibernate.annotations.JavaType; -import org.hibernate.annotations.JdbcTypeCode; -import org.hibernate.boot.spi.MetadataBuilderContributor; -import org.hibernate.boot.spi.MetadataBuilderImplementor; -import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl; -import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase; -import org.hibernate.query.NativeQuery; -import org.hibernate.testing.orm.junit.DialectFeatureChecks; -import org.hibernate.testing.orm.junit.RequiresDialectFeature; -import org.hibernate.type.SqlTypes; -import org.hibernate.type.spi.TypeConfiguration; - -import org.hibernate.orm.test.id.usertype.inet.Inet; -import org.hibernate.orm.test.id.usertype.inet.InetJavaType; -import org.hibernate.orm.test.id.usertype.inet.InetJdbcType; -import org.hibernate.orm.test.id.usertype.inet.InetType; -import org.hibernate.orm.test.id.usertype.json.Json; -import org.hibernate.orm.test.id.usertype.json.JsonJavaType; -import org.hibernate.orm.test.id.usertype.json.JsonType; -import org.junit.Test; - -import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; -import static org.junit.Assert.assertEquals; - -/** - * @author Vlad Mihalcea - */ -@RequiresDialectFeature(feature = DialectFeatureChecks.IsPgJdbc.class) -public class PostgreSQLMultipleTypesOtherContributorTest extends BaseEntityManagerFunctionalTestCase { - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { - Event.class - }; - } - - @Override - protected void afterEntityManagerFactoryBuilt() { - - doInJPA( this::entityManagerFactory, entityManager -> { - Event event = new Event(); - event.setId( 1L ); - event.setIp( "192.168.0.123/24" ); - event.setProperties( new Json( "{\"key\": \"temp\", \"value\": \"9C\"}" ) ); - - entityManager.persist( event ); - } ); - } - - @Override - protected void addConfigOptions(Map options) { - options.put( - EntityManagerFactoryBuilderImpl.METADATA_BUILDER_CONTRIBUTOR, - (MetadataBuilderContributor) metadataBuilder -> { - final TypeConfiguration typeConfiguration = - ( (MetadataBuilderImplementor) metadataBuilder ) - .getBootstrapContext() - .getTypeConfiguration(); - typeConfiguration.getJavaTypeRegistry().addDescriptor( InetJavaType.INSTANCE ); - typeConfiguration.getJdbcTypeRegistry().addDescriptor( InetJdbcType.INSTANCE ); - metadataBuilder.applyBasicType( - InetType.INSTANCE, InetType.INSTANCE.getName() - ); - metadataBuilder.applyBasicType( - JsonType.INSTANCE, JsonType.INSTANCE.getName() - ); - } - ); - } - - @Test - public void testMultipleTypeContributions() { - doInJPA( this::entityManagerFactory, entityManager -> { - List inets = entityManager.createNativeQuery( - "select e.ip " + - "from Event e " + - "where e.id = :id" ) - .setParameter( "id", 1L ) - .getResultList(); - - assertEquals( 1, inets.size() ); - assertEquals( "192.168.0.123/24", inets.get( 0 ).getAddress() ); - } ); - } - - @Test - public void testMultipleTypeContributionsExplicitBinding() { - doInJPA( this::entityManagerFactory, entityManager -> { - List inets = entityManager.createNativeQuery( - "select e.ip " + - "from Event e " + - "where e.id = :id" ) - .setParameter( "id", 1L ) - .unwrap( NativeQuery.class ) - .addScalar( "ip", InetType.INSTANCE ) - .getResultList(); - - assertEquals( 1, inets.size() ); - assertEquals( "192.168.0.123/24", inets.get( 0 ).getAddress() ); - } ); - } - - @Entity(name = "Event") - @Table(name = "event") - public class Event { - - @Id - private Long id; - - @Column(name = "ip") - @JdbcTypeCode(SqlTypes.INET) - @JavaType(InetJavaType.class) - private Inet ip; - - @Column(name = "properties") - @JdbcTypeCode(SqlTypes.JSON) - @JavaType(JsonJavaType.class) - private Json properties; - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public Inet getIp() { - return ip; - } - - public void setIp(String address) { - this.ip = new Inet( address ); - } - - public Json getProperties() { - return properties; - } - - public void setProperties(Json properties) { - this.properties = properties; - } - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/inet/PostgreSQLInetTypeTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/inet/PostgreSQLInetTypeTests.java new file mode 100644 index 000000000000..3484c6fc0358 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/inet/PostgreSQLInetTypeTests.java @@ -0,0 +1,95 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.id.usertype.inet; + +import org.hibernate.boot.model.TypeContributions; +import org.hibernate.boot.model.TypeContributor; +import org.hibernate.query.NativeQuery; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.testing.orm.junit.BootstrapServiceRegistry; +import org.hibernate.testing.orm.junit.DialectFeatureChecks; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.RequiresDialectFeature; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; + +/** + * @author Vlad Mihalcea + */ +@SuppressWarnings("JUnitMalformedDeclaration") +@RequiresDialectFeature(feature = DialectFeatureChecks.IsPgJdbc.class) +@BootstrapServiceRegistry( javaServices = @BootstrapServiceRegistry.JavaService( + role = TypeContributor.class, + impl = PostgreSQLInetTypeTests.TypeContributorImpl.class +) ) +@DomainModel(annotatedClasses = Event.class) +@SessionFactory +public class PostgreSQLInetTypeTests { + @BeforeEach + void setUp(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (session) -> { + var event = new Event(); + event.setId( 1L ); + event.setIp( "192.168.0.123/24" ); + + session.persist( event ); + } ); + } + + @AfterEach + void tearDown(SessionFactoryScope factoryScope) { + factoryScope.dropData(); + } + + @Test + public void testJPQL(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( entityManager -> { + var inets = entityManager.createQuery( + "select e.ip " + + "from Event e " + + "where e.id = :id", Inet.class ) + .setParameter( "id", 1L ) + .getResultList(); + + Assertions.assertEquals( 1, inets.size() ); + Assertions.assertEquals( "192.168.0.123/24", inets.get( 0 ).getAddress() ); + } ); + } + + @Test + public void testNativeSQLAddScalar(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( entityManager -> { + List inets = entityManager.createNativeQuery( + "select e.ip as ip " + + "from Event e " + + "where e.id = :id" ) + .setParameter( "id", 1L ) + .unwrap( NativeQuery.class ) + .addScalar( "ip", InetType.INSTANCE ) + .getResultList(); + + Assertions.assertEquals( 1, inets.size() ); + Assertions.assertEquals( "192.168.0.123/24", inets.get( 0 ).getAddress() ); + } ); + } + + + public static class TypeContributorImpl implements TypeContributor { + @Override + public void contribute(TypeContributions typeContributions, ServiceRegistry serviceRegistry) { + typeContributions.contributeJavaType( InetJavaType.INSTANCE ); + typeContributions.contributeJdbcType( InetJdbcType.INSTANCE ); + + var typeConfiguration = typeContributions.getTypeConfiguration(); + typeConfiguration.getBasicTypeRegistry().register( InetType.INSTANCE ); + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/inet/PostgreSQLInetTypesOtherContributorTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/inet/PostgreSQLInetTypesOtherContributorTest.java deleted file mode 100644 index 6d348d0e6ea2..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/inet/PostgreSQLInetTypesOtherContributorTest.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.test.id.usertype.inet; - -import java.util.List; -import java.util.Map; - -import org.hibernate.boot.MetadataBuilder; -import org.hibernate.boot.spi.MetadataBuilderContributor; -import org.hibernate.boot.spi.MetadataBuilderImplementor; -import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl; -import org.hibernate.testing.orm.junit.DialectFeatureChecks; -import org.hibernate.testing.orm.junit.RequiresDialectFeature; -import org.hibernate.type.spi.TypeConfiguration; - -import org.junit.Test; - -import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; -import static org.junit.Assert.assertEquals; - -/** - * @author Vlad Mihalcea - */ -@RequiresDialectFeature(feature = DialectFeatureChecks.IsPgJdbc.class) -public class PostgreSQLInetTypesOtherContributorTest extends PostgreSQLInetTypesOtherTest { - - @Override - protected void addConfigOptions(Map options) { - options.put( EntityManagerFactoryBuilderImpl.METADATA_BUILDER_CONTRIBUTOR, new InetTypeMetadataBuilderContributor() ); - } - - @Test - public void testTypeContribution() { - doInJPA( this::entityManagerFactory, entityManager -> { - List inets = entityManager.createNativeQuery( - "select e.ip " + - "from Event e " + - "where e.id = :id" ) - .setParameter( "id", 1L ) - .getResultList(); - - assertEquals( 1, inets.size() ); - assertEquals( "192.168.0.123/24", inets.get( 0 ).getAddress() ); - } ); - } - - public class InetTypeMetadataBuilderContributor - implements MetadataBuilderContributor { - - @Override - public void contribute(MetadataBuilder metadataBuilder) { - final TypeConfiguration typeConfiguration = - ( (MetadataBuilderImplementor) metadataBuilder ) - .getBootstrapContext() - .getTypeConfiguration(); - typeConfiguration.getJavaTypeRegistry().addDescriptor( InetJavaType.INSTANCE ); - typeConfiguration.getJdbcTypeRegistry().addDescriptor( InetJdbcType.INSTANCE ); - metadataBuilder.applyBasicType( - InetType.INSTANCE, "inet" - ); - } - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/inet/PostgreSQLInetTypesOtherTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/inet/PostgreSQLInetTypesOtherTest.java deleted file mode 100644 index e02103aefff9..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/inet/PostgreSQLInetTypesOtherTest.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.test.id.usertype.inet; - -import java.util.List; -import java.util.Map; - -import org.hibernate.boot.spi.MetadataBuilderContributor; -import org.hibernate.boot.spi.MetadataBuilderImplementor; -import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl; -import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase; -import org.hibernate.query.NativeQuery; -import org.hibernate.testing.orm.junit.DialectFeatureChecks; -import org.hibernate.testing.orm.junit.RequiresDialectFeature; -import org.hibernate.type.spi.TypeConfiguration; - -import org.junit.Test; - -import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; -import static org.junit.Assert.assertEquals; - -/** - * @author Vlad Mihalcea - */ -@RequiresDialectFeature(feature = DialectFeatureChecks.IsPgJdbc.class) -public class PostgreSQLInetTypesOtherTest extends BaseEntityManagerFunctionalTestCase { - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { - Event.class - }; - } - - @Override - protected void addConfigOptions(Map options) { - options.put( - EntityManagerFactoryBuilderImpl.METADATA_BUILDER_CONTRIBUTOR, - (MetadataBuilderContributor) metadataBuilder -> { - final TypeConfiguration typeConfiguration = - ( (MetadataBuilderImplementor) metadataBuilder ) - .getBootstrapContext() - .getTypeConfiguration(); - typeConfiguration.getJavaTypeRegistry().addDescriptor( InetJavaType.INSTANCE ); - typeConfiguration.getJdbcTypeRegistry().addDescriptor( InetJdbcType.INSTANCE ); - metadataBuilder.applyBasicType( - InetType.INSTANCE, InetType.INSTANCE.getName() - ); - } - ); - } - - @Override - protected void afterEntityManagerFactoryBuilt() { - - doInJPA( this::entityManagerFactory, entityManager -> { - Event event = new Event(); - event.setId( 1L ); - event.setIp( "192.168.0.123/24" ); - - entityManager.persist( event ); - } ); - } - - @Test - public void testJPQL() { - doInJPA( this::entityManagerFactory, entityManager -> { - List inets = entityManager.createQuery( - "select e.ip " + - "from Event e " + - "where e.id = :id" ) - .setParameter( "id", 1L ) - .getResultList(); - - assertEquals( 1, inets.size() ); - assertEquals( "192.168.0.123/24", inets.get( 0 ).getAddress() ); - } ); - } - - @Test - public void testNativeSQLAddScalar() { - doInJPA( this::entityManagerFactory, entityManager -> { - List inets = entityManager.createNativeQuery( - "select e.ip as ip " + - "from Event e " + - "where e.id = :id" ) - .setParameter( "id", 1L ) - .unwrap( NativeQuery.class ) - .addScalar( "ip", InetType.INSTANCE ) - .getResultList(); - - assertEquals( 1, inets.size() ); - assertEquals( "192.168.0.123/24", inets.get( 0 ).getAddress() ); - } ); - } - -} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/json/PostgreSQLMultipleTypesContributorTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/json/PostgreSQLMultipleTypesContributorTest.java new file mode 100644 index 000000000000..03c3792a0a1a --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/json/PostgreSQLMultipleTypesContributorTest.java @@ -0,0 +1,152 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.id.usertype.json; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import org.hibernate.annotations.JavaType; +import org.hibernate.annotations.JdbcTypeCode; +import org.hibernate.boot.model.TypeContributions; +import org.hibernate.boot.model.TypeContributor; +import org.hibernate.orm.test.id.usertype.inet.Inet; +import org.hibernate.orm.test.id.usertype.inet.InetJavaType; +import org.hibernate.orm.test.id.usertype.inet.InetJdbcType; +import org.hibernate.orm.test.id.usertype.inet.InetType; +import org.hibernate.query.NativeQuery; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.testing.orm.junit.BootstrapServiceRegistry; +import org.hibernate.testing.orm.junit.DialectFeatureChecks; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.RequiresDialectFeature; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.type.SqlTypes; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import java.util.List; + +/** + * @author Vlad Mihalcea + */ +@SuppressWarnings("JUnitMalformedDeclaration") +@RequiresDialectFeature(feature = DialectFeatureChecks.IsPgJdbc.class) +@BootstrapServiceRegistry( javaServices = @BootstrapServiceRegistry.JavaService( + role = TypeContributor.class, + impl = PostgreSQLMultipleTypesContributorTest.TypeContributorImpl.class +) ) +@DomainModel(annotatedClasses = PostgreSQLMultipleTypesContributorTest.Event.class) +@SessionFactory +public class PostgreSQLMultipleTypesContributorTest { + + @BeforeEach + public void setUp(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (session) -> { + var event = new Event(); + event.setId( 1L ); + event.setIp( "192.168.0.123/24" ); + event.setProperties( new Json( "{\"key\": \"temp\", \"value\": \"9C\"}" ) ); + + session.persist( event ); + } ); + } + + @AfterEach + public void tearDown(SessionFactoryScope factoryScope) { + factoryScope.dropData(); + } + + @Test + public void testMultipleTypeContributions(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( entityManager -> { + //noinspection removal + var inets = entityManager.createNativeQuery( + "select e.ip " + + "from Event e " + + "where e.id = :id", Inet.class ) + .setParameter( "id", 1L ) + .getResultList(); + + Assertions.assertEquals( 1, inets.size() ); + Assertions.assertEquals( "192.168.0.123/24", inets.get( 0 ).getAddress() ); + } ); + } + + @Test + public void testMultipleTypeContributionsExplicitBinding(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( entityManager -> { + //noinspection unchecked,deprecation + List inets = entityManager.createNativeQuery( + "select e.ip " + + "from Event e " + + "where e.id = :id" ) + .setParameter( "id", 1L ) + .unwrap( NativeQuery.class ) + .addScalar( "ip", InetType.INSTANCE ) + .getResultList(); + + Assertions.assertEquals( 1, inets.size() ); + Assertions.assertEquals( "192.168.0.123/24", inets.get( 0 ).getAddress() ); + } ); + } + + @Entity(name = "Event") + @Table(name = "event") + public static class Event { + + @Id + private Long id; + + @Column(name = "ip") + @JdbcTypeCode(SqlTypes.INET) + @JavaType(InetJavaType.class) + private Inet ip; + + @Column(name = "properties") + @JdbcTypeCode(SqlTypes.JSON) + @JavaType(JsonJavaType.class) + private Json properties; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Inet getIp() { + return ip; + } + + public void setIp(String address) { + this.ip = new Inet( address ); + } + + public Json getProperties() { + return properties; + } + + public void setProperties(Json properties) { + this.properties = properties; + } + } + + public static class TypeContributorImpl implements TypeContributor { + @Override + public void contribute(TypeContributions typeContributions, ServiceRegistry serviceRegistry) { + typeContributions.contributeJavaType( InetJavaType.INSTANCE ); + typeContributions.contributeJdbcType( InetJdbcType.INSTANCE ); + + var typeConfiguration = typeContributions.getTypeConfiguration(); + typeConfiguration.getBasicTypeRegistry().register( InetType.INSTANCE ); + typeConfiguration.getBasicTypeRegistry().register( JsonType.INSTANCE ); + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/idgen/enhanced/HiloOptimizerConcurrencyTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/idgen/enhanced/HiloOptimizerConcurrencyTest.java index 605aaf907049..5e7c202433f6 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/idgen/enhanced/HiloOptimizerConcurrencyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/idgen/enhanced/HiloOptimizerConcurrencyTest.java @@ -4,257 +4,87 @@ */ package org.hibernate.orm.test.idgen.enhanced; -import java.util.Arrays; -import java.util.List; -import java.util.concurrent.Callable; -import java.util.concurrent.CopyOnWriteArrayList; -import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; - -import org.hibernate.Session; import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.Parameter; -import org.hibernate.boot.registry.StandardServiceRegistry; +import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.exception.ConstraintViolationException; - +import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.service.ServiceRegistry; import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; -import org.junit.Test; +import org.hibernate.testing.orm.transaction.TransactionUtil; +import org.hibernate.tool.schema.Action; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.fail; +import java.util.function.Consumer; + +import static org.hibernate.cfg.SchemaToolingSettings.HBM2DDL_AUTO; /** - * Demonstrates HHH-3628 issue with rolling over buckets in HiLoOptimizer. There are - * two variants of the test which do pretty much the same thing - one in sessions in - * parallel threads and one simply performing actions in sequence in two sessions. - * Possibly the threaded version is somewhat redundant given that the simpler test - * also exhibits the problem. - * * @author Richard Barnes 4 May 2016 */ @JiraKey(value = "HHH-3628") -public class HiloOptimizerConcurrencyTest extends BaseNonConfigCoreFunctionalTestCase { - - private boolean createSchema = true; - - private ExecutorService executor = Executors.newFixedThreadPool( 2 ); - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { - HibPerson.class - }; - } +public class HiloOptimizerConcurrencyTest { @Test - public void testTwoSessionsParallelGeneration() { - createSchema = true; - - StandardServiceRegistry serviceRegistry = serviceRegistry(); - SessionFactoryImplementor sessionFactory = sessionFactory(); - - try { - final Session session1 = openSession(); + public void testTwoSessionsSerialGeneration() { + inSessionFactory( true, (sf1) -> { + var session1 = sf1.openSession(); - try { - session1.beginTransaction(); - HibPerson p = new HibPerson(); + TransactionUtil.inTransaction( session1, (SessionImplementor s) -> { + var p = new HibPerson(); session1.persist( p ); - } - finally { - session1.getTransaction().commit(); - } - - createSchema = false; - buildResources(); - - final Session session2 = openSession(); - try { - session2.beginTransaction(); - HibPerson p = new HibPerson(); - session2.persist( p ); - } - finally { - session2.getTransaction().commit(); - } + } ); - final List errs = new CopyOnWriteArrayList<>(); + inSessionFactory( false, (sf2) -> { + var session2 = sf2.openSession(); - CountDownLatch firstLatch = new CountDownLatch( 1 ); - CountDownLatch secondLatch = new CountDownLatch( 1 ); + TransactionUtil.inTransaction( session2, (SessionImplementor s) -> { + var p = new HibPerson(); + session2.persist( p ); + } ); - Callable callable1 = () -> { - try { - for ( int i = 2; i < 6; i++ ) { - try { - session1.beginTransaction(); - HibPerson p = new HibPerson(); - session1.persist( p ); - } - finally { - session1.getTransaction().commit(); - } - } - firstLatch.countDown(); - secondLatch.await(); - try { - session1.beginTransaction(); - HibPerson p = new HibPerson(); + for ( int i = 2; i < 6; i++ ) { + TransactionUtil.inTransaction( session1, (SessionImplementor s) -> { + var p = new HibPerson(); session1.persist( p ); - } - finally { - session1.getTransaction().commit(); - } - } - catch (Throwable t) { - errs.add( t ); - } - - return null; - }; - - Callable callable2 = () -> { - try { - firstLatch.await(); - secondLatch.countDown(); - try { - session2.beginTransaction(); - HibPerson p = new HibPerson(); - session2.persist( p ); - } - finally { - session2.getTransaction().commit(); - } - } - catch (Throwable t) { - errs.add( t ); + } ); } - return null; - }; - - executor.invokeAll( Arrays.asList( - callable1, callable2 - ) , 30, TimeUnit.SECONDS).forEach( c -> { - try { - c.get(); - } - catch (InterruptedException|ExecutionException e) { - Thread.interrupted(); - fail(e.getMessage()); - } - }); - - for(Throwable ex : errs) { - fail(ex.getMessage()); - } - } - catch (InterruptedException e) { - fail(e.getMessage()); - } - finally { - releaseResources( serviceRegistry, sessionFactory ); - } - } + TransactionUtil.inTransaction( session2, (SessionImplementor s) -> { + var p = new HibPerson(); + session2.persist( p ); + } ); - @Test - public void testTwoSessionsSerialGeneration() { - createSchema = true; - rebuildSessionFactory(); - StandardServiceRegistry serviceRegistry = serviceRegistry(); - SessionFactoryImplementor sessionFactory = sessionFactory(); - - try { - final Session session1 = openSession(); - - try { - session1.beginTransaction(); - HibPerson p = new HibPerson(); - session1.persist( p ); - } - finally { - session1.getTransaction().commit(); - } - - createSchema = false; - buildResources(); - - final Session session2 = openSession(); - session2.beginTransaction(); - try { - HibPerson p = new HibPerson(); - session2.persist( p ); - } - finally { - session2.getTransaction().commit(); - } - - for ( int i = 2; i < 6; i++ ) { - session1.beginTransaction(); - try { - HibPerson p = new HibPerson(); + TransactionUtil.inTransaction( session1, (SessionImplementor s) -> { + var p = new HibPerson(); session1.persist( p ); - } - finally { - session1.getTransaction().commit(); - } - } - session2.beginTransaction(); - try { - HibPerson p = new HibPerson(); - session2.persist( p ); - } - finally { - session2.getTransaction().commit(); - } - session1.beginTransaction(); - try { - HibPerson p = new HibPerson(); - session1.persist( p ); - } - finally { - session1.getTransaction().commit(); - } - } - catch (ConstraintViolationException cve) { - fail( "ConstraintViolationException: " + cve.getMessage() ); - } - finally { - releaseResources( serviceRegistry, sessionFactory ); - } + } ); + } ); + } ); } - private void releaseResources(StandardServiceRegistry serviceRegistry, SessionFactoryImplementor sessionFactory) { - if ( sessionFactory != null ) { - try { - sessionFactory.close(); - } - catch (Exception e) { - fail( "Unable to release SessionFactory : " + e.getMessage() ); - } - } - - if ( serviceRegistry != null ) { - try { - StandardServiceRegistryBuilder.destroy( serviceRegistry ); - } - catch (Exception e) { - fail( "Unable to release StandardServiceRegistry : " + e.getMessage() ); + private void inSessionFactory(boolean createSchema, Consumer action) { + try (var serviceRegistry = createServiceRegistry( createSchema )) { + final MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( serviceRegistry ) + .addAnnotatedClass( HibPerson.class ) + .buildMetadata(); + try (var sessionFactory = metadata.buildSessionFactory()) { + action.accept( sessionFactory ); } } } - @Override - protected boolean createSchema() { - return createSchema; + private ServiceRegistry createServiceRegistry(boolean createSchema) { + final StandardServiceRegistryBuilder ssrb = new StandardServiceRegistryBuilder(); + if ( createSchema ) { + ssrb.applySetting( HBM2DDL_AUTO, Action.CREATE_DROP ); + } + return ssrb.build(); } @Entity(name = "HibPerson") diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/inheritance/MultipleInheritanceTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/inheritance/MultipleInheritanceTest.java index f8e07563504c..77f6e7e0427a 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/inheritance/MultipleInheritanceTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/inheritance/MultipleInheritanceTest.java @@ -16,35 +16,31 @@ import jakarta.persistence.MappedSuperclass; import jakarta.persistence.OneToMany; import jakarta.persistence.OneToOne; - import org.hibernate.annotations.NotFound; import org.hibernate.annotations.NotFoundAction; - -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.junit.Test; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Test; import java.io.Serializable; import java.util.List; import static org.junit.jupiter.api.Assertions.assertNotNull; -public class MultipleInheritanceTest extends BaseCoreFunctionalTestCase { - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { - CarOptional.class, - CarPart.class, - BasicCar.class, - SuperCar.class, - Car.class - }; - } - +@SuppressWarnings("JUnitMalformedDeclaration") +@DomainModel(annotatedClasses = { + MultipleInheritanceTest.CarOptional.class, + MultipleInheritanceTest.CarPart.class, + MultipleInheritanceTest.BasicCar.class, + MultipleInheritanceTest.SuperCar.class, + MultipleInheritanceTest.Car.class +}) +@SessionFactory +public class MultipleInheritanceTest { @Test - public void test() { - inTransaction( session -> { - + public void test(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( session -> { Car car = new Car(); CarPart carPart = new CarPart(); @@ -122,7 +118,7 @@ public static class CarOptional { private String name; @Embeddable - public class CarOptionalPK implements Serializable { + public static class CarOptionalPK implements Serializable { @Column(name = "OPTIONAL_ID1") private String id1; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/interceptor/InterceptorTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/interceptor/InterceptorTest.java index a22d1dc0f152..3cda67f507ca 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/interceptor/InterceptorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/interceptor/InterceptorTest.java @@ -6,78 +6,81 @@ import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; -import java.util.LinkedList; -import java.util.List; -import java.util.Locale; -import java.util.Queue; - -import org.junit.Test; - import org.hibernate.AssertionFailure; import org.hibernate.Interceptor; import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.TransactionException; -import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; - import org.hibernate.resource.jdbc.internal.EmptyStatementInspector; import org.hibernate.resource.jdbc.spi.StatementInspector; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; import org.hibernate.type.Type; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +import java.util.LinkedList; +import java.util.List; +import java.util.Locale; +import java.util.Queue; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertSame; -import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * @author Gavin King * @author Lukasz Antoniak */ -public class InterceptorTest extends BaseCoreFunctionalTestCase { - @Override - public String[] getMappings() { - return new String[] { "interceptor/User.hbm.xml", "interceptor/Image.hbm.xml" }; +@SuppressWarnings("JUnitMalformedDeclaration") +@DomainModel(xmlMappings = { + "org/hibernate/orm/test/interceptor/User.hbm.xml", + "org/hibernate/orm/test/interceptor/Image.hbm.xml" +}) +@SessionFactory +public class InterceptorTest { + @AfterEach + void tearDown(SessionFactoryScope factoryScope) { + factoryScope.dropData(); } @Test - public void testCollectionIntercept() { - Session s = openSession( new CollectionInterceptor() ); - Transaction t = s.beginTransaction(); - User u = new User( "Gavin", "nivag" ); - s.persist( u ); - u.setPassword( "vagni" ); - t.commit(); - s.close(); + public void testCollectionIntercept(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( + (sf) -> sf.withOptions().interceptor( new CollectionInterceptor() ).openSession(), + (s) -> { + User u = new User( "Gavin", "nivag" ); + s.persist( u ); + u.setPassword( "vagni" ); + } + ); - s = openSession(); - t = s.beginTransaction(); - u = s.get( User.class, "Gavin" ); - assertEquals( 2, u.getActions().size() ); - s.remove( u ); - t.commit(); - s.close(); + factoryScope.inTransaction( (s) -> { + var u = s.find( User.class, "Gavin" ); + Assertions.assertEquals( 2, u.getActions().size() ); + s.remove( u ); + } ); } @Test - public void testPropertyIntercept() { - Session s = openSession( new PropertyInterceptor() ); - Transaction t = s.beginTransaction(); - User u = new User( "Gavin", "nivag" ); - s.persist( u ); - u.setPassword( "vagni" ); - t.commit(); - s.close(); + public void testPropertyIntercept(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( + (sf) -> sf.withOptions().interceptor( new PropertyInterceptor() ).openSession(), + (s) -> { + User u = new User( "Gavin", "nivag" ); + s.persist( u ); + u.setPassword( "vagni" ); + } + ); - s = openSession(); - t = s.beginTransaction(); - u = s.get( User.class, "Gavin" ); - assertNotNull( u.getCreated() ); - assertNotNull( u.getLastUpdated() ); - s.remove( u ); - t.commit(); - s.close(); + factoryScope.inTransaction( (s) -> { + var u = s.find( User.class, "Gavin" ); + assertNotNull( u.getCreated() ); + assertNotNull( u.getLastUpdated() ); + s.remove( u ); + } ); } /** @@ -87,180 +90,165 @@ public void testPropertyIntercept() { */ @Test @JiraKey(value = "HHH-1921") - public void testPropertyIntercept2() { - Session s = openSession(); - Transaction t = s.beginTransaction(); - User u = new User( "Josh", "test" ); - s.persist( u ); - t.commit(); - s.close(); - - s = openSession( - new Interceptor() { - @Override - public boolean onFlushDirty( - Object entity, - Object id, - Object[] currentState, - Object[] previousState, - String[] propertyNames, - Type[] types) { - for ( int i = 0; i < propertyNames.length; i++ ) { - if ( propertyNames[i].equals( "password" ) ) { - currentState[i] = "test"; + public void testPropertyIntercept2(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( (s) -> { + User u = new User( "Josh", "test" ); + s.persist( u ); + } ); + + factoryScope.inTransaction( + (sf) -> sf.withOptions().interceptor( + new Interceptor() { + @Override + public boolean onFlushDirty( + Object entity, + Object id, + Object[] currentState, + Object[] previousState, + String[] propertyNames, + Type[] types) { + for ( int i = 0; i < propertyNames.length; i++ ) { + if ( propertyNames[i].equals( "password" ) ) { + currentState[i] = "test"; + } + } + + return true; } - } - - return true; - } + } ).openSession(), + (s) -> { + var u = s.find( User.class, "Josh" ); + u.setPassword( "nottest" ); } ); - t = s.beginTransaction(); - u = s.get( User.class, u.getName() ); - u.setPassword( "nottest" ); - t.commit(); - s.close(); - s = openSession(); - t = s.beginTransaction(); - u = s.get( User.class, "Josh" ); - assertEquals( "test", u.getPassword() ); - s.remove( u ); - t.commit(); - s.close(); + factoryScope.inTransaction( (s) -> { + var u = s.find( User.class, "Josh" ); + Assertions.assertEquals( "test", u.getPassword() ); + s.remove( u ); + } ); } @Test - public void testComponentInterceptor() { + public void testComponentInterceptor(SessionFactoryScope factoryScope) { final int checkPerm = 500; final String checkComment = "generated from interceptor"; - Session s = openSession( - new Interceptor() { - @Override - public boolean onPersist( - Object entity, - Object id, - Object[] state, - String[] propertyNames, - Type[] types) { - if ( state[0] == null ) { - Image.Details detail = new Image.Details(); - detail.setPerm1( checkPerm ); - detail.setComment( checkComment ); - state[0] = detail; + factoryScope.inTransaction( + (sf) -> sf.withOptions().interceptor( + new Interceptor() { + @Override + public boolean onPersist( + Object entity, + Object id, + Object[] state, + String[] propertyNames, + Type[] types) { + if ( state[0] == null ) { + Image.Details detail = new Image.Details(); + detail.setPerm1( checkPerm ); + detail.setComment( checkComment ); + state[0] = detail; + } + return true; + } } - return true; - } + ).openSession(), + (s) -> { + Image i = new Image(); + i.setName( "compincomp" ); + i = s.merge( i ); + assertNotNull( i.getDetails() ); + Assertions.assertEquals( checkPerm, i.getDetails().getPerm1() ); + Assertions.assertEquals( checkComment, i.getDetails().getComment() ); } ); - s.beginTransaction(); - Image i = new Image(); - i.setName( "compincomp" ); - i = (Image) s.merge( i ); - assertNotNull( i.getDetails() ); - assertEquals( checkPerm, i.getDetails().getPerm1() ); - assertEquals( checkComment, i.getDetails().getComment() ); - s.getTransaction().commit(); - s.close(); - s = openSession(); - s.beginTransaction(); - i = s.get( Image.class, i.getId() ); - assertNotNull( i.getDetails() ); - assertEquals( checkPerm, i.getDetails().getPerm1() ); - assertEquals( checkComment, i.getDetails().getComment() ); - s.remove( i ); - s.getTransaction().commit(); - s.close(); + factoryScope.inTransaction( (s) -> { + var i = s.find( Image.class, 1L ); + assertNotNull( i.getDetails() ); + Assertions.assertEquals( checkPerm, i.getDetails().getPerm1() ); + Assertions.assertEquals( checkComment, i.getDetails().getComment() ); + s.remove( i ); + } ); } @Test - public void testStatefulIntercept() { - User u = new User( "Gavin", "nivag" ); - + public void testStatefulIntercept(SessionFactoryScope factoryScope) { + final User u = new User( "Gavin", "nivag" ); final StatefulInterceptor statefulInterceptor = new StatefulInterceptor(); - try (Session s = openSession( statefulInterceptor )) { - statefulInterceptor.setSession( s ); - Transaction t = s.beginTransaction(); - try { - s.persist( u ); - u.setPassword( "vagni" ); - t.commit(); - } - catch (Exception e) { - if ( t.isActive() ) { - t.rollback(); + factoryScope.inTransaction( + (sf) -> sf.withOptions().interceptor( statefulInterceptor ).openSession(), + (s) -> { + statefulInterceptor.setSession( s ); + s.persist( u ); + u.setPassword( "vagni" ); } - throw e; - } - } + ); - inTransaction( - s -> { - CriteriaBuilder criteriaBuilder = s.getCriteriaBuilder(); - CriteriaQuery criteria = criteriaBuilder.createQuery( Log.class ); - criteria.from( Log.class ); - List logs = s.createQuery( criteria ).list(); + factoryScope.inTransaction( s -> { + CriteriaBuilder criteriaBuilder = s.getCriteriaBuilder(); + CriteriaQuery criteria = criteriaBuilder.createQuery( Log.class ); + criteria.from( Log.class ); + List logs = s.createQuery( criteria ).list(); // List logs = s.createCriteria(Log.class).list(); - assertEquals( 2, logs.size() ); - s.remove( u ); - s.createMutationQuery( "delete from Log" ).executeUpdate(); - - } - ); + Assertions.assertEquals( 2, logs.size() ); + s.remove( u ); + s.createMutationQuery( "delete from Log" ).executeUpdate(); + } ); } @Test - public void testInitiateIntercept() { + public void testInitiateIntercept(SessionFactoryScope factoryScope) { final String injectedString = "******"; final InstantiateInterceptor initiateInterceptor = new InstantiateInterceptor( injectedString ); - Session s = openSession( initiateInterceptor ); - - Transaction t = s.beginTransaction(); - User u = new User( "Gavin", "nivag" ); - s.persist( u ); - t.commit(); - s.close(); - - assertNull( u.getInjectedString() ); - u.setPassword( "blah" ); + var created = factoryScope.fromTransaction( + (sf) -> sf.withOptions().interceptor( initiateInterceptor ).openSession(), + (s) -> { + User u = new User( "Gavin", "nivag" ); + s.persist( u ); + Assertions.assertNull( u.getInjectedString() ); + return u; + } + ); - s = openSession( initiateInterceptor ); - t = s.beginTransaction(); + created.setPassword( "blah" ); - User merged = (User) s.merge( u ); - assertEquals( injectedString, merged.getInjectedString() ); - assertEquals( u.getName(), merged.getName() ); - assertEquals( u.getPassword(), merged.getPassword() ); + factoryScope.inTransaction( + (sf) -> sf.withOptions().interceptor( initiateInterceptor ).openSession(), + (s) -> { + User merged = s.merge( created ); + Assertions.assertEquals( injectedString, merged.getInjectedString() ); + Assertions.assertEquals( created.getName(), merged.getName() ); + Assertions.assertEquals( created.getPassword(), merged.getPassword() ); - merged.setInjectedString( null ); + merged.setInjectedString( null ); - User loaded = s.getReference( User.class, merged.getName() ); - // the session-bound instance was not instantiated by the interceptor, load simply returns it - assertSame( merged, loaded ); - assertNull( merged.getInjectedString() ); + User loaded = s.getReference( User.class, merged.getName() ); + // the session-bound instance was not instantiated by the interceptor, load simply returns it + Assertions.assertSame( merged, loaded ); + Assertions.assertNull( merged.getInjectedString() ); - // flush the session and evict the merged instance from session to force an actual load - s.flush(); - s.evict( merged ); + // flush the session and evict the merged instance from session to force an actual load + s.flush(); + s.evict( merged ); - User reloaded = s.getReference( User.class, merged.getName() ); - // Interceptor IS called for instantiating the persistent instance associated to the session when using load - assertEquals( injectedString, reloaded.getInjectedString() ); - assertEquals( u.getName(), reloaded.getName() ); - assertEquals( u.getPassword(), reloaded.getPassword() ); + User reloaded = s.getReference( User.class, merged.getName() ); + // Interceptor IS called for instantiating the persistent instance associated to the session when using load + Assertions.assertEquals( injectedString, reloaded.getInjectedString() ); + Assertions.assertEquals( created.getName(), reloaded.getName() ); + Assertions.assertEquals( created.getPassword(), reloaded.getPassword() ); - s.remove( reloaded ); - t.commit(); - s.close(); + s.remove( reloaded ); + } + ); } @Test @JiraKey(value = "HHH-6594") - public void testPrepareStatementIntercept() { + public void testPrepareStatementIntercept(SessionFactoryScope factoryScope) { final Queue expectedSQLs = new LinkedList<>(); // Transaction 1 expectedSQLs.add( "insert" ); @@ -281,21 +269,22 @@ public String inspect(String sql) { assertNotNull( sql ); String expectedSql = expectedSQLs.poll().toLowerCase( Locale.ROOT ); assertTrue( - "sql:\n " + sql.toLowerCase( Locale.ROOT ) + "\n doesn't start with \n" + expectedSql + "\n", - sql.toLowerCase( Locale.ROOT ).startsWith( expectedSql ) + sql.toLowerCase( Locale.ROOT ).startsWith( expectedSql ), + "sql:\n " + sql.toLowerCase( Locale.ROOT ) + "\n doesn't start with \n" + expectedSql + "\n" + ); return sql; } }; - Session s = sessionFactory().withOptions().statementInspector( statementInspector ).openSession(); + Session s = factoryScope.getSessionFactory().withOptions().statementInspector( statementInspector ).openSession(); Transaction t = s.beginTransaction(); User u = new User( "Lukasz", "Antoniak" ); s.persist( u ); t.commit(); s.close(); - s = sessionFactory().withOptions().statementInspector( statementInspector ).openSession(); + s = factoryScope.getSessionFactory().withOptions().statementInspector( statementInspector ).openSession(); t = s.beginTransaction(); s.get( User.class, "Lukasz" ); s.createQuery( "from User u" ).list(); @@ -303,13 +292,13 @@ public String inspect(String sql) { s.close(); u.setPassword( "Kinga" ); - s = sessionFactory().withOptions().statementInspector( statementInspector ).openSession(); + s = factoryScope.getSessionFactory().withOptions().statementInspector( statementInspector ).openSession(); t = s.beginTransaction(); s.merge( u ); t.commit(); s.close(); - s = sessionFactory().withOptions().statementInspector( statementInspector ).openSession(); + s = factoryScope.getSessionFactory().withOptions().statementInspector( statementInspector ).openSession(); t = s.beginTransaction(); s.remove( u ); t.commit(); @@ -318,7 +307,8 @@ public String inspect(String sql) { assertTrue( expectedSQLs.isEmpty() ); } - public void testPrepareStatementFaultIntercept() { + @Test + public void testPrepareStatementFaultIntercept(SessionFactoryScope factoryScope) { final StatementInspector statementInspector = new EmptyStatementInspector() { @Override public String inspect(String sql) { @@ -326,19 +316,19 @@ public String inspect(String sql) { } }; - Session s = sessionFactory().withOptions().statementInspector( statementInspector ).openSession(); - try { - - Transaction t = s.beginTransaction(); - User u = new User( "Kinga", "Mroz" ); - s.persist( u ); - t.commit(); - } - catch (TransactionException e) { - assertTrue( e.getCause() instanceof AssertionFailure ); - } - finally { - s.close(); + try (var s = factoryScope.getSessionFactory().withOptions().statementInspector( statementInspector ).openSession()) { + try { + Transaction t = s.beginTransaction(); + User u = new User( "Kinga", "Mroz" ); + s.persist( u ); + t.commit(); + } + catch (TransactionException e) { + Assertions.assertInstanceOf( AssertionFailure.class, e.getCause() ); + } + finally { + s.close(); + } } } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/interceptor/InterceptorTransactionEventTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/interceptor/InterceptorTransactionEventTest.java index 38ae79968ecc..9562e5c482af 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/interceptor/InterceptorTransactionEventTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/interceptor/InterceptorTransactionEventTest.java @@ -5,31 +5,35 @@ package org.hibernate.orm.test.interceptor; import org.hibernate.Interceptor; -import org.hibernate.Session; import org.hibernate.Transaction; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.junit.Test; - -import static org.junit.Assert.assertTrue; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; /** * Tests, whether {@link Interceptor} gets the transaction events */ -public class InterceptorTransactionEventTest extends BaseCoreFunctionalTestCase { +@SuppressWarnings("JUnitMalformedDeclaration") +@SessionFactory +public class InterceptorTransactionEventTest { @Test - public void testTransactionEvents() { + public void testTransactionEvents(SessionFactoryScope factoryScope) { LoggingInterceptor interceptor = new LoggingInterceptor(); - Session s = openSession(interceptor); - Transaction tx = s.beginTransaction(); - // Do nothing, open and closing the transaction is enough - tx.commit(); - s.close(); + factoryScope.inTransaction( + (sf) -> sf.withOptions().interceptor( interceptor ).openSession(), + (s) -> { + // Do nothing, open and closing the transaction is enough + } + ); - assertTrue("afterTransactionBeginCalled not called", interceptor.isAfterTransactionBeginCalled()); - assertTrue("afterTransactionCompletionCalled not called", interceptor.isAfterTransactionCompletionCalled()); - assertTrue("beforeTransactionCompletionCalled not called", interceptor.isBeforeTransactionCompletionCalled()); + Assertions.assertTrue( interceptor.isAfterTransactionBeginCalled(), "afterTransactionBeginCalled not called" ); + Assertions.assertTrue( interceptor.isAfterTransactionCompletionCalled(), + "afterTransactionCompletionCalled not called" ); + Assertions.assertTrue( interceptor.isBeforeTransactionCompletionCalled(), + "beforeTransactionCompletionCalled not called" ); } private static class LoggingInterceptor implements Interceptor { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/nulliteral/NullLiteralExpression.java b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/nulliteral/NullLiteralExpression.java index 5911237b6e9f..7e2ac919b2bc 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/nulliteral/NullLiteralExpression.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/jpa/criteria/nulliteral/NullLiteralExpression.java @@ -4,30 +4,24 @@ */ package org.hibernate.orm.test.jpa.criteria.nulliteral; -import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase; - -import org.hibernate.testing.orm.junit.Jira; -import org.junit.Test; - import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaUpdate; - -import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.Jira; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Test; /** * @author Andrea Boriero */ -public class NullLiteralExpression extends BaseEntityManagerFunctionalTestCase { - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { Person.class, Subject.class }; - } - +@DomainModel(annotatedClasses = { Person.class, Subject.class }) +@SessionFactory +public class NullLiteralExpression { @Test @Jira( "https://hibernate.atlassian.net/browse/HHH-11159" ) - public void testNullLiteralExpressionInCriteriaUpdate() { - doInJPA( this::entityManagerFactory, entityManager -> { + public void testNullLiteralExpressionInCriteriaUpdate(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( entityManager -> { CriteriaBuilder builder = entityManager.getCriteriaBuilder(); CriteriaUpdate criteriaUpdate = builder.createCriteriaUpdate( Person.class ); criteriaUpdate.from( Person.class ); @@ -38,8 +32,8 @@ public void testNullLiteralExpressionInCriteriaUpdate() { @Test @Jira( "https://hibernate.atlassian.net/browse/HHH-16803" ) - public void testEnumNullLiteralUpdate() { - doInJPA( this::entityManagerFactory, entityManager -> { + public void testEnumNullLiteralUpdate(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( entityManager -> { final CriteriaBuilder builder = entityManager.getCriteriaBuilder(); final CriteriaUpdate criteriaUpdate = builder.createCriteriaUpdate( Person.class ); criteriaUpdate.from( Person.class ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/locking/warning/LockNoneWarningTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/locking/warning/LockNoneWarningTest.java index b3563603369d..15515e076fe3 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/locking/warning/LockNoneWarningTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/locking/warning/LockNoneWarningTest.java @@ -15,68 +15,64 @@ import jakarta.persistence.OneToMany; import jakarta.persistence.Table; -import org.hibernate.Session; -import org.hibernate.query.Query; +import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.hibernate.testing.logger.LoggerInspectionRule; -import org.hibernate.testing.logger.Triggerable; -import org.hibernate.testing.transaction.TransactionUtil; -import org.junit.After; -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; +import org.hibernate.testing.orm.junit.Logger; +import org.hibernate.testing.orm.junit.LoggingInspections; +import org.hibernate.testing.orm.junit.LoggingInspectionsScope; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import static jakarta.persistence.LockModeType.NONE; -import static org.hibernate.internal.CoreMessageLogger.CORE_LOGGER; -import static org.junit.Assert.assertFalse; /** * @author Andrea Boriero */ +@SuppressWarnings("JUnitMalformedDeclaration") @JiraKey(value = "HHH-10513") -public class LockNoneWarningTest extends BaseCoreFunctionalTestCase { - - private Triggerable triggerable; - - @Rule - public LoggerInspectionRule logInspection = new LoggerInspectionRule( CORE_LOGGER ); - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] {Item.class, Bid.class}; - } - - @Before - public void setUp() { - buildSessionFactory(); - final Set messagesPrefixes = new HashSet<>(); - messagesPrefixes.add( "HHH000444" ); - messagesPrefixes.add( "HHH000445" ); - triggerable = logInspection.watchForLogMessages( messagesPrefixes ); - TransactionUtil.doInHibernate( this::sessionFactory, session -> { +@LoggingInspections(messages = { + @LoggingInspections.Message( + messageKey = "HHH000444", + loggers = @Logger(loggerName = CoreMessageLogger.NAME) + ), + @LoggingInspections.Message( + messageKey = "HHH000445", + loggers = @Logger(loggerName = CoreMessageLogger.NAME) + ) +}) +@DomainModel(annotatedClasses = {LockNoneWarningTest.Item.class, LockNoneWarningTest.Bid.class}) +@SessionFactory +public class LockNoneWarningTest { + @BeforeEach + void setUp(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( session -> { Item item = new Item(); item.name = "ZZZZ"; session.persist( item ); } ); } - @After - public void tearDown(){ - releaseSessionFactory(); - triggerable.reset(); + @AfterEach + void tearDown(SessionFactoryScope factoryScope) { + factoryScope.dropData(); } + /// Test that no warning is triggered when [#NONE] is used with follow-on locking @Test - public void testQuerySetLockModeNONEDoNotLogAWarnMessageWhenTheDialectUseFollowOnLockingIsTrue() { - try (Session s = openSession();) { - final Query query = s.createQuery( "from Item i join i.bids b where name = :name", Object[].class ); - query.setParameter( "name", "ZZZZ" ); - query.setLockMode( NONE ); - query.list(); - assertFalse( "Log message was not triggered", triggerable.wasTriggered() ); - } + public void testIt(SessionFactoryScope factoryScope, LoggingInspectionsScope loggingScope) { + factoryScope.inTransaction( (s) -> { + s.createQuery( "from Item i join i.bids b where name = :name", Object[].class ) + .setParameter( "name", "ZZZZ" ) + .setLockMode( NONE ) + .list(); + Assertions.assertFalse( loggingScope.wereAnyTriggered(), "Log message was unexpectedly triggered" ); + } ); } @Entity(name = "Item") diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/ConnectionsReleaseTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/ConnectionsReleaseTest.java index 3fbde03955f2..c9da835c51c0 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/ConnectionsReleaseTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/ConnectionsReleaseTest.java @@ -4,29 +4,27 @@ */ package org.hibernate.orm.test.schemaupdate; -import java.util.EnumSet; import jakarta.persistence.Entity; import jakarta.persistence.Id; import jakarta.persistence.Table; - -import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.dialect.H2Dialect; -import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; +import org.hibernate.testing.jdbc.SharedDriverManagerConnectionProvider; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.hibernate.testing.orm.junit.ServiceRegistryFunctionalTesting; +import org.hibernate.testing.orm.junit.ServiceRegistryProducer; import org.hibernate.tool.hbm2ddl.SchemaUpdate; import org.hibernate.tool.hbm2ddl.SchemaValidator; import org.hibernate.tool.schema.TargetType; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; -import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.jdbc.SharedDriverManagerConnectionProvider; -import org.hibernate.testing.junit4.BaseUnitTestCase; -import org.hibernate.testing.orm.junit.RequiresDialect; -import org.hibernate.testing.util.ServiceRegistryUtil; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import java.util.EnumSet; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; @@ -34,43 +32,32 @@ /** * @author Andrea Boriero */ +@SuppressWarnings("JUnitMalformedDeclaration") @JiraKey(value = "HHH-10443") @RequiresDialect( H2Dialect.class ) -public class ConnectionsReleaseTest extends BaseUnitTestCase { - - private StandardServiceRegistry ssr; - private MetadataImplementor metadata; - private SharedDriverManagerConnectionProvider connectionProvider; - - @Before - public void setUp() { - connectionProvider = SharedDriverManagerConnectionProvider.getInstance(); - - ssr = ServiceRegistryUtil.serviceRegistryBuilder() - .addService( ConnectionProvider.class, connectionProvider ) - .build(); - metadata = (MetadataImplementor) new MetadataSources( ssr ) - .addAnnotatedClass( Thing.class ) - .buildMetadata(); - metadata.orderColumns( false ); - metadata.validate(); - } +@ServiceRegistryFunctionalTesting +@DomainModel(annotatedClasses = ConnectionsReleaseTest.Thing.class) +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class ConnectionsReleaseTest implements ServiceRegistryProducer { - @After - public void tearDown() { - StandardServiceRegistryBuilder.destroy( ssr ); + @BeforeAll + static void beforeAll(DomainModelScope modelScope) { + modelScope.getDomainModel().orderColumns( false ); + modelScope.getDomainModel().validate(); } @Test - public void testSchemaUpdateReleasesAllConnections() { - new SchemaUpdate().execute( EnumSet.of( TargetType.DATABASE ), metadata ); - assertThat( connectionProvider.getOpenConnections(), is( 0 ) ); + @Order(1) + public void testSchemaUpdateReleasesAllConnections(DomainModelScope modelScope) { + new SchemaUpdate().execute( EnumSet.of( TargetType.DATABASE ), modelScope.getDomainModel() ); + assertThat( SharedDriverManagerConnectionProvider.getInstance().getOpenConnections(), is( 0 ) ); } @Test - public void testSchemaValidatorReleasesAllConnections() { - new SchemaValidator().validate( metadata ); - assertThat( connectionProvider.getOpenConnections(), is( 0 ) ); + @Order(2) + public void testSchemaValidatorReleasesAllConnections(DomainModelScope modelScope) { + new SchemaValidator().validate( modelScope.getDomainModel() ); + assertThat( SharedDriverManagerConnectionProvider.getInstance().getOpenConnections(), is( 0 ) ); } @Entity(name = "Thing") diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/HANASchemaMigrationTargetScriptCreationTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/HANASchemaMigrationTargetScriptCreationTest.java index 2c126b80968e..492562675055 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/HANASchemaMigrationTargetScriptCreationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/HANASchemaMigrationTargetScriptCreationTest.java @@ -8,176 +8,225 @@ import jakarta.persistence.Id; import jakarta.persistence.Lob; import jakarta.persistence.Table; +import org.hamcrest.MatcherAssert; +import org.hibernate.boot.registry.StandardServiceRegistry; +import org.hibernate.dialect.HANADialect; +import org.hibernate.engine.config.spi.ConfigurationService; +import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; +import org.hibernate.testing.orm.junit.DialectContext; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.ServiceRegistryScope; +import org.hibernate.testing.orm.junit.Setting; +import org.hibernate.tool.schema.internal.ExceptionHandlerHaltImpl; +import org.hibernate.tool.schema.internal.SchemaCreatorImpl; +import org.hibernate.tool.schema.internal.exec.GenerationTargetToScript; +import org.hibernate.tool.schema.internal.exec.ScriptTargetOutputToFile; +import org.hibernate.tool.schema.spi.ExceptionHandler; +import org.hibernate.tool.schema.spi.ExecutionOptions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + import java.io.File; -import java.io.IOException; import java.nio.file.Files; -import java.util.EnumSet; +import java.util.Map; +import java.util.function.Consumer; import java.util.regex.Matcher; import java.util.regex.Pattern; -import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.spi.MetadataImplementor; -import org.hibernate.cfg.Configuration; -import org.hibernate.cfg.Environment; -import org.hibernate.dialect.HANADialect; -import org.hibernate.dialect.Dialect; -import org.hibernate.service.ServiceRegistry; -import org.hibernate.tool.hbm2ddl.SchemaExport; -import org.hibernate.tool.schema.TargetType; - -import org.junit.After; -import org.junit.Test; -import org.hibernate.testing.RequiresDialect; -import org.hibernate.testing.ServiceRegistryBuilder; -import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; - import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.fail; /** * @author Jonathan Bregler */ -@RequiresDialect(value = HANADialect.class) -public class HANASchemaMigrationTargetScriptCreationTest extends BaseCoreFunctionalTestCase { - - private File output; +@SuppressWarnings("JUnitMalformedDeclaration") +@RequiresDialect(HANADialect.class) +public class HANASchemaMigrationTargetScriptCreationTest { private String varcharType; private String clobType; - @Override - protected Class[] getAnnotatedClasses() { - return new Class[]{ TestEntity.class }; + @BeforeEach + void setUp() { + final HANADialect dialect = (HANADialect) DialectContext.getDialect(); + this.varcharType = dialect.isUseUnicodeStringTypes() ? "nvarchar" : "varchar"; + this.clobType = dialect.isUseUnicodeStringTypes() ? "nclob" : "clob"; } - @Override - protected boolean createSchema() { - return false; - } + @Test + @JiraKey(value = "HHH-12302") + @ServiceRegistry + @DomainModel(annotatedClasses = HANASchemaMigrationTargetScriptCreationTest.TestEntity.class) + public void testTargetScriptIsCreatedStringTypeDefault( + ServiceRegistryScope registryScope, + DomainModelScope modelScope, + @TempDir File tmpDir) throws Exception { + var scriptFile = new File( tmpDir, "script.sql" ); - @Override - protected void configure(Configuration configuration) { - try { - this.output = File.createTempFile( "update_script", ".sql" ); - } - catch (IOException e) { - fail( e.getMessage() ); - } - this.output.deleteOnExit(); - configuration.setProperty( Environment.JAKARTA_HBM2DDL_SCRIPTS_ACTION, "create" ); - configuration.setProperty( Environment.JAKARTA_HBM2DDL_SCRIPTS_CREATE_TARGET, this.output.getAbsolutePath() ); + exportToScriptFile( registryScope, null, modelScope, scriptFile ); + + String fileContent = new String( Files.readAllBytes( scriptFile.toPath() ) ); + Pattern fileContentPattern = Pattern.compile( "create( (column|row))? table test_entity \\(b boolean[^,]+, c " + this.varcharType + "[^,]+, field " + this.varcharType + "[^,]+, lob " + this.clobType ); + Matcher fileContentMatcher = fileContentPattern.matcher( fileContent.toLowerCase() ); + MatcherAssert.assertThat( "Script file : " + fileContent.toLowerCase(), + fileContentMatcher.find(), + is( true ) ); } - @Override - protected void afterSessionFactoryBuilt() { - super.afterSessionFactoryBuilt(); - final Dialect dialect = sessionFactory().getJdbcServices().getDialect(); - this.varcharType = ( (HANADialect) dialect ).isUseUnicodeStringTypes() ? "nvarchar" : "varchar"; - this.clobType = ( (HANADialect) dialect ).isUseUnicodeStringTypes() ? "nclob" : "clob"; + private void exportToScriptFile( + ServiceRegistryScope registryScope, + Consumer> configurer, + DomainModelScope modelScope, + File scriptFile) { + var schemaCreator = new SchemaCreatorImpl( registryScope.getRegistry() ); + schemaCreator.createFromMetadata( + modelScope.getDomainModel(), + executionOptions( registryScope.getRegistry(), configurer ), + registryScope.getRegistry().requireService( JdbcEnvironment.class ).getDialect(), + source -> source, + new GenerationTargetToScript( new ScriptTargetOutputToFile( scriptFile, "utf8" ), ";" ) + ); } - @After - public void tearDown() { - ServiceRegistry serviceRegistry = ServiceRegistryBuilder.buildServiceRegistry( Environment.getProperties() ); - try { - MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( serviceRegistry ) - .addAnnotatedClass( TestEntity.class ) - .buildMetadata(); - metadata.orderColumns( false ); - metadata.validate(); - - new SchemaExport().drop( EnumSet.of( TargetType.DATABASE, TargetType.STDOUT ), metadata ); + private ExecutionOptions executionOptions( + StandardServiceRegistry registry, + Consumer> configurer) { + final Map settings = registry.requireService( ConfigurationService.class ).getSettings(); + if ( configurer != null ) { + configurer.accept( settings ); } - finally { - ServiceRegistryBuilder.destroy( serviceRegistry ); - } - } - @Test - @JiraKey(value = "HHH-12302") - public void testTargetScriptIsCreatedStringTypeDefault() throws Exception { - this.rebuildSessionFactory(); - String fileContent = new String( Files.readAllBytes( this.output.toPath() ) ); - Pattern fileContentPattern = Pattern.compile( "create( (column|row))? table test_entity \\(b boolean[^,]+, c " + this.varcharType + "[^,]+, field " + this.varcharType + "[^,]+, lob " + this.clobType ); - Matcher fileContentMatcher = fileContentPattern.matcher( fileContent.toLowerCase() ); - assertThat( - "Script file : " + fileContent.toLowerCase(), - fileContentMatcher.find(), - is( true ) ); + return new ExecutionOptions() { + @Override + public Map getConfigurationValues() { + return settings; + } + + @Override + public boolean shouldManageNamespaces() { + return false; + } + + @Override + public ExceptionHandler getExceptionHandler() { + return ExceptionHandlerHaltImpl.INSTANCE; + } + }; } @Test @JiraKey(value = "HHH-12302") - public void testTargetScriptIsCreatedStringTypeNVarchar() throws Exception { - this.rebuildSessionFactory( config -> { - config.setProperty( "hibernate.dialect.hana.use_unicode_string_types", "true" ); - } ); - String fileContent = new String( Files.readAllBytes( this.output.toPath() ) ); + @ServiceRegistry(settings = { + @Setting(name = "hibernate.dialect.hana.use_unicode_string_types", value = "true") + }) + @DomainModel(annotatedClasses = HANASchemaMigrationTargetScriptCreationTest.TestEntity.class) + public void testTargetScriptIsCreatedStringTypeNVarchar( + ServiceRegistryScope registryScope, + DomainModelScope modelScope, + @TempDir File tmpDir) throws Exception { + var scriptFile = new File( tmpDir, "script.sql" ); + + exportToScriptFile( + registryScope, + (settingsMap) -> { + settingsMap.put( "hibernate.dialect.hana.use_unicode_string_types", true ); + }, + modelScope, + scriptFile + ); + + String fileContent = new String( Files.readAllBytes( scriptFile.toPath() ) ); Pattern fileContentPattern = Pattern.compile( "create( (column|row))? table test_entity \\(b boolean[^,]+, c nvarchar[^,]+, field nvarchar[^,]+, lob nclob" ); Matcher fileContentMatcher = fileContentPattern.matcher( fileContent.toLowerCase() ); - assertThat( - "Script file : " + fileContent.toLowerCase(), - fileContentMatcher.find(), - is( true ) ); + MatcherAssert.assertThat( "Script file : " + fileContent.toLowerCase(), fileContentMatcher.find(), is( true ) ); } @Test @JiraKey(value = "HHH-12302") - public void testTargetScriptIsCreatedStringTypeVarchar() throws Exception { - this.rebuildSessionFactory( config -> { - config.setProperty( "hibernate.dialect.hana.use_unicode_string_types", "false" ); - } ); - String fileContent = new String( Files.readAllBytes( this.output.toPath() ) ); + public void testTargetScriptIsCreatedStringTypeVarchar( + ServiceRegistryScope registryScope, + DomainModelScope modelScope, + @TempDir File tmpDir) throws Exception { + var scriptFile = new File( tmpDir, "script.sql" ); + + exportToScriptFile( + registryScope, + (settingsMap) -> { + settingsMap.put( "hibernate.dialect.hana.use_unicode_string_types", false ); + }, + modelScope, + scriptFile + ); + + String fileContent = new String( Files.readAllBytes( scriptFile.toPath() ) ); Pattern fileContentPattern = Pattern.compile( "create( (column|row))? table test_entity \\(b boolean[^,]+, c " + this.varcharType + "[^,]+, field " + this.varcharType + "[^,]+, lob " + this.clobType ); Matcher fileContentMatcher = fileContentPattern.matcher( fileContent.toLowerCase() ); - assertThat( - "Script file : " + fileContent.toLowerCase(), - fileContentMatcher.find(), - is( true ) ); + MatcherAssert.assertThat( "Script file : " + fileContent.toLowerCase(), fileContentMatcher.find(), is( true ) ); } @Test @JiraKey(value = "HHH-12132") - public void testTargetScriptIsCreatedBooleanTypeDefault() throws Exception { - this.rebuildSessionFactory(); - String fileContent = new String( Files.readAllBytes( this.output.toPath() ) ); + public void testTargetScriptIsCreatedBooleanTypeDefault( + ServiceRegistryScope registryScope, + DomainModelScope modelScope, + @TempDir File tmpDir) throws Exception { + var scriptFile = new File( tmpDir, "script.sql" ); + + exportToScriptFile( registryScope, null, modelScope, scriptFile ); + + String fileContent = new String( Files.readAllBytes( scriptFile.toPath() ) ); Pattern fileContentPattern = Pattern.compile( "create( (column|row))? table test_entity \\(b boolean[^,]+, c " + this.varcharType + "[^,]+, field " + this.varcharType + "[^,]+, lob " + this.clobType ); Matcher fileContentMatcher = fileContentPattern.matcher( fileContent.toLowerCase() ); - assertThat( - "Script file : " + fileContent.toLowerCase(), - fileContentMatcher.find(), - is( true ) ); + MatcherAssert.assertThat( "Script file : " + fileContent.toLowerCase(), fileContentMatcher.find(), is( true ) ); } @Test @JiraKey(value = "HHH-12132") - public void testTargetScriptIsCreatedBooleanTypeLegacy() throws Exception { - this.rebuildSessionFactory( config -> { - config.setProperty( "hibernate.dialect.hana.use_legacy_boolean_type", "true" ); - } ); - String fileContent = new String( Files.readAllBytes( this.output.toPath() ) ); + public void testTargetScriptIsCreatedBooleanTypeLegacy( + ServiceRegistryScope registryScope, + DomainModelScope modelScope, + @TempDir File tmpDir) throws Exception { + var scriptFile = new File( tmpDir, "script.sql" ); + + exportToScriptFile( + registryScope, + (settingsMap) -> { + settingsMap.put( "hibernate.dialect.hana.use_legacy_boolean_type", true ); + }, + modelScope, + scriptFile + ); + + String fileContent = new String( Files.readAllBytes( scriptFile.toPath() ) ); Pattern fileContentPattern = Pattern.compile( "create( (column|row))? table test_entity \\(b tinyint[^,]+, c " + this.varcharType + "[^,]+, field " + this.varcharType + "[^,]+, lob " + this.clobType ); Matcher fileContentMatcher = fileContentPattern.matcher( fileContent.toLowerCase() ); - assertThat( - "Script file : " + fileContent.toLowerCase(), - fileContentMatcher.find(), - is( true ) ); + MatcherAssert.assertThat( "Script file : " + fileContent.toLowerCase(), fileContentMatcher.find(), is( true ) ); } @Test @JiraKey(value = "HHH-12132") - public void testTargetScriptIsCreatedBooleanType() throws Exception { - this.rebuildSessionFactory( config -> { - config.setProperty( "hibernate.dialect.hana.use_legacy_boolean_type", "false" ); - } ); - String fileContent = new String( Files.readAllBytes( this.output.toPath() ) ); + public void testTargetScriptIsCreatedBooleanType( + ServiceRegistryScope registryScope, + DomainModelScope modelScope, + @TempDir File tmpDir) throws Exception { + var scriptFile = new File( tmpDir, "script.sql" ); + + exportToScriptFile( + registryScope, + (settingsMap) -> { + settingsMap.put( "hibernate.dialect.hana.use_legacy_boolean_type", false ); + }, + modelScope, + scriptFile + ); + + String fileContent = new String( Files.readAllBytes( scriptFile.toPath() ) ); Pattern fileContentPattern = Pattern.compile( "create( (column|row))? table test_entity \\(b boolean[^,]+, c " + this.varcharType + "[^,]+, field " + this.varcharType + "[^,]+, lob " + this.clobType ); Matcher fileContentMatcher = fileContentPattern.matcher( fileContent.toLowerCase() ); - assertThat( - "Script file : " + fileContent.toLowerCase(), - fileContentMatcher.find(), - is( true ) ); + MatcherAssert.assertThat( "Script file : " + fileContent.toLowerCase(), fileContentMatcher.find(), is( true ) ); } @Entity diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/MixedFieldPropertyAnnotationTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/MixedFieldPropertyAnnotationTest.java index 3e5759678c7b..a54f4308ca82 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/MixedFieldPropertyAnnotationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/MixedFieldPropertyAnnotationTest.java @@ -8,41 +8,55 @@ import jakarta.persistence.Entity; import jakarta.persistence.Id; import jakarta.persistence.Table; -import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.boot.spi.MetadataImplementor; -import org.hibernate.cfg.Environment; import org.hibernate.dialect.MySQLDialect; -import org.hibernate.service.ServiceRegistry; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; import org.hibernate.testing.orm.junit.JiraKey; import org.hibernate.testing.orm.junit.RequiresDialect; -import org.hibernate.testing.util.ServiceRegistryUtil; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.Setting; import org.hibernate.tool.hbm2ddl.SchemaExport; import org.hibernate.tool.hbm2ddl.SchemaUpdate; import org.hibernate.tool.schema.TargetType; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.util.EnumSet; +import static org.hibernate.cfg.MappingSettings.GLOBALLY_QUOTED_IDENTIFIERS; + /** * @author Andrea Boriero */ +@SuppressWarnings("JUnitMalformedDeclaration") @JiraKey(value = "HHH-9849") @RequiresDialect(MySQLDialect.class) +@ServiceRegistry(settings = @Setting(name = GLOBALLY_QUOTED_IDENTIFIERS, value = "false")) +@DomainModel(annotatedClasses = MixedFieldPropertyAnnotationTest.MyEntity.class) public class MixedFieldPropertyAnnotationTest { - protected ServiceRegistry serviceRegistry; - protected MetadataImplementor metadata; + @BeforeEach + void setUp(DomainModelScope modelScope) { + System.out.println( "********* Starting SchemaExport for START-UP *************************" ); + new SchemaExport().create( EnumSet.of( TargetType.STDOUT, TargetType.DATABASE ), modelScope.getDomainModel() ); + System.out.println( "********* Completed SchemaExport for START-UP *************************" ); + } @Test - public void testUpdateSchema() { - new SchemaUpdate().execute( EnumSet.of( TargetType.STDOUT, TargetType.DATABASE ), metadata ); + public void testUpdateSchema(DomainModelScope modelScope) { + new SchemaUpdate().execute( EnumSet.of( TargetType.STDOUT, TargetType.DATABASE ), modelScope.getDomainModel() ); + } + + @AfterEach + public void tearDown(DomainModelScope modelScope) { + System.out.println( "********* Starting SchemaExport (drop) for TEAR-DOWN *************************" ); + new SchemaExport().drop( EnumSet.of( TargetType.STDOUT, TargetType.DATABASE ), modelScope.getDomainModel() ); + System.out.println( "********* Completed SchemaExport (drop) for TEAR-DOWN *************************" ); } @Entity @Table(name = "MyEntity") - class MyEntity { + public static class MyEntity { @Id public int getId() { @@ -61,27 +75,4 @@ public void setValue(int value) { } } - @Before - public void setUp() { - serviceRegistry = ServiceRegistryUtil.serviceRegistryBuilder() - .applySetting( Environment.GLOBALLY_QUOTED_IDENTIFIERS, "false" ) - .build(); - metadata = (MetadataImplementor) new MetadataSources( serviceRegistry ) - .addAnnotatedClass( MyEntity.class ) - .buildMetadata(); - - System.out.println( "********* Starting SchemaExport for START-UP *************************" ); - new SchemaExport().create( EnumSet.of( TargetType.STDOUT, TargetType.DATABASE ), metadata ); - System.out.println( "********* Completed SchemaExport for START-UP *************************" ); - } - - @After - public void tearDown() { - System.out.println( "********* Starting SchemaExport (drop) for TEAR-DOWN *************************" ); - new SchemaExport().drop( EnumSet.of( TargetType.STDOUT, TargetType.DATABASE ), metadata ); - System.out.println( "********* Completed SchemaExport (drop) for TEAR-DOWN *************************" ); - - StandardServiceRegistryBuilder.destroy( serviceRegistry ); - serviceRegistry = null; - } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/derivedid/ColumnLengthTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/derivedid/ColumnLengthTest.java index 67db3f941647..0397e5d1deea 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/derivedid/ColumnLengthTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/derivedid/ColumnLengthTest.java @@ -4,11 +4,6 @@ */ package org.hibernate.orm.test.schemaupdate.derivedid; -import java.io.File; -import java.io.Serializable; -import java.nio.file.Files; -import java.util.EnumSet; -import java.util.List; import jakarta.persistence.Column; import jakarta.persistence.Embeddable; import jakarta.persistence.EmbeddedId; @@ -17,68 +12,57 @@ import jakarta.persistence.ManyToOne; import jakarta.persistence.MapsId; import jakarta.persistence.Table; - -import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.boot.spi.MetadataImplementor; -import org.hibernate.cfg.Environment; import org.hibernate.dialect.H2Dialect; +import org.hibernate.testing.orm.junit.BaseUnitTest; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.Setting; import org.hibernate.tool.hbm2ddl.SchemaExport; import org.hibernate.tool.schema.TargetType; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; -import org.hibernate.testing.RequiresDialect; -import org.hibernate.testing.junit4.BaseUnitTestCase; -import org.hibernate.testing.util.ServiceRegistryUtil; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import java.io.File; +import java.io.Serializable; +import java.nio.file.Files; +import java.util.EnumSet; +import java.util.List; -import static org.junit.Assert.assertTrue; +import static org.hibernate.cfg.SchemaToolingSettings.HBM2DDL_AUTO; /** * @author Andrea Boriero */ +@SuppressWarnings("JUnitMalformedDeclaration") @RequiresDialect(H2Dialect.class) -public class ColumnLengthTest extends BaseUnitTestCase { - - private StandardServiceRegistry ssr; - private File outputFile; - private MetadataImplementor metadata; +@BaseUnitTest +@ServiceRegistry(settings = @Setting(name = HBM2DDL_AUTO, value = "none")) +@DomainModel(annotatedClasses = { + ColumnLengthTest.Employee.class, + ColumnLengthTest.Dependent.class +}) +public class ColumnLengthTest { - @Before - public void setUp() throws Exception { - outputFile = File.createTempFile( "update_script", ".sql" ); - outputFile.deleteOnExit(); - - ssr = ServiceRegistryUtil.serviceRegistryBuilder() - .applySetting( Environment.HBM2DDL_AUTO, "none" ) - .build(); + @Test + public void testColumnLengthsAreApplied(DomainModelScope modelScope, @TempDir File tempDir) throws Exception { + final var scriptFile = new File( tempDir, "update_script.sql" ); - metadata = (MetadataImplementor) new MetadataSources( ssr ) - .addAnnotatedClass( Employee.class ) - .addAnnotatedClass( Dependent.class ) - .buildMetadata(); + final var metadata = modelScope.getDomainModel(); metadata.orderColumns( true ); metadata.validate(); - } - - @After - public void tearDown() { - StandardServiceRegistryBuilder.destroy( ssr ); - } - @Test - public void testTheColumnsLenghtAreApplied() throws Exception { new SchemaExport() - .setOutputFile( outputFile.getAbsolutePath() ) + .setOutputFile( scriptFile.getAbsolutePath() ) .setDelimiter( ";" ) .setFormat( false ) .createOnly( EnumSet.of( TargetType.SCRIPT ), metadata ); - List commands = Files.readAllLines( outputFile.toPath() ); + final var commands = Files.readAllLines( scriptFile.toPath() ); - assertTrue( checkCommandIsGenerated( + Assertions.assertTrue( checkCommandIsGenerated( commands, "create table DEPENDENT (FK2 varchar(10) not null, FK1 varchar(32) not null, name varchar(255) not null, primary key (FK1, FK2, name));" ) ); @@ -94,27 +78,31 @@ boolean checkCommandIsGenerated(List generatedCommands, String toCheck) return false; } + @SuppressWarnings("unused") @Embeddable - public class EmployeeId implements Serializable { + public static class EmployeeId implements Serializable { @Column(name = "first_name", length = 32) String firstName; @Column(name = "last_name", length = 10) String lastName; } + @SuppressWarnings("unused") @Entity - @Table(name = "EMLOYEE") + @Table(name = "EMPLOYEE") public static class Employee { @EmbeddedId EmployeeId id; } + @SuppressWarnings("unused") @Embeddable - public class DependentId implements Serializable { + public static class DependentId implements Serializable { String name; EmployeeId empPK; } + @SuppressWarnings("unused") @Entity @Table(name = "DEPENDENT") public static class Dependent { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/ForeignKeyDropTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/ForeignKeyDropTest.java index 2ab6b7398018..23217ea2e9ad 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/ForeignKeyDropTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/ForeignKeyDropTest.java @@ -4,112 +4,100 @@ */ package org.hibernate.orm.test.schemaupdate.foreignkeys; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.util.EnumSet; -import java.util.List; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import jakarta.persistence.Entity; import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.OneToMany; import jakarta.persistence.Table; - -import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.boot.spi.MetadataImplementor; -import org.hibernate.cfg.Environment; +import org.hamcrest.MatcherAssert; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; +import org.hibernate.testing.orm.junit.BaseUnitTest; +import org.hibernate.testing.orm.junit.DialectFeatureChecks; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.RequiresDialectFeature; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.ServiceRegistryScope; +import org.hibernate.testing.orm.junit.Setting; import org.hibernate.tool.hbm2ddl.SchemaExport; import org.hibernate.tool.schema.TargetType; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; -import org.hibernate.testing.DialectChecks; -import org.hibernate.testing.RequiresDialectFeature; -import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.junit4.BaseUnitTestCase; -import org.hibernate.testing.util.ServiceRegistryUtil; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.EnumSet; +import java.util.List; +import java.util.Set; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; +import static org.hibernate.cfg.JdbcSettings.FORMAT_SQL; +import static org.hibernate.cfg.JdbcSettings.SHOW_SQL; +import static org.hibernate.cfg.SchemaToolingSettings.HBM2DDL_AUTO; /** * @author Andrea Boriero */ +@SuppressWarnings("JUnitMalformedDeclaration") @JiraKey(value = "HHH-12271") -@RequiresDialectFeature(DialectChecks.SupportDropConstraints.class) -public class ForeignKeyDropTest extends BaseUnitTestCase { - private File output; - private MetadataImplementor metadata; - private StandardServiceRegistry ssr; - private SchemaExport schemaExport; - - @Before - public void setUp() throws Exception { - output = File.createTempFile( "update_script", ".sql" ); - output.deleteOnExit(); - ssr = ServiceRegistryUtil.serviceRegistryBuilder() - .applySetting( Environment.HBM2DDL_AUTO, "none" ) - .applySetting( Environment.FORMAT_SQL, "false" ) - .applySetting( Environment.SHOW_SQL, "true" ) - .build(); - metadata = (MetadataImplementor) new MetadataSources( ssr ) - .addAnnotatedClass( ParentEntity.class ) - .addAnnotatedClass( ChildEntity.class ) - .buildMetadata(); - metadata.orderColumns( false ); - metadata.validate(); - schemaExport = new SchemaExport().setHaltOnError( false ).setOutputFile( output.getAbsolutePath() ); - } - +@BaseUnitTest +@RequiresDialectFeature(feature = DialectFeatureChecks.SupportDropConstraints.class) +@ServiceRegistry(settings = { + @Setting(name = HBM2DDL_AUTO, value = "none"), + @Setting(name = FORMAT_SQL, value = "false"), + @Setting(name = SHOW_SQL, value = "true") +}) +@DomainModel(annotatedClasses = { + ForeignKeyDropTest.ParentEntity.class, + ForeignKeyDropTest.ChildEntity.class +}) +public class ForeignKeyDropTest { @Test @JiraKey(value = "HHH-11236") - public void testForeignKeyDropIsCorrectlyGenerated() throws Exception { - - schemaExport - .drop( EnumSet.of( TargetType.SCRIPT, TargetType.DATABASE ), metadata ); + public void testForeignKeyDropIsCorrectlyGenerated( + ServiceRegistryScope registryScope, + DomainModelScope modelScope, + @TempDir File tmpDir) throws Exception { + final var metadata = modelScope.getDomainModel(); + metadata.orderColumns( false ); + metadata.validate(); - assertThat( - "The ddl foreign key drop command has not been properly generated", - checkDropForeignKeyConstraint( "CHILD_ENTITY" ), - is( true ) - ); - } + final var scriptFile = new File( tmpDir, "script.sql" ); - @After - public void tearDown() { - StandardServiceRegistryBuilder.destroy( ssr ); - } + final var schemaExport = new SchemaExport().setHaltOnError( false ).setOutputFile( scriptFile.getAbsolutePath() ); + schemaExport.drop( EnumSet.of( TargetType.SCRIPT, TargetType.DATABASE ), metadata ); - protected Dialect getDialect() { - return ssr.getService( JdbcEnvironment.class ).getDialect(); + final Dialect dialect = registryScope.getRegistry().requireService( JdbcEnvironment.class ).getDialect(); + MatcherAssert.assertThat( "The ddl foreign key drop command has not been properly generated", + checkDropForeignKeyConstraint( "CHILD_ENTITY", scriptFile, dialect ), is( true ) ); } - private boolean checkDropForeignKeyConstraint(String tableName) throws IOException { + private boolean checkDropForeignKeyConstraint( + String tableName, + File scriptFile, + Dialect dialect) throws IOException { boolean matches = false; - String regex = getDialect().getAlterTableString( tableName ); - regex += " " + getDialect().getDropForeignKeyString() + " "; + String regex = dialect.getAlterTableString( tableName ); + regex += " " + dialect.getDropForeignKeyString() + " "; - if ( getDialect().supportsIfExistsBeforeConstraintName() ) { + if ( dialect.supportsIfExistsBeforeConstraintName() ) { regex += "if exists "; } regex += "fk(.)*"; - if ( getDialect().supportsIfExistsAfterConstraintName() ) { + if ( dialect.supportsIfExistsAfterConstraintName() ) { regex += " if exists"; } - return isMatching( matches, regex.toLowerCase() ); + return isMatching( matches, regex.toLowerCase(), scriptFile ); } - private boolean isMatching(boolean matches, String regex) throws IOException { - List commands = Files.readAllLines( output.toPath() ); + private boolean isMatching(boolean matches, String regex, File scriptFile) throws IOException { + List commands = Files.readAllLines( scriptFile.toPath() ); Pattern p = Pattern.compile( regex ); for ( String line : commands ) { @@ -121,6 +109,7 @@ private boolean isMatching(boolean matches, String regex) throws IOException { return matches; } + @SuppressWarnings("unused") @Entity(name = "ParentEntity") @Table(name = "PARENT_ENTITY") public static class ParentEntity { @@ -132,6 +121,7 @@ public static class ParentEntity { Set children; } + @SuppressWarnings("unused") @Entity(name = "ChildEntity") @Table(name = "CHILD_ENTITY") public static class ChildEntity { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/ForeignKeyGenerationTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/ForeignKeyGenerationTest.java index bfe80cb81ff2..d7f4e1ca0da2 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/ForeignKeyGenerationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/ForeignKeyGenerationTest.java @@ -5,31 +5,27 @@ package org.hibernate.orm.test.schemaupdate.foreignkeys; import java.io.File; -import java.io.IOException; import java.nio.charset.Charset; import java.nio.file.Files; import java.util.EnumSet; import java.util.List; import java.util.function.UnaryOperator; -import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.community.dialect.InformixDialect; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.ServiceRegistryScope; import org.hibernate.testing.orm.junit.SkipForDialect; import org.hibernate.tool.hbm2ddl.SchemaExport; import org.hibernate.tool.schema.TargetType; import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.junit4.BaseUnitTestCase; -import org.hibernate.testing.util.ServiceRegistryUtil; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; @@ -38,43 +34,37 @@ /** * @author Andrea Boriero */ +@SuppressWarnings("JUnitMalformedDeclaration") @SkipForDialect(dialectClass = InformixDialect.class, reason = "Informix has a strange syntax for 'alter table add constraint'") -public class ForeignKeyGenerationTest extends BaseUnitTestCase { - private File output; - private StandardServiceRegistry ssr; - - @Before - public void setUp() throws IOException { - output = File.createTempFile( "update_script", ".sql" ); - output.deleteOnExit(); - ssr = ServiceRegistryUtil.serviceRegistry(); - } - - @After - public void tearsDown() { - StandardServiceRegistryBuilder.destroy( ssr ); - } - +@ServiceRegistry +public class ForeignKeyGenerationTest { @Test @JiraKey(value = "HHH-9591") - public void oneToOneTest() throws Exception { - createSchema( new Class[] {User.class, UserSetting.class, Group.class} ); + @DomainModel(annotatedClasses = {User.class, UserSetting.class, Group.class}) + public void oneToOneTest( + ServiceRegistryScope registryScope, + DomainModelScope modelScope, + @TempDir File tmpDir) throws Exception { + var scriptFile = new File( tmpDir, "one-to-one.sql" ); + createSchema( modelScope, scriptFile ); + + var jdbcEnv = registryScope.getRegistry().requireService( JdbcEnvironment.class ); /* The generated SQL for the foreign keys should be: alter table USERS add constraint FK_TO_USER_SETTING foreign key (USER_SETTING_ID) references USER_SETTING alter table USER_SETTING add constraint FK_TO_USER foreign key (USERS_ID) references USERS */ - checkAlterTableStatement( new AlterTableStatement( - ssr, + checkAlterTableStatement( scriptFile, new AlterTableStatement( + jdbcEnv, "USERS", "FK_TO_USER_SETTING", "USER_SETTING_ID", "USER_SETTING" ) ); - checkAlterTableStatement( new AlterTableStatement( - ssr, + checkAlterTableStatement( scriptFile, new AlterTableStatement( + jdbcEnv, "USER_SETTING", "FK_TO_USER", "USER_ID", @@ -84,15 +74,22 @@ alter table USER_SETTING add constraint FK_TO_USER foreign key (USERS_ID) refere @Test @JiraKey(value = "HHH-10396") - public void oneToManyTest() throws Exception { - createSchema( new Class[] {User.class, UserSetting.class, Group.class} ); + @DomainModel(annotatedClasses = {User.class, UserSetting.class, Group.class}) + public void oneToManyTest( + ServiceRegistryScope registryScope, + DomainModelScope modelScope, + @TempDir File tmpDir) throws Exception { + var scriptFile = new File( tmpDir, "one-to-many.sql" ); + createSchema( modelScope, scriptFile ); + + var jdbcEnv = registryScope.getRegistry().requireService( JdbcEnvironment.class ); /* The generated SQL for the foreign keys should be: alter table GROUP add constraint FK_USER_GROUP foreign key (USER_ID) references USERS */ - checkAlterTableStatement( new AlterTableStatement( - ssr, + checkAlterTableStatement( scriptFile, new AlterTableStatement( + jdbcEnv, "GROUP", "FK_USER_GROUP", "USER_ID", @@ -102,23 +99,30 @@ alter table GROUP add constraint FK_USER_GROUP foreign key (USER_ID) references @Test @JiraKey(value = "HHH-10385") - public void oneToManyWithJoinTableTest() throws Exception { - createSchema( new Class[] {Person.class, Phone.class} ); + @DomainModel(annotatedClasses = {Person.class, Phone.class}) + public void oneToManyWithJoinTableTest( + ServiceRegistryScope registryScope, + DomainModelScope modelScope, + @TempDir File tmpDir) throws Exception { + var scriptFile = new File( tmpDir, "one-to-many-join.sql" ); + createSchema( modelScope, scriptFile ); + + var jdbcEnv = registryScope.getRegistry().requireService( JdbcEnvironment.class ); /* The generated SQL for the foreign keys should be: alter table PERSON_PHONE add constraint PERSON_ID_FK foreign key (PERSON_ID) references PERSON alter table PERSON_PHONE add constraint PHONE_ID_FK foreign key (PHONE_ID) references PHONE */ - checkAlterTableStatement( new AlterTableStatement( - ssr, + checkAlterTableStatement( scriptFile, new AlterTableStatement( + jdbcEnv, "PERSON_PHONE", "PERSON_ID_FK", "PERSON_ID", "PERSON" ) ); - checkAlterTableStatement( new AlterTableStatement( - ssr, + checkAlterTableStatement( scriptFile, new AlterTableStatement( + jdbcEnv, "PERSON_PHONE", "PHONE_ID_FK", "PHONE_ID", @@ -128,23 +132,30 @@ alter table PERSON_PHONE add constraint PHONE_ID_FK foreign key (PHONE_ID) refer @Test @JiraKey(value = "HHH-10386") - public void manyToManyTest() throws Exception { - createSchema( new Class[] {Project.class, Employee.class} ); - - /* - The generated SQL for the foreign keys should be: - alter table EMPLOYEE_PROJECT add constraint FK_EMPLOYEE foreign key (EMPLOYEE_ID) references EMPLOYEE - alter table EMPLOYEE_PROJECT add constraint FK_PROJECT foreign key (PROJECT_ID) references PROJECT - */ - checkAlterTableStatement( new AlterTableStatement( - ssr, + @DomainModel(annotatedClasses = {Project.class, Employee.class}) + public void manyToManyTest( + ServiceRegistryScope registryScope, + DomainModelScope modelScope, + @TempDir File tmpDir) throws Exception { + var scriptFile = new File( tmpDir, "many-to-many.sql" ); + createSchema( modelScope, scriptFile ); + + var jdbcEnv = registryScope.getRegistry().requireService( JdbcEnvironment.class ); + + /* + The generated SQL for the foreign keys should be: + alter table EMPLOYEE_PROJECT add constraint FK_EMPLOYEE foreign key (EMPLOYEE_ID) references EMPLOYEE + alter table EMPLOYEE_PROJECT add constraint FK_PROJECT foreign key (PROJECT_ID) references PROJECT + */ + checkAlterTableStatement( scriptFile, new AlterTableStatement( + jdbcEnv, "EMPLOYEE_PROJECT", "FK_EMPLOYEE", "EMPLOYEE_ID", "EMPLOYEE" ) ); - checkAlterTableStatement( new AlterTableStatement( - ssr, + checkAlterTableStatement( scriptFile, new AlterTableStatement( + jdbcEnv, "EMPLOYEE_PROJECT", "FK_PROJECT", "PROJECT_ID", @@ -152,60 +163,44 @@ alter table EMPLOYEE_PROJECT add constraint FK_PROJECT foreign key (PROJECT_ID) ) ); } - private void createSchema(Class[] annotatedClasses) { - final MetadataSources metadataSources = new MetadataSources( ssr ); - - for ( Class c : annotatedClasses ) { - metadataSources.addAnnotatedClass( c ); - } - final MetadataImplementor metadata = (MetadataImplementor) metadataSources.buildMetadata(); + private void createSchema(DomainModelScope modelScope, File scriptFile) { + final var metadata = modelScope.getDomainModel(); metadata.orderColumns( false ); metadata.validate(); + new SchemaExport() .setHaltOnError( true ) - .setOutputFile( output.getAbsolutePath() ) + .setOutputFile( scriptFile.getAbsolutePath() ) .setFormat( false ) .create( EnumSet.of( TargetType.SCRIPT ), metadata ); } - private void checkAlterTableStatement(AlterTableStatement alterTableStatement) - throws Exception { + private void checkAlterTableStatement( + File scriptFile, + AlterTableStatement alterTableStatement) throws Exception { final String expectedAlterTableStatement = alterTableStatement.toSQL(); - final List sqlLines = Files.readAllLines( output.toPath(), Charset.defaultCharset() ); + final List sqlLines = Files.readAllLines( scriptFile.toPath(), Charset.defaultCharset() ); assertThat( "Expected alter table statement not found", sqlLines, hasItem( containsString( expectedAlterTableStatement ) ) ); } - private static class AlterTableStatement { - final StandardServiceRegistry ssr; - final String tableName; - final String fkConstraintName; - final String fkColumnName; - final String referenceTableName; - - public AlterTableStatement( - StandardServiceRegistry ssr, - String tableName, - String fkConstraintName, - String fkColumnName, - String referenceTableName) { - this.ssr = ssr; - this.tableName = tableName; - this.fkConstraintName = fkConstraintName; - this.fkColumnName = fkColumnName; - this.referenceTableName = referenceTableName; - } - + private record AlterTableStatement( + JdbcEnvironment jdbcEnv, + String tableName, + String fkConstraintName, + String fkColumnName, + String referenceTableName) { public String toSQL() { - JdbcEnvironment jdbcEnvironment = ssr.requireService( JdbcEnvironment.class ); - Dialect dialect = jdbcEnvironment.getDialect(); - IdentifierHelper identifierHelper = jdbcEnvironment.getIdentifierHelper(); - UnaryOperator asIdentifier = identifier -> identifierHelper.toIdentifier( identifier ).render( dialect ); - return dialect.getAlterTableString( asIdentifier.apply( tableName ) ) + Dialect dialect = jdbcEnv.getDialect(); + IdentifierHelper identifierHelper = jdbcEnv.getIdentifierHelper(); + UnaryOperator asIdentifier = identifier -> identifierHelper.toIdentifier( identifier ) + .render( dialect ); + return dialect.getAlterTableString( asIdentifier.apply( tableName ) ) + " add constraint " + asIdentifier.apply( fkConstraintName ) - + " foreign key (" + asIdentifier.apply( fkColumnName ) + ") references " + asIdentifier.apply( referenceTableName ); + + " foreign key (" + asIdentifier.apply( fkColumnName ) + ") references " + asIdentifier.apply( + referenceTableName ); + } } - } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/ForeignKeyMigrationTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/ForeignKeyMigrationTest.java index ad1667dace0d..bd916e57c744 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/ForeignKeyMigrationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/ForeignKeyMigrationTest.java @@ -11,53 +11,43 @@ import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; -import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.boot.spi.MetadataImplementor; +import org.hibernate.testing.orm.junit.DialectFeatureChecks; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; +import org.hibernate.testing.orm.junit.RequiresDialectFeature; +import org.hibernate.testing.orm.junit.ServiceRegistry; import org.hibernate.tool.hbm2ddl.SchemaExport; import org.hibernate.tool.hbm2ddl.SchemaUpdate; import org.hibernate.tool.schema.TargetType; -import org.hibernate.testing.DialectChecks; -import org.hibernate.testing.RequiresDialectFeature; import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.junit4.BaseUnitTestCase; -import org.hibernate.testing.util.ServiceRegistryUtil; -import org.junit.Test; +import org.junit.jupiter.api.Test; /** * @author Steve Ebersole */ -@RequiresDialectFeature( value = {DialectChecks.SupportCatalogCreation.class}) -public class ForeignKeyMigrationTest extends BaseUnitTestCase { +@SuppressWarnings("JUnitMalformedDeclaration") +@RequiresDialectFeature(feature = DialectFeatureChecks.SupportCatalogCreation.class) +@ServiceRegistry +@DomainModel(annotatedClasses = {ForeignKeyMigrationTest.Box.class, ForeignKeyMigrationTest.Thing.class}) +public class ForeignKeyMigrationTest { @Test @JiraKey( value = "HHH-9716" ) -// @FailureExpected( jiraKey = "HHH-9716" ) - public void testMigrationOfForeignKeys() { - StandardServiceRegistry ssr = ServiceRegistryUtil.serviceRegistry(); - try { - final MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr ) - .addAnnotatedClass( Box.class ) - .addAnnotatedClass( Thing.class ) - .buildMetadata(); - metadata.orderColumns( false ); - metadata.validate(); + public void testMigrationOfForeignKeys(DomainModelScope modelScope) { + final var metadata = modelScope.getDomainModel(); + metadata.orderColumns( false ); + metadata.validate(); - // first create the schema... - new SchemaExport().create( EnumSet.of( TargetType.DATABASE ), metadata ); + // first create the schema... + new SchemaExport().create( EnumSet.of( TargetType.DATABASE ), metadata ); - try { - // try to update the just created schema - new SchemaUpdate().execute( EnumSet.of( TargetType.DATABASE ), metadata ); - } - finally { - // clean up - new SchemaExport().drop( EnumSet.of( TargetType.DATABASE ), metadata ); - } + try { + // try to update the just created schema + new SchemaUpdate().execute( EnumSet.of( TargetType.DATABASE ), metadata ); } finally { - StandardServiceRegistryBuilder.destroy( ssr ); + // clean up + new SchemaExport().drop( EnumSet.of( TargetType.DATABASE ), metadata ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/JoinedInheritanceForeignKeyTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/JoinedInheritanceForeignKeyTest.java index a3810c9e4488..f277f70c5447 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/JoinedInheritanceForeignKeyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/JoinedInheritanceForeignKeyTest.java @@ -14,126 +14,103 @@ import jakarta.persistence.Inheritance; import jakarta.persistence.InheritanceType; import jakarta.persistence.PrimaryKeyJoinColumn; -import java.io.File; -import java.io.IOException; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.util.EnumSet; -import java.util.List; -import java.util.function.UnaryOperator; - -import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.boot.spi.MetadataImplementor; +import org.hamcrest.MatcherAssert; import org.hibernate.community.dialect.InformixDialect; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.ServiceRegistryScope; import org.hibernate.testing.orm.junit.SkipForDialect; import org.hibernate.tool.hbm2ddl.SchemaExport; import org.hibernate.tool.schema.TargetType; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.junit4.BaseUnitTestCase; -import org.hibernate.testing.util.ServiceRegistryUtil; +import java.io.File; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.util.EnumSet; +import java.util.List; +import java.util.function.UnaryOperator; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.hasItem; -import static org.junit.Assert.assertThat; /** * @author Andrea Boriero */ +@SuppressWarnings("JUnitMalformedDeclaration") @JiraKey(value = "HHH-10352") -public class JoinedInheritanceForeignKeyTest extends BaseUnitTestCase { - private File output; - private StandardServiceRegistry ssr; - private MetadataImplementor metadata; - - @Before - public void setUp() throws IOException { - output = File.createTempFile( "update_script", ".sql" ); - output.deleteOnExit(); - ssr = ServiceRegistryUtil.serviceRegistry(); - } - - @After - public void tearsDown() { - StandardServiceRegistryBuilder.destroy( ssr ); - } - +@ServiceRegistry +@DomainModel(annotatedClasses = { + JoinedInheritanceForeignKeyTest.Role.class, + JoinedInheritanceForeignKeyTest.User.class, + JoinedInheritanceForeignKeyTest.Person.class +}) +public class JoinedInheritanceForeignKeyTest { @Test @SkipForDialect(dialectClass = InformixDialect.class, reason="Informix has a strange syntax for 'alter table ... add constraint'") - public void testForeignKeyHasCorrectName() throws Exception { - createSchema( new Class[] {Role.class, User.class, Person.class} ); - checkAlterTableStatement( new AlterTableStatement( - ssr, "User", + public void testForeignKeyHasCorrectName( + ServiceRegistryScope registryScope, + DomainModelScope modelScope, + @TempDir File tmpDir) throws Exception { + final var scriptFile = new File( tmpDir, "script.sql" ); + + createSchema( modelScope, scriptFile ); + + final var jdbcEnv = registryScope.getRegistry().requireService( JdbcEnvironment.class ); + checkAlterTableStatement( scriptFile, new AlterTableStatement( + jdbcEnv, "User", "FK_PERSON_ROLE", "USER_ID", "PersonRole" ) ); } - private void checkAlterTableStatement(AlterTableStatement alterTableStatement) - throws Exception { - final String expectedAlterTableStatement = alterTableStatement.toSQL(); - final List sqlLines = Files.readAllLines( output.toPath(), Charset.defaultCharset() ); - - assertThat( "Expected alter table statement not found", sqlLines, hasItem( containsString( expectedAlterTableStatement ) ) ); - } - - private static class AlterTableStatement { - final StandardServiceRegistry ssr; - final String tableName; - final String fkConstraintName; - final String fkColumnName; - final String referenceTableName; - - public AlterTableStatement( - StandardServiceRegistry ssr, String tableName, - String fkConstraintName, - String fkColumnName, - String referenceTableName) { - this.ssr = ssr; - this.tableName = tableName; - this.fkConstraintName = fkConstraintName; - this.fkColumnName = fkColumnName; - this.referenceTableName = referenceTableName; - } - - public String toSQL() { - JdbcEnvironment jdbcEnvironment = ssr.getService( JdbcEnvironment.class ); - Dialect dialect = jdbcEnvironment.getDialect(); - IdentifierHelper identifierHelper = jdbcEnvironment.getIdentifierHelper(); - UnaryOperator asIdentifier = identifier -> identifierHelper.toIdentifier( identifier ).render( dialect ); - return dialect.getAlterTableString( asIdentifier.apply( tableName ) ) - + " add constraint " + asIdentifier.apply( fkConstraintName ) - + " foreign key (" + asIdentifier.apply( fkColumnName ) + ") references " + asIdentifier.apply( referenceTableName ); - } - } - - private void createSchema(Class[] annotatedClasses) { - final MetadataSources metadataSources = new MetadataSources( ssr ); - - for ( Class c : annotatedClasses ) { - metadataSources.addAnnotatedClass( c ); - } - metadata = (MetadataImplementor) metadataSources.buildMetadata(); + private void createSchema(DomainModelScope modelScope, File scriptFile) { + final var metadata = modelScope.getDomainModel(); metadata.orderColumns( false ); metadata.validate(); + new SchemaExport() .setHaltOnError( true ) - .setOutputFile( output.getAbsolutePath() ) + .setOutputFile( scriptFile.getAbsolutePath() ) .setFormat( false ) .create( EnumSet.of( TargetType.SCRIPT ), metadata ); } + private void checkAlterTableStatement(File scriptFile, AlterTableStatement alterTableStatement) throws Exception { + final String expectedAlterTableStatement = alterTableStatement.toSQL(); + final List sqlLines = Files.readAllLines( scriptFile.toPath(), Charset.defaultCharset() ); + + MatcherAssert.assertThat( "Expected alter table statement not found", sqlLines, + hasItem( containsString( expectedAlterTableStatement ) ) ); + } + + private record AlterTableStatement( + JdbcEnvironment jdbcEnv, + String tableName, + String fkConstraintName, + String fkColumnName, + String referenceTableName) { + + public String toSQL() { + Dialect dialect = jdbcEnv.getDialect(); + IdentifierHelper identifierHelper = jdbcEnv.getIdentifierHelper(); + UnaryOperator asIdentifier = identifier -> identifierHelper.toIdentifier( identifier ) + .render( dialect ); + return dialect.getAlterTableString( asIdentifier.apply( tableName ) ) + + " add constraint " + asIdentifier.apply( fkConstraintName ) + + " foreign key (" + asIdentifier.apply( fkColumnName ) + ") references " + asIdentifier.apply( + referenceTableName ); + } + } + @Entity(name = "PersonRole") @Inheritance(strategy = InheritanceType.JOINED) @DiscriminatorColumn(name = "PERSON_ROLE_TYPE", discriminatorType = DiscriminatorType.INTEGER) diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/SchemaUpdateWithKeywordAutoQuotingEnabledTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/SchemaUpdateWithKeywordAutoQuotingEnabledTest.java index 5320e44d0e25..f988c6d96f1f 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/SchemaUpdateWithKeywordAutoQuotingEnabledTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/SchemaUpdateWithKeywordAutoQuotingEnabledTest.java @@ -6,7 +6,6 @@ import java.util.EnumSet; import java.util.Map; -import java.util.TreeMap; import jakarta.persistence.CollectionTable; import jakarta.persistence.ElementCollection; import jakarta.persistence.Entity; @@ -14,61 +13,63 @@ import jakarta.persistence.Id; import jakarta.persistence.Table; -import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.boot.spi.MetadataImplementor; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.Setting; import org.hibernate.tool.hbm2ddl.SchemaExport; import org.hibernate.tool.hbm2ddl.SchemaUpdate; import org.hibernate.tool.schema.TargetType; import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.junit4.BaseUnitTestCase; -import org.hibernate.testing.util.ServiceRegistryUtil; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +import static org.hibernate.cfg.MappingSettings.KEYWORD_AUTO_QUOTING_ENABLED; /** * @author Andrea Boriero */ +@SuppressWarnings("JUnitMalformedDeclaration") @JiraKey(value = "HHH-11061") -public class SchemaUpdateWithKeywordAutoQuotingEnabledTest extends BaseUnitTestCase { - private StandardServiceRegistry ssr; - private MetadataImplementor metadata; - - @Before - public void setUp() { - ssr = ServiceRegistryUtil.serviceRegistryBuilder() - .applySetting( org.hibernate.cfg.AvailableSettings.KEYWORD_AUTO_QUOTING_ENABLED, "true" ) - .build(); +@ServiceRegistry(settings = @Setting(name = KEYWORD_AUTO_QUOTING_ENABLED, value = "true")) +@DomainModel(annotatedClasses = SchemaUpdateWithKeywordAutoQuotingEnabledTest.Match.class) +public class SchemaUpdateWithKeywordAutoQuotingEnabledTest { - final MetadataSources metadataSources = new MetadataSources( ssr ); - metadataSources.addAnnotatedClass( Match.class ); - metadata = (MetadataImplementor) metadataSources.buildMetadata(); + @BeforeEach + void createSchema(DomainModelScope modelScope) { + final var metadata = modelScope.getDomainModel(); metadata.orderColumns( false ); metadata.validate(); - try { - createSchema(); - } - catch (Exception e) { - tearDown(); - throw e; - } + + dropSchema( modelScope ); + + new SchemaExport().setHaltOnError( true ) + .createOnly( EnumSet.of( TargetType.DATABASE ), metadata ); } - @After - public void tearDown() { - dropSchema(); - StandardServiceRegistryBuilder.destroy( ssr ); + @AfterEach + void dropSchema(DomainModelScope modelScope) { + final var metadata = modelScope.getDomainModel(); + metadata.orderColumns( false ); + metadata.validate(); + + new SchemaExport() + .drop( EnumSet.of( TargetType.DATABASE ), metadata ); } @Test - public void testUpdate() { + public void testUpdate(DomainModelScope modelScope) { + final var metadata = modelScope.getDomainModel(); + metadata.orderColumns( false ); + metadata.validate(); + new SchemaUpdate().setHaltOnError( true ) .execute( EnumSet.of( TargetType.DATABASE ), metadata ); } + @SuppressWarnings("unused") @Entity(name = "Match") @Table(name = "MATCH") public static class Match { @@ -77,17 +78,6 @@ public static class Match { @ElementCollection(fetch = FetchType.EAGER) @CollectionTable - private Map timeline = new TreeMap<>(); - } - - private void createSchema() { - dropSchema(); - new SchemaExport().setHaltOnError( true ) - .createOnly( EnumSet.of( TargetType.DATABASE ), metadata ); - } - - private void dropSchema() { - new SchemaExport() - .drop( EnumSet.of( TargetType.DATABASE ), metadata ); + private Map timeline; } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/crossschema/CrossSchemaForeignKeyGenerationTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/crossschema/CrossSchemaForeignKeyGenerationTest.java index 8bb049d1d9c3..467498e43eaf 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/crossschema/CrossSchemaForeignKeyGenerationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/crossschema/CrossSchemaForeignKeyGenerationTest.java @@ -4,147 +4,123 @@ */ package org.hibernate.orm.test.schemaupdate.foreignkeys.crossschema; -import java.io.File; -import java.io.IOException; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.util.EnumSet; -import java.util.List; -import java.util.Map; - -import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.model.relational.Database; -import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.boot.spi.MetadataImplementor; -import org.hibernate.cfg.AvailableSettings; +import org.hamcrest.MatcherAssert; import org.hibernate.engine.config.spi.ConfigurationService; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.jdbc.spi.JdbcServices; +import org.hibernate.orm.test.tool.schema.TargetDatabaseImpl; +import org.hibernate.testing.orm.junit.DialectFeatureChecks; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.RequiresDialectFeature; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.ServiceRegistryScope; +import org.hibernate.testing.orm.junit.Setting; import org.hibernate.tool.hbm2ddl.SchemaExport; import org.hibernate.tool.hbm2ddl.SchemaUpdate; import org.hibernate.tool.schema.SourceType; import org.hibernate.tool.schema.TargetType; import org.hibernate.tool.schema.internal.DefaultSchemaFilter; import org.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl; -import org.hibernate.tool.schema.internal.HibernateSchemaManagementTool; import org.hibernate.tool.schema.internal.GroupedSchemaMigratorImpl; -import org.hibernate.tool.schema.internal.SchemaDropperImpl; +import org.hibernate.tool.schema.internal.HibernateSchemaManagementTool; import org.hibernate.tool.schema.internal.IndividuallySchemaMigratorImpl; -import org.hibernate.tool.schema.spi.GenerationTarget; +import org.hibernate.tool.schema.internal.SchemaDropperImpl; import org.hibernate.tool.schema.internal.exec.GenerationTargetToStdout; import org.hibernate.tool.schema.spi.ContributableMatcher; import org.hibernate.tool.schema.spi.ExceptionHandler; import org.hibernate.tool.schema.spi.ExecutionOptions; +import org.hibernate.tool.schema.spi.GenerationTarget; import org.hibernate.tool.schema.spi.SchemaManagementTool; import org.hibernate.tool.schema.spi.ScriptSourceInput; import org.hibernate.tool.schema.spi.ScriptTargetOutput; import org.hibernate.tool.schema.spi.SourceDescriptor; import org.hibernate.tool.schema.spi.TargetDescriptor; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; -import org.hibernate.testing.DialectChecks; -import org.hibernate.testing.RequiresDialectFeature; -import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.junit4.BaseUnitTestCase; -import org.hibernate.testing.util.ServiceRegistryUtil; - -import org.hibernate.orm.test.tool.schema.TargetDatabaseImpl; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.util.EnumSet; +import java.util.List; +import java.util.Map; import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; +import static org.hibernate.cfg.SchemaToolingSettings.JAKARTA_HBM2DDL_CREATE_SCHEMAS; /** * @author Andrea Boriero */ -@RequiresDialectFeature( value = DialectChecks.SupportSchemaCreation.class) -public class CrossSchemaForeignKeyGenerationTest extends BaseUnitTestCase { - private File output; - private StandardServiceRegistry ssr; - - @Before - public void setUp() throws IOException { - output = File.createTempFile( "update_script", ".sql" ); - output.deleteOnExit(); - ssr = ServiceRegistryUtil.serviceRegistryBuilder() - .applySetting( AvailableSettings.HBM2DDL_CREATE_SCHEMAS, "true" ) - .build(); - } - - @After - public void tearsDown() { - StandardServiceRegistryBuilder.destroy( ssr ); +@SuppressWarnings("JUnitMalformedDeclaration") +@RequiresDialectFeature(feature = DialectFeatureChecks.SupportSchemaCreation.class) +@ServiceRegistry(settings = @Setting(name = JAKARTA_HBM2DDL_CREATE_SCHEMAS, value = "true")) +@DomainModel(annotatedClasses = {SchemaOneEntity.class, SchemaTwoEntity.class}) +public class CrossSchemaForeignKeyGenerationTest { + @BeforeEach + public void setUp(DomainModelScope modelScope) throws IOException { + modelScope.getDomainModel().orderColumns( false ); + modelScope.getDomainModel().validate(); } @Test @JiraKey(value = "HHH-10420") - public void testSchemaExportForeignKeysAreGeneratedAfterAllTheTablesAreCreated() throws Exception { - final MetadataSources metadataSources = new MetadataSources( ssr ); - metadataSources.addAnnotatedClass( SchemaOneEntity.class ); - metadataSources.addAnnotatedClass( SchemaTwoEntity.class ); - - MetadataImplementor metadata = (MetadataImplementor) metadataSources.buildMetadata(); - metadata.orderColumns( false ); - metadata.validate(); + public void testSchemaExportForeignKeysAreGeneratedAfterAllTheTablesAreCreated( + DomainModelScope modelScope, + @TempDir File tmpDir) throws Exception { + var scriptFile = new File( tmpDir, "fk-order.sql" ); new SchemaExport().setHaltOnError( true ) - .setOutputFile( output.getAbsolutePath() ) + .setOutputFile( scriptFile.getAbsolutePath() ) .setFormat( false ) - .create( EnumSet.of( TargetType.SCRIPT, TargetType.STDOUT ), metadata ); + .create( EnumSet.of( TargetType.SCRIPT, TargetType.STDOUT ), modelScope.getDomainModel() ); - final List sqlLines = Files.readAllLines( output.toPath(), Charset.defaultCharset() ); - assertThat( - "Expected alter table SCHEMA1.Child add constraint but is : " + sqlLines.get( 4 ), - sqlLines.get( sqlLines.size() - 1 ).startsWith( "alter table " ), - is( true ) - ); + final List sqlLines = Files.readAllLines( scriptFile.toPath(), Charset.defaultCharset() ); + MatcherAssert.assertThat( "Expected alter table SCHEMA1.Child add constraint but is : " + sqlLines.get( 4 ), + sqlLines.get( sqlLines.size() - 1 ).startsWith( "alter table " ), is( true ) ); } @Test @JiraKey(value = "HHH-10802") - public void testSchemaUpdateDoesNotFailResolvingCrossSchemaForeignKey() throws Exception { - final MetadataSources metadataSources = new MetadataSources( ssr ); - metadataSources.addAnnotatedClass( SchemaOneEntity.class ); - metadataSources.addAnnotatedClass( SchemaTwoEntity.class ); - - MetadataImplementor metadata = (MetadataImplementor) metadataSources.buildMetadata(); - metadata.orderColumns( false ); - metadata.validate(); + public void testSchemaUpdateDoesNotFailResolvingCrossSchemaForeignKey( + DomainModelScope modelScope, + @TempDir File tmpDir) throws Exception { + var scriptFile = new File( tmpDir, "cross-schema.sql" ); new SchemaExport() - .setOutputFile( output.getAbsolutePath() ) + .setOutputFile( scriptFile.getAbsolutePath() ) .setFormat( false ) - .create( EnumSet.of( TargetType.DATABASE ), metadata ); + .create( EnumSet.of( TargetType.DATABASE ), modelScope.getDomainModel() ); new SchemaUpdate().setHaltOnError( true ) - .setOutputFile( output.getAbsolutePath() ) + .setOutputFile( scriptFile.getAbsolutePath() ) .setFormat( false ) - .execute( EnumSet.of( TargetType.DATABASE ), metadata ); + .execute( EnumSet.of( TargetType.DATABASE ), modelScope.getDomainModel() ); new SchemaExport().setHaltOnError( true ) - .setOutputFile( output.getAbsolutePath() ) + .setOutputFile( scriptFile.getAbsolutePath() ) .setFormat( false ) - .drop( EnumSet.of( TargetType.DATABASE ), metadata ); + .drop( EnumSet.of( TargetType.DATABASE ), modelScope.getDomainModel() ); } @Test @JiraKey(value = "HHH-10420") - public void testSchemaMigrationForeignKeysAreGeneratedAfterAllTheTablesAreCreated() throws Exception { - final MetadataSources metadataSources = new MetadataSources( ssr ); - metadataSources.addAnnotatedClass( SchemaOneEntity.class ); - metadataSources.addAnnotatedClass( SchemaTwoEntity.class ); - - MetadataImplementor metadata = (MetadataImplementor) metadataSources.buildMetadata(); - metadata.orderColumns( false ); - metadata.validate(); - - final Database database = metadata.getDatabase(); - final HibernateSchemaManagementTool tool = (HibernateSchemaManagementTool) ssr.getService( SchemaManagementTool.class ); - - final Map configurationValues = ssr.requireService( ConfigurationService.class ).getSettings(); + public void testSchemaMigrationForeignKeysAreGeneratedAfterAllTheTablesAreCreated( + ServiceRegistryScope registryScope, + DomainModelScope modelScope) throws Exception { + final var metadata = modelScope.getDomainModel(); + + final HibernateSchemaManagementTool tool = (HibernateSchemaManagementTool) registryScope + .getRegistry() + .requireService( SchemaManagementTool.class ); + + final Map configurationValues = registryScope + .getRegistry() + .requireService( ConfigurationService.class ) + .getSettings(); final ExecutionOptions options = new ExecutionOptions() { @Override public boolean shouldManageNamespaces() { @@ -179,7 +155,7 @@ public ExceptionHandler getExceptionHandler() { new SchemaDropperImpl( tool ).doDrop( metadata, options, - ssr.getService( JdbcEnvironment.class ).getDialect(), + registryScope.getRegistry().requireService( JdbcEnvironment.class ).getDialect(), new SourceDescriptor() { @Override public SourceType getSourceType() { @@ -191,24 +167,24 @@ public ScriptSourceInput getScriptSourceInput() { return null; } }, - buildTargets() + buildTargets( registryScope.getRegistry().requireService( JdbcServices.class ) ) ); } @Test @JiraKey(value = "HHH-10420") - public void testImprovedSchemaMigrationForeignKeysAreGeneratedAfterAllTheTablesAreCreated() throws Exception { - final MetadataSources metadataSources = new MetadataSources( ssr ); - metadataSources.addAnnotatedClass( SchemaOneEntity.class ); - metadataSources.addAnnotatedClass( SchemaTwoEntity.class ); + public void testImprovedSchemaMigrationForeignKeysAreGeneratedAfterAllTheTablesAreCreated( + ServiceRegistryScope registryScope, + DomainModelScope modelScope) throws Exception { + final HibernateSchemaManagementTool tool = (HibernateSchemaManagementTool) registryScope + .getRegistry() + .requireService( SchemaManagementTool.class ); + + final Map configurationValues = registryScope + .getRegistry() + .requireService( ConfigurationService.class ) + .getSettings(); - MetadataImplementor metadata = (MetadataImplementor) metadataSources.buildMetadata(); - metadata.orderColumns( false ); - metadata.validate(); - - final HibernateSchemaManagementTool tool = (HibernateSchemaManagementTool) ssr.getService( SchemaManagementTool.class ); - - final Map configurationValues = ssr.requireService( ConfigurationService.class ).getSettings(); final ExecutionOptions options = new ExecutionOptions() { @Override public boolean shouldManageNamespaces() { @@ -227,16 +203,18 @@ public ExceptionHandler getExceptionHandler() { }; new GroupedSchemaMigratorImpl( tool, DefaultSchemaFilter.INSTANCE ).doMigration( - metadata, + modelScope.getDomainModel(), options, ContributableMatcher.ALL, TargetDescriptorImpl.INSTANCE ); + final var jdbcServices = registryScope.getRegistry().requireService( JdbcServices.class ); + new SchemaDropperImpl( tool ).doDrop( - metadata, + modelScope.getDomainModel(), options, - ssr.getService( JdbcEnvironment.class ).getDialect(), + jdbcServices.getDialect(), new SourceDescriptor() { @Override public SourceType getSourceType() { @@ -248,14 +226,14 @@ public ScriptSourceInput getScriptSourceInput() { return null; } }, - buildTargets() + buildTargets( jdbcServices ) ); } - public GenerationTarget[] buildTargets() { + public GenerationTarget[] buildTargets(JdbcServices jdbcServices) { return new GenerationTarget[] { new GenerationTargetToStdout(), - new TargetDatabaseImpl( ssr.getService( JdbcServices.class ).getBootstrapJdbcConnectionAccess() ) + new TargetDatabaseImpl( jdbcServices.getBootstrapJdbcConnectionAccess() ) }; } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/definition/AbstractForeignKeyDefinitionTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/definition/AbstractForeignKeyDefinitionTest.java index bb0bccc6fdfe..1878d5d7c92e 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/definition/AbstractForeignKeyDefinitionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/definition/AbstractForeignKeyDefinitionTest.java @@ -4,66 +4,40 @@ */ package org.hibernate.orm.test.schemaupdate.foreignkeys.definition; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.util.EnumSet; - import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.boot.spi.MetadataImplementor; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.ServiceRegistryScope; import org.hibernate.tool.hbm2ddl.SchemaExport; import org.hibernate.tool.schema.TargetType; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; -import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.junit4.BaseUnitTestCase; -import org.hibernate.testing.util.ServiceRegistryUtil; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import static org.junit.Assert.assertTrue; +import java.io.File; +import java.nio.file.Files; +import java.util.EnumSet; /** * @author Vlad MIhalcea */ - -public abstract class AbstractForeignKeyDefinitionTest extends BaseUnitTestCase { - - private File output; - - private StandardServiceRegistry ssr; - +@SuppressWarnings("JUnitMalformedDeclaration") +@ServiceRegistry +public abstract class AbstractForeignKeyDefinitionTest { private MetadataImplementor metadata; - @Before - public void setUp() throws IOException { - output = File.createTempFile( "update_script", ".sql" ); - output.deleteOnExit(); - ssr = ServiceRegistryUtil.serviceRegistry(); - createSchema(); - } - - @After - public void tearsDown() { - StandardServiceRegistryBuilder.destroy( ssr ); - } - - private void createSchema() { - final MetadataSources metadataSources = new MetadataSources( ssr ); + @BeforeEach + public void setUp(ServiceRegistryScope registryScope) { + final MetadataSources metadataSources = new MetadataSources( registryScope.getRegistry() ); - for ( Class c : getAnnotatedClasses() ) { + for ( Class c : getAnnotatedClasses() ) { metadataSources.addAnnotatedClass( c ); } metadata = (MetadataImplementor) metadataSources.buildMetadata(); metadata.orderColumns( false ); metadata.validate(); - new SchemaExport() - .setHaltOnError( true ) - .setOutputFile( output.getAbsolutePath() ) - .setFormat( false ) - .create( EnumSet.of( TargetType.SCRIPT ), metadata ); } protected abstract Class[] getAnnotatedClasses(); @@ -72,10 +46,17 @@ private void createSchema() { @Test @JiraKey(value = "HHH-10643") - public void testForeignKeyDefinitionOverridesDefaultNamingStrategy() - throws Exception { - String fileContent = new String( Files.readAllBytes( output.toPath() ) ); - assertTrue( "Script file : " + fileContent, validate( fileContent ) ); + public void testForeignKeyDefinitionOverridesDefaultNamingStrategy(@TempDir File tmpDir) throws Exception { + final var scriptFile = new File( tmpDir, "script.sql" ); + + new SchemaExport() + .setHaltOnError( true ) + .setOutputFile( scriptFile.getAbsolutePath() ) + .setFormat( false ) + .create( EnumSet.of( TargetType.SCRIPT ), metadata ); + + String fileContent = new String( Files.readAllBytes( scriptFile.toPath() ) ); + Assertions.assertTrue( validate( fileContent ), "Script file : " + fileContent ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/definition/ForeignKeyDefinitionManyToOneTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/definition/ForeignKeyDefinitionManyToOneTest.java index 9d89e99f5aa3..d726358bab30 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/definition/ForeignKeyDefinitionManyToOneTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/definition/ForeignKeyDefinitionManyToOneTest.java @@ -11,22 +11,22 @@ import jakarta.persistence.ManyToOne; import org.hibernate.dialect.H2Dialect; - -import org.hibernate.testing.RequiresDialect; +import org.hibernate.testing.orm.junit.RequiresDialect; /** * @author Vlad Mihalcea */ -@RequiresDialect(value = H2Dialect.class) -public class ForeignKeyDefinitionManyToOneTest - extends AbstractForeignKeyDefinitionTest { +@RequiresDialect(H2Dialect.class) +public class ForeignKeyDefinitionManyToOneTest extends AbstractForeignKeyDefinitionTest { @Override protected Class[] getAnnotatedClasses() { - return new Class[] { - Box.class, - Thing.class, - }; + return new Class[] { Box.class, Thing.class }; + } + + @Override + protected boolean validate(String fileContent) { + return fileContent.contains( "/* FK */" ); } @Entity(name = "Box") @@ -44,9 +44,4 @@ public static class Thing { @Id public Integer id; } - - @Override - protected boolean validate(String fileContent) { - return fileContent.contains( "/* FK */" ); - } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/definition/ForeignKeyDefinitionOneToManyJoinTableTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/definition/ForeignKeyDefinitionOneToManyJoinTableTest.java index 8d852e2d86bd..fc0ea307379a 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/definition/ForeignKeyDefinitionOneToManyJoinTableTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/definition/ForeignKeyDefinitionOneToManyJoinTableTest.java @@ -14,22 +14,23 @@ import jakarta.persistence.OneToMany; import org.hibernate.dialect.H2Dialect; - -import org.hibernate.testing.RequiresDialect; +import org.hibernate.testing.orm.junit.RequiresDialect; /** * @author Vlad Mihalcea */ -@RequiresDialect(value = H2Dialect.class) -public class ForeignKeyDefinitionOneToManyJoinTableTest - extends AbstractForeignKeyDefinitionTest { +@RequiresDialect(H2Dialect.class) +public class ForeignKeyDefinitionOneToManyJoinTableTest extends AbstractForeignKeyDefinitionTest { @Override protected Class[] getAnnotatedClasses() { - return new Class[] { - Box.class, - Thing.class, - }; + return new Class[] { Box.class, Thing.class }; + } + + @Override + protected boolean validate(String fileContent) { + return fileContent.contains( "/* Thing_FK */" ) + && fileContent.contains( "/* Box_FK */" ); } @Entity(name = "Box") @@ -58,10 +59,4 @@ public static class Thing { ) public List things = new ArrayList<>(); } - - @Override - protected boolean validate(String fileContent) { - return fileContent.contains( "/* Thing_FK */" ) && fileContent.contains( - "/* Box_FK */" ); - } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/definition/ForeignKeyDefinitionOneToOneTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/definition/ForeignKeyDefinitionOneToOneTest.java index 5fb5d37269c0..6d4aeeec7404 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/definition/ForeignKeyDefinitionOneToOneTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/definition/ForeignKeyDefinitionOneToOneTest.java @@ -11,22 +11,22 @@ import jakarta.persistence.OneToOne; import org.hibernate.dialect.H2Dialect; - -import org.hibernate.testing.RequiresDialect; +import org.hibernate.testing.orm.junit.RequiresDialect; /** * @author Vlad Mihalcea */ -@RequiresDialect(value = H2Dialect.class) -public class ForeignKeyDefinitionOneToOneTest - extends AbstractForeignKeyDefinitionTest { +@RequiresDialect(H2Dialect.class) +public class ForeignKeyDefinitionOneToOneTest extends AbstractForeignKeyDefinitionTest { @Override protected Class[] getAnnotatedClasses() { - return new Class[] { - Box.class, - Thing.class, - }; + return new Class[] { Box.class, Thing.class }; + } + + @Override + protected boolean validate(String fileContent) { + return fileContent.contains( "/* FK */" ); } @Entity(name = "Box") @@ -44,9 +44,4 @@ public static class Thing { @Id public Integer id; } - - @Override - protected boolean validate(String fileContent) { - return fileContent.contains( "/* FK */" ); - } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/definition/ForeignKeyDefinitionSecondaryTableTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/definition/ForeignKeyDefinitionSecondaryTableTest.java index c55ebd53d604..9d94f109f830 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/definition/ForeignKeyDefinitionSecondaryTableTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/foreignkeys/definition/ForeignKeyDefinitionSecondaryTableTest.java @@ -13,27 +13,28 @@ import jakarta.persistence.Table; import org.hibernate.dialect.H2Dialect; - -import org.hibernate.testing.RequiresDialect; +import org.hibernate.testing.orm.junit.RequiresDialect; /** * @author Vlad Mihalcea */ -@RequiresDialect(value = H2Dialect.class) -public class ForeignKeyDefinitionSecondaryTableTest - extends AbstractForeignKeyDefinitionTest { +@RequiresDialect(H2Dialect.class) +public class ForeignKeyDefinitionSecondaryTableTest extends AbstractForeignKeyDefinitionTest { @Override protected Class[] getAnnotatedClasses() { - return new Class[] { - User.class, - }; + return new Class[] { User.class }; + } + + @Override + protected boolean validate(String fileContent) { + return fileContent.contains( "/* FK */" ); } @Entity(name = "User") @Table(name = "USERS") @SecondaryTable(name = "User_details", foreignKey = @ForeignKey(name = "secondary", foreignKeyDefinition = "foreign key /* FK */ (id) references Users")) - public class User { + public static class User { @Id @GeneratedValue @@ -47,10 +48,4 @@ public class User { @Column(name = "SECURITY_PASSWORD", table = "User_details") private String password; } - - - @Override - protected boolean validate(String fileContent) { - return fileContent.contains( "/* FK */" ); - } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/idbag/IdBagSequenceTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/idbag/IdBagSequenceTest.java index 9a0d5188f06e..8a482ec22811 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/idbag/IdBagSequenceTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/idbag/IdBagSequenceTest.java @@ -4,63 +4,55 @@ */ package org.hibernate.orm.test.schemaupdate.idbag; -import java.io.File; -import java.nio.file.Files; -import java.util.EnumSet; - -import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.boot.spi.MetadataImplementor; -import org.hibernate.cfg.Environment; +import org.hamcrest.MatcherAssert; +import org.hibernate.testing.orm.junit.DialectFeatureChecks; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.RequiresDialectFeature; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.Setting; import org.hibernate.tool.hbm2ddl.SchemaUpdate; import org.hibernate.tool.schema.TargetType; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; -import org.hibernate.testing.DialectChecks; -import org.hibernate.testing.RequiresDialectFeature; -import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.junit4.BaseUnitTestCase; -import org.hibernate.testing.util.ServiceRegistryUtil; -import org.junit.Test; +import java.io.File; +import java.nio.file.Files; +import java.util.EnumSet; import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; +import static org.hibernate.cfg.SchemaToolingSettings.HBM2DDL_AUTO; /** * @author Andrea Boriero */ +@SuppressWarnings("JUnitMalformedDeclaration") @JiraKey(value = "HHH-10373") -@RequiresDialectFeature(DialectChecks.SupportsSequences.class) -public class IdBagSequenceTest extends BaseUnitTestCase { +@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsSequences.class) +@ServiceRegistry(settings = @Setting(name = HBM2DDL_AUTO, value = "none")) +@DomainModel(xmlMappings = "org/hibernate/orm/test/schemaupdate/idbag/Mappings.hbm.xml") +public class IdBagSequenceTest { @Test - public void testIdBagSequenceGeneratorIsCreated() throws Exception { - StandardServiceRegistry ssr = ServiceRegistryUtil.serviceRegistryBuilder() - .applySetting( Environment.HBM2DDL_AUTO, "none" ) - .build(); - try { - File output = File.createTempFile( "update_script", ".sql" ); - output.deleteOnExit(); - - final MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr ) - .addResource( "org/hibernate/orm/test/schemaupdate/idbag/Mappings.hbm.xml" ) - .buildMetadata(); - metadata.orderColumns( false ); - metadata.validate(); - - new SchemaUpdate() - .setHaltOnError( true ) - .setOutputFile( output.getAbsolutePath() ) - .setDelimiter( ";" ) - .setFormat( true ) - .execute( EnumSet.of( TargetType.SCRIPT ), metadata ); - - String fileContent = new String( Files.readAllBytes( output.toPath() ) ); - assertThat( fileContent.toLowerCase().contains( "create sequence seq_child_id" ), is( true ) ); - } - finally { - StandardServiceRegistryBuilder.destroy( ssr ); - } + public void testIdBagSequenceGeneratorIsCreated( + DomainModelScope modelScope, + @TempDir File tmpDir) throws Exception { + final var scriptFile = new File( tmpDir, "update_script.sql" ); + + final var metadata = modelScope.getDomainModel(); + metadata.orderColumns( false ); + metadata.validate(); + + new SchemaUpdate() + .setHaltOnError( true ) + .setOutputFile( scriptFile.getAbsolutePath() ) + .setDelimiter( ";" ) + .setFormat( true ) + .execute( EnumSet.of( TargetType.SCRIPT ), metadata ); + + String fileContent = new String( Files.readAllBytes( scriptFile.toPath() ) ); + MatcherAssert.assertThat( fileContent.toLowerCase().contains( "create sequence seq_child_id" ), is( true ) ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/idgenerator/SequenceGenerationTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/idgenerator/SequenceGenerationTest.java index 41243c75777a..b4b6614f225b 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/idgenerator/SequenceGenerationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/idgenerator/SequenceGenerationTest.java @@ -4,90 +4,65 @@ */ package org.hibernate.orm.test.schemaupdate.idgenerator; -import java.io.File; -import java.nio.file.Files; -import java.util.EnumSet; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.SequenceGenerator; import jakarta.persistence.Table; - -import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.boot.spi.MetadataImplementor; -import org.hibernate.cfg.Environment; +import org.hamcrest.MatcherAssert; import org.hibernate.dialect.H2Dialect; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.Setting; import org.hibernate.tool.hbm2ddl.SchemaExport; import org.hibernate.tool.schema.TargetType; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; -import org.hibernate.testing.RequiresDialect; -import org.hibernate.testing.junit4.BaseUnitTestCase; -import org.hibernate.testing.util.ServiceRegistryUtil; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import java.io.File; +import java.nio.file.Files; +import java.util.EnumSet; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; +import static org.hibernate.cfg.SchemaToolingSettings.HBM2DDL_AUTO; /** * @author Andrea Boriero */ +@SuppressWarnings("JUnitMalformedDeclaration") @RequiresDialect(H2Dialect.class) -public class SequenceGenerationTest extends BaseUnitTestCase { - private StandardServiceRegistry ssr; - private File output; - private MetadataImplementor metadata; +@ServiceRegistry(settings = @Setting(name = HBM2DDL_AUTO, value = "none")) +@DomainModel(annotatedClasses = SequenceGenerationTest.TestEntity.class) +public class SequenceGenerationTest { + @Test + public void testSequenceIsGenerated( + DomainModelScope modelScope, + @TempDir File tmpDir) throws Exception { + final var scriptFile = new File( tmpDir, "update_script.sql" ); - @Before - public void setUp() throws Exception { - ssr = ServiceRegistryUtil.serviceRegistryBuilder() - .applySetting( Environment.HBM2DDL_AUTO, "none" ) - .build(); - output = File.createTempFile( "update_script", ".sql" ); - output.deleteOnExit(); - metadata = (MetadataImplementor) new MetadataSources( ssr ) - .addAnnotatedClass( TestEntity.class ) - .buildMetadata(); + final var metadata = modelScope.getDomainModel(); metadata.orderColumns( false ); metadata.validate(); - } - @Test - public void testSequenceIsGenerated() throws Exception { new SchemaExport() - .setOutputFile( output.getAbsolutePath() ) - .create( EnumSet.of( TargetType.SCRIPT, TargetType.DATABASE ), metadata ); + .setOutputFile( scriptFile.getAbsolutePath() ) + .create( EnumSet.of( TargetType.SCRIPT ), metadata ); - List commands = Files.readAllLines( output.toPath() ); + List commands = Files.readAllLines( scriptFile.toPath() ); - assertThat( + MatcherAssert.assertThat( isCommandGenerated( commands, "create table test_entity \\(id .*, primary key \\(id\\)\\);" ), - is( true ) - ); + is( true ) ); - assertThat( + MatcherAssert.assertThat( isCommandGenerated( commands, "create sequence sequence_generator start with 5 increment by 3;" ), - is( true ) - ); - } - - @After - public void tearDown() { - try { - new SchemaExport() - .drop( EnumSet.of( TargetType.DATABASE ), metadata ); - } - finally { - StandardServiceRegistryBuilder.destroy( ssr ); - } - + is( true ) ); } private boolean isCommandGenerated(List commands, String expectedCommnad) { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/idgenerator/SequenceGeneratorsTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/idgenerator/SequenceGeneratorsTest.java index 853aab3704b6..2cab40bbbaea 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/idgenerator/SequenceGeneratorsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/idgenerator/SequenceGeneratorsTest.java @@ -4,12 +4,6 @@ */ package org.hibernate.orm.test.schemaupdate.idgenerator; -import java.io.File; -import java.nio.file.Files; -import java.util.EnumSet; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; @@ -17,78 +11,59 @@ import jakarta.persistence.SequenceGenerator; import jakarta.persistence.SequenceGenerators; import jakarta.persistence.Table; - -import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.boot.spi.MetadataImplementor; -import org.hibernate.cfg.Environment; +import org.hamcrest.MatcherAssert; import org.hibernate.dialect.H2Dialect; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.Setting; import org.hibernate.tool.hbm2ddl.SchemaExport; import org.hibernate.tool.schema.TargetType; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; -import org.hibernate.testing.RequiresDialect; -import org.hibernate.testing.junit4.BaseUnitTestCase; -import org.hibernate.testing.util.ServiceRegistryUtil; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import java.io.File; +import java.nio.file.Files; +import java.util.EnumSet; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; +import static org.hibernate.cfg.SchemaToolingSettings.HBM2DDL_AUTO; /** * @author Andrea Boriero */ +@SuppressWarnings("JUnitMalformedDeclaration") @RequiresDialect(H2Dialect.class) -public class SequenceGeneratorsTest extends BaseUnitTestCase { - private StandardServiceRegistry ssr; - private File output; - private MetadataImplementor metadata; +@ServiceRegistry(settings = @Setting(name = HBM2DDL_AUTO, value = "none")) +@DomainModel(annotatedClasses = SequenceGeneratorsTest.TestEntity.class) +public class SequenceGeneratorsTest { + @Test + public void testSequenceIsGenerated( + DomainModelScope modelScope, + @TempDir File tmpDir) throws Exception { + final var scriptFile = new File( tmpDir, "update_script.sql" ); - @Before - public void setUp() throws Exception { - ssr = ServiceRegistryUtil.serviceRegistryBuilder() - .applySetting( Environment.HBM2DDL_AUTO, "none" ) - .build(); - output = File.createTempFile( "update_script", ".sql" ); - output.deleteOnExit(); - metadata = (MetadataImplementor) new MetadataSources( ssr ) - .addAnnotatedClass( TestEntity.class ) - .buildMetadata(); + final var metadata = modelScope.getDomainModel(); metadata.orderColumns( false ); metadata.validate(); - } - @Test - public void testSequenceIsGenerated() throws Exception { new SchemaExport() - .setOutputFile( output.getAbsolutePath() ) - .create( EnumSet.of( TargetType.SCRIPT, TargetType.DATABASE ), metadata ); + .setOutputFile( scriptFile.getAbsolutePath() ) + .create( EnumSet.of( TargetType.SCRIPT ), metadata ); - List commands = Files.readAllLines( output.toPath() ); + var commands = Files.readAllLines( scriptFile.toPath() ); - assertThat( + MatcherAssert.assertThat( isCommandGenerated( commands, "CREATE TABLE TEST_ENTITY \\(ID .*, PRIMARY KEY \\(ID\\)\\);" ), - is( true ) - ); + is( true ) ); - assertThat( + MatcherAssert.assertThat( isCommandGenerated( commands, "CREATE SEQUENCE SEQUENCE_GENERATOR START WITH 5 INCREMENT BY 3;" ), - is( true ) - ); - } - - @After - public void tearDown() { - try { - new SchemaExport() - .drop( EnumSet.of( TargetType.DATABASE ), metadata ); - } - finally { - StandardServiceRegistryBuilder.destroy( ssr ); - } - + is( true ) ); } private boolean isCommandGenerated(List commands, String expectedCommnad) { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/idgenerator/TableGeneratorTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/idgenerator/TableGeneratorTest.java index b8c33a76e34c..ace935f5bb70 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/idgenerator/TableGeneratorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/idgenerator/TableGeneratorTest.java @@ -4,109 +4,74 @@ */ package org.hibernate.orm.test.schemaupdate.idgenerator; -import java.io.File; -import java.nio.file.Files; -import java.util.EnumSet; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.Table; import jakarta.persistence.TableGenerator; - -import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.boot.spi.MetadataImplementor; -import org.hibernate.cfg.Environment; import org.hibernate.dialect.H2Dialect; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.Setting; import org.hibernate.tool.hbm2ddl.SchemaExport; import org.hibernate.tool.schema.TargetType; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; -import org.hibernate.testing.RequiresDialect; -import org.hibernate.testing.junit4.BaseUnitTestCase; -import org.hibernate.testing.util.ServiceRegistryUtil; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import java.io.File; +import java.nio.file.Files; +import java.util.EnumSet; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; -import static org.junit.Assert.assertTrue; +import static org.hibernate.cfg.SchemaToolingSettings.HBM2DDL_AUTO; /** * @author Andrea Boriero */ +@SuppressWarnings("JUnitMalformedDeclaration") @RequiresDialect(H2Dialect.class) -public class TableGeneratorTest extends BaseUnitTestCase { +@ServiceRegistry(settings = @Setting(name = HBM2DDL_AUTO, value = "none")) +@DomainModel(annotatedClasses = TableGeneratorTest.TestEntity.class) +public class TableGeneratorTest { - private StandardServiceRegistry ssr; - private File output; - private MetadataImplementor metadata; private static final int INITIAL_VALUE = 5; private static final int EXPECTED_DB_INSERTED_VALUE = INITIAL_VALUE; - @Before - public void setUp() throws Exception { - ssr = ServiceRegistryUtil.serviceRegistryBuilder() - .applySetting( Environment.HBM2DDL_AUTO, "none" ) - .build(); - - output = File.createTempFile( "update_script", ".sql" ); - output.deleteOnExit(); + @Test + public void testTableGeneratorIsGenerated(DomainModelScope modelScope, @TempDir File tmpDir) throws Exception { + final var scriptFile = new File( tmpDir, "update_script.sql" ); - metadata = (MetadataImplementor) new MetadataSources( ssr ) - .addAnnotatedClass( TestEntity.class ) - .buildMetadata(); + final var metadata = modelScope.getDomainModel(); metadata.orderColumns( true ); metadata.validate(); - } - @Test - public void testTableGeneratorIsGenerated() throws Exception { new SchemaExport() - .setOutputFile( output.getAbsolutePath() ) - .create( EnumSet.of( TargetType.SCRIPT, TargetType.DATABASE ), metadata ); + .setOutputFile( scriptFile.getAbsolutePath() ) + .create( EnumSet.of( TargetType.SCRIPT ), metadata ); - final List commands = Files.readAllLines( output.toPath() ); + final List commands = Files.readAllLines( scriptFile.toPath() ); final String expectedTestEntityTableCreationCommand = "CREATE TABLE TEST_ENTITY \\(ID .*, PRIMARY KEY \\(ID\\)\\);"; - assertTrue( - "The command '" + expectedTestEntityTableCreationCommand + "' has not been correctly generated", - isCommandGenerated( commands, expectedTestEntityTableCreationCommand ) - ); + Assertions.assertTrue( isCommandGenerated( commands, expectedTestEntityTableCreationCommand ), + "The command '" + expectedTestEntityTableCreationCommand + "' has not been correctly generated" ); final String expectedIdTableGeneratorCreationCommand = "CREATE TABLE ID_TABLE_GENERATOR \\(VALUE .*, PK .*, PRIMARY KEY \\(PK\\)\\);"; - - assertTrue( - "The command '" + expectedIdTableGeneratorCreationCommand + "' has not been correctly generated", - - isCommandGenerated( - commands, - expectedIdTableGeneratorCreationCommand - ) - ); + Assertions.assertTrue( isCommandGenerated( + commands, + expectedIdTableGeneratorCreationCommand + ), "The command '" + expectedIdTableGeneratorCreationCommand + "' has not been correctly generated" ); final String expectedInsertIntoTableGeneratorCommand = "INSERT INTO ID_TABLE_GENERATOR\\(PK, VALUE\\) VALUES \\('TEST_ENTITY_ID'," + EXPECTED_DB_INSERTED_VALUE + "\\);"; - - assertTrue( - "The command '" + expectedInsertIntoTableGeneratorCommand + "' has not been correctly generated", - isCommandGenerated( - commands, - expectedInsertIntoTableGeneratorCommand - ) - ); - } - - @After - public void tearDown() { - try { - new SchemaExport().drop( EnumSet.of( TargetType.DATABASE ), metadata ); - } - finally { - StandardServiceRegistryBuilder.destroy( ssr ); - } + Assertions.assertTrue( isCommandGenerated( + commands, + expectedInsertIntoTableGeneratorCommand + ), "The command '" + expectedInsertIntoTableGeneratorCommand + "' has not been correctly generated" ); } @Entity(name = "TestEntity") diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/idgenerator/TableGeneratorsTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/idgenerator/TableGeneratorsTest.java index b9cfc3b5f3e3..e996ed860cb3 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/idgenerator/TableGeneratorsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/idgenerator/TableGeneratorsTest.java @@ -4,123 +4,84 @@ */ package org.hibernate.orm.test.schemaupdate.idgenerator; -import java.io.File; -import java.nio.file.Files; -import java.util.EnumSet; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.Table; import jakarta.persistence.TableGenerator; -import jakarta.persistence.TableGenerators; - -import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.boot.spi.MetadataImplementor; -import org.hibernate.cfg.Environment; import org.hibernate.dialect.H2Dialect; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.Setting; import org.hibernate.tool.hbm2ddl.SchemaExport; import org.hibernate.tool.schema.TargetType; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; -import org.hibernate.testing.RequiresDialect; -import org.hibernate.testing.junit4.BaseUnitTestCase; -import org.hibernate.testing.util.ServiceRegistryUtil; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import java.io.File; +import java.nio.file.Files; +import java.util.EnumSet; +import java.util.List; +import java.util.regex.Matcher; +import java.util.regex.Pattern; -import static org.junit.Assert.assertTrue; +import static org.hibernate.cfg.SchemaToolingSettings.HBM2DDL_AUTO; /** * @author Andrea Boriero */ +@SuppressWarnings("JUnitMalformedDeclaration") @RequiresDialect(H2Dialect.class) -public class TableGeneratorsTest extends BaseUnitTestCase { - - private StandardServiceRegistry ssr; - private File output; - private MetadataImplementor metadata; +@ServiceRegistry(settings = @Setting(name = HBM2DDL_AUTO, value = "none")) +@DomainModel(annotatedClasses = TableGeneratorsTest.TestEntity.class) +public class TableGeneratorsTest { private static final int INITIAL_VALUE = 5; private static final int EXPECTED_DB_INSERTED_VALUE = INITIAL_VALUE; - @Before - public void setUp() throws Exception { - ssr = ServiceRegistryUtil.serviceRegistryBuilder() - .applySetting( Environment.HBM2DDL_AUTO, "none" ) - .build(); - - output = File.createTempFile( "update_script", ".sql" ); - output.deleteOnExit(); + @Test + public void testTableGeneratorIsGenerated(DomainModelScope modelScope, @TempDir File tmpDir) throws Exception { + final var scriptFile = new File( tmpDir, "update_script.sql" ); - metadata = (MetadataImplementor) new MetadataSources( ssr ) - .addAnnotatedClass( TestEntity.class ) - .buildMetadata(); + final var metadata = modelScope.getDomainModel(); metadata.orderColumns( true ); metadata.validate(); - } - @Test - public void testTableGeneratorIsGenerated() throws Exception { new SchemaExport() - .setOutputFile( output.getAbsolutePath() ) - .create( EnumSet.of( TargetType.SCRIPT, TargetType.DATABASE ), metadata ); + .setOutputFile( scriptFile.getAbsolutePath() ) + .create( EnumSet.of( TargetType.SCRIPT ), metadata ); - final List commands = Files.readAllLines( output.toPath() ); + final List commands = Files.readAllLines( scriptFile.toPath() ); final String expectedTestEntityTableCreationCommand = "CREATE TABLE TEST_ENTITY \\(ID .*, PRIMARY KEY \\(ID\\)\\);"; - assertTrue( - "The command '" + expectedTestEntityTableCreationCommand + "' has not been correctly generated", - isCommandGenerated( commands, expectedTestEntityTableCreationCommand ) - ); + Assertions.assertTrue( isCommandGenerated( commands, expectedTestEntityTableCreationCommand ), + "The command '" + expectedTestEntityTableCreationCommand + "' has not been correctly generated" ); final String expectedIdTableGeneratorCreationCommand = "CREATE TABLE ID_TABLE_GENERATOR \\(VALUE .*, PK .*, PRIMARY KEY \\(PK\\)\\);"; - - assertTrue( - "The command '" + expectedIdTableGeneratorCreationCommand + "' has not been correctly generated", - - isCommandGenerated( - commands, - expectedIdTableGeneratorCreationCommand - ) - ); + Assertions.assertTrue( isCommandGenerated( + commands, + expectedIdTableGeneratorCreationCommand + ), "The command '" + expectedIdTableGeneratorCreationCommand + "' has not been correctly generated" ); final String expectedInsertIntoTableGeneratorCommand = "INSERT INTO ID_TABLE_GENERATOR\\(PK, VALUE\\) VALUES \\('TEST_ENTITY_ID'," + EXPECTED_DB_INSERTED_VALUE + "\\);"; - - assertTrue( - "The command '" + expectedInsertIntoTableGeneratorCommand + "' has not been correctly generated", - isCommandGenerated( - commands, - expectedInsertIntoTableGeneratorCommand - ) - ); - } - - @After - public void tearDown() { - try { - new SchemaExport().drop( EnumSet.of( TargetType.DATABASE ), metadata ); - } - finally { - StandardServiceRegistryBuilder.destroy( ssr ); - } + Assertions.assertTrue( isCommandGenerated( + commands, + expectedInsertIntoTableGeneratorCommand + ), "The command '" + expectedInsertIntoTableGeneratorCommand + "' has not been correctly generated" ); } @Entity(name = "TestEntity") @Table(name = "TEST_ENTITY") - @TableGenerators({ - @TableGenerator(name = "tableGenerator", - table = "ID_TABLE_GENERATOR", - pkColumnName = "PK", - pkColumnValue = "TEST_ENTITY_ID", - valueColumnName = "VALUE", - allocationSize = 3, - initialValue = INITIAL_VALUE) - } + @TableGenerator(name = "tableGenerator", + table = "ID_TABLE_GENERATOR", + pkColumnName = "PK", + pkColumnValue = "TEST_ENTITY_ID", + valueColumnName = "VALUE", + allocationSize = 3, + initialValue = INITIAL_VALUE ) public static class TestEntity { Long id; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/index/ComponentIndexTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/index/ComponentIndexTest.java index 865ddd2d4433..38511cb69e90 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/index/ComponentIndexTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/index/ComponentIndexTest.java @@ -4,50 +4,36 @@ */ package org.hibernate.orm.test.schemaupdate.index; -import java.util.List; import jakarta.persistence.Embeddable; import jakarta.persistence.Embedded; import jakarta.persistence.Entity; import jakarta.persistence.Id; - import jakarta.persistence.Index; import jakarta.persistence.Table; -import org.hibernate.boot.Metadata; -import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.tool.schema.internal.SchemaCreatorImpl; - +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.util.ServiceRegistryUtil; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.ServiceRegistryScope; +import org.hibernate.tool.schema.internal.SchemaCreatorImpl; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertTrue; +import java.util.List; /** * @author Andrea Boriero */ +@SuppressWarnings("JUnitMalformedDeclaration") @JiraKey( value = "HHH-11815") +@ServiceRegistry +@DomainModel(annotatedClasses = ComponentIndexTest.User.class) public class ComponentIndexTest { - private StandardServiceRegistry ssr; - private Metadata metadata; - - @Before - public void setUp(){ - ssr = ServiceRegistryUtil.serviceRegistry(); - metadata = new MetadataSources( ssr ) - .addAnnotatedClass( User.class ) - .buildMetadata(); - } @Test - public void testTheIndexIsGenerated() { - final List commands = new SchemaCreatorImpl( ssr ).generateCreationCommands( - metadata, - false - ); + public void testTheIndexIsGenerated(ServiceRegistryScope registryScope, DomainModelScope modelScope) { + final List commands = new SchemaCreatorImpl( registryScope.getRegistry() ) + .generateCreationCommands( modelScope.getDomainModel(), false ); assertThatCreateIndexCommandIsGenerated( commands ); } @@ -57,22 +43,15 @@ private void assertThatCreateIndexCommandIsGenerated(List commands) { for ( String command : commands ) { if ( command.toLowerCase().contains( "create index city_index" ) ) { createIndexCommandIsGenerated = true; + break; } } - assertTrue( - "Expected create index command not found", - createIndexCommandIsGenerated - ); - } - - @After - public void tearDown(){ - StandardServiceRegistryBuilder.destroy( ssr ); + Assertions.assertTrue( createIndexCommandIsGenerated, "Expected create index command not found" ); } @Entity(name = "user") @Table(indexes = @Index(name = "city_index", columnList = "city")) - public class User { + public static class User { @Id private Long id; @Embedded @@ -80,7 +59,7 @@ public class User { } @Embeddable - public class Address { + public static class Address { private String city; private String street; private String postalCode; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/index/IndexesCreationTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/index/IndexesCreationTest.java index bc1b82547067..4868231a6d84 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/index/IndexesCreationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/index/IndexesCreationTest.java @@ -4,54 +4,38 @@ */ package org.hibernate.orm.test.schemaupdate.index; -import java.util.List; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.Id; import jakarta.persistence.Index; import jakarta.persistence.Table; - -import org.hibernate.boot.Metadata; -import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.dialect.H2Dialect; import org.hibernate.dialect.MySQLDialect; import org.hibernate.dialect.PostgreSQLDialect; -import org.hibernate.tool.schema.internal.SchemaCreatorImpl; - -import org.hibernate.testing.RequiresDialect; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.junit4.BaseUnitTestCase; -import org.hibernate.testing.util.ServiceRegistryUtil; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.ServiceRegistryScope; +import org.hibernate.tool.schema.internal.SchemaCreatorImpl; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; -import static org.junit.Assert.assertTrue; +import java.util.List; +@SuppressWarnings("JUnitMalformedDeclaration") @JiraKey(value = "HHH-11913") @RequiresDialect(H2Dialect.class) @RequiresDialect(PostgreSQLDialect.class) @RequiresDialect(MySQLDialect.class) -public class IndexesCreationTest extends BaseUnitTestCase { - private StandardServiceRegistry ssr; - private Metadata metadata; - - @Before - public void setUp() { - ssr = ServiceRegistryUtil.serviceRegistry(); - metadata = new MetadataSources( ssr ) - .addAnnotatedClass( TestEntity.class ) - .buildMetadata(); - } - +@ServiceRegistry +@DomainModel(annotatedClasses = IndexesCreationTest.TestEntity.class) +public class IndexesCreationTest { @Test - public void testTheIndexIsGenerated() { - final List commands = new SchemaCreatorImpl( ssr ).generateCreationCommands( - metadata, - false - ); + public void testTheIndexIsGenerated(ServiceRegistryScope registryScope, DomainModelScope modelScope) { + final List commands = new SchemaCreatorImpl( registryScope.getRegistry() ) + .generateCreationCommands( modelScope.getDomainModel(), false ); assertThatCreateIndexCommandIsGenerated( "CREATE INDEX FIELD_1_INDEX ON TEST_ENTITY (FIELD_1)", commands ); assertThatCreateIndexCommandIsGenerated( @@ -69,18 +53,10 @@ private void assertThatCreateIndexCommandIsGenerated(String expectedCommand, Lis for ( String command : commands ) { if ( command.toLowerCase().contains( expectedCommand.toLowerCase() ) ) { createIndexCommandIsGenerated = true; + break; } } - assertTrue( - - "Expected " + expectedCommand + " command not found", - createIndexCommandIsGenerated - ); - } - - @After - public void tearDown() { - StandardServiceRegistryBuilder.destroy( ssr ); + Assertions.assertTrue( createIndexCommandIsGenerated, "Expected " + expectedCommand + " command not found" ); } @Entity(name = "TestEntity") diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/inheritance/ForeignKeyNameTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/inheritance/ForeignKeyNameTest.java index 6a3feb217aea..ffff8c5c0aa9 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/inheritance/ForeignKeyNameTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/inheritance/ForeignKeyNameTest.java @@ -4,92 +4,78 @@ */ package org.hibernate.orm.test.schemaupdate.inheritance; -import java.io.File; -import java.nio.file.Files; -import java.util.EnumSet; - -import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.boot.spi.MetadataImplementor; -import org.hibernate.cfg.Environment; +import org.hamcrest.MatcherAssert; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.Setting; import org.hibernate.tool.hbm2ddl.SchemaUpdate; import org.hibernate.tool.schema.TargetType; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; -import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.junit4.BaseUnitTestCase; -import org.hibernate.testing.util.ServiceRegistryUtil; -import org.junit.Test; +import java.io.File; +import java.nio.file.Files; +import java.util.EnumSet; import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; +import static org.hibernate.cfg.SchemaToolingSettings.HBM2DDL_AUTO; /** * @author Andrea Boriero */ -public class ForeignKeyNameTest extends BaseUnitTestCase { +@SuppressWarnings("JUnitMalformedDeclaration") +@ServiceRegistry(settings = @Setting(name = HBM2DDL_AUTO, value = "none")) +public class ForeignKeyNameTest { @Test @JiraKey(value = "HHH-10169") - public void testJoinedSubclassForeignKeyNameIsNotAutoGeneratedWhenProvided() throws Exception { - StandardServiceRegistry ssr = ServiceRegistryUtil.serviceRegistryBuilder() - .applySetting( Environment.HBM2DDL_AUTO, "none" ) - .build(); - try { - File output = File.createTempFile( "update_script", ".sql" ); - output.deleteOnExit(); + @DomainModel(xmlMappings = { + "org/hibernate/orm/test/schemaupdate/inheritance/Employee.hbm.xml", + "org/hibernate/orm/test/schemaupdate/inheritance/Person.hbm.xml", + "org/hibernate/orm/test/schemaupdate/inheritance/Manager.hbm.xml", + "org/hibernate/orm/test/schemaupdate/inheritance/Payment.hbm.xml" + }) + public void testJoinedSubclassForeignKeyNameIsNotAutoGeneratedWhenProvided( + DomainModelScope modelScope, + @TempDir File tmpDir) throws Exception { + final var scriptFile = new File( tmpDir, "update_script.sql" ); - final MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr ) - .addResource( "org/hibernate/orm/test/schemaupdate/inheritance/Employee.hbm.xml" ) - .addResource( "org/hibernate/orm/test/schemaupdate/inheritance/Person.hbm.xml" ) - .addResource( "org/hibernate/orm/test/schemaupdate/inheritance/Manager.hbm.xml" ) - .addResource( "org/hibernate/orm/test/schemaupdate/inheritance/Payment.hbm.xml" ) - .buildMetadata(); - metadata.orderColumns( false ); - metadata.validate(); + final var metadata = modelScope.getDomainModel(); + metadata.orderColumns( false ); + metadata.validate(); - new SchemaUpdate() - .setHaltOnError( true ) - .setOutputFile( output.getAbsolutePath() ) - .setDelimiter( ";" ) - .setFormat( true ) - .execute( EnumSet.of( TargetType.SCRIPT ), metadata ); + new SchemaUpdate() + .setHaltOnError( true ) + .setOutputFile( scriptFile.getAbsolutePath() ) + .setDelimiter( ";" ) + .setFormat( true ) + .execute( EnumSet.of( TargetType.SCRIPT ), metadata ); - String fileContent = new String( Files.readAllBytes( output.toPath() ) ); - assertThat( fileContent.toLowerCase().contains( "fk_emp_per" ), is( true ) ); - } - finally { - StandardServiceRegistryBuilder.destroy( ssr ); - } + String fileContent = new String( Files.readAllBytes( scriptFile.toPath() ) ); + MatcherAssert.assertThat( fileContent.toLowerCase().contains( "fk_emp_per" ), is( true ) ); } @Test - public void testSubclassForeignKeyNameIsNotAutoGeneratedWhenProvided() throws Exception { - StandardServiceRegistry ssr = ServiceRegistryUtil.serviceRegistryBuilder() - .applySetting( Environment.HBM2DDL_AUTO, "none" ) - .build(); - try { - File output = File.createTempFile( "update_script", ".sql" ); - output.deleteOnExit(); + @DomainModel(xmlMappings = "org/hibernate/orm/test/schemaupdate/inheritance/Payment.hbm.xml") + public void testSubclassForeignKeyNameIsNotAutoGeneratedWhenProvided( + DomainModelScope modelScope, + @TempDir File tmpDir) throws Exception { + final var scriptFile = new File( tmpDir, "update_script.sql" ); - final MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr ) - .addResource( "org/hibernate/orm/test/schemaupdate/inheritance/Payment.hbm.xml" ) - .buildMetadata(); - metadata.orderColumns( false ); - metadata.validate(); + final var metadata = modelScope.getDomainModel(); + metadata.orderColumns( false ); + metadata.validate(); - new SchemaUpdate() - .setHaltOnError( true ) - .setOutputFile( output.getAbsolutePath() ) - .setDelimiter( ";" ) - .setFormat( true ) - .execute( EnumSet.of( TargetType.SCRIPT ), metadata ); + new SchemaUpdate() + .setHaltOnError( true ) + .setOutputFile( scriptFile.getAbsolutePath() ) + .setDelimiter( ";" ) + .setFormat( true ) + .execute( EnumSet.of( TargetType.SCRIPT ), metadata ); - String fileContent = new String( Files.readAllBytes( output.toPath() ) ); - assertThat( fileContent.toLowerCase().contains( "fk_cc_pay" ), is( true ) ); - } - finally { - StandardServiceRegistryBuilder.destroy( ssr ); - } + String fileContent = new String( Files.readAllBytes( scriptFile.toPath() ) ); + MatcherAssert.assertThat( fileContent.toLowerCase().contains( "fk_cc_pay" ), is( true ) ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/inheritance/hhh_x/InheritanceSchemaUpdateTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/inheritance/hhh_x/InheritanceSchemaUpdateTest.java index fe1b91889cd7..07409275bc12 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/inheritance/hhh_x/InheritanceSchemaUpdateTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/inheritance/hhh_x/InheritanceSchemaUpdateTest.java @@ -4,49 +4,39 @@ */ package org.hibernate.orm.test.schemaupdate.inheritance.hhh_x; -import java.util.EnumSet; - -import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.boot.spi.MetadataImplementor; +import org.hibernate.testing.orm.junit.DialectFeatureChecks; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; +import org.hibernate.testing.orm.junit.RequiresDialectFeature; +import org.hibernate.testing.orm.junit.ServiceRegistry; import org.hibernate.tool.hbm2ddl.SchemaExport; import org.hibernate.tool.hbm2ddl.SchemaUpdate; import org.hibernate.tool.schema.TargetType; +import org.junit.jupiter.api.Test; + +import java.util.EnumSet; -import org.hibernate.testing.DialectChecks; -import org.hibernate.testing.RequiresDialectFeature; -import org.hibernate.testing.junit4.BaseUnitTestCase; -import org.hibernate.testing.util.ServiceRegistryUtil; -import org.junit.Test; /** * @author Andrea Boriero */ -@RequiresDialectFeature( value = DialectChecks.SupportsIdentityColumns.class) -public class InheritanceSchemaUpdateTest extends BaseUnitTestCase { +@SuppressWarnings("JUnitMalformedDeclaration") +@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsIdentityColumns.class) +@ServiceRegistry +@DomainModel(annotatedClasses = {Step.class, GroupStep.class}) +public class InheritanceSchemaUpdateTest { @Test - public void testBidirectionalOneToManyReferencingRootEntity() throws Exception { - StandardServiceRegistry ssr = ServiceRegistryUtil.serviceRegistry(); + public void testBidirectionalOneToManyReferencingRootEntity(DomainModelScope modelScope) { + final var metadata = modelScope.getDomainModel(); + metadata.orderColumns( false ); + metadata.validate(); try { - MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr ) - .addAnnotatedClass( Step.class ) - .addAnnotatedClass( GroupStep.class ) - .buildMetadata(); - metadata.orderColumns( false ); - metadata.validate(); - - try { - new SchemaUpdate().execute( EnumSet.of( TargetType.DATABASE ), metadata ); - } - finally { - new SchemaExport().drop( EnumSet.of( TargetType.DATABASE ), metadata ); - } + new SchemaUpdate().execute( EnumSet.of( TargetType.DATABASE ), metadata ); } finally { - StandardServiceRegistryBuilder.destroy( ssr ); + new SchemaExport().drop( EnumSet.of( TargetType.DATABASE ), metadata ); } } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/inheritance/tableperclass/SchemaCreationTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/inheritance/tableperclass/SchemaCreationTest.java index 7af0534b64c3..a7f6451a7773 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/inheritance/tableperclass/SchemaCreationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/inheritance/tableperclass/SchemaCreationTest.java @@ -4,82 +4,63 @@ */ package org.hibernate.orm.test.schemaupdate.inheritance.tableperclass; +import org.hamcrest.MatcherAssert; +import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.ServiceRegistryScope; +import org.hibernate.tool.hbm2ddl.SchemaExport; +import org.hibernate.tool.schema.TargetType; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; + import java.io.File; -import java.io.IOException; import java.nio.charset.Charset; import java.nio.file.Files; import java.sql.Types; import java.util.EnumSet; import java.util.List; -import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.boot.spi.MetadataImplementor; -import org.hibernate.dialect.Dialect; -import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; -import org.hibernate.tool.hbm2ddl.SchemaExport; -import org.hibernate.tool.schema.TargetType; - -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - -import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.util.ServiceRegistryUtil; - import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; /** * @author Andrea Boriero */ +@SuppressWarnings("JUnitMalformedDeclaration") +@ServiceRegistry +@DomainModel(annotatedClasses = {Element.class, Category.class}) public class SchemaCreationTest { - private File output; - private StandardServiceRegistry ssr; - private MetadataImplementor metadata; - private Dialect dialect; - - @Before - public void setUp() throws IOException { - output = File.createTempFile( "update_script", ".sql" ); - output.deleteOnExit(); - ssr = ServiceRegistryUtil.serviceRegistry(); - dialect = ssr.getService(JdbcEnvironment.class).getDialect(); - } - - @After - public void tearsDown() { - StandardServiceRegistryBuilder.destroy( ssr ); - } @Test @JiraKey(value = "HHH-10553") - public void testUniqueConstraintIsCorrectlyGenerated() throws Exception { - - final MetadataSources metadataSources = new MetadataSources( ssr ); + public void testUniqueConstraintIsCorrectlyGenerated( + ServiceRegistryScope registryScope, + DomainModelScope modelScope, + @TempDir File tmpDir) throws Exception { + final var scriptFile = new File( tmpDir, "update_script.sql" ); - metadataSources.addAnnotatedClass( Element.class ); - metadataSources.addAnnotatedClass( Category.class ); - metadata = (MetadataImplementor) metadataSources.buildMetadata(); + final var metadata = modelScope.getDomainModel(); metadata.orderColumns( false ); metadata.validate(); + final SchemaExport schemaExport = new SchemaExport( ) .setHaltOnError( true ) - .setOutputFile( output.getAbsolutePath() ) + .setOutputFile( scriptFile.getAbsolutePath() ) .setFormat( false ); schemaExport.create( EnumSet.of( TargetType.SCRIPT ), metadata ); - final List sqlLines = Files.readAllLines( output.toPath(), Charset.defaultCharset() ); + final List sqlLines = Files.readAllLines( scriptFile.toPath(), Charset.defaultCharset() ); + + final var dialect = registryScope.getRegistry().requireService( JdbcEnvironment.class ).getDialect(); boolean isUniqueConstraintCreated = false; for ( String statement : sqlLines ) { statement = statement.toLowerCase(); - assertThat( + MatcherAssert.assertThat( "Should not try to create the unique constraint for the non existing table element", - statement.matches( dialect.getAlterTableString( "element" ) ), - is( false ) - ); + statement.matches( dialect.getAlterTableString( "element" ) ), is( false ) ); String varchar255 = metadata.getTypeConfiguration().getDdlTypeRegistry() .getTypeName(Types.VARCHAR,255L,0,0); isUniqueConstraintCreated = isUniqueConstraintCreated @@ -97,10 +78,7 @@ public void testUniqueConstraintIsCorrectlyGenerated() throws Exception { && statement.contains("unique(code)"); } - assertThat( - "Unique constraint for table category is not created", - isUniqueConstraintCreated, - is( true ) - ); + MatcherAssert.assertThat( "Unique constraint for table category is not created", isUniqueConstraintCreated, + is( true ) ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/manytomany/ForeignKeyNameTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/manytomany/ForeignKeyNameTest.java index c7e71a7a3f7d..cb690f45c52e 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/manytomany/ForeignKeyNameTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/manytomany/ForeignKeyNameTest.java @@ -4,59 +4,51 @@ */ package org.hibernate.orm.test.schemaupdate.manytomany; -import java.io.File; -import java.nio.file.Files; -import java.util.EnumSet; - -import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.boot.spi.MetadataImplementor; -import org.hibernate.cfg.Environment; +import org.hamcrest.MatcherAssert; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.Setting; import org.hibernate.tool.hbm2ddl.SchemaExport; import org.hibernate.tool.schema.TargetType; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; -import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.junit4.BaseUnitTestCase; -import org.hibernate.testing.util.ServiceRegistryUtil; -import org.junit.Test; +import java.io.File; +import java.nio.file.Files; +import java.util.EnumSet; import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; +import static org.hibernate.cfg.SchemaToolingSettings.HBM2DDL_AUTO; /** * @author Andrea Boriero */ -public class ForeignKeyNameTest extends BaseUnitTestCase { +@SuppressWarnings("JUnitMalformedDeclaration") +@ServiceRegistry(settings = @Setting(name = HBM2DDL_AUTO, value = "none")) +@DomainModel(xmlMappings = "org/hibernate/orm/test/schemaupdate/manytomany/UserGroup.hbm.xml") +public class ForeignKeyNameTest { @Test @JiraKey(value = "HHH-10247") - public void testJoinedSubclassForeignKeyNameIsNotAutoGeneratedWhenProvided() throws Exception { - StandardServiceRegistry ssr = ServiceRegistryUtil.serviceRegistryBuilder() - .applySetting( Environment.HBM2DDL_AUTO, "none" ) - .build(); - try { - File output = File.createTempFile( "update_script", ".sql" ); - output.deleteOnExit(); - - final MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr ) - .addResource( "org/hibernate/orm/test/schemaupdate/manytomany/UserGroup.hbm.xml" ) - .buildMetadata(); - metadata.orderColumns( false ); - metadata.validate(); - - new SchemaExport() - .setOutputFile( output.getAbsolutePath() ) - .setDelimiter( ";" ) - .setFormat( true ) - .create( EnumSet.of( TargetType.SCRIPT ), metadata ); - - String fileContent = new String( Files.readAllBytes( output.toPath() ) ); - assertThat( fileContent.toLowerCase().contains( "fk_user_group" ), is( true ) ); - assertThat( fileContent.toLowerCase().contains( "fk_group_user" ), is( true ) ); - } - finally { - StandardServiceRegistryBuilder.destroy( ssr ); - } + public void testJoinedSubclassForeignKeyNameIsNotAutoGeneratedWhenProvided( + DomainModelScope modelScope, + @TempDir File tmpDir) throws Exception { + final var scriptFile = new File( tmpDir, "script.sql" ); + + final var metadata = modelScope.getDomainModel(); + metadata.orderColumns( false ); + metadata.validate(); + + new SchemaExport() + .setOutputFile( scriptFile.getAbsolutePath() ) + .setDelimiter( ";" ) + .setFormat( true ) + .create( EnumSet.of( TargetType.SCRIPT ), metadata ); + + String fileContent = new String( Files.readAllBytes( scriptFile.toPath() ) ); + MatcherAssert.assertThat( fileContent.toLowerCase().contains( "fk_user_group" ), is( true ) ); + MatcherAssert.assertThat( fileContent.toLowerCase().contains( "fk_group_user" ), is( true ) ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/uniqueconstraint/UniqueConstraintDropTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/uniqueconstraint/UniqueConstraintDropTest.java index 7bc6e65b0650..5ac7a5dc9860 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/uniqueconstraint/UniqueConstraintDropTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/uniqueconstraint/UniqueConstraintDropTest.java @@ -4,26 +4,20 @@ */ package org.hibernate.orm.test.schemaupdate.uniqueconstraint; -import java.io.File; -import java.io.IOException; -import java.nio.charset.Charset; -import java.nio.file.Files; -import java.util.EnumSet; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.hibernate.boot.MetadataSources; +import org.hamcrest.MatcherAssert; import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.boot.spi.MetadataImplementor; -import org.hibernate.cfg.Environment; import org.hibernate.dialect.Dialect; import org.hibernate.dialect.unique.AlterTableUniqueDelegate; import org.hibernate.dialect.unique.AlterTableUniqueIndexDelegate; import org.hibernate.dialect.unique.SkipNullableUniqueDelegate; import org.hibernate.engine.config.spi.ConfigurationService; -import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; +import org.hibernate.engine.jdbc.spi.JdbcServices; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.ServiceRegistryScope; +import org.hibernate.testing.orm.junit.Setting; import org.hibernate.tool.schema.TargetType; import org.hibernate.tool.schema.internal.DefaultSchemaFilter; import org.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl; @@ -36,44 +30,80 @@ import org.hibernate.tool.schema.spi.SchemaManagementTool; import org.hibernate.tool.schema.spi.ScriptTargetOutput; import org.hibernate.tool.schema.spi.TargetDescriptor; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; -import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.util.ServiceRegistryUtil; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import java.io.File; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.util.EnumSet; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; +import static org.hibernate.cfg.JdbcSettings.FORMAT_SQL; +import static org.hibernate.cfg.JdbcSettings.SHOW_SQL; +import static org.hibernate.cfg.SchemaToolingSettings.HBM2DDL_AUTO; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * @author Andrea Boriero */ +@SuppressWarnings("JUnitMalformedDeclaration") +@ServiceRegistry(settings = { + @Setting(name = HBM2DDL_AUTO, value = "none"), + @Setting(name = FORMAT_SQL, value = "false"), + @Setting(name = SHOW_SQL, value = "true") +}) +@DomainModel(xmlMappings = "org/hibernate/orm/test/schemaupdate/uniqueconstraint/TestEntity.hbm.xml") public class UniqueConstraintDropTest { - private File output; - private MetadataImplementor metadata; - private StandardServiceRegistry ssr; - private HibernateSchemaManagementTool tool; - private ExecutionOptions options; - - @Before - public void setUp() throws Exception { - output = File.createTempFile( "update_script", ".sql" ); - output.deleteOnExit(); - ssr = ServiceRegistryUtil.serviceRegistryBuilder() - .applySetting( Environment.HBM2DDL_AUTO, "none" ) - .applySetting( Environment.FORMAT_SQL, "false" ) - .applySetting( Environment.SHOW_SQL, "true" ) - .build(); - metadata = (MetadataImplementor) new MetadataSources( ssr ) - .addResource( "org/hibernate/orm/test/schemaupdate/uniqueconstraint/TestEntity.hbm.xml" ) - .buildMetadata(); + + @Test + @JiraKey(value = "HHH-11236") + public void testUniqueConstraintIsDropped( + ServiceRegistryScope registryScope, + DomainModelScope modelScope, + @TempDir File tmpDir) throws Exception { + final var scriptFile = new File( tmpDir, "script.sql" ); + + final var metadata = modelScope.getDomainModel(); metadata.orderColumns( false ); metadata.validate(); - tool = (HibernateSchemaManagementTool) ssr.getService( SchemaManagementTool.class ); - final Map configurationValues = ssr.requireService( ConfigurationService.class ).getSettings(); - options = new ExecutionOptions() { + final var jdbcServices = registryScope.getRegistry().requireService( JdbcServices.class ); + final var dialect = jdbcServices.getDialect(); + final var tool = (HibernateSchemaManagementTool) registryScope.getRegistry().requireService( SchemaManagementTool.class ); + + new IndividuallySchemaMigratorImpl( tool, DefaultSchemaFilter.INSTANCE ).doMigration( + metadata, + executionOptions( registryScope.getRegistry() ), + ContributableMatcher.ALL, + new TargetDescriptorImpl( scriptFile ) + ); + + if ( !(dialect.getUniqueDelegate() instanceof SkipNullableUniqueDelegate) ) { + if ( dialect.getUniqueDelegate() instanceof AlterTableUniqueIndexDelegate) { + assertTrue( checkDropIndex( scriptFile ) ); + } + else if ( dialect.getUniqueDelegate() instanceof AlterTableUniqueDelegate ) { + MatcherAssert.assertThat( "The test_entity_item table unique constraint has not been dropped", + checkDropConstraint( "test_entity_item", dialect, scriptFile ), + is( true ) + ); + } + } + + MatcherAssert.assertThat( + checkDropConstraint( "test_entity_children", dialect, scriptFile ), + is( true ) + ); + } + + private ExecutionOptions executionOptions(StandardServiceRegistry registry) { + final Map configurationValues = registry.requireService( ConfigurationService.class ).getSettings(); + return new ExecutionOptions() { @Override public boolean shouldManageNamespaces() { return true; @@ -91,89 +121,29 @@ public ExceptionHandler getExceptionHandler() { }; } - @After - public void tearDown() { - StandardServiceRegistryBuilder.destroy( ssr ); - } - - @Test - @JiraKey(value = "HHH-11236") - public void testUniqueConstraintIsDropped() throws Exception { - - new IndividuallySchemaMigratorImpl( tool, DefaultSchemaFilter.INSTANCE ) - .doMigration( - metadata, - options, - ContributableMatcher.ALL, - new TargetDescriptorImpl() - ); - - if ( !(getDialect().getUniqueDelegate() instanceof SkipNullableUniqueDelegate) ) { - if ( getDialect().getUniqueDelegate() instanceof AlterTableUniqueIndexDelegate) { - checkDropIndex( "test_entity_item", "item" ); - } - else if ( getDialect().getUniqueDelegate() instanceof AlterTableUniqueDelegate ) { - assertThat( - "The test_entity_item table unique constraint has not been dropped", - checkDropConstraint( "test_entity_item", "item" ), - is( true ) - ); - } - } - - assertThat( - checkDropConstraint( "test_entity_children", "child" ), - is( true ) - ); - } - - protected Dialect getDialect() { - return ssr.getService( JdbcEnvironment.class ).getDialect(); - } - - private boolean checkDropConstraint(String tableName, String columnName) throws IOException { - String regex = getDialect().getAlterTableString( tableName ) + ' ' + getDialect().getDropUniqueKeyString(); - if ( getDialect().supportsIfExistsBeforeConstraintName() ) { + private boolean checkDropConstraint( + String tableName, + Dialect dialect, + File scriptFile) throws IOException { + String regex = dialect.getAlterTableString( tableName ) + ' ' + dialect.getDropUniqueKeyString(); + if ( dialect.supportsIfExistsBeforeConstraintName() ) { regex += " if exists"; } regex += " uk.*"; - if ( getDialect().supportsIfExistsAfterConstraintName() ) { + if ( dialect.supportsIfExistsAfterConstraintName() ) { regex += " if exists"; } regex += ";"; - return isMatching( regex ); + return isMatching( regex, scriptFile ); } -// private boolean checkAlterTableDropIndex(String tableName, String columnName) throws IOException { -// String regex = "alter table "; -// -// if ( getDialect().supportsIfExistsAfterAlterTable() ) { -// regex += "if exists "; -// } -// regex += tableName; -// if ( getDialect().supportsIfExistsAfterTableName() ) { -// regex += " if exists"; -// } -// regex += " drop index"; -// -// if ( getDialect().supportsIfExistsBeforeConstraintName() ) { -// regex += " if exists"; -// } -// regex += " uk.*"; -// if ( getDialect().supportsIfExistsAfterConstraintName() ) { -// regex += " if exists"; -// } -// -// return isMatching( regex ); -// } - - private boolean checkDropIndex(String tableName, String columnName) throws IOException { - String regex = "drop index " + tableName + ".uk.*"; - return isMatching( regex ); + private boolean checkDropIndex(File scriptFile) throws IOException { + String regex = "drop index test_entity_item.uk.*"; + return isMatching( regex, scriptFile ); } - private boolean isMatching(String regex) throws IOException { - final String fileContent = new String( Files.readAllBytes( output.toPath() ) ).toLowerCase(); + private boolean isMatching(String regex, File scriptFile) throws IOException { + final String fileContent = new String( Files.readAllBytes( scriptFile.toPath() ) ).toLowerCase(); final String[] split = fileContent.split( System.lineSeparator() ); Pattern p = Pattern.compile( regex ); for ( String line : split ) { @@ -185,14 +155,14 @@ private boolean isMatching(String regex) throws IOException { return false; } - private class TargetDescriptorImpl implements TargetDescriptor { + private record TargetDescriptorImpl(File scriptFile) implements TargetDescriptor { public EnumSet getTargetTypes() { return EnumSet.of( TargetType.SCRIPT ); } @Override public ScriptTargetOutput getScriptTargetOutput() { - return new ScriptTargetOutputToFile( output, Charset.defaultCharset().name() ); + return new ScriptTargetOutputToFile( scriptFile, Charset.defaultCharset().name() ); } } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/uniqueconstraint/UniqueConstraintGenerationTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/uniqueconstraint/UniqueConstraintGenerationTest.java index 880190c7294b..d74e71168cab 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/uniqueconstraint/UniqueConstraintGenerationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemaupdate/uniqueconstraint/UniqueConstraintGenerationTest.java @@ -4,101 +4,86 @@ */ package org.hibernate.orm.test.schemaupdate.uniqueconstraint; -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.util.EnumSet; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.boot.spi.MetadataImplementor; -import org.hibernate.cfg.Environment; +import org.hamcrest.MatcherAssert; import org.hibernate.dialect.Dialect; import org.hibernate.dialect.unique.AlterTableUniqueDelegate; import org.hibernate.dialect.unique.AlterTableUniqueIndexDelegate; import org.hibernate.dialect.unique.CreateTableUniqueDelegate; import org.hibernate.dialect.unique.SkipNullableUniqueDelegate; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.ServiceRegistryScope; +import org.hibernate.testing.orm.junit.Setting; import org.hibernate.tool.hbm2ddl.SchemaExport; import org.hibernate.tool.schema.TargetType; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.io.TempDir; -import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.util.ServiceRegistryUtil; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.EnumSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; +import static org.hibernate.cfg.SchemaToolingSettings.HBM2DDL_AUTO; /** * @author Andrea Boriero */ +@SuppressWarnings("JUnitMalformedDeclaration") +@ServiceRegistry(settings = @Setting(name = HBM2DDL_AUTO, value = "none")) +@DomainModel(xmlMappings = "org/hibernate/orm/test/schemaupdate/uniqueconstraint/TestEntity.hbm.xml") public class UniqueConstraintGenerationTest { - private File output; - private MetadataImplementor metadata; - StandardServiceRegistry ssr; - @Before - public void setUp() throws Exception { - output = File.createTempFile( "update_script", ".sql" ); - output.deleteOnExit(); - ssr = ServiceRegistryUtil.serviceRegistryBuilder() - .applySetting( Environment.HBM2DDL_AUTO, "none" ) - .build(); - metadata = (MetadataImplementor) new MetadataSources( ssr ) - .addResource( "org/hibernate/orm/test/schemaupdate/uniqueconstraint/TestEntity.hbm.xml" ) - .buildMetadata(); + @Test + @JiraKey(value = "HHH-11101") + public void testUniqueConstraintIsGenerated( + ServiceRegistryScope registryScope, + DomainModelScope modelScope, + @TempDir File tmpDir) throws Exception { + final var scriptFile = new File( tmpDir, "update_script.sql" ); + + final var metadata = modelScope.getDomainModel(); metadata.orderColumns( false ); metadata.validate(); - } - @After - public void tearDown() { - StandardServiceRegistryBuilder.destroy( ssr ); - } - - @Test - @JiraKey(value = "HHH-11101") - public void testUniqueConstraintIsGenerated() throws Exception { new SchemaExport() - .setOutputFile( output.getAbsolutePath() ) + .setOutputFile( scriptFile.getAbsolutePath() ) .create( EnumSet.of( TargetType.SCRIPT ), metadata ); - if ( !(getDialect().getUniqueDelegate() instanceof SkipNullableUniqueDelegate) ) { - if ( getDialect().getUniqueDelegate() instanceof AlterTableUniqueIndexDelegate ) { - assertThat( - "The test_entity_item table unique constraint has not been generated", - isCreateUniqueIndexGenerated("test_entity_item", "item"), + final var dialect = registryScope.getRegistry().requireService( JdbcEnvironment.class ).getDialect(); + if ( !(dialect.getUniqueDelegate() instanceof SkipNullableUniqueDelegate) ) { + if ( dialect.getUniqueDelegate() instanceof AlterTableUniqueIndexDelegate ) { + MatcherAssert.assertThat( "The test_entity_item table unique constraint has not been generated", + isCreateUniqueIndexGenerated("test_entity_item", "item", scriptFile), is(true) ); } else { - assertThat( - "The test_entity_item table unique constraint has not been generated", - isUniqueConstraintGenerated("test_entity_item", "item"), + MatcherAssert.assertThat( "The test_entity_item table unique constraint has not been generated", + isUniqueConstraintGenerated("test_entity_item", "item", dialect, scriptFile), is(true) ); } - assertThat( - "The test_entity_children table unique constraint has not been generated", - isUniqueConstraintGenerated( "test_entity_children", "child" ), + MatcherAssert.assertThat( "The test_entity_children table unique constraint has not been generated", + isUniqueConstraintGenerated( "test_entity_children", "child", dialect, scriptFile ), is( true ) ); } } - private Dialect getDialect() { - return ssr.getService(JdbcEnvironment.class).getDialect(); - } - - private boolean isUniqueConstraintGenerated(String tableName, String columnName) throws IOException { + private boolean isUniqueConstraintGenerated( + String tableName, + String columnName, + Dialect dialect, + File scriptFile) throws IOException { final String regex; - Dialect dialect = getDialect(); if ( dialect.getUniqueDelegate() instanceof CreateTableUniqueDelegate ) { regex = dialect.getCreateTableString() + " " + tableName + " .* " + columnName + " .+ unique.*\\)" + dialect.getTableTypeString().toLowerCase() + ";"; @@ -110,7 +95,7 @@ else if ( dialect.getUniqueDelegate() instanceof AlterTableUniqueDelegate) { return true; } - final String fileContent = new String( Files.readAllBytes( output.toPath() ) ).toLowerCase(); + final String fileContent = new String( Files.readAllBytes( scriptFile.toPath() ) ).toLowerCase(); final String[] split = fileContent.split( System.lineSeparator() ); for ( String line : split ) { if ( line.matches(regex) ) { @@ -120,10 +105,13 @@ else if ( dialect.getUniqueDelegate() instanceof AlterTableUniqueDelegate) { return false; } - private boolean isCreateUniqueIndexGenerated(String tableName, String columnName) throws IOException { + private boolean isCreateUniqueIndexGenerated( + String tableName, + String columnName, + File scriptFile) throws IOException { String regex = "create unique (nonclustered )?index uk.* on " + tableName + " \\(" + columnName + "\\)( where .*| exclude null keys)?;"; - final String fileContent = new String( Files.readAllBytes( output.toPath() ) ).toLowerCase(); + final String fileContent = new String( Files.readAllBytes( scriptFile.toPath() ) ).toLowerCase(); final String[] split = fileContent.split( System.lineSeparator() ); Pattern p = Pattern.compile( regex ); for ( String line : split ) { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/DurationValidationTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/DurationValidationTest.java index a35030f78c35..b524d71224e4 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/DurationValidationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/DurationValidationTest.java @@ -36,7 +36,6 @@ import org.hibernate.testing.orm.junit.BaseUnitTest; import org.hibernate.testing.orm.junit.JiraKey; import org.hibernate.testing.orm.junit.RequiresDialect; -import org.hibernate.testing.orm.junit.RequiresDialects; import org.hibernate.testing.util.ServiceRegistryUtil; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.params.ParameterizedTest; @@ -51,14 +50,9 @@ @JiraKey("HHH-17293") @BaseUnitTest -@RequiresDialects( - { - @RequiresDialect(PostgreSQLDialect.class), - @RequiresDialect(H2Dialect.class), - } -) +@RequiresDialect(PostgreSQLDialect.class) +@RequiresDialect(H2Dialect.class) public class DurationValidationTest implements ExecutionOptions { - private StandardServiceRegistry ssr; private MetadataImplementor metadata; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/EnumValidationTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/EnumValidationTest.java index e6ca843ec685..5f6365775267 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/EnumValidationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/EnumValidationTest.java @@ -4,151 +4,135 @@ */ package org.hibernate.orm.test.schemavalidation; -import java.sql.Types; -import java.util.Arrays; -import java.util.Collection; -import java.util.EnumSet; -import java.util.Map; - +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.Id; import org.hibernate.annotations.JdbcTypeCode; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.boot.spi.MetadataImplementor; -import org.hibernate.cfg.AvailableSettings; import org.hibernate.engine.config.spi.ConfigurationService; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.ServiceRegistryFunctionalTesting; +import org.hibernate.testing.orm.junit.ServiceRegistryProducer; +import org.hibernate.testing.orm.junit.ServiceRegistryScope; import org.hibernate.tool.hbm2ddl.SchemaExport; import org.hibernate.tool.schema.JdbcMetadataAccessStrategy; -import org.hibernate.tool.schema.SourceType; import org.hibernate.tool.schema.TargetType; import org.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl; import org.hibernate.tool.schema.spi.ContributableMatcher; import org.hibernate.tool.schema.spi.ExceptionHandler; import org.hibernate.tool.schema.spi.ExecutionOptions; import org.hibernate.tool.schema.spi.SchemaManagementTool; -import org.hibernate.tool.schema.spi.ScriptSourceInput; -import org.hibernate.tool.schema.spi.ScriptTargetOutput; -import org.hibernate.tool.schema.spi.SourceDescriptor; -import org.hibernate.tool.schema.spi.TargetDescriptor; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedClass; +import org.junit.jupiter.params.provider.MethodSource; -import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.util.ServiceRegistryUtil; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import java.sql.Types; +import java.util.EnumSet; +import java.util.List; +import java.util.Map; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; -import jakarta.persistence.Id; +import static org.hibernate.cfg.SchemaToolingSettings.HBM2DDL_JDBC_METADATA_EXTRACTOR_STRATEGY; /** * Test that an existing tinyint column works even if we switch to smallint type code for enums. */ @JiraKey(value = "HHH-15288") -@RunWith(Parameterized.class) -public class EnumValidationTest implements ExecutionOptions { - @Parameterized.Parameters - public static Collection parameters() { - return Arrays.asList( - JdbcMetadataAccessStrategy.GROUPED.toString(), - JdbcMetadataAccessStrategy.INDIVIDUALLY.toString() +@TestInstance( TestInstance.Lifecycle.PER_METHOD ) +@ParameterizedClass +@MethodSource("extractorStrategies") +@ServiceRegistryFunctionalTesting +@DomainModel(annotatedClasses = EnumValidationTest.TestEntityOld.class) +public class EnumValidationTest implements ServiceRegistryProducer { + static List extractorStrategies() { + return List.of( + JdbcMetadataAccessStrategy.GROUPED, + JdbcMetadataAccessStrategy.INDIVIDUALLY ); } - @Parameterized.Parameter - public String jdbcMetadataExtractorStrategy; + private final JdbcMetadataAccessStrategy jdbcMetadataExtractorStrategy; - private StandardServiceRegistry ssr; - private MetadataImplementor metadata; - private MetadataImplementor oldMetadata; + public EnumValidationTest(JdbcMetadataAccessStrategy jdbcMetadataExtractorStrategy) { + this.jdbcMetadataExtractorStrategy = jdbcMetadataExtractorStrategy; + } - @Before - public void beforeTest() { - ssr = ServiceRegistryUtil.serviceRegistryBuilder() - .applySetting( - AvailableSettings.HBM2DDL_JDBC_METADATA_EXTRACTOR_STRATEGY, - jdbcMetadataExtractorStrategy - ) + @Override + public StandardServiceRegistry produceServiceRegistry(StandardServiceRegistryBuilder builder) { + return builder + .applySetting( HBM2DDL_JDBC_METADATA_EXTRACTOR_STRATEGY, jdbcMetadataExtractorStrategy ) .build(); - oldMetadata = (MetadataImplementor) new MetadataSources( ssr ) - .addAnnotatedClass( TestEntityOld.class ) - .buildMetadata(); - oldMetadata.orderColumns( false ); - oldMetadata.validate(); - metadata = (MetadataImplementor) new MetadataSources( ssr ) - .addAnnotatedClass( TestEntity.class ) - .buildMetadata(); - metadata.orderColumns( false ); - metadata.validate(); - - try { - dropSchema(); - // create the schema - createSchema(); - } - catch (Exception e) { - tearDown(); - throw e; - } } - @After - public void tearDown() { - dropSchema(); - if ( ssr != null ) { - StandardServiceRegistryBuilder.destroy( ssr ); - } + @BeforeEach + void setUp(DomainModelScope modelScope) { + final var model = modelScope.getDomainModel(); + model.orderColumns( false ); + model.validate(); + + dropSchema( model ); + createSchema( model ); } - @Test - public void testValidation() { - doValidation(); + private void createSchema(MetadataImplementor model) { + new SchemaExport().create( EnumSet.of( TargetType.DATABASE ), model ); } - private void doValidation() { - ssr.getService( SchemaManagementTool.class ).getSchemaValidator( null ) - .doValidation( metadata, this, ContributableMatcher.ALL ); + @AfterEach + void tearDown(DomainModelScope modelScope) { + final var model = modelScope.getDomainModel(); + model.orderColumns( false ); + model.validate(); + + dropSchema( model ); } - private void createSchema() { - ssr.getService( SchemaManagementTool.class ).getSchemaCreator( null ).doCreation( - oldMetadata, - this, - ContributableMatcher.ALL, - new SourceDescriptor() { - @Override - public SourceType getSourceType() { - return SourceType.METADATA; - } - - @Override - public ScriptSourceInput getScriptSourceInput() { - return null; - } - }, - new TargetDescriptor() { - @Override - public EnumSet getTargetTypes() { - return EnumSet.of( TargetType.DATABASE ); - } - - @Override - public ScriptTargetOutput getScriptTargetOutput() { - return null; - } - } - ); + private void dropSchema(MetadataImplementor model) { + new SchemaExport().drop( EnumSet.of( TargetType.DATABASE ), model ); } - private void dropSchema() { - new SchemaExport() - .drop( EnumSet.of( TargetType.DATABASE ), oldMetadata ); + @Test + public void testValidation(ServiceRegistryScope registryScope) { + final var newModel = (MetadataImplementor) new MetadataSources( registryScope.getRegistry() ) + .addAnnotatedClasses( TestEntity.class ) + .buildMetadata(); + newModel.orderColumns( false ); + newModel.validate(); + + final var tool = registryScope.getRegistry().requireService( SchemaManagementTool.class ); + + final var execOptions = new ExecutionOptions() { + final Map settings = registryScope.getRegistry().requireService( ConfigurationService.class ).getSettings(); + + @Override + public Map getConfigurationValues() { + return settings; + } + + @Override + public boolean shouldManageNamespaces() { + return false; + } + + @Override + public ExceptionHandler getExceptionHandler() { + return ExceptionHandlerLoggedImpl.INSTANCE; + } + }; + + tool.getSchemaValidator( null ).doValidation( newModel, execOptions, ContributableMatcher.ALL ); } + @SuppressWarnings("unused") @Entity(name = "TestEntity") public static class TestEntityOld { @Id @@ -160,6 +144,7 @@ public static class TestEntityOld { TestEnum enumVal; } + @SuppressWarnings("unused") @Entity(name = "TestEntity") public static class TestEntity { @Id @@ -174,19 +159,4 @@ public enum TestEnum { VALUE1, VALUE2 } - - @Override - public Map getConfigurationValues() { - return ssr.requireService( ConfigurationService.class ).getSettings(); - } - - @Override - public boolean shouldManageNamespaces() { - return false; - } - - @Override - public ExceptionHandler getExceptionHandler() { - return ExceptionHandlerLoggedImpl.INSTANCE; - } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/ExistingVarcharEnumColumnValidationTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/ExistingVarcharEnumColumnValidationTest.java index 81ac1b267bbe..97ee5b321045 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/ExistingVarcharEnumColumnValidationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/ExistingVarcharEnumColumnValidationTest.java @@ -4,79 +4,95 @@ */ package org.hibernate.orm.test.schemavalidation; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.EnumType; +import jakarta.persistence.Enumerated; +import jakarta.persistence.Id; +import jakarta.persistence.Table; import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.AvailableSettings; import org.hibernate.dialect.H2Dialect; import org.hibernate.dialect.MySQLDialect; -import org.hibernate.tool.hbm2ddl.SchemaValidator; - -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; +import org.hibernate.testing.jdbc.JdbcUtils; import org.hibernate.testing.orm.junit.JiraKey; import org.hibernate.testing.orm.junit.RequiresDialect; -import org.hibernate.testing.transaction.TransactionUtil; import org.hibernate.testing.util.ServiceRegistryUtil; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import org.hibernate.tool.hbm2ddl.SchemaValidator; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.EnumType; -import jakarta.persistence.Enumerated; -import jakarta.persistence.Id; -import jakarta.persistence.Table; +import java.sql.SQLException; +import java.sql.Statement; @JiraKey("HHH-17908") @RequiresDialect( H2Dialect.class ) @RequiresDialect( MySQLDialect.class ) -public class ExistingVarcharEnumColumnValidationTest extends BaseCoreFunctionalTestCase { +public class ExistingVarcharEnumColumnValidationTest { - private StandardServiceRegistry ssr; + @BeforeEach + public void setUp() { + try (var registry = ServiceRegistryUtil.serviceRegistryBuilder().build()) { + JdbcUtils.withConnection( registry, (connection) -> { + try (var statement = connection.createStatement()) { + try { + dropSchema( statement ); + } + catch (Exception ignore) { + } + createSchema( statement ); + } + } ); + } + } - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { EntityE.class }; + private void dropSchema(Statement statement) throws SQLException { + statement.execute( "drop table en cascade" ); } - @Before - public void setUp() { - try { - tearDown(); - } - catch (Exception ex) { - // ignore - } - TransactionUtil.doInHibernate( this::sessionFactory, session -> { - session.createNativeQuery( - "create table en (id integer not null, sign_position varchar(255) check (sign_position in ('AFTER_NO_SPACE','AFTER_WITH_SPACE','BEFORE_NO_SPACE','BEFORE_WITH_SPACE')), primary key (id))" ) - .executeUpdate(); - } ); + private void createSchema(Statement statement) throws SQLException { + statement.execute( + """ + create table en ( + id integer not null, + sign_position varchar(255) + check (sign_position in ( + 'AFTER_NO_SPACE', + 'AFTER_WITH_SPACE', + 'BEFORE_NO_SPACE', + 'BEFORE_WITH_SPACE') + ), + primary key (id) + ) + """ + ); } - @After + @AfterEach public void tearDown() { - TransactionUtil.doInHibernate( this::sessionFactory, session -> { - session.createNativeQuery( "drop table en cascade" ).executeUpdate(); - } ); + try (var registry = ServiceRegistryUtil.serviceRegistryBuilder().build()) { + final var connections = registry.requireService( ConnectionProvider.class ); + JdbcUtils.withConnection( connections, (connection) -> { + try (var statement = connection.createStatement()) { + dropSchema( statement ); + } + } ); + } } @Test public void testEnumDataTypeSchemaValidator() { - ssr = ServiceRegistryUtil.serviceRegistryBuilder() + try (var ssr = ServiceRegistryUtil.serviceRegistryBuilder() .applySetting( AvailableSettings.HBM2DDL_AUTO, "validate" ) - .build(); - try { + .build()) { final MetadataSources metadataSources = new MetadataSources( ssr ); metadataSources.addAnnotatedClass( EntityE.class ); new SchemaValidator().validate( metadataSources.buildMetadata() ); } - finally { - StandardServiceRegistryBuilder.destroy( ssr ); - } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/H2ExistingEnumColumnValidationTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/H2ExistingEnumColumnValidationTest.java index 5061856b440f..57dbba705b52 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/H2ExistingEnumColumnValidationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/H2ExistingEnumColumnValidationTest.java @@ -4,22 +4,6 @@ */ package org.hibernate.orm.test.schemavalidation; -import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.cfg.AvailableSettings; -import org.hibernate.dialect.H2Dialect; -import org.hibernate.tool.hbm2ddl.SchemaValidator; - -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.orm.junit.RequiresDialect; -import org.hibernate.testing.transaction.TransactionUtil; -import org.hibernate.testing.util.ServiceRegistryUtil; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.EnumType; @@ -27,51 +11,70 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; import jakarta.persistence.Table; +import org.hibernate.boot.MetadataSources; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.dialect.H2Dialect; +import org.hibernate.testing.jdbc.JdbcUtils; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.hibernate.testing.util.ServiceRegistryUtil; +import org.hibernate.tool.hbm2ddl.SchemaValidator; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import static jakarta.persistence.GenerationType.IDENTITY; @JiraKey("HHH-17675") @RequiresDialect(H2Dialect.class) -public class H2ExistingEnumColumnValidationTest extends BaseCoreFunctionalTestCase { - - private StandardServiceRegistry ssr; +public class H2ExistingEnumColumnValidationTest { - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { EntityE.class }; - } - - @Before + @BeforeEach public void setUp() { - TransactionUtil.doInHibernate( this::sessionFactory, session -> { - session.createNativeQuery( "DROP TABLE IF EXISTS en CASCADE" ).executeUpdate(); - session.createNativeQuery( - "CREATE TABLE en (id INTEGER NOT NULL AUTO_INCREMENT, sign_position enum ('AFTER_NO_SPACE','AFTER_WITH_SPACE','BEFORE_NO_SPACE','BEFORE_WITH_SPACE'), PRIMARY KEY (id))" ) - .executeUpdate(); - } ); + try (var registry = ServiceRegistryUtil.serviceRegistryBuilder().build()) { + JdbcUtils.withConnection( registry, (connection) -> { + try (var statement = connection.createStatement()) { + statement.execute( "DROP TABLE IF EXISTS en CASCADE" ); + statement.execute( + """ + CREATE TABLE en ( + id INTEGER NOT NULL AUTO_INCREMENT, + sign_position enum ( + 'AFTER_NO_SPACE', + 'AFTER_WITH_SPACE', + 'BEFORE_NO_SPACE', + 'BEFORE_WITH_SPACE' + ), + PRIMARY KEY (id) + ) + """ + ); + } + } ); + } } - @After + @AfterEach public void tearDown() { - TransactionUtil.doInHibernate( this::sessionFactory, session -> { - session.createNativeQuery( "DROP TABLE en CASCADE" ).executeUpdate(); - } ); + try (var registry = ServiceRegistryUtil.serviceRegistryBuilder().build()) { + JdbcUtils.withConnection( registry, (connection) -> { + try (var statement = connection.createStatement()) { + statement.execute( "DROP TABLE en CASCADE" ); + } + } ); + } } @Test public void testEnumDataTypeSchemaValidator() { - ssr = ServiceRegistryUtil.serviceRegistryBuilder() + try (var ssr = ServiceRegistryUtil.serviceRegistryBuilder() .applySetting( AvailableSettings.HBM2DDL_AUTO, "validate" ) - .build(); - try { + .build()) { final MetadataSources metadataSources = new MetadataSources( ssr ); metadataSources.addAnnotatedClass( EntityE.class ); new SchemaValidator().validate( metadataSources.buildMetadata() ); } - finally { - StandardServiceRegistryBuilder.destroy( ssr ); - } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/IdentityGenerationValidationTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/IdentityGenerationValidationTest.java index c1caee005f94..72289abffb29 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/IdentityGenerationValidationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/IdentityGenerationValidationTest.java @@ -4,53 +4,48 @@ */ package org.hibernate.orm.test.schemavalidation; -import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.dialect.PostgreSQLDialect; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; import org.hibernate.tool.hbm2ddl.SchemaValidator; -import org.hibernate.testing.RequiresDialect; import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.hibernate.testing.util.ServiceRegistryUtil; -import org.junit.Test; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.GenerationType; import jakarta.persistence.Id; import jakarta.persistence.Table; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; /** * @author Jan Schatteman */ @JiraKey( value = "HHH-13106" ) -@RequiresDialect( value = PostgreSQLDialect.class ) -public class IdentityGenerationValidationTest extends BaseCoreFunctionalTestCase { - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] {TestEntity.class}; +@RequiresDialect(PostgreSQLDialect.class) +@ServiceRegistry +@DomainModel(annotatedClasses = IdentityGenerationValidationTest.TestEntity.class) +@SessionFactory +public class IdentityGenerationValidationTest { + @BeforeEach + void setUp(SessionFactoryScope factoryScope) { + // force the schema export + factoryScope.getSessionFactory(); } @Test - public void testSynonymUsingIndividuallySchemaValidator() { - StandardServiceRegistry ssr = ServiceRegistryUtil.serviceRegistry(); - try { - final MetadataSources metadataSources = new MetadataSources( ssr ); - metadataSources.addAnnotatedClass( TestEntity.class ); - - new SchemaValidator().validate( metadataSources.buildMetadata() ); - } - finally { - StandardServiceRegistryBuilder.destroy( ssr ); - } + public void testSynonymUsingIndividuallySchemaValidator(DomainModelScope modelScope) { + new SchemaValidator().validate( modelScope.getDomainModel() ); } @Entity @Table(name = "test_entity") - private static class TestEntity { + public static class TestEntity { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/InstantValidationTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/InstantValidationTest.java index e19c3b837010..f4f629ac3974 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/InstantValidationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/InstantValidationTest.java @@ -4,148 +4,132 @@ */ package org.hibernate.orm.test.schemavalidation; -import java.time.Instant; -import java.util.Arrays; -import java.util.Collection; -import java.util.EnumSet; -import java.util.Map; - +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.boot.spi.MetadataImplementor; -import org.hibernate.cfg.AvailableSettings; import org.hibernate.engine.config.spi.ConfigurationService; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.ServiceRegistryFunctionalTesting; +import org.hibernate.testing.orm.junit.ServiceRegistryProducer; +import org.hibernate.testing.orm.junit.ServiceRegistryScope; import org.hibernate.tool.hbm2ddl.SchemaExport; import org.hibernate.tool.schema.JdbcMetadataAccessStrategy; -import org.hibernate.tool.schema.SourceType; import org.hibernate.tool.schema.TargetType; import org.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl; import org.hibernate.tool.schema.spi.ContributableMatcher; import org.hibernate.tool.schema.spi.ExceptionHandler; import org.hibernate.tool.schema.spi.ExecutionOptions; import org.hibernate.tool.schema.spi.SchemaManagementTool; -import org.hibernate.tool.schema.spi.ScriptSourceInput; -import org.hibernate.tool.schema.spi.ScriptTargetOutput; -import org.hibernate.tool.schema.spi.SourceDescriptor; -import org.hibernate.tool.schema.spi.TargetDescriptor; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedClass; +import org.junit.jupiter.params.provider.MethodSource; -import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.util.ServiceRegistryUtil; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import java.time.Instant; +import java.util.EnumSet; +import java.util.List; +import java.util.Map; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; +import static org.hibernate.cfg.SchemaToolingSettings.HBM2DDL_JDBC_METADATA_EXTRACTOR_STRATEGY; /** * Test that an existing timestamp with timezone column works for fields that use java.time.Instant. */ @JiraKey(value = "HHH-15548") -@RunWith(Parameterized.class) -public class InstantValidationTest implements ExecutionOptions { - @Parameterized.Parameters - public static Collection parameters() { - return Arrays.asList( - JdbcMetadataAccessStrategy.GROUPED.toString(), - JdbcMetadataAccessStrategy.INDIVIDUALLY.toString() +@TestInstance( TestInstance.Lifecycle.PER_METHOD ) +@ParameterizedClass +@MethodSource("extractorStrategies") +@ServiceRegistryFunctionalTesting +@DomainModel(annotatedClasses = InstantValidationTest.TestEntityOld.class) +public class InstantValidationTest implements ServiceRegistryProducer { + static List extractorStrategies() { + return List.of( + JdbcMetadataAccessStrategy.GROUPED, + JdbcMetadataAccessStrategy.INDIVIDUALLY ); } - @Parameterized.Parameter - public String jdbcMetadataExtractorStrategy; + private final JdbcMetadataAccessStrategy extractorStrategy; - private StandardServiceRegistry ssr; - private MetadataImplementor metadata; - private MetadataImplementor oldMetadata; + public InstantValidationTest(JdbcMetadataAccessStrategy extractorStrategy) { + this.extractorStrategy = extractorStrategy; + } - @Before - public void beforeTest() { - ssr = ServiceRegistryUtil.serviceRegistryBuilder() - .applySetting( - AvailableSettings.HBM2DDL_JDBC_METADATA_EXTRACTOR_STRATEGY, - jdbcMetadataExtractorStrategy - ) + @Override + public StandardServiceRegistry produceServiceRegistry(StandardServiceRegistryBuilder builder) { + return builder + .applySetting( HBM2DDL_JDBC_METADATA_EXTRACTOR_STRATEGY, extractorStrategy ) .build(); - oldMetadata = (MetadataImplementor) new MetadataSources( ssr ) - .addAnnotatedClass( TestEntityOld.class ) - .buildMetadata(); - oldMetadata.orderColumns( false ); - oldMetadata.validate(); - metadata = (MetadataImplementor) new MetadataSources( ssr ) - .addAnnotatedClass( TestEntity.class ) - .buildMetadata(); - metadata.orderColumns( false ); - metadata.validate(); - - try { - dropSchema(); - // create the schema - createSchema(); - } - catch (Exception e) { - tearDown(); - throw e; - } } - @After - public void tearDown() { - dropSchema(); - if ( ssr != null ) { - StandardServiceRegistryBuilder.destroy( ssr ); - } + @BeforeEach + void setUp(DomainModelScope modelScope) { + final var model = modelScope.getDomainModel(); + model.orderColumns( false ); + model.validate(); + + dropSchema( model ); + createSchema( model ); } - @Test - public void testValidation() { - doValidation(); + private void dropSchema(MetadataImplementor model) { + new SchemaExport().drop( EnumSet.of( TargetType.DATABASE ), model ); } - private void doValidation() { - ssr.getService( SchemaManagementTool.class ).getSchemaValidator( null ) - .doValidation( metadata, this, ContributableMatcher.ALL ); + private void createSchema(MetadataImplementor model) { + new SchemaExport().create( EnumSet.of( TargetType.DATABASE ), model ); } - private void createSchema() { - ssr.getService( SchemaManagementTool.class ).getSchemaCreator( null ).doCreation( - oldMetadata, - this, - ContributableMatcher.ALL, - new SourceDescriptor() { - @Override - public SourceType getSourceType() { - return SourceType.METADATA; - } - - @Override - public ScriptSourceInput getScriptSourceInput() { - return null; - } - }, - new TargetDescriptor() { - @Override - public EnumSet getTargetTypes() { - return EnumSet.of( TargetType.DATABASE ); - } - - @Override - public ScriptTargetOutput getScriptTargetOutput() { - return null; - } - } - ); + @AfterEach + void tearDown(DomainModelScope modelScope) { + final var model = modelScope.getDomainModel(); + model.orderColumns( false ); + model.validate(); + + dropSchema( model ); } - private void dropSchema() { - new SchemaExport() - .drop( EnumSet.of( TargetType.DATABASE ), oldMetadata ); + @Test + void testValidation(ServiceRegistryScope registryScope) { + final var newModel = (MetadataImplementor) new MetadataSources( registryScope.getRegistry() ) + .addAnnotatedClasses( TestEntity.class ) + .buildMetadata(); + newModel.orderColumns( false ); + newModel.validate(); + + final var tool = registryScope.getRegistry().requireService( SchemaManagementTool.class ); + + final var execOptions = new ExecutionOptions() { + final Map settings = registryScope.getRegistry().requireService( ConfigurationService.class ).getSettings(); + + @Override + public Map getConfigurationValues() { + return settings; + } + + @Override + public boolean shouldManageNamespaces() { + return false; + } + + @Override + public ExceptionHandler getExceptionHandler() { + return ExceptionHandlerLoggedImpl.INSTANCE; + } + }; + + tool.getSchemaValidator( null ).doValidation( newModel, execOptions, ContributableMatcher.ALL ); } + @SuppressWarnings("unused") @Entity(name = "TestEntity") public static class TestEntityOld { @Id @@ -155,6 +139,7 @@ public static class TestEntityOld { Instant instantVal; } + @SuppressWarnings("unused") @Entity(name = "TestEntity") public static class TestEntity { @Id @@ -163,19 +148,4 @@ public static class TestEntity { @Column(name = "instantVal") Instant instantVal; } - - @Override - public Map getConfigurationValues() { - return ssr.requireService( ConfigurationService.class ).getSettings(); - } - - @Override - public boolean shouldManageNamespaces() { - return false; - } - - @Override - public ExceptionHandler getExceptionHandler() { - return ExceptionHandlerLoggedImpl.INSTANCE; - } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/JoinTableWithDefaultSchemaTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/JoinTableWithDefaultSchemaTest.java index 01f7c9b01159..45818540a12c 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/JoinTableWithDefaultSchemaTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/JoinTableWithDefaultSchemaTest.java @@ -4,48 +4,41 @@ */ package org.hibernate.orm.test.schemavalidation; -import java.util.ArrayList; -import java.util.EnumSet; -import java.util.List; - import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; import jakarta.persistence.JoinTable; import jakarta.persistence.OneToMany; import jakarta.persistence.Table; - import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.cfg.AvailableSettings; import org.hibernate.dialect.SQLServerDialect; -import org.hibernate.testing.RequiresDialect; import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.junit4.BaseUnitTestCase; +import org.hibernate.testing.orm.junit.RequiresDialect; import org.hibernate.testing.util.ServiceRegistryUtil; - import org.hibernate.tool.hbm2ddl.SchemaExport; import org.hibernate.tool.hbm2ddl.SchemaValidator; import org.hibernate.tool.schema.TargetType; -import org.junit.Test; +import org.junit.jupiter.api.Test; + +import java.util.EnumSet; +import java.util.List; +import java.util.Objects; import static org.hibernate.testing.jdbc.GradleParallelTestingResolver.resolveUsername; /** * @author Chris Cranford */ -public class JoinTableWithDefaultSchemaTest extends BaseUnitTestCase { - +public class JoinTableWithDefaultSchemaTest { @Test @JiraKey(value = "HHH-10978") @RequiresDialect(SQLServerDialect.class) public void testGetTableDataForJoinTableWithDefaultSchema() { - StandardServiceRegistry ssr = ServiceRegistryUtil.serviceRegistryBuilder() + try (var ssr = ServiceRegistryUtil.serviceRegistryBuilder() .applySetting( AvailableSettings.DEFAULT_CATALOG, resolveUsername( "hibernate_orm_test_$worker" ) ) - .build(); - try { + .build()) { final MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr ) .addAnnotatedClass( Task.class ) .addAnnotatedClass( Project.class ) @@ -64,9 +57,6 @@ public void testGetTableDataForJoinTableWithDefaultSchema() { new SchemaExport().drop( EnumSet.of( TargetType.DATABASE ), metadata ); } } - finally { - StandardServiceRegistryBuilder.destroy( ssr ); - } } @Entity(name = "Task") @@ -105,17 +95,17 @@ public boolean equals(Object object) { if ( object == this ) { return true; } - if ( object == null || !( object instanceof Task ) ) { + if ( !(object instanceof Task task) ) { return false; } - Task task = (Task) object; - if ( id != null ? !id.equals( task.id ) : task.id != null ) { + if ( !Objects.equals( id, task.id ) ) { return false; } - return !( name != null ? !name.equals( task.name ) : task.name != null ); + return Objects.equals( name, task.name ); } } + @SuppressWarnings("unused") @Entity(name = "Project") @Table(name = "projects", schema = "dbo") public static class Project { @@ -125,7 +115,7 @@ public static class Project { private String name; @OneToMany @JoinTable(name = "project_tasks", schema="dbo") - private List tasks = new ArrayList(); + private List tasks; @Override public int hashCode() { @@ -135,18 +125,13 @@ public int hashCode() { } @Override - public boolean equals(Object object) { - if ( object == this ) { - return true; - } - if ( object == null || !( object instanceof Task ) ) { - return false; - } - Project project = (Project) object; - if ( id != null ? !id.equals( project.id ) : project.id != null ) { + public boolean equals(Object o) { + if ( o == null || getClass() != o.getClass() ) { return false; } - return !( name != null ? !name.equals( project.name ) : project.name != null ); + Project project = (Project) o; + return Objects.equals( id, project.id ) + && Objects.equals( name, project.name ); } } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/LongVarcharValidationTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/LongVarcharValidationTest.java index 1567cf5a1b31..d9568acc6728 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/LongVarcharValidationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/LongVarcharValidationTest.java @@ -4,163 +4,121 @@ */ package org.hibernate.orm.test.schemavalidation; -import java.sql.Types; -import java.util.Arrays; -import java.util.Collection; -import java.util.EnumSet; -import java.util.Map; - +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; import org.hibernate.annotations.JdbcTypeCode; -import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.boot.spi.MetadataImplementor; -import org.hibernate.cfg.AvailableSettings; import org.hibernate.engine.config.spi.ConfigurationService; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.ServiceRegistryFunctionalTesting; +import org.hibernate.testing.orm.junit.ServiceRegistryProducer; +import org.hibernate.testing.orm.junit.ServiceRegistryScope; +import org.hibernate.tool.hbm2ddl.SchemaExport; import org.hibernate.tool.schema.JdbcMetadataAccessStrategy; -import org.hibernate.tool.schema.SourceType; import org.hibernate.tool.schema.TargetType; import org.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl; import org.hibernate.tool.schema.spi.ContributableMatcher; import org.hibernate.tool.schema.spi.ExceptionHandler; import org.hibernate.tool.schema.spi.ExecutionOptions; import org.hibernate.tool.schema.spi.SchemaManagementTool; -import org.hibernate.tool.schema.spi.ScriptSourceInput; -import org.hibernate.tool.schema.spi.ScriptTargetOutput; -import org.hibernate.tool.schema.spi.SourceDescriptor; -import org.hibernate.tool.schema.spi.TargetDescriptor; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedClass; +import org.junit.jupiter.params.provider.MethodSource; -import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.util.ServiceRegistryUtil; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import java.sql.Types; +import java.util.EnumSet; +import java.util.List; +import java.util.Map; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.Table; +import static org.hibernate.cfg.SchemaToolingSettings.HBM2DDL_JDBC_METADATA_EXTRACTOR_STRATEGY; /** * @author Steve Ebersole */ @JiraKey(value = "HHH-9693") -@RunWith(Parameterized.class) -public class LongVarcharValidationTest implements ExecutionOptions { - @Parameterized.Parameters - public static Collection parameters() { - return Arrays.asList( - JdbcMetadataAccessStrategy.GROUPED.toString(), - JdbcMetadataAccessStrategy.INDIVIDUALLY.toString() +@TestInstance( TestInstance.Lifecycle.PER_METHOD ) +@ParameterizedClass +@MethodSource("extractorStrategies") +@ServiceRegistryFunctionalTesting +@DomainModel(annotatedClasses = LongVarcharValidationTest.Translation.class) +public class LongVarcharValidationTest implements ServiceRegistryProducer { + static List extractorStrategies() { + return List.of( + JdbcMetadataAccessStrategy.GROUPED, + JdbcMetadataAccessStrategy.INDIVIDUALLY ); } - @Parameterized.Parameter - public String jdbcMetadataExtractorStrategy; - - private StandardServiceRegistry ssr; + private final JdbcMetadataAccessStrategy jdbcMetadataExtractorStrategy; - @Before - public void beforeTest() { - ssr = ServiceRegistryUtil.serviceRegistryBuilder() - .applySetting( AvailableSettings.HBM2DDL_JDBC_METADATA_EXTRACTOR_STRATEGY, jdbcMetadataExtractorStrategy ) - .build(); + public LongVarcharValidationTest(JdbcMetadataAccessStrategy jdbcMetadataExtractorStrategy) { + this.jdbcMetadataExtractorStrategy = jdbcMetadataExtractorStrategy; } - @After - public void afterTest() { - if ( ssr != null ) { - StandardServiceRegistryBuilder.destroy( ssr ); - } + @Override + public StandardServiceRegistry produceServiceRegistry(StandardServiceRegistryBuilder builder) { + return builder + .applySetting( HBM2DDL_JDBC_METADATA_EXTRACTOR_STRATEGY, jdbcMetadataExtractorStrategy ) + .build(); } @Test - public void testValidation() { - MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr ) - .addAnnotatedClass( Translation.class ) - .buildMetadata(); + public void testValidation(ServiceRegistryScope registryScope, DomainModelScope modelScope) { + MetadataImplementor metadata = modelScope.getDomainModel(); metadata.orderColumns( false ); metadata.validate(); - // create the schema createSchema( metadata ); try { - doValidation( metadata ); + doValidation( registryScope.getRegistry(), metadata ); } finally { dropSchema( metadata ); } } - private void doValidation(MetadataImplementor metadata) { - ssr.getService( SchemaManagementTool.class ).getSchemaValidator( null ).doValidation( - metadata, - this, - ContributableMatcher.ALL - ); + private void doValidation(ServiceRegistry serviceRegistry, MetadataImplementor metadata) { + serviceRegistry.requireService( SchemaManagementTool.class ) + .getSchemaValidator( null ) + .doValidation( metadata, executionOptions( serviceRegistry ), ContributableMatcher.ALL ); + } + + private ExecutionOptions executionOptions(ServiceRegistry serviceRegistry) { + return new ExecutionOptions() { + final Map settings = serviceRegistry.requireService( ConfigurationService.class ).getSettings(); + + @Override + public Map getConfigurationValues() { + return settings; + } + + @Override + public boolean shouldManageNamespaces() { + return false; + } + + @Override + public ExceptionHandler getExceptionHandler() { + return ExceptionHandlerLoggedImpl.INSTANCE; + } + }; } private void createSchema(MetadataImplementor metadata) { - ssr.getService( SchemaManagementTool.class ).getSchemaCreator( null ).doCreation( - metadata, - this, - ContributableMatcher.ALL, - new SourceDescriptor() { - @Override - public SourceType getSourceType() { - return SourceType.METADATA; - } - - @Override - public ScriptSourceInput getScriptSourceInput() { - return null; - } - }, - new TargetDescriptor() { - @Override - public EnumSet getTargetTypes() { - return EnumSet.of( TargetType.DATABASE ); - } - - @Override - public ScriptTargetOutput getScriptTargetOutput() { - return null; - } - } - ); + new SchemaExport().create( EnumSet.of( TargetType.DATABASE ), metadata ); } private void dropSchema(MetadataImplementor metadata) { - ssr.getService( SchemaManagementTool.class ).getSchemaDropper( null ).doDrop( - metadata, - this, - ContributableMatcher.ALL, - new SourceDescriptor() { - @Override - public SourceType getSourceType() { - return SourceType.METADATA; - } - - @Override - public ScriptSourceInput getScriptSourceInput() { - return null; - } - }, - new TargetDescriptor() { - @Override - public EnumSet getTargetTypes() { - return EnumSet.of( TargetType.DATABASE ); - } - - @Override - public ScriptTargetOutput getScriptTargetOutput() { - return null; - } - } - ); + new SchemaExport().drop( EnumSet.of( TargetType.DATABASE ), metadata ); } @Entity(name = "Translation") @@ -171,19 +129,4 @@ public static class Translation { @JdbcTypeCode(Types.LONGVARCHAR) String text; } - - @Override - public Map getConfigurationValues() { - return ssr.requireService( ConfigurationService.class ).getSettings(); - } - - @Override - public boolean shouldManageNamespaces() { - return false; - } - - @Override - public ExceptionHandler getExceptionHandler() { - return ExceptionHandlerLoggedImpl.INSTANCE; - } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/MariaDbJsonColumnValidationTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/MariaDbJsonColumnValidationTest.java index 17d54ca7849b..ecf71cd5f17e 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/MariaDbJsonColumnValidationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/MariaDbJsonColumnValidationTest.java @@ -8,48 +8,61 @@ import jakarta.persistence.Id; import jakarta.persistence.Table; import org.hibernate.dialect.MariaDBDialect; -import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.hibernate.testing.jdbc.JdbcUtils; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; import org.hibernate.testing.orm.junit.JiraKey; import org.hibernate.testing.orm.junit.RequiresDialect; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.ServiceRegistryScope; import org.hibernate.tool.hbm2ddl.SchemaValidator; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import java.math.BigDecimal; +@SuppressWarnings("JUnitMalformedDeclaration") @JiraKey(value = "HHH-18869") @RequiresDialect(value = MariaDBDialect.class) -public class MariaDbJsonColumnValidationTest extends BaseNonConfigCoreFunctionalTestCase { - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] {Foo.class}; +@ServiceRegistry +public class MariaDbJsonColumnValidationTest { + + @BeforeEach + void setUp(ServiceRegistryScope registryScope) { + JdbcUtils.withConnection( registryScope.getRegistry(), connection -> { + try (var statement = connection.createStatement()) { + try { + statement.execute( "drop table Foo" ); + } + catch (Exception ignore) { + } + statement.execute( + """ + create table Foo ( + id integer not null, + bigDecimals json, + primary key (id) + ) engine=InnoDB + """ + ); + } + } ); } - @Before - public void init() { - try { - inTransaction( session -> { - try { - session.createNativeMutationQuery( "drop table Foo" ).executeUpdate(); - } - catch (Exception e) { - throw new RuntimeException( e ); - } - } - ); - inTransaction( session -> - session.createNativeMutationQuery( - "create table Foo (id integer not null, bigDecimals json, primary key (id)) engine=InnoDB" - ).executeUpdate() - ); - } - catch (Exception ignored) { - } + @AfterEach + void tearDown(ServiceRegistryScope registryScope) { + JdbcUtils.withConnection( registryScope.getRegistry(), connection -> { + try (var statement = connection.createStatement()) { + statement.execute( "drop table Foo" ); + } + } ); } @Test - public void testSchemaValidation() { - new SchemaValidator().validate( metadata() ); + @DomainModel(annotatedClasses = Foo.class) + public void testSchemaValidation(DomainModelScope modelScope) { + new SchemaValidator().validate( modelScope.getDomainModel() ); } @Entity(name = "Foo") diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/MySqlExistingEnumColumnValidationTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/MySqlExistingEnumColumnValidationTest.java index 0a8d717faa30..c4ced224a006 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/MySqlExistingEnumColumnValidationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/MySqlExistingEnumColumnValidationTest.java @@ -4,22 +4,6 @@ */ package org.hibernate.orm.test.schemavalidation; -import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.registry.StandardServiceRegistry; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.cfg.AvailableSettings; -import org.hibernate.dialect.MySQLDialect; -import org.hibernate.tool.hbm2ddl.SchemaValidator; - -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.orm.junit.RequiresDialect; -import org.hibernate.testing.transaction.TransactionUtil; -import org.hibernate.testing.util.ServiceRegistryUtil; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; - import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.EnumType; @@ -27,51 +11,63 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; import jakarta.persistence.Table; +import org.hibernate.boot.MetadataSources; +import org.hibernate.dialect.MySQLDialect; +import org.hibernate.testing.jdbc.JdbcUtils; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.hibernate.testing.orm.junit.ServiceRegistry; +import org.hibernate.testing.orm.junit.ServiceRegistryScope; +import org.hibernate.tool.hbm2ddl.SchemaValidator; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import static jakarta.persistence.GenerationType.IDENTITY; +@SuppressWarnings("JUnitMalformedDeclaration") @JiraKey("HHH-16498") @RequiresDialect(MySQLDialect.class) -public class MySqlExistingEnumColumnValidationTest extends BaseCoreFunctionalTestCase { - - private StandardServiceRegistry ssr; - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { EntityE.class }; - } - - @Before - public void setUp() { - TransactionUtil.doInHibernate( this::sessionFactory, session -> { - session.createNativeQuery( "DROP TABLE IF EXISTS en CASCADE" ).executeUpdate(); - session.createNativeQuery( - "CREATE TABLE en (id INTEGER NOT NULL AUTO_INCREMENT, sign_position enum ('AFTER_NO_SPACE','AFTER_WITH_SPACE','BEFORE_NO_SPACE','BEFORE_WITH_SPACE'), PRIMARY KEY (id))" ) - .executeUpdate(); +@ServiceRegistry +public class MySqlExistingEnumColumnValidationTest { + @BeforeEach + void setUp(ServiceRegistryScope registryScope) { + JdbcUtils.withConnection( registryScope.getRegistry(), connection -> { + try ( var statement = connection.createStatement() ) { + statement.execute( "DROP TABLE IF EXISTS en CASCADE" ); + statement.execute( + """ + CREATE TABLE en ( + id INTEGER NOT NULL AUTO_INCREMENT, + sign_position enum ( + 'AFTER_NO_SPACE', + 'AFTER_WITH_SPACE', + 'BEFORE_NO_SPACE', + 'BEFORE_WITH_SPACE' + ), + PRIMARY KEY (id) + ) + """ + ); + } } ); } - @After - public void tearDown() { - TransactionUtil.doInHibernate( this::sessionFactory, session -> { - session.createNativeQuery( "DROP TABLE en CASCADE" ).executeUpdate(); + @AfterEach + void tearDown(ServiceRegistryScope registryScope) { + JdbcUtils.withConnection( registryScope.getRegistry(), connection -> { + try ( var statement = connection.createStatement() ) { + statement.execute( "DROP TABLE en CASCADE" ); + } } ); } @Test - public void testSynonymUsingGroupedSchemaValidator() { - ssr = ServiceRegistryUtil.serviceRegistryBuilder() - .applySetting( AvailableSettings.HBM2DDL_AUTO, "validate" ) - .build(); - try { - final MetadataSources metadataSources = new MetadataSources( ssr ); - metadataSources.addAnnotatedClass( EntityE.class ); + public void testSynonymUsingGroupedSchemaValidator(ServiceRegistryScope registryScope) { + final MetadataSources metadataSources = new MetadataSources( registryScope.getRegistry() ); + metadataSources.addAnnotatedClass( EntityE.class ); - new SchemaValidator().validate( metadataSources.buildMetadata() ); - } - finally { - StandardServiceRegistryBuilder.destroy( ssr ); - } + new SchemaValidator().validate( metadataSources.buildMetadata() ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/NumericValidationTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/NumericValidationTest.java index 3645638b7658..32e1655dd6ba 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/NumericValidationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/NumericValidationTest.java @@ -4,141 +4,126 @@ */ package org.hibernate.orm.test.schemavalidation; -import java.math.BigDecimal; -import java.util.Arrays; -import java.util.Collection; -import java.util.EnumSet; -import java.util.Map; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.Id; - -import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.boot.spi.MetadataImplementor; -import org.hibernate.cfg.AvailableSettings; import org.hibernate.engine.config.spi.ConfigurationService; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.ServiceRegistryFunctionalTesting; +import org.hibernate.testing.orm.junit.ServiceRegistryProducer; +import org.hibernate.testing.orm.junit.ServiceRegistryScope; import org.hibernate.tool.hbm2ddl.SchemaExport; import org.hibernate.tool.schema.JdbcMetadataAccessStrategy; -import org.hibernate.tool.schema.SourceType; import org.hibernate.tool.schema.TargetType; import org.hibernate.tool.schema.internal.ExceptionHandlerLoggedImpl; import org.hibernate.tool.schema.spi.ContributableMatcher; import org.hibernate.tool.schema.spi.ExceptionHandler; import org.hibernate.tool.schema.spi.ExecutionOptions; import org.hibernate.tool.schema.spi.SchemaManagementTool; -import org.hibernate.tool.schema.spi.ScriptSourceInput; -import org.hibernate.tool.schema.spi.ScriptTargetOutput; -import org.hibernate.tool.schema.spi.SourceDescriptor; -import org.hibernate.tool.schema.spi.TargetDescriptor; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedClass; +import org.junit.jupiter.params.provider.MethodSource; -import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.util.ServiceRegistryUtil; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.Parameterized; +import java.math.BigDecimal; +import java.util.EnumSet; +import java.util.List; +import java.util.Map; + +import static org.hibernate.cfg.SchemaToolingSettings.HBM2DDL_JDBC_METADATA_EXTRACTOR_STRATEGY; /** * @author Jonathan Bregler */ @JiraKey(value = "HHH-12203") -@RunWith(Parameterized.class) -public class NumericValidationTest implements ExecutionOptions { - @Parameterized.Parameters - public static Collection parameters() { - return Arrays.asList( - JdbcMetadataAccessStrategy.GROUPED.toString(), - JdbcMetadataAccessStrategy.INDIVIDUALLY.toString() +@TestInstance( TestInstance.Lifecycle.PER_METHOD ) +@ParameterizedClass +@MethodSource("extractorStrategies") +@ServiceRegistryFunctionalTesting +@DomainModel(annotatedClasses = NumericValidationTest.TestEntity.class) +public class NumericValidationTest implements ServiceRegistryProducer { + static List extractorStrategies() { + return List.of( + JdbcMetadataAccessStrategy.GROUPED, + JdbcMetadataAccessStrategy.INDIVIDUALLY ); } - @Parameterized.Parameter - public String jdbcMetadataExtractorStrategy; + private final JdbcMetadataAccessStrategy extractorStrategy; - private StandardServiceRegistry ssr; - private MetadataImplementor metadata; + public NumericValidationTest(JdbcMetadataAccessStrategy extractorStrategy) { + this.extractorStrategy = extractorStrategy; + } - @Before - public void beforeTest() { - ssr = ServiceRegistryUtil.serviceRegistryBuilder() - .applySetting( - AvailableSettings.HBM2DDL_JDBC_METADATA_EXTRACTOR_STRATEGY, - jdbcMetadataExtractorStrategy - ) + @Override + public StandardServiceRegistry produceServiceRegistry(StandardServiceRegistryBuilder builder) { + return builder + .applySetting( HBM2DDL_JDBC_METADATA_EXTRACTOR_STRATEGY, extractorStrategy ) .build(); - metadata = (MetadataImplementor) new MetadataSources( ssr ) - .addAnnotatedClass( TestEntity.class ) - .buildMetadata(); - metadata.orderColumns( false ); - metadata.validate(); - - try { - dropSchema(); - // create the schema - createSchema(); - } - catch (Exception e) { - tearDown(); - throw e; - } } - @After - public void tearDown() { - dropSchema(); - if ( ssr != null ) { - StandardServiceRegistryBuilder.destroy( ssr ); - } + @BeforeEach + void setUp(DomainModelScope modelScope) { + final var model = modelScope.getDomainModel(); + model.orderColumns( false ); + model.validate(); + + dropSchema( model ); + createSchema( model ); } - @Test - public void testValidation() { - doValidation(); + private void dropSchema(MetadataImplementor model) { + new SchemaExport().drop( EnumSet.of( TargetType.DATABASE ), model ); } - private void doValidation() { - ssr.getService( SchemaManagementTool.class ).getSchemaValidator( null ) - .doValidation( metadata, this, ContributableMatcher.ALL ); + private void createSchema(MetadataImplementor model) { + new SchemaExport().create( EnumSet.of( TargetType.DATABASE ), model ); } - private void createSchema() { - ssr.getService( SchemaManagementTool.class ).getSchemaCreator( null ).doCreation( - metadata, - this, - ContributableMatcher.ALL, - new SourceDescriptor() { - @Override - public SourceType getSourceType() { - return SourceType.METADATA; - } - - @Override - public ScriptSourceInput getScriptSourceInput() { - return null; - } - }, - new TargetDescriptor() { - @Override - public EnumSet getTargetTypes() { - return EnumSet.of( TargetType.DATABASE ); - } - - @Override - public ScriptTargetOutput getScriptTargetOutput() { - return null; - } - } - ); + @AfterEach + void tearDown(DomainModelScope modelScope) { + final var model = modelScope.getDomainModel(); + model.orderColumns( false ); + model.validate(); + + dropSchema( model ); } - private void dropSchema() { - new SchemaExport() - .drop( EnumSet.of( TargetType.DATABASE ), metadata ); + @Test + public void testValidation(ServiceRegistryScope registryScope, DomainModelScope modelScope) { + final var tool = registryScope.getRegistry().requireService( SchemaManagementTool.class ); + + final var execOptions = new ExecutionOptions() { + final Map settings = registryScope.getRegistry().requireService( ConfigurationService.class ).getSettings(); + + @Override + public Map getConfigurationValues() { + return settings; + } + + @Override + public boolean shouldManageNamespaces() { + return false; + } + + @Override + public ExceptionHandler getExceptionHandler() { + return ExceptionHandlerLoggedImpl.INSTANCE; + } + }; + + tool.getSchemaValidator( null ).doValidation( modelScope.getDomainModel(), execOptions, ContributableMatcher.ALL ); } + + @SuppressWarnings("unused") @Entity(name = "TestEntity") public static class TestEntity { @Id @@ -147,19 +132,4 @@ public static class TestEntity { @Column(name = "numberValue") BigDecimal number; } - - @Override - public Map getConfigurationValues() { - return ssr.requireService( ConfigurationService.class ).getSettings(); - } - - @Override - public boolean shouldManageNamespaces() { - return false; - } - - @Override - public ExceptionHandler getExceptionHandler() { - return ExceptionHandlerLoggedImpl.INSTANCE; - } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/ViewValidationTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/ViewValidationTest.java index 441fe5a925cb..e792f1d52ca3 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/ViewValidationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/ViewValidationTest.java @@ -8,103 +8,94 @@ import jakarta.persistence.Entity; import jakarta.persistence.Id; import jakarta.persistence.Table; - -import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.cfg.AvailableSettings; -import org.hibernate.dialect.CockroachDialect; import org.hibernate.dialect.H2Dialect; -import org.hibernate.testing.SkipForDialect; - import org.hibernate.dialect.PostgreSQLDialect; +import org.hibernate.testing.jdbc.JdbcUtils; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.hibernate.testing.orm.junit.ServiceRegistryFunctionalTesting; +import org.hibernate.testing.orm.junit.ServiceRegistryProducer; +import org.hibernate.testing.orm.junit.ServiceRegistryScope; +import org.hibernate.tool.hbm2ddl.SchemaExport; import org.hibernate.tool.hbm2ddl.SchemaValidator; import org.hibernate.tool.schema.JdbcMetadataAccessStrategy; +import org.hibernate.tool.schema.TargetType; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedClass; +import org.junit.jupiter.params.provider.MethodSource; + +import java.util.EnumSet; +import java.util.List; -import org.hibernate.testing.RequiresDialect; -import org.hibernate.testing.RequiresDialects; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.hibernate.testing.transaction.TransactionUtil; -import org.hibernate.testing.util.ServiceRegistryUtil; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; +import static org.hibernate.cfg.SchemaToolingSettings.ENABLE_SYNONYMS; +import static org.hibernate.cfg.SchemaToolingSettings.HBM2DDL_JDBC_METADATA_EXTRACTOR_STRATEGY; /** * @author Andrea Boriero */ -@RequiresDialects({ - @RequiresDialect(PostgreSQLDialect.class), - @RequiresDialect(H2Dialect.class) -}) -@SkipForDialect(value = CockroachDialect.class, comment = "https://github.com/cockroachdb/cockroach/issues/10028") -public class ViewValidationTest extends BaseCoreFunctionalTestCase { - private StandardServiceRegistry ssr; +@RequiresDialect(PostgreSQLDialect.class) +@RequiresDialect(H2Dialect.class) +@TestInstance( TestInstance.Lifecycle.PER_METHOD ) +@ParameterizedClass +@MethodSource("extractorStrategies") +@ServiceRegistryFunctionalTesting +@DomainModel(annotatedClasses = ViewValidationTest.TestEntity.class) +public class ViewValidationTest implements ServiceRegistryProducer { + static List extractorStrategies() { + return List.of( + JdbcMetadataAccessStrategy.GROUPED, + JdbcMetadataAccessStrategy.INDIVIDUALLY + ); + } - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] {TestEntity.class}; + private final JdbcMetadataAccessStrategy extractorStrategy; + + public ViewValidationTest(JdbcMetadataAccessStrategy extractorStrategy) { + this.extractorStrategy = extractorStrategy; } - @Before - public void setUp() { - TransactionUtil.doInHibernate( this::sessionFactory, session -> { - session.createNativeQuery( "CREATE VIEW test_synonym AS SELECT * FROM test_entity" ).executeUpdate(); - } ); + @Override + public StandardServiceRegistry produceServiceRegistry(StandardServiceRegistryBuilder builder) { + return builder + .applySetting( ENABLE_SYNONYMS, true ) + .applySetting( HBM2DDL_JDBC_METADATA_EXTRACTOR_STRATEGY, extractorStrategy ) + .build(); } - @After - public void tearDown() { - TransactionUtil.doInHibernate( this::sessionFactory, session -> { - session.createNativeQuery( "DROP VIEW test_synonym CASCADE" ).executeUpdate(); + @BeforeEach + void setUp(ServiceRegistryScope registryScope, DomainModelScope modelScope) { + new SchemaExport().create( EnumSet.of( TargetType.DATABASE ), modelScope.getDomainModel() ); + JdbcUtils.withConnection( registryScope.getRegistry(), connection -> { + try (var statement = connection.createStatement()) { + statement.execute( "CREATE VIEW test_synonym AS SELECT * FROM test_entity" ); + } } ); } - @Test - public void testSynonymUsingGroupedSchemaValidator() { - ssr = ServiceRegistryUtil.serviceRegistryBuilder() - .applySetting( AvailableSettings.ENABLE_SYNONYMS, "true" ) - .applySetting( - AvailableSettings.HBM2DDL_JDBC_METADATA_EXTRACTOR_STRATEGY, - JdbcMetadataAccessStrategy.GROUPED - ) - .build(); - try { - final MetadataSources metadataSources = new MetadataSources( ssr ); - metadataSources.addAnnotatedClass( TestEntityWithSynonym.class ); - metadataSources.addAnnotatedClass( TestEntity.class ); - - new SchemaValidator().validate( metadataSources.buildMetadata() ); - } - finally { - StandardServiceRegistryBuilder.destroy( ssr ); - } + @AfterEach + void tearDown(ServiceRegistryScope registryScope, DomainModelScope modelScope) { + JdbcUtils.withConnection( registryScope.getRegistry(), connection -> { + try (var statement = connection.createStatement()) { + statement.execute( "DROP VIEW test_synonym CASCADE" ); + } + } ); + new SchemaExport().drop( EnumSet.of( TargetType.DATABASE ), modelScope.getDomainModel() ); } @Test - public void testSynonymUsingIndividuallySchemaValidator() { - ssr = ServiceRegistryUtil.serviceRegistryBuilder() - .applySetting( AvailableSettings.ENABLE_SYNONYMS, "true" ) - .applySetting( - AvailableSettings.HBM2DDL_JDBC_METADATA_EXTRACTOR_STRATEGY, - JdbcMetadataAccessStrategy.INDIVIDUALLY - ) - .build(); - try { - final MetadataSources metadataSources = new MetadataSources( ssr ); - metadataSources.addAnnotatedClass( TestEntityWithSynonym.class ); - metadataSources.addAnnotatedClass( TestEntity.class ); - - new SchemaValidator().validate( metadataSources.buildMetadata() ); - } - finally { - StandardServiceRegistryBuilder.destroy( ssr ); - } + public void testSynonymValidation(DomainModelScope modelScope) { + new SchemaValidator().validate( modelScope.getDomainModel() ); } @Entity @Table(name = "test_entity") - private static class TestEntity { + public static class TestEntity { @Id private Long id; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/matchingtablenames/TableNamesWithUnderscoreTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/matchingtablenames/TableNamesWithUnderscoreTest.java index 491377a68bae..a8922c79a3cb 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/matchingtablenames/TableNamesWithUnderscoreTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/schemavalidation/matchingtablenames/TableNamesWithUnderscoreTest.java @@ -9,30 +9,35 @@ import jakarta.persistence.GeneratedValue; import jakarta.persistence.Id; import jakarta.persistence.Table; - -import org.hibernate.tool.hbm2ddl.SchemaValidator; - -import org.junit.Test; - +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.DomainModelScope; import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.tool.hbm2ddl.SchemaValidator; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; /** * @author Andrea Boriero */ +@SuppressWarnings("JUnitMalformedDeclaration") @JiraKey(value = "HHH-10718") -public class TableNamesWithUnderscoreTest extends BaseNonConfigCoreFunctionalTestCase { - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { - Entity1.class, - Entity01.class - }; +@DomainModel(annotatedClasses = { + TableNamesWithUnderscoreTest.Entity1.class, + TableNamesWithUnderscoreTest.Entity01.class +}) +@SessionFactory +public class TableNamesWithUnderscoreTest { + @BeforeEach + public void setUp(SessionFactoryScope factoryScope) { + // force schema export + factoryScope.getSessionFactory(); } @Test - public void testSchemaValidationDoesNotFailDueToAMoreThanOneTableFound() { - new SchemaValidator().validate( metadata() ); + public void testSchemaValidationDoesNotFailDueToAMoreThanOneTableFound(DomainModelScope modelScope) { + new SchemaValidator().validate( modelScope.getDomainModel() ); } @Entity(name = "Entity1") diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/type/AbstractJavaTimeTypeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/type/AbstractJavaTimeTypeTest.java deleted file mode 100644 index 690c1aca29b3..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/type/AbstractJavaTimeTypeTest.java +++ /dev/null @@ -1,426 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.test.type; - -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.time.ZoneId; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import java.util.TimeZone; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.Future; -import java.util.function.Consumer; -import java.util.function.Predicate; - -import org.hibernate.boot.model.TypeContributions; -import org.hibernate.cfg.AvailableSettings; -import org.hibernate.cfg.Configuration; -import org.hibernate.dialect.Dialect; -import org.hibernate.dialect.H2Dialect; -import org.hibernate.service.ServiceRegistry; - -import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.jdbc.SharedDriverManagerConnectionProvider; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.hibernate.testing.junit4.CustomParameterized; -import org.hibernate.testing.orm.junit.DialectContext; -import org.junit.Assume; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import static org.hibernate.dialect.SimpleDatabaseVersion.ZERO_VERSION; -import static org.junit.Assert.assertEquals; - -/** - * Tests for storage of Instant properties. - * - * @param The time type being tested. - * @param The entity type used in tests. - */ -@RunWith(CustomParameterized.class) -public abstract class AbstractJavaTimeTypeTest extends BaseCoreFunctionalTestCase { - - private static Dialect determineDialect() { - try { - return DialectContext.getDialect(); - } - catch (Exception e) { - return new Dialect( ZERO_VERSION ) {}; - } - } - - protected static final String ENTITY_NAME = "theentity"; - protected static final String ID_COLUMN_NAME = "theid"; - protected static final String PROPERTY_COLUMN_NAME = "thevalue"; - - protected static final ZoneId ZONE_UTC_MINUS_8 = ZoneId.of( "UTC-8" ); - protected static final ZoneId ZONE_PARIS = ZoneId.of( "Europe/Paris" ); - protected static final ZoneId ZONE_GMT = ZoneId.of( "GMT" ); - protected static final ZoneId ZONE_OSLO = ZoneId.of( "Europe/Oslo" ); - protected static final ZoneId ZONE_AMSTERDAM = ZoneId.of( "Europe/Amsterdam" ); - protected static final ZoneId ZONE_AUCKLAND = ZoneId.of( "Pacific/Auckland" ); - protected static final ZoneId ZONE_SANTIAGO = ZoneId.of( "America/Santiago" ); - - private final EnvironmentParameters env; - - public AbstractJavaTimeTypeTest(EnvironmentParameters env) { - this.env = env; - } - - @Override - protected final Class[] getAnnotatedClasses() { - return new Class[] { getEntityType() }; - } - - @Override - protected void configure(Configuration configuration) { - super.configure( configuration ); - if ( env.hibernateJdbcTimeZone != null ) { - configuration.setProperty( AvailableSettings.JDBC_TIME_ZONE, env.hibernateJdbcTimeZone.getId() ); - } - if ( env.remappingDialectClass != null ) { - configuration.setProperty( AvailableSettings.DIALECT, env.remappingDialectClass.getName() ); - } - } - - protected abstract Class getEntityType(); - - protected abstract E createEntityForHibernateWrite(int id); - - protected abstract T getExpectedPropertyValueAfterHibernateRead(); - - protected abstract T getActualPropertyValue(E entity); - - protected abstract void setJdbcValueForNonHibernateWrite(PreparedStatement statement, int parameterIndex) throws SQLException; - - protected abstract Object getExpectedJdbcValueAfterHibernateWrite(); - - protected abstract Object getActualJdbcValue(ResultSet resultSet, int columnIndex) throws SQLException; - - @Before - public void cleanup() { - inTransaction( session -> { - session.createNativeQuery( "DELETE FROM " + ENTITY_NAME ).executeUpdate(); - } ); - } - - @Test - @JiraKey(value = "HHH-13266") - public void writeThenRead() { - withDefaultTimeZone( () -> { - inTransaction( session -> { - session.persist( createEntityForHibernateWrite( 1 ) ); - } ); - inTransaction( session -> { - T read = getActualPropertyValue( session.find( getEntityType(), 1 ) ); - T expected = getExpectedPropertyValueAfterHibernateRead(); - assertEquals( - "Writing then reading a value should return the original value", - expected, read - ); - } ); - } ); - } - - @Test - @JiraKey(value = "HHH-13266") - public void writeThenNativeRead() { - assumeNoJdbcTimeZone(); - - withDefaultTimeZone( () -> { - inTransaction( session -> { - session.persist( createEntityForHibernateWrite( 1 ) ); - } ); - inTransaction( session -> { - session.doWork( connection -> { - try (PreparedStatement statement = connection.prepareStatement( - "SELECT " + PROPERTY_COLUMN_NAME + " FROM " + ENTITY_NAME + " WHERE " + ID_COLUMN_NAME + " = ?" - )) { - statement.setInt( 1, 1 ); - statement.execute(); - try (ResultSet resultSet = statement.getResultSet()) { - resultSet.next(); - Object nativeRead = getActualJdbcValue( resultSet, 1 ); - Object expected = getExpectedJdbcValueAfterHibernateWrite(); - assertEquals( - "Values written by Hibernate ORM should match the original value (same day, hour, ...)", - expected, nativeRead - ); - } - } - } ); - } ); - } ); - } - - @Test - @JiraKey(value = "HHH-13266") - public void nativeWriteThenRead() { - assumeNoJdbcTimeZone(); - - withDefaultTimeZone( () -> { - inTransaction( session -> { - session.doWork( connection -> { - try (PreparedStatement statement = connection.prepareStatement( - "INSERT INTO " + ENTITY_NAME + " (" + ID_COLUMN_NAME + ", " + PROPERTY_COLUMN_NAME + ") " - + " VALUES ( ? , ? )" - )) { - statement.setInt( 1, 1 ); - setJdbcValueForNonHibernateWrite( statement, 2 ); - statement.execute(); - } - } ); - } ); - inTransaction( session -> { - T read = getActualPropertyValue( session.find( getEntityType(), 1 ) ); - T expected = getExpectedPropertyValueAfterHibernateRead(); - assertEquals( - "Values written without Hibernate ORM should be read correctly by Hibernate ORM", - expected, read - ); - } ); - } ); - } - - protected final void withDefaultTimeZone(Runnable runnable) { - TimeZone timeZoneBefore = TimeZone.getDefault(); - TimeZone.setDefault( toTimeZone( env.defaultJvmTimeZone ) ); - SharedDriverManagerConnectionProvider.getInstance().onDefaultTimeZoneChange(); - /* - * Run the code in a new thread, because some libraries (looking at you, h2 JDBC driver) - * cache data dependent on the default timezone in thread local variables, - * and we want this data to be reinitialized with the new default time zone. - */ - try { - ExecutorService executor = Executors.newSingleThreadExecutor(); - Future future = executor.submit( runnable ); - executor.shutdown(); - future.get(); - } - catch (InterruptedException e) { - throw new IllegalStateException( "Interrupted while testing", e ); - } - catch (ExecutionException e) { - Throwable cause = e.getCause(); - if ( cause instanceof RuntimeException ) { - throw (RuntimeException) cause; - } - else if ( cause instanceof Error ) { - throw (Error) cause; - } - else { - throw new IllegalStateException( "Unexpected exception while testing", cause ); - } - } - finally { - TimeZone.setDefault( timeZoneBefore ); - SharedDriverManagerConnectionProvider.getInstance().onDefaultTimeZoneChange(); - } - } - - private static TimeZone toTimeZone(ZoneId zoneId) { - String idString = zoneId.getId(); - if ( idString.startsWith( "UTC+" ) || idString.startsWith( "UTC-" ) ) { - // Apparently TimeZone doesn't understand UTC+XXX nor UTC-XXX - // Using GMT+XXX or GMT-XXX as a fallback - idString = "GMT" + idString.substring( "UTC".length() ); - } - - TimeZone result = TimeZone.getTimeZone( idString ); - if ( !idString.equals( result.getID() ) ) { - // If the timezone is not understood, getTimeZone returns GMT and the condition above is true - throw new IllegalStateException( "Attempting to test an unsupported timezone: " + zoneId ); - } - - return result; - } - - protected final Class getRemappingDialectClass() { - return env.remappingDialectClass; - } - - protected void assumeNoJdbcTimeZone() { - Assume.assumeTrue( - "Tests with native read/writes are only relevant when not using " + AvailableSettings.JDBC_TIME_ZONE - + ", because the expectations do not take that time zone into account." - + " When this property is set, we only test that a write by Hibernate followed by " - + " a read by Hibernate returns the same value.", - env.hibernateJdbcTimeZone == null - ); - } - - protected static abstract class AbstractParametersBuilder> { - - private final Dialect dialect; - - private final List result = new ArrayList<>(); - - private final List> remappingDialectClasses = new ArrayList<>(); - - private ZoneId forcedJdbcTimeZone = null; - - protected AbstractParametersBuilder() { - dialect = determineDialect(); - remappingDialectClasses.add( null ); // Always test without remapping - } - - public S skippedForDialects(List> dialectClasses, Consumer skippedIfDialectMatchesClasses) { - boolean skip = false; - for ( Class dialectClass : dialectClasses ) { - if ( dialectClass.isInstance( dialect ) ) { - skip = true; - } - } - if ( !skip ) { - skippedIfDialectMatchesClasses.accept( thisAsS() ); - } - return thisAsS(); - } - - public S skippedForDialects(Predicate skipPredicate, Consumer skippedIfDialectMatchesClasses) { - if ( !skipPredicate.test( dialect ) ) { - skippedIfDialectMatchesClasses.accept( thisAsS() ); - } - return thisAsS(); - } - - public S withForcedJdbcTimezone(String zoneIdString, Consumer contributor) { - ZoneId zoneId = ZoneId.of( zoneIdString ); - this.forcedJdbcTimeZone = zoneId; - try { - contributor.accept( thisAsS() ); - } - finally { - this.forcedJdbcTimeZone = null; - } - return thisAsS(); - } - - @SafeVarargs - public final S alsoTestRemappingsWithH2(Class ... dialectClasses) { - if ( dialect instanceof H2Dialect && !( (H2Dialect) dialect ).hasOddDstBehavior() ) { - // Only test remappings with H2 - Collections.addAll( remappingDialectClasses, dialectClasses ); - } - return thisAsS(); - } - - protected final boolean isNanosecondPrecisionSupported() { - // This used to return true for H2Dialect, but as of 1.4.197 h2 does not use ns precision by default anymore. - // Bringing back ns precision would require timestamp(9) in the dialect class. - return false; - } - - protected final S add(ZoneId defaultJvmTimeZone, Object ... subClassParameters) { - for ( Class remappingDialectClass : remappingDialectClasses ) { - List parameters = new ArrayList<>(); - parameters.add( - new EnvironmentParameters( - defaultJvmTimeZone, - forcedJdbcTimeZone, - remappingDialectClass - ) - ); - Collections.addAll( parameters, subClassParameters ); - result.add( parameters.toArray() ); - } - if ( forcedJdbcTimeZone == null ) { - for ( ZoneId hibernateJdbcTimeZone : getHibernateJdbcTimeZonesToTest() ) { - List parameters = new ArrayList<>(); - parameters.add( - new EnvironmentParameters( - defaultJvmTimeZone, - hibernateJdbcTimeZone, - null - ) - ); - Collections.addAll( parameters, subClassParameters ); - result.add( parameters.toArray() ); - } - } - return thisAsS(); - } - - protected Iterable getHibernateJdbcTimeZonesToTest() { - return Arrays.asList( ZONE_GMT, ZONE_OSLO ); - } - - private S thisAsS() { - return (S) this; - } - - public List build() { - return result; - } - - } - - protected final static class EnvironmentParameters { - - /* - * The default timezone affects conversions done using java.util, - * which is why we take it into account even with timezone-independent types such as Instant. - */ - private final ZoneId defaultJvmTimeZone; - - /** - * The Hibernate setting, {@value AvailableSettings#JDBC_TIME_ZONE}, - * may affect a lot of time-related types, - * which is why we take it into account even with timezone-independent types such as Instant. - */ - private final ZoneId hibernateJdbcTimeZone; - - private final Class remappingDialectClass; - - private EnvironmentParameters(ZoneId defaultJvmTimeZone, ZoneId hibernateJdbcTimeZone, - Class remappingDialectClass) { - this.defaultJvmTimeZone = defaultJvmTimeZone; - this.hibernateJdbcTimeZone = hibernateJdbcTimeZone; - this.remappingDialectClass = remappingDialectClass; - } - - @Override - public String toString() { - return String.format( - "[JVM TZ: %s, JDBC TZ: %s, remapping dialect: %s]", - defaultJvmTimeZone, - hibernateJdbcTimeZone, - remappingDialectClass == null ? null : remappingDialectClass.getSimpleName() - ); - } - } - - protected static class AbstractRemappingH2Dialect extends H2Dialect { - private final int overriddenSqlTypeCode; - private final int overridingSqlTypeCode; - - public AbstractRemappingH2Dialect(int overriddenSqlTypeCode, int overridingSqlTypeCode) { - super( getDialect().getVersion() ); - this.overriddenSqlTypeCode = overriddenSqlTypeCode; - this.overridingSqlTypeCode = overridingSqlTypeCode; - } - - @Override - public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) { - super.contributeTypes( typeContributions, serviceRegistry ); - - typeContributions.getTypeConfiguration().getJdbcTypeRegistry().addDescriptor( - overriddenSqlTypeCode, - typeContributions.getTypeConfiguration().getJdbcTypeRegistry().getDescriptor( - overridingSqlTypeCode - ) - ); - } - - } - -} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/type/InstantTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/type/InstantTest.java deleted file mode 100644 index 3ae11ca27fcb..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/type/InstantTest.java +++ /dev/null @@ -1,200 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.test.type; - -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Timestamp; -import java.time.Instant; -import java.time.OffsetDateTime; -import java.time.ZoneId; -import java.time.ZoneOffset; -import java.util.Arrays; -import java.util.Calendar; -import java.util.List; -import java.util.TimeZone; - -import jakarta.persistence.Basic; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; - -import org.hibernate.dialect.H2Dialect; -import org.hibernate.dialect.MariaDBDialect; -import org.hibernate.dialect.MySQLDialect; -import org.hibernate.dialect.SybaseASEDialect; -import org.hibernate.dialect.SybaseDialect; -import org.hibernate.dialect.TimeZoneSupport; - -import org.junit.runners.Parameterized; - -/** - * Tests for storage of Instant properties. - */ -public class InstantTest extends AbstractJavaTimeTypeTest { - - private static class ParametersBuilder extends AbstractParametersBuilder { - public ParametersBuilder add(int year, int month, int day, - int hour, int minute, int second, int nanosecond, ZoneId defaultTimeZone) { - if ( !isNanosecondPrecisionSupported() ) { - nanosecond = 0; - } - return add( defaultTimeZone, year, month, day, hour, minute, second, nanosecond ); - } - } - - @Parameterized.Parameters(name = "{1}-{2}-{3}T{4}:{5}:{6}.{7}Z {0}") - public static List data() { - return new ParametersBuilder() - // Not affected by any known bug - .add( 2017, 11, 6, 19, 19, 1, 0, ZONE_UTC_MINUS_8 ) - .add( 2017, 11, 6, 19, 19, 1, 0, ZONE_PARIS ) - .add( 2017, 11, 6, 19, 19, 1, 500, ZONE_PARIS ) - .skippedForDialects( - // MySQL/Mariadb cannot store values equal to epoch exactly, or less, in a timestamp. - Arrays.asList( MySQLDialect.class, MariaDBDialect.class ), - b -> b - .add( 1970, 1, 1, 0, 0, 0, 0, ZONE_GMT ) - .add( 1900, 1, 1, 0, 0, 0, 0, ZONE_GMT ) - .add( 1900, 1, 1, 0, 0, 0, 0, ZONE_OSLO ) - .add( 1900, 1, 1, 0, 0, 0, 0, ZONE_PARIS ) - .add( 1900, 1, 2, 0, 9, 21, 0, ZONE_PARIS ) - .add( 1900, 1, 1, 0, 0, 0, 0, ZONE_AMSTERDAM ) - .add( 1900, 1, 2, 0, 19, 32, 0, ZONE_AMSTERDAM ) - .add( 1899, 12, 31, 23, 59, 59, 999_999_999, ZONE_PARIS ) - .add( 1899, 12, 31, 23, 59, 59, 999_999_999, ZONE_AMSTERDAM ) - ) - .skippedForDialects( - // MySQL/Mariadb/Sybase cannot store dates in 1600 in a timestamp. - dialect -> dialect instanceof MySQLDialect || dialect instanceof MariaDBDialect - || dialect instanceof SybaseDialect - || dialect instanceof H2Dialect && ( (H2Dialect) dialect ).hasOddDstBehavior(), - b -> b - .add( 1600, 1, 1, 0, 0, 0, 0, ZONE_AMSTERDAM ) - // Affected by HHH-13266 (JDK-8061577) - .add( 1892, 1, 1, 0, 0, 0, 0, ZONE_OSLO ) - ) - // HHH-13379: DST end (where Timestamp becomes ambiguous, see JDK-4312621) - // => This used to work correctly in 5.4.1.Final and earlier - .skippedForDialects( - dialect -> dialect instanceof H2Dialect && ( (H2Dialect) dialect ).hasOddDstBehavior(), - b -> b.add( 2018, 10, 28, 1, 0, 0, 0, ZONE_PARIS ) - .add( 2018, 3, 31, 14, 0, 0, 0, ZONE_AUCKLAND ) - ) - // => This has never worked correctly, unless the JDBC timezone was set to UTC - .withForcedJdbcTimezone( "UTC", b -> b - .add( 2018, 10, 28, 0, 0, 0, 0, ZONE_PARIS ) - .add( 2018, 3, 31, 13, 0, 0, 0, ZONE_AUCKLAND ) - ) - // => Also test DST start, just in case - .add( 2018, 3, 25, 1, 0, 0, 0, ZONE_PARIS ) - .skippedForDialects( - // No idea what Sybase is doing here exactly - dialect -> dialect instanceof SybaseASEDialect, - b -> b.add( 2018, 3, 25, 2, 0, 0, 0, ZONE_PARIS ) - .add( 2018, 9, 30, 2, 0, 0, 0, ZONE_AUCKLAND ) - ) - .add( 2018, 9, 30, 3, 0, 0, 0, ZONE_AUCKLAND ) - // => Also test dates around 1905-01-01, because the code behaves differently before and after 1905 - .add( 1904, 12, 31, 22, 59, 59, 999_999_999, ZONE_PARIS ) - .add( 1904, 12, 31, 23, 59, 59, 999_999_999, ZONE_PARIS ) - .add( 1905, 1, 1, 0, 59, 59, 999_999_999, ZONE_PARIS ) - .add( 1904, 12, 31, 23, 0, 0, 0, ZONE_PARIS ) - .add( 1905, 1, 1, 0, 0, 0, 0, ZONE_PARIS ) - .add( 1905, 1, 1, 1, 0, 0, 0, ZONE_PARIS ) - .build(); - } - - private final int year; - private final int month; - private final int day; - private final int hour; - private final int minute; - private final int second; - private final int nanosecond; - - public InstantTest(EnvironmentParameters env, int year, int month, int day, - int hour, int minute, int second, int nanosecond) { - super( env ); - this.year = year; - this.month = month; - this.day = day; - this.hour = hour; - this.minute = minute; - this.second = second; - this.nanosecond = nanosecond; - } - - @Override - protected Class getEntityType() { - return EntityWithInstant.class; - } - - @Override - protected EntityWithInstant createEntityForHibernateWrite(int id) { - return new EntityWithInstant( id, getExpectedPropertyValueAfterHibernateRead() ); - } - - @Override - protected Instant getExpectedPropertyValueAfterHibernateRead() { - return OffsetDateTime.of( year, month, day, hour, minute, second, nanosecond, ZoneOffset.UTC ).toInstant(); - } - - @Override - protected Instant getActualPropertyValue(EntityWithInstant entity) { - return entity.value; - } - - @Override - protected void setJdbcValueForNonHibernateWrite(PreparedStatement statement, int parameterIndex) throws SQLException { - if ( sessionFactory().getJdbcServices().getDialect().getTimeZoneSupport() == TimeZoneSupport.NATIVE ) { - // Oracle and H2 require reading/writing through OffsetDateTime to avoid TZ related miscalculations - statement.setObject( parameterIndex, getExpectedJdbcValueAfterHibernateWrite().toInstant().atOffset( ZoneOffset.UTC ) ); - } - else { - statement.setTimestamp( - parameterIndex, - getExpectedJdbcValueAfterHibernateWrite(), - Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) ) - ); - } - } - - @Override - protected Timestamp getExpectedJdbcValueAfterHibernateWrite() { - return Timestamp.from( getExpectedPropertyValueAfterHibernateRead() ); - } - - @Override - protected Object getActualJdbcValue(ResultSet resultSet, int columnIndex) throws SQLException { - if ( sessionFactory().getJdbcServices().getDialect().getTimeZoneSupport() == TimeZoneSupport.NATIVE ) { - // Oracle and H2 require reading/writing through OffsetDateTime to avoid TZ related miscalculations - return Timestamp.from( resultSet.getObject( columnIndex, OffsetDateTime.class ).toInstant() ); - } - else { - return resultSet.getTimestamp( columnIndex, Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) ) ); - } - } - - @Entity(name = ENTITY_NAME) - static final class EntityWithInstant { - @Id - @Column(name = ID_COLUMN_NAME) - private Integer id; - - @Basic - @Column(name = PROPERTY_COLUMN_NAME) - private Instant value; - - protected EntityWithInstant() { - } - - private EntityWithInstant(int id, Instant value) { - this.id = id; - this.value = value; - } - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/type/LocalTimeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/type/LocalTimeTest.java deleted file mode 100644 index d6e841c75c09..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/type/LocalTimeTest.java +++ /dev/null @@ -1,237 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * Copyright Red Hat Inc. and Hibernate Authors - */ -package org.hibernate.orm.test.type; - -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Time; -import java.sql.Timestamp; -import java.sql.Types; -import java.time.LocalTime; -import java.time.ZoneId; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; -import jakarta.persistence.Basic; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; - -import org.hibernate.dialect.HANADialect; -import org.hibernate.dialect.H2Dialect; -import org.hibernate.dialect.HSQLDialect; -import org.hibernate.dialect.MariaDBDialect; -import org.hibernate.dialect.MySQLDialect; - -import org.hibernate.testing.SkipForDialect; -import org.junit.Test; -import org.junit.runners.Parameterized; - -/** - * Tests for storage of LocalTime properties. - */ -@SkipForDialect(value = H2Dialect.class, comment = "H2 1.4.200 DST bug. See org.hibernate.dialect.H2Dialect.hasDstBug") -public class LocalTimeTest extends AbstractJavaTimeTypeTest { - - private static class ParametersBuilder extends AbstractParametersBuilder { - public ParametersBuilder add(int hour, int minute, int second, int nanosecond, ZoneId defaultTimeZone) { - if ( !isNanosecondPrecisionSupported() ) { - nanosecond = 0; - } - return add( defaultTimeZone, hour, minute, second, nanosecond, 1970, 1, 1 ); - } - - public ParametersBuilder addPersistedWithoutHibernate(int yearWhenPersistedWithoutHibernate, - int monthWhenPersistedWithoutHibernate, int dayWhenPersistedWithoutHibernate, - int hour, int minute, int second, int nanosecond, ZoneId defaultTimeZone) { - if ( !isNanosecondPrecisionSupported() ) { - nanosecond = 0; - } - return add( - defaultTimeZone, hour, minute, second, nanosecond, - yearWhenPersistedWithoutHibernate, - monthWhenPersistedWithoutHibernate, dayWhenPersistedWithoutHibernate - ); - } - - @Override - protected Iterable getHibernateJdbcTimeZonesToTest() { - // The MariaDB Connector/J JDBC driver has a bug in ResultSet#getTime(int, Calendar) - // that prevents our explicit JDBC timezones from being recognized - // See https://hibernate.atlassian.net/browse/HHH-13581 - // See https://jira.mariadb.org/browse/CONJ-724 - if ( MariaDBDialect.class.isInstance( getDialect() ) ) { - return Collections.emptySet(); - } - return super.getHibernateJdbcTimeZonesToTest(); - } - } - - @Parameterized.Parameters(name = "{1}:{2}:{3}.{4} (JDBC write date: {5}-{6}-{7}) {0}") - public static List data() { - return new ParametersBuilder() - .alsoTestRemappingsWithH2( TimeAsTimestampRemappingH2Dialect.class ) - // None of these values was affected by HHH-13266 (JDK-8061577) - .add( 19, 19, 1, 0, ZONE_UTC_MINUS_8 ) - .add( 19, 19, 1, 0, ZONE_PARIS ) - .add( 19, 19, 1, 500, ZONE_PARIS ) - .add( 0, 9, 20, 0, ZONE_PARIS ) - .add( 0, 19, 31, 0, ZONE_AMSTERDAM ) - .skippedForDialects( - // MySQL/Mariadb cannot store values equal to epoch exactly, or less, in a timestamp. - Arrays.asList( MySQLDialect.class, MariaDBDialect.class ), - b -> b - .add( 0, 0, 0, 0, ZONE_GMT ) - .add( 0, 0, 0, 0, ZONE_OSLO ) - .add( 0, 0, 0, 0, ZONE_AMSTERDAM ) - .addPersistedWithoutHibernate( 1900, 1, 1, 0, 0, 0, 0, ZONE_OSLO ) - .addPersistedWithoutHibernate( 1900, 1, 2, 0, 9, 21, 0, ZONE_PARIS ) - .addPersistedWithoutHibernate( 1900, 1, 2, 0, 19, 32, 0, ZONE_AMSTERDAM ) - .addPersistedWithoutHibernate( 1892, 1, 1, 0, 0, 0, 0, ZONE_OSLO ) - .addPersistedWithoutHibernate( 1900, 1, 1, 0, 9, 20, 0, ZONE_PARIS ) - .addPersistedWithoutHibernate( 1900, 1, 1, 0, 19, 31, 0, ZONE_AMSTERDAM ) - .addPersistedWithoutHibernate( 1600, 1, 1, 0, 0, 0, 0, ZONE_AMSTERDAM ) - ) - // HHH-13379: DST end (where Timestamp becomes ambiguous, see JDK-4312621) - // It doesn't seem that any time on 1970-01-01 can be affected by HHH-13379, but we add some tests just in case - .add( 1, 0, 0, 0, ZONE_PARIS ) - .add( 2, 0, 0, 0, ZONE_PARIS ) - .add( 3, 0, 0, 0, ZONE_PARIS ) - .add( 1, 0, 0, 0, ZONE_AUCKLAND ) - .add( 2, 0, 0, 0, ZONE_AUCKLAND ) - .add( 3, 0, 0, 0, ZONE_AUCKLAND ) - .build(); - } - - private final int hour; - private final int minute; - private final int second; - private final int nanosecond; - - private final int yearWhenPersistedWithoutHibernate; - private final int monthWhenPersistedWithoutHibernate; - private final int dayWhenPersistedWithoutHibernate; - - public LocalTimeTest(EnvironmentParameters env, int hour, int minute, int second, int nanosecond, - int yearWhenPersistedWithoutHibernate, int monthWhenPersistedWithoutHibernate, int dayWhenPersistedWithoutHibernate) { - super( env ); - this.hour = hour; - this.minute = minute; - this.second = second; - this.nanosecond = nanosecond; - this.yearWhenPersistedWithoutHibernate = yearWhenPersistedWithoutHibernate; - this.monthWhenPersistedWithoutHibernate = monthWhenPersistedWithoutHibernate; - this.dayWhenPersistedWithoutHibernate = dayWhenPersistedWithoutHibernate; - } - - @Override - protected Class getEntityType() { - return EntityWithLocalTime.class; - } - - @Override - protected EntityWithLocalTime createEntityForHibernateWrite(int id) { - return new EntityWithLocalTime( id, getOriginalPropertyValue() ); - } - - protected LocalTime getOriginalPropertyValue() { - return LocalTime.of( hour, minute, second, nanosecond ); - } - - @Override - protected LocalTime getExpectedPropertyValueAfterHibernateRead() { - if ( TimeAsTimestampRemappingH2Dialect.class.equals( getRemappingDialectClass() ) ) { - return getOriginalPropertyValue(); - } - else { - // When storing time as java.sql.Time, we only get second precision (not nanosecond) - return getOriginalPropertyValue().withNano( 0 ); - } - } - - @Override - protected LocalTime getActualPropertyValue(EntityWithLocalTime entity) { - return entity.value; - } - - @Override - protected void setJdbcValueForNonHibernateWrite(PreparedStatement statement, int parameterIndex) - throws SQLException { - if ( TimeAsTimestampRemappingH2Dialect.class.equals( getRemappingDialectClass() ) ) { - statement.setTimestamp( - parameterIndex, - new Timestamp( - yearWhenPersistedWithoutHibernate - 1900, - monthWhenPersistedWithoutHibernate - 1, - dayWhenPersistedWithoutHibernate, - hour, minute, second, nanosecond - ) - ); - } - else { - statement.setTime( parameterIndex, new Time( hour, minute, second ) ); - } - } - - @Override - protected Object getExpectedJdbcValueAfterHibernateWrite() { - if ( TimeAsTimestampRemappingH2Dialect.class.equals( getRemappingDialectClass() ) ) { - return new Timestamp( 1970 - 1900, 0, 1, hour, minute, second, nanosecond ); - } - else { - return new Time( hour, minute, second ); - } - } - - @Override - protected Object getActualJdbcValue(ResultSet resultSet, int columnIndex) throws SQLException { - if ( TimeAsTimestampRemappingH2Dialect.class.equals( getRemappingDialectClass() ) ) { - return resultSet.getTimestamp( columnIndex ); - } - else { - return resultSet.getTime( columnIndex ); - } - } - - @Override - @Test - @SkipForDialect(value = HANADialect.class, comment = "HANA seems to return a java.sql.Timestamp instead of a java.sql.Time") - @SkipForDialect(value = MySQLDialect.class, - comment = "HHH-13580 MySQL seems to store the whole timestamp, not just the time," - + " which for some timezones results in a date other than 1970-01-01 being returned" - + " (typically 1969-12-31), even though the time is always right." - + " Since java.sql.Time holds the whole timestamp, not just the time," - + " its equals() method ends up returning false in this test.") - @SkipForDialect(value = HSQLDialect.class, comment = "Timezone issue?") - public void writeThenNativeRead() { - super.writeThenNativeRead(); - } - - @Entity(name = ENTITY_NAME) - static final class EntityWithLocalTime { - @Id - @Column(name = ID_COLUMN_NAME) - private Integer id; - - @Basic - @Column(name = PROPERTY_COLUMN_NAME) - private LocalTime value; - - protected EntityWithLocalTime() { - } - - private EntityWithLocalTime(int id, LocalTime value) { - this.id = id; - this.value = value; - } - } - - public static class TimeAsTimestampRemappingH2Dialect extends AbstractRemappingH2Dialect { - public TimeAsTimestampRemappingH2Dialect() { - super( Types.TIME, Types.TIMESTAMP ); - } - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/type/descriptor/java/StringArrayDescriptorTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/type/descriptor/java/StringArrayDescriptorTest.java index 8f1487233513..4f4080d67573 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/type/descriptor/java/StringArrayDescriptorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/type/descriptor/java/StringArrayDescriptorTest.java @@ -7,9 +7,8 @@ import org.hibernate.orm.test.mapping.type.java.AbstractDescriptorTest; import org.hibernate.type.descriptor.java.ArrayJavaType; import org.hibernate.type.descriptor.java.StringJavaType; - -import static org.junit.Assert.assertTrue; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; /** * @author Jordan Gigov @@ -40,7 +39,7 @@ public void testEmptyArrayExternalization() { String[] emptyArray = new String[]{}; String externalized = typeDescriptor().toString( emptyArray ); String[] consumed = typeDescriptor().fromString( externalized ); - assertTrue( typeDescriptor().areEqual( emptyArray, consumed ) ); + Assertions.assertTrue( typeDescriptor().areEqual( emptyArray, consumed ) ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/AbstractJavaTimeTypeTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/AbstractJavaTimeTypeTests.java new file mode 100644 index 000000000000..7413b6a95eb9 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/AbstractJavaTimeTypeTests.java @@ -0,0 +1,159 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.type.temporal; + +import org.hibernate.boot.registry.StandardServiceRegistry; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.ServiceRegistryFunctionalTesting; +import org.hibernate.testing.orm.junit.ServiceRegistryProducer; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Assumptions; +import org.junit.jupiter.api.Test; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +import static org.hibernate.cfg.JdbcSettings.DIALECT; +import static org.hibernate.cfg.JdbcSettings.JDBC_TIME_ZONE; + +/** + * Test support for handling of temporal values. + * + * @param The time type being tested. + * @param The entity type used in tests. + */ +@ServiceRegistryFunctionalTesting +public abstract class AbstractJavaTimeTypeTests + implements ServiceRegistryProducer { + + protected static final String ENTITY_TBL_NAME = "entity_tbl"; + protected static final String ID_COLUMN_NAME = "id_col"; + protected static final String VALUE_COLUMN_NAME = "value_col"; + + private final Environment env; + + public AbstractJavaTimeTypeTests(Environment env) { + this.env = env; + } + + @Override + public StandardServiceRegistry produceServiceRegistry(StandardServiceRegistryBuilder builder) { + if ( env.hibernateJdbcTimeZone() != null ) { + builder.applySetting( JDBC_TIME_ZONE, env.hibernateJdbcTimeZone().getId() ); + } + if ( env.remappingDialectClass() != null ) { + builder.applySetting( DIALECT, env.remappingDialectClass().getName() ); + } + return builder.build(); + } + + protected abstract Class getEntityType(); + + protected abstract E createEntityForHibernateWrite(int id); + + protected abstract T getExpectedPropertyValueAfterHibernateRead(); + + protected abstract T getActualPropertyValue(E entity); + + protected abstract Object getExpectedJdbcValueAfterHibernateWrite(); + + protected abstract void bindJdbcValue( + PreparedStatement statement, + int parameterIndex, + SessionFactoryScope factoryScope) throws SQLException; + + protected abstract Object extractJdbcValue( + ResultSet resultSet, + int columnIndex, + SessionFactoryScope factoryScope) throws SQLException; + + @AfterEach + public void tearDown(SessionFactoryScope factoryScope) { + factoryScope.dropData(); + } + + @Test + @JiraKey(value = "HHH-13266") + public void writeThenRead(SessionFactoryScope factoryScope) { + Timezones.withDefaultTimeZone( env, () -> { + factoryScope.inTransaction( (session) -> { + session.persist( createEntityForHibernateWrite( 1 ) ); + } ); + factoryScope.inTransaction( (session) -> { + T read = getActualPropertyValue( session.find( getEntityType(), 1 ) ); + T expected = getExpectedPropertyValueAfterHibernateRead(); + Assertions.assertEquals( expected, read, + "Writing then reading a value should return the original value" ); + } ); + } ); + } + + @Test + @JiraKey(value = "HHH-13266") + public void writeThenNativeRead(SessionFactoryScope factoryScope) { + assumeNoJdbcTimeZone(); + + Timezones.withDefaultTimeZone( env, () -> { + factoryScope.inTransaction( session -> { + session.persist( createEntityForHibernateWrite( 1 ) ); + } ); + factoryScope.inTransaction( session -> { + session.doWork( connection -> { + try (PreparedStatement statement = connection.prepareStatement( + "select value_col from entity_tbl where id_col = ?" + )) { + statement.setInt( 1, 1 ); + statement.execute(); + try (ResultSet resultSet = statement.getResultSet()) { + resultSet.next(); + Object nativeRead = extractJdbcValue( resultSet, 1, factoryScope ); + Object expected = getExpectedJdbcValueAfterHibernateWrite(); + Assertions.assertEquals( expected, nativeRead, + "Values written by Hibernate ORM should match the original value (same day, hour, ...)" ); + } + } + } ); + } ); + } ); + } + + @Test + @JiraKey(value = "HHH-13266") + public void nativeWriteThenRead(SessionFactoryScope factoryScope) { + assumeNoJdbcTimeZone(); + + Timezones.withDefaultTimeZone( env, () -> { + factoryScope.inTransaction( session -> { + session.doWork( connection -> { + try (PreparedStatement statement = connection.prepareStatement( + "insert into entity_tbl (id_col, value_col) values (?,?)" + )) { + statement.setInt( 1, 1 ); + bindJdbcValue( statement, 2, factoryScope ); + statement.execute(); + } + } ); + } ); + factoryScope.inTransaction( session -> { + T read = getActualPropertyValue( session.find( getEntityType(), 1 ) ); + T expected = getExpectedPropertyValueAfterHibernateRead(); + Assertions.assertEquals( expected, read, + "Values written without Hibernate ORM should be read correctly by Hibernate ORM" ); + } ); + } ); + } + + protected void assumeNoJdbcTimeZone() { + Assumptions.assumeTrue( env.hibernateJdbcTimeZone() == null, + "Tests with native read/writes are only relevant when not using " + JDBC_TIME_ZONE + + ", because the expectations do not take that time zone into account." + + " When this property is set, we only test that a write by Hibernate followed by " + + " a read by Hibernate returns the same value." ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/AbstractParametersBuilder.java b/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/AbstractParametersBuilder.java new file mode 100644 index 000000000000..41a320007e93 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/AbstractParametersBuilder.java @@ -0,0 +1,120 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.type.temporal; + +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.H2Dialect; + +import java.time.ZoneId; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Predicate; + +/** + * @author Steve Ebersole + */ +public class AbstractParametersBuilder,B extends AbstractParametersBuilder> { + protected final Dialect dialect; + + private final List> result = new ArrayList<>(); + + private final List> remappingDialectClasses = new ArrayList<>(); + + private ZoneId forcedJdbcTimeZone = null; + + protected AbstractParametersBuilder(Dialect dialect) { + this.dialect = dialect; + // Always test without remapping + remappingDialectClasses.add( null ); + } + + public B skippedForDialects(List> dialectsToSkip, Consumer ifNotSkipped) { + boolean skip = false; + for ( Class dialectClass : dialectsToSkip ) { + if ( dialectClass.isInstance( dialect ) ) { + skip = true; + break; + } + } + if ( !skip ) { + ifNotSkipped.accept( thisAsB() ); + } + return thisAsB(); + } + + public B skippedForDialects(Predicate skipPredicate, Consumer ifNotSkipped) { + if ( !skipPredicate.test( dialect ) ) { + ifNotSkipped.accept( thisAsB() ); + } + return thisAsB(); + } + + public B withForcedJdbcTimezone(String zoneIdString, Consumer contributor) { + this.forcedJdbcTimeZone = ZoneId.of( zoneIdString ); + try { + contributor.accept( thisAsB() ); + } + finally { + this.forcedJdbcTimeZone = null; + } + return thisAsB(); + } + + @SafeVarargs + public final B alsoTestRemappingsWithH2(Class... dialectClasses) { + if ( dialect instanceof H2Dialect && !( (H2Dialect) dialect ).hasOddDstBehavior() ) { + // Only test remappings with H2 + Collections.addAll( remappingDialectClasses, dialectClasses ); + } + return thisAsB(); + } + + protected final boolean isNanosecondPrecisionSupported() { + // This used to return true for H2Dialect, but as of 1.4.197 h2 does not use ns precision by default anymore. + // Bringing back ns precision would require timestamp(9) in the dialect class. + return false; + } + + protected final B add(ZoneId defaultJvmTimeZone, D testData) { + for ( Class remappingDialectClass : remappingDialectClasses ) { + addParam( defaultJvmTimeZone, forcedJdbcTimeZone, remappingDialectClass, testData ); + } + + if ( forcedJdbcTimeZone == null ) { + for ( ZoneId hibernateJdbcTimeZone : getHibernateJdbcTimeZonesToTest() ) { + addParam( defaultJvmTimeZone, hibernateJdbcTimeZone, null, testData ); + } + } + return thisAsB(); + } + + private void addParam( + ZoneId defaultJvmTimeZone, + ZoneId forcedJdbcTimeZone, + Class remappingDialectClass, + D testData) { + result.add( new Parameter<>( + new Environment( defaultJvmTimeZone, forcedJdbcTimeZone, remappingDialectClass ), + testData + ) ); + + } + + protected Iterable getHibernateJdbcTimeZonesToTest() { + return Arrays.asList( Timezones.ZONE_GMT, Timezones.ZONE_OSLO ); + } + + private B thisAsB() { + //noinspection unchecked + return (B) this; + } + + public List> build() { + return result; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/AbstractRemappingH2Dialect.java b/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/AbstractRemappingH2Dialect.java new file mode 100644 index 000000000000..ee9011879e93 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/AbstractRemappingH2Dialect.java @@ -0,0 +1,37 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.type.temporal; + +import org.hibernate.boot.model.TypeContributions; +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.H2Dialect; +import org.hibernate.service.ServiceRegistry; + +/** + * @author Steve Ebersole + */ +public class AbstractRemappingH2Dialect extends H2Dialect { + private final int overriddenSqlTypeCode; + private final int overridingSqlTypeCode; + + public AbstractRemappingH2Dialect(Dialect baseDialect, int overriddenSqlTypeCode, int overridingSqlTypeCode) { + super( baseDialect.getVersion() ); + this.overriddenSqlTypeCode = overriddenSqlTypeCode; + this.overridingSqlTypeCode = overridingSqlTypeCode; + } + + @Override + public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) { + super.contributeTypes( typeContributions, serviceRegistry ); + + typeContributions.getTypeConfiguration().getJdbcTypeRegistry().addDescriptor( + overriddenSqlTypeCode, + typeContributions.getTypeConfiguration().getJdbcTypeRegistry().getDescriptor( + overridingSqlTypeCode + ) + ); + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/Data.java b/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/Data.java new file mode 100644 index 000000000000..3ed5edcb6ee6 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/Data.java @@ -0,0 +1,12 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.type.temporal; + +/** + * @author Steve Ebersole + */ +public interface Data { + V makeValue(); +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/Environment.java b/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/Environment.java new file mode 100644 index 000000000000..bf71eb52e8ad --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/Environment.java @@ -0,0 +1,32 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.type.temporal; + +import org.hibernate.cfg.AvailableSettings; + +import java.time.ZoneId; + +/** + * @param defaultJvmTimeZone The default timezone affects conversions done using java.util, + * which is why we take it into account even with timezone-independent types such as Instant. + * @param hibernateJdbcTimeZone The Hibernate setting, {@value AvailableSettings#JDBC_TIME_ZONE}, + * may affect a lot of time-related types, + * which is why we take it into account even with timezone-independent types such as Instant. + */ +public record Environment( + ZoneId defaultJvmTimeZone, + ZoneId hibernateJdbcTimeZone, + Class remappingDialectClass) { + + @Override + public String toString() { + return String.format( + "[JVM TZ: %s, JDBC TZ: %s, remapping dialect: %s]", + defaultJvmTimeZone, + hibernateJdbcTimeZone, + remappingDialectClass == null ? null : remappingDialectClass.getSimpleName() + ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/InstantTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/InstantTests.java new file mode 100644 index 000000000000..4232ac09d221 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/InstantTests.java @@ -0,0 +1,272 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.type.temporal; + +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.H2Dialect; +import org.hibernate.dialect.MySQLDialect; +import org.hibernate.dialect.SybaseASEDialect; +import org.hibernate.dialect.SybaseDialect; +import org.hibernate.dialect.TimeZoneSupport; +import org.hibernate.testing.orm.junit.DialectContext; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedClass; +import org.junit.jupiter.params.provider.MethodSource; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.time.Instant; +import java.time.OffsetDateTime; +import java.time.ZoneId; +import java.time.ZoneOffset; +import java.util.Calendar; +import java.util.List; +import java.util.TimeZone; + + +/** + * Tests for storage of Instant properties. + */ +@TestInstance( TestInstance.Lifecycle.PER_METHOD ) +@ParameterizedClass +@MethodSource("testData") +@DomainModel(annotatedClasses = InstantTests.EntityWithInstant.class) +@SessionFactory +public class InstantTests extends AbstractJavaTimeTypeTests { + + protected static List> testData() { + return new ParametersBuilder( DialectContext.getDialect() ) + // Not affected by any known bug + .add( 2017, 11, 6, 19, 19, 1, 0, Timezones.ZONE_UTC_MINUS_8 ) + .add( 2017, 11, 6, 19, 19, 1, 0, Timezones.ZONE_PARIS ) + .add( 2017, 11, 6, 19, 19, 1, 500, Timezones.ZONE_PARIS ) + .skippedForDialects( + // MySQL/Mariadb cannot store values equal to epoch exactly, or less, in a timestamp. + List.of(MySQLDialect.class), + (collector) -> collector + .add( 1970, 1, 1, 0, 0, 0, 0, Timezones.ZONE_GMT ) + .add( 1900, 1, 1, 0, 0, 0, 0, Timezones.ZONE_GMT ) + .add( 1900, 1, 1, 0, 0, 0, 0, Timezones.ZONE_OSLO ) + .add( 1900, 1, 1, 0, 0, 0, 0, Timezones.ZONE_PARIS ) + .add( 1900, 1, 2, 0, 9, 21, 0, Timezones.ZONE_PARIS ) + .add( 1900, 1, 1, 0, 0, 0, 0, Timezones.ZONE_AMSTERDAM ) + .add( 1900, 1, 2, 0, 19, 32, 0, Timezones.ZONE_AMSTERDAM ) + .add( 1899, 12, 31, 23, 59, 59, 999_999_999, Timezones.ZONE_PARIS ) + .add( 1899, 12, 31, 23, 59, 59, 999_999_999, Timezones.ZONE_AMSTERDAM ) + ) + .skippedForDialects( + // MySQL/Mariadb/Sybase cannot store dates in 1600 in a timestamp. + dialect -> dialect instanceof MySQLDialect + || dialect instanceof SybaseDialect + || dialect instanceof H2Dialect && ( (H2Dialect) dialect ).hasOddDstBehavior(), + b -> b + .add( 1600, 1, 1, 0, 0, 0, 0, Timezones.ZONE_AMSTERDAM ) + // Affected by HHH-13266 (JDK-8061577) + .add( 1892, 1, 1, 0, 0, 0, 0, Timezones.ZONE_OSLO ) + ) + // HHH-13379: DST end (where Timestamp becomes ambiguous, see JDK-4312621) + // => This used to work correctly in 5.4.1.Final and earlier + .skippedForDialects( + dialect -> dialect instanceof H2Dialect && ( (H2Dialect) dialect ).hasOddDstBehavior(), + b -> b.add( 2018, 10, 28, 1, 0, 0, 0, Timezones.ZONE_PARIS ) + .add( 2018, 3, 31, 14, 0, 0, 0, Timezones.ZONE_AUCKLAND ) + ) + // => This has never worked correctly, unless the JDBC timezone was set to UTC + .withForcedJdbcTimezone( "UTC", b -> b + .add( 2018, 10, 28, 0, 0, 0, 0, Timezones.ZONE_PARIS ) + .add( 2018, 3, 31, 13, 0, 0, 0, Timezones.ZONE_AUCKLAND ) + ) + // => Also test DST start, just in case + .add( 2018, 3, 25, 1, 0, 0, 0, Timezones.ZONE_PARIS ) + .skippedForDialects( + // No idea what Sybase is doing here exactly + dialect -> dialect instanceof SybaseASEDialect, + b -> b.add( 2018, 3, 25, 2, 0, 0, 0, Timezones.ZONE_PARIS ) + .add( 2018, 9, 30, 2, 0, 0, 0, Timezones.ZONE_AUCKLAND ) + ) + .add( 2018, 9, 30, 3, 0, 0, 0, Timezones.ZONE_AUCKLAND ) + // => Also test dates around 1905-01-01, because the code behaves differently before and after 1905 + .add( 1904, 12, 31, 22, 59, 59, 999_999_999, Timezones.ZONE_PARIS ) + .add( 1904, 12, 31, 23, 59, 59, 999_999_999, Timezones.ZONE_PARIS ) + .add( 1905, 1, 1, 0, 59, 59, 999_999_999, Timezones.ZONE_PARIS ) + .add( 1904, 12, 31, 23, 0, 0, 0, Timezones.ZONE_PARIS ) + .add( 1905, 1, 1, 0, 0, 0, 0, Timezones.ZONE_PARIS ) + .add( 1905, 1, 1, 1, 0, 0, 0, Timezones.ZONE_PARIS ) + .build(); + } + + private final Parameter testParam; + + public InstantTests(Parameter testParam) { + super( testParam.env() ); + this.testParam = testParam; + } + + @Override + protected Class getEntityType() { + return EntityWithInstant.class; + } + + @Override + protected EntityWithInstant createEntityForHibernateWrite(int id) { + return new EntityWithInstant( id, testParam.data().makeValue() ); + } + + @Override + protected Instant getExpectedPropertyValueAfterHibernateRead() { + return testParam.data().asInstant(); + } + + @Override + protected Instant getActualPropertyValue(EntityWithInstant entity) { + return entity.getValue(); + } + + @Override + protected Timestamp getExpectedJdbcValueAfterHibernateWrite() { + return Timestamp.from( getExpectedPropertyValueAfterHibernateRead() ); + } + + @Override + protected Object extractJdbcValue( + ResultSet resultSet, + int position, + SessionFactoryScope factoryScope) throws SQLException { + if ( factoryScope.getSessionFactory().getJdbcServices().getDialect().getTimeZoneSupport() == TimeZoneSupport.NATIVE ) { + // Oracle and H2 require reading/writing through OffsetDateTime to avoid TZ related miscalculations + return Timestamp.from( resultSet.getObject( position, OffsetDateTime.class ).toInstant() ); + } + else { + return resultSet.getTimestamp( position, Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) ) ); + } + } + + @Override + protected void bindJdbcValue( + PreparedStatement statement, + int position, + SessionFactoryScope factoryScope) throws SQLException { + if ( factoryScope.getSessionFactory().getJdbcServices().getDialect().getTimeZoneSupport() == TimeZoneSupport.NATIVE ) { + // Oracle and H2 require reading/writing through OffsetDateTime to avoid TZ related miscalculations + statement.setObject( + position, + testParam.data().asInstant().atOffset( ZoneOffset.UTC ) + ); + } + else { + statement.setTimestamp( + position, + testParam.data().asTimestamp(), + Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) ) + ); + } + } + + public record InstantData(int year, int month, int day, + int hour, int minute, int second, int nanosecond) implements Data { + + public Instant asInstant() { + return OffsetDateTime.of( year, month, day, hour, minute, second, nanosecond, ZoneOffset.UTC ).toInstant(); + } + + public Timestamp asTimestamp() { + return Timestamp.from( asInstant() ); + } + + @Override + public Instant makeValue() { + return asInstant(); + } + } + + private static class ParametersBuilder extends AbstractParametersBuilder { + public ParametersBuilder(Dialect dialect) { + super( dialect ); + } + + public ParametersBuilder add(int year, int month, int day, + int hour, int minute, int second, int nanosecond, + ZoneId defaultTimeZone) { + if ( !isNanosecondPrecisionSupported() ) { + nanosecond = 0; + } + return add( defaultTimeZone, new InstantData( year, month, day, hour, minute, second, nanosecond ) ); + } + } + + protected Instant createInstant(int year, int month, int day, int hour, int minute, int second, int nanosecond) { + return OffsetDateTime.of( year, month, day, hour, minute, second, nanosecond, ZoneOffset.UTC ).toInstant(); + } + + protected Timestamp createTimestamp(int year, int month, int day, int hour, int minute, int second, int nanosecond) { + return Timestamp.from( createInstant( year, month, day, hour, minute, second, nanosecond ) ); + } + + protected void setJdbcValueForNonHibernateWrite( + PreparedStatement statement, + int parameterIndex, + Instant instant, + SessionFactoryScope factoryScope) throws SQLException { + if ( factoryScope.getSessionFactory().getJdbcServices().getDialect().getTimeZoneSupport() == TimeZoneSupport.NATIVE ) { + // Oracle and H2 require reading/writing through OffsetDateTime to avoid TZ related miscalculations + statement.setObject( parameterIndex, instant.atOffset( ZoneOffset.UTC ) ); + } + else { + statement.setTimestamp( + parameterIndex, + Timestamp.from( instant ), + Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) ) + ); + } + } + + protected Object getActualJdbcValue(ResultSet resultSet, int columnIndex, SessionFactoryScope factoryScope) throws SQLException { + if ( factoryScope.getSessionFactory().getJdbcServices().getDialect().getTimeZoneSupport() == TimeZoneSupport.NATIVE ) { + // Oracle and H2 require reading/writing through OffsetDateTime to avoid TZ related miscalculations + return Timestamp.from( resultSet.getObject( columnIndex, OffsetDateTime.class ).toInstant() ); + } + else { + return resultSet.getTimestamp( columnIndex, Calendar.getInstance( TimeZone.getTimeZone( "UTC" ) ) ); + } + } + + @Entity + @Table(name = ENTITY_TBL_NAME) + public static class EntityWithInstant { + @Id + @Column(name = ID_COLUMN_NAME) + private Integer id; + + @Basic + @Column(name = VALUE_COLUMN_NAME) + private Instant value; + + protected EntityWithInstant() { + } + + private EntityWithInstant(int id, Instant value) { + this.id = id; + this.value = value; + } + + public Integer getId() { + return id; + } + + public Instant getValue() { + return value; + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/type/Java8DateTimeTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/Java8DateTimeTests.java similarity index 99% rename from hibernate-core/src/test/java/org/hibernate/orm/test/type/Java8DateTimeTests.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/Java8DateTimeTests.java index a72b9db8756a..1d0c587796d2 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/type/Java8DateTimeTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/Java8DateTimeTests.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.orm.test.type; +package org.hibernate.orm.test.type.temporal; import jakarta.persistence.Column; import jakarta.persistence.Entity; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/type/LocalDateTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/LocalDateTest.java similarity index 51% rename from hibernate-core/src/test/java/org/hibernate/orm/test/type/LocalDateTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/LocalDateTest.java index 8d047e92b977..f339222fa642 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/type/LocalDateTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/LocalDateTest.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.orm.test.type; +package org.hibernate.orm.test.type.temporal; import java.sql.Date; import java.sql.PreparedStatement; @@ -19,6 +19,8 @@ import jakarta.persistence.Entity; import jakarta.persistence.Id; +import jakarta.persistence.Table; +import org.hibernate.dialect.Dialect; import org.hibernate.dialect.HANADialect; import org.hibernate.dialect.H2Dialect; import org.hibernate.dialect.HSQLDialect; @@ -26,34 +28,48 @@ import org.hibernate.dialect.MySQLDialect; import org.hibernate.dialect.SybaseASEDialect; -import org.hibernate.testing.SkipForDialect; +import org.hibernate.testing.orm.junit.DialectContext; +import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.JiraKey; -import org.junit.runners.Parameterized; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.testing.orm.junit.SkipForDialect; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedClass; +import org.junit.jupiter.params.provider.MethodSource; + +import static org.hibernate.orm.test.type.temporal.Timezones.ZONE_AMSTERDAM; +import static org.hibernate.orm.test.type.temporal.Timezones.ZONE_AUCKLAND; +import static org.hibernate.orm.test.type.temporal.Timezones.ZONE_GMT; +import static org.hibernate.orm.test.type.temporal.Timezones.ZONE_OSLO; +import static org.hibernate.orm.test.type.temporal.Timezones.ZONE_PARIS; +import static org.hibernate.orm.test.type.temporal.Timezones.ZONE_SANTIAGO; +import static org.hibernate.orm.test.type.temporal.Timezones.ZONE_UTC_MINUS_8; /** * Tests for storage of LocalDate properties. */ @JiraKey(value = "HHH-10371") -@SkipForDialect(value = HANADialect.class, - comment = "HANA systematically returns the wrong date when the JVM default timezone is not UTC") -@SkipForDialect(value = MySQLDialect.class, - comment = "HHH-13582: MySQL ConnectorJ 8.x returns the wrong date" +@TestInstance( TestInstance.Lifecycle.PER_METHOD ) +@ParameterizedClass +@MethodSource("testData") +@DomainModel(annotatedClasses = LocalDateTest.EntityWithLocalDate.class) +@SessionFactory +@SkipForDialect(dialectClass = HANADialect.class, + reason = "HANA systematically returns the wrong date when the JVM default timezone is not UTC") +@SkipForDialect(dialectClass = MySQLDialect.class, + reason = "HHH-13582: MySQL ConnectorJ 8.x returns the wrong date" + " when the JVM default timezone is different from the server timezone:" + " https://bugs.mysql.com/bug.php?id=91112" ) -@SkipForDialect(value = H2Dialect.class, comment = "H2 1.4.200 DST bug. See org.hibernate.dialect.H2Dialect.hasDstBug") -@SkipForDialect(value = HSQLDialect.class, comment = "HSQL has problems with DST edges") -public class LocalDateTest extends AbstractJavaTimeTypeTest { - - private static class ParametersBuilder extends AbstractParametersBuilder { - public ParametersBuilder add(int year, int month, int day, ZoneId defaultTimeZone) { - return add( defaultTimeZone, year, month, day ); - } - } - - @Parameterized.Parameters(name = "{1}-{2}-{3} {0}") - public static List data() { - return new ParametersBuilder() +@SkipForDialect(dialectClass = H2Dialect.class, + reason = "H2 1.4.200 DST bug. See org.hibernate.dialect.H2Dialect.hasDstBug") +@SkipForDialect(dialectClass = HSQLDialect.class, + reason = "HSQL has problems with DST edges") +public class LocalDateTest extends AbstractJavaTimeTypeTests { + + public static List> testData() { + return new ParametersBuilder( DialectContext.getDialect() ) .alsoTestRemappingsWithH2( DateAsTimestampRemappingH2Dialect.class ) // Not affected by HHH-13266 (JDK-8061577) .add( 2017, 11, 6, ZONE_UTC_MINUS_8 ) @@ -90,15 +106,11 @@ public static List data() { .build(); } - private final int year; - private final int month; - private final int day; + private final Parameter testParam; - public LocalDateTest(EnvironmentParameters env, int year, int month, int day) { - super( env ); - this.year = year; - this.month = month; - this.day = day; + public LocalDateTest(Parameter testParam) { + super( testParam.env() ); + this.testParam = testParam; } @Override @@ -113,7 +125,7 @@ protected EntityWithLocalDate createEntityForHibernateWrite(int id) { @Override protected LocalDate getExpectedPropertyValueAfterHibernateRead() { - return LocalDate.of( year, month, day ); + return testParam.data().makeValue(); } @Override @@ -122,28 +134,34 @@ protected LocalDate getActualPropertyValue(EntityWithLocalDate entity) { } @Override - protected void setJdbcValueForNonHibernateWrite(PreparedStatement statement, int parameterIndex) throws SQLException { - if ( DateAsTimestampRemappingH2Dialect.class.equals( getRemappingDialectClass() ) ) { - statement.setTimestamp( parameterIndex, new Timestamp( year - 1900, month - 1, day, 0, 0, 0, 0 ) ); + protected void bindJdbcValue( + PreparedStatement statement, + int parameterIndex, + SessionFactoryScope factoryScope) throws SQLException { + if ( DateAsTimestampRemappingH2Dialect.class.equals( testParam.env().remappingDialectClass() ) ) { + statement.setTimestamp( parameterIndex, testParam.data().asTimestamp() ); } else { - statement.setDate( parameterIndex, new Date( year - 1900, month - 1, day ) ); + statement.setDate( parameterIndex, testParam.data().asDate() ); } } @Override protected Object getExpectedJdbcValueAfterHibernateWrite() { - if ( DateAsTimestampRemappingH2Dialect.class.equals( getRemappingDialectClass() ) ) { - return new Timestamp( year - 1900, month - 1, day, 0, 0, 0, 0 ); + if ( DateAsTimestampRemappingH2Dialect.class.equals( testParam.env().remappingDialectClass() ) ) { + return testParam.data().asTimestamp(); } else { - return new Date( year - 1900, month - 1, day ); + return testParam.data().asDate(); } } @Override - protected Object getActualJdbcValue(ResultSet resultSet, int columnIndex) throws SQLException { - if ( DateAsTimestampRemappingH2Dialect.class.equals( getRemappingDialectClass() ) ) { + protected Object extractJdbcValue( + ResultSet resultSet, + int columnIndex, + SessionFactoryScope factoryScope) throws SQLException { + if ( DateAsTimestampRemappingH2Dialect.class.equals( testParam.env().remappingDialectClass() ) ) { return resultSet.getTimestamp( columnIndex ); } else { @@ -151,14 +169,16 @@ protected Object getActualJdbcValue(ResultSet resultSet, int columnIndex) throws } } - @Entity(name = ENTITY_NAME) - static final class EntityWithLocalDate { + @SuppressWarnings({"unused", "FieldCanBeLocal"}) + @Entity + @Table(name = ENTITY_TBL_NAME) + public static class EntityWithLocalDate { @Id @Column(name = ID_COLUMN_NAME) private Integer id; @Basic - @Column(name = PROPERTY_COLUMN_NAME) + @Column(name = VALUE_COLUMN_NAME) private LocalDate value; protected EntityWithLocalDate() { @@ -172,7 +192,32 @@ private EntityWithLocalDate(int id, LocalDate value) { public static class DateAsTimestampRemappingH2Dialect extends AbstractRemappingH2Dialect { public DateAsTimestampRemappingH2Dialect() { - super( Types.DATE, Types.TIMESTAMP ); + super( DialectContext.getDialect(), Types.DATE, Types.TIMESTAMP ); + } + } + + public record DataImpl(int year, int month, int day) implements Data { + @Override + public LocalDate makeValue() { + return LocalDate.of( year, month, day ); + } + + public Timestamp asTimestamp() { + return new Timestamp( year - 1900, month - 1, day, 0, 0, 0, 0 ); + } + + public Date asDate() { + return new Date( year - 1900, month - 1, day ); + } + } + + private static class ParametersBuilder extends AbstractParametersBuilder { + protected ParametersBuilder(Dialect dialect) { + super( dialect ); + } + + public ParametersBuilder add(int year, int month, int day, ZoneId defaultTimeZone) { + return add( defaultTimeZone, new DataImpl( year, month, day ) ); } } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/type/LocalDateTimeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/LocalDateTimeTest.java similarity index 61% rename from hibernate-core/src/test/java/org/hibernate/orm/test/type/LocalDateTimeTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/LocalDateTimeTest.java index a405b3e5ccc8..5ed5e0abe2cf 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/type/LocalDateTimeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/LocalDateTimeTest.java @@ -2,46 +2,55 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.orm.test.type; +package org.hibernate.orm.test.type.temporal; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Timestamp; -import java.time.LocalDateTime; -import java.time.ZoneId; -import java.util.Arrays; -import java.util.List; import jakarta.persistence.Basic; import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.Id; - +import jakarta.persistence.Table; +import org.hibernate.dialect.Dialect; import org.hibernate.dialect.H2Dialect; import org.hibernate.dialect.MariaDBDialect; import org.hibernate.dialect.MySQLDialect; import org.hibernate.dialect.SybaseDialect; +import org.hibernate.testing.orm.junit.DialectContext; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedClass; +import org.junit.jupiter.params.provider.MethodSource; -import org.junit.runners.Parameterized; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Timestamp; +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.Arrays; +import java.util.List; + +import static org.hibernate.orm.test.type.temporal.Timezones.ZONE_AMSTERDAM; +import static org.hibernate.orm.test.type.temporal.Timezones.ZONE_AUCKLAND; +import static org.hibernate.orm.test.type.temporal.Timezones.ZONE_GMT; +import static org.hibernate.orm.test.type.temporal.Timezones.ZONE_OSLO; +import static org.hibernate.orm.test.type.temporal.Timezones.ZONE_PARIS; +import static org.hibernate.orm.test.type.temporal.Timezones.ZONE_UTC_MINUS_8; /** * Tests for storage of LocalDateTime properties. */ -public class LocalDateTimeTest extends AbstractJavaTimeTypeTest { - - private static class ParametersBuilder extends AbstractParametersBuilder { - public ParametersBuilder add(int year, int month, int day, - int hour, int minute, int second, int nanosecond, ZoneId defaultTimeZone) { - if ( !isNanosecondPrecisionSupported() ) { - nanosecond = 0; - } - return add( defaultTimeZone, year, month, day, hour, minute, second, nanosecond ); - } - } - - @Parameterized.Parameters(name = "{1}-{2}-{3}T{4}:{5}:{6}.{7} {0}") - public static List data() { - return new ParametersBuilder() +@TestInstance( TestInstance.Lifecycle.PER_METHOD ) +@ParameterizedClass +@MethodSource("testData") +@DomainModel(annotatedClasses = LocalDateTimeTest.EntityWithLocalDateTime.class) +@SessionFactory +public class LocalDateTimeTest + extends AbstractJavaTimeTypeTests { + + public static List> testData() { + return new ParametersBuilder( DialectContext.getDialect() ) // Not affected by HHH-13266 (JDK-8061577) .add( 2017, 11, 6, 19, 19, 1, 0, ZONE_UTC_MINUS_8 ) .add( 2017, 11, 6, 19, 19, 1, 0, ZONE_PARIS ) @@ -101,24 +110,11 @@ public static List data() { .build(); } - private final int year; - private final int month; - private final int day; - private final int hour; - private final int minute; - private final int second; - private final int nanosecond; - - public LocalDateTimeTest(EnvironmentParameters env, int year, int month, int day, - int hour, int minute, int second, int nanosecond) { - super( env ); - this.year = year; - this.month = month; - this.day = day; - this.hour = hour; - this.minute = minute; - this.second = second; - this.nanosecond = nanosecond; + private final Parameter testParam; + + public LocalDateTimeTest(Parameter testParam) { + super( testParam.env() ); + this.testParam = testParam; } @Override @@ -133,7 +129,7 @@ protected EntityWithLocalDateTime createEntityForHibernateWrite(int id) { @Override protected LocalDateTime getExpectedPropertyValueAfterHibernateRead() { - return LocalDateTime.of( year, month, day, hour, minute, second, nanosecond ); + return testParam.data().makeValue(); } @Override @@ -142,31 +138,35 @@ protected LocalDateTime getActualPropertyValue(EntityWithLocalDateTime entity) { } @Override - protected void setJdbcValueForNonHibernateWrite(PreparedStatement statement, int parameterIndex) throws SQLException { + protected void bindJdbcValue( + PreparedStatement statement, + int parameterIndex, + SessionFactoryScope factoryScope) throws SQLException { statement.setTimestamp( parameterIndex, getExpectedJdbcValueAfterHibernateWrite() ); } @Override protected Timestamp getExpectedJdbcValueAfterHibernateWrite() { - return new Timestamp( - year - 1900, month - 1, day, - hour, minute, second, nanosecond - ); + return testParam.data().asTimestamp(); } @Override - protected Object getActualJdbcValue(ResultSet resultSet, int columnIndex) throws SQLException { + protected Object extractJdbcValue( + ResultSet resultSet, + int columnIndex, + SessionFactoryScope factoryScope) throws SQLException { return resultSet.getTimestamp( columnIndex ); } - @Entity(name = ENTITY_NAME) - static final class EntityWithLocalDateTime { + @Entity + @Table(name = ENTITY_TBL_NAME) + public static final class EntityWithLocalDateTime { @Id @Column(name = ID_COLUMN_NAME) private Integer id; @Basic - @Column(name = PROPERTY_COLUMN_NAME) + @Column(name = VALUE_COLUMN_NAME) private LocalDateTime value; protected EntityWithLocalDateTime() { @@ -177,4 +177,37 @@ private EntityWithLocalDateTime(int id, LocalDateTime value) { this.value = value; } } + + private static class ParametersBuilder + extends AbstractParametersBuilder { + protected ParametersBuilder(Dialect dialect) { + super( dialect ); + } + + public ParametersBuilder add(int year, int month, int day, + int hour, int minute, int second, int nanosecond, ZoneId defaultTimeZone) { + if ( !isNanosecondPrecisionSupported() ) { + nanosecond = 0; + } + return add( defaultTimeZone, new DataImpl( year, month, day, hour, minute, second, nanosecond ) ); + } + } + + public record DataImpl( + int year, + int month, + int day, + int hour, + int minute, + int second, + int nanosecond) implements Data { + @Override + public LocalDateTime makeValue() { + return LocalDateTime.of( year, month, day, hour, minute, second, nanosecond ); + } + + public Timestamp asTimestamp() { + return new Timestamp( year - 1900, month - 1, day, hour, minute, second, nanosecond ); + } + } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/LocalTimeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/LocalTimeTest.java new file mode 100644 index 000000000000..4fdde7c53ac5 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/LocalTimeTest.java @@ -0,0 +1,278 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.type.temporal; + +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.H2Dialect; +import org.hibernate.dialect.HANADialect; +import org.hibernate.dialect.HSQLDialect; +import org.hibernate.dialect.MariaDBDialect; +import org.hibernate.dialect.MySQLDialect; +import org.hibernate.testing.orm.junit.DialectContext; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.testing.orm.junit.SkipForDialect; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedClass; +import org.junit.jupiter.params.provider.MethodSource; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Time; +import java.sql.Timestamp; +import java.sql.Types; +import java.time.LocalTime; +import java.time.ZoneId; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +/** + * Tests for storage of LocalTime properties. + */ +@TestInstance( TestInstance.Lifecycle.PER_METHOD ) +@ParameterizedClass +@MethodSource("testData") +@DomainModel(annotatedClasses = LocalTimeTest.EntityWithLocalTime.class) +@SessionFactory +@SkipForDialect(dialectClass = H2Dialect.class, reason = "H2 1.4.200 DST bug. See org.hibernate.dialect.H2Dialect.hasDstBug") +public class LocalTimeTest extends AbstractJavaTimeTypeTests { + + protected static List> testData() { + return new ParametersBuilder( DialectContext.getDialect() ) + .alsoTestRemappingsWithH2( TimeAsTimestampRemappingH2Dialect.class ) + // None of these values was affected by HHH-13266 (JDK-8061577) + .add( 19, 19, 1, 0, Timezones.ZONE_UTC_MINUS_8 ) + .add( 19, 19, 1, 0, Timezones.ZONE_PARIS ) + .add( 19, 19, 1, 500, Timezones.ZONE_PARIS ) + .add( 0, 9, 20, 0, Timezones.ZONE_PARIS ) + .add( 0, 19, 31, 0, Timezones.ZONE_AMSTERDAM ) + .skippedForDialects( + // MySQL/Mariadb cannot store values equal to epoch exactly, or less, in a timestamp. + Arrays.asList( MySQLDialect.class, MariaDBDialect.class ), + b -> b + .add( 0, 0, 0, 0, Timezones.ZONE_GMT ) + .add( 0, 0, 0, 0, Timezones.ZONE_OSLO ) + .add( 0, 0, 0, 0, Timezones.ZONE_AMSTERDAM ) + .addPersistedWithoutHibernate( 1900, 1, 1, 0, 0, 0, 0, Timezones.ZONE_OSLO ) + .addPersistedWithoutHibernate( 1900, 1, 2, 0, 9, 21, 0, Timezones.ZONE_PARIS ) + .addPersistedWithoutHibernate( 1900, 1, 2, 0, 19, 32, 0, Timezones.ZONE_AMSTERDAM ) + .addPersistedWithoutHibernate( 1892, 1, 1, 0, 0, 0, 0, Timezones.ZONE_OSLO ) + .addPersistedWithoutHibernate( 1900, 1, 1, 0, 9, 20, 0, Timezones.ZONE_PARIS ) + .addPersistedWithoutHibernate( 1900, 1, 1, 0, 19, 31, 0, Timezones.ZONE_AMSTERDAM ) + .addPersistedWithoutHibernate( 1600, 1, 1, 0, 0, 0, 0, Timezones.ZONE_AMSTERDAM ) + ) + // HHH-13379: DST end (where Timestamp becomes ambiguous, see JDK-4312621) + // It doesn't seem that any time on 1970-01-01 can be affected by HHH-13379, but we add some tests just in case + .add( 1, 0, 0, 0, Timezones.ZONE_PARIS ) + .add( 2, 0, 0, 0, Timezones.ZONE_PARIS ) + .add( 3, 0, 0, 0, Timezones.ZONE_PARIS ) + .add( 1, 0, 0, 0, Timezones.ZONE_AUCKLAND ) + .add( 2, 0, 0, 0, Timezones.ZONE_AUCKLAND ) + .add( 3, 0, 0, 0, Timezones.ZONE_AUCKLAND ) + .build(); + } + + private final Parameter testParam; + + public LocalTimeTest(Parameter testParam) { + super( testParam.env() ); + this.testParam = testParam; + } + + @Override + protected Class getEntityType() { + return EntityWithLocalTime.class; + } + + @Override + protected EntityWithLocalTime createEntityForHibernateWrite(int id) { + return new EntityWithLocalTime( id, getOriginalPropertyValue() ); + } + + protected LocalTime getOriginalPropertyValue() { + return testParam.data().makeValue(); + } + + @Override + protected LocalTime getExpectedPropertyValueAfterHibernateRead() { + if ( TimeAsTimestampRemappingH2Dialect.class.equals( testParam.env().remappingDialectClass() ) ) { + return getOriginalPropertyValue(); + } + else { + // When storing time as java.sql.Time, we only get second precision (not nanosecond) + return getOriginalPropertyValue().withNano( 0 ); + } + } + + @Override + protected LocalTime getActualPropertyValue(EntityWithLocalTime entity) { + return entity.value; + } + + @Override + protected void bindJdbcValue( + PreparedStatement statement, + int parameterIndex, + SessionFactoryScope factoryScope) throws SQLException { + if ( TimeAsTimestampRemappingH2Dialect.class.equals( testParam.env().remappingDialectClass() ) ) { + statement.setTimestamp( parameterIndex, testParam.data().asTimestamp() ); + } + else { + statement.setTime( parameterIndex, testParam.data().asTime() ); + } + } + + @Override + protected Object getExpectedJdbcValueAfterHibernateWrite() { + if ( TimeAsTimestampRemappingH2Dialect.class.equals( testParam.env().remappingDialectClass() ) ) { + return testParam.data().asTimestamp(); + } + else { + return testParam.data().asTime(); + } + } + + @Override + protected Object extractJdbcValue( + ResultSet resultSet, + int columnIndex, + SessionFactoryScope factoryScope) throws SQLException { + if ( TimeAsTimestampRemappingH2Dialect.class.equals( testParam.env().remappingDialectClass() ) ) { + return resultSet.getTimestamp( columnIndex ); + } + else { + return resultSet.getTime( columnIndex ); + } + } + + @Override + @Test + @SkipForDialect(dialectClass = HANADialect.class, + reason = "HANA seems to return a java.sql.Timestamp instead of a java.sql.Time") + @SkipForDialect(dialectClass = MySQLDialect.class, + reason = "HHH-13580 MySQL seems to store the whole timestamp, not just the time," + + " which for some timezones results in a date other than 1970-01-01 being returned" + + " (typically 1969-12-31), even though the time is always right." + + " Since java.sql.Time holds the whole timestamp, not just the time," + + " its equals() method ends up returning false in this test.") + @SkipForDialect(dialectClass = HSQLDialect.class, + reason = "Timezone issue?") + public void writeThenNativeRead(SessionFactoryScope factoryScope) { + super.writeThenNativeRead( factoryScope ); + } + + @Entity + @Table(name = ENTITY_TBL_NAME) + public static final class EntityWithLocalTime { + @Id + @Column(name = ID_COLUMN_NAME) + private Integer id; + + @Basic + @Column(name = VALUE_COLUMN_NAME) + private LocalTime value; + + protected EntityWithLocalTime() { + } + + private EntityWithLocalTime(int id, LocalTime value) { + this.id = id; + this.value = value; + } + } + + private static class ParametersBuilder extends AbstractParametersBuilder { + public ParametersBuilder(Dialect dialect) { + super( dialect ); + } + + public ParametersBuilder add(int hour, int minute, int second, int nanosecond, ZoneId defaultTimeZone) { + if ( !isNanosecondPrecisionSupported() ) { + nanosecond = 0; + } + return add( defaultTimeZone, new LocalTimeData( + hour, + minute, + second, + nanosecond, + 1970, + 1, + 1 + ) ); + } + + public ParametersBuilder addPersistedWithoutHibernate( + int yearWhenPersistedWithoutHibernate, + int monthWhenPersistedWithoutHibernate, + int dayWhenPersistedWithoutHibernate, + int hour, + int minute, + int second, + int nanosecond, + ZoneId defaultTimeZone) { + if ( !isNanosecondPrecisionSupported() ) { + nanosecond = 0; + } + return add( defaultTimeZone, new LocalTimeData( + hour, minute, second, nanosecond, + yearWhenPersistedWithoutHibernate, monthWhenPersistedWithoutHibernate, dayWhenPersistedWithoutHibernate + ) ); + } + + @Override + protected Iterable getHibernateJdbcTimeZonesToTest() { + // The MariaDB Connector/J JDBC driver has a bug in ResultSet#getTime(int, Calendar) + // that prevents our explicit JDBC timezones from being recognized + // See https://hibernate.atlassian.net/browse/HHH-13581 + // See https://jira.mariadb.org/browse/CONJ-724 + if ( DialectContext.getDialect() instanceof MariaDBDialect ) { + return Collections.emptySet(); + } + return super.getHibernateJdbcTimeZonesToTest(); + } + } + + public static class TimeAsTimestampRemappingH2Dialect extends AbstractRemappingH2Dialect { + public TimeAsTimestampRemappingH2Dialect(Dialect baseDialect) { + super( baseDialect, Types.TIME, Types.TIMESTAMP ); + } + } + + public record LocalTimeData( + int hour, + int minute, + int second, + int nanosecond, + int yearWhenPersistedWithoutHibernate, + int monthWhenPersistedWithoutHibernate, + int dayWhenPersistedWithoutHibernate) implements Data { + @Override + public LocalTime makeValue() { + return LocalTime.of( hour(), minute(), second(), nanosecond() ); + } + + public Time asTime() { + return new Time( hour(), minute(), second() ); + } + + public Timestamp asTimestamp() { + return new Timestamp( + yearWhenPersistedWithoutHibernate - 1900, + monthWhenPersistedWithoutHibernate - 1, + dayWhenPersistedWithoutHibernate, + hour, minute, second, nanosecond + ); + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/type/OffsetDateTimeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/OffsetDateTimeTest.java similarity index 66% rename from hibernate-core/src/test/java/org/hibernate/orm/test/type/OffsetDateTimeTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/OffsetDateTimeTest.java index 9b928964fc2f..3046f6463902 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/type/OffsetDateTimeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/OffsetDateTimeTest.java @@ -2,7 +2,31 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.orm.test.type; +package org.hibernate.orm.test.type.temporal; + +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import org.hamcrest.MatcherAssert; +import org.hibernate.boot.registry.StandardServiceRegistry; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.H2Dialect; +import org.hibernate.dialect.MariaDBDialect; +import org.hibernate.dialect.MySQLDialect; +import org.hibernate.dialect.SybaseDialect; +import org.hibernate.testing.orm.junit.DialectContext; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.type.StandardBasicTypes; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedClass; +import org.junit.jupiter.params.provider.MethodSource; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -15,53 +39,30 @@ import java.util.Arrays; import java.util.List; import java.util.function.Consumer; -import jakarta.persistence.Basic; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; - -import org.hibernate.annotations.TimeZoneStorageType; -import org.hibernate.cfg.AvailableSettings; -import org.hibernate.cfg.Configuration; -import org.hibernate.dialect.H2Dialect; -import org.hibernate.query.Query; -import org.hibernate.dialect.MariaDBDialect; -import org.hibernate.dialect.MySQLDialect; -import org.hibernate.dialect.SybaseDialect; -import org.hibernate.type.StandardBasicTypes; - -import org.hibernate.testing.orm.junit.JiraKey; -import org.junit.Test; -import org.junit.runners.Parameterized; import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; +import static org.hibernate.annotations.TimeZoneStorageType.NORMALIZE; +import static org.hibernate.cfg.MappingSettings.TIMEZONE_DEFAULT_STORAGE; +import static org.hibernate.orm.test.type.temporal.Timezones.ZONE_AMSTERDAM; +import static org.hibernate.orm.test.type.temporal.Timezones.ZONE_AUCKLAND; +import static org.hibernate.orm.test.type.temporal.Timezones.ZONE_GMT; +import static org.hibernate.orm.test.type.temporal.Timezones.ZONE_OSLO; +import static org.hibernate.orm.test.type.temporal.Timezones.ZONE_PARIS; +import static org.hibernate.orm.test.type.temporal.Timezones.ZONE_UTC_MINUS_8; /** * @author Andrea Boriero */ @JiraKey(value = "HHH-10372") -public class OffsetDateTimeTest extends AbstractJavaTimeTypeTest { +@TestInstance( TestInstance.Lifecycle.PER_METHOD ) +@ParameterizedClass +@MethodSource("testData") +@DomainModel(annotatedClasses = OffsetDateTimeTest.EntityWithOffsetDateTime.class) +@SessionFactory +public class OffsetDateTimeTest extends AbstractJavaTimeTypeTests { - @Override - protected void configure(Configuration configuration) { - super.configure(configuration); - configuration.setProperty( AvailableSettings.TIMEZONE_DEFAULT_STORAGE, TimeZoneStorageType.NORMALIZE ); - } - - private static class ParametersBuilder extends AbstractParametersBuilder { - public ParametersBuilder add(int year, int month, int day, - int hour, int minute, int second, int nanosecond, String offset, ZoneId defaultTimeZone) { - if ( !isNanosecondPrecisionSupported() ) { - nanosecond = 0; - } - return add( defaultTimeZone, year, month, day, hour, minute, second, nanosecond, offset ); - } - } - - @Parameterized.Parameters(name = "{1}-{2}-{3}T{4}:{5}:{6}.{7}[{8}] {0}") - public static List data() { - return new ParametersBuilder() + public static List> testData() { + return new ParametersBuilder( DialectContext.getDialect() ) // Not affected by any known bug .add( 2017, 11, 6, 19, 19, 1, 0, "+10:00", ZONE_UTC_MINUS_8 ) .add( 2017, 11, 6, 19, 19, 1, 0, "+07:00", ZONE_UTC_MINUS_8 ) @@ -141,26 +142,17 @@ public static List data() { .build(); } - private final int year; - private final int month; - private final int day; - private final int hour; - private final int minute; - private final int second; - private final int nanosecond; - private final String offset; - - public OffsetDateTimeTest(EnvironmentParameters env, int year, int month, int day, - int hour, int minute, int second, int nanosecond, String offset) { - super( env ); - this.year = year; - this.month = month; - this.day = day; - this.hour = hour; - this.minute = minute; - this.second = second; - this.nanosecond = nanosecond; - this.offset = offset; + private final Parameter testParam; + + public OffsetDateTimeTest(Parameter testParam) { + super( testParam.env() ); + this.testParam = testParam; + } + + @Override + public StandardServiceRegistry produceServiceRegistry(StandardServiceRegistryBuilder builder) { + builder.applySetting( TIMEZONE_DEFAULT_STORAGE, NORMALIZE ); + return super.produceServiceRegistry( builder ); } @Override @@ -174,7 +166,7 @@ protected EntityWithOffsetDateTime createEntityForHibernateWrite(int id) { } private OffsetDateTime getOriginalOffsetDateTime() { - return OffsetDateTime.of( year, month, day, hour, minute, second, nanosecond, ZoneOffset.of( offset ) ); + return testParam.data().makeValue(); } @Override @@ -188,7 +180,10 @@ protected OffsetDateTime getActualPropertyValue(EntityWithOffsetDateTime entity) } @Override - protected void setJdbcValueForNonHibernateWrite(PreparedStatement statement, int parameterIndex) throws SQLException { + protected void bindJdbcValue( + PreparedStatement statement, + int parameterIndex, + SessionFactoryScope factoryScope) throws SQLException { statement.setTimestamp( parameterIndex, getExpectedJdbcValueAfterHibernateWrite() ); } @@ -206,21 +201,24 @@ protected Timestamp getExpectedJdbcValueAfterHibernateWrite() { } @Override - protected Object getActualJdbcValue(ResultSet resultSet, int columnIndex) throws SQLException { + protected Object extractJdbcValue( + ResultSet resultSet, + int columnIndex, + SessionFactoryScope factoryScope) throws SQLException { return resultSet.getTimestamp( columnIndex ); } @Test - public void testRetrievingEntityByOffsetDateTime() { - withDefaultTimeZone( () -> { - inTransaction( session -> { + public void testRetrievingEntityByOffsetDateTime(SessionFactoryScope factoryScope) { + Timezones.withDefaultTimeZone( testParam.env(), () -> { + factoryScope.inTransaction( session -> { session.persist( new EntityWithOffsetDateTime( 1, getOriginalOffsetDateTime() ) ); } ); - Consumer checkOneMatch = expected -> inSession( s -> { - Query query = s.createQuery( "from " + ENTITY_NAME + " o where o.value = :date" ); - query.setParameter( "date", expected, StandardBasicTypes.OFFSET_DATE_TIME ); - List list = query.list(); - assertThat( list.size(), is( 1 ) ); + Consumer checkOneMatch = expected -> factoryScope.inSession( s -> { + var list = s.createQuery( "from EntityWithOffsetDateTime o where o.value = :date" ) + .setParameter( "date", expected, StandardBasicTypes.OFFSET_DATE_TIME ) + .list(); + MatcherAssert.assertThat( list.size(), is( 1 ) ); } ); checkOneMatch.accept( getOriginalOffsetDateTime() ); checkOneMatch.accept( getExpectedPropertyValueAfterHibernateRead() ); @@ -228,14 +226,16 @@ public void testRetrievingEntityByOffsetDateTime() { } ); } - @Entity(name = ENTITY_NAME) - static final class EntityWithOffsetDateTime { + @SuppressWarnings({"FieldCanBeLocal", "unused"}) + @Entity(name = "EntityWithOffsetDateTime") + @Table(name = ENTITY_TBL_NAME) + public static class EntityWithOffsetDateTime { @Id @Column(name = ID_COLUMN_NAME) private Integer id; @Basic - @Column(name = PROPERTY_COLUMN_NAME) + @Column(name = VALUE_COLUMN_NAME) private OffsetDateTime value; protected EntityWithOffsetDateTime() { @@ -246,4 +246,28 @@ private EntityWithOffsetDateTime(int id, OffsetDateTime value) { this.value = value; } } + + private static class ParametersBuilder extends AbstractParametersBuilder { + protected ParametersBuilder(Dialect dialect) { + super( dialect ); + } + + public ParametersBuilder add(int year, int month, int day, + int hour, int minute, int second, int nanosecond, String offset, ZoneId defaultTimeZone) { + if ( !isNanosecondPrecisionSupported() ) { + nanosecond = 0; + } + return add( defaultTimeZone, new DataImpl( year, month, day, hour, minute, second, nanosecond, offset ) ); + } + } + + public record DataImpl( + int year, int month, int day, + int hour, int minute, int second, int nanosecond, + String offset) implements Data { + @Override + public OffsetDateTime makeValue() { + return OffsetDateTime.of( year, month, day, hour, minute, second, nanosecond, ZoneOffset.of( offset ) ); + } + } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/type/OffsetTimeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/OffsetTimeTest.java similarity index 55% rename from hibernate-core/src/test/java/org/hibernate/orm/test/type/OffsetTimeTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/OffsetTimeTest.java index 123bfc9e170f..2ad2a34730a5 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/type/OffsetTimeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/OffsetTimeTest.java @@ -2,7 +2,7 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.orm.test.type; +package org.hibernate.orm.test.type.temporal; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -24,67 +24,46 @@ import jakarta.persistence.Entity; import jakarta.persistence.Id; -import org.hibernate.annotations.TimeZoneStorageType; -import org.hibernate.cfg.AvailableSettings; -import org.hibernate.cfg.Configuration; +import jakarta.persistence.Table; +import org.hibernate.boot.registry.StandardServiceRegistry; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.dialect.Dialect; import org.hibernate.dialect.HANADialect; import org.hibernate.dialect.H2Dialect; import org.hibernate.dialect.HSQLDialect; import org.hibernate.dialect.MariaDBDialect; import org.hibernate.dialect.MySQLDialect; +import org.hibernate.testing.orm.junit.DialectContext; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.testing.orm.junit.SkipForDialect; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedClass; +import org.junit.jupiter.params.provider.MethodSource; -import org.hibernate.testing.SkipForDialect; -import org.junit.Test; -import org.junit.runners.Parameterized; +import static org.hibernate.annotations.TimeZoneStorageType.NORMALIZE; +import static org.hibernate.cfg.MappingSettings.TIMEZONE_DEFAULT_STORAGE; +import static org.hibernate.orm.test.type.temporal.Timezones.ZONE_AMSTERDAM; +import static org.hibernate.orm.test.type.temporal.Timezones.ZONE_AUCKLAND; +import static org.hibernate.orm.test.type.temporal.Timezones.ZONE_GMT; +import static org.hibernate.orm.test.type.temporal.Timezones.ZONE_OSLO; +import static org.hibernate.orm.test.type.temporal.Timezones.ZONE_PARIS; +import static org.hibernate.orm.test.type.temporal.Timezones.ZONE_UTC_MINUS_8; /** * Tests for storage of OffsetTime properties. */ -public class OffsetTimeTest extends AbstractJavaTimeTypeTest { +@TestInstance( TestInstance.Lifecycle.PER_METHOD ) +@ParameterizedClass +@MethodSource("testData") +@DomainModel(annotatedClasses = OffsetTimeTest.EntityWithOffsetTime.class) +@SessionFactory +public class OffsetTimeTest extends AbstractJavaTimeTypeTests { - @Override - protected void configure(Configuration configuration) { - super.configure(configuration); - configuration.setProperty( AvailableSettings.TIMEZONE_DEFAULT_STORAGE, TimeZoneStorageType.NORMALIZE ); - } - - private static class ParametersBuilder extends AbstractParametersBuilder { - public ParametersBuilder add(int hour, int minute, int second, int nanosecond, String offset, ZoneId defaultTimeZone) { - if ( !isNanosecondPrecisionSupported() ) { - nanosecond = 0; - } - return add( defaultTimeZone, hour, minute, second, nanosecond, offset, 1970, 1, 1 ); - } - - public ParametersBuilder addPersistedWithoutHibernate(int yearWhenPersistedWithoutHibernate, - int monthWhenPersistedWithoutHibernate, int dayWhenPersistedWithoutHibernate, - int hour, int minute, int second, int nanosecond, String offset, ZoneId defaultTimeZone) { - if ( !isNanosecondPrecisionSupported() ) { - nanosecond = 0; - } - return add( - defaultTimeZone, hour, minute, second, nanosecond, offset, - yearWhenPersistedWithoutHibernate, - monthWhenPersistedWithoutHibernate, dayWhenPersistedWithoutHibernate - ); - } - - @Override - protected Iterable getHibernateJdbcTimeZonesToTest() { - // The MariaDB Connector/J JDBC driver has a bug in ResultSet#getTime(int, Calendar) - // that prevents our explicit JDBC timezones from being recognized - // See https://hibernate.atlassian.net/browse/HHH-13581 - // See https://jira.mariadb.org/browse/CONJ-724 - if ( MariaDBDialect.class.isInstance( getDialect() ) ) { - return Collections.emptySet(); - } - return super.getHibernateJdbcTimeZonesToTest(); - } - } - - @Parameterized.Parameters(name = "{1}:{2}:{3}.{4}[{5}] (JDBC write date: {6}-{7}-{8}) {0}") - public static List data() { - return new ParametersBuilder() + public static List> testData() { + return new ParametersBuilder( DialectContext.getDialect() ) .alsoTestRemappingsWithH2( TimeAsTimestampRemappingH2Dialect.class ) // None of these values was affected by HHH-13266 (JDK-8061577) .add( 19, 19, 1, 0, "+10:00", ZONE_UTC_MINUS_8 ) @@ -141,27 +120,17 @@ public static List data() { .build(); } - private final int hour; - private final int minute; - private final int second; - private final int nanosecond; - private final String offset; + private final Parameter testParam; - private final int yearWhenPersistedWithoutHibernate; - private final int monthWhenPersistedWithoutHibernate; - private final int dayWhenPersistedWithoutHibernate; + public OffsetTimeTest(Parameter testParam) { + super( testParam.env() ); + this.testParam = testParam; + } - public OffsetTimeTest(EnvironmentParameters env, int hour, int minute, int second, int nanosecond, String offset, - int yearWhenPersistedWithoutHibernate, int monthWhenPersistedWithoutHibernate, int dayWhenPersistedWithoutHibernate) { - super( env ); - this.hour = hour; - this.minute = minute; - this.second = second; - this.nanosecond = nanosecond; - this.offset = offset; - this.yearWhenPersistedWithoutHibernate = yearWhenPersistedWithoutHibernate; - this.monthWhenPersistedWithoutHibernate = monthWhenPersistedWithoutHibernate; - this.dayWhenPersistedWithoutHibernate = dayWhenPersistedWithoutHibernate; + @Override + public StandardServiceRegistry produceServiceRegistry(StandardServiceRegistryBuilder builder) { + builder.applySetting( TIMEZONE_DEFAULT_STORAGE, NORMALIZE ); + return super.produceServiceRegistry( builder ); } @Override @@ -175,13 +144,13 @@ protected EntityWithOffsetTime createEntityForHibernateWrite(int id) { } protected OffsetTime getOriginalPropertyValue() { - return OffsetTime.of( hour, minute, second, nanosecond, ZoneOffset.of( offset ) ); + return testParam.data().makeValue(); } @Override protected OffsetTime getExpectedPropertyValueAfterHibernateRead() { // For some reason, the offset is not stored, so the restored values use the offset from the default JVM timezone. - if ( TimeAsTimestampRemappingH2Dialect.class.equals( getRemappingDialectClass() ) ) { + if ( TimeAsTimestampRemappingH2Dialect.class.equals( testParam.env().remappingDialectClass() ) ) { return getOriginalPropertyValue().withOffsetSameInstant( OffsetDateTime.now().getOffset() ); } else { @@ -196,36 +165,34 @@ protected OffsetTime getActualPropertyValue(EntityWithOffsetTime entity) { } @Override - protected void setJdbcValueForNonHibernateWrite(PreparedStatement statement, int parameterIndex) - throws SQLException { - OffsetTime offsetTime = OffsetTime.of( hour, minute, second, 0, ZoneOffset.of(offset) ) - .withOffsetSameInstant( OffsetDateTime.now().getOffset() ); - if ( TimeAsTimestampRemappingH2Dialect.class.equals( getRemappingDialectClass() ) ) { - statement.setTimestamp( - parameterIndex, - Timestamp.valueOf( offsetTime.atDate( LocalDate.EPOCH ).toLocalDateTime() ) - ); + protected void bindJdbcValue( + PreparedStatement statement, + int parameterIndex, + SessionFactoryScope factoryScope) throws SQLException { + if ( TimeAsTimestampRemappingH2Dialect.class.equals( testParam.env().remappingDialectClass() ) ) { + statement.setTimestamp( parameterIndex, testParam.data().asTimestamp() ); } else { - statement.setTime( parameterIndex, Time.valueOf( offsetTime.toLocalTime() ) ); + statement.setTime( parameterIndex, testParam.data().asTime() ); } } @Override protected Object getExpectedJdbcValueAfterHibernateWrite() { - OffsetTime offsetTime = OffsetTime.of( hour, minute, second, 0, ZoneOffset.of(offset) ) - .withOffsetSameInstant( OffsetDateTime.now().getOffset() ); - if ( TimeAsTimestampRemappingH2Dialect.class.equals( getRemappingDialectClass() ) ) { - return Timestamp.valueOf( offsetTime.atDate( LocalDate.EPOCH ).toLocalDateTime() ); + if ( TimeAsTimestampRemappingH2Dialect.class.equals( testParam.env().remappingDialectClass() ) ) { + return testParam.data().asTimestamp(); } else { - return Time.valueOf( offsetTime.toLocalTime() ); + return testParam.data().asTime(); } } @Override - protected Object getActualJdbcValue(ResultSet resultSet, int columnIndex) throws SQLException { - if ( TimeAsTimestampRemappingH2Dialect.class.equals( getRemappingDialectClass() ) ) { + protected Object extractJdbcValue( + ResultSet resultSet, + int columnIndex, + SessionFactoryScope factoryScope) throws SQLException { + if ( TimeAsTimestampRemappingH2Dialect.class.equals( testParam.env().remappingDialectClass() ) ) { return resultSet.getTimestamp( columnIndex ); } else { @@ -235,27 +202,32 @@ protected Object getActualJdbcValue(ResultSet resultSet, int columnIndex) throws @Override @Test - @SkipForDialect(value = HANADialect.class, comment = "HANA seems to return a java.sql.Timestamp instead of a java.sql.Time") - @SkipForDialect(value = MySQLDialect.class, - comment = "HHH-13580 MySQL seems to store the whole timestamp, not just the time," + @SkipForDialect(dialectClass = HANADialect.class, + reason = "HANA seems to return a java.sql.Timestamp instead of a java.sql.Time") + @SkipForDialect(dialectClass = MySQLDialect.class, + reason = "HHH-13580 MySQL seems to store the whole timestamp, not just the time," + " which for some timezones results in a date other than 1970-01-01 being returned" + " (typically 1969-12-31), even though the time is always right." + " Since java.sql.Time holds the whole timestamp, not just the time," + " its equals() method ends up returning false in this test.") - @SkipForDialect(value = HSQLDialect.class, comment = "Timezone issue?") - @SkipForDialect(value = H2Dialect.class, comment = "As of version 2.0.202 this seems to be a problem") - public void writeThenNativeRead() { - super.writeThenNativeRead(); + @SkipForDialect(dialectClass = HSQLDialect.class, + reason = "Timezone issue?") + @SkipForDialect(dialectClass = H2Dialect.class, + reason = "As of version 2.0.202 this seems to be a problem") + public void writeThenNativeRead(SessionFactoryScope factoryScope) { + super.writeThenNativeRead( factoryScope ); } - @Entity(name = ENTITY_NAME) - static final class EntityWithOffsetTime { + @SuppressWarnings({"FieldCanBeLocal", "unused"}) + @Entity + @Table(name = ENTITY_TBL_NAME) + public static class EntityWithOffsetTime { @Id @Column(name = ID_COLUMN_NAME) private Integer id; @Basic - @Column(name = PROPERTY_COLUMN_NAME) + @Column(name = VALUE_COLUMN_NAME) private OffsetTime value; protected EntityWithOffsetTime() { @@ -269,13 +241,67 @@ private EntityWithOffsetTime(int id, OffsetTime value) { public static class TimeAsTimestampRemappingH2Dialect extends AbstractRemappingH2Dialect { public TimeAsTimestampRemappingH2Dialect() { - super( Types.TIME, Types.TIMESTAMP ); + super( DialectContext.getDialect(), Types.TIME, Types.TIMESTAMP ); } } - public static class TimeAsBigIntRemappingH2Dialect extends AbstractRemappingH2Dialect { - public TimeAsBigIntRemappingH2Dialect() { - super( Types.TIME, Types.BIGINT ); + public record DataImpl(int hour, int minute, int second, int nanosecond, String offset, + int yearWhenPersistedWithoutHibernate, int monthWhenPersistedWithoutHibernate, + int dayWhenPersistedWithoutHibernate) implements Data { + @Override + public OffsetTime makeValue() { + return OffsetTime.of( hour, minute, second, nanosecond, ZoneOffset.of( offset ) ); + } + + public Timestamp asTimestamp() { + OffsetTime offsetTime = OffsetTime.of( hour, minute, second, 0, ZoneOffset.of(offset) ) + .withOffsetSameInstant( OffsetDateTime.now().getOffset() ); + return Timestamp.valueOf( offsetTime.atDate( LocalDate.EPOCH ).toLocalDateTime() ); + + } + + public Time asTime() { + OffsetTime offsetTime = OffsetTime.of( hour, minute, second, 0, ZoneOffset.of(offset) ) + .withOffsetSameInstant( OffsetDateTime.now().getOffset() ); + return Time.valueOf( offsetTime.toLocalTime() ); + } + } + + private static class ParametersBuilder + extends AbstractParametersBuilder { + protected ParametersBuilder(Dialect dialect) { + super( dialect ); + } + + public ParametersBuilder add(int hour, int minute, int second, int nanosecond, String offset, ZoneId defaultTimeZone) { + if ( !isNanosecondPrecisionSupported() ) { + nanosecond = 0; + } + return add( defaultTimeZone, new DataImpl( hour, minute, second, nanosecond, offset, 1970, 1, 1 ) ); + } + + public ParametersBuilder addPersistedWithoutHibernate( + int yearWhenPersistedWithoutHibernate, int monthWhenPersistedWithoutHibernate, int dayWhenPersistedWithoutHibernate, + int hour, int minute, int second, int nanosecond, String offset, ZoneId defaultTimeZone) { + if ( !isNanosecondPrecisionSupported() ) { + nanosecond = 0; + } + return add( defaultTimeZone, new DataImpl( + hour, minute, second, nanosecond, offset, + yearWhenPersistedWithoutHibernate, monthWhenPersistedWithoutHibernate, dayWhenPersistedWithoutHibernate + ) ); + } + + @Override + protected Iterable getHibernateJdbcTimeZonesToTest() { + // The MariaDB Connector/J JDBC driver has a bug in ResultSet#getTime(int, Calendar) + // that prevents our explicit JDBC timezones from being recognized + // See https://hibernate.atlassian.net/browse/HHH-13581 + // See https://jira.mariadb.org/browse/CONJ-724 + if ( DialectContext.getDialect() instanceof MariaDBDialect ) { + return Collections.emptySet(); + } + return super.getHibernateJdbcTimeZonesToTest(); } } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/Parameter.java b/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/Parameter.java new file mode 100644 index 000000000000..d822892031a2 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/Parameter.java @@ -0,0 +1,11 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.type.temporal; + +/** + * @author Steve Ebersole + */ +public record Parameter>(Environment env, D data) { +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/Timezones.java b/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/Timezones.java new file mode 100644 index 000000000000..271bf2c59af3 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/Timezones.java @@ -0,0 +1,92 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.orm.test.type.temporal; + +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.testing.jdbc.SharedDriverManagerConnectionProvider; +import org.junit.jupiter.api.Assumptions; + +import java.time.ZoneId; +import java.util.TimeZone; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +/** + * @author Steve Ebersole + */ +public class Timezones { + protected static final ZoneId ZONE_UTC_MINUS_8 = ZoneId.of( "UTC-8" ); + protected static final ZoneId ZONE_PARIS = ZoneId.of( "Europe/Paris" ); + protected static final ZoneId ZONE_GMT = ZoneId.of( "GMT" ); + protected static final ZoneId ZONE_OSLO = ZoneId.of( "Europe/Oslo" ); + protected static final ZoneId ZONE_AMSTERDAM = ZoneId.of( "Europe/Amsterdam" ); + protected static final ZoneId ZONE_AUCKLAND = ZoneId.of( "Pacific/Auckland" ); + protected static final ZoneId ZONE_SANTIAGO = ZoneId.of( "America/Santiago" ); + + static TimeZone toTimeZone(ZoneId zoneId) { + String idString = zoneId.getId(); + if ( idString.startsWith( "UTC+" ) || idString.startsWith( "UTC-" ) ) { + // Apparently TimeZone doesn't understand UTC+XXX nor UTC-XXX + // Using GMT+XXX or GMT-XXX as a fallback + idString = "GMT" + idString.substring( "UTC".length() ); + } + + TimeZone result = TimeZone.getTimeZone( idString ); + if ( !idString.equals( result.getID() ) ) { + // If the timezone is not understood, getTimeZone returns GMT and the condition above is true + throw new IllegalStateException( "Attempting to test an unsupported timezone: " + zoneId ); + } + + return result; + } + + public static void withDefaultTimeZone(Environment env, Runnable runnable) { + TimeZone timeZoneBefore = TimeZone.getDefault(); + TimeZone.setDefault( toTimeZone( env.defaultJvmTimeZone() ) ); + SharedDriverManagerConnectionProvider.getInstance().onDefaultTimeZoneChange(); + /* + * Run the code in a new thread, because some libraries (looking at you, h2 JDBC driver) + * cache data dependent on the default timezone in thread local variables, + * and we want this data to be reinitialized with the new default time zone. + */ + try { + ExecutorService executor = Executors.newSingleThreadExecutor(); + Future future = executor.submit( runnable ); + executor.shutdown(); + future.get(); + } + catch (InterruptedException e) { + throw new IllegalStateException( "Interrupted while testing", e ); + } + catch (ExecutionException e) { + Throwable cause = e.getCause(); + if ( cause instanceof RuntimeException ) { + throw (RuntimeException) cause; + } + else if ( cause instanceof Error ) { + throw (Error) cause; + } + else { + throw new IllegalStateException( "Unexpected exception while testing", cause ); + } + } + finally { + TimeZone.setDefault( timeZoneBefore ); + SharedDriverManagerConnectionProvider.getInstance().onDefaultTimeZoneChange(); + } + } + + public static void assumeNoJdbcTimeZone(Environment env) { + Assumptions.assumeTrue( + env.hibernateJdbcTimeZone() == null, + "Tests with native read/writes are only relevant when not using " + AvailableSettings.JDBC_TIME_ZONE + + ", because the expectations do not take that time zone into account." + + " When this property is set, we only test that a write by Hibernate followed by " + + " a read by Hibernate returns the same value." + ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/type/ZonedDateTimeTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/ZonedDateTimeTest.java similarity index 67% rename from hibernate-core/src/test/java/org/hibernate/orm/test/type/ZonedDateTimeTest.java rename to hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/ZonedDateTimeTest.java index 1525591c7cb5..8a72c00225d8 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/type/ZonedDateTimeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/type/temporal/ZonedDateTimeTest.java @@ -2,7 +2,31 @@ * SPDX-License-Identifier: Apache-2.0 * Copyright Red Hat Inc. and Hibernate Authors */ -package org.hibernate.orm.test.type; +package org.hibernate.orm.test.type.temporal; + +import jakarta.persistence.Basic; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import org.hamcrest.MatcherAssert; +import org.hibernate.boot.registry.StandardServiceRegistry; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.H2Dialect; +import org.hibernate.dialect.MariaDBDialect; +import org.hibernate.dialect.MySQLDialect; +import org.hibernate.dialect.SybaseDialect; +import org.hibernate.testing.orm.junit.DialectContext; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.hibernate.type.StandardBasicTypes; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.params.ParameterizedClass; +import org.junit.jupiter.params.provider.MethodSource; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -15,53 +39,31 @@ import java.util.Arrays; import java.util.List; import java.util.function.Consumer; -import jakarta.persistence.Basic; -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; - -import org.hibernate.annotations.TimeZoneStorageType; -import org.hibernate.cfg.AvailableSettings; -import org.hibernate.cfg.Configuration; -import org.hibernate.dialect.H2Dialect; -import org.hibernate.query.Query; -import org.hibernate.dialect.MariaDBDialect; -import org.hibernate.dialect.MySQLDialect; -import org.hibernate.dialect.SybaseDialect; -import org.hibernate.type.StandardBasicTypes; - -import org.hibernate.testing.orm.junit.JiraKey; -import org.junit.Test; -import org.junit.runners.Parameterized; import static org.hamcrest.core.Is.is; -import static org.junit.Assert.assertThat; +import static org.hibernate.annotations.TimeZoneStorageType.NORMALIZE; +import static org.hibernate.cfg.MappingSettings.TIMEZONE_DEFAULT_STORAGE; +import static org.hibernate.orm.test.type.temporal.Timezones.ZONE_AMSTERDAM; +import static org.hibernate.orm.test.type.temporal.Timezones.ZONE_AUCKLAND; +import static org.hibernate.orm.test.type.temporal.Timezones.ZONE_GMT; +import static org.hibernate.orm.test.type.temporal.Timezones.ZONE_OSLO; +import static org.hibernate.orm.test.type.temporal.Timezones.ZONE_PARIS; +import static org.hibernate.orm.test.type.temporal.Timezones.ZONE_UTC_MINUS_8; /** * @author Andrea Boriero */ +@TestInstance( TestInstance.Lifecycle.PER_METHOD ) +@ParameterizedClass +@MethodSource("testData") +@DomainModel(annotatedClasses = ZonedDateTimeTest.EntityWithZonedDateTime.class) +@SessionFactory @JiraKey(value = "HHH-10372") -public class ZonedDateTimeTest extends AbstractJavaTimeTypeTest { - - @Override - protected void configure(Configuration configuration) { - super.configure(configuration); - configuration.setProperty( AvailableSettings.TIMEZONE_DEFAULT_STORAGE, TimeZoneStorageType.NORMALIZE ); - } - - private static class ParametersBuilder extends AbstractParametersBuilder { - public ParametersBuilder add(int year, int month, int day, - int hour, int minute, int second, int nanosecond, String zone, ZoneId defaultTimeZone) { - if ( !isNanosecondPrecisionSupported() ) { - nanosecond = 0; - } - return add( defaultTimeZone, year, month, day, hour, minute, second, nanosecond, zone ); - } - } +public class ZonedDateTimeTest + extends AbstractJavaTimeTypeTests { - @Parameterized.Parameters(name = "{1}-{2}-{3}T{4}:{5}:{6}.{7}[{8}] {0}") - public static List data() { - return new ParametersBuilder() + public static List> testData() { + return new ParametersBuilder( DialectContext.getDialect() ) // Not affected by any known bug .add( 2017, 11, 6, 19, 19, 1, 0, "GMT+10:00", ZONE_UTC_MINUS_8 ) .add( 2017, 11, 6, 19, 19, 1, 0, "GMT+07:00", ZONE_UTC_MINUS_8 ) @@ -153,26 +155,17 @@ public static List data() { .build(); } - private final int year; - private final int month; - private final int day; - private final int hour; - private final int minute; - private final int second; - private final int nanosecond; - private final String zone; + private final Parameter testParam; + + public ZonedDateTimeTest(Parameter testParam) { + super( testParam.env() ); + this.testParam = testParam; + } - public ZonedDateTimeTest(EnvironmentParameters env, int year, int month, int day, - int hour, int minute, int second, int nanosecond, String zone) { - super( env ); - this.year = year; - this.month = month; - this.day = day; - this.hour = hour; - this.minute = minute; - this.second = second; - this.nanosecond = nanosecond; - this.zone = zone; + @Override + public StandardServiceRegistry produceServiceRegistry(StandardServiceRegistryBuilder builder) { + builder.applySetting( TIMEZONE_DEFAULT_STORAGE, NORMALIZE ); + return super.produceServiceRegistry( builder ); } @Override @@ -182,14 +175,11 @@ protected Class getEntityType() { @Override protected EntityWithZonedDateTime createEntityForHibernateWrite(int id) { - return new EntityWithZonedDateTime( - id, - getOriginalZonedDateTime() - ); + return new EntityWithZonedDateTime( id, getOriginalZonedDateTime() ); } private ZonedDateTime getOriginalZonedDateTime() { - return ZonedDateTime.of( year, month, day, hour, minute, second, nanosecond, ZoneId.of( zone ) ); + return testParam.data().makeValue(); } @Override @@ -203,13 +193,17 @@ protected ZonedDateTime getActualPropertyValue(EntityWithZonedDateTime entity) { } @Override - protected void setJdbcValueForNonHibernateWrite(PreparedStatement statement, int parameterIndex) throws SQLException { + protected void bindJdbcValue( + PreparedStatement statement, + int parameterIndex, + SessionFactoryScope factoryScope) throws SQLException { statement.setTimestamp( parameterIndex, getExpectedJdbcValueAfterHibernateWrite() ); } @Override protected Timestamp getExpectedJdbcValueAfterHibernateWrite() { - LocalDateTime dateTimeInDefaultTimeZone = getOriginalZonedDateTime().withZoneSameInstant( ZoneId.systemDefault() ) + LocalDateTime dateTimeInDefaultTimeZone = getOriginalZonedDateTime() + .withZoneSameInstant( ZoneId.systemDefault() ) .toLocalDateTime(); return new Timestamp( dateTimeInDefaultTimeZone.getYear() - 1900, dateTimeInDefaultTimeZone.getMonthValue() - 1, @@ -221,21 +215,24 @@ protected Timestamp getExpectedJdbcValueAfterHibernateWrite() { } @Override - protected Object getActualJdbcValue(ResultSet resultSet, int columnIndex) throws SQLException { + protected Object extractJdbcValue( + ResultSet resultSet, + int columnIndex, + SessionFactoryScope factoryScope) throws SQLException { return resultSet.getTimestamp( columnIndex ); } @Test - public void testRetrievingEntityByZonedDateTime() { - withDefaultTimeZone( () -> { - inTransaction( session -> { + public void testRetrievingEntityByZonedDateTime(SessionFactoryScope factoryScope) { + Timezones.withDefaultTimeZone( testParam.env(), () -> { + factoryScope.inTransaction( session -> { session.persist( new EntityWithZonedDateTime( 1, getOriginalZonedDateTime() ) ); } ); - Consumer checkOneMatch = expected -> inSession( s -> { - Query query = s.createQuery( "from " + ENTITY_NAME + " o where o.value = :date" ); - query.setParameter( "date", expected, StandardBasicTypes.ZONED_DATE_TIME ); - List list = query.list(); - assertThat( list.size(), is( 1 ) ); + Consumer checkOneMatch = expected -> factoryScope.inTransaction( s -> { + var result = s.createQuery( "from EntityWithZonedDateTime o where o.value = :date", EntityWithZonedDateTime.class ) + .setParameter( "date", expected, StandardBasicTypes.ZONED_DATE_TIME ) + .list(); + MatcherAssert.assertThat( result.size(), is( 1 ) ); } ); checkOneMatch.accept( getOriginalZonedDateTime() ); checkOneMatch.accept( getExpectedPropertyValueAfterHibernateRead() ); @@ -243,14 +240,16 @@ public void testRetrievingEntityByZonedDateTime() { } ); } - @Entity(name = ENTITY_NAME) - static final class EntityWithZonedDateTime { + @SuppressWarnings({"FieldCanBeLocal", "unused"}) + @Entity(name = "EntityWithZonedDateTime") + @Table(name = ENTITY_TBL_NAME) + public static class EntityWithZonedDateTime { @Id @Column(name = ID_COLUMN_NAME) private Integer id; @Basic - @Column(name = PROPERTY_COLUMN_NAME) + @Column(name = VALUE_COLUMN_NAME) private ZonedDateTime value; protected EntityWithZonedDateTime() { @@ -261,4 +260,30 @@ private EntityWithZonedDateTime(int id, ZonedDateTime value) { this.value = value; } } + + + private static class ParametersBuilder extends AbstractParametersBuilder { + protected ParametersBuilder(Dialect dialect) { + super( dialect ); + } + + public ParametersBuilder add( + int year, int month, int day, + int hour, int minute, int second, int nanosecond, + String zone, + ZoneId defaultTimeZone) { + if ( !isNanosecondPrecisionSupported() ) { + nanosecond = 0; + } + return add( defaultTimeZone, new DataImpl( year, month, day, hour, minute, second, nanosecond, zone ) ); + } + } + + public record DataImpl(int year, int month, int day, int hour, int minute, int second, int nanosecond, String zone) + implements Data { + @Override + public ZonedDateTime makeValue() { + return ZonedDateTime.of( year, month, day, hour, minute, second, nanosecond, ZoneId.of( zone ) ); + } + } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/version/mappedsuperclass/HbmMappingMappedSuperclassWithVersionTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/version/mappedsuperclass/HbmMappingMappedSuperclassWithVersionTest.java index a22abcbae5f9..16f796bfd3ee 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/version/mappedsuperclass/HbmMappingMappedSuperclassWithVersionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/version/mappedsuperclass/HbmMappingMappedSuperclassWithVersionTest.java @@ -7,46 +7,42 @@ import jakarta.persistence.criteria.CriteriaBuilder; import jakarta.persistence.criteria.CriteriaQuery; import jakarta.persistence.criteria.Root; - -import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase; - +import org.hamcrest.MatcherAssert; +import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.transaction.TransactionUtil; -import org.junit.Test; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.Test; import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.CoreMatchers.notNullValue; -import static org.junit.Assert.assertThat; /** * @author Andrea Boriero */ +@SuppressWarnings("JUnitMalformedDeclaration") @JiraKey(value = "HHH-11549") -public class HbmMappingMappedSuperclassWithVersionTest extends BaseEntityManagerFunctionalTestCase { - @Override - public String[] getMappings() { - return new String[] {"org/hibernate/orm/test/version/mappedsuperclass/TestEntity.hbm.xml"}; - } - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] {AbstractEntity.class}; - } +@DomainModel( + xmlMappings = "org/hibernate/orm/test/version/mappedsuperclass/TestEntity.hbm.xml", + annotatedClasses = AbstractEntity.class +) +@SessionFactory +public class HbmMappingMappedSuperclassWithVersionTest { @Test - public void testMetamodelContainsHbmVersion() { - TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> { + public void testMetamodelContainsHbmVersion(SessionFactoryScope factoryScope) { + factoryScope.inTransaction( entityManager -> { final TestEntity entity = new TestEntity(); entity.setName( "Chris" ); entityManager.persist( entity ); } ); - TransactionUtil.doInJPA( this::entityManagerFactory, entityManager -> { + factoryScope.inTransaction( entityManager -> { final CriteriaBuilder builder = entityManager.getCriteriaBuilder(); final CriteriaQuery query = builder.createQuery( TestEntity.class ); final Root root = query.from( TestEntity.class ); - assertThat( root.get( "version" ), is( notNullValue() ) ); + MatcherAssert.assertThat( root.get( "version" ), is( notNullValue() ) ); } ); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/version/sybase/Group.java b/hibernate-core/src/test/java/org/hibernate/orm/test/version/sybase/Group.java index 3ae94cd425e8..ba31f0f23a84 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/version/sybase/Group.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/version/sybase/Group.java @@ -12,23 +12,24 @@ * @author Steve Ebersole */ public class Group { - private Long id; + private Integer id; private Date timestamp; private String name; - private Set users; + private Set users; public Group() { } - public Group(String name) { + public Group(Integer id, String name) { + this.id = id; this.name = name; } - public Long getId() { + public Integer getId() { return id; } - public void setId(Long id) { + protected void setId(Integer id) { this.id = id; } @@ -48,11 +49,11 @@ public void setName(String name) { this.name = name; } - public Set getUsers() { + public Set getUsers() { return users; } - public void setUsers(Set users) { + public void setUsers(Set users) { this.users = users; } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/version/sybase/Permission.java b/hibernate-core/src/test/java/org/hibernate/orm/test/version/sybase/Permission.java index 6cc6280cb8fd..2715d40b7c2c 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/version/sybase/Permission.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/version/sybase/Permission.java @@ -11,7 +11,7 @@ * @author Steve Ebersole */ public class Permission { - private Long id; + private Integer id; private Date timestamp; private String name; private String context; @@ -20,17 +20,18 @@ public class Permission { public Permission() { } - public Permission(String name, String context, String access) { + public Permission(Integer id, String name, String context, String access) { + this.id = id; this.name = name; this.context = context; this.access = access; } - public Long getId() { + public Integer getId() { return id; } - public void setId(Long id) { + protected void setId(Integer id) { this.id = id; } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/version/sybase/SybaseTimestampComparisonAnnotationsTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/version/sybase/SybaseTimestampComparisonAnnotationsTest.java index 6bb772bde824..1eab183218df 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/version/sybase/SybaseTimestampComparisonAnnotationsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/version/sybase/SybaseTimestampComparisonAnnotationsTest.java @@ -4,79 +4,72 @@ */ package org.hibernate.orm.test.version.sybase; -import org.hibernate.Session; +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import jakarta.persistence.Version; import org.hibernate.annotations.Generated; import org.hibernate.dialect.SybaseASEDialect; import org.hibernate.generator.EventType; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; import org.hibernate.type.BasicType; import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType; import org.hibernate.type.descriptor.jdbc.VarbinaryJdbcType; - -import org.hibernate.testing.RequiresDialect; -import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.junit.Test; - -import jakarta.persistence.Column; -import jakarta.persistence.Entity; -import jakarta.persistence.Id; -import jakarta.persistence.Table; -import jakarta.persistence.Version; - -import static org.junit.Assert.assertTrue; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; /** * @author Gail Badner */ +@SuppressWarnings("JUnitMalformedDeclaration") @RequiresDialect( SybaseASEDialect.class ) -public class SybaseTimestampComparisonAnnotationsTest extends BaseCoreFunctionalTestCase { +@DomainModel(annotatedClasses = SybaseTimestampComparisonAnnotationsTest.Thing.class) +@SessionFactory +public class SybaseTimestampComparisonAnnotationsTest { + @AfterEach + void tearDown(SessionFactoryScope factoryScope) { + factoryScope.dropData(); + } @Test @JiraKey( value = "HHH-10413" ) - public void testComparableTimestamps() { - final BasicType versionType = sessionFactory() + public void testComparableTimestamps(SessionFactoryScope factoryScope) { + final BasicType versionType = factoryScope + .getSessionFactory() .getMappingMetamodel() .getEntityDescriptor(Thing.class.getName()).getVersionType(); - assertTrue( versionType.getJavaTypeDescriptor() instanceof PrimitiveByteArrayJavaType ); - assertTrue( versionType.getJdbcType() instanceof VarbinaryJdbcType ); - - Session s = openSession(); - s.getTransaction().begin(); - Thing thing = new Thing(); - thing.name = "n"; - s.persist( thing ); - s.getTransaction().commit(); - s.close(); + Assertions.assertInstanceOf( PrimitiveByteArrayJavaType.class, versionType.getJavaTypeDescriptor() ); + Assertions.assertInstanceOf( VarbinaryJdbcType.class, versionType.getJdbcType() ); - byte[] previousVersion = thing.version; - for ( int i = 0 ; i < 20 ; i++ ) { - try { - Thread.sleep(1000); //1000 milliseconds is one second. - } catch(InterruptedException ex) { - Thread.currentThread().interrupt(); - } + final var created = factoryScope.fromTransaction( (s) -> { + var t = new Thing(); + t.name = "n"; + s.persist( t ); + return t; + } ); - s = openSession(); - s.getTransaction().begin(); - thing.name = "n" + i; - thing = (Thing) s.merge( thing ); - s.getTransaction().commit(); - s.close(); + byte[] previousVersion = created.version; - assertTrue( versionType.compare( previousVersion, thing.version ) < 0 ); - previousVersion = thing.version; + try { + // 2 seconds + Thread.sleep(2000); + } + catch(InterruptedException ex) { + Thread.currentThread().interrupt(); } - s = openSession(); - s.getTransaction().begin(); - s.remove( thing ); - s.getTransaction().commit(); - s.close(); - } + var merged = factoryScope.fromTransaction( (s) -> { + created.name = "x"; + return s.merge( created ); + } ); - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { Thing.class }; + Assertions.assertTrue( versionType.compare( previousVersion, merged.version ) < 0 ); } @Entity diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/version/sybase/SybaseTimestampVersioningTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/version/sybase/SybaseTimestampVersioningTest.java index ce682f7edecb..9e5cc8a85598 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/version/sybase/SybaseTimestampVersioningTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/version/sybase/SybaseTimestampVersioningTest.java @@ -5,298 +5,172 @@ package org.hibernate.orm.test.version.sybase; import jakarta.persistence.OptimisticLockException; - -import org.junit.Test; - -import org.hibernate.Session; -import org.hibernate.Transaction; - -import org.hibernate.testing.RequiresDialect; -import org.hibernate.testing.orm.junit.JiraKey; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; - import org.hibernate.dialect.SybaseASEDialect; +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.RequiresDialect; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; import org.hibernate.type.BasicType; import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType; import org.hibernate.type.descriptor.jdbc.VarbinaryJdbcType; - -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - -/** - * Implementation of VersionTest. - * - * @author Steve Ebersole - */ -@RequiresDialect( SybaseASEDialect.class ) -public class SybaseTimestampVersioningTest extends BaseCoreFunctionalTestCase { - - @Override - protected String getBaseForMappings() { - return "org/hibernate/orm/test/"; - } - - @Override - public String[] getMappings() { - return new String[] { "version/sybase/User.hbm.xml" }; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +/// @author Steve Ebersole +@SuppressWarnings("JUnitMalformedDeclaration") +@RequiresDialect(SybaseASEDialect.class) +@DomainModel(xmlMappings = "org/hibernate/orm/test/version/sybase/User.hbm.xml") +@SessionFactory +public class SybaseTimestampVersioningTest { + @AfterEach + public void tearDown(SessionFactoryScope factoryScope) { + factoryScope.dropData(); } @Test - public void testLocking() { + public void testLocking(SessionFactoryScope factoryScope) { // First, create the needed row... - Session s = openSession(); - Transaction t = s.beginTransaction(); - User steve = new User( "steve" ); - s.persist( steve ); - t.commit(); - s.close(); + factoryScope.inTransaction( (s) -> { + var steve = new User( 1, "steve" ); + s.persist( steve ); + } ); // next open two sessions, and try to update from each "simultaneously"... - Session s1 = null; - Session s2 = null; - Transaction t1 = null; - Transaction t2 = null; try { - s1 = sessionFactory().openSession(); - t1 = s1.beginTransaction(); - s2 = sessionFactory().openSession(); - t2 = s2.beginTransaction(); - - User user1 = s1.get( User.class, steve.getId() ); - User user2 = s2.get( User.class, steve.getId() ); - - user1.setUsername( "se" ); - t1.commit(); - t1 = null; - - user2.setUsername( "steve-e" ); - try { - t2.commit(); - fail( "optimistic lock check did not fail" ); - } - catch( OptimisticLockException e ) { - // expected... - try { - t2.rollback(); - } - catch( Throwable ignore ) { - } - } - } - catch( Throwable error ) { - if ( t1 != null ) { - try { - t1.rollback(); - } - catch( Throwable ignore ) { - } - } - if ( t2 != null ) { - try { - t2.rollback(); - } - catch( Throwable ignore ) { - } - } - throw error; + factoryScope.inTransaction( (s1) -> { + var steve1 = s1.find( User.class, 1 ); + + factoryScope.inTransaction( (s2) -> { + var steve2 = s2.find( User.class, 1 ); + steve2.setUsername( "steve-e" ); + } ); + + // this one should cause a failure during flush + steve1.setUsername( "se" ); + } ); + Assertions.fail( "Should have thrown an OptimisticLockException" ); } - finally { - if ( s1 != null ) { - try { - s1.close(); - } - catch( Throwable ignore ) { - } - } - if ( s2 != null ) { - try { - s2.close(); - } - catch( Throwable ignore ) { - } - } + catch (OptimisticLockException expected) { } - - // lastly, clean up... - s = openSession(); - t = s.beginTransaction(); - s.remove( s.getReference( User.class, steve.getId() ) ); - t.commit(); - s.close(); } @Test - @SuppressWarnings( {"unchecked"}) - public void testCollectionVersion() { - Session s = openSession(); - Transaction t = s.beginTransaction(); - User steve = new User( "steve" ); - s.persist( steve ); - Group admin = new Group( "admin" ); - s.persist( admin ); - t.commit(); - s.close(); - - byte[] steveTimestamp = steve.getTimestamp(); + public void testCollectionVersion(SessionFactoryScope factoryScope) { + var first = factoryScope.fromTransaction( (s) -> { + var steve = new User( 1, "steve" ); + s.persist( steve ); + var admin = new Group( 1, "admin" ); + s.persist( admin ); + return steve; + } ); sleep(); - s = openSession(); - t = s.beginTransaction(); - steve = s.get( User.class, steve.getId() ); - admin = s.get( Group.class, admin.getId() ); - steve.getGroups().add( admin ); - admin.getUsers().add( steve ); - t.commit(); - s.close(); - - // Hibernate used to increment the version here, - // when the collections changed, but now doesn't - // that's OK, because the only reason this worked - // in H5 was due to a bug (it used to go and ask - // for getdate() from the database, even though - // it wasn't planning on doing anything with it, - // and then issue a spurious 'update' statement) -// assertFalse( -// "owner version not incremented", -// PrimitiveByteArrayJavaType.INSTANCE.areEqual( steveTimestamp, steve.getTimestamp() ) -// ); + var second = factoryScope.fromTransaction( (s) -> { + var steve = s.find( User.class, 1 ); + var admin = s.find( Group.class, 1 ); + steve.getGroups().add( admin ); + admin.getUsers().add( steve ); + return steve; + } ); - steveTimestamp = steve.getTimestamp(); + // since this collection is mapped as excluded from + // optimistic locking, the version should not change + Assertions.assertTrue( PrimitiveByteArrayJavaType.INSTANCE.areEqual( first.getTimestamp(), second.getTimestamp() ), + "owner version unexpectedly incremented" ); sleep(); - s = openSession(); - t = s.beginTransaction(); - steve = s.get( User.class, steve.getId() ); - steve.getGroups().clear(); - t.commit(); - s.close(); + var third = factoryScope.fromTransaction( (s) -> { + var steve = s.find( User.class, 1 ); + steve.getGroups().clear(); + return steve; + } ); - // Hibernate used to increment the version here, - // when the collections changed, but now doesn't - // that's OK, because the only reason this worked - // in H5 was due to a bug (it used to go and ask - // for getdate() from the database, even though - // it wasn't planning on doing anything with it, - // and then issue a spurious 'update' statement) -// assertFalse( -// "owner version not incremented", -// PrimitiveByteArrayJavaType.INSTANCE.areEqual( steveTimestamp, steve.getTimestamp() ) -// ); - - sleep(); - - s = openSession(); - t = s.beginTransaction(); - s.remove( s.getReference( User.class, steve.getId() ) ); - s.remove( s.getReference( Group.class, admin.getId() ) ); - t.commit(); - s.close(); + // as per discussion before, the version should not change + Assertions.assertTrue( PrimitiveByteArrayJavaType.INSTANCE.areEqual( second.getTimestamp(), third.getTimestamp() ), + "owner version unexpectedly incremented" ); } @Test @SuppressWarnings( {"unchecked"}) - public void testCollectionNoVersion() { - Session s = openSession(); - Transaction t = s.beginTransaction(); - User steve = new User( "steve" ); - s.persist( steve ); - Permission perm = new Permission( "silly", "user", "rw" ); - s.persist( perm ); - t.commit(); - s.close(); - - byte[] steveTimestamp = steve.getTimestamp(); + public void testCollectionNoVersion(SessionFactoryScope factoryScope) { + var first = factoryScope.fromTransaction( (s) -> { + User steve = new User( 1, "steve" ); + s.persist( steve ); + Permission perm = new Permission( 1, "silly", "user", "rw" ); + s.persist( perm ); + return steve; + } ); sleep(); - s = openSession(); - t = s.beginTransaction(); - steve = s.get( User.class, steve.getId() ); - perm = s.get( Permission.class, perm.getId() ); - steve.getPermissions().add( perm ); - t.commit(); - s.close(); + var second = factoryScope.fromTransaction( (s) -> { + var steve = s.find( User.class, 1 ); + var perm = s.find( Permission.class, 1 ); + steve.getPermissions().add( perm ); + return steve; + } ); - assertTrue( - "owner version was incremented", - PrimitiveByteArrayJavaType.INSTANCE.areEqual( steveTimestamp, steve.getTimestamp() ) - ); + // since this collection *is* included in optimistic locking, + // this should trigger an increment of the version + Assertions.assertTrue( + PrimitiveByteArrayJavaType.INSTANCE.areEqual( first.getTimestamp(), second.getTimestamp() ), + "owner version was incremented" ); sleep(); - s = openSession(); - t = s.beginTransaction(); - steve = s.get( User.class, steve.getId() ); - steve.getPermissions().clear(); - t.commit(); - s.close(); + var third = factoryScope.fromTransaction( (s) -> { + var steve = s.find( User.class, 1 ); + steve.getPermissions().clear(); + return steve; + } ); - assertTrue( - "owner version was incremented", - PrimitiveByteArrayJavaType.INSTANCE.areEqual( steveTimestamp, steve.getTimestamp() ) - ); - - sleep(); - - s = openSession(); - t = s.beginTransaction(); - s.remove( s.getReference( User.class, steve.getId() ) ); - s.remove( s.getReference( Permission.class, perm.getId() ) ); - t.commit(); - s.close(); + Assertions.assertTrue( + PrimitiveByteArrayJavaType.INSTANCE.areEqual( second.getTimestamp(), third.getTimestamp() ), + "owner version was incremented" ); } private static void sleep() { + sleep( 200 ); + } + + private static void sleep(long millis) { try { - Thread.sleep(200); - } catch (InterruptedException ignored) { + Thread.sleep(millis); + } + catch (InterruptedException ignored) { } } @Test @JiraKey( value = "HHH-10413" ) - public void testComparableTimestamps() { - final BasicType versionType = sessionFactory() + public void testComparableTimestamps(SessionFactoryScope factoryScope) { + final BasicType versionType = factoryScope + .getSessionFactory() .getMappingMetamodel() .getEntityDescriptor(User.class.getName()) .getVersionType(); - assertTrue( versionType.getJavaTypeDescriptor() instanceof PrimitiveByteArrayJavaType ); - assertTrue( versionType.getJdbcType() instanceof VarbinaryJdbcType ); + Assertions.assertInstanceOf( PrimitiveByteArrayJavaType.class, versionType.getJavaTypeDescriptor() ); + Assertions.assertInstanceOf( VarbinaryJdbcType.class, versionType.getJdbcType() ); - Session s = openSession(); - s.getTransaction().begin(); - User user = new User(); - user.setUsername( "n" ); - s.persist( user ); - s.getTransaction().commit(); - s.close(); + var first = factoryScope.fromTransaction( (s) -> { + var user = new User( 1, "n" ); + s.persist( user ); + return user; + } ); - byte[] previousTimestamp = user.getTimestamp(); - for ( int i = 0 ; i < 20 ; i++ ) { - try { - Thread.sleep(1000); //1000 milliseconds is one second. - } catch(InterruptedException ex) { - Thread.currentThread().interrupt(); - } + sleep( 2000 ); - s = openSession(); - s.getTransaction().begin(); - user.setUsername( "n" + i ); - user = s.merge( user ); - s.getTransaction().commit(); - s.close(); - - assertTrue( versionType.compare( previousTimestamp, user.getTimestamp() ) < 0 ); - previousTimestamp = user.getTimestamp(); - } + var second = factoryScope.fromTransaction( (s) -> { + var u = s.find( User.class, 1 ); + u.setUsername( "x" ); + return u; + } ); - s = openSession(); - s.getTransaction().begin(); - s.remove( user ); - s.getTransaction().commit(); - s.close(); + Assertions.assertTrue( versionType.compare( first.getTimestamp(), second.getTimestamp() ) < 0 ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/version/sybase/User.java b/hibernate-core/src/test/java/org/hibernate/orm/test/version/sybase/User.java index c5e3857e9d64..07d3dee86f2a 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/version/sybase/User.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/version/sybase/User.java @@ -11,24 +11,25 @@ * @author Steve Ebersole */ public class User { - private Long id; + private Integer id; private byte[] timestamp; private String username; - private Set groups; - private Set permissions; + private Set groups; + private Set permissions; public User() { } - public User(String username) { + public User(Integer id, String username) { + this.id = id; this.username = username; } - public Long getId() { + public Integer getId() { return id; } - public void setId(Long id) { + protected void setId(Integer id) { this.id = id; } @@ -48,19 +49,19 @@ public void setUsername(String username) { this.username = username; } - public Set getGroups() { + public Set getGroups() { return groups; } - public void setGroups(Set groups) { + public void setGroups(Set groups) { this.groups = groups; } - public Set getPermissions() { + public Set getPermissions() { return permissions; } - public void setPermissions(Set permissions) { + public void setPermissions(Set permissions) { this.permissions = permissions; } } diff --git a/hibernate-core/src/test/resources/org/hibernate/orm/test/version/sybase/User.hbm.xml b/hibernate-core/src/test/resources/org/hibernate/orm/test/version/sybase/User.hbm.xml index 5754232ff478..bdf840a1542e 100644 --- a/hibernate-core/src/test/resources/org/hibernate/orm/test/version/sybase/User.hbm.xml +++ b/hibernate-core/src/test/resources/org/hibernate/orm/test/version/sybase/User.hbm.xml @@ -14,9 +14,7 @@ - - - + @@ -32,9 +30,7 @@ - - - + @@ -44,9 +40,7 @@ - - - + diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/jdbc/JdbcUtils.java b/hibernate-testing/src/main/java/org/hibernate/testing/jdbc/JdbcUtils.java new file mode 100644 index 000000000000..7fd56dd2c197 --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/jdbc/JdbcUtils.java @@ -0,0 +1,58 @@ +/* + * SPDX-License-Identifier: Apache-2.0 + * Copyright Red Hat Inc. and Hibernate Authors + */ +package org.hibernate.testing.jdbc; + +import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; +import org.hibernate.service.ServiceRegistry; + +import java.sql.Connection; +import java.sql.SQLException; + +/** + * @author Steve Ebersole + */ +public class JdbcUtils { + @FunctionalInterface + public interface ConnectionAction { + void execute(Connection connection) throws SQLException; + } + + public static void withConnection(ServiceRegistry serviceRegistry, ConnectionAction action) { + final ConnectionProvider connections = serviceRegistry.requireService( ConnectionProvider.class ); + try { + final var connection = connections.getConnection(); + try { + action.execute( connection ); + } + catch (SQLException e) { + throw new RuntimeException( e ); + } + finally { + connections.closeConnection( connection ); + } + } + catch (SQLException e) { + throw new RuntimeException( e ); + } + } + + public static void withConnection(ConnectionProvider connections, ConnectionAction action) { + try { + final var connection = connections.getConnection(); + try { + action.execute( connection ); + } + catch (SQLException e) { + throw new RuntimeException( e ); + } + finally { + connections.closeConnection( connection ); + } + } + catch (SQLException e) { + throw new RuntimeException( e ); + } + } +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/LoggingInspectionsScope.java b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/LoggingInspectionsScope.java index ed549f3eed13..e5a34b39230a 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/LoggingInspectionsScope.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/LoggingInspectionsScope.java @@ -72,4 +72,15 @@ public MessageKeyWatcher getWatcher(String messageKey, Class loggerNameClass) final Map messageKeyWatcherMap = watcherMap.get( messageKey ); return messageKeyWatcherMap.get( loggerNameClass.getName() ); } + + public boolean wereAnyTriggered() { + for ( Map.Entry> watcherMapEntry : watcherMap.entrySet() ) { + for ( Map.Entry messageWatcherEntry : watcherMapEntry.getValue().entrySet() ) { + if ( messageWatcherEntry.getValue().wasTriggered() ) { + return true; + } + } + } + return false; + } } diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/SessionFactoryExtension.java b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/SessionFactoryExtension.java index 8e5a3474c85b..53c9025cf1fa 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/SessionFactoryExtension.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/SessionFactoryExtension.java @@ -384,6 +384,15 @@ public T fromTransaction(SessionImplementor session, Function T fromTransaction(Function sessionProducer, Function action) { + log.trace( "fromTransaction(Function,Function)" ); + + try (SessionImplementor session = sessionProducer.apply( getSessionFactory() )) { + return TransactionUtil.fromTransaction( session, action ); + } + } + @Override public void inStatelessSession(Consumer action) { log.trace( "#inStatelessSession(Consumer)" ); diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/SessionFactoryScope.java b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/SessionFactoryScope.java index 7443b044d1a1..ae1e3b8b86f6 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/SessionFactoryScope.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/orm/junit/SessionFactoryScope.java @@ -38,6 +38,7 @@ default void withSessionFactory(Consumer action) { T fromSession(Function action); T fromTransaction(Function action); T fromTransaction(SessionImplementor session, Function action); + T fromTransaction(Function sessionProducer, Function action); void inStatelessSession(Consumer action); void inStatelessTransaction(Consumer action); diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/util/ServiceRegistryUtil.java b/hibernate-testing/src/main/java/org/hibernate/testing/util/ServiceRegistryUtil.java index 417f0da4e9a8..d167def2711f 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/util/ServiceRegistryUtil.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/util/ServiceRegistryUtil.java @@ -29,7 +29,7 @@ public static StandardServiceRegistryBuilder serviceRegistryBuilder(boolean appl return applySettings( ssrb ); } - private static void applyEnvSettings(StandardServiceRegistryBuilder ssrb) { + public static void applyEnvSettings(StandardServiceRegistryBuilder ssrb) { ssrb.applySettings( Environment.getProperties() ); }