package freenet.client.async; import freenet.support.CheatingTicker; import freenet.support.Executor; import freenet.support.PooledExecutor; import freenet.support.Ticker; import freenet.support.WaitableExecutor; import freenet.support.io.NativeThread; import junit.framework.TestCase; public class PersistentJobRunnerImplTest extends TestCase { final WaitableExecutor exec = new WaitableExecutor(new PooledExecutor()); final Ticker ticker = new CheatingTicker(exec); final JobRunner jobRunner; final ClientContext context; public PersistentJobRunnerImplTest() { jobRunner = new JobRunner(exec, ticker, 1000); context = new ClientContext(0, null, exec, null, null, null, null, null, null, null, null, ticker, null, null, null, null, null, null, null, null, null, null, null, null, null, null); jobRunner.start(context); jobRunner.onStarted(false); exec.waitForIdle(); jobRunner.grabHasCheckpointed(); } private class WakeableJob implements PersistentJob { private boolean wake; private boolean started; private boolean finished; @Override public boolean run(ClientContext context) { synchronized(this) { started = true; notifyAll(); while(!wake) { try { wait(); } catch (InterruptedException e) { // Ignore. } } finished = true; notifyAll(); } return false; } public synchronized void wakeUp() { wake = true; notifyAll(); } public synchronized boolean started() { return started; } public synchronized boolean finished() { return finished; } public synchronized void waitForStarted() { while(!started) { try { wait(); } catch (InterruptedException e) { // Ignore. } } } } private class JobRunner extends PersistentJobRunnerImpl { private boolean hasCheckpointed; public JobRunner(Executor executor, Ticker ticker, long interval) { super(executor, ticker, interval); // TODO Auto-generated constructor stub } @Override public boolean newSalt() { // Ignore. return false; } @Override protected synchronized void innerCheckpoint(boolean shutdown) { hasCheckpointed = true; notifyAll(); } public synchronized boolean grabHasCheckpointed() { boolean ret = hasCheckpointed; hasCheckpointed = false; return ret; } } private class WaitAndCheckpoint implements Runnable { private final JobRunner jobRunner; private boolean started; private boolean finished; public WaitAndCheckpoint(JobRunner jobRunner2) { jobRunner = jobRunner2; } @Override public void run() { synchronized(this) { started = true; notifyAll(); } try { jobRunner.waitAndCheckpoint(); } catch (PersistenceDisabledException e) { System.err.println("Impossible: "+e); return; } assertTrue(jobRunner.grabHasCheckpointed()); synchronized(this) { finished = true; notifyAll(); } } public synchronized boolean hasStarted() { return started; } public synchronized void waitForFinished() { while(!finished) { try { wait(); } catch (InterruptedException e) { // Ignore. } } } public synchronized void waitForStarted() { while(!started) { try { wait(); } catch (InterruptedException e) { // Ignore. } } } } public void testWaitForCheckpoint() throws PersistenceDisabledException { jobRunner.onLoading(); WakeableJob w = new WakeableJob(); jobRunner.queue(w, NativeThread.NORM_PRIORITY); w.waitForStarted(); WaitAndCheckpoint checkpointer = new WaitAndCheckpoint(jobRunner); new Thread(checkpointer).start(); checkpointer.waitForStarted(); w.wakeUp(); checkpointer.waitForFinished(); assertTrue(w.finished()); } public void testDisabledCheckpointing() throws PersistenceDisabledException { jobRunner.setCheckpointASAP(); exec.waitForIdle(); assertFalse(jobRunner.mustCheckpoint()); // Has checkpointed, now false. jobRunner.disableWrite(); assertFalse(jobRunner.mustCheckpoint()); jobRunner.setCheckpointASAP(); assertFalse(jobRunner.mustCheckpoint()); // Run a job which will request a checkpoint. jobRunner.queue(new PersistentJob() { @Override public boolean run(ClientContext context) { return true; } }, NativeThread.NORM_PRIORITY); // Wait for the job to complete. exec.waitForIdle(); assertFalse(jobRunner.mustCheckpoint()); } }