mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-14 03:39:05 +01:00
Merge branch '1232-pending-contact-states' into 'master'
Add ContactManager support for pending contact states See merge request briar/briar!1122
This commit is contained in:
@@ -8,6 +8,7 @@ import org.briarproject.bramble.api.contact.ContactManager;
|
||||
import org.briarproject.bramble.api.contact.PendingContact;
|
||||
import org.briarproject.bramble.api.contact.PendingContactId;
|
||||
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.PublicKey;
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
@@ -15,24 +16,34 @@ import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.NoSuchContactException;
|
||||
import org.briarproject.bramble.api.db.Transaction;
|
||||
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.identity.Author;
|
||||
import org.briarproject.bramble.api.identity.AuthorId;
|
||||
import org.briarproject.bramble.api.identity.AuthorInfo;
|
||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||
import org.briarproject.bramble.api.identity.LocalAuthor;
|
||||
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 java.security.GeneralSecurityException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentMap;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.concurrent.ThreadSafe;
|
||||
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.identity.AuthorConstants.MAX_AUTHOR_NAME_LENGTH;
|
||||
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.OURSELVES;
|
||||
@@ -43,24 +54,29 @@ import static org.briarproject.bramble.util.StringUtils.toUtf8;
|
||||
|
||||
@ThreadSafe
|
||||
@NotNullByDefault
|
||||
class ContactManagerImpl implements ContactManager {
|
||||
class ContactManagerImpl implements ContactManager, EventListener {
|
||||
|
||||
private final DatabaseComponent db;
|
||||
private final KeyManager keyManager;
|
||||
private final IdentityManager identityManager;
|
||||
private final PendingContactFactory pendingContactFactory;
|
||||
private final EventBus eventBus;
|
||||
|
||||
private final List<ContactHook> hooks;
|
||||
private final List<ContactHook> hooks = new CopyOnWriteArrayList<>();
|
||||
private final ConcurrentMap<PendingContactId, PendingContactState> states =
|
||||
new ConcurrentHashMap<>();
|
||||
|
||||
@Inject
|
||||
ContactManagerImpl(DatabaseComponent db, KeyManager keyManager,
|
||||
ContactManagerImpl(DatabaseComponent db,
|
||||
KeyManager keyManager,
|
||||
IdentityManager identityManager,
|
||||
PendingContactFactory pendingContactFactory) {
|
||||
PendingContactFactory pendingContactFactory,
|
||||
EventBus eventBus) {
|
||||
this.db = db;
|
||||
this.keyManager = keyManager;
|
||||
this.identityManager = identityManager;
|
||||
this.pendingContactFactory = pendingContactFactory;
|
||||
hooks = new CopyOnWriteArrayList<>();
|
||||
this.eventBus = eventBus;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -86,6 +102,7 @@ class ContactManagerImpl implements ContactManager {
|
||||
throws DbException, GeneralSecurityException {
|
||||
PendingContact pendingContact = db.getPendingContact(txn, p);
|
||||
db.removePendingContact(txn, p);
|
||||
states.remove(p);
|
||||
PublicKey theirPublicKey = pendingContact.getPublicKey();
|
||||
ContactId c =
|
||||
db.addContact(txn, remote, local, theirPublicKey, verified);
|
||||
@@ -139,6 +156,7 @@ class ContactManagerImpl implements ContactManager {
|
||||
} finally {
|
||||
db.endTransaction(txn);
|
||||
}
|
||||
setState(p.getId(), WAITING_FOR_CONNECTION);
|
||||
return p;
|
||||
}
|
||||
|
||||
@@ -156,7 +174,9 @@ class ContactManagerImpl implements ContactManager {
|
||||
List<Pair<PendingContact, PendingContactState>> pairs =
|
||||
new ArrayList<>(pendingContacts.size());
|
||||
for (PendingContact p : pendingContacts) {
|
||||
pairs.add(new Pair<>(p, WAITING_FOR_CONNECTION)); // TODO
|
||||
PendingContactState state = states.get(p.getId());
|
||||
if (state == null) state = WAITING_FOR_CONNECTION;
|
||||
pairs.add(new Pair<>(p, state));
|
||||
}
|
||||
return pairs;
|
||||
}
|
||||
@@ -164,6 +184,7 @@ class ContactManagerImpl implements ContactManager {
|
||||
@Override
|
||||
public void removePendingContact(PendingContactId p) throws DbException {
|
||||
db.transaction(false, txn -> db.removePendingContact(txn, p));
|
||||
states.remove(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -263,4 +284,48 @@ class ContactManagerImpl implements ContactManager {
|
||||
else return new AuthorInfo(UNVERIFIED, c.getAlias());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void eventOccurred(Event e) {
|
||||
if (e instanceof RendezvousConnectionOpenedEvent) {
|
||||
RendezvousConnectionOpenedEvent r =
|
||||
(RendezvousConnectionOpenedEvent) e;
|
||||
setStateConnected(r.getPendingContactId());
|
||||
} 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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package org.briarproject.bramble.contact;
|
||||
import org.briarproject.bramble.api.contact.ContactExchangeManager;
|
||||
import org.briarproject.bramble.api.contact.ContactManager;
|
||||
import org.briarproject.bramble.api.contact.HandshakeManager;
|
||||
import org.briarproject.bramble.api.event.EventBus;
|
||||
|
||||
import javax.inject.Inject;
|
||||
import javax.inject.Singleton;
|
||||
@@ -20,7 +21,9 @@ public class ContactModule {
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
ContactManager provideContactManager(ContactManagerImpl contactManager) {
|
||||
ContactManager provideContactManager(EventBus eventBus,
|
||||
ContactManagerImpl contactManager) {
|
||||
eventBus.addListener(contactManager);
|
||||
return contactManager;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,25 +1,32 @@
|
||||
package org.briarproject.bramble.contact;
|
||||
|
||||
import org.briarproject.bramble.api.Pair;
|
||||
import org.briarproject.bramble.api.contact.Contact;
|
||||
import org.briarproject.bramble.api.contact.ContactId;
|
||||
import org.briarproject.bramble.api.contact.ContactManager;
|
||||
import org.briarproject.bramble.api.contact.PendingContact;
|
||||
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.PrivateKey;
|
||||
import org.briarproject.bramble.api.crypto.PublicKey;
|
||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
||||
import org.briarproject.bramble.api.db.DatabaseComponent;
|
||||
import org.briarproject.bramble.api.db.DbException;
|
||||
import org.briarproject.bramble.api.db.NoSuchContactException;
|
||||
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.AuthorId;
|
||||
import org.briarproject.bramble.api.identity.AuthorInfo;
|
||||
import org.briarproject.bramble.api.identity.IdentityManager;
|
||||
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.test.BrambleMockTestCase;
|
||||
import org.briarproject.bramble.test.DbExpectations;
|
||||
import org.briarproject.bramble.test.PredicateMatcher;
|
||||
import org.jmock.Expectations;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -28,6 +35,9 @@ import java.util.Random;
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Collections.singletonList;
|
||||
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.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.UNKNOWN;
|
||||
@@ -38,6 +48,7 @@ import static org.briarproject.bramble.test.TestUtils.getAgreementPublicKey;
|
||||
import static org.briarproject.bramble.test.TestUtils.getAuthor;
|
||||
import static org.briarproject.bramble.test.TestUtils.getContact;
|
||||
import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
|
||||
import static org.briarproject.bramble.test.TestUtils.getPendingContact;
|
||||
import static org.briarproject.bramble.test.TestUtils.getRandomId;
|
||||
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
||||
import static org.briarproject.bramble.util.StringUtils.getRandomBase32String;
|
||||
@@ -54,24 +65,31 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
||||
context.mock(IdentityManager.class);
|
||||
private final PendingContactFactory pendingContactFactory =
|
||||
context.mock(PendingContactFactory.class);
|
||||
private final ContactManager contactManager;
|
||||
private final EventBus eventBus = context.mock(EventBus.class);
|
||||
|
||||
private final Author remote = getAuthor();
|
||||
private final LocalAuthor localAuthor = getLocalAuthor();
|
||||
private final AuthorId local = localAuthor.getId();
|
||||
private final boolean verified = false, active = true;
|
||||
private final Contact contact = getContact(remote, local, verified);
|
||||
private final ContactId contactId = contact.getId();
|
||||
private final KeyPair handshakeKeyPair =
|
||||
new KeyPair(getAgreementPublicKey(), getAgreementPrivateKey());
|
||||
private final PendingContact pendingContact = getPendingContact();
|
||||
private final SecretKey rootKey = getSecretKey();
|
||||
private final long timestamp = System.currentTimeMillis();
|
||||
private final boolean alice = new Random().nextBoolean();
|
||||
|
||||
public ContactManagerImplTest() {
|
||||
private ContactManagerImpl contactManager;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
contactManager = new ContactManagerImpl(db, keyManager,
|
||||
identityManager, pendingContactFactory);
|
||||
identityManager, pendingContactFactory, eventBus);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testAddContact() throws Exception {
|
||||
SecretKey rootKey = getSecretKey();
|
||||
long timestamp = System.currentTimeMillis();
|
||||
boolean alice = new Random().nextBoolean();
|
||||
Transaction txn = new Transaction(null, false);
|
||||
|
||||
context.checking(new DbExpectations() {{
|
||||
@@ -91,6 +109,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
||||
@Test
|
||||
public void testGetContact() throws Exception {
|
||||
Transaction txn = new Transaction(null, true);
|
||||
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||
oneOf(db).getContact(txn, contactId);
|
||||
@@ -104,6 +123,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
||||
public void testGetContactByAuthor() throws Exception {
|
||||
Transaction txn = new Transaction(null, true);
|
||||
Collection<Contact> contacts = singletonList(contact);
|
||||
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||
oneOf(db).getContactsByAuthorId(txn, remote.getId());
|
||||
@@ -116,6 +136,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
||||
@Test(expected = NoSuchContactException.class)
|
||||
public void testGetContactByUnknownAuthor() throws Exception {
|
||||
Transaction txn = new Transaction(null, true);
|
||||
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||
oneOf(db).getContactsByAuthorId(txn, remote.getId());
|
||||
@@ -129,6 +150,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
||||
public void testGetContactByUnknownLocalAuthor() throws Exception {
|
||||
Transaction txn = new Transaction(null, true);
|
||||
Collection<Contact> contacts = singletonList(contact);
|
||||
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||
oneOf(db).getContactsByAuthorId(txn, remote.getId());
|
||||
@@ -142,6 +164,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
||||
public void testGetContacts() throws Exception {
|
||||
Collection<Contact> contacts = singletonList(contact);
|
||||
Transaction txn = new Transaction(null, true);
|
||||
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||
oneOf(db).getContacts(txn);
|
||||
@@ -154,6 +177,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
||||
@Test
|
||||
public void testRemoveContact() throws Exception {
|
||||
Transaction txn = new Transaction(null, false);
|
||||
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transaction(with(false), withDbRunnable(txn));
|
||||
oneOf(db).getContact(txn, contactId);
|
||||
@@ -187,6 +211,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
||||
@Test
|
||||
public void testContactExists() throws Exception {
|
||||
Transaction txn = new Transaction(null, true);
|
||||
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||
oneOf(db).containsContact(txn, remote.getId(), local);
|
||||
@@ -206,6 +231,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
||||
oneOf(db).getContactsByAuthorId(txn, remote.getId());
|
||||
will(returnValue(singletonList(contact)));
|
||||
}});
|
||||
|
||||
AuthorInfo authorInfo =
|
||||
contactManager.getAuthorInfo(txn, remote.getId());
|
||||
assertEquals(UNVERIFIED, authorInfo.getStatus());
|
||||
@@ -223,6 +249,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
||||
oneOf(db).getContactsByAuthorId(txn, remote.getId());
|
||||
will(returnValue(emptyList()));
|
||||
}});
|
||||
|
||||
AuthorInfo authorInfo =
|
||||
contactManager.getAuthorInfo(txn, remote.getId());
|
||||
assertEquals(UNKNOWN, authorInfo.getStatus());
|
||||
@@ -247,6 +274,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
||||
will(returnValue(localAuthor));
|
||||
never(db).getContactsByAuthorId(txn, remote.getId());
|
||||
}});
|
||||
|
||||
authorInfo = contactManager.getAuthorInfo(txn, localAuthor.getId());
|
||||
assertEquals(OURSELVES, authorInfo.getStatus());
|
||||
assertNull(authorInfo.getAlias());
|
||||
@@ -265,19 +293,178 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
||||
@Test
|
||||
public void testGetHandshakeLink() throws Exception {
|
||||
Transaction txn = new Transaction(null, true);
|
||||
PublicKey publicKey = getAgreementPublicKey();
|
||||
PrivateKey privateKey = getAgreementPrivateKey();
|
||||
KeyPair keyPair = new KeyPair(publicKey, privateKey);
|
||||
String link = "briar://" + getRandomBase32String(BASE32_LINK_BYTES);
|
||||
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||
oneOf(identityManager).getHandshakeKeys(txn);
|
||||
will(returnValue(keyPair));
|
||||
oneOf(pendingContactFactory).createHandshakeLink(publicKey);
|
||||
will(returnValue(handshakeKeyPair));
|
||||
oneOf(pendingContactFactory).createHandshakeLink(
|
||||
handshakeKeyPair.getPublic());
|
||||
will(returnValue(link));
|
||||
}});
|
||||
|
||||
assertEquals(link, contactManager.getHandshakeLink());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDefaultPendingContactState() throws Exception {
|
||||
Transaction txn = new Transaction(null, true);
|
||||
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||
oneOf(db).getPendingContacts(txn);
|
||||
will(returnValue(singletonList(pendingContact)));
|
||||
}});
|
||||
|
||||
// No events have happened for this pending contact, so the state
|
||||
// should be WAITING_FOR_CONNECTION
|
||||
Collection<Pair<PendingContact, PendingContactState>> pairs =
|
||||
contactManager.getPendingContacts();
|
||||
assertEquals(1, pairs.size());
|
||||
Pair<PendingContact, PendingContactState> pair =
|
||||
pairs.iterator().next();
|
||||
assertEquals(pendingContact, pair.getFirst());
|
||||
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));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPendingContactExpiresDuringSuccessfulConnection()
|
||||
throws Exception {
|
||||
Transaction txn = new Transaction(null, false);
|
||||
|
||||
// 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 pending contact is converted to a contact - no state is broadcast
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).getPendingContact(txn, pendingContact.getId());
|
||||
will(returnValue(pendingContact));
|
||||
oneOf(db).removePendingContact(txn, pendingContact.getId());
|
||||
oneOf(db).addContact(txn, remote, local,
|
||||
pendingContact.getPublicKey(), verified);
|
||||
will(returnValue(contactId));
|
||||
oneOf(db).setContactAlias(txn, contactId,
|
||||
pendingContact.getAlias());
|
||||
oneOf(identityManager).getHandshakeKeys(txn);
|
||||
will(returnValue(handshakeKeyPair));
|
||||
oneOf(keyManager).addContact(txn, contactId,
|
||||
pendingContact.getPublicKey(), handshakeKeyPair);
|
||||
oneOf(keyManager).addRotationKeys(txn, contactId, rootKey,
|
||||
timestamp, alice, active);
|
||||
oneOf(db).getContact(txn, contactId);
|
||||
will(returnValue(contact));
|
||||
}});
|
||||
|
||||
contactManager.addContact(txn, pendingContact.getId(), remote,
|
||||
local, rootKey, timestamp, alice, verified, active);
|
||||
context.assertIsSatisfied();
|
||||
|
||||
// The rendezvous connection succeeds - no state is broadcast
|
||||
contactManager.eventOccurred(new RendezvousConnectionClosedEvent(
|
||||
pendingContact.getId(), true));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPendingContactRemovedDuringFailedConnection()
|
||||
throws Exception {
|
||||
Transaction txn = new Transaction(null, false);
|
||||
|
||||
// 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 is removed - no state is broadcast
|
||||
context.checking(new DbExpectations() {{
|
||||
oneOf(db).transaction(with(false), withDbRunnable(txn));
|
||||
oneOf(db).removePendingContact(txn, pendingContact.getId());
|
||||
}});
|
||||
|
||||
contactManager.removePendingContact(pendingContact.getId());
|
||||
context.assertIsSatisfied();
|
||||
|
||||
// The rendezvous connection fails - no state is broadcast
|
||||
contactManager.eventOccurred(new RendezvousConnectionClosedEvent(
|
||||
pendingContact.getId(), false));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
package org.briarproject.bramble.test;
|
||||
|
||||
import org.briarproject.bramble.api.Predicate;
|
||||
import org.hamcrest.BaseMatcher;
|
||||
import org.hamcrest.Description;
|
||||
|
||||
public class PredicateMatcher<T> extends BaseMatcher<T> {
|
||||
|
||||
private final Class<T> matchedClass;
|
||||
private final Predicate<T> predicate;
|
||||
|
||||
public PredicateMatcher(Class<T> matchedClass, Predicate<T> predicate) {
|
||||
this.matchedClass = matchedClass;
|
||||
this.predicate = predicate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(Object item) {
|
||||
if (matchedClass.isInstance(item))
|
||||
return predicate.test(matchedClass.cast(item));
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void describeTo(Description description) {
|
||||
description.appendText("matches an item against a predicate");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user