Skip to content
Snippets Groups Projects
Commit 4338bd9a authored by akwizgran's avatar akwizgran
Browse files

Refactored PollingRemovableDriveMonitor, fixed test.

parent 4f2704e6
No related branches found
No related tags found
No related merge requests found
......@@ -12,7 +12,7 @@ import net.sf.briar.api.plugins.PluginExecutor;
class PollingRemovableDriveMonitor implements RemovableDriveMonitor, Runnable {
private static final Logger LOG =
Logger.getLogger(PollingRemovableDriveMonitor.class.getName());
Logger.getLogger(PollingRemovableDriveMonitor.class.getName());
private final Executor pluginExecutor;
private final RemovableDriveFinder finder;
......@@ -21,7 +21,6 @@ class PollingRemovableDriveMonitor implements RemovableDriveMonitor, Runnable {
private volatile boolean running = false;
private volatile Callback callback = null;
private volatile IOException exception = null;
public PollingRemovableDriveMonitor(@PluginExecutor Executor pluginExecutor,
RemovableDriveFinder finder, long pollingInterval) {
......@@ -34,7 +33,6 @@ class PollingRemovableDriveMonitor implements RemovableDriveMonitor, Runnable {
synchronized(this) {
assert !running;
assert this.callback == null;
assert exception == null;
running = true;
this.callback = callback;
}
......@@ -42,19 +40,15 @@ class PollingRemovableDriveMonitor implements RemovableDriveMonitor, Runnable {
}
public void stop() throws IOException {
IOException e;
synchronized(this) {
assert running;
assert callback != null;
running = false;
callback = null;
e = exception;
exception = null;
}
synchronized(pollingLock) {
pollingLock.notifyAll();
}
if(e != null) throw e;
}
public void run() {
......@@ -76,7 +70,7 @@ class PollingRemovableDriveMonitor implements RemovableDriveMonitor, Runnable {
LOG.info("Interrupted while waiting to poll");
Thread.currentThread().interrupt();
} catch(IOException e) {
exception = e;
callback.exceptionThrown(e);
}
}
}
......@@ -12,5 +12,7 @@ interface RemovableDriveMonitor {
interface Callback {
void driveInserted(File root);
void exceptionThrown(IOException e);
}
}
......@@ -123,4 +123,8 @@ implements RemovableDriveMonitor.Callback {
for(File f : files) if(f.isFile()) createReaderFromFile(f);
}
}
public void exceptionThrown(IOException e) {
if(LOG.isLoggable(Level.WARNING)) LOG.warning(e.toString());
}
}
......@@ -3,90 +3,92 @@ package net.sf.briar.plugins.file;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import net.sf.briar.BriarTestCase;
import net.sf.briar.plugins.file.RemovableDriveMonitor.Callback;
import org.jmock.Expectations;
import org.jmock.Mockery;
import org.junit.Test;
public class PollingRemovableDriveMonitorTest extends BriarTestCase {
@Test
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 file2 = new File("bar");
// Create a finder that returns no files the first time, then two files
final List<File> noDrives = Collections.emptyList();
final List<File> twoDrives = new ArrayList<File>();
twoDrives.add(file1);
twoDrives.add(file2);
Mockery context = new Mockery();
final RemovableDriveFinder finder =
context.mock(RemovableDriveFinder.class);
context.checking(new Expectations() {{
oneOf(finder).findRemovableDrives();
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 RemovableDriveFinder finder = new RemovableDriveFinder() {
private AtomicBoolean firstCall = new AtomicBoolean(true);
public Collection<File> findRemovableDrives() throws IOException {
if(firstCall.getAndSet(false)) return Collections.emptyList();
else return Arrays.asList(new File[] {file1, file2});
}
};
// Create a callback that waits for two files
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) {
detected.add(f);
latch.countDown();
}
public void exceptionThrown(IOException e) {
fail();
}
};
// Create the monitor and start it
final RemovableDriveMonitor monitor = new PollingRemovableDriveMonitor(
Executors.newCachedThreadPool(), finder, 10);
Executors.newCachedThreadPool(), finder, 1);
monitor.start(callback);
// Wait for the monitor to detect the files
assertTrue(latch.await(5, TimeUnit.SECONDS));
assertTrue(latch.await(10, TimeUnit.SECONDS));
monitor.stop();
// Check that both files were detected
assertEquals(2, detected.size());
assertTrue(detected.contains(file1));
assertTrue(detected.contains(file2));
// Check that the finder was polled twice
context.assertIsSatisfied();
}
@Test
public void testExceptionRethrownWhenStopping() throws Exception {
final List<File> noDrives = Collections.emptyList();
public void testExceptionCallback() throws Exception {
// Create a finder that throws an exception the second time it's polled
Mockery context = new Mockery();
final RemovableDriveFinder finder =
context.mock(RemovableDriveFinder.class);
context.checking(new Expectations() {{
oneOf(finder).findRemovableDrives();
will(returnValue(noDrives));
oneOf(finder).findRemovableDrives();
will(throwException(new IOException()));
}});
// Create the monitor, start it, and give it some time to run
final RemovableDriveMonitor monitor = new PollingRemovableDriveMonitor(
Executors.newCachedThreadPool(), finder, 10);
monitor.start(new Callback() {
final RemovableDriveFinder finder = new RemovableDriveFinder() {
private AtomicBoolean firstCall = new AtomicBoolean(true);
public Collection<File> findRemovableDrives() throws IOException {
if(firstCall.getAndSet(false)) return Collections.emptyList();
else throw new IOException();
}
};
// Create a callback that waits for an exception
final CountDownLatch latch = new CountDownLatch(1);
Callback callback = new Callback() {
public void driveInserted(File root) {
fail();
}
});
Thread.sleep(100);
// The monitor should rethrow the exception when it stops
try {
monitor.stop();
fail();
} catch(IOException expected) {}
context.assertIsSatisfied();
public void exceptionThrown(IOException e) {
latch.countDown();
}
};
// Create the monitor and start it
final RemovableDriveMonitor monitor = new PollingRemovableDriveMonitor(
Executors.newCachedThreadPool(), finder, 1);
monitor.start(callback);
assertTrue(latch.await(10, TimeUnit.SECONDS));
monitor.stop();
}
}
package net.sf.briar.plugins.file;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CountDownLatch;
......@@ -33,9 +34,14 @@ public class UnixRemovableDriveMonitorTest extends BriarTestCase {
File doesNotExist = new File(testDir, "doesNotExist");
RemovableDriveMonitor monitor = createMonitor(doesNotExist);
monitor.start(new Callback() {
public void driveInserted(File root) {
fail();
}
public void exceptionThrown(IOException e) {
fail();
}
});
monitor.stop();
}
......@@ -50,10 +56,15 @@ public class UnixRemovableDriveMonitorTest extends BriarTestCase {
final List<File> detected = new ArrayList<File>();
final CountDownLatch latch = new CountDownLatch(2);
final Callback callback = new Callback() {
public void driveInserted(File f) {
detected.add(f);
latch.countDown();
}
public void exceptionThrown(IOException e) {
fail();
}
};
// Create the monitor and start it
RemovableDriveMonitor monitor = createMonitor(testDir);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment