#1130: Add scheduler unit tests and make more robust.

This commit is contained in:
md_5 2015-01-18 12:09:38 +11:00
parent 28496e0471
commit cf722de1d2
6 changed files with 123 additions and 9 deletions

View File

@ -96,8 +96,9 @@ public class Plugin
{ {
if ( service == null ) if ( service == null )
{ {
service = Executors.newCachedThreadPool( new ThreadFactoryBuilder().setNameFormat( getDescription().getName() + " Pool Thread #%1$d" ) String name = ( getDescription() == null ) ? "unknown" : getDescription().getName();
.setThreadFactory( new GroupedThreadFactory( this ) ).build() ); service = Executors.newCachedThreadPool( new ThreadFactoryBuilder().setNameFormat( name + " Pool Thread #%1$d" )
.setThreadFactory( new GroupedThreadFactory( this, name ) ).build() );
} }
return service; return service;
} }

View File

@ -21,9 +21,9 @@ public class GroupedThreadFactory implements ThreadFactory
} }
public GroupedThreadFactory(Plugin plugin) public GroupedThreadFactory(Plugin plugin, String name)
{ {
this.group = new BungeeGroup( plugin.getDescription().getName() ); this.group = new BungeeGroup( name );
} }
@Override @Override

View File

@ -19,6 +19,7 @@ import net.md_5.bungee.api.scheduler.TaskScheduler;
public class BungeeScheduler implements TaskScheduler public class BungeeScheduler implements TaskScheduler
{ {
private final Object lock = new Object();
private final AtomicInteger taskCounter = new AtomicInteger(); private final AtomicInteger taskCounter = new AtomicInteger();
private final TIntObjectMap<BungeeTask> tasks = TCollections.synchronizedMap( new TIntObjectHashMap<BungeeTask>() ); private final TIntObjectMap<BungeeTask> tasks = TCollections.synchronizedMap( new TIntObjectHashMap<BungeeTask>() );
private final Multimap<Plugin, BungeeTask> tasksByPlugin = Multimaps.synchronizedMultimap( HashMultimap.<Plugin, BungeeTask>create() ); private final Multimap<Plugin, BungeeTask> tasksByPlugin = Multimaps.synchronizedMultimap( HashMultimap.<Plugin, BungeeTask>create() );
@ -36,10 +37,20 @@ public class BungeeScheduler implements TaskScheduler
@Override @Override
public void cancel(int id) public void cancel(int id)
{ {
BungeeTask task = tasks.remove( id ); BungeeTask task = tasks.get( id );
Preconditions.checkArgument( task != null, "No task with id %s", id );
task.cancel(); task.cancel();
}
void cancel0(BungeeTask task)
{
synchronized ( lock )
{
tasks.remove( task.getId() );
tasksByPlugin.values().remove( task ); tasksByPlugin.values().remove( task );
} }
}
@Override @Override
public void cancel(ScheduledTask task) public void cancel(ScheduledTask task)
@ -80,8 +91,13 @@ public class BungeeScheduler implements TaskScheduler
Preconditions.checkNotNull( owner, "owner" ); Preconditions.checkNotNull( owner, "owner" );
Preconditions.checkNotNull( task, "task" ); Preconditions.checkNotNull( task, "task" );
BungeeTask prepared = new BungeeTask( this, taskCounter.getAndIncrement(), owner, task, delay, period, unit ); BungeeTask prepared = new BungeeTask( this, taskCounter.getAndIncrement(), owner, task, delay, period, unit );
synchronized ( lock )
{
tasks.put( prepared.getId(), prepared ); tasks.put( prepared.getId(), prepared );
tasksByPlugin.put( owner, prepared ); tasksByPlugin.put( owner, prepared );
}
owner.getExecutorService().execute( prepared ); owner.getExecutorService().execute( prepared );
return prepared; return prepared;
} }

View File

@ -38,7 +38,7 @@ public class BungeeTask implements Runnable, ScheduledTask
if ( wasRunning ) if ( wasRunning )
{ {
sched.cancel( this.getId() ); sched.cancel0( this );
} }
} }

View File

@ -0,0 +1,11 @@
package net.md_5.bungee.api.plugin;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class DummyPlugin extends Plugin
{
public static final DummyPlugin INSTANCE = new DummyPlugin();
}

View File

@ -0,0 +1,86 @@
package net.md_5.bungee.scheduler;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import net.md_5.bungee.api.plugin.DummyPlugin;
import net.md_5.bungee.api.scheduler.ScheduledTask;
import net.md_5.bungee.api.scheduler.TaskScheduler;
import org.junit.Assert;
import org.junit.Test;
public class SchedulerTest
{
@Test
public void testRun() throws InterruptedException
{
TaskScheduler scheduler = new BungeeScheduler();
final CountDownLatch latch = new CountDownLatch( 1 );
scheduler.runAsync( DummyPlugin.INSTANCE, new Runnable()
{
@Override
public void run()
{
latch.countDown();
}
} );
latch.await( 5, TimeUnit.SECONDS );
Assert.assertEquals( 0, latch.getCount() );
}
@Test
public void testCancel() throws InterruptedException
{
TaskScheduler scheduler = new BungeeScheduler();
AtomicBoolean b = new AtomicBoolean();
ScheduledTask task = setup( scheduler, b );
scheduler.cancel( task.getId() );
Thread.sleep( 250 );
Assert.assertFalse( b.get() );
task = setup( scheduler, b );
scheduler.cancel( task );
Thread.sleep( 250 );
Assert.assertFalse( b.get() );
task = setup( scheduler, b );
scheduler.cancel( task.getOwner() );
Thread.sleep( 250 );
Assert.assertFalse( b.get() );
}
@Test
public void testScheduleAndRepeat() throws InterruptedException
{
TaskScheduler scheduler = new BungeeScheduler();
AtomicBoolean b = new AtomicBoolean();
setup( scheduler, b );
Thread.sleep( 250 );
Assert.assertTrue( b.get() );
b.set( false );
Thread.sleep( 250 );
Assert.assertTrue( b.get() );
}
private ScheduledTask setup(TaskScheduler scheduler, final AtomicBoolean hasRun)
{
return scheduler.schedule( DummyPlugin.INSTANCE, new Runnable()
{
@Override
public void run()
{
hasRun.set( true );
}
}, 100, 100, TimeUnit.MILLISECONDS );
}
}