package com.processpuzzle.persistence.domain;
import static org.hamcrest.core.Is.is;
import static org.hamcrest.core.IsEqual.equalTo;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.Iterator;
import java.util.List;
import org.apache.commons.configuration.HierarchicalConfiguration;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import com.processpuzzle.application.configuration.domain.MeasurementContext;
import com.processpuzzle.application.configuration.domain.PersistentDataInitializationStrategies;
import com.processpuzzle.application.configuration.domain.ProcessPuzzleContext;
import com.processpuzzle.application.configuration.domain.PropertyContext;
import com.processpuzzle.application.configuration.domain.PropertyKeys;
import com.processpuzzle.application.domain.Application;
import com.processpuzzle.commons.persistence.PersistentObject;
import com.processpuzzle.commons.persistence.RepositoryResultSet;
import com.processpuzzle.commons.persistence.query.Count;
import com.processpuzzle.fundamental_types.domain.GenericEntity;
import com.processpuzzle.persistence.query.domain.ComparisonOperators;
import com.processpuzzle.persistence.query.domain.DefaultQuery;
import com.processpuzzle.persistence.query.domain.IntegerAttributeCondition;
import com.processpuzzle.sharedfixtures.domaintier.DomainTierTestConfiguration;
import com.processpuzzle.sharedfixtures.domaintier.TestUserRequestFixture;
public class HibernatePersistenceProviderTest {
private static String PERSISTENCE_STRATEGY = DomainTierTestConfiguration.STRATEGY_NAME;
private static String MASTER_PERSISTENCE_PROVIDER = DomainTierTestConfiguration.PERSISTENCE_PROVIDER_NAME;
private static String DATABASE_DRIVER = "org.hsqldb.jdbcDriver";
private static String QUERY_TEST_ENTITY = "SELECT * FROM {0} WHERE ID = {1}";
private static Integer NUMBER_OF_BULK_ENTITITES = 33;
private static Integer COLLECTION_PAGE_SIZE = 10;
private static TestUserRequestFixture userRequestFixture;
private static PropertyContext propertyContext;
private static MeasurementContext measurementContext;
private static HierarchicalConfiguration providerConfiguration;
private static List<Class<?>> persistentClasses = new ArrayList<Class<?>>();
private static Connection databaseConnection = null;
private static ProcessPuzzleContext applicationContext;
private static Application application;
private HibernatePersistenceProvider persistenceProvider = null;
private TestEntity testEntity_1 = null;
private TestEntity testEntity_2 = null;
@BeforeClass
public static void beforeAllTests() {
applicationContext = mock( ProcessPuzzleContext.class );
application = mock( Application.class );
//when( application.getContext() ).thenReturn( applicationContext );
propertyContext = new PropertyContext( application, DomainTierTestConfiguration.APPLICATION_CONFIGURATION_DESCRIPTOR_PATH );
propertyContext.setUp( Application.Action.start );
//when( applicationContext.getPropertyContext() ).thenReturn( propertyContext );
measurementContext = new MeasurementContext( application );
measurementContext.setUp( Application.Action.start );
//when( applicationContext.getMeasurementContext() ).thenReturn( measurementContext );
userRequestFixture = TestUserRequestFixture.getInstance( application );
userRequestFixture.setUp();
Object[] parametersForKey = { PERSISTENCE_STRATEGY, MASTER_PERSISTENCE_PROVIDER };
String configurationAt = PropertyKeys.createKey( PropertyKeys.PERSISTENCE_STRATEGY_EVENT_HANDLER_PROPERTIES.getDefaultKey(), parametersForKey );
providerConfiguration = propertyContext.getConfigurationAt( configurationAt );
persistentClasses.add( TestEntity.class );
persistentClasses.add( TestEntityComponent.class );
persistentClasses.add( GenericEntity.class );
}
@Before
public void beforeEachTests() {
configureHibernatePersistenceProvider();
createJDBCConnection();
saveTestEntities();
}
@Test
public void testConfigure() {
assertTrue( persistenceProvider.isConfigured() );
assertEquals( "configure() sets the properties of hibernate Confifiguration, given in HierarchicalConfiguration. Eg.:",
DATABASE_DRIVER, persistenceProvider.getHibernateConfiguration().getProperty( "hibernate.connection.driver_class" ) );
assertNotNull( "configure() also adds classes which are persited by Hibernate. Eg.:", persistenceProvider.getHibernateConfiguration()
.getClassMapping( TestEntity.class.getName() ) );
assertNotNull( "configure() initializes a Hibernate SessionFactory.", persistenceProvider.getSessionFactory() );
assertFalse( persistenceProvider.getSessionFactory().isClosed() );
}
@Test
public void testConfigure_ForHbm2DdlProperty() {
persistenceProvider = new HibernatePersistenceProvider( "HIBERNATE_PROVIDER", providerConfiguration, persistentClasses,
PersistentDataInitializationStrategies.update );
persistenceProvider.configure();
assertEquals( "We have overriden the 'hibernate.hbm2dd.auto' property to:", PersistentDataInitializationStrategies.update.asString(),
persistenceProvider.getHibernateConfiguration().getProperty( "hibernate.hbm2ddl.auto" ) );
}
@Test
public void testAdd() {
assertNotNull( "Hibernate gives an id to all new persisted objects.", testEntity_1.getId() );
assertEquals( "'TestEntity_1' name field is persited in database.", testEntity_1.getName(), retrieveColumnFromRow( "T_TEST_ENTITY",
testEntity_1.getId(), String.class, "name" ) );
assertEquals( "'testEntity_1' textAttribute is persited in database.", testEntity_1.getTextAttribute(), retrieveColumnFromRow(
"T_TEST_ENTITY", testEntity_1.getId(), String.class, "textAttribute" ) );
assertEquals( "'testEntity_1' numberAttribute is persited in database.", testEntity_1.getNumberAttribute(), retrieveColumnFromRow(
"T_TEST_ENTITY", testEntity_1.getId(), Integer.class, "numberAttribute" ) );
assertEquals( "'testEntity_1' enitiyComponentWithCascade is persisted in database.", testEntity_1.getEnitiyComponentWithCascade()
.getId(), retrieveColumnFromRow( "T_TEST_ENTITY_COMPONENT", testEntity_1.getEnitiyComponentWithCascade().getId(),
Integer.class, "id" ) );
assertEquals(
"'testEntity_1' enitiyComponentWithoutCascade is persisted in database, but note that it was 'added' separately. See: beforeEachTests()",
testEntity_1.getEnitiyComponentWithoutCascade().getId(), retrieveColumnFromRow( "T_TEST_ENTITY_COMPONENT", testEntity_1
.getEnitiyComponentWithoutCascade().getId(), Integer.class, "id" ) );
}
@Test
public void testUpdate() {
DefaultUnitOfWork modifyWork = new DefaultUnitOfWork( true );
modifyTestEntity( testEntity_1, "NewEntityName", "newTextValue", 5311, new GregorianCalendar( 1965, 6, 22 ).getTime() );
testEntity_1.getEnitiyComponentWithCascade().setName( "NewEntityComponentName" );
testEntity_1.getEnitiyComponentWithoutCascade().setName( "NewEntityComponentName" );
modifyWork.start();
persistenceProvider.update( modifyWork, TestEntity.class, testEntity_1 );
modifyWork.finish();
assertEquals( "'testEntity_1' name is chnaged in database.", "NewEntityName", retrieveColumnFromRow( "T_TEST_ENTITY", testEntity_1
.getId(), String.class, "name" ) );
assertEquals( "'testEntity_1' textAttribute is modified in database.", "newTextValue", retrieveColumnFromRow( "T_TEST_ENTITY",
testEntity_1.getId(), String.class, "textAttribute" ) );
assertEquals( "'testEntity_1' numberAttribute is modified in database.", new Integer(5311), retrieveColumnFromRow( "T_TEST_ENTITY", testEntity_1
.getId(), Integer.class, "numberAttribute" ) );
assertEquals( "'testEntity_1' dateAttribute is modified in database.", new GregorianCalendar( 1965, 6, 22 ).getTime(),
retrieveColumnFromRow( "T_TEST_ENTITY", testEntity_1.getId(), Date.class, "dateAttribute" ) );
assertEquals(
"'testEntity_1' enitiyComponentWithCascade is also modified in database.",
"NewEntityComponentName",
retrieveColumnFromRow( "T_TEST_ENTITY_COMPONENT", testEntity_1.getEnitiyComponentWithCascade().getId(), String.class, "name" ) );
assertEquals( "'testEntity_1' enitiyComponentWithoutCascade is NOT modified in database.", "TestEntity_1_Component_2",
retrieveColumnFromRow( "T_TEST_ENTITY_COMPONENT", testEntity_1.getEnitiyComponentWithoutCascade().getId(), String.class,
"name" ) );
}
@Test
public void testDelete() {
TestEntity entityToDelete = createTestEntity( "EntityToDelete" );
DefaultUnitOfWork addWork = new DefaultUnitOfWork( true );
persistenceProvider.add( addWork, TestEntityComponent.class, entityToDelete.getEnitiyComponentWithoutCascade() );
persistenceProvider.add( addWork, TestEntity.class, entityToDelete );
addWork.finish();
Integer id = entityToDelete.getId();
DefaultUnitOfWork deleteWork = new DefaultUnitOfWork( true );
persistenceProvider.delete( deleteWork, TestEntity.class, entityToDelete );
deleteWork.finish();
assertNull( "We can't find 'entityToDelete' in the database.", retrieveColumnFromRow( "T_TEST_ENTITY", id, Integer.class, "id" ) );
assertNotNull( "EntityComponentWithoutCascade remains in the database.", retrieveColumnFromRow( "T_TEST_ENTITY_COMPONENT",
entityToDelete.getEnitiyComponentWithoutCascade().getId(), Integer.class, "id" ) );
}
@Test
public void testFindById() {
DefaultUnitOfWork findWork = new DefaultUnitOfWork( true );
assertNotNull( persistenceProvider.findById( findWork, TestEntity.class, testEntity_1.getId() ) );
assertEquals( testEntity_1, persistenceProvider.findById( findWork, TestEntity.class, testEntity_1.getId() ) );
findWork.finish();
}
@Test public void testFindAll() {
DefaultUnitOfWork findAllWork = new DefaultUnitOfWork( true );
RepositoryResultSet<TestEntity> resultSet = persistenceProvider.findAll( findAllWork, TestEntity.class );
findAllWork.finish();
assertEquals( "The total number of TestEntities is:", 2, resultSet.size() );
}
@Test public void testFindByQuery() {
DefaultQuery query = new DefaultQuery( TestEntity.class );
IntegerAttributeCondition condition = new IntegerAttributeCondition( "numberAttribute", 2007, ComparisonOperators.EQUAL_TO );
query.getQueryCondition().addAttributeCondition( condition );
DefaultUnitOfWork work = new DefaultUnitOfWork( true );
RepositoryResultSet<? extends PersistentObject> resultSet = persistenceProvider.findByQuery( work, query );
work.finish();
assertEquals( "We expect two hits.", 2, resultSet.size() );
assertEquals( "We found:", testEntity_1, resultSet.getEntityAt( 0 ) );
assertEquals( "and:", testEntity_2, resultSet.getEntityAt( 1 ) );
}
@Test public void findByQuery_ShouldConsiderPagingInfo() {
//SETUP:
createAndSaveBulkOfTestEntities();
DefaultQuery query = new DefaultQuery( TestEntity.class );
query.setFirstResult( 5 );
query.setMaxResults( COLLECTION_PAGE_SIZE );
//EXCERCISE:
DefaultUnitOfWork work = new DefaultUnitOfWork( true );
RepositoryResultSet<? extends PersistentObject> resultSet = persistenceProvider.findByQuery( work, query );
work.finish();
//VERIFY:
assertThat( resultSet.size(), equalTo( COLLECTION_PAGE_SIZE ));
assertThat( ((TestEntity) resultSet.getEntityAt( 0 )).getName().contains( "4" ), is( true ) );
}
@Test public void findByQuery_ShouldAccepCountFunction() {
//SETUP:
createAndSaveBulkOfTestEntities();
DefaultQuery query = new DefaultQuery( TestEntity.class );
query.getAttributeFilter().addAggregateFunction( new Count( "name" ));
//EXCERCISE:
DefaultUnitOfWork work = new DefaultUnitOfWork( true );
RepositoryResultSet<? extends PersistentObject> resultSet = persistenceProvider.findByQuery( work, query );
work.finish();
//VERIFY:
Long count = ((PersistentLong) resultSet.getEntityAt( 0 )).getValue();
assertThat( count.intValue(), equalTo( NUMBER_OF_BULK_ENTITITES + 2) );
}
@Test
public void testTransactionHandling() {
DefaultUnitOfWork updateWork = new DefaultUnitOfWork( true );
TestEntity entity = (TestEntity) persistenceProvider.findById( updateWork, TestEntity.class, testEntity_1.getId() );
entity.rename( "a new name" );
persistenceProvider.update( updateWork, TestEntity.class, entity );
updateWork.discard();
DefaultUnitOfWork newWork = new DefaultUnitOfWork( true );
entity = (TestEntity) persistenceProvider.findById( newWork, TestEntity.class, testEntity_1.getId() );
newWork.finish();
assertEquals( "New was not saved, the name remains as before 'updateWork'.", testEntity_1.getName(), entity.getName() );
}
@Test
public void testGetDriverClass_ForSuccess() {
String expectedDriverClass = providerConfiguration.getString( "hibernate/connection/driver_class" );
assertThat( persistenceProvider.getDriverClass(), equalTo( expectedDriverClass ) );
}
@After
public void afterEachTests() {
DefaultUnitOfWork deletion = new DefaultUnitOfWork( false );
deletion.start();
persistenceProvider.delete( deletion, TestEntity.class, testEntity_1 );
deletion.finish();
persistenceProvider = null;
}
@AfterClass
public static void afterAllTests() {
propertyContext.tearDown( Application.Action.stop );
}
// Private helper methods
private void configureHibernatePersistenceProvider() {
persistenceProvider = new HibernatePersistenceProvider( "HIBERNATE_PROVIDER", providerConfiguration, persistentClasses,
PersistentDataInitializationStrategies.dropAndCreate );
persistenceProvider.configure();
}
private void createAndSaveBulkOfTestEntities() {
String entityBaseName = "BulkTestEntity_";
DefaultUnitOfWork setUpWork = new DefaultUnitOfWork( true );
for( int i = 1; i <= NUMBER_OF_BULK_ENTITITES; i++ ){
String entityName = entityBaseName + new Integer( i ).toString();
TestEntity testEntity = new TestEntity( entityName );
persistenceProvider.add( setUpWork, TestEntity.class, testEntity );
}
setUpWork.finish();
}
private void createJDBCConnection() {
String driverClass = persistenceProvider.getDriverClass();
String connectionUrl = persistenceProvider.getConnectionUrl();
String user = persistenceProvider.getUserName();
String password = persistenceProvider.getPassword();
try{
Class.forName( driverClass );
databaseConnection = DriverManager.getConnection( connectionUrl, user, password );
}catch( SQLException e ){
// TODO Auto-generated catch block
e.printStackTrace();
}catch( ClassNotFoundException e ){
// TODO Auto-generated catch block
e.printStackTrace();
}
}
private void saveTestEntities() {
testEntity_1 = createTestEntity( "TestEntity_1" );
testEntity_2 = createTestEntity( "TestEntity_2" );
DefaultUnitOfWork setUpWork = new DefaultUnitOfWork( false );
setUpWork.start();
persistenceProvider.add( setUpWork, TestEntityComponent.class, testEntity_1.getEnitiyComponentWithoutCascade() );
persistenceProvider.add( setUpWork, TestEntity.class, testEntity_1 );
persistenceProvider.add( setUpWork, TestEntityComponent.class, testEntity_2.getEnitiyComponentWithoutCascade() );
persistenceProvider.add( setUpWork, TestEntity.class, testEntity_2 );
setUpWork.finish();
}
@SuppressWarnings("unchecked")
private <D> D retrieveColumnFromRow( String table, Integer id, Class<D> dataType, String columnName ) {
ResultSet resultSet = null;
try{
Statement statement = databaseConnection.createStatement();
String queryStatement = MessageFormat.format( QUERY_TEST_ENTITY, new Object[] { table, id.toString() } );
resultSet = statement.executeQuery( queryStatement );
resultSet.next();
switch( com.processpuzzle.commons.rdbms.DatabaseSpy.DataType.getTypeIndex( dataType )) {
case DATE:
return (D) resultSet.getDate( columnName );
case INTEGER:
return (D) new Integer( resultSet.getInt( columnName ) );
case STRING:
return (D) resultSet.getString( columnName );
default:
return (D) resultSet.getString( columnName );
}
}catch( SQLException e ){
return null;
}
}
private TestEntity createTestEntity( String name ) {
TestEntity testEntity = new TestEntity( name );
testEntity.setDateAttribute( new GregorianCalendar( 1960, 12, 9 ).getTime() );
testEntity.setNumberAttribute( 2007 );
testEntity.setTextAttribute( "any text" );
testEntity.setEnitiyComponentWithCascade( new TestEntityComponent( "TestEntity_1_Component_1" ) );
testEntity.setEnitiyComponentWithoutCascade( new TestEntityComponent( "TestEntity_1_Component_2" ) );
testEntity.addComponent( new TestEntityComponent( "bulk_1" ) );
testEntity.addComponent( new TestEntityComponent( "bulk_2" ) );
return testEntity;
}
private void modifyTestEntity( TestEntity testEntity, String name, String text, Integer number, Date date ) {
testEntity.rename( name );
testEntity.setTextAttribute( text );
testEntity.setNumberAttribute( number );
testEntity.setDateAttribute( date );
}
@SuppressWarnings( { "unused", "unchecked" } )
private static void printPropertyContext() {
for( Iterator<String> iter = propertyContext.getConfiguration().getKeys(); iter.hasNext(); ){
String key = (String) iter.next();
System.err.println( key + " = " + propertyContext.getProperty( key ) );
}
}
}