diff --git a/briar-api/src/org/briarproject/api/plugins/PluginManager.java b/briar-api/src/org/briarproject/api/plugins/PluginManager.java index 838c66ff86e1ac74a41c507f9d48b6774038c247..18e71c2ec2e75ae4790c7e1580b7b95e75b1700c 100644 --- a/briar-api/src/org/briarproject/api/plugins/PluginManager.java +++ b/briar-api/src/org/briarproject/api/plugins/PluginManager.java @@ -2,24 +2,39 @@ package org.briarproject.api.plugins; import org.briarproject.api.TransportId; import org.briarproject.api.plugins.duplex.DuplexPlugin; +import org.briarproject.api.plugins.simplex.SimplexPlugin; import java.util.Collection; /** - * Responsible for starting transport plugins at startup, stopping them at - * shutdown, and providing access to plugins for exchanging invitations. + * Responsible for starting transport plugins at startup and stopping them at + * shutdown. */ public interface PluginManager { /** * Returns the plugin for the given transport, or null if no such plugin - * is running. + * has been created. */ Plugin getPlugin(TransportId t); - /** Returns any running duplex plugins that support invitations. */ + /** + * Returns any simplex plugins that have been created. + */ + Collection<SimplexPlugin> getSimplexPlugins(); + + /** + * Returns any duplex plugins that have been created. + */ + Collection<DuplexPlugin> getDuplexPlugins(); + + /** + * Returns any duplex plugins that support invitations. + */ Collection<DuplexPlugin> getInvitationPlugins(); - /** Returns any running duplex plugins that support key agreement. */ + /** + * Returns any duplex plugins that support key agreement. + */ Collection<DuplexPlugin> getKeyAgreementPlugins(); } diff --git a/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java b/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java index 00f037a8c3376955f6a2d0eea1ff777255d33c3e..ebd6f6c017678c9843d60cc4b23fe1afbb77fb48 100644 --- a/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java +++ b/briar-core/src/org/briarproject/plugins/PluginManagerImpl.java @@ -3,18 +3,13 @@ package org.briarproject.plugins; import org.briarproject.api.TransportId; import org.briarproject.api.contact.ContactId; import org.briarproject.api.db.DbException; -import org.briarproject.api.event.ConnectionClosedEvent; -import org.briarproject.api.event.ContactStatusChangedEvent; -import org.briarproject.api.event.Event; import org.briarproject.api.event.EventBus; -import org.briarproject.api.event.EventListener; import org.briarproject.api.event.TransportDisabledEvent; import org.briarproject.api.event.TransportEnabledEvent; import org.briarproject.api.lifecycle.IoExecutor; import org.briarproject.api.lifecycle.Service; import org.briarproject.api.lifecycle.ServiceException; import org.briarproject.api.plugins.ConnectionManager; -import org.briarproject.api.plugins.ConnectionRegistry; import org.briarproject.api.plugins.Plugin; import org.briarproject.api.plugins.PluginCallback; import org.briarproject.api.plugins.PluginConfig; @@ -51,7 +46,7 @@ import javax.inject.Inject; import static java.util.logging.Level.INFO; import static java.util.logging.Level.WARNING; -class PluginManagerImpl implements PluginManager, Service, EventListener { +class PluginManagerImpl implements PluginManager, Service { private static final Logger LOG = Logger.getLogger(PluginManagerImpl.class.getName()); @@ -59,9 +54,7 @@ class PluginManagerImpl implements PluginManager, Service, EventListener { private final Executor ioExecutor; private final EventBus eventBus; private final PluginConfig pluginConfig; - private final Poller poller; private final ConnectionManager connectionManager; - private final ConnectionRegistry connectionRegistry; private final SettingsManager settingsManager; private final TransportPropertyManager transportPropertyManager; private final UiCallback uiCallback; @@ -71,18 +64,14 @@ class PluginManagerImpl implements PluginManager, Service, EventListener { @Inject PluginManagerImpl(@IoExecutor Executor ioExecutor, EventBus eventBus, - PluginConfig pluginConfig, Poller poller, - ConnectionManager connectionManager, - ConnectionRegistry connectionRegistry, + PluginConfig pluginConfig, ConnectionManager connectionManager, SettingsManager settingsManager, TransportPropertyManager transportPropertyManager, UiCallback uiCallback) { this.ioExecutor = ioExecutor; this.eventBus = eventBus; this.pluginConfig = pluginConfig; - this.poller = poller; this.connectionManager = connectionManager; - this.connectionRegistry = connectionRegistry; this.settingsManager = settingsManager; this.transportPropertyManager = transportPropertyManager; this.uiCallback = uiCallback; @@ -93,36 +82,55 @@ class PluginManagerImpl implements PluginManager, Service, EventListener { @Override public void startService() throws ServiceException { + Collection<SimplexPluginFactory> simplexFactories = + pluginConfig.getSimplexFactories(); + Collection<DuplexPluginFactory> duplexFactories = + pluginConfig.getDuplexFactories(); + int numPlugins = simplexFactories.size() + duplexFactories.size(); + CountDownLatch latch = new CountDownLatch(numPlugins); // Instantiate and start the simplex plugins LOG.info("Starting simplex plugins"); - Collection<SimplexPluginFactory> sFactories = - pluginConfig.getSimplexFactories(); - final CountDownLatch sLatch = new CountDownLatch(sFactories.size()); - for (SimplexPluginFactory factory : sFactories) - ioExecutor.execute(new SimplexPluginStarter(factory, sLatch)); + for (SimplexPluginFactory f : simplexFactories) { + TransportId t = f.getId(); + SimplexPluginCallback c = new SimplexCallback(t); + SimplexPlugin s = f.createPlugin(c); + if (s == null) { + if (LOG.isLoggable(WARNING)) + LOG.warning("Could not create plugin for " + t); + latch.countDown(); + } else { + plugins.put(t, s); + simplexPlugins.add(s); + ioExecutor.execute(new PluginStarter(s, latch)); + } + } // Instantiate and start the duplex plugins LOG.info("Starting duplex plugins"); - Collection<DuplexPluginFactory> dFactories = - pluginConfig.getDuplexFactories(); - final CountDownLatch dLatch = new CountDownLatch(dFactories.size()); - for (DuplexPluginFactory factory : dFactories) - ioExecutor.execute(new DuplexPluginStarter(factory, dLatch)); - // Wait for the plugins to start + for (DuplexPluginFactory f : duplexFactories) { + TransportId t = f.getId(); + DuplexPluginCallback c = new DuplexCallback(t); + DuplexPlugin d = f.createPlugin(c); + if (d == null) { + if (LOG.isLoggable(WARNING)) + LOG.warning("Could not create plugin for " + t); + latch.countDown(); + } else { + plugins.put(t, d); + duplexPlugins.add(d); + ioExecutor.execute(new PluginStarter(d, latch)); + } + } + // Wait for all the plugins to start try { - sLatch.await(); - dLatch.await(); + latch.await(); } catch (InterruptedException e) { throw new ServiceException(e); } - // Listen for events - eventBus.addListener(this); } @Override public void stopService() throws ServiceException { - // Stop listening for events - eventBus.removeListener(this); - final CountDownLatch latch = new CountDownLatch(plugins.size()); + CountDownLatch latch = new CountDownLatch(plugins.size()); // Stop the simplex plugins LOG.info("Stopping simplex plugins"); for (SimplexPlugin plugin : simplexPlugins) @@ -144,6 +152,18 @@ class PluginManagerImpl implements PluginManager, Service, EventListener { return plugins.get(t); } + @Override + public Collection<SimplexPlugin> getSimplexPlugins() { + List<SimplexPlugin> copy = new ArrayList<SimplexPlugin>(simplexPlugins); + return Collections.unmodifiableList(copy); + } + + @Override + public Collection<DuplexPlugin> getDuplexPlugins() { + List<DuplexPlugin> copy = new ArrayList<DuplexPlugin>(duplexPlugins); + return Collections.unmodifiableList(copy); + } + @Override public Collection<DuplexPlugin> getInvitationPlugins() { List<DuplexPlugin> supported = new ArrayList<DuplexPlugin>(); @@ -160,149 +180,24 @@ class PluginManagerImpl implements PluginManager, Service, EventListener { return Collections.unmodifiableList(supported); } - @Override - public void eventOccurred(Event e) { - if (e instanceof ContactStatusChangedEvent) { - ContactStatusChangedEvent c = (ContactStatusChangedEvent) e; - if (c.isActive()) { - // Connect to the newly activated contact - connectToContact(c.getContactId()); - } - } else if (e instanceof ConnectionClosedEvent) { - ConnectionClosedEvent c = (ConnectionClosedEvent) e; - if (!c.isIncoming()) { - // Connect to the disconnected contact - connectToContact(c.getContactId(), c.getTransportId()); - } - } - } - - private void connectToContact(ContactId c) { - for (SimplexPlugin s : simplexPlugins) - if (s.shouldPoll()) connectToContact(c, s); - for (DuplexPlugin d : duplexPlugins) - if (d.shouldPoll()) connectToContact(c, d); - } + private class PluginStarter implements Runnable { - private void connectToContact(ContactId c, TransportId t) { - Plugin p = plugins.get(t); - if (p instanceof SimplexPlugin && p.shouldPoll()) - connectToContact(c, (SimplexPlugin) p); - else if (p instanceof DuplexPlugin && p.shouldPoll()) - connectToContact(c, (DuplexPlugin) p); - } - - private void connectToContact(final ContactId c, final SimplexPlugin p) { - ioExecutor.execute(new Runnable() { - @Override - public void run() { - TransportId t = p.getId(); - if (!connectionRegistry.isConnected(c, t)) { - TransportConnectionWriter w = p.createWriter(c); - if (w != null) - connectionManager.manageOutgoingConnection(c, t, w); - } - } - }); - } - - private void connectToContact(final ContactId c, final DuplexPlugin p) { - ioExecutor.execute(new Runnable() { - @Override - public void run() { - TransportId t = p.getId(); - if (!connectionRegistry.isConnected(c, t)) { - DuplexTransportConnection d = p.createConnection(c); - if (d != null) - connectionManager.manageOutgoingConnection(c, t, d); - } - } - }); - } - - private class SimplexPluginStarter implements Runnable { - - private final SimplexPluginFactory factory; - private final CountDownLatch latch; - - private SimplexPluginStarter(SimplexPluginFactory factory, - CountDownLatch latch) { - this.factory = factory; - this.latch = latch; - } - - @Override - public void run() { - try { - TransportId id = factory.getId(); - SimplexCallback callback = new SimplexCallback(id); - SimplexPlugin plugin = factory.createPlugin(callback); - if (plugin == null) { - if (LOG.isLoggable(INFO)) { - String name = factory.getClass().getSimpleName(); - LOG.info(name + " did not create a plugin"); - } - return; - } - try { - long start = System.currentTimeMillis(); - boolean started = plugin.start(); - long duration = System.currentTimeMillis() - start; - if (started) { - plugins.put(id, plugin); - simplexPlugins.add(plugin); - if (LOG.isLoggable(INFO)) { - String name = plugin.getClass().getSimpleName(); - LOG.info("Starting " + name + " took " + - duration + " ms"); - } - } else { - if (LOG.isLoggable(WARNING)) { - String name = plugin.getClass().getSimpleName(); - LOG.warning(name + " did not start"); - } - } - } catch (IOException e) { - if (LOG.isLoggable(WARNING)) - LOG.log(WARNING, e.toString(), e); - } - } finally { - latch.countDown(); - } - } - } - - private class DuplexPluginStarter implements Runnable { - - private final DuplexPluginFactory factory; + private final Plugin plugin; private final CountDownLatch latch; - private DuplexPluginStarter(DuplexPluginFactory factory, - CountDownLatch latch) { - this.factory = factory; + private PluginStarter(Plugin plugin, CountDownLatch latch) { + this.plugin = plugin; this.latch = latch; } @Override public void run() { try { - TransportId id = factory.getId(); - DuplexCallback callback = new DuplexCallback(id); - DuplexPlugin plugin = factory.createPlugin(callback); - if (plugin == null) { - if (LOG.isLoggable(INFO)) { - String name = factory.getClass().getSimpleName(); - LOG.info(name + " did not create a plugin"); - } - return; - } try { long start = System.currentTimeMillis(); boolean started = plugin.start(); long duration = System.currentTimeMillis() - start; if (started) { - plugins.put(id, plugin); - duplexPlugins.add(plugin); if (LOG.isLoggable(INFO)) { String name = plugin.getClass().getSimpleName(); LOG.info("Starting " + name + " took " + @@ -428,8 +323,6 @@ class PluginManagerImpl implements PluginManager, Service, EventListener { @Override public void transportEnabled() { eventBus.broadcast(new TransportEnabledEvent(id)); - Plugin p = plugins.get(id); - if (p != null && p.shouldPoll()) poller.pollNow(p); } @Override diff --git a/briar-core/src/org/briarproject/plugins/PluginsModule.java b/briar-core/src/org/briarproject/plugins/PluginsModule.java index 97799fa24aa68ef4b487b60e1d7f6ba5cb441d2e..764708512cee7fffef5325222a19450590f617e4 100644 --- a/briar-core/src/org/briarproject/plugins/PluginsModule.java +++ b/briar-core/src/org/briarproject/plugins/PluginsModule.java @@ -26,6 +26,8 @@ public class PluginsModule { public static class EagerSingletons { @Inject PluginManager pluginManager; + @Inject + Poller poller; } @Provides @@ -35,7 +37,8 @@ public class PluginsModule { @Provides @Singleton - Poller providePoller(PollerImpl poller) { + Poller providePoller(EventBus eventBus, PollerImpl poller) { + eventBus.addListener(poller); return poller; } diff --git a/briar-core/src/org/briarproject/plugins/Poller.java b/briar-core/src/org/briarproject/plugins/Poller.java index cb98150723f89527f8ce59c6c70d0270fc894d7d..c344935ffc16181a5c456a40fcb91e458078ecb1 100644 --- a/briar-core/src/org/briarproject/plugins/Poller.java +++ b/briar-core/src/org/briarproject/plugins/Poller.java @@ -1,9 +1,6 @@ package org.briarproject.plugins; -import org.briarproject.api.plugins.Plugin; - interface Poller { - /** Tells the poller to poll the given plugin immediately. */ - void pollNow(Plugin p); + // TODO: Remove this interface } diff --git a/briar-core/src/org/briarproject/plugins/PollerImpl.java b/briar-core/src/org/briarproject/plugins/PollerImpl.java index 843e455f637b3782d98d5d678a3c7e24c205c948..32f54129d2fc4fe5c241889dc83fcf85a2bbda07 100644 --- a/briar-core/src/org/briarproject/plugins/PollerImpl.java +++ b/briar-core/src/org/briarproject/plugins/PollerImpl.java @@ -1,9 +1,21 @@ package org.briarproject.plugins; import org.briarproject.api.TransportId; +import org.briarproject.api.contact.ContactId; +import org.briarproject.api.event.ConnectionClosedEvent; +import org.briarproject.api.event.ContactStatusChangedEvent; +import org.briarproject.api.event.Event; +import org.briarproject.api.event.EventListener; +import org.briarproject.api.event.TransportEnabledEvent; import org.briarproject.api.lifecycle.IoExecutor; +import org.briarproject.api.plugins.ConnectionManager; import org.briarproject.api.plugins.ConnectionRegistry; import org.briarproject.api.plugins.Plugin; +import org.briarproject.api.plugins.PluginManager; +import org.briarproject.api.plugins.TransportConnectionWriter; +import org.briarproject.api.plugins.duplex.DuplexPlugin; +import org.briarproject.api.plugins.duplex.DuplexTransportConnection; +import org.briarproject.api.plugins.simplex.SimplexPlugin; import java.security.SecureRandom; import java.util.Map; @@ -17,30 +29,100 @@ import javax.inject.Inject; import static java.util.concurrent.TimeUnit.MILLISECONDS; import static java.util.logging.Level.INFO; -class PollerImpl implements Poller { +class PollerImpl implements Poller, EventListener { private static final Logger LOG = Logger.getLogger(PollerImpl.class.getName()); private final Executor ioExecutor; private final ScheduledExecutorService scheduler; + private final ConnectionManager connectionManager; private final ConnectionRegistry connectionRegistry; + private final PluginManager pluginManager; private final SecureRandom random; private final Map<TransportId, PollTask> tasks; @Inject PollerImpl(@IoExecutor Executor ioExecutor, ScheduledExecutorService scheduler, - ConnectionRegistry connectionRegistry, SecureRandom random) { + ConnectionManager connectionManager, + ConnectionRegistry connectionRegistry, PluginManager pluginManager, + SecureRandom random) { this.ioExecutor = ioExecutor; + this.connectionManager = connectionManager; this.connectionRegistry = connectionRegistry; + this.pluginManager = pluginManager; this.random = random; this.scheduler = scheduler; tasks = new ConcurrentHashMap<TransportId, PollTask>(); } + @Override - public void pollNow(Plugin p) { + public void eventOccurred(Event e) { + if (e instanceof ContactStatusChangedEvent) { + ContactStatusChangedEvent c = (ContactStatusChangedEvent) e; + if (c.isActive()) { + // Connect to the newly activated contact + connectToContact(c.getContactId()); + } + } else if (e instanceof ConnectionClosedEvent) { + ConnectionClosedEvent c = (ConnectionClosedEvent) e; + if (!c.isIncoming()) { + // Connect to the disconnected contact + connectToContact(c.getContactId(), c.getTransportId()); + } + } else if (e instanceof TransportEnabledEvent) { + TransportEnabledEvent t = (TransportEnabledEvent) e; + Plugin p = pluginManager.getPlugin(t.getTransportId()); + if (p.shouldPoll()) pollNow(p); + } + } + + private void connectToContact(ContactId c) { + for (SimplexPlugin s : pluginManager.getSimplexPlugins()) + if (s.shouldPoll()) connectToContact(c, s); + for (DuplexPlugin d : pluginManager.getDuplexPlugins()) + if (d.shouldPoll()) connectToContact(c, d); + } + + private void connectToContact(ContactId c, TransportId t) { + Plugin p = pluginManager.getPlugin(t); + if (p instanceof SimplexPlugin && p.shouldPoll()) + connectToContact(c, (SimplexPlugin) p); + else if (p instanceof DuplexPlugin && p.shouldPoll()) + connectToContact(c, (DuplexPlugin) p); + } + + private void connectToContact(final ContactId c, final SimplexPlugin p) { + ioExecutor.execute(new Runnable() { + @Override + public void run() { + TransportId t = p.getId(); + if (!connectionRegistry.isConnected(c, t)) { + TransportConnectionWriter w = p.createWriter(c); + if (w != null) + connectionManager.manageOutgoingConnection(c, t, w); + } + } + }); + } + + private void connectToContact(final ContactId c, final DuplexPlugin p) { + ioExecutor.execute(new Runnable() { + @Override + public void run() { + TransportId t = p.getId(); + if (!connectionRegistry.isConnected(c, t)) { + DuplexTransportConnection d = p.createConnection(c); + if (d != null) + connectionManager.manageOutgoingConnection(c, t, d); + } + } + }); + } + + private void pollNow(Plugin p) { // Randomise next polling interval schedule(p, 0, true); } diff --git a/briar-tests/src/org/briarproject/RunAction.java b/briar-tests/src/org/briarproject/RunAction.java new file mode 100644 index 0000000000000000000000000000000000000000..ef547ce189deda0120d635bab425dcd693d8334f --- /dev/null +++ b/briar-tests/src/org/briarproject/RunAction.java @@ -0,0 +1,20 @@ +package org.briarproject; + +import org.hamcrest.Description; +import org.jmock.api.Action; +import org.jmock.api.Invocation; + +public class RunAction implements Action { + + @Override + public Object invoke(Invocation invocation) throws Throwable { + Runnable task = (Runnable) invocation.getParameter(0); + task.run(); + return null; + } + + @Override + public void describeTo(Description description) { + description.appendText("runs a runnable"); + } +} diff --git a/briar-tests/src/org/briarproject/plugins/PluginManagerImplTest.java b/briar-tests/src/org/briarproject/plugins/PluginManagerImplTest.java index 9f094dadbc9858db52b6a4e226e7ca792dcfb5a8..c186a170013628b51c3378d8c30a02a0ed140ac1 100644 --- a/briar-tests/src/org/briarproject/plugins/PluginManagerImplTest.java +++ b/briar-tests/src/org/briarproject/plugins/PluginManagerImplTest.java @@ -1,20 +1,13 @@ package org.briarproject.plugins; import org.briarproject.BriarTestCase; -import org.briarproject.ImmediateExecutor; import org.briarproject.api.TransportId; -import org.briarproject.api.contact.ContactId; -import org.briarproject.api.event.ContactStatusChangedEvent; import org.briarproject.api.event.EventBus; -import org.briarproject.api.event.EventListener; import org.briarproject.api.plugins.ConnectionManager; -import org.briarproject.api.plugins.ConnectionRegistry; import org.briarproject.api.plugins.PluginConfig; -import org.briarproject.api.plugins.TransportConnectionWriter; import org.briarproject.api.plugins.duplex.DuplexPlugin; import org.briarproject.api.plugins.duplex.DuplexPluginCallback; import org.briarproject.api.plugins.duplex.DuplexPluginFactory; -import org.briarproject.api.plugins.duplex.DuplexTransportConnection; import org.briarproject.api.plugins.simplex.SimplexPlugin; import org.briarproject.api.plugins.simplex.SimplexPluginCallback; import org.briarproject.api.plugins.simplex.SimplexPluginFactory; @@ -40,11 +33,8 @@ public class PluginManagerImplTest extends BriarTestCase { final Executor ioExecutor = Executors.newSingleThreadExecutor(); final EventBus eventBus = context.mock(EventBus.class); final PluginConfig pluginConfig = context.mock(PluginConfig.class); - final Poller poller = context.mock(Poller.class); final ConnectionManager connectionManager = context.mock(ConnectionManager.class); - final ConnectionRegistry connectionRegistry = - context.mock(ConnectionRegistry.class); final SettingsManager settingsManager = context.mock(SettingsManager.class); final TransportPropertyManager transportPropertyManager = @@ -108,19 +98,16 @@ public class PluginManagerImplTest extends BriarTestCase { oneOf(duplexFailFactory).createPlugin(with(any( DuplexPluginCallback.class))); will(returnValue(null)); // Failed to create a plugin - // Start listening for events - oneOf(eventBus).addListener(with(any(EventListener.class))); // stop() - // Stop listening for events - oneOf(eventBus).removeListener(with(any(EventListener.class))); // Stop the plugins oneOf(simplexPlugin).stop(); + oneOf(simplexFailPlugin).stop(); oneOf(duplexPlugin).stop(); }}); PluginManagerImpl p = new PluginManagerImpl(ioExecutor, eventBus, - pluginConfig, poller, connectionManager, connectionRegistry, - settingsManager, transportPropertyManager, uiCallback); + pluginConfig, connectionManager, settingsManager, + transportPropertyManager, uiCallback); // Two plugins should be started and stopped p.startService(); @@ -128,139 +115,4 @@ public class PluginManagerImplTest extends BriarTestCase { context.assertIsSatisfied(); } - - @Test - public void testConnectToNewContact() throws Exception { - Mockery context = new Mockery(); - final Executor ioExecutor = new ImmediateExecutor(); - final EventBus eventBus = context.mock(EventBus.class); - final PluginConfig pluginConfig = context.mock(PluginConfig.class); - final Poller poller = context.mock(Poller.class); - final ConnectionManager connectionManager = - context.mock(ConnectionManager.class); - final ConnectionRegistry connectionRegistry = - context.mock(ConnectionRegistry.class); - final SettingsManager settingsManager = - context.mock(SettingsManager.class); - final TransportPropertyManager transportPropertyManager = - context.mock(TransportPropertyManager.class); - final UiCallback uiCallback = context.mock(UiCallback.class); - final TransportConnectionWriter transportConnectionWriter = - context.mock(TransportConnectionWriter.class); - final DuplexTransportConnection duplexTransportConnection = - context.mock(DuplexTransportConnection.class); - - final ContactId contactId = new ContactId(234); - - // Two simplex plugins: one supports polling, the other doesn't - final SimplexPluginFactory simplexFactory = - context.mock(SimplexPluginFactory.class); - final SimplexPlugin simplexPlugin = context.mock(SimplexPlugin.class); - final TransportId simplexId = new TransportId("simplex"); - final SimplexPluginFactory simplexFactory1 = - context.mock(SimplexPluginFactory.class, "simplexFactory1"); - final SimplexPlugin simplexPlugin1 = - context.mock(SimplexPlugin.class, "simplexPlugin1"); - final TransportId simplexId1 = new TransportId("simplex1"); - - // Two duplex plugins: one supports polling, the other doesn't - final DuplexPluginFactory duplexFactory = - context.mock(DuplexPluginFactory.class); - final DuplexPlugin duplexPlugin = context.mock(DuplexPlugin.class); - final TransportId duplexId = new TransportId("duplex"); - final DuplexPluginFactory duplexFactory1 = - context.mock(DuplexPluginFactory.class, "duplexFactory1"); - final DuplexPlugin duplexPlugin1 = - context.mock(DuplexPlugin.class, "duplexPlugin1"); - final TransportId duplexId1 = new TransportId("duplex1"); - - context.checking(new Expectations() {{ - // start() - // First simplex plugin - oneOf(pluginConfig).getSimplexFactories(); - will(returnValue(Arrays.asList(simplexFactory, simplexFactory1))); - oneOf(simplexFactory).getId(); - will(returnValue(simplexId)); - oneOf(simplexFactory).createPlugin(with(any( - SimplexPluginCallback.class))); - will(returnValue(simplexPlugin)); // Created - oneOf(simplexPlugin).start(); - will(returnValue(true)); // Started - // Second simplex plugin - oneOf(simplexFactory1).getId(); - will(returnValue(simplexId1)); - oneOf(simplexFactory1).createPlugin(with(any( - SimplexPluginCallback.class))); - will(returnValue(simplexPlugin1)); // Created - oneOf(simplexPlugin1).start(); - will(returnValue(true)); // Started - // First duplex plugin - oneOf(pluginConfig).getDuplexFactories(); - will(returnValue(Arrays.asList(duplexFactory, duplexFactory1))); - oneOf(duplexFactory).getId(); - will(returnValue(duplexId)); - oneOf(duplexFactory).createPlugin(with(any( - DuplexPluginCallback.class))); - will(returnValue(duplexPlugin)); // Created - oneOf(duplexPlugin).start(); - will(returnValue(true)); // Started - // Second duplex plugin - oneOf(duplexFactory1).getId(); - will(returnValue(duplexId1)); - oneOf(duplexFactory1).createPlugin(with(any( - DuplexPluginCallback.class))); - will(returnValue(duplexPlugin1)); // Created - oneOf(duplexPlugin1).start(); - will(returnValue(true)); // Started - // Start listening for events - oneOf(eventBus).addListener(with(any(EventListener.class))); - // eventOccurred() - // First simplex plugin - oneOf(simplexPlugin).shouldPoll(); - will(returnValue(true)); - oneOf(simplexPlugin).getId(); - will(returnValue(simplexId)); - oneOf(connectionRegistry).isConnected(contactId, simplexId); - will(returnValue(false)); - oneOf(simplexPlugin).createWriter(contactId); - will(returnValue(transportConnectionWriter)); - oneOf(connectionManager).manageOutgoingConnection(contactId, - simplexId, transportConnectionWriter); - // Second simplex plugin - oneOf(simplexPlugin1).shouldPoll(); - will(returnValue(false)); - // First duplex plugin - oneOf(duplexPlugin).shouldPoll(); - will(returnValue(true)); - oneOf(duplexPlugin).getId(); - will(returnValue(duplexId)); - oneOf(connectionRegistry).isConnected(contactId, duplexId); - will(returnValue(false)); - oneOf(duplexPlugin).createConnection(contactId); - will(returnValue(duplexTransportConnection)); - oneOf(connectionManager).manageOutgoingConnection(contactId, - duplexId, duplexTransportConnection); - // Second duplex plugin - oneOf(duplexPlugin1).shouldPoll(); - will(returnValue(false)); - // stop() - // Stop listening for events - oneOf(eventBus).removeListener(with(any(EventListener.class))); - // Stop the plugins - oneOf(simplexPlugin).stop(); - oneOf(simplexPlugin1).stop(); - oneOf(duplexPlugin).stop(); - oneOf(duplexPlugin1).stop(); - }}); - - PluginManagerImpl p = new PluginManagerImpl(ioExecutor, eventBus, - pluginConfig, poller, connectionManager, connectionRegistry, - settingsManager, transportPropertyManager, uiCallback); - - p.startService(); - p.eventOccurred(new ContactStatusChangedEvent(contactId, true)); - p.stopService(); - - context.assertIsSatisfied(); - } } diff --git a/briar-tests/src/org/briarproject/plugins/PollerImplTest.java b/briar-tests/src/org/briarproject/plugins/PollerImplTest.java new file mode 100644 index 0000000000000000000000000000000000000000..0093d85de5ad4cdaadb5ec80731255608fea9382 --- /dev/null +++ b/briar-tests/src/org/briarproject/plugins/PollerImplTest.java @@ -0,0 +1,222 @@ +package org.briarproject.plugins; + +import org.briarproject.BriarTestCase; +import org.briarproject.ImmediateExecutor; +import org.briarproject.RunAction; +import org.briarproject.api.TransportId; +import org.briarproject.api.contact.ContactId; +import org.briarproject.api.event.ConnectionClosedEvent; +import org.briarproject.api.event.ContactStatusChangedEvent; +import org.briarproject.api.event.TransportEnabledEvent; +import org.briarproject.api.plugins.ConnectionManager; +import org.briarproject.api.plugins.ConnectionRegistry; +import org.briarproject.api.plugins.Plugin; +import org.briarproject.api.plugins.PluginManager; +import org.briarproject.api.plugins.TransportConnectionWriter; +import org.briarproject.api.plugins.duplex.DuplexPlugin; +import org.briarproject.api.plugins.duplex.DuplexTransportConnection; +import org.briarproject.api.plugins.simplex.SimplexPlugin; +import org.jmock.Expectations; +import org.jmock.Mockery; +import org.jmock.lib.legacy.ClassImposteriser; +import org.junit.Test; + +import java.security.SecureRandom; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.Executor; +import java.util.concurrent.ScheduledExecutorService; + +import static java.util.concurrent.TimeUnit.MILLISECONDS; + +public class PollerImplTest extends BriarTestCase { + + private final ContactId contactId = new ContactId(234); + + @Test + public void testConnectToNewContact() throws Exception { + Mockery context = new Mockery(); + context.setImposteriser(ClassImposteriser.INSTANCE); + final Executor ioExecutor = new ImmediateExecutor(); + final ScheduledExecutorService scheduler = + context.mock(ScheduledExecutorService.class); + final ConnectionManager connectionManager = + context.mock(ConnectionManager.class); + final ConnectionRegistry connectionRegistry = + context.mock(ConnectionRegistry.class); + final PluginManager pluginManager = context.mock(PluginManager.class); + final SecureRandom random = context.mock(SecureRandom.class); + + // Two simplex plugins: one supports polling, the other doesn't + final SimplexPlugin simplexPlugin = context.mock(SimplexPlugin.class); + final SimplexPlugin simplexPlugin1 = + context.mock(SimplexPlugin.class, "simplexPlugin1"); + final TransportId simplexId1 = new TransportId("simplex1"); + final List<SimplexPlugin> simplexPlugins = Arrays.asList(simplexPlugin, + simplexPlugin1); + final TransportConnectionWriter simplexWriter = + context.mock(TransportConnectionWriter.class); + + // Two duplex plugins: one supports polling, the other doesn't + final DuplexPlugin duplexPlugin = context.mock(DuplexPlugin.class); + final TransportId duplexId = new TransportId("duplex"); + final DuplexPlugin duplexPlugin1 = + context.mock(DuplexPlugin.class, "duplexPlugin1"); + final List<DuplexPlugin> duplexPlugins = Arrays.asList(duplexPlugin, + duplexPlugin1); + final DuplexTransportConnection duplexConnection = + context.mock(DuplexTransportConnection.class); + + context.checking(new Expectations() {{ + // Get the simplex plugins + oneOf(pluginManager).getSimplexPlugins(); + will(returnValue(simplexPlugins)); + // The first plugin doesn't support polling + oneOf(simplexPlugin).shouldPoll(); + will(returnValue(false)); + // The second plugin supports polling + oneOf(simplexPlugin1).shouldPoll(); + will(returnValue(true)); + // Check whether the contact is already connected + oneOf(simplexPlugin1).getId(); + will(returnValue(simplexId1)); + oneOf(connectionRegistry).isConnected(contactId, simplexId1); + will(returnValue(false)); + // Connect to the contact + oneOf(simplexPlugin1).createWriter(contactId); + will(returnValue(simplexWriter)); + // Pass the connection to the connection manager + oneOf(connectionManager).manageOutgoingConnection(contactId, + simplexId1, simplexWriter); + // Get the duplex plugins + oneOf(pluginManager).getDuplexPlugins(); + will(returnValue(duplexPlugins)); + // The first plugin supports polling + oneOf(duplexPlugin).shouldPoll(); + will(returnValue(true)); + // Check whether the contact is already connected + oneOf(duplexPlugin).getId(); + will(returnValue(duplexId)); + oneOf(connectionRegistry).isConnected(contactId, duplexId); + will(returnValue(false)); + // Connect to the contact + oneOf(duplexPlugin).createConnection(contactId); + will(returnValue(duplexConnection)); + // Pass the connection to the connection manager + oneOf(connectionManager).manageOutgoingConnection(contactId, + duplexId, duplexConnection); + // The second plugin doesn't support polling + oneOf(duplexPlugin1).shouldPoll(); + will(returnValue(false)); + }}); + + PollerImpl p = new PollerImpl(ioExecutor, scheduler, connectionManager, + connectionRegistry, pluginManager, random); + + p.eventOccurred(new ContactStatusChangedEvent(contactId, true)); + + context.assertIsSatisfied(); + } + + @Test + public void testReconnectToDisconnectedContact() throws Exception { + Mockery context = new Mockery(); + context.setImposteriser(ClassImposteriser.INSTANCE); + final Executor ioExecutor = new ImmediateExecutor(); + final ScheduledExecutorService scheduler = + context.mock(ScheduledExecutorService.class); + final ConnectionManager connectionManager = + context.mock(ConnectionManager.class); + final ConnectionRegistry connectionRegistry = + context.mock(ConnectionRegistry.class); + final PluginManager pluginManager = context.mock(PluginManager.class); + final SecureRandom random = context.mock(SecureRandom.class); + + final DuplexPlugin plugin = context.mock(DuplexPlugin.class); + final TransportId transportId = new TransportId("id"); + final DuplexTransportConnection duplexConnection = + context.mock(DuplexTransportConnection.class); + + context.checking(new Expectations() {{ + // Get the plugin + oneOf(pluginManager).getPlugin(transportId); + will(returnValue(plugin)); + // The plugin supports polling + oneOf(plugin).shouldPoll(); + will(returnValue(true)); + // Check whether the contact is already connected + oneOf(plugin).getId(); + will(returnValue(transportId)); + oneOf(connectionRegistry).isConnected(contactId, transportId); + will(returnValue(false)); + // Connect to the contact + oneOf(plugin).createConnection(contactId); + will(returnValue(duplexConnection)); + // Pass the connection to the connection manager + oneOf(connectionManager).manageOutgoingConnection(contactId, + transportId, duplexConnection); + }}); + + PollerImpl p = new PollerImpl(ioExecutor, scheduler, connectionManager, + connectionRegistry, pluginManager, random); + + p.eventOccurred(new ConnectionClosedEvent(contactId, transportId, + false)); + + context.assertIsSatisfied(); + } + + @Test + public void testPollWhenTransportIsEnabled() throws Exception { + Mockery context = new Mockery(); + context.setImposteriser(ClassImposteriser.INSTANCE); + final Executor ioExecutor = new ImmediateExecutor(); + final ScheduledExecutorService scheduler = + context.mock(ScheduledExecutorService.class); + final ConnectionManager connectionManager = + context.mock(ConnectionManager.class); + final ConnectionRegistry connectionRegistry = + context.mock(ConnectionRegistry.class); + final PluginManager pluginManager = context.mock(PluginManager.class); + final SecureRandom random = context.mock(SecureRandom.class); + + final Plugin plugin = context.mock(Plugin.class); + final TransportId transportId = new TransportId("id"); + final int pollingInterval = 60 * 1000; + final List<ContactId> connected = Collections.singletonList(contactId); + + context.checking(new Expectations() {{ + allowing(plugin).getId(); + will(returnValue(transportId)); + // Get the plugin + oneOf(pluginManager).getPlugin(transportId); + will(returnValue(plugin)); + // The plugin supports polling + oneOf(plugin).shouldPoll(); + will(returnValue(true)); + // Schedule a polling task immediately + oneOf(scheduler).schedule(with(any(Runnable.class)), with(0L), + with(MILLISECONDS)); + will(new RunAction()); + // Run the polling task + oneOf(plugin).getPollingInterval(); + will(returnValue(pollingInterval)); + oneOf(random).nextDouble(); + will(returnValue(0.5)); + oneOf(scheduler).schedule(with(any(Runnable.class)), + with((long) (pollingInterval * 0.5)), with(MILLISECONDS)); + // Poll the plugin + oneOf(connectionRegistry).getConnectedContacts(transportId); + will(returnValue(connected)); + oneOf(plugin).poll(connected); + }}); + + PollerImpl p = new PollerImpl(ioExecutor, scheduler, connectionManager, + connectionRegistry, pluginManager, random); + + p.eventOccurred(new TransportEnabledEvent(transportId)); + + context.assertIsSatisfied(); + } +} diff --git a/briar-tests/src/org/briarproject/transport/TransportKeyManagerTest.java b/briar-tests/src/org/briarproject/transport/TransportKeyManagerTest.java index bf035fd3c72b8bb221ebb57eda13b97f597fdf03..4a32490c953999232fb0190c05affd658bb85b2e 100644 --- a/briar-tests/src/org/briarproject/transport/TransportKeyManagerTest.java +++ b/briar-tests/src/org/briarproject/transport/TransportKeyManagerTest.java @@ -1,6 +1,7 @@ package org.briarproject.transport; import org.briarproject.BriarTestCase; +import org.briarproject.RunAction; import org.briarproject.TestUtils; import org.briarproject.api.TransportId; import org.briarproject.api.contact.ContactId; @@ -501,19 +502,4 @@ public class TransportKeyManagerTest extends BriarTestCase { description.appendText("encodes a tag"); } } - - private static class RunAction implements Action { - - @Override - public Object invoke(Invocation invocation) throws Throwable { - Runnable task = (Runnable) invocation.getParameter(0); - task.run(); - return null; - } - - @Override - public void describeTo(Description description) { - description.appendText("runs a runnable"); - } - } }