Commit 4a4abd7e authored by Torsten Grote's avatar Torsten Grote

Merge branch '1232-polling-events' into 'master'

Show "connecting" state for pending contacts

See merge request !1129
parents f31b85ac a4a45efd
Pipeline #3514 passed with stage
in 8 minutes and 53 seconds
...@@ -3,7 +3,7 @@ package org.briarproject.bramble.api.contact; ...@@ -3,7 +3,7 @@ package org.briarproject.bramble.api.contact;
public enum PendingContactState { public enum PendingContactState {
WAITING_FOR_CONNECTION, WAITING_FOR_CONNECTION,
CONNECTED, CONNECTING,
ADDING_CONTACT, ADDING_CONTACT,
FAILED FAILED
} }
package org.briarproject.bramble.api.rendezvous;
import org.briarproject.bramble.api.contact.PendingContactId;
/**
* Interface for the poller that makes rendezvous connections to pending
* contacts.
*/
public interface RendezvousPoller {
long getLastPollTime(PendingContactId p);
}
...@@ -3,23 +3,34 @@ package org.briarproject.bramble.api.rendezvous.event; ...@@ -3,23 +3,34 @@ package org.briarproject.bramble.api.rendezvous.event;
import org.briarproject.bramble.api.contact.PendingContactId; import org.briarproject.bramble.api.contact.PendingContactId;
import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.plugin.TransportId;
import java.util.Collection;
import javax.annotation.concurrent.Immutable; import javax.annotation.concurrent.Immutable;
/** /**
* An event that is broadcast when a rendezvous with a pending contact fails. * An event that is broadcast when a transport plugin is polled for connections
* to one or more pending contacts.
*/ */
@Immutable @Immutable
@NotNullByDefault @NotNullByDefault
public class RendezvousFailedEvent extends Event { public class RendezvousPollEvent extends Event {
private final TransportId transportId;
private final Collection<PendingContactId> pendingContacts;
private final PendingContactId pendingContactId; public RendezvousPollEvent(TransportId transportId,
Collection<PendingContactId> pendingContacts) {
this.transportId = transportId;
this.pendingContacts = pendingContacts;
}
public RendezvousFailedEvent(PendingContactId pendingContactId) { public TransportId getTransportId() {
this.pendingContactId = pendingContactId; return transportId;
} }
public PendingContactId getPendingContactId() { public Collection<PendingContactId> getPendingContacts() {
return pendingContactId; return pendingContacts;
} }
} }
...@@ -17,7 +17,6 @@ import org.briarproject.bramble.api.db.DbException; ...@@ -17,7 +17,6 @@ import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.NoSuchContactException; import org.briarproject.bramble.api.db.NoSuchContactException;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.event.Event; import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.event.EventListener; import org.briarproject.bramble.api.event.EventListener;
import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId; import org.briarproject.bramble.api.identity.AuthorId;
...@@ -25,25 +24,20 @@ import org.briarproject.bramble.api.identity.AuthorInfo; ...@@ -25,25 +24,20 @@ import org.briarproject.bramble.api.identity.AuthorInfo;
import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import org.briarproject.bramble.api.rendezvous.event.RendezvousConnectionClosedEvent;
import org.briarproject.bramble.api.rendezvous.event.RendezvousConnectionOpenedEvent;
import org.briarproject.bramble.api.rendezvous.event.RendezvousFailedEvent;
import org.briarproject.bramble.api.transport.KeyManager; import org.briarproject.bramble.api.transport.KeyManager;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import javax.annotation.concurrent.ThreadSafe; import javax.annotation.concurrent.ThreadSafe;
import javax.inject.Inject; import javax.inject.Inject;
import static org.briarproject.bramble.api.contact.PendingContactState.ADDING_CONTACT;
import static org.briarproject.bramble.api.contact.PendingContactState.FAILED;
import static org.briarproject.bramble.api.contact.PendingContactState.WAITING_FOR_CONNECTION; import static org.briarproject.bramble.api.contact.PendingContactState.WAITING_FOR_CONNECTION;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.OURSELVES; import static org.briarproject.bramble.api.identity.AuthorInfo.Status.OURSELVES;
...@@ -60,23 +54,20 @@ class ContactManagerImpl implements ContactManager, EventListener { ...@@ -60,23 +54,20 @@ class ContactManagerImpl implements ContactManager, EventListener {
private final KeyManager keyManager; private final KeyManager keyManager;
private final IdentityManager identityManager; private final IdentityManager identityManager;
private final PendingContactFactory pendingContactFactory; private final PendingContactFactory pendingContactFactory;
private final EventBus eventBus;
private final List<ContactHook> hooks = new CopyOnWriteArrayList<>(); private final List<ContactHook> hooks = new CopyOnWriteArrayList<>();
private final ConcurrentMap<PendingContactId, PendingContactState> states = private final Map<PendingContactId, PendingContactState> states =
new ConcurrentHashMap<>(); new ConcurrentHashMap<>();
@Inject @Inject
ContactManagerImpl(DatabaseComponent db, ContactManagerImpl(DatabaseComponent db,
KeyManager keyManager, KeyManager keyManager,
IdentityManager identityManager, IdentityManager identityManager,
PendingContactFactory pendingContactFactory, PendingContactFactory pendingContactFactory) {
EventBus eventBus) {
this.db = db; this.db = db;
this.keyManager = keyManager; this.keyManager = keyManager;
this.identityManager = identityManager; this.identityManager = identityManager;
this.pendingContactFactory = pendingContactFactory; this.pendingContactFactory = pendingContactFactory;
this.eventBus = eventBus;
} }
@Override @Override
...@@ -156,7 +147,7 @@ class ContactManagerImpl implements ContactManager, EventListener { ...@@ -156,7 +147,7 @@ class ContactManagerImpl implements ContactManager, EventListener {
} finally { } finally {
db.endTransaction(txn); db.endTransaction(txn);
} }
setState(p.getId(), WAITING_FOR_CONNECTION); states.put(p.getId(), WAITING_FOR_CONNECTION);
return p; return p;
} }
...@@ -286,46 +277,10 @@ class ContactManagerImpl implements ContactManager, EventListener { ...@@ -286,46 +277,10 @@ class ContactManagerImpl implements ContactManager, EventListener {
@Override @Override
public void eventOccurred(Event e) { public void eventOccurred(Event e) {
if (e instanceof RendezvousConnectionOpenedEvent) { if (e instanceof PendingContactStateChangedEvent) {
RendezvousConnectionOpenedEvent r = PendingContactStateChangedEvent p =
(RendezvousConnectionOpenedEvent) e; (PendingContactStateChangedEvent) e;
setStateConnected(r.getPendingContactId()); states.put(p.getId(), p.getPendingContactState());
} else if (e instanceof RendezvousConnectionClosedEvent) {
RendezvousConnectionClosedEvent r =
(RendezvousConnectionClosedEvent) e;
// We're only interested in failures - if the rendezvous succeeds
// the pending contact will be removed
if (!r.isSuccess()) setStateDisconnected(r.getPendingContactId());
} else if (e instanceof RendezvousFailedEvent) {
RendezvousFailedEvent r = (RendezvousFailedEvent) e;
setState(r.getPendingContactId(), FAILED);
}
}
/**
* Sets the state of the given pending contact and broadcasts an event.
*/
private void setState(PendingContactId p, PendingContactState state) {
states.put(p, state);
eventBus.broadcast(new PendingContactStateChangedEvent(p, state));
}
private void setStateConnected(PendingContactId p) {
// Set the state to ADDING_CONTACT if there's no current state or the
// current state is WAITING_FOR_CONNECTION
if (states.putIfAbsent(p, ADDING_CONTACT) == null ||
states.replace(p, WAITING_FOR_CONNECTION, ADDING_CONTACT)) {
eventBus.broadcast(new PendingContactStateChangedEvent(p,
ADDING_CONTACT));
}
}
private void setStateDisconnected(PendingContactId p) {
// Set the state to WAITING_FOR_CONNECTION if the current state is
// ADDING_CONTACT
if (states.replace(p, ADDING_CONTACT, WAITING_FOR_CONNECTION)) {
eventBus.broadcast(new PendingContactStateChangedEvent(p,
WAITING_FOR_CONNECTION));
} }
} }
} }
...@@ -2,6 +2,7 @@ package org.briarproject.bramble.rendezvous; ...@@ -2,6 +2,7 @@ package org.briarproject.bramble.rendezvous;
import org.briarproject.bramble.api.event.EventBus; import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.lifecycle.LifecycleManager; import org.briarproject.bramble.api.lifecycle.LifecycleManager;
import org.briarproject.bramble.api.rendezvous.RendezvousPoller;
import javax.inject.Inject; import javax.inject.Inject;
import javax.inject.Singleton; import javax.inject.Singleton;
......
package org.briarproject.bramble.rendezvous;
/**
* Empty interface for injecting the rendezvous poller.
*/
interface RendezvousPoller {
}
...@@ -4,8 +4,10 @@ import org.briarproject.bramble.PoliteExecutor; ...@@ -4,8 +4,10 @@ import org.briarproject.bramble.PoliteExecutor;
import org.briarproject.bramble.api.Pair; import org.briarproject.bramble.api.Pair;
import org.briarproject.bramble.api.contact.PendingContact; import org.briarproject.bramble.api.contact.PendingContact;
import org.briarproject.bramble.api.contact.PendingContactId; import org.briarproject.bramble.api.contact.PendingContactId;
import org.briarproject.bramble.api.contact.PendingContactState;
import org.briarproject.bramble.api.contact.event.PendingContactAddedEvent; import org.briarproject.bramble.api.contact.event.PendingContactAddedEvent;
import org.briarproject.bramble.api.contact.event.PendingContactRemovedEvent; import org.briarproject.bramble.api.contact.event.PendingContactRemovedEvent;
import org.briarproject.bramble.api.contact.event.PendingContactStateChangedEvent;
import org.briarproject.bramble.api.crypto.KeyPair; import org.briarproject.bramble.api.crypto.KeyPair;
import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.crypto.TransportCrypto; import org.briarproject.bramble.api.crypto.TransportCrypto;
...@@ -34,7 +36,10 @@ import org.briarproject.bramble.api.plugin.event.TransportEnabledEvent; ...@@ -34,7 +36,10 @@ import org.briarproject.bramble.api.plugin.event.TransportEnabledEvent;
import org.briarproject.bramble.api.properties.TransportProperties; import org.briarproject.bramble.api.properties.TransportProperties;
import org.briarproject.bramble.api.rendezvous.KeyMaterialSource; import org.briarproject.bramble.api.rendezvous.KeyMaterialSource;
import org.briarproject.bramble.api.rendezvous.RendezvousEndpoint; import org.briarproject.bramble.api.rendezvous.RendezvousEndpoint;
import org.briarproject.bramble.api.rendezvous.event.RendezvousFailedEvent; import org.briarproject.bramble.api.rendezvous.RendezvousPoller;
import org.briarproject.bramble.api.rendezvous.event.RendezvousConnectionClosedEvent;
import org.briarproject.bramble.api.rendezvous.event.RendezvousConnectionOpenedEvent;
import org.briarproject.bramble.api.rendezvous.event.RendezvousPollEvent;
import org.briarproject.bramble.api.system.Clock; import org.briarproject.bramble.api.system.Clock;
import org.briarproject.bramble.api.system.Scheduler; import org.briarproject.bramble.api.system.Scheduler;
...@@ -45,6 +50,7 @@ import java.util.HashMap; ...@@ -45,6 +50,7 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Map.Entry; import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
...@@ -58,6 +64,9 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS; ...@@ -58,6 +64,9 @@ import static java.util.concurrent.TimeUnit.MILLISECONDS;
import static java.util.logging.Level.INFO; import static java.util.logging.Level.INFO;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger; import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.api.contact.PendingContactState.ADDING_CONTACT;
import static org.briarproject.bramble.api.contact.PendingContactState.FAILED;
import static org.briarproject.bramble.api.contact.PendingContactState.WAITING_FOR_CONNECTION;
import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNull; import static org.briarproject.bramble.api.nullsafety.NullSafety.requireNull;
import static org.briarproject.bramble.rendezvous.RendezvousConstants.POLLING_INTERVAL_MS; import static org.briarproject.bramble.rendezvous.RendezvousConstants.POLLING_INTERVAL_MS;
import static org.briarproject.bramble.rendezvous.RendezvousConstants.RENDEZVOUS_TIMEOUT_MS; import static org.briarproject.bramble.rendezvous.RendezvousConstants.RENDEZVOUS_TIMEOUT_MS;
...@@ -81,6 +90,9 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener { ...@@ -81,6 +90,9 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
private final Clock clock; private final Clock clock;
private final AtomicBoolean used = new AtomicBoolean(false); private final AtomicBoolean used = new AtomicBoolean(false);
private final Map<PendingContactId, Long> lastPollTimes =
new ConcurrentHashMap<>();
// Executor that runs one task at a time // Executor that runs one task at a time
private final Executor worker; private final Executor worker;
// The following fields are only accessed on the worker // The following fields are only accessed on the worker
...@@ -113,6 +125,12 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener { ...@@ -113,6 +125,12 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
worker = new PoliteExecutor("RendezvousPoller", ioExecutor, 1); worker = new PoliteExecutor("RendezvousPoller", ioExecutor, 1);
} }
@Override
public long getLastPollTime(PendingContactId p) {
Long time = lastPollTimes.get(p);
return time == null ? 0 : time;
}
@Override @Override
public void startService() throws ServiceException { public void startService() throws ServiceException {
if (used.getAndSet(true)) throw new IllegalStateException(); if (used.getAndSet(true)) throw new IllegalStateException();
...@@ -140,8 +158,10 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener { ...@@ -140,8 +158,10 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
private void addPendingContact(PendingContact p) { private void addPendingContact(PendingContact p) {
long now = clock.currentTimeMillis(); long now = clock.currentTimeMillis();
long expiry = p.getTimestamp() + RENDEZVOUS_TIMEOUT_MS; long expiry = p.getTimestamp() + RENDEZVOUS_TIMEOUT_MS;
if (expiry <= now) { if (expiry > now) {
eventBus.broadcast(new RendezvousFailedEvent(p.getId())); broadcastState(p.getId(), WAITING_FOR_CONNECTION);
} else {
broadcastState(p.getId(), FAILED);
return; return;
} }
try { try {
...@@ -168,6 +188,10 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener { ...@@ -168,6 +188,10 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
} }
} }
private void broadcastState(PendingContactId p, PendingContactState state) {
eventBus.broadcast(new PendingContactStateChangedEvent(p, state));
}
@Nullable @Nullable
private RendezvousEndpoint createEndpoint(DuplexPlugin plugin, private RendezvousEndpoint createEndpoint(DuplexPlugin plugin,
PendingContactId p, CryptoState cs) { PendingContactId p, CryptoState cs) {
...@@ -195,7 +219,7 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener { ...@@ -195,7 +219,7 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
} }
for (PendingContactId p : expired) { for (PendingContactId p : expired) {
removePendingContact(p); removePendingContact(p);
eventBus.broadcast(new RendezvousFailedEvent(p)); broadcastState(p, FAILED);
} }
} }
...@@ -203,6 +227,7 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener { ...@@ -203,6 +227,7 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
private void removePendingContact(PendingContactId p) { private void removePendingContact(PendingContactId p) {
// We can come here twice if a pending contact expires and is removed // We can come here twice if a pending contact expires and is removed
if (cryptoStates.remove(p) == null) return; if (cryptoStates.remove(p) == null) return;
lastPollTimes.remove(p);
for (PluginState ps : pluginStates.values()) { for (PluginState ps : pluginStates.values()) {
RendezvousEndpoint endpoint = ps.endpoints.remove(p); RendezvousEndpoint endpoint = ps.endpoints.remove(p);
if (endpoint != null) tryToClose(endpoint, LOG, INFO); if (endpoint != null) tryToClose(endpoint, LOG, INFO);
...@@ -211,16 +236,22 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener { ...@@ -211,16 +236,22 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
// Worker // Worker
private void poll(PluginState ps) { private void poll(PluginState ps) {
if (ps.endpoints.isEmpty()) return;
TransportId t = ps.plugin.getId();
List<Pair<TransportProperties, ConnectionHandler>> properties = List<Pair<TransportProperties, ConnectionHandler>> properties =
new ArrayList<>(); new ArrayList<>();
for (Entry<PendingContactId, RendezvousEndpoint> e : for (Entry<PendingContactId, RendezvousEndpoint> e :
ps.endpoints.entrySet()) { ps.endpoints.entrySet()) {
TransportProperties props = TransportProperties props =
e.getValue().getRemoteTransportProperties(); e.getValue().getRemoteTransportProperties();
Handler h = new Handler(e.getKey(), ps.plugin.getId(), false); Handler h = new Handler(e.getKey(), t, false);
properties.add(new Pair<>(props, h)); properties.add(new Pair<>(props, h));
} }
if (!properties.isEmpty()) ps.plugin.poll(properties); List<PendingContactId> polled = new ArrayList<>(ps.endpoints.keySet());
long now = clock.currentTimeMillis();
for (PendingContactId p : polled) lastPollTimes.put(p, now);
eventBus.broadcast(new RendezvousPollEvent(t, polled));
ps.plugin.poll(properties);
} }
@Override @Override
...@@ -241,6 +272,14 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener { ...@@ -241,6 +272,14 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
} else if (e instanceof TransportDisabledEvent) { } else if (e instanceof TransportDisabledEvent) {
TransportDisabledEvent t = (TransportDisabledEvent) e; TransportDisabledEvent t = (TransportDisabledEvent) e;
removeTransportAsync(t.getTransportId()); removeTransportAsync(t.getTransportId());
} else if (e instanceof RendezvousConnectionOpenedEvent) {
RendezvousConnectionOpenedEvent r =
(RendezvousConnectionOpenedEvent) e;
connectionOpenedAsync(r.getPendingContactId());
} else if (e instanceof RendezvousConnectionClosedEvent) {
RendezvousConnectionClosedEvent r =
(RendezvousConnectionClosedEvent) e;
if (!r.isSuccess()) connectionFailedAsync(r.getPendingContactId());
} }
} }
...@@ -257,9 +296,13 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener { ...@@ -257,9 +296,13 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
for (PluginState ps : pluginStates.values()) { for (PluginState ps : pluginStates.values()) {
RendezvousEndpoint endpoint = ps.endpoints.get(p); RendezvousEndpoint endpoint = ps.endpoints.get(p);
if (endpoint != null) { if (endpoint != null) {
TransportId t = ps.plugin.getId();
TransportProperties props = TransportProperties props =
endpoint.getRemoteTransportProperties(); endpoint.getRemoteTransportProperties();
Handler h = new Handler(p, ps.plugin.getId(), false); Handler h = new Handler(p, t, false);
lastPollTimes.put(p, clock.currentTimeMillis());
eventBus.broadcast(
new RendezvousPollEvent(t, singletonList(p)));
ps.plugin.poll(singletonList(new Pair<>(props, h))); ps.plugin.poll(singletonList(new Pair<>(props, h)));
} }
} }
...@@ -307,6 +350,29 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener { ...@@ -307,6 +350,29 @@ class RendezvousPollerImpl implements RendezvousPoller, Service, EventListener {
} }
} }
@EventExecutor
private void connectionOpenedAsync(PendingContactId p) {
worker.execute(() -> connectionOpened(p));
}
// Worker
private void connectionOpened(PendingContactId p) {
// Check that the pending contact hasn't expired
if (cryptoStates.containsKey(p)) broadcastState(p, ADDING_CONTACT);
}
@EventExecutor
private void connectionFailedAsync(PendingContactId p) {
worker.execute(() -> connectionFailed(p));
}
// Worker
private void connectionFailed(PendingContactId p) {
// Check that the pending contact hasn't expired
if (cryptoStates.containsKey(p))
broadcastState(p, WAITING_FOR_CONNECTION);
}
private static class PluginState { private static class PluginState {
private final DuplexPlugin plugin; private final DuplexPlugin plugin;
......
...@@ -5,26 +5,20 @@ import org.briarproject.bramble.api.contact.Contact; ...@@ -5,26 +5,20 @@ import org.briarproject.bramble.api.contact.Contact;
import org.briarproject.bramble.api.contact.ContactId; import org.briarproject.bramble.api.contact.ContactId;
import org.briarproject.bramble.api.contact.PendingContact; import org.briarproject.bramble.api.contact.PendingContact;
import org.briarproject.bramble.api.contact.PendingContactState; import org.briarproject.bramble.api.contact.PendingContactState;
import org.briarproject.bramble.api.contact.event.PendingContactStateChangedEvent;
import org.briarproject.bramble.api.crypto.KeyPair; import org.briarproject.bramble.api.crypto.KeyPair;
import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DatabaseComponent; import org.briarproject.bramble.api.db.DatabaseComponent;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
import org.briarproject.bramble.api.db.NoSuchContactException; import org.briarproject.bramble.api.db.NoSuchContactException;
import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.db.Transaction;
import org.briarproject.bramble.api.event.EventBus;
import org.briarproject.bramble.api.identity.Author; import org.briarproject.bramble.api.identity.Author;
import org.briarproject.bramble.api.identity.AuthorId; import org.briarproject.bramble.api.identity.AuthorId;
import org.briarproject.bramble.api.identity.AuthorInfo; import org.briarproject.bramble.api.identity.AuthorInfo;
import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.identity.IdentityManager;
import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.identity.LocalAuthor;
import org.briarproject.bramble.api.rendezvous.event.RendezvousConnectionClosedEvent;
import org.briarproject.bramble.api.rendezvous.event.RendezvousConnectionOpenedEvent;
import org.briarproject.bramble.api.rendezvous.event.RendezvousFailedEvent;
import org.briarproject.bramble.api.transport.KeyManager; import org.briarproject.bramble.api.transport.KeyManager;
import org.briarproject.bramble.test.BrambleMockTestCase; import org.briarproject.bramble.test.BrambleMockTestCase;
import org.briarproject.bramble.test.DbExpectations; import org.briarproject.bramble.test.DbExpectations;
import org.briarproject.bramble.test.PredicateMatcher;
import org.jmock.Expectations; import org.jmock.Expectations;
import org.junit.Before; import org.junit.Before;
import org.junit.Test; import org.junit.Test;
...@@ -35,8 +29,6 @@ import java.util.Random; ...@@ -35,8 +29,6 @@ import java.util.Random;
import static java.util.Collections.emptyList; import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;
import static org.briarproject.bramble.api.contact.HandshakeLinkConstants.BASE32_LINK_BYTES; import static org.briarproject.bramble.api.contact.HandshakeLinkConstants.BASE32_LINK_BYTES;
import static org.briarproject.bramble.api.contact.PendingContactState.ADDING_CONTACT;
import static org.briarproject.bramble.api.contact.PendingContactState.FAILED;
import static org.briarproject.bramble.api.contact.PendingContactState.WAITING_FOR_CONNECTION; import static org.briarproject.bramble.api.contact.PendingContactState.WAITING_FOR_CONNECTION;
import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH; import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.OURSELVES; import static org.briarproject.bramble.api.identity.AuthorInfo.Status.OURSELVES;
...@@ -65,7 +57,6 @@ public class ContactManagerImplTest extends BrambleMockTestCase { ...@@ -65,7 +57,6 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
context.mock(IdentityManager.class); context.mock(IdentityManager.class);
private final PendingContactFactory pendingContactFactory = private final PendingContactFactory pendingContactFactory =
context.mock(PendingContactFactory.class); context.mock(PendingContactFactory.class);
private final EventBus eventBus = context.mock(EventBus.class);
private final Author remote = getAuthor(); private final Author remote = getAuthor();
private final LocalAuthor localAuthor = getLocalAuthor(); private final LocalAuthor localAuthor = getLocalAuthor();
...@@ -85,7 +76,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase { ...@@ -85,7 +76,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
@Before @Before
public void setUp() { public void setUp() {
contactManager = new ContactManagerImpl(db, keyManager, contactManager = new ContactManagerImpl(db, keyManager,
identityManager, pendingContactFactory, eventBus); identityManager, pendingContactFactory);
} }
@Test @Test
...@@ -328,143 +319,4 @@ public class ContactManagerImplTest extends BrambleMockTestCase { ...@@ -328,143 +319,4 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
assertEquals(WAITING_FOR_CONNECTION, pair.getSecond()); assertEquals(WAITING_FOR_CONNECTION, pair.getSecond());
} }
@Test
public void testPendingContactExpiresBeforeConnection() {
// The pending contact expires - the FAILED state is broadcast
context.checking(new Expectations() {{
oneOf(eventBus).broadcast(with(new PredicateMatcher<>(
PendingContactStateChangedEvent.class, e ->
e.getPendingContactState() == FAILED)));
}});
contactManager.eventOccurred(new RendezvousFailedEvent(
pendingContact.getId()));
context.assertIsSatisfied();
// A rendezvous connection is opened - no state is broadcast
contactManager.eventOccurred(new RendezvousConnectionOpenedEvent(
pendingContact.getId()));
context.assertIsSatisfied();
// The rendezvous connection fails - no state is broadcast
contactManager.eventOccurred(new RendezvousConnectionClosedEvent(
pendingContact.getId(), false));
}
@Test
public void testPendingContactExpiresDuringFailedConnection() {
// A rendezvous connection is opened - the ADDING_CONTACT state is
// broadcast
context.checking(new Expectations() {{
oneOf(eventBus).broadcast(with(new PredicateMatcher<>(
PendingContactStateChangedEvent.class, e ->
e.getPendingContactState() == ADDING_CONTACT)));
}});
contactManager.eventOccurred(new RendezvousConnectionOpenedEvent(
pendingContact.getId()));
context.assertIsSatisfied();
// The pending contact expires - the FAILED state is broadcast
context.checking(new Expectations() {{
oneOf(eventBus).broadcast(with(new PredicateMatcher<>(
PendingContactStateChangedEvent.class, e ->
e.getPendingContactState() == FAILED)));
}});
contactManager.eventOccurred(new RendezvousFailedEvent(
pendingContact.getId()));
context.assertIsSatisfied();
// The rendezvous connection fails - no state is broadcast
contactManager.eventOccurred(new RendezvousConnectionClosedEvent(
pendingContact.getId(), false));