Refactored PollingRemovableDriveMonitor, fixed test.

This commit is contained in:
akwizgran
2012-05-04 14:24:16 +01:00
parent 4f2704e624
commit 4338bd9a8b
5 changed files with 67 additions and 54 deletions

View File

@@ -12,7 +12,7 @@ import net.sf.briar.api.plugins.PluginExecutor;
class PollingRemovableDriveMonitor implements RemovableDriveMonitor, Runnable { class PollingRemovableDriveMonitor implements RemovableDriveMonitor, Runnable {
private static final Logger LOG = private static final Logger LOG =
Logger.getLogger(PollingRemovableDriveMonitor.class.getName()); Logger.getLogger(PollingRemovableDriveMonitor.class.getName());
private final Executor pluginExecutor; private final Executor pluginExecutor;
private final RemovableDriveFinder finder; private final RemovableDriveFinder finder;
@@ -21,7 +21,6 @@ class PollingRemovableDriveMonitor implements RemovableDriveMonitor, Runnable {
private volatile boolean running = false; private volatile boolean running = false;
private volatile Callback callback = null; private volatile Callback callback = null;
private volatile IOException exception = null;
public PollingRemovableDriveMonitor(@PluginExecutor Executor pluginExecutor, public PollingRemovableDriveMonitor(@PluginExecutor Executor pluginExecutor,
RemovableDriveFinder finder, long pollingInterval) { RemovableDriveFinder finder, long pollingInterval) {
@@ -34,7 +33,6 @@ class PollingRemovableDriveMonitor implements RemovableDriveMonitor, Runnable {
synchronized(this) { synchronized(this) {
assert !running; assert !running;
assert this.callback == null; assert this.callback == null;
assert exception == null;
running = true; running = true;
this.callback = callback; this.callback = callback;
} }
@@ -42,19 +40,15 @@ class PollingRemovableDriveMonitor implements RemovableDriveMonitor, Runnable {
} }
public void stop() throws IOException { public void stop() throws IOException {
IOException e;
synchronized(this) { synchronized(this) {
assert running; assert running;
assert callback != null; assert callback != null;
running = false; running = false;
callback = null; callback = null;
e = exception;
exception = null;
} }
synchronized(pollingLock) { synchronized(pollingLock) {
pollingLock.notifyAll(); pollingLock.notifyAll();
} }
if(e != null) throw e;
} }
public void run() { public void run() {
@@ -76,7 +70,7 @@ class PollingRemovableDriveMonitor implements RemovableDriveMonitor, Runnable {
LOG.info("Interrupted while waiting to poll"); LOG.info("Interrupted while waiting to poll");
Thread.currentThread().interrupt(); Thread.currentThread().interrupt();
} catch(IOException e) { } catch(IOException e) {
exception = e; callback.exceptionThrown(e);
} }
} }
} }

View File

@@ -12,5 +12,7 @@ interface RemovableDriveMonitor {
interface Callback { interface Callback {
void driveInserted(File root); void driveInserted(File root);
void exceptionThrown(IOException e);
} }
} }

View File

@@ -123,4 +123,8 @@ implements RemovableDriveMonitor.Callback {
for(File f : files) if(f.isFile()) createReaderFromFile(f); for(File f : files) if(f.isFile()) createReaderFromFile(f);
} }
} }
public void exceptionThrown(IOException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
}
} }

View File

@@ -3,90 +3,92 @@ package net.sf.briar.plugins.file;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import net.sf.briar.BriarTestCase; import net.sf.briar.BriarTestCase;
import net.sf.briar.plugins.file.RemovableDriveMonitor.Callback; import net.sf.briar.plugins.file.RemovableDriveMonitor.Callback;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.junit.Test; import org.junit.Test;
public class PollingRemovableDriveMonitorTest extends BriarTestCase { public class PollingRemovableDriveMonitorTest extends BriarTestCase {
@Test @Test
public void testOneCallbackPerFile() throws Exception { public void testOneCallbackPerFile() throws Exception {
// Create a finder that returns no files the first time, then two files
final File file1 = new File("foo"); final File file1 = new File("foo");
final File file2 = new File("bar"); final File file2 = new File("bar");
// Create a finder that returns no files the first time, then two files final RemovableDriveFinder finder = new RemovableDriveFinder() {
final List<File> noDrives = Collections.emptyList();
final List<File> twoDrives = new ArrayList<File>(); private AtomicBoolean firstCall = new AtomicBoolean(true);
twoDrives.add(file1);
twoDrives.add(file2); public Collection<File> findRemovableDrives() throws IOException {
Mockery context = new Mockery(); if(firstCall.getAndSet(false)) return Collections.emptyList();
final RemovableDriveFinder finder = else return Arrays.asList(new File[] {file1, file2});
context.mock(RemovableDriveFinder.class); }
context.checking(new Expectations() {{ };
oneOf(finder).findRemovableDrives(); // Create a callback that waits for two files
will(returnValue(noDrives));
oneOf(finder).findRemovableDrives();
will(returnValue(twoDrives));
}});
// Create a callback that will wait for two files before stopping
final List<File> detected = new ArrayList<File>();
final CountDownLatch latch = new CountDownLatch(2); final CountDownLatch latch = new CountDownLatch(2);
final Callback callback = new Callback() { final List<File> detected = new ArrayList<File>();
Callback callback = new Callback() {
public void driveInserted(File f) { public void driveInserted(File f) {
detected.add(f); detected.add(f);
latch.countDown(); latch.countDown();
} }
public void exceptionThrown(IOException e) {
fail();
}
}; };
// Create the monitor and start it // Create the monitor and start it
final RemovableDriveMonitor monitor = new PollingRemovableDriveMonitor( final RemovableDriveMonitor monitor = new PollingRemovableDriveMonitor(
Executors.newCachedThreadPool(), finder, 10); Executors.newCachedThreadPool(), finder, 1);
monitor.start(callback); monitor.start(callback);
// Wait for the monitor to detect the files // Wait for the monitor to detect the files
assertTrue(latch.await(5, TimeUnit.SECONDS)); assertTrue(latch.await(10, TimeUnit.SECONDS));
monitor.stop(); monitor.stop();
// Check that both files were detected // Check that both files were detected
assertEquals(2, detected.size()); assertEquals(2, detected.size());
assertTrue(detected.contains(file1)); assertTrue(detected.contains(file1));
assertTrue(detected.contains(file2)); assertTrue(detected.contains(file2));
// Check that the finder was polled twice
context.assertIsSatisfied();
} }
@Test @Test
public void testExceptionRethrownWhenStopping() throws Exception { public void testExceptionCallback() throws Exception {
final List<File> noDrives = Collections.emptyList();
// Create a finder that throws an exception the second time it's polled // Create a finder that throws an exception the second time it's polled
Mockery context = new Mockery(); final RemovableDriveFinder finder = new RemovableDriveFinder() {
final RemovableDriveFinder finder =
context.mock(RemovableDriveFinder.class); private AtomicBoolean firstCall = new AtomicBoolean(true);
context.checking(new Expectations() {{
oneOf(finder).findRemovableDrives(); public Collection<File> findRemovableDrives() throws IOException {
will(returnValue(noDrives)); if(firstCall.getAndSet(false)) return Collections.emptyList();
oneOf(finder).findRemovableDrives(); else throw new IOException();
will(throwException(new IOException())); }
}}); };
// Create the monitor, start it, and give it some time to run // Create a callback that waits for an exception
final RemovableDriveMonitor monitor = new PollingRemovableDriveMonitor( final CountDownLatch latch = new CountDownLatch(1);
Executors.newCachedThreadPool(), finder, 10); Callback callback = new Callback() {
monitor.start(new Callback() {
public void driveInserted(File root) { public void driveInserted(File root) {
fail(); fail();
} }
});
Thread.sleep(100); public void exceptionThrown(IOException e) {
// The monitor should rethrow the exception when it stops latch.countDown();
try { }
monitor.stop(); };
fail(); // Create the monitor and start it
} catch(IOException expected) {} final RemovableDriveMonitor monitor = new PollingRemovableDriveMonitor(
context.assertIsSatisfied(); Executors.newCachedThreadPool(), finder, 1);
monitor.start(callback);
assertTrue(latch.await(10, TimeUnit.SECONDS));
monitor.stop();
} }
} }

View File

@@ -1,6 +1,7 @@
package net.sf.briar.plugins.file; package net.sf.briar.plugins.file;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.concurrent.CountDownLatch; import java.util.concurrent.CountDownLatch;
@@ -33,9 +34,14 @@ public class UnixRemovableDriveMonitorTest extends BriarTestCase {
File doesNotExist = new File(testDir, "doesNotExist"); File doesNotExist = new File(testDir, "doesNotExist");
RemovableDriveMonitor monitor = createMonitor(doesNotExist); RemovableDriveMonitor monitor = createMonitor(doesNotExist);
monitor.start(new Callback() { monitor.start(new Callback() {
public void driveInserted(File root) { public void driveInserted(File root) {
fail(); fail();
} }
public void exceptionThrown(IOException e) {
fail();
}
}); });
monitor.stop(); monitor.stop();
} }
@@ -50,10 +56,15 @@ public class UnixRemovableDriveMonitorTest extends BriarTestCase {
final List<File> detected = new ArrayList<File>(); final List<File> detected = new ArrayList<File>();
final CountDownLatch latch = new CountDownLatch(2); final CountDownLatch latch = new CountDownLatch(2);
final Callback callback = new Callback() { final Callback callback = new Callback() {
public void driveInserted(File f) { public void driveInserted(File f) {
detected.add(f); detected.add(f);
latch.countDown(); latch.countDown();
} }
public void exceptionThrown(IOException e) {
fail();
}
}; };
// Create the monitor and start it // Create the monitor and start it
RemovableDriveMonitor monitor = createMonitor(testDir); RemovableDriveMonitor monitor = createMonitor(testDir);