Skip to content

Commit

Permalink
HHH-17824 - Extend the use of @jpa to test methods
Browse files Browse the repository at this point in the history
Signed-off-by: Jan Schatteman <jschatte@redhat.com>
  • Loading branch information
jrenaat authored and sebersole committed Mar 28, 2024
1 parent ddcfc54 commit 454e1cb
Show file tree
Hide file tree
Showing 7 changed files with 266 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -310,8 +310,6 @@ private EntityManagerFactoryBuilderImpl(
}

// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// push back class transformation to the environment; for the time being this only has any effect in EE
// container situations, calling back into PersistenceUnitInfo#addClassTransformer

final boolean dirtyTrackingEnabled;
Object propertyValue = configurationValues.remove( ENHANCER_ENABLE_DIRTY_TRACKING );
Expand Down Expand Up @@ -344,6 +342,8 @@ private EntityManagerFactoryBuilderImpl(
associationManagementEnabled
);

// push back class transformation to the environment; for the time being this only has any effect in EE
// container situations, calling back into PersistenceUnitInfo#addClassTransformer
persistenceUnit.pushClassTransformer( enhancementContext );
final ClassTransformer classTransformer = persistenceUnit.getClassTransformer();
if ( classTransformer != null ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
import org.hibernate.testing.orm.domain.StandardDomainModel;
import org.hibernate.testing.orm.jpa.PersistenceUnitInfoImpl;
import org.hibernate.testing.util.ServiceRegistryUtil;
import org.junit.jupiter.api.extension.AfterAllCallback;
import org.junit.jupiter.api.extension.BeforeEachCallback;
import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.TestExecutionExceptionHandler;
import org.junit.jupiter.api.extension.TestInstancePostProcessor;
Expand All @@ -54,19 +54,26 @@
* @see SessionFactoryExtension
*/
public class EntityManagerFactoryExtension
implements TestInstancePostProcessor, AfterAllCallback, TestExecutionExceptionHandler {
implements TestInstancePostProcessor, BeforeEachCallback, TestExecutionExceptionHandler {

private static final Logger log = Logger.getLogger( EntityManagerFactoryExtension.class );
private static final String EMF_KEY = EntityManagerFactoryScope.class.getName();

private static ExtensionContext.Store locateExtensionStore(Object testInstance, ExtensionContext context) {
return JUnitHelper.locateExtensionStore( EntityManagerFactoryExtension.class, context, testInstance );
private static ExtensionContext.Store locateExtensionStore(Object testScope, ExtensionContext context) {
return JUnitHelper.locateExtensionStore( EntityManagerFactoryExtension.class, context, testScope );
}

public static EntityManagerFactoryScope findEntityManagerFactoryScope(
Object testInstance,
Object testScope,
Optional<Jpa> emfAnnWrapper,
ExtensionContext context) {
final ExtensionContext.Store store = locateExtensionStore( testInstance, context );

if ( emfAnnWrapper.isEmpty() ) {
// No annotation on the test class, should be on the test methods
return null;
}

final ExtensionContext.Store store = locateExtensionStore( testScope, context );
final EntityManagerFactoryScope existing = (EntityManagerFactoryScope) store.get( EMF_KEY );
if ( existing != null ) {
return existing;
Expand All @@ -75,12 +82,7 @@ public static EntityManagerFactoryScope findEntityManagerFactoryScope(
if ( !context.getElement().isPresent() ) {
throw new RuntimeException( "Unable to determine how to handle given ExtensionContext : " + context.getDisplayName() );
}

final Optional<Jpa> emfAnnWrapper = AnnotationSupport.findAnnotation(
context.getElement().get(),
Jpa.class
);
final Jpa emfAnn = emfAnnWrapper.orElseThrow( () -> new RuntimeException( "Could not locate @EntityManagerFactory" ) );
final Jpa emfAnn = emfAnnWrapper.get();

final PersistenceUnitInfoImpl pui = new PersistenceUnitInfoImpl( emfAnn.persistenceUnitName() );
( (Map<Object, Object>) Environment.getProperties() ).forEach(
Expand Down Expand Up @@ -196,7 +198,7 @@ public static EntityManagerFactoryScope findEntityManagerFactoryScope(
ServiceRegistryUtil.applySettings( integrationSettings );
final EntityManagerFactoryScopeImpl scope = new EntityManagerFactoryScopeImpl( pui, integrationSettings );

locateExtensionStore( testInstance, context ).put( EMF_KEY, scope );
store.put( EMF_KEY, scope );

return scope;
}
Expand Down Expand Up @@ -267,29 +269,31 @@ public void sessionFactoryClosing(org.hibernate.SessionFactory factory) {
}

@Override
public void postProcessTestInstance(Object testInstance, ExtensionContext context) {
log.tracef( "#postProcessTestInstance(%s, %s)", testInstance, context.getDisplayName() );
public void beforeEach(ExtensionContext context) {
log.tracef( "#beforeEach(%s)", context.getDisplayName() );
final Optional<Jpa> emfAnnWrapper = AnnotationSupport.findAnnotation(
context.getRequiredTestMethod(),
Jpa.class
);

findEntityManagerFactoryScope( testInstance, context );
if ( emfAnnWrapper.isEmpty() ) {
// assume the annotation is defined on the class-level...
return;
}

findEntityManagerFactoryScope( context.getRequiredTestMethod(), emfAnnWrapper, context );
}

@Override
public void afterAll(ExtensionContext context) {
log.tracef( "#afterAll(%s)", context.getDisplayName() );

final Object testInstance = context.getRequiredTestInstance();
public void postProcessTestInstance(Object testInstance, ExtensionContext context) {
log.tracef( "#postProcessTestInstance(%s, %s)", testInstance, context.getDisplayName() );

if ( testInstance instanceof SessionFactoryScopeAware ) {
( (SessionFactoryScopeAware) testInstance ).injectSessionFactoryScope( null );
}
final Optional<Jpa> emfAnnWrapper = AnnotationSupport.findAnnotation(
context.getRequiredTestClass(),
Jpa.class
);

final EntityManagerFactoryScopeImpl removed = (EntityManagerFactoryScopeImpl) locateExtensionStore(
testInstance,
context
).remove( EMF_KEY );
if ( removed != null ) {
removed.close();
}
findEntityManagerFactoryScope( testInstance, emfAnnWrapper, context );
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@
*/
package org.hibernate.testing.orm.junit;

import java.util.Optional;

import jakarta.persistence.EntityManagerFactory;

import org.junit.jupiter.api.extension.ExtensionContext;
import org.junit.jupiter.api.extension.ParameterContext;
import org.junit.jupiter.api.extension.ParameterResolutionException;
import org.junit.jupiter.api.extension.ParameterResolver;
import org.junit.platform.commons.support.AnnotationSupport;

import static org.hibernate.testing.orm.junit.EntityManagerFactoryExtension.findEntityManagerFactoryScope;

Expand All @@ -34,8 +37,31 @@ public boolean supportsParameter(
public Object resolveParameter(
ParameterContext parameterContext,
ExtensionContext extensionContext) throws ParameterResolutionException {

// Fall back on the test class annotation in case the method isn't annotated or we're in a @Before/@After method
Optional<Jpa> emfAnnWrapper = AnnotationSupport.findAnnotation(
extensionContext.getRequiredTestClass(),
Jpa.class
);
Object testScope = extensionContext.getRequiredTestInstance();

// coming from a @Test
if (parameterContext.getDeclaringExecutable() instanceof java.lang.reflect.Method && !extensionContext.getTestMethod().isEmpty()) {

Optional<Jpa> testEmfAnnWrapper = AnnotationSupport.findAnnotation(
extensionContext.getRequiredTestMethod(),
Jpa.class
);
// @Jpa on the test, so override the class annotation
if ( !testEmfAnnWrapper.isEmpty() ) {
testScope = extensionContext.getRequiredTestMethod();
emfAnnWrapper = testEmfAnnWrapper;
}
}

final EntityManagerFactoryScope scope = findEntityManagerFactoryScope(
extensionContext.getRequiredTestInstance(),
testScope,
emfAnnWrapper,
extensionContext
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
* @author Steve Ebersole
*/
@Inherited
@Target( ElementType.TYPE )
@Target( {ElementType.TYPE, ElementType.METHOD} )
@Retention( RetentionPolicy.RUNTIME )

@TestInstance( TestInstance.Lifecycle.PER_CLASS )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,4 +33,4 @@ public void testBasicUsage(EntityManagerFactoryScope scope) {
);
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.testing.annotations.methods;

import java.util.Set;

import org.hibernate.dialect.H2Dialect;

import org.hibernate.testing.annotations.AnEntity;
import org.hibernate.testing.annotations.AnotherEntity;
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
import org.hibernate.testing.orm.junit.Jpa;
import org.hibernate.testing.orm.junit.RequiresDialect;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;

import jakarta.persistence.metamodel.EntityType;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

@RequiresDialect(H2Dialect.class)
@Jpa(
annotatedClasses = {
AnEntity.class
}
)
public class EntityManagerFactoryScopeTesting {

@BeforeAll
public void setup(EntityManagerFactoryScope scope) {
scope.inTransaction(
entityManager -> {
AnEntity ae = new AnEntity(1, "AnEntity_1");
entityManager.persist( ae );
}
);
}

@AfterAll
public void tearDown(EntityManagerFactoryScope scope) {
scope.inTransaction(
entityManager -> {
entityManager.createQuery( "delete from AnEntity" ).executeUpdate();
}
);
}

@Test
public void testBasicUsage(EntityManagerFactoryScope scope) {
assertThat( scope, notNullValue() );
assertThat( scope.getEntityManagerFactory(), notNullValue() );
// check we can use the EMF to create EMs
scope.inTransaction(
(session) -> session.createQuery( "select a from AnEntity a" ).getResultList()
);
}

@Test
public void nonAnnotatedMethodTest(EntityManagerFactoryScope scope) {
Set<EntityType<?>> entities = scope.getEntityManagerFactory().getMetamodel().getEntities();
assertEquals( 1, entities.size() );
assertEquals( "AnEntity", entities.iterator().next().getName() );
assertEquals( Boolean.FALSE, scope.getEntityManagerFactory().getProperties().get( "hibernate.jpa.compliance.query" ) );
scope.inEntityManager(
entityManager -> {
AnEntity ae = entityManager.find( AnEntity.class, 1 );
assertNotNull( ae );
assertEquals( 1, ae.getId() );
assertEquals( "AnEntity_1", ae.getName() );
}
);
}

@Jpa(
annotatedClasses = AnotherEntity.class,
queryComplianceEnabled = true
)
@Test
public void annotatedMethodTest(EntityManagerFactoryScope scope) {
assertThat( scope, notNullValue() );
assertThat( scope.getEntityManagerFactory(), notNullValue() );
Set<EntityType<?>> entities = scope.getEntityManagerFactory().getMetamodel().getEntities();
assertEquals( 1, entities.size() );
assertEquals( "AnotherEntity", entities.iterator().next().getName() );
assertEquals( Boolean.TRUE, scope.getEntityManagerFactory().getProperties().get( "hibernate.jpa.compliance.query" ) );
scope.inTransaction(
entityManager -> {
AnotherEntity aoe = new AnotherEntity( 2, "AnotherEntity_1" );
entityManager.persist( aoe );
}
);
scope.inTransaction(
entityManager -> {
AnotherEntity aoe = entityManager.find( AnotherEntity.class, 2 );
assertNotNull( aoe );
assertEquals( 2, aoe.getId() );
assertEquals( "AnotherEntity_1", aoe.getName() );
}
);
Assertions.assertThrows(
IllegalArgumentException.class,
() -> scope.inTransaction(
entityManager -> {
AnEntity ae = entityManager.find( AnEntity.class, 1 );
}
)
);
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.testing.annotations.methods;

import java.util.Set;

import org.hibernate.dialect.H2Dialect;

import org.hibernate.testing.annotations.AnEntity;
import org.hibernate.testing.annotations.AnotherEntity;
import org.hibernate.testing.orm.junit.EntityManagerFactoryScope;
import org.hibernate.testing.orm.junit.Jpa;
import org.hibernate.testing.orm.junit.RequiresDialect;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

import jakarta.persistence.metamodel.EntityType;

import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

@RequiresDialect(H2Dialect.class)
public class MoreEntityManagerFactoryScopeTesting {

@Jpa(
annotatedClasses = {
AnEntity.class
}
)
@Test
public void testBasicUsage(EntityManagerFactoryScope scope) {
assertThat( scope, notNullValue() );
assertThat( scope.getEntityManagerFactory(), notNullValue() );
// check we can use the EMF to create EMs
scope.inTransaction(
(session) -> session.createQuery( "select a from AnEntity a" ).getResultList()
);
}

@Jpa(
annotatedClasses = AnotherEntity.class,
queryComplianceEnabled = true
)
@Test
public void annotatedMethodTest(EntityManagerFactoryScope scope) {
assertThat( scope, notNullValue() );
assertThat( scope.getEntityManagerFactory(), notNullValue() );
Set<EntityType<?>> entities = scope.getEntityManagerFactory().getMetamodel().getEntities();
assertEquals( 1, entities.size() );
assertEquals( "AnotherEntity", entities.iterator().next().getName() );
assertEquals( Boolean.TRUE, scope.getEntityManagerFactory().getProperties().get( "hibernate.jpa.compliance.query" ) );
scope.inTransaction(
entityManager -> {
AnotherEntity aoe = new AnotherEntity( 2, "AnotherEntity_1" );
entityManager.persist( aoe );
}
);
scope.inTransaction(
entityManager -> {
AnotherEntity aoe = entityManager.find( AnotherEntity.class, 2 );
assertNotNull( aoe );
assertEquals( 2, aoe.getId() );
assertEquals( "AnotherEntity_1", aoe.getName() );
}
);
Assertions.assertThrows(
IllegalArgumentException.class,
() -> scope.inTransaction(
entityManager -> {
AnEntity ae = entityManager.find( AnEntity.class, 1 );
}
)
);
}

}

0 comments on commit 454e1cb

Please sign in to comment.