package org.qi4j.test.performance.entitystore.model;
import org.junit.Before;
import org.junit.Test;
import org.qi4j.api.structure.Application;
import org.qi4j.api.structure.Module;
import org.qi4j.api.unitofwork.UnitOfWork;
import org.qi4j.api.unitofwork.UnitOfWorkCompletionException;
import org.qi4j.api.unitofwork.UnitOfWorkFactory;
import org.qi4j.bootstrap.*;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.Random;
import java.util.logging.Logger;
/**
* Performance Test Suite for Entity Stores.
*/
public abstract class AbstractEntityStorePerformanceTest
{
private Application application;
private UnitOfWorkFactory unitOfWorkFactory;
private String storeName;
private Assembler infrastructure;
private int ITERATIONS = 20000;
protected AbstractEntityStorePerformanceTest( String storeName, Assembler infrastructure )
{
this.storeName = storeName;
this.infrastructure = infrastructure;
}
@Before
public void warmup()
throws Exception
{
Assembler assembler = new Assembler()
{
public void assemble( ModuleAssembly module )
throws AssemblyException
{
module.entities( SimpleProduct.class );
}
};
createQi4jRuntime( assembler );
for( int i = 0; i < 10000; i++ )
{
UnitOfWork uow = unitOfWorkFactory.newUnitOfWork();
SimpleProduct product = uow.newEntity( SimpleProduct.class );
String id = product.identity().get();
uow.discard();
}
}
@Test
public void whenCreateEntityWithSinglePropertyThenRecordIterationsPerSecond()
throws Exception
{
try
{
Assembler assembler = new Assembler()
{
public void assemble( ModuleAssembly module )
throws AssemblyException
{
module.entities( SimpleProduct.class );
}
};
createQi4jRuntime( assembler );
profile( new Runnable()
{
public void run()
{
try
{
Report report = new Report( storeName );
report.start( "createEntityWithSingleProperty" );
for( int i = 0; i < ITERATIONS; i++ )
{
UnitOfWork uow = unitOfWorkFactory.newUnitOfWork();
SimpleProduct product = uow.newEntity( SimpleProduct.class );
String id = product.identity().get();
uow.complete();
if( i % 1000 == 0 )
{
Logger.getLogger( getClass().getName() ).info( "Iteration:" + i );
}
}
report.stop( ITERATIONS );
writeReport( report );
}
catch( UnitOfWorkCompletionException e )
{
e.printStackTrace();
}
catch( IOException e )
{
e.printStackTrace();
}
}
} );
}
finally
{
cleanUp();
}
}
@Test
public void whenCreateEntityWithSinglePropertyInBatchThenRecordIterationsPerSecond()
throws Exception
{
try
{
Assembler assembler = new Assembler()
{
public void assemble( ModuleAssembly module )
throws AssemblyException
{
module.entities( SimpleProduct.class );
}
};
createQi4jRuntime( assembler );
profile( new Runnable()
{
public void run()
{
try
{
Report report = new Report( storeName );
report.start( "createEntityInBulkWithSingleProperty" );
UnitOfWork uow = unitOfWorkFactory.newUnitOfWork();
for( int i = 0; i < ITERATIONS; i++ )
{
SimpleProduct product = uow.newEntity( SimpleProduct.class );
String id = product.identity().get();
if( i % 1000 == 0 )
{
uow.complete();
uow = unitOfWorkFactory.newUnitOfWork();
}
}
uow.complete();
report.stop( ITERATIONS );
writeReport( report );
}
catch( UnitOfWorkCompletionException e )
{
e.printStackTrace();
}
catch( IOException e )
{
e.printStackTrace();
}
}
} );
}
finally
{
cleanUp();
}
}
@Test
public void whenCreateEntityWithComplexTypeThenRecordIterationsPerSecond()
throws Exception
{
try
{
Assembler assembler = new Assembler()
{
public void assemble( ModuleAssembly module )
throws AssemblyException
{
module.entities( ComplexProduct.class );
}
};
createQi4jRuntime( assembler );
profile( new Runnable()
{
public void run()
{
try
{
Report report = new Report( storeName );
report.start( "createEntityWithComplexType" );
for( int i = 0; i < ITERATIONS; i++ )
{
UnitOfWork uow = unitOfWorkFactory.newUnitOfWork();
ComplexProduct product = uow.newEntity( ComplexProduct.class );
String id = product.identity().get();
uow.complete();
}
report.stop( ITERATIONS );
writeReport( report );
}
catch( UnitOfWorkCompletionException e )
{
e.printStackTrace();
}
catch( IOException e )
{
e.printStackTrace();
}
}
} );
}
finally
{
cleanUp();
}
}
@Test
public void whenCreateEntityWithComplexTypeInBatchThenRecordIterationsPerSecond()
throws Exception
{
try
{
Assembler assembler = new Assembler()
{
public void assemble( ModuleAssembly module )
throws AssemblyException
{
module.entities( ComplexProduct.class );
}
};
createQi4jRuntime( assembler );
profile( new Runnable()
{
public void run()
{
try
{
Report report = new Report( storeName );
report.start( "createEntityInBulkWithComplexType" );
UnitOfWork uow = unitOfWorkFactory.newUnitOfWork();
for( int i = 0; i < ITERATIONS; i++ )
{
ComplexProduct product = uow.newEntity( ComplexProduct.class );
String id = product.identity().get();
if( i % 1000 == 0 )
{
uow.complete();
uow = unitOfWorkFactory.newUnitOfWork();
}
}
uow.complete();
report.stop( ITERATIONS );
writeReport( report );
}
catch( UnitOfWorkCompletionException e )
{
e.printStackTrace();
}
catch( IOException e )
{
e.printStackTrace();
}
}
} );
}
finally
{
cleanUp();
}
}
@Test
public void whenReadEntityWithComplexTypeThenRecordIterationsPerSecond()
throws Exception
{
try
{
Assembler assembler = new Assembler()
{
public void assemble( ModuleAssembly module )
throws AssemblyException
{
module.entities( ComplexProduct.class );
}
};
createQi4jRuntime( assembler );
{
UnitOfWork uow = unitOfWorkFactory.newUnitOfWork();
for( int i = 0; i < ITERATIONS; i++ )
{
ComplexProduct product = uow.newEntity( ComplexProduct.class, "product" + i );
product.name().set( "Product " + i );
if( i % 1000 == 0 )
{
uow.complete();
uow = unitOfWorkFactory.newUnitOfWork();
}
}
uow.complete();
}
profile( new Runnable()
{
public void run()
{
try
{
Report report = new Report( storeName );
UnitOfWork uow = unitOfWorkFactory.newUnitOfWork();
Random rnd = new Random();
report.start( "readEntityWithComplexType" );
String id = rnd.nextInt( ITERATIONS ) + "";
for( int i = 0; i < ITERATIONS; i++ )
{
ComplexProduct product = uow.get( ComplexProduct.class, "product" + id );
String name = product.name().get();
if( i % 100 == 0 )
{
uow.discard();
uow = unitOfWorkFactory.newUnitOfWork();
}
}
uow.complete();
report.stop( ITERATIONS );
writeReport( report );
}
catch( UnitOfWorkCompletionException e )
{
e.printStackTrace();
}
catch( IOException e )
{
e.printStackTrace();
}
}
} );
}
finally
{
cleanUp();
}
}
// If you want to profile this test, then tell profiler to only check
// below this method call
private void profile( Runnable runnable )
{
runnable.run();
}
private void writeReport( Report report )
throws IOException
{
File dir = new File( "target/perf-result/" );
dir.mkdirs();
String name = dir.getAbsolutePath() + "/result-" + report.name() + ".xml";
FileWriter writer = new FileWriter( name, true );
BufferedWriter out = new BufferedWriter( writer );
report.writeTo( out );
out.flush();
out.close();
System.out.println( "Report written to " + name );
}
private void createQi4jRuntime( Assembler testSetup )
throws Exception
{
Energy4Java qi4j = new Energy4Java();
Assembler[][][] assemblers = new Assembler[][][]
{
{
{ infrastructure, testSetup }
}
};
application = qi4j.newApplication( new ApplicationAssemblerAdapter( assemblers )
{
} );
application.activate();
Module moduleInstance = application.findModule( "Layer 1", "Module 1" );
unitOfWorkFactory = moduleInstance;
}
protected void cleanUp()
throws Exception
{
if( unitOfWorkFactory != null && unitOfWorkFactory.isUnitOfWorkActive())
{
UnitOfWork current;
while( unitOfWorkFactory.isUnitOfWorkActive() && ( current = unitOfWorkFactory.currentUnitOfWork() ) != null )
{
if( current.isOpen() )
{
current.discard();
}
else
{
throw new InternalError( "I have seen a case where a UoW is on the stack, but not opened." );
}
}
new Exception( "UnitOfWork not properly cleaned up" ).printStackTrace();
}
if( application != null )
{
application.passivate();
}
}
}