mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-22 23:59:54 +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.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.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.PublicKey;
|
import org.briarproject.bramble.api.crypto.PublicKey;
|
||||||
import org.briarproject.bramble.api.crypto.SecretKey;
|
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.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.EventBus;
|
||||||
|
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;
|
||||||
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.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.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;
|
||||||
@@ -43,24 +54,29 @@ import static org.briarproject.bramble.util.StringUtils.toUtf8;
|
|||||||
|
|
||||||
@ThreadSafe
|
@ThreadSafe
|
||||||
@NotNullByDefault
|
@NotNullByDefault
|
||||||
class ContactManagerImpl implements ContactManager {
|
class ContactManagerImpl implements ContactManager, EventListener {
|
||||||
|
|
||||||
private final DatabaseComponent db;
|
private final DatabaseComponent db;
|
||||||
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;
|
private final List<ContactHook> hooks = new CopyOnWriteArrayList<>();
|
||||||
|
private final ConcurrentMap<PendingContactId, PendingContactState> states =
|
||||||
|
new ConcurrentHashMap<>();
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
ContactManagerImpl(DatabaseComponent db, KeyManager keyManager,
|
ContactManagerImpl(DatabaseComponent db,
|
||||||
|
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;
|
||||||
hooks = new CopyOnWriteArrayList<>();
|
this.eventBus = eventBus;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -86,6 +102,7 @@ class ContactManagerImpl implements ContactManager {
|
|||||||
throws DbException, GeneralSecurityException {
|
throws DbException, GeneralSecurityException {
|
||||||
PendingContact pendingContact = db.getPendingContact(txn, p);
|
PendingContact pendingContact = db.getPendingContact(txn, p);
|
||||||
db.removePendingContact(txn, p);
|
db.removePendingContact(txn, p);
|
||||||
|
states.remove(p);
|
||||||
PublicKey theirPublicKey = pendingContact.getPublicKey();
|
PublicKey theirPublicKey = pendingContact.getPublicKey();
|
||||||
ContactId c =
|
ContactId c =
|
||||||
db.addContact(txn, remote, local, theirPublicKey, verified);
|
db.addContact(txn, remote, local, theirPublicKey, verified);
|
||||||
@@ -139,6 +156,7 @@ class ContactManagerImpl implements ContactManager {
|
|||||||
} finally {
|
} finally {
|
||||||
db.endTransaction(txn);
|
db.endTransaction(txn);
|
||||||
}
|
}
|
||||||
|
setState(p.getId(), WAITING_FOR_CONNECTION);
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -156,7 +174,9 @@ class ContactManagerImpl implements ContactManager {
|
|||||||
List<Pair<PendingContact, PendingContactState>> pairs =
|
List<Pair<PendingContact, PendingContactState>> pairs =
|
||||||
new ArrayList<>(pendingContacts.size());
|
new ArrayList<>(pendingContacts.size());
|
||||||
for (PendingContact p : pendingContacts) {
|
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;
|
return pairs;
|
||||||
}
|
}
|
||||||
@@ -164,6 +184,7 @@ class ContactManagerImpl implements ContactManager {
|
|||||||
@Override
|
@Override
|
||||||
public void removePendingContact(PendingContactId p) throws DbException {
|
public void removePendingContact(PendingContactId p) throws DbException {
|
||||||
db.transaction(false, txn -> db.removePendingContact(txn, p));
|
db.transaction(false, txn -> db.removePendingContact(txn, p));
|
||||||
|
states.remove(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -263,4 +284,48 @@ class ContactManagerImpl implements ContactManager {
|
|||||||
else return new AuthorInfo(UNVERIFIED, c.getAlias());
|
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.ContactExchangeManager;
|
||||||
import org.briarproject.bramble.api.contact.ContactManager;
|
import org.briarproject.bramble.api.contact.ContactManager;
|
||||||
import org.briarproject.bramble.api.contact.HandshakeManager;
|
import org.briarproject.bramble.api.contact.HandshakeManager;
|
||||||
|
import org.briarproject.bramble.api.event.EventBus;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
@@ -20,7 +21,9 @@ public class ContactModule {
|
|||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@Singleton
|
@Singleton
|
||||||
ContactManager provideContactManager(ContactManagerImpl contactManager) {
|
ContactManager provideContactManager(EventBus eventBus,
|
||||||
|
ContactManagerImpl contactManager) {
|
||||||
|
eventBus.addListener(contactManager);
|
||||||
return contactManager;
|
return contactManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,32 @@
|
|||||||
package org.briarproject.bramble.contact;
|
package org.briarproject.bramble.contact;
|
||||||
|
|
||||||
|
import org.briarproject.bramble.api.Pair;
|
||||||
import org.briarproject.bramble.api.contact.Contact;
|
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.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.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.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.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
@@ -28,6 +35,9 @@ 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.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;
|
||||||
import static org.briarproject.bramble.api.identity.AuthorInfo.Status.UNKNOWN;
|
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.getAuthor;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getContact;
|
import static org.briarproject.bramble.test.TestUtils.getContact;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getLocalAuthor;
|
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.getRandomId;
|
||||||
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
import static org.briarproject.bramble.test.TestUtils.getSecretKey;
|
||||||
import static org.briarproject.bramble.util.StringUtils.getRandomBase32String;
|
import static org.briarproject.bramble.util.StringUtils.getRandomBase32String;
|
||||||
@@ -54,24 +65,31 @@ 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 ContactManager contactManager;
|
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();
|
||||||
private final AuthorId local = localAuthor.getId();
|
private final AuthorId local = localAuthor.getId();
|
||||||
private final boolean verified = false, active = true;
|
private final boolean verified = false, active = true;
|
||||||
private final Contact contact = getContact(remote, local, verified);
|
private final Contact contact = getContact(remote, local, verified);
|
||||||
private final ContactId contactId = contact.getId();
|
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,
|
contactManager = new ContactManagerImpl(db, keyManager,
|
||||||
identityManager, pendingContactFactory);
|
identityManager, pendingContactFactory, eventBus);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddContact() throws Exception {
|
public void testAddContact() throws Exception {
|
||||||
SecretKey rootKey = getSecretKey();
|
|
||||||
long timestamp = System.currentTimeMillis();
|
|
||||||
boolean alice = new Random().nextBoolean();
|
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
|
|
||||||
context.checking(new DbExpectations() {{
|
context.checking(new DbExpectations() {{
|
||||||
@@ -91,6 +109,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testGetContact() throws Exception {
|
public void testGetContact() throws Exception {
|
||||||
Transaction txn = new Transaction(null, true);
|
Transaction txn = new Transaction(null, true);
|
||||||
|
|
||||||
context.checking(new DbExpectations() {{
|
context.checking(new DbExpectations() {{
|
||||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||||
oneOf(db).getContact(txn, contactId);
|
oneOf(db).getContact(txn, contactId);
|
||||||
@@ -104,6 +123,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
|||||||
public void testGetContactByAuthor() throws Exception {
|
public void testGetContactByAuthor() throws Exception {
|
||||||
Transaction txn = new Transaction(null, true);
|
Transaction txn = new Transaction(null, true);
|
||||||
Collection<Contact> contacts = singletonList(contact);
|
Collection<Contact> contacts = singletonList(contact);
|
||||||
|
|
||||||
context.checking(new DbExpectations() {{
|
context.checking(new DbExpectations() {{
|
||||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||||
oneOf(db).getContactsByAuthorId(txn, remote.getId());
|
oneOf(db).getContactsByAuthorId(txn, remote.getId());
|
||||||
@@ -116,6 +136,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
|||||||
@Test(expected = NoSuchContactException.class)
|
@Test(expected = NoSuchContactException.class)
|
||||||
public void testGetContactByUnknownAuthor() throws Exception {
|
public void testGetContactByUnknownAuthor() throws Exception {
|
||||||
Transaction txn = new Transaction(null, true);
|
Transaction txn = new Transaction(null, true);
|
||||||
|
|
||||||
context.checking(new DbExpectations() {{
|
context.checking(new DbExpectations() {{
|
||||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||||
oneOf(db).getContactsByAuthorId(txn, remote.getId());
|
oneOf(db).getContactsByAuthorId(txn, remote.getId());
|
||||||
@@ -129,6 +150,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
|||||||
public void testGetContactByUnknownLocalAuthor() throws Exception {
|
public void testGetContactByUnknownLocalAuthor() throws Exception {
|
||||||
Transaction txn = new Transaction(null, true);
|
Transaction txn = new Transaction(null, true);
|
||||||
Collection<Contact> contacts = singletonList(contact);
|
Collection<Contact> contacts = singletonList(contact);
|
||||||
|
|
||||||
context.checking(new DbExpectations() {{
|
context.checking(new DbExpectations() {{
|
||||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||||
oneOf(db).getContactsByAuthorId(txn, remote.getId());
|
oneOf(db).getContactsByAuthorId(txn, remote.getId());
|
||||||
@@ -142,6 +164,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
|||||||
public void testGetContacts() throws Exception {
|
public void testGetContacts() throws Exception {
|
||||||
Collection<Contact> contacts = singletonList(contact);
|
Collection<Contact> contacts = singletonList(contact);
|
||||||
Transaction txn = new Transaction(null, true);
|
Transaction txn = new Transaction(null, true);
|
||||||
|
|
||||||
context.checking(new DbExpectations() {{
|
context.checking(new DbExpectations() {{
|
||||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||||
oneOf(db).getContacts(txn);
|
oneOf(db).getContacts(txn);
|
||||||
@@ -154,6 +177,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testRemoveContact() throws Exception {
|
public void testRemoveContact() throws Exception {
|
||||||
Transaction txn = new Transaction(null, false);
|
Transaction txn = new Transaction(null, false);
|
||||||
|
|
||||||
context.checking(new DbExpectations() {{
|
context.checking(new DbExpectations() {{
|
||||||
oneOf(db).transaction(with(false), withDbRunnable(txn));
|
oneOf(db).transaction(with(false), withDbRunnable(txn));
|
||||||
oneOf(db).getContact(txn, contactId);
|
oneOf(db).getContact(txn, contactId);
|
||||||
@@ -187,6 +211,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testContactExists() throws Exception {
|
public void testContactExists() throws Exception {
|
||||||
Transaction txn = new Transaction(null, true);
|
Transaction txn = new Transaction(null, true);
|
||||||
|
|
||||||
context.checking(new DbExpectations() {{
|
context.checking(new DbExpectations() {{
|
||||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||||
oneOf(db).containsContact(txn, remote.getId(), local);
|
oneOf(db).containsContact(txn, remote.getId(), local);
|
||||||
@@ -206,6 +231,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(db).getContactsByAuthorId(txn, remote.getId());
|
oneOf(db).getContactsByAuthorId(txn, remote.getId());
|
||||||
will(returnValue(singletonList(contact)));
|
will(returnValue(singletonList(contact)));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
AuthorInfo authorInfo =
|
AuthorInfo authorInfo =
|
||||||
contactManager.getAuthorInfo(txn, remote.getId());
|
contactManager.getAuthorInfo(txn, remote.getId());
|
||||||
assertEquals(UNVERIFIED, authorInfo.getStatus());
|
assertEquals(UNVERIFIED, authorInfo.getStatus());
|
||||||
@@ -223,6 +249,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
|||||||
oneOf(db).getContactsByAuthorId(txn, remote.getId());
|
oneOf(db).getContactsByAuthorId(txn, remote.getId());
|
||||||
will(returnValue(emptyList()));
|
will(returnValue(emptyList()));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
AuthorInfo authorInfo =
|
AuthorInfo authorInfo =
|
||||||
contactManager.getAuthorInfo(txn, remote.getId());
|
contactManager.getAuthorInfo(txn, remote.getId());
|
||||||
assertEquals(UNKNOWN, authorInfo.getStatus());
|
assertEquals(UNKNOWN, authorInfo.getStatus());
|
||||||
@@ -247,6 +274,7 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
|||||||
will(returnValue(localAuthor));
|
will(returnValue(localAuthor));
|
||||||
never(db).getContactsByAuthorId(txn, remote.getId());
|
never(db).getContactsByAuthorId(txn, remote.getId());
|
||||||
}});
|
}});
|
||||||
|
|
||||||
authorInfo = contactManager.getAuthorInfo(txn, localAuthor.getId());
|
authorInfo = contactManager.getAuthorInfo(txn, localAuthor.getId());
|
||||||
assertEquals(OURSELVES, authorInfo.getStatus());
|
assertEquals(OURSELVES, authorInfo.getStatus());
|
||||||
assertNull(authorInfo.getAlias());
|
assertNull(authorInfo.getAlias());
|
||||||
@@ -265,19 +293,178 @@ public class ContactManagerImplTest extends BrambleMockTestCase {
|
|||||||
@Test
|
@Test
|
||||||
public void testGetHandshakeLink() throws Exception {
|
public void testGetHandshakeLink() throws Exception {
|
||||||
Transaction txn = new Transaction(null, true);
|
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);
|
String link = "briar://" + getRandomBase32String(BASE32_LINK_BYTES);
|
||||||
|
|
||||||
context.checking(new DbExpectations() {{
|
context.checking(new DbExpectations() {{
|
||||||
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
oneOf(db).transactionWithResult(with(true), withDbCallable(txn));
|
||||||
oneOf(identityManager).getHandshakeKeys(txn);
|
oneOf(identityManager).getHandshakeKeys(txn);
|
||||||
will(returnValue(keyPair));
|
will(returnValue(handshakeKeyPair));
|
||||||
oneOf(pendingContactFactory).createHandshakeLink(publicKey);
|
oneOf(pendingContactFactory).createHandshakeLink(
|
||||||
|
handshakeKeyPair.getPublic());
|
||||||
will(returnValue(link));
|
will(returnValue(link));
|
||||||
}});
|
}});
|
||||||
|
|
||||||
assertEquals(link, contactManager.getHandshakeLink());
|
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