Merge branch '1567-remove-pending-contact-state-from-db' into 'master'

Remove pending contact state from DB

See merge request briar/briar!1102
This commit is contained in:
Torsten Grote
2019-05-22 16:56:59 +00:00
25 changed files with 280 additions and 172 deletions

View File

@@ -1,6 +1,7 @@
package org.briarproject.bramble.api.contact; package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.FormatException;
import org.briarproject.bramble.api.Pair;
import org.briarproject.bramble.api.UnsupportedVersionException; import org.briarproject.bramble.api.UnsupportedVersionException;
import org.briarproject.bramble.api.crypto.SecretKey; import org.briarproject.bramble.api.crypto.SecretKey;
import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.DbException;
@@ -76,9 +77,11 @@ public interface ContactManager {
throws DbException, FormatException; throws DbException, FormatException;
/** /**
* Returns a list of {@link PendingContact}s. * Returns a list of {@link PendingContact PendingContacts} and their
* {@link PendingContactState states}.
*/ */
Collection<PendingContact> getPendingContacts() throws DbException; Collection<Pair<PendingContact, PendingContactState>> getPendingContacts()
throws DbException;
/** /**
* Removes a {@link PendingContact}. * Removes a {@link PendingContact}.

View File

@@ -12,15 +12,13 @@ public class PendingContact {
private final PendingContactId id; private final PendingContactId id;
private final PublicKey publicKey; private final PublicKey publicKey;
private final String alias; private final String alias;
private final PendingContactState state;
private final long timestamp; private final long timestamp;
public PendingContact(PendingContactId id, PublicKey publicKey, public PendingContact(PendingContactId id, PublicKey publicKey,
String alias, PendingContactState state, long timestamp) { String alias, long timestamp) {
this.id = id; this.id = id;
this.publicKey = publicKey; this.publicKey = publicKey;
this.alias = alias; this.alias = alias;
this.state = state;
this.timestamp = timestamp; this.timestamp = timestamp;
} }
@@ -36,10 +34,6 @@ public class PendingContact {
return alias; return alias;
} }
public PendingContactState getState() {
return state;
}
public long getTimestamp() { public long getTimestamp() {
return timestamp; return timestamp;
} }

View File

@@ -1,30 +1,9 @@
package org.briarproject.bramble.api.contact; package org.briarproject.bramble.api.contact;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
public enum PendingContactState { public enum PendingContactState {
WAITING_FOR_CONNECTION(0), WAITING_FOR_CONNECTION,
CONNECTED(1), CONNECTED,
ADDING_CONTACT(2), ADDING_CONTACT,
FAILED(3); FAILED
private final int value;
PendingContactState(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public static PendingContactState fromValue(int value) {
for (PendingContactState s : values()) if (s.value == value) return s;
throw new IllegalArgumentException();
}
} }

View File

@@ -0,0 +1,25 @@
package org.briarproject.bramble.api.contact.event;
import org.briarproject.bramble.api.contact.PendingContact;
import org.briarproject.bramble.api.event.Event;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
/**
* An event that is broadcast when a pending contact is added.
*/
@Immutable
@NotNullByDefault
public class PendingContactAddedEvent extends Event {
private final PendingContact pendingContact;
public PendingContactAddedEvent(PendingContact pendingContact) {
this.pendingContact = pendingContact;
}
public PendingContact getPendingContact() {
return pendingContact;
}
}

View File

@@ -5,7 +5,6 @@ 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.PendingContactId; import org.briarproject.bramble.api.contact.PendingContactId;
import org.briarproject.bramble.api.contact.PendingContactState;
import org.briarproject.bramble.api.crypto.AgreementPrivateKey; import org.briarproject.bramble.api.crypto.AgreementPrivateKey;
import org.briarproject.bramble.api.crypto.AgreementPublicKey; import org.briarproject.bramble.api.crypto.AgreementPublicKey;
import org.briarproject.bramble.api.crypto.PrivateKey; import org.briarproject.bramble.api.crypto.PrivateKey;
@@ -181,10 +180,7 @@ public class TestUtils {
PendingContactId id = new PendingContactId(getRandomId()); PendingContactId id = new PendingContactId(getRandomId());
PublicKey publicKey = getAgreementPublicKey(); PublicKey publicKey = getAgreementPublicKey();
String alias = getRandomString(nameLength); String alias = getRandomString(nameLength);
int stateIndex = return new PendingContact(id, publicKey, alias, timestamp);
random.nextInt(PendingContactState.values().length - 1);
PendingContactState state = PendingContactState.values()[stateIndex];
return new PendingContact(id, publicKey, alias, state, timestamp);
} }
public static ContactId getContactId() { public static ContactId getContactId() {

View File

@@ -1,11 +1,13 @@
package org.briarproject.bramble.contact; package org.briarproject.bramble.contact;
import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.FormatException;
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.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.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;
@@ -19,6 +21,7 @@ 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.transport.KeyManager; import org.briarproject.bramble.api.transport.KeyManager;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CopyOnWriteArrayList;
@@ -28,6 +31,7 @@ import javax.annotation.concurrent.ThreadSafe;
import javax.inject.Inject; import javax.inject.Inject;
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.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;
@@ -111,8 +115,16 @@ class ContactManagerImpl implements ContactManager {
} }
@Override @Override
public Collection<PendingContact> getPendingContacts() throws DbException { public Collection<Pair<PendingContact, PendingContactState>> getPendingContacts()
return db.transactionWithResult(true, db::getPendingContacts); throws DbException {
Collection<PendingContact> pendingContacts =
db.transactionWithResult(true, db::getPendingContacts);
List<Pair<PendingContact, PendingContactState>> pairs =
new ArrayList<>(pendingContacts.size());
for (PendingContact p : pendingContacts) {
pairs.add(new Pair<>(p, WAITING_FOR_CONNECTION)); // TODO
}
return pairs;
} }
@Override @Override

View File

@@ -20,7 +20,6 @@ import static org.briarproject.bramble.api.contact.HandshakeLinkConstants.FORMAT
import static org.briarproject.bramble.api.contact.HandshakeLinkConstants.ID_LABEL; import static org.briarproject.bramble.api.contact.HandshakeLinkConstants.ID_LABEL;
import static org.briarproject.bramble.api.contact.HandshakeLinkConstants.LINK_REGEX; import static org.briarproject.bramble.api.contact.HandshakeLinkConstants.LINK_REGEX;
import static org.briarproject.bramble.api.contact.HandshakeLinkConstants.RAW_LINK_BYTES; import static org.briarproject.bramble.api.contact.HandshakeLinkConstants.RAW_LINK_BYTES;
import static org.briarproject.bramble.api.contact.PendingContactState.WAITING_FOR_CONNECTION;
class PendingContactFactoryImpl implements PendingContactFactory { class PendingContactFactoryImpl implements PendingContactFactory {
@@ -39,8 +38,7 @@ class PendingContactFactoryImpl implements PendingContactFactory {
PublicKey publicKey = parseHandshakeLink(link); PublicKey publicKey = parseHandshakeLink(link);
PendingContactId id = getPendingContactId(publicKey); PendingContactId id = getPendingContactId(publicKey);
long timestamp = clock.currentTimeMillis(); long timestamp = clock.currentTimeMillis();
return new PendingContact(id, publicKey, alias, WAITING_FOR_CONNECTION, return new PendingContact(id, publicKey, alias, timestamp);
timestamp);
} }
private PublicKey parseHandshakeLink(String link) throws FormatException { private PublicKey parseHandshakeLink(String link) throws FormatException {

View File

@@ -4,7 +4,6 @@ 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.PendingContactId; import org.briarproject.bramble.api.contact.PendingContactId;
import org.briarproject.bramble.api.contact.PendingContactState;
import org.briarproject.bramble.api.crypto.PrivateKey; import org.briarproject.bramble.api.crypto.PrivateKey;
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;
@@ -674,12 +673,6 @@ interface Database<T> {
void setMessageState(T txn, MessageId m, MessageState state) void setMessageState(T txn, MessageId m, MessageState state)
throws DbException; throws DbException;
/**
* Sets the state of the given pending contact.
*/
void setPendingContactState(T txn, PendingContactId p,
PendingContactState state) throws DbException;
/** /**
* Sets the reordering window for the given transport keys in the given * Sets the reordering window for the given transport keys in the given
* time period. * time period.

View File

@@ -7,8 +7,8 @@ import org.briarproject.bramble.api.contact.PendingContactId;
import org.briarproject.bramble.api.contact.event.ContactAddedEvent; import org.briarproject.bramble.api.contact.event.ContactAddedEvent;
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent; import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
import org.briarproject.bramble.api.contact.event.ContactVerifiedEvent; import org.briarproject.bramble.api.contact.event.ContactVerifiedEvent;
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.PrivateKey; import org.briarproject.bramble.api.crypto.PrivateKey;
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;
@@ -295,8 +295,7 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
if (db.containsPendingContact(txn, p.getId())) if (db.containsPendingContact(txn, p.getId()))
throw new PendingContactExistsException(); throw new PendingContactExistsException();
db.addPendingContact(txn, p); db.addPendingContact(txn, p);
transaction.attach(new PendingContactStateChangedEvent(p.getId(), transaction.attach(new PendingContactAddedEvent(p));
p.getState()));
} }
@Override @Override

View File

@@ -4,7 +4,6 @@ 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.PendingContactId; import org.briarproject.bramble.api.contact.PendingContactId;
import org.briarproject.bramble.api.contact.PendingContactState;
import org.briarproject.bramble.api.crypto.AgreementPrivateKey; import org.briarproject.bramble.api.crypto.AgreementPrivateKey;
import org.briarproject.bramble.api.crypto.AgreementPublicKey; import org.briarproject.bramble.api.crypto.AgreementPublicKey;
import org.briarproject.bramble.api.crypto.PrivateKey; import org.briarproject.bramble.api.crypto.PrivateKey;
@@ -98,7 +97,7 @@ import static org.briarproject.bramble.util.LogUtils.now;
abstract class JdbcDatabase implements Database<Connection> { abstract class JdbcDatabase implements Database<Connection> {
// Package access for testing // Package access for testing
static final int CODE_SCHEMA_VERSION = 44; static final int CODE_SCHEMA_VERSION = 45;
// Time period offsets for incoming transport keys // Time period offsets for incoming transport keys
private static final int OFFSET_PREV = -1; private static final int OFFSET_PREV = -1;
@@ -264,7 +263,6 @@ abstract class JdbcDatabase implements Database<Connection> {
+ " (pendingContactId _HASH NOT NULL," + " (pendingContactId _HASH NOT NULL,"
+ " publicKey _BINARY NOT NULL," + " publicKey _BINARY NOT NULL,"
+ " alias _STRING NOT NULL," + " alias _STRING NOT NULL,"
+ " state INT NOT NULL,"
+ " timestamp BIGINT NOT NULL," + " timestamp BIGINT NOT NULL,"
+ " PRIMARY KEY (pendingContactId))"; + " PRIMARY KEY (pendingContactId))";
@@ -457,7 +455,8 @@ abstract class JdbcDatabase implements Database<Connection> {
new Migration40_41(dbTypes), new Migration40_41(dbTypes),
new Migration41_42(dbTypes), new Migration41_42(dbTypes),
new Migration42_43(dbTypes), new Migration42_43(dbTypes),
new Migration43_44(dbTypes) new Migration43_44(dbTypes),
new Migration44_45()
); );
} }
@@ -933,14 +932,13 @@ abstract class JdbcDatabase implements Database<Connection> {
PreparedStatement ps = null; PreparedStatement ps = null;
try { try {
String sql = "INSERT INTO pendingContacts (pendingContactId," String sql = "INSERT INTO pendingContacts (pendingContactId,"
+ " publicKey, alias, state, timestamp)" + " publicKey, alias, timestamp)"
+ " VALUES (?, ?, ?, ?, ?)"; + " VALUES (?, ?, ?, ?)";
ps = txn.prepareStatement(sql); ps = txn.prepareStatement(sql);
ps.setBytes(1, p.getId().getBytes()); ps.setBytes(1, p.getId().getBytes());
ps.setBytes(2, p.getPublicKey().getEncoded()); ps.setBytes(2, p.getPublicKey().getEncoded());
ps.setString(3, p.getAlias()); ps.setString(3, p.getAlias());
ps.setInt(4, p.getState().getValue()); ps.setLong(4, p.getTimestamp());
ps.setLong(5, p.getTimestamp());
int affected = ps.executeUpdate(); int affected = ps.executeUpdate();
if (affected != 1) throw new DbStateException(); if (affected != 1) throw new DbStateException();
ps.close(); ps.close();
@@ -2213,8 +2211,7 @@ abstract class JdbcDatabase implements Database<Connection> {
Statement s = null; Statement s = null;
ResultSet rs = null; ResultSet rs = null;
try { try {
String sql = "SELECT pendingContactId, publicKey, alias, state," String sql = "SELECT pendingContactId, publicKey, alias, timestamp"
+ " timestamp"
+ " FROM pendingContacts"; + " FROM pendingContacts";
s = txn.createStatement(); s = txn.createStatement();
rs = s.executeQuery(sql); rs = s.executeQuery(sql);
@@ -2223,11 +2220,9 @@ abstract class JdbcDatabase implements Database<Connection> {
PendingContactId id = new PendingContactId(rs.getBytes(1)); PendingContactId id = new PendingContactId(rs.getBytes(1));
PublicKey publicKey = new AgreementPublicKey(rs.getBytes(2)); PublicKey publicKey = new AgreementPublicKey(rs.getBytes(2));
String alias = rs.getString(3); String alias = rs.getString(3);
PendingContactState state = long timestamp = rs.getLong(4);
PendingContactState.fromValue(rs.getInt(4));
long timestamp = rs.getLong(5);
pendingContacts.add(new PendingContact(id, publicKey, alias, pendingContacts.add(new PendingContact(id, publicKey, alias,
state, timestamp)); timestamp));
} }
rs.close(); rs.close();
s.close(); s.close();
@@ -3077,25 +3072,6 @@ abstract class JdbcDatabase implements Database<Connection> {
} }
} }
@Override
public void setPendingContactState(Connection txn, PendingContactId p,
PendingContactState state) throws DbException {
PreparedStatement ps = null;
try {
String sql = "UPDATE pendingContacts SET state = ?"
+ " WHERE pendingContactId = ?";
ps = txn.prepareStatement(sql);
ps.setInt(1, state.getValue());
ps.setBytes(2, p.getBytes());
int affected = ps.executeUpdate();
if (affected < 0 || affected > 1) throw new DbStateException();
ps.close();
} catch (SQLException e) {
tryToClose(ps, LOG, WARNING);
throw new DbException(e);
}
}
@Override @Override
public void setReorderingWindow(Connection txn, KeySetId k, public void setReorderingWindow(Connection txn, KeySetId k,
TransportId t, long timePeriod, long base, byte[] bitmap) TransportId t, long timePeriod, long base, byte[] bitmap)

View File

@@ -0,0 +1,39 @@
package org.briarproject.bramble.db;
import org.briarproject.bramble.api.db.DbException;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.logging.Logger;
import static java.util.logging.Level.WARNING;
import static java.util.logging.Logger.getLogger;
import static org.briarproject.bramble.db.JdbcUtils.tryToClose;
class Migration44_45 implements Migration<Connection> {
private static final Logger LOG = getLogger(Migration44_45.class.getName());
@Override
public int getStartVersion() {
return 44;
}
@Override
public int getEndVersion() {
return 45;
}
@Override
public void migrate(Connection txn) throws DbException {
Statement s = null;
try {
s = txn.createStatement();
s.execute("ALTER TABLE pendingContacts DROP COLUMN state");
} catch (SQLException e) {
tryToClose(s, LOG, WARNING);
throw new DbException(e);
}
}
}

View File

@@ -19,7 +19,6 @@ import static org.briarproject.bramble.api.contact.HandshakeLinkConstants.BASE32
import static org.briarproject.bramble.api.contact.HandshakeLinkConstants.FORMAT_VERSION; import static org.briarproject.bramble.api.contact.HandshakeLinkConstants.FORMAT_VERSION;
import static org.briarproject.bramble.api.contact.HandshakeLinkConstants.ID_LABEL; import static org.briarproject.bramble.api.contact.HandshakeLinkConstants.ID_LABEL;
import static org.briarproject.bramble.api.contact.HandshakeLinkConstants.RAW_LINK_BYTES; import static org.briarproject.bramble.api.contact.HandshakeLinkConstants.RAW_LINK_BYTES;
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.test.TestUtils.getAgreementPublicKey; import static org.briarproject.bramble.test.TestUtils.getAgreementPublicKey;
import static org.briarproject.bramble.test.TestUtils.getRandomId; import static org.briarproject.bramble.test.TestUtils.getRandomId;
@@ -108,7 +107,6 @@ public class PendingContactFactoryImplTest extends BrambleMockTestCase {
assertArrayEquals(publicKey.getEncoded(), assertArrayEquals(publicKey.getEncoded(),
p.getPublicKey().getEncoded()); p.getPublicKey().getEncoded());
assertEquals(alias, p.getAlias()); assertEquals(alias, p.getAlias());
assertEquals(WAITING_FOR_CONNECTION, p.getState());
assertEquals(timestamp, p.getTimestamp()); assertEquals(timestamp, p.getTimestamp());
} }

View File

@@ -56,7 +56,6 @@ import static java.util.Collections.emptyMap;
import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;
import static java.util.Collections.singletonMap; import static java.util.Collections.singletonMap;
import static java.util.concurrent.TimeUnit.SECONDS; import static java.util.concurrent.TimeUnit.SECONDS;
import static org.briarproject.bramble.api.contact.PendingContactState.FAILED;
import static org.briarproject.bramble.api.db.Metadata.REMOVE; import static org.briarproject.bramble.api.db.Metadata.REMOVE;
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.sync.Group.Visibility.INVISIBLE; import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE;
@@ -2211,16 +2210,6 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
PendingContact retrieved = pendingContacts.iterator().next(); PendingContact retrieved = pendingContacts.iterator().next();
assertEquals(pendingContact.getId(), retrieved.getId()); assertEquals(pendingContact.getId(), retrieved.getId());
assertEquals(pendingContact.getAlias(), retrieved.getAlias()); assertEquals(pendingContact.getAlias(), retrieved.getAlias());
assertEquals(pendingContact.getState(), retrieved.getState());
assertEquals(pendingContact.getTimestamp(), retrieved.getTimestamp());
db.setPendingContactState(txn, pendingContact.getId(), FAILED);
pendingContacts = db.getPendingContacts(txn);
assertEquals(1, pendingContacts.size());
retrieved = pendingContacts.iterator().next();
assertEquals(pendingContact.getId(), retrieved.getId());
assertEquals(pendingContact.getAlias(), retrieved.getAlias());
assertEquals(FAILED, retrieved.getState());
assertEquals(pendingContact.getTimestamp(), retrieved.getTimestamp()); assertEquals(pendingContact.getTimestamp(), retrieved.getTimestamp());
db.removePendingContact(txn, pendingContact.getId()); db.removePendingContact(txn, pendingContact.getId());
@@ -2232,8 +2221,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
@Test @Test
public void testSetHandshakeKeyPair() throws Exception { public void testSetHandshakeKeyPair() throws Exception {
Identity withoutKeys = Identity withoutKeys = new Identity(localAuthor, null, null,
new Identity(localAuthor, null, null, identity.getTimeCreated()); identity.getTimeCreated());
assertFalse(withoutKeys.hasHandshakeKeyPair()); assertFalse(withoutKeys.hasHandshakeKeyPair());
PublicKey publicKey = getAgreementPublicKey(); PublicKey publicKey = getAgreementPublicKey();
PrivateKey privateKey = getAgreementPrivateKey(); PrivateKey privateKey = getAgreementPrivateKey();

View File

@@ -18,10 +18,9 @@ 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.ContactManager;
import org.briarproject.bramble.api.contact.event.ContactAddedEvent; import org.briarproject.bramble.api.contact.event.ContactAddedEvent;
import org.briarproject.bramble.api.contact.event.ContactAddedRemotelyEvent;
import org.briarproject.bramble.api.contact.event.ContactRemovedEvent; import org.briarproject.bramble.api.contact.event.ContactRemovedEvent;
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.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.event.Event; import org.briarproject.bramble.api.event.Event;
@@ -65,7 +64,6 @@ import static android.support.v4.app.ActivityOptionsCompat.makeSceneTransitionAn
import static android.support.v4.view.ViewCompat.getTransitionName; import static android.support.v4.view.ViewCompat.getTransitionName;
import static java.util.Objects.requireNonNull; import static java.util.Objects.requireNonNull;
import static java.util.logging.Level.WARNING; import static java.util.logging.Level.WARNING;
import static org.briarproject.bramble.api.contact.PendingContactState.WAITING_FOR_CONNECTION;
import static org.briarproject.bramble.util.LogUtils.logDuration; import static org.briarproject.bramble.util.LogUtils.logDuration;
import static org.briarproject.bramble.util.LogUtils.logException; import static org.briarproject.bramble.util.LogUtils.logException;
import static org.briarproject.bramble.util.LogUtils.now; import static org.briarproject.bramble.util.LogUtils.now;
@@ -293,15 +291,8 @@ public class ContactListFragment extends BaseFragment implements EventListener,
(ConversationMessageReceivedEvent) e; (ConversationMessageReceivedEvent) e;
ConversationMessageHeader h = p.getMessageHeader(); ConversationMessageHeader h = p.getMessageHeader();
updateItem(p.getContactId(), h); updateItem(p.getContactId(), h);
} else if (e instanceof PendingContactStateChangedEvent) { } else if (e instanceof PendingContactAddedEvent ||
PendingContactStateChangedEvent pe = e instanceof PendingContactRemovedEvent) {
(PendingContactStateChangedEvent) e;
// only re-check pending contacts for initial state
if (pe.getPendingContactState() == WAITING_FOR_CONNECTION) {
checkForPendingContacts();
}
} else if (e instanceof PendingContactRemovedEvent ||
e instanceof ContactAddedRemotelyEvent) {
checkForPendingContacts(); checkForPendingContacts();
} }
} }

View File

@@ -4,7 +4,6 @@ import android.app.Application;
import android.arch.lifecycle.AndroidViewModel; import android.arch.lifecycle.AndroidViewModel;
import android.arch.lifecycle.LiveData; import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.MutableLiveData; import android.arch.lifecycle.MutableLiveData;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import org.briarproject.bramble.api.FormatException; import org.briarproject.bramble.api.FormatException;
@@ -45,7 +44,7 @@ public class AddContactViewModel extends AndroidViewModel {
private String remoteHandshakeLink; private String remoteHandshakeLink;
@Inject @Inject
public AddContactViewModel(@NonNull Application application, AddContactViewModel(Application application,
ContactManager contactManager, ContactManager contactManager,
@DatabaseExecutor Executor dbExecutor) { @DatabaseExecutor Executor dbExecutor) {
super(application); super(application);

View File

@@ -0,0 +1,29 @@
package org.briarproject.briar.android.contact.add.remote;
import org.briarproject.bramble.api.contact.PendingContact;
import org.briarproject.bramble.api.contact.PendingContactState;
import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import javax.annotation.concurrent.Immutable;
@Immutable
@NotNullByDefault
class PendingContactItem {
private final PendingContact pendingContact;
private final PendingContactState state;
PendingContactItem(PendingContact pendingContact,
PendingContactState state) {
this.pendingContact = pendingContact;
this.state = state;
}
PendingContact getPendingContact() {
return pendingContact;
}
PendingContactState getState() {
return state;
}
}

View File

@@ -53,7 +53,8 @@ public class PendingContactListActivity extends BriarActivity
viewModel.getPendingContacts() viewModel.getPendingContacts()
.observe(this, this::onPendingContactsChanged); .observe(this, this::onPendingContactsChanged);
adapter = new PendingContactListAdapter(this, this, PendingContact.class); adapter = new PendingContactListAdapter(this, this,
PendingContactItem.class);
list = findViewById(R.id.list); list = findViewById(R.id.list);
list.setEmptyText(R.string.no_pending_contacts); list.setEmptyText(R.string.no_pending_contacts);
list.setLayoutManager(new LinearLayoutManager(this)); list.setLayoutManager(new LinearLayoutManager(this));
@@ -75,13 +76,11 @@ public class PendingContactListActivity extends BriarActivity
@Override @Override
public boolean onOptionsItemSelected(MenuItem item) { public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) { if (item.getItemId() == android.R.id.home) {
case android.R.id.home: onBackPressed();
onBackPressed(); return true;
return true;
default:
return super.onOptionsItemSelected(item);
} }
return super.onOptionsItemSelected(item);
} }
@Override @Override
@@ -89,8 +88,9 @@ public class PendingContactListActivity extends BriarActivity
viewModel.removePendingContact(pendingContact.getId()); viewModel.removePendingContact(pendingContact.getId());
} }
private void onPendingContactsChanged(Collection<PendingContact> contacts) { private void onPendingContactsChanged(
if (contacts.isEmpty()) { Collection<PendingContactItem> items) {
if (items.isEmpty()) {
if (adapter.isEmpty()) { if (adapter.isEmpty()) {
list.showData(); // hides progress bar, shows empty text list.showData(); // hides progress bar, shows empty text
} else { } else {
@@ -98,7 +98,7 @@ public class PendingContactListActivity extends BriarActivity
supportFinishAfterTransition(); supportFinishAfterTransition();
} }
} else { } else {
adapter.setItems(contacts); adapter.setItems(items);
} }
} }

View File

@@ -12,12 +12,12 @@ import org.briarproject.briar.android.util.BriarAdapter;
@NotNullByDefault @NotNullByDefault
class PendingContactListAdapter extends class PendingContactListAdapter extends
BriarAdapter<PendingContact, PendingContactViewHolder> { BriarAdapter<PendingContactItem, PendingContactViewHolder> {
private final PendingContactListener listener; private final PendingContactListener listener;
PendingContactListAdapter(Context ctx, PendingContactListener listener, PendingContactListAdapter(Context ctx, PendingContactListener listener,
Class<PendingContact> c) { Class<PendingContactItem> c) {
super(ctx, c); super(ctx, c);
this.listener = listener; this.listener = listener;
} }
@@ -37,23 +37,29 @@ class PendingContactListAdapter extends
} }
@Override @Override
public int compare(PendingContact item1, PendingContact item2) { public int compare(PendingContactItem item1, PendingContactItem item2) {
return (int) (item1.getTimestamp() - item2.getTimestamp()); long timestamp1 = item1.getPendingContact().getTimestamp();
long timestamp2 = item2.getPendingContact().getTimestamp();
return Long.compare(timestamp1, timestamp2);
} }
@Override @Override
public boolean areContentsTheSame(PendingContact item1, public boolean areContentsTheSame(PendingContactItem item1,
PendingContact item2) { PendingContactItem item2) {
return item1.getId().equals(item2.getId()) && PendingContact p1 = item1.getPendingContact();
item1.getAlias().equals(item2.getAlias()) && PendingContact p2 = item2.getPendingContact();
item1.getTimestamp() == item2.getTimestamp() && return p1.getId().equals(p2.getId()) &&
p1.getAlias().equals(p2.getAlias()) &&
p1.getTimestamp() == p2.getTimestamp() &&
item1.getState() == item2.getState(); item1.getState() == item2.getState();
} }
@Override @Override
public boolean areItemsTheSame(PendingContact item1, public boolean areItemsTheSame(PendingContactItem item1,
PendingContact item2) { PendingContactItem item2) {
return item1.getId().equals(item2.getId()); PendingContact p1 = item1.getPendingContact();
PendingContact p2 = item2.getPendingContact();
return p1.getId().equals(p2.getId());
} }
} }

View File

@@ -5,10 +5,11 @@ import android.arch.lifecycle.AndroidViewModel;
import android.arch.lifecycle.LiveData; import android.arch.lifecycle.LiveData;
import android.arch.lifecycle.MutableLiveData; import android.arch.lifecycle.MutableLiveData;
import org.briarproject.bramble.api.Pair;
import org.briarproject.bramble.api.contact.ContactManager; 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.event.ContactAddedRemotelyEvent; import org.briarproject.bramble.api.contact.PendingContactState;
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.contact.event.PendingContactStateChangedEvent;
import org.briarproject.bramble.api.db.DatabaseExecutor; import org.briarproject.bramble.api.db.DatabaseExecutor;
@@ -18,7 +19,9 @@ 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.nullsafety.NotNullByDefault; import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import java.util.concurrent.Executor; import java.util.concurrent.Executor;
import java.util.logging.Logger; import java.util.logging.Logger;
@@ -40,11 +43,11 @@ public class PendingContactListViewModel extends AndroidViewModel
private final ContactManager contactManager; private final ContactManager contactManager;
private final EventBus eventBus; private final EventBus eventBus;
private final MutableLiveData<Collection<PendingContact>> pendingContacts = private final MutableLiveData<Collection<PendingContactItem>>
new MutableLiveData<>(); pendingContacts = new MutableLiveData<>();
@Inject @Inject
public PendingContactListViewModel(Application application, PendingContactListViewModel(Application application,
@DatabaseExecutor Executor dbExecutor, @DatabaseExecutor Executor dbExecutor,
ContactManager contactManager, EventBus eventBus) { ContactManager contactManager, EventBus eventBus) {
super(application); super(application);
@@ -63,8 +66,7 @@ public class PendingContactListViewModel extends AndroidViewModel
@Override @Override
public void eventOccurred(Event e) { public void eventOccurred(Event e) {
if (e instanceof ContactAddedRemotelyEvent || if (e instanceof PendingContactStateChangedEvent ||
e instanceof PendingContactStateChangedEvent ||
e instanceof PendingContactRemovedEvent) { e instanceof PendingContactRemovedEvent) {
loadPendingContacts(); loadPendingContacts();
} }
@@ -73,14 +75,21 @@ public class PendingContactListViewModel extends AndroidViewModel
private void loadPendingContacts() { private void loadPendingContacts() {
dbExecutor.execute(() -> { dbExecutor.execute(() -> {
try { try {
pendingContacts.postValue(contactManager.getPendingContacts()); Collection<Pair<PendingContact, PendingContactState>> pairs =
contactManager.getPendingContacts();
List<PendingContactItem> items = new ArrayList<>(pairs.size());
for (Pair<PendingContact, PendingContactState> p : pairs) {
items.add(new PendingContactItem(p.getFirst(),
p.getSecond()));
}
pendingContacts.setValue(items);
} catch (DbException e) { } catch (DbException e) {
logException(LOG, WARNING, e); logException(LOG, WARNING, e);
} }
}); });
} }
LiveData<Collection<PendingContact>> getPendingContacts() { LiveData<Collection<PendingContactItem>> getPendingContacts() {
return pendingContacts; return pendingContacts;
} }

View File

@@ -35,13 +35,14 @@ class PendingContactViewHolder extends ViewHolder {
this.listener = listener; this.listener = listener;
} }
public void bind(PendingContact item) { public void bind(PendingContactItem item) {
avatar.setText(item.getAlias()); PendingContact p = item.getPendingContact();
avatar.setBackgroundBytes(item.getId().getBytes()); avatar.setText(p.getAlias());
name.setText(item.getAlias()); avatar.setBackgroundBytes(p.getId().getBytes());
time.setText(formatDate(time.getContext(), item.getTimestamp())); name.setText(p.getAlias());
time.setText(formatDate(time.getContext(), p.getTimestamp()));
removeButton.setOnClickListener(v -> { removeButton.setOnClickListener(v -> {
listener.onFailedPendingContactRemoved(item); listener.onFailedPendingContactRemoved(p);
removeButton.setEnabled(false); removeButton.setEnabled(false);
}); });

View File

@@ -107,11 +107,27 @@ Until it is completed, a pending contact is returned as JSON:
{ {
"pendingContactId": "jsTgWcsEQ2g9rnomeK1g/hmO8M1Ix6ZIGWAjgBtlS9U=", "pendingContactId": "jsTgWcsEQ2g9rnomeK1g/hmO8M1Ix6ZIGWAjgBtlS9U=",
"alias": "ztatsaajzeegraqcizbbfftofdekclatyht", "alias": "ztatsaajzeegraqcizbbfftofdekclatyht",
"state": "adding_contact",
"timestamp": 1557838312175 "timestamp": 1557838312175
} }
``` ```
It is possible to get a list of all pending contacts:
`GET /v1/contacts/add/pending`
This will return a JSON array of pending contacts and their states:
```json
{
"pendingContact": {
"pendingContactId": "jsTgWcsEQ2g9rnomeK1g/hmO8M1Ix6ZIGWAjgBtlS9U=",
"alias": "ztatsaajzeegraqcizbbfftofdekclatyht",
"timestamp": 1557838312175
},
"state": "adding_contact"
}
```
The state can be one of these values: The state can be one of these values:
* `waiting_for_connection` * `waiting_for_connection`
@@ -119,21 +135,16 @@ The state can be one of these values:
* `adding_contact` * `adding_contact`
* `failed` * `failed`
If you want to get informed about state changes, If you want to be informed about state changes,
you can use the Websocket API (below) to listen for events. you can use the Websocket API (below) to listen for events.
The following events are relevant here: The following events are relevant here:
* `PendingContactAddedEvent`
* `PendingContactStateChangedEvent` * `PendingContactStateChangedEvent`
* `PendingContactRemovedEvent` * `PendingContactRemovedEvent`
* `ContactAddedRemotelyEvent` (when the pending contact becomes an actual contact) * `ContactAddedRemotelyEvent` (when the pending contact becomes an actual contact)
It is possible to get a list of all pending contacts:
`GET /v1/contacts/add/pending`
This will return a JSON array of pending contacts formatted as shown above.
To remove a pending contact and abort the process of adding it: To remove a pending contact and abort the process of adding it:
`DELETE /v1/contacts/add/pending` `DELETE /v1/contacts/add/pending`
@@ -302,6 +313,22 @@ it will send a JSON object representing the new contact to connected websocket c
} }
``` ```
### A pending contact was added
```json
{
"data": {
"pendingContact": {
"pendingContactId": "jsTgWcsEQ2g9rnomeK1g/hmO8M1Ix6ZIGWAjgBtlS9U=",
"alias": "ztatsaajzeegraqcizbbfftofdekclatyht",
"timestamp": 1557838312175
}
},
"name": "PendingContactAddedEvent",
"type": "event"
}
```
### A pending contact changed its state ### A pending contact changed its state
```json ```json

View File

@@ -8,6 +8,7 @@ import org.briarproject.bramble.api.contact.ContactManager
import org.briarproject.bramble.api.contact.HandshakeLinkConstants.LINK_REGEX import org.briarproject.bramble.api.contact.HandshakeLinkConstants.LINK_REGEX
import org.briarproject.bramble.api.contact.PendingContactId import org.briarproject.bramble.api.contact.PendingContactId
import org.briarproject.bramble.api.contact.event.ContactAddedRemotelyEvent import org.briarproject.bramble.api.contact.event.ContactAddedRemotelyEvent
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.contact.event.PendingContactStateChangedEvent
import org.briarproject.bramble.api.db.NoSuchContactException import org.briarproject.bramble.api.db.NoSuchContactException
@@ -28,6 +29,7 @@ import javax.inject.Singleton
internal const val EVENT_CONTACT_ADDED_REMOTELY = "ContactAddedRemotelyEvent" internal const val EVENT_CONTACT_ADDED_REMOTELY = "ContactAddedRemotelyEvent"
internal const val EVENT_PENDING_CONTACT_STATE_CHANGED = "PendingContactStateChangedEvent" internal const val EVENT_PENDING_CONTACT_STATE_CHANGED = "PendingContactStateChangedEvent"
internal const val EVENT_PENDING_CONTACT_ADDED = "PendingContactAddedEvent"
internal const val EVENT_PENDING_CONTACT_REMOVED = "PendingContactRemovedEvent" internal const val EVENT_PENDING_CONTACT_REMOVED = "PendingContactRemovedEvent"
@Immutable @Immutable
@@ -47,6 +49,9 @@ constructor(
is PendingContactStateChangedEvent -> { is PendingContactStateChangedEvent -> {
webSocket.sendEvent(EVENT_PENDING_CONTACT_STATE_CHANGED, e.output()) webSocket.sendEvent(EVENT_PENDING_CONTACT_STATE_CHANGED, e.output())
} }
is PendingContactAddedEvent -> {
webSocket.sendEvent(EVENT_PENDING_CONTACT_ADDED, e.output())
}
is PendingContactRemovedEvent -> { is PendingContactRemovedEvent -> {
webSocket.sendEvent(EVENT_PENDING_CONTACT_REMOVED, e.output()) webSocket.sendEvent(EVENT_PENDING_CONTACT_REMOVED, e.output())
} }
@@ -78,8 +83,8 @@ constructor(
} }
override fun listPendingContacts(ctx: Context): Context { override fun listPendingContacts(ctx: Context): Context {
val pendingContacts = contactManager.pendingContacts.map { pendingContact -> val pendingContacts = contactManager.pendingContacts.map { pair ->
pendingContact.output() JsonDict("pendingContact" to pair.first.output(), "state" to pair.second.output())
} }
return ctx.json(pendingContacts) return ctx.json(pendingContacts)
} }

View File

@@ -3,6 +3,7 @@ package org.briarproject.briar.headless.contact
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.PendingContactState.* import org.briarproject.bramble.api.contact.PendingContactState.*
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.contact.event.PendingContactStateChangedEvent
import org.briarproject.briar.headless.json.JsonDict import org.briarproject.briar.headless.json.JsonDict
@@ -10,7 +11,6 @@ import org.briarproject.briar.headless.json.JsonDict
internal fun PendingContact.output() = JsonDict( internal fun PendingContact.output() = JsonDict(
"pendingContactId" to id.bytes, "pendingContactId" to id.bytes,
"alias" to alias, "alias" to alias,
"state" to state.output(),
"timestamp" to timestamp "timestamp" to timestamp
) )
@@ -22,6 +22,10 @@ internal fun PendingContactState.output() = when(this) {
else -> throw AssertionError() else -> throw AssertionError()
} }
internal fun PendingContactAddedEvent.output() = JsonDict(
"pendingContact" to pendingContact.output()
)
internal fun PendingContactStateChangedEvent.output() = JsonDict( internal fun PendingContactStateChangedEvent.output() = JsonDict(
"pendingContactId" to id.bytes, "pendingContactId" to id.bytes,
"state" to pendingContactState.output() "state" to pendingContactState.output()

View File

@@ -11,7 +11,7 @@ import org.junit.jupiter.api.Test
class ContactControllerIntegrationTest: IntegrationTest() { class ContactControllerIntegrationTest: IntegrationTest() {
@Test @Test
fun `list of contacts need authentication token`() { fun `returning list of contacts needs authentication token`() {
val response = getWithWrongToken("$url/contacts") val response = getWithWrongToken("$url/contacts")
assertEquals(401, response.statusCode) assertEquals(401, response.statusCode)
} }
@@ -72,11 +72,10 @@ class ContactControllerIntegrationTest: IntegrationTest() {
assertEquals(200, response.statusCode) assertEquals(200, response.statusCode)
assertEquals(1, response.jsonArray.length()) assertEquals(1, response.jsonArray.length())
val jsonObject = response.jsonArray.getJSONObject(0) val jsonObject = response.jsonArray.getJSONObject(0)
assertEquals(alias, jsonObject.getString("alias")) assertEquals(alias, jsonObject.getJSONObject("pendingContact").getString("alias"))
assertEquals("waiting_for_connection", jsonObject.getString("state"))
// remove pending contact again // remove pending contact again
val idString = jsonObject.getString("pendingContactId") val idString = jsonObject.getJSONObject("pendingContact").getString("pendingContactId")
val deleteJson = """{"pendingContactId": "$idString"}""" val deleteJson = """{"pendingContactId": "$idString"}"""
response = delete("$url/contacts/add/pending", deleteJson) response = delete("$url/contacts/add/pending", deleteJson)
assertEquals(200, response.statusCode) assertEquals(200, response.statusCode)
@@ -94,7 +93,7 @@ class ContactControllerIntegrationTest: IntegrationTest() {
} }
@Test @Test
fun `adding pending contacts needs authentication token`() { fun `adding a pending contact needs authentication token`() {
val response = postWithWrongToken("$url/contacts/add/pending") val response = postWithWrongToken("$url/contacts/add/pending")
assertEquals(401, response.statusCode) assertEquals(401, response.statusCode)
} }
@@ -106,7 +105,7 @@ class ContactControllerIntegrationTest: IntegrationTest() {
} }
@Test @Test
fun `deleting contact need authentication token`() { fun `deleting a contact needs authentication token`() {
val response = deleteWithWrongToken("$url/contacts/1") val response = deleteWithWrongToken("$url/contacts/1")
assertEquals(401, response.statusCode) assertEquals(401, response.statusCode)
} }

View File

@@ -7,11 +7,14 @@ import io.mockk.Runs
import io.mockk.every import io.mockk.every
import io.mockk.just import io.mockk.just
import io.mockk.runs import io.mockk.runs
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.PendingContactId import org.briarproject.bramble.api.contact.PendingContactId
import org.briarproject.bramble.api.contact.PendingContactState.FAILED import org.briarproject.bramble.api.contact.PendingContactState.FAILED
import org.briarproject.bramble.api.contact.PendingContactState.WAITING_FOR_CONNECTION
import org.briarproject.bramble.api.contact.event.ContactAddedRemotelyEvent import org.briarproject.bramble.api.contact.event.ContactAddedRemotelyEvent
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.contact.event.PendingContactStateChangedEvent
import org.briarproject.bramble.api.db.NoSuchContactException import org.briarproject.bramble.api.db.NoSuchContactException
@@ -124,8 +127,14 @@ internal class ContactControllerTest : ControllerTest() {
@Test @Test
fun testListPendingContacts() { fun testListPendingContacts() {
every { contactManager.pendingContacts } returns listOf(pendingContact) every { contactManager.pendingContacts } returns listOf(
every { ctx.json(listOf(pendingContact.output())) } returns ctx Pair(pendingContact, WAITING_FOR_CONNECTION)
)
val dict = JsonDict(
"pendingContact" to pendingContact.output(),
"state" to WAITING_FOR_CONNECTION.output()
)
every { ctx.json(listOf(dict)) } returns ctx
controller.listPendingContacts(ctx) controller.listPendingContacts(ctx)
} }
@@ -225,6 +234,20 @@ internal class ContactControllerTest : ControllerTest() {
controller.eventOccurred(event) controller.eventOccurred(event)
} }
@Test
fun testPendingContactAddedEvent() {
val event = PendingContactAddedEvent(pendingContact)
every {
webSocketController.sendEvent(
EVENT_PENDING_CONTACT_ADDED,
event.output()
)
} just runs
controller.eventOccurred(event)
}
@Test @Test
fun testPendingContactRemovedEvent() { fun testPendingContactRemovedEvent() {
val event = PendingContactRemovedEvent(pendingContact.id) val event = PendingContactRemovedEvent(pendingContact.id)
@@ -284,13 +307,27 @@ internal class ContactControllerTest : ControllerTest() {
{ {
"pendingContactId": ${toJson(pendingContact.id.bytes)}, "pendingContactId": ${toJson(pendingContact.id.bytes)},
"alias": "${pendingContact.alias}", "alias": "${pendingContact.alias}",
"state": "${pendingContact.state.name.toLowerCase()}",
"timestamp": ${pendingContact.timestamp} "timestamp": ${pendingContact.timestamp}
} }
""" """
assertJsonEquals(json, pendingContact.output()) assertJsonEquals(json, pendingContact.output())
} }
@Test
fun testOutputPendingContactAddedEvent() {
val event = PendingContactAddedEvent(pendingContact)
val json = """
{
"pendingContact": {
"pendingContactId": ${toJson(pendingContact.id.bytes)},
"alias": "${pendingContact.alias}",
"timestamp": ${pendingContact.timestamp}
}
}
"""
assertJsonEquals(json, event.output())
}
@Test @Test
fun testOutputPendingContactStateChangedEvent() { fun testOutputPendingContactStateChangedEvent() {
val event = PendingContactStateChangedEvent(pendingContact.id, FAILED) val event = PendingContactStateChangedEvent(pendingContact.id, FAILED)