package org.limewire.security; import java.util.Arrays; import java.util.List; import java.util.concurrent.AbstractExecutorService; import java.util.concurrent.Callable; import java.util.concurrent.Future; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import junit.framework.Test; import org.limewire.concurrent.SimpleTimer; import org.limewire.util.BaseTestCase; public class MACCalculatorRotatorTest extends BaseTestCase { public MACCalculatorRotatorTest(String name) { super(name); } public static Test suite() { return buildTestSuite(MACCalculatorRotatorTest.class); } public void testKeyGeneratorsAreRotatedAndExpired() { SchedulingTestThreadPool pool = new SchedulingTestThreadPool(); MACCalculatorRotator rotator = new MACCalculatorRotator(pool, new TEAMACCalculatorFactory(), new SettingsProvider() { public long getChangePeriod() { return 1; } public long getGracePeriod() { return 0; } }); MACCalculator generator = rotator.getCurrentMACCalculator(); assertEquals(1, rotator.getValidMACCalculators().length); assertContains(Arrays.asList(rotator.getValidMACCalculators()), generator); // run rotate Runnable r = pool.r; pool.r = null; r.run(); assertEquals(2, rotator.getValidMACCalculators().length); MACCalculator generatorNew = rotator.getCurrentMACCalculator(); assertNotSame(generator, generatorNew); assertContains(Arrays.asList(rotator.getValidMACCalculators()), generator); assertContains(Arrays.asList(rotator.getValidMACCalculators()), generatorNew); // expire old key r = pool.r2; pool.r2 = null; r.run(); assertEquals(1, rotator.getValidMACCalculators().length); MACCalculator generator3 = rotator.getCurrentMACCalculator(); assertSame(generatorNew, generator3); assertContains(Arrays.asList(rotator.getValidMACCalculators()), generator3); assertNotContains(Arrays.asList(rotator.getValidMACCalculators()), generator); } public void testGracePeriodIsHonored() throws Exception { WrappingSchedulingTestThreadPool pool = new WrappingSchedulingTestThreadPool(); MACCalculatorRotator rotator = new MACCalculatorRotator(pool, new TEAMACCalculatorFactory(), new SettingsProvider() { public long getChangePeriod() { return 500; } public long getGracePeriod() { return 250; } }); assertEquals(1, rotator.getValidMACCalculators().length); pool.r.waitForRunnable(); assertEquals(2, rotator.getValidMACCalculators().length); pool.r2.waitForRunnable(); assertEquals(1, rotator.getValidMACCalculators().length); pool.r.waitForRunnable(); assertEquals(2, rotator.getValidMACCalculators().length); } public void testInvalidSettings() throws Exception { try { new MACCalculatorRotator(new SchedulingTestThreadPool(), new TEAMACCalculatorFactory(), new SettingsProvider() { public long getChangePeriod() { return 500; } public long getGracePeriod() { return 2500; } }); fail("constructed rotator with grace > expiry"); } catch (IllegalArgumentException expected ){} } private static class WrappingSchedulingTestThreadPool extends AbstractExecutorService implements ScheduledExecutorService { private ScheduledExecutorService pool = new SimpleTimer(true); private NotifyinRunnable r; private NotifyinRunnable r2; private int modCounter = 0; public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) { if ((modCounter++ % 2) == 0) { this.r = new NotifyinRunnable(command); return pool.schedule(this.r, delay, unit); } else { this.r2 = new NotifyinRunnable(command); return pool.schedule(this.r2, delay, unit); } } public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) { throw new UnsupportedOperationException(); } public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) { throw new UnsupportedOperationException(); } public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) { throw new UnsupportedOperationException(); } public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { throw new UnsupportedOperationException(); } public boolean isShutdown() { throw new UnsupportedOperationException(); } public boolean isTerminated() { throw new UnsupportedOperationException(); } public void shutdown() { throw new UnsupportedOperationException(); } public List<Runnable> shutdownNow() { throw new UnsupportedOperationException(); } @Override public <T> Future<T> submit(Callable<T> task) { throw new UnsupportedOperationException(); } @Override public Future<?> submit(Runnable task) { throw new UnsupportedOperationException(); } @Override public <T> Future<T> submit(Runnable task, T result) { throw new UnsupportedOperationException(); } public void execute(Runnable command) { throw new UnsupportedOperationException(); } } private static class NotifyinRunnable implements Runnable { private Runnable r; public NotifyinRunnable(Runnable r) { this.r = r; } public synchronized void run() { r.run(); r = null; notify(); } public synchronized void waitForRunnable() throws InterruptedException { while (r != null) { wait(); } } } private static class SchedulingTestThreadPool extends AbstractExecutorService implements ScheduledExecutorService { Runnable r; Runnable r2; public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) { if (this.r == null) { this.r = command; } else { r2 = command; } return null; } public <V> ScheduledFuture<V> schedule(Callable<V> callable, long delay, TimeUnit unit) { throw new UnsupportedOperationException(); } public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) { throw new UnsupportedOperationException(); } public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) { throw new UnsupportedOperationException(); } public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { throw new UnsupportedOperationException(); } public boolean isShutdown() { throw new UnsupportedOperationException(); } public boolean isTerminated() { throw new UnsupportedOperationException(); } public void shutdown() { throw new UnsupportedOperationException(); } public List<Runnable> shutdownNow() { throw new UnsupportedOperationException(); } @Override public <T> Future<T> submit(Callable<T> task) { throw new UnsupportedOperationException(); } @Override public Future<?> submit(Runnable task) { throw new UnsupportedOperationException(); } @Override public <T> Future<T> submit(Runnable task, T result) { throw new UnsupportedOperationException(); } public void execute(Runnable command) { throw new UnsupportedOperationException(); } } }