Game updates improvements
* Added a set of tables which define game updates and their targets. These definitions replace the old enumerate type. Added a set of triggers which automatically create specific update tables, insert missing entries, etc... when game update types are being manipulated. * Removed manual insertion of game updates from empire creation function and universe generator. * Added registration of core update targets (i.e. planets and empires), updated all existing game update processing functions and added type registrations * Created Maven project for game updates control components, moved existing components from the -simple project, rewritten most of what they contained, added new components for server-side update batch processing
This commit is contained in:
parent
ba6a1e2b41
commit
56eddcc4f0
93 changed files with 4004 additions and 578 deletions
legacyworlds-server-tests/src/test/java/com/deepclone/lw
|
@ -0,0 +1,62 @@
|
|||
package com.deepclone.lw.beans.updates;
|
||||
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
|
||||
import com.deepclone.lw.interfaces.game.updates.UpdateBatchProcessor;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A dummy batch processor used in game update tests
|
||||
*
|
||||
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
|
||||
*/
|
||||
class DummyBatchProcessor
|
||||
implements UpdateBatchProcessor
|
||||
{
|
||||
/** The name that will be returned by {@link #getUpdateType()} */
|
||||
private final String updateType;
|
||||
|
||||
/** Ticks for which the {@link #processBatch(long)} was called */
|
||||
private final HashSet< Long > ticks = new HashSet< Long >( );
|
||||
|
||||
|
||||
/**
|
||||
* Set the update type
|
||||
*
|
||||
* @param updateType
|
||||
* the update type
|
||||
*/
|
||||
public DummyBatchProcessor( String updateType )
|
||||
{
|
||||
this.updateType = updateType;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return whatever type name was set when the instance was created
|
||||
*/
|
||||
@Override
|
||||
public String getUpdateType( )
|
||||
{
|
||||
return this.updateType;
|
||||
}
|
||||
|
||||
|
||||
/** Adds the specified tick identifier to the set of ticks */
|
||||
@Override
|
||||
public void processBatch( long tickId )
|
||||
{
|
||||
this.ticks.add( tickId );
|
||||
}
|
||||
|
||||
|
||||
/** @return the set of ticks for which {@link #processBatch(long)} was called */
|
||||
Collection< Long > getTicks( )
|
||||
{
|
||||
return this.ticks;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
package com.deepclone.lw.beans.updates;
|
||||
|
||||
|
||||
import com.deepclone.lw.interfaces.game.updates.GameUpdateProcessor;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A mock game update processor
|
||||
*
|
||||
* <p>
|
||||
* This mock component keeps track of which of its methods have been called. It can also simulate
|
||||
* runtime errors during tick processing.
|
||||
*
|
||||
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
|
||||
*
|
||||
*/
|
||||
public class MockGameUpdateProcessor
|
||||
implements GameUpdateProcessor
|
||||
{
|
||||
private boolean tryLockCalled = false;
|
||||
private boolean unlockCalled = false;
|
||||
private boolean endCycleCalled = false;
|
||||
private boolean executeCalled = false;
|
||||
|
||||
private boolean failExecute = false;
|
||||
|
||||
|
||||
public boolean wasTryLockCalled( )
|
||||
{
|
||||
return this.tryLockCalled;
|
||||
}
|
||||
|
||||
|
||||
public boolean wasUnlockCalled( )
|
||||
{
|
||||
return this.unlockCalled;
|
||||
}
|
||||
|
||||
|
||||
public boolean wasEndCycleCalled( )
|
||||
{
|
||||
return this.endCycleCalled;
|
||||
}
|
||||
|
||||
|
||||
public boolean wasExecuteCalled( )
|
||||
{
|
||||
return this.executeCalled;
|
||||
}
|
||||
|
||||
|
||||
public void setFailExecute( boolean failExecute )
|
||||
{
|
||||
this.failExecute = failExecute;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean tryLock( )
|
||||
{
|
||||
this.tryLockCalled = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void unlock( )
|
||||
{
|
||||
this.unlockCalled = true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean endPreviousCycle( )
|
||||
{
|
||||
this.endCycleCalled = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void executeUpdateCycle( )
|
||||
{
|
||||
this.executeCalled = true;
|
||||
if ( this.failExecute ) {
|
||||
throw new RuntimeException( "fail" );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package com.deepclone.lw.beans.updates;
|
||||
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import com.deepclone.lw.interfaces.game.updates.UpdateBatchProcessor;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A mock processor registry
|
||||
*
|
||||
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
|
||||
*/
|
||||
class MockRegistry
|
||||
implements ServerProcessorRegistry
|
||||
{
|
||||
|
||||
/** The map of "processors" to return */
|
||||
private final HashMap< String , UpdateBatchProcessor > processors = new HashMap< String , UpdateBatchProcessor >( );
|
||||
|
||||
|
||||
/**
|
||||
* Add a processor to the registry
|
||||
*
|
||||
* @param processor
|
||||
* the processor to add
|
||||
*/
|
||||
public void put( UpdateBatchProcessor processor )
|
||||
{
|
||||
this.processors.put( processor.getUpdateType( ) , processor );
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public UpdateBatchProcessor getProcessorFor( String type )
|
||||
{
|
||||
return this.processors.get( type );
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package com.deepclone.lw.beans.updates;
|
||||
|
||||
|
||||
import com.deepclone.lw.interfaces.game.updates.UpdatesDAO;
|
||||
import com.deepclone.lw.sqld.sys.GameUpdateResult;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Mock updates DAO used in tests
|
||||
*
|
||||
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
|
||||
*/
|
||||
class MockUpdatesDAO
|
||||
implements UpdatesDAO
|
||||
{
|
||||
/** The index to read at the next call to {@link #processUpdates(long)} */
|
||||
public int index = 0;
|
||||
|
||||
/** The values to return as the update type to process */
|
||||
public String[] values = new String[] { };
|
||||
|
||||
|
||||
@Override
|
||||
public GameUpdateResult processUpdates( long tickId )
|
||||
{
|
||||
if ( this.index >= this.values.length ) {
|
||||
return new GameUpdateResult( );
|
||||
}
|
||||
return new GameUpdateResult( this.values[ this.index++ ] );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,240 @@
|
|||
package com.deepclone.lw.beans.updates;
|
||||
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.sql.Timestamp;
|
||||
import java.util.Date;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.deepclone.lw.interfaces.game.updates.UpdateBatchProcessor;
|
||||
import com.deepclone.lw.interfaces.sys.MaintenanceData;
|
||||
import com.deepclone.lw.testing.MockLogger;
|
||||
import com.deepclone.lw.testing.MockSystemStatus;
|
||||
import com.deepclone.lw.testing.MockTransactionManager;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Tests for {@link GameUpdateProcessorBean}
|
||||
*
|
||||
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
|
||||
*/
|
||||
public class TestGameUpdateProcessorBean
|
||||
{
|
||||
|
||||
/** The mock logger */
|
||||
private MockLogger logger;
|
||||
|
||||
/** Mock updates access interface */
|
||||
private MockUpdatesDAO updatesDAO;
|
||||
|
||||
/** Mock processor registry */
|
||||
private MockRegistry registry;
|
||||
|
||||
/** Mock system status component */
|
||||
private MockSystemStatus system;
|
||||
|
||||
/** The instance under test */
|
||||
private GameUpdateProcessorBean gup;
|
||||
|
||||
/**
|
||||
* A fake batch processor which actually enables maintenance mode.
|
||||
*
|
||||
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
|
||||
*/
|
||||
private static class MaintenanceEnabler
|
||||
implements UpdateBatchProcessor
|
||||
{
|
||||
|
||||
/** Mock system status component */
|
||||
private MockSystemStatus system;
|
||||
|
||||
|
||||
/**
|
||||
* Set the mock system status component
|
||||
*
|
||||
* @param system
|
||||
* the mock system status component
|
||||
*/
|
||||
MaintenanceEnabler( MockSystemStatus system )
|
||||
{
|
||||
this.system = system;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getUpdateType( )
|
||||
{
|
||||
return "maintenance";
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void processBatch( long tickId )
|
||||
{
|
||||
this.system.setMaintenance( new MaintenanceData( new Timestamp( new Date( ).getTime( ) ) , new Timestamp(
|
||||
new Date( ).getTime( ) ) , "no reason" ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp( )
|
||||
{
|
||||
this.logger = new MockLogger( );
|
||||
this.updatesDAO = new MockUpdatesDAO( );
|
||||
this.updatesDAO.values = new String[] {
|
||||
null
|
||||
};
|
||||
this.system = new MockSystemStatus( );
|
||||
this.registry = new MockRegistry( );
|
||||
this.registry.put( new MaintenanceEnabler( this.system ) );
|
||||
|
||||
this.gup = new GameUpdateProcessorBean( );
|
||||
this.gup.setLogger( this.logger );
|
||||
this.gup.setUpdatesDAO( this.updatesDAO );
|
||||
this.gup.setRegistry( this.registry );
|
||||
this.gup.setTransactionManager( new MockTransactionManager( ) );
|
||||
this.gup.setSystemStatus( this.system );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Try locking the processor
|
||||
*/
|
||||
@Test
|
||||
public void testLocking( )
|
||||
{
|
||||
assertTrue( this.gup.tryLock( ) );
|
||||
assertFalse( this.gup.tryLock( ) );
|
||||
}
|
||||
|
||||
|
||||
/** Try unlocking the processor */
|
||||
@Test
|
||||
public void testUnlocking( )
|
||||
{
|
||||
this.gup.tryLock( );
|
||||
this.gup.unlock( );
|
||||
assertTrue( this.gup.tryLock( ) );
|
||||
}
|
||||
|
||||
|
||||
/** Try unlocking the processor when it's not locked */
|
||||
@Test( expected = IllegalStateException.class )
|
||||
public void testUnlockingWithNoLock( )
|
||||
{
|
||||
this.gup.unlock( );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@link GameUpdateProcessorBean#endPreviousCycle()} returns <code>false</code> when there is
|
||||
* no "stuck" tick
|
||||
*/
|
||||
@Test
|
||||
public void testEndCycleNoStuckTick( )
|
||||
{
|
||||
assertFalse( this.gup.endPreviousCycle( ) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@link GameUpdateProcessorBean#endPreviousCycle()} returns <code>true</code> when maintenance
|
||||
* mode is enabled, but the update is not processed
|
||||
*/
|
||||
@Test
|
||||
public void testEndCycleMaintenance( )
|
||||
{
|
||||
this.system.setCSTBehaviour( -2 );
|
||||
assertTrue( this.gup.endPreviousCycle( ) );
|
||||
assertEquals( 0 , this.updatesDAO.index );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@link GameUpdateProcessorBean#endPreviousCycle()} returns <code>true</code> when there is a
|
||||
* stuck tick, and the update is processed
|
||||
*/
|
||||
@Test
|
||||
public void testEndCycle( )
|
||||
{
|
||||
this.system.setCSTBehaviour( 0 );
|
||||
assertTrue( this.gup.endPreviousCycle( ) );
|
||||
assertEquals( 1 , this.updatesDAO.index );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@link GameUpdateProcessorBean#executeUpdateCycle()} does not start a tick if there was a
|
||||
* stuck tick, but the previous tick is processed.
|
||||
*/
|
||||
@Test
|
||||
public void testProcessWithStuckTick( )
|
||||
{
|
||||
this.system.setCSTBehaviour( 0 );
|
||||
this.gup.executeUpdateCycle( );
|
||||
assertFalse( this.system.wasStartTickCalled( ) );
|
||||
assertEquals( 1 , this.updatesDAO.index );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@link GameUpdateProcessorBean#executeUpdateCycle()} does not start a tick if maintenance
|
||||
* mode was enabled from the start
|
||||
*/
|
||||
@Test
|
||||
public void testProcessWithStuckTickAndMaintenance( )
|
||||
{
|
||||
this.system.setCSTBehaviour( -2 );
|
||||
this.gup.executeUpdateCycle( );
|
||||
assertFalse( this.system.wasStartTickCalled( ) );
|
||||
assertEquals( 0 , this.updatesDAO.index );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@link GameUpdateProcessorBean#executeUpdateCycle()} does not start a tick if maintenance
|
||||
* mode is enabled between the check for stuck ticks and the new tick's start.
|
||||
*/
|
||||
@Test
|
||||
public void testProcessWithMaintenance( )
|
||||
{
|
||||
this.system.setSTBehaviour( -2 );
|
||||
this.gup.executeUpdateCycle( );
|
||||
assertTrue( this.system.wasStartTickCalled( ) );
|
||||
assertEquals( 0 , this.updatesDAO.index );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@link GameUpdateProcessorBean#executeUpdateCycle()} throws a runtime exception if there
|
||||
* seems to be a tick running when the new tick is supposed to start.
|
||||
*/
|
||||
@Test( expected = RuntimeException.class )
|
||||
public void testProcessWithBadState( )
|
||||
{
|
||||
this.system.setSTBehaviour( -1 );
|
||||
this.gup.executeUpdateCycle( );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* {@link GameUpdateProcessorBean#executeUpdateCycle()} stops processing mid-way if maintenance
|
||||
* mode becomes enabled
|
||||
*/
|
||||
@Test
|
||||
public void testProcessWithMaintenanceEnabledMidWay( )
|
||||
{
|
||||
this.updatesDAO.values = new String[] {
|
||||
null , "maintenance" , null
|
||||
};
|
||||
this.gup.executeUpdateCycle( );
|
||||
assertTrue( this.system.wasStartTickCalled( ) );
|
||||
assertEquals( 2 , this.updatesDAO.index );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
package com.deepclone.lw.beans.updates;
|
||||
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import com.deepclone.lw.interfaces.sys.Ticker.Frequency;
|
||||
import com.deepclone.lw.testing.MockTicker;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Tests for {@link GameUpdateTaskBean}
|
||||
*
|
||||
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
|
||||
*/
|
||||
public class TestGameUpdateTaskBean
|
||||
{
|
||||
/** The mock ticker */
|
||||
private MockTicker ticker;
|
||||
|
||||
/** The mock game update processor */
|
||||
private MockGameUpdateProcessor processor;
|
||||
|
||||
/** The game update task */
|
||||
private GameUpdateTaskBean gut;
|
||||
|
||||
|
||||
/**
|
||||
* Initialise the mock components and the game update task instance
|
||||
*/
|
||||
@Before
|
||||
public void setUp( )
|
||||
{
|
||||
this.ticker = new MockTicker( Frequency.MINUTE , "Game update" , GameUpdateTaskBean.class );
|
||||
this.processor = new MockGameUpdateProcessor( );
|
||||
|
||||
this.gut = new GameUpdateTaskBean( );
|
||||
this.gut.setTicker( this.ticker );
|
||||
this.gut.setGameUpdateProcessor( this.processor );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check the component's initialisation
|
||||
*/
|
||||
@Test
|
||||
public void testInitialisation( )
|
||||
{
|
||||
this.gut.afterPropertiesSet( );
|
||||
assertTrue( this.processor.wasTryLockCalled( ) );
|
||||
assertTrue( this.processor.wasUnlockCalled( ) );
|
||||
assertTrue( this.processor.wasEndCycleCalled( ) );
|
||||
assertFalse( this.processor.wasExecuteCalled( ) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check the component's run() method
|
||||
*/
|
||||
@Test
|
||||
public void testNormalRun( )
|
||||
{
|
||||
this.gut.run( );
|
||||
assertTrue( this.processor.wasTryLockCalled( ) );
|
||||
assertTrue( this.processor.wasUnlockCalled( ) );
|
||||
assertFalse( this.processor.wasEndCycleCalled( ) );
|
||||
assertTrue( this.processor.wasExecuteCalled( ) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Make sure the component is unlocked even if the execution fails
|
||||
*/
|
||||
@Test
|
||||
public void testFailedRun( )
|
||||
{
|
||||
this.processor.setFailExecute( true );
|
||||
try {
|
||||
this.gut.run( );
|
||||
fail( "Mock processor failed to fail" );
|
||||
} catch ( RuntimeException e ) {
|
||||
// EMPTY
|
||||
}
|
||||
assertTrue( this.processor.wasTryLockCalled( ) );
|
||||
assertTrue( this.processor.wasUnlockCalled( ) );
|
||||
assertFalse( this.processor.wasEndCycleCalled( ) );
|
||||
assertTrue( this.processor.wasExecuteCalled( ) );
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
package com.deepclone.lw.beans.updates;
|
||||
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Tests for {@link GameUpdateTransaction}
|
||||
*
|
||||
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
|
||||
*/
|
||||
public class TestGameUpdateTransaction
|
||||
{
|
||||
|
||||
/** The mock updates DAO */
|
||||
private MockUpdatesDAO updatesDAO;
|
||||
|
||||
/** The dummy batch processor used in the tests */
|
||||
private DummyBatchProcessor processor;
|
||||
|
||||
/** The mock processor registry */
|
||||
private MockRegistry registry;
|
||||
|
||||
/** The game update transaction used as a "guinea pig" */
|
||||
private GameUpdateTransaction transaction;
|
||||
|
||||
|
||||
/** Set up the mock objects and the guinea pig transaction instance */
|
||||
@Before
|
||||
public void setUp( )
|
||||
{
|
||||
this.updatesDAO = new MockUpdatesDAO( );
|
||||
this.registry = new MockRegistry( );
|
||||
this.registry.put( this.processor = new DummyBatchProcessor( "test" ) );
|
||||
this.transaction = new GameUpdateTransaction( this.updatesDAO , this.registry , 1 );
|
||||
}
|
||||
|
||||
|
||||
/** Test return value when the stored procedure says that no more updates are to be processed */
|
||||
@Test
|
||||
public void testWhenFinished( )
|
||||
{
|
||||
assertTrue( this.transaction.doInTransaction( null ) );
|
||||
}
|
||||
|
||||
|
||||
/** Test return value when the stored procedure says that more updates are to be processed */
|
||||
@Test
|
||||
public void testWhenHasMore( )
|
||||
{
|
||||
this.updatesDAO.values = new String[] {
|
||||
null
|
||||
};
|
||||
assertFalse( this.transaction.doInTransaction( null ) );
|
||||
}
|
||||
|
||||
|
||||
/** Test what happens when the stored procedure indicates the need for local processing */
|
||||
@Test
|
||||
public void testLocalProcessing( )
|
||||
{
|
||||
this.updatesDAO.values = new String[] {
|
||||
"test"
|
||||
};
|
||||
assertFalse( this.transaction.doInTransaction( null ) );
|
||||
assertEquals( 1 , this.processor.getTicks( ).size( ) );
|
||||
assertTrue( this.processor.getTicks( ).contains( 1L ) );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Test what happens when the stored procedure indicates the need for local processing but the
|
||||
* specified processor does not exist
|
||||
*/
|
||||
@Test( expected = UnsupportedUpdateException.class )
|
||||
public void testMissingProcessor( )
|
||||
{
|
||||
this.updatesDAO.values = new String[] {
|
||||
"missing processor"
|
||||
};
|
||||
this.transaction.doInTransaction( null );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package com.deepclone.lw.beans.updates;
|
||||
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.BeanInitializationException;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Tests for {@link ServerProcessorRegistryBean}
|
||||
*
|
||||
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
|
||||
*/
|
||||
public class TestServerProcessorRegistryBean
|
||||
{
|
||||
/** The "guinea pig" instance */
|
||||
private ServerProcessorRegistryBean registry;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp( )
|
||||
{
|
||||
this.registry = new ServerProcessorRegistryBean( );
|
||||
this.registry.postProcessAfterInitialization( new DummyBatchProcessor( "test" ) , "test" );
|
||||
}
|
||||
|
||||
|
||||
/** The registry returns <code>null</code> when the type has no processor */
|
||||
@Test
|
||||
public void testMissingReturnsNull( )
|
||||
{
|
||||
assertNull( this.registry.getProcessorFor( "does not exist" ) );
|
||||
}
|
||||
|
||||
|
||||
/** The registry returns the processor when there is one */
|
||||
@Test
|
||||
public void testExistingReturnsProcessor( )
|
||||
{
|
||||
assertNotNull( this.registry.getProcessorFor( "test" ) );
|
||||
}
|
||||
|
||||
|
||||
/** The registry ignores objects which are not batch processors */
|
||||
@Test
|
||||
public void testIgnoresOtherObjects( )
|
||||
{
|
||||
this.registry.postProcessAfterInitialization( "test" , "test" );
|
||||
}
|
||||
|
||||
|
||||
/** The registry crashes when two batch processors are defined for the same type */
|
||||
@Test( expected = BeanInitializationException.class )
|
||||
public void testFailsIfDuplicate( )
|
||||
{
|
||||
this.registry.postProcessAfterInitialization( new DummyBatchProcessor( "test" ) , "test" );
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package com.deepclone.lw.testing;
|
||||
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
import com.deepclone.lw.interfaces.eventlog.Logger;
|
||||
import com.deepclone.lw.interfaces.eventlog.SystemLogger;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A mock Logger component
|
||||
*
|
||||
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
|
||||
*
|
||||
*/
|
||||
public class MockLogger
|
||||
implements Logger
|
||||
{
|
||||
/** Map of existing system loggers */
|
||||
private final HashMap< String , MockSystemLogger > loggers = new HashMap< String , MockSystemLogger >( );
|
||||
|
||||
|
||||
@Override
|
||||
public SystemLogger getSystemLogger( String component )
|
||||
{
|
||||
MockSystemLogger logger = this.loggers.get( component );
|
||||
if ( logger == null ) {
|
||||
this.loggers.put( component , logger = new MockSystemLogger( ) );
|
||||
}
|
||||
return logger;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package com.deepclone.lw.testing;
|
||||
|
||||
|
||||
import com.deepclone.lw.cmd.admin.logs.LogLevel;
|
||||
import com.deepclone.lw.interfaces.eventlog.SystemLogger;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A mock logger for components
|
||||
*
|
||||
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
|
||||
*/
|
||||
public class MockSystemLogger
|
||||
implements SystemLogger
|
||||
{
|
||||
/** How many messages were logged */
|
||||
private int counter = 0;
|
||||
|
||||
|
||||
/** @return the amount of messages that were logged */
|
||||
public int getCounter( )
|
||||
{
|
||||
return counter;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the message counter
|
||||
*
|
||||
* @param counter
|
||||
* the counter's new value
|
||||
*/
|
||||
public void setCounter( int counter )
|
||||
{
|
||||
this.counter = counter;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SystemLogger log( LogLevel level , String message )
|
||||
{
|
||||
this.counter++;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SystemLogger log( LogLevel level , String message , Throwable exception )
|
||||
{
|
||||
this.counter++;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SystemLogger flush( )
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,148 @@
|
|||
package com.deepclone.lw.testing;
|
||||
|
||||
|
||||
import com.deepclone.lw.interfaces.sys.MaintenanceData;
|
||||
import com.deepclone.lw.interfaces.sys.MaintenanceStatusException;
|
||||
import com.deepclone.lw.interfaces.sys.SystemStatus;
|
||||
import com.deepclone.lw.interfaces.sys.TickStatusException;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A mock system status component
|
||||
*
|
||||
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
|
||||
*/
|
||||
public class MockSystemStatus
|
||||
implements SystemStatus
|
||||
{
|
||||
/** Maintenance data to return when {@link #checkMaintenance()} is called */
|
||||
private MaintenanceData maintenance = null;
|
||||
|
||||
/** Value that determines the behaviour of {@link #startTick()} */
|
||||
private long stValue = 0;
|
||||
|
||||
/** Value that determines the behaviour of {@link #checkStuckTick()} */
|
||||
private long cstValue = -1;
|
||||
|
||||
/** Was {@link #startTick()} called? */
|
||||
private boolean startTickCalled = false;
|
||||
|
||||
|
||||
/**
|
||||
* Set the maintenance data to return when {@link #checkMaintenance()} is called
|
||||
*
|
||||
* @param maintenance
|
||||
* the data to return from {@link #checkMaintenance()}
|
||||
*/
|
||||
public void setMaintenance( MaintenanceData maintenance )
|
||||
{
|
||||
this.maintenance = maintenance;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the value that determines the behaviour of {@link #checkStuckTick()}
|
||||
*
|
||||
* <ul>
|
||||
* <li>-2 will cause a {@link MaintenanceStatusException},
|
||||
* <li>-1 will cause it to return <code>null</code>,
|
||||
* <li>any other value will be returned.
|
||||
* </ul>
|
||||
*
|
||||
* @param cstValue
|
||||
* the value
|
||||
*/
|
||||
public void setCSTBehaviour( long cstValue )
|
||||
{
|
||||
this.cstValue = cstValue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the value that determines the behaviour of {@link #startTick()}
|
||||
*
|
||||
* <ul>
|
||||
* <li>-2 will cause a {@link MaintenanceStatusException},
|
||||
* <li>-1 will cause a {@link TickStatusException},
|
||||
* <li>any other value will be returned.
|
||||
* </ul>
|
||||
*
|
||||
* @param cstValue
|
||||
* the value
|
||||
*/
|
||||
public void setSTBehaviour( long stValue )
|
||||
{
|
||||
this.stValue = stValue;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if {@link #startTick()} was called.
|
||||
*/
|
||||
public boolean wasStartTickCalled( )
|
||||
{
|
||||
return startTickCalled;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public MaintenanceData checkMaintenance( )
|
||||
{
|
||||
return this.maintenance;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void startMaintenance( int adminId , String reason , int duration )
|
||||
throws MaintenanceStatusException
|
||||
{
|
||||
// EMPTY - ignored
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void updateMaintenance( int adminId , int durationFromNow )
|
||||
throws MaintenanceStatusException
|
||||
{
|
||||
// EMPTY - ignored
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void endMaintenance( int adminId )
|
||||
throws MaintenanceStatusException
|
||||
{
|
||||
// EMPTY - ignored
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public long startTick( )
|
||||
throws TickStatusException , MaintenanceStatusException
|
||||
{
|
||||
this.startTickCalled = true;
|
||||
if ( this.stValue == -1 ) {
|
||||
throw new TickStatusException( );
|
||||
}
|
||||
if ( this.stValue == -2 ) {
|
||||
throw new MaintenanceStatusException( );
|
||||
}
|
||||
return this.stValue;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Long checkStuckTick( )
|
||||
throws MaintenanceStatusException
|
||||
{
|
||||
if ( this.cstValue == -1 ) {
|
||||
return null;
|
||||
}
|
||||
if ( this.cstValue == -2 ) {
|
||||
throw new MaintenanceStatusException( );
|
||||
}
|
||||
return this.cstValue;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package com.deepclone.lw.testing;
|
||||
|
||||
|
||||
import com.deepclone.lw.interfaces.sys.Ticker;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A mock ticker component
|
||||
*
|
||||
* <p>
|
||||
* This mock component can be used to make sure that another component registers some task as
|
||||
* expected.
|
||||
*
|
||||
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
|
||||
*
|
||||
*/
|
||||
public class MockTicker
|
||||
implements Ticker
|
||||
{
|
||||
/** The task's expected frequency */
|
||||
private final Frequency expectedFrequency;
|
||||
|
||||
/** The task's expected name */
|
||||
private final String expectedName;
|
||||
|
||||
/** The task's expected type */
|
||||
private final Class< ? > expectedType;
|
||||
|
||||
|
||||
/**
|
||||
* Initialise the mock ticker's expectations
|
||||
*
|
||||
* @param expectedFrequency
|
||||
* the task's expected frequency
|
||||
* @param expectedName
|
||||
* the task's expected name
|
||||
* @param expectedType
|
||||
* the task's expected type
|
||||
*/
|
||||
public MockTicker( Frequency expectedFrequency , String expectedName , Class< ? > expectedType )
|
||||
{
|
||||
this.expectedFrequency = expectedFrequency;
|
||||
this.expectedName = expectedName;
|
||||
this.expectedType = expectedType;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void registerTask( Frequency frequency , String name , Runnable task )
|
||||
{
|
||||
assertEquals( this.expectedFrequency , frequency );
|
||||
assertEquals( this.expectedName , name );
|
||||
assertTrue( this.expectedType.isInstance( task ) );
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void pause( )
|
||||
throws IllegalStateException
|
||||
{
|
||||
// EMPTY - ignored
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void unpause( )
|
||||
throws IllegalStateException
|
||||
{
|
||||
// EMPTY - ignored
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean isActive( )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
package com.deepclone.lw.testing;
|
||||
|
||||
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.TransactionException;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* A mock transaction manager
|
||||
*
|
||||
* @author <a href="mailto:tseeker@legacyworlds.com">E. Benoît</a>
|
||||
*/
|
||||
public class MockTransactionManager
|
||||
implements PlatformTransactionManager
|
||||
{
|
||||
|
||||
@Override
|
||||
public TransactionStatus getTransaction( TransactionDefinition definition )
|
||||
throws TransactionException
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void commit( TransactionStatus status )
|
||||
throws TransactionException
|
||||
{
|
||||
// EMPTY
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void rollback( TransactionStatus status )
|
||||
throws TransactionException
|
||||
{
|
||||
// EMPTY
|
||||
}
|
||||
|
||||
}
|
Reference in a new issue