From e979f17e45e2ef1e08f5e2ab2fc2f46edc91c2fc Mon Sep 17 00:00:00 2001 From: akwizgran Date: Fri, 12 Feb 2016 11:30:33 +0000 Subject: [PATCH 1/3] Execute test tasks in a deterministic order. --- .../src/org/briarproject/plugins/PluginManagerImplTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/briar-tests/src/org/briarproject/plugins/PluginManagerImplTest.java b/briar-tests/src/org/briarproject/plugins/PluginManagerImplTest.java index 25cb91d03..52b5b5448 100644 --- a/briar-tests/src/org/briarproject/plugins/PluginManagerImplTest.java +++ b/briar-tests/src/org/briarproject/plugins/PluginManagerImplTest.java @@ -38,7 +38,7 @@ public class PluginManagerImplTest extends BriarTestCase { Mockery context = new Mockery() {{ setThreadingPolicy(new Synchroniser()); }}; - final Executor ioExecutor = Executors.newCachedThreadPool(); + final Executor ioExecutor = Executors.newSingleThreadExecutor(); final EventBus eventBus = context.mock(EventBus.class); final SimplexPluginConfig simplexPluginConfig = context.mock(SimplexPluginConfig.class); From 6b76b75d086024c5c3565526c3544330feed190b Mon Sep 17 00:00:00 2001 From: akwizgran Date: Fri, 12 Feb 2016 11:44:07 +0000 Subject: [PATCH 2/3] More efficient database joins. Don't keep message status rows for groups that are invisible to the contact - this avoids the need to join the groupVisibilities table when selecting messages to offer or send. Add or remove status rows when group visibility changes. --- .../src/org/briarproject/db/Database.java | 16 ++- .../db/DatabaseComponentImpl.java | 50 +++---- .../src/org/briarproject/db/JdbcDatabase.java | 129 ++++++++---------- .../db/DatabaseComponentImplTest.java | 11 +- .../org/briarproject/db/H2DatabaseTest.java | 38 ------ 5 files changed, 93 insertions(+), 151 deletions(-) diff --git a/briar-core/src/org/briarproject/db/Database.java b/briar-core/src/org/briarproject/db/Database.java index 91d17b49d..aef7a1437 100644 --- a/briar-core/src/org/briarproject/db/Database.java +++ b/briar-core/src/org/briarproject/db/Database.java @@ -188,11 +188,6 @@ interface Database { */ Contact getContact(T txn, ContactId c) throws DbException; - /** - * Returns the IDs of all contacts. - */ - Collection getContactIds(T txn) throws DbException; - /** * Returns all contacts. */ @@ -240,6 +235,11 @@ interface Database { */ Collection getLocalAuthors(T txn) throws DbException; + /** + * Returns the IDs of all messages in the given group. + */ + Collection getMessageIds(T txn, GroupId g) throws DbException; + /** * Returns the metadata for all messages in the given group. */ @@ -424,6 +424,12 @@ interface Database { void removeOfferedMessages(T txn, ContactId c, Collection requested) throws DbException; + /** + * Removes the status of the given message with respect to the given + * contact. + */ + void removeStatus(T txn, ContactId c, MessageId m) throws DbException; + /** * Removes a transport (and all associated state) from the database. */ diff --git a/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java b/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java index 8ed1ece78..1e3a18c91 100644 --- a/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java +++ b/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java @@ -56,7 +56,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; -import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -70,12 +69,6 @@ import static org.briarproject.api.sync.ValidationManager.Validity.UNKNOWN; import static org.briarproject.api.sync.ValidationManager.Validity.VALID; import static org.briarproject.db.DatabaseConstants.MAX_OFFERED_MESSAGES; -/** - * An implementation of DatabaseComponent using reentrant read-write locks. - * Depending on the JVM's lock implementation, this implementation may allow - * writers to starve. LockFairnessTest can be used to test whether this - * implementation is safe on a given JVM. - */ class DatabaseComponentImpl implements DatabaseComponent { private static final Logger LOG = @@ -177,7 +170,7 @@ class DatabaseComponentImpl implements DatabaseComponent { if (!db.containsGroup(txn, m.getGroupId())) throw new NoSuchGroupException(); if (!db.containsMessage(txn, m.getId())) { - addMessage(txn, m, VALID, shared, null); + addMessage(txn, m, VALID, shared); transaction.attach(new MessageAddedEvent(m, null)); transaction.attach(new MessageValidatedEvent(m, c, true, true)); if (shared) transaction.attach(new MessageSharedEvent(m)); @@ -185,26 +178,12 @@ class DatabaseComponentImpl implements DatabaseComponent { db.mergeMessageMetadata(txn, m.getId(), meta); } - /** - * Stores a message and initialises its status with respect to each contact. - * - * @param sender null for a locally generated message. - */ - private void addMessage(T txn, Message m, Validity validity, boolean shared, - ContactId sender) throws DbException { + private void addMessage(T txn, Message m, Validity validity, boolean shared) + throws DbException { db.addMessage(txn, m, validity, shared); - GroupId g = m.getGroupId(); - Collection visibility = db.getVisibility(txn, g); - visibility = new HashSet(visibility); - for (ContactId c : db.getContactIds(txn)) { - if (visibility.contains(c)) { - boolean offered = db.removeOfferedMessage(txn, c, m.getId()); - boolean seen = offered || c.equals(sender); - db.addStatus(txn, c, m.getId(), offered, seen); - } else { - if (c.equals(sender)) throw new IllegalStateException(); - db.addStatus(txn, c, m.getId(), false, false); - } + for (ContactId c : db.getVisibility(txn, m.getGroupId())) { + boolean offered = db.removeOfferedMessage(txn, c, m.getId()); + db.addStatus(txn, c, m.getId(), offered, offered); } } @@ -516,7 +495,7 @@ class DatabaseComponentImpl implements DatabaseComponent { throw new NoSuchContactException(); if (db.containsVisibleGroup(txn, c, m.getGroupId())) { if (!db.containsMessage(txn, m.getId())) { - addMessage(txn, m, UNKNOWN, false, c); + addMessage(txn, m, UNKNOWN, false); transaction.attach(new MessageAddedEvent(m, c)); } db.raiseAckFlag(txn, c, m.getId()); @@ -529,8 +508,8 @@ class DatabaseComponentImpl implements DatabaseComponent { T txn = unbox(transaction); if (!db.containsContact(txn, c)) throw new NoSuchContactException(); - int count = db.countOfferedMessages(txn, c); boolean ack = false, request = false; + int count = db.countOfferedMessages(txn, c); for (MessageId m : o.getMessageIds()) { if (db.containsVisibleMessage(txn, c, m)) { db.raiseSeenFlag(txn, c, m); @@ -638,8 +617,17 @@ class DatabaseComponentImpl implements DatabaseComponent { if (!db.containsGroup(txn, g)) throw new NoSuchGroupException(); boolean wasVisible = db.containsVisibleGroup(txn, c, g); - if (visible && !wasVisible) db.addVisibility(txn, c, g); - else if (!visible && wasVisible) db.removeVisibility(txn, c, g); + if (visible && !wasVisible) { + db.addVisibility(txn, c, g); + for (MessageId m : db.getMessageIds(txn, g)) { + boolean seen = db.removeOfferedMessage(txn, c, m); + db.addStatus(txn, c, m, seen, seen); + } + } else if (!visible && wasVisible) { + db.removeVisibility(txn, c, g); + for (MessageId m : db.getMessageIds(txn, g)) + db.removeStatus(txn, c, m); + } if (visible != wasVisible) { List affected = Collections.singletonList(c); transaction.attach(new GroupVisibilityUpdatedEvent(affected)); diff --git a/briar-core/src/org/briarproject/db/JdbcDatabase.java b/briar-core/src/org/briarproject/db/JdbcDatabase.java index 4af26f320..4a1cca229 100644 --- a/briar-core/src/org/briarproject/db/JdbcDatabase.java +++ b/briar-core/src/org/briarproject/db/JdbcDatabase.java @@ -63,15 +63,15 @@ import static org.briarproject.db.ExponentialBackoff.calculateExpiry; */ abstract class JdbcDatabase implements Database { - private static final int SCHEMA_VERSION = 21; - private static final int MIN_SCHEMA_VERSION = 21; + private static final int SCHEMA_VERSION = 22; + private static final int MIN_SCHEMA_VERSION = 22; private static final String CREATE_SETTINGS = "CREATE TABLE settings" - + " (key VARCHAR NOT NULL," + + " (namespace VARCHAR NOT NULL," + + " key VARCHAR NOT NULL," + " value VARCHAR NOT NULL," - + " namespace VARCHAR NOT NULL," - + " PRIMARY KEY (key, namespace))"; + + " PRIMARY KEY (namespace, key))"; private static final String CREATE_LOCAL_AUTHORS = "CREATE TABLE localAuthors" @@ -468,31 +468,6 @@ abstract class JdbcDatabase implements Database { if (rs.next()) throw new DbStateException(); rs.close(); ps.close(); - // Create a status row for each message - sql = "SELECT messageID FROM messages"; - ps = txn.prepareStatement(sql); - rs = ps.executeQuery(); - Collection ids = new ArrayList(); - while (rs.next()) ids.add(rs.getBytes(1)); - rs.close(); - ps.close(); - if (!ids.isEmpty()) { - sql = "INSERT INTO statuses (messageId, contactId, ack," - + " seen, requested, expiry, txCount)" - + " VALUES (?, ?, FALSE, FALSE, FALSE, 0, 0)"; - ps = txn.prepareStatement(sql); - ps.setInt(2, c.getInt()); - for (byte[] id : ids) { - ps.setBytes(1, id); - ps.addBatch(); - } - int[] batchAffected = ps.executeBatch(); - if (batchAffected.length != ids.size()) - throw new DbStateException(); - for (int rows : batchAffected) - if (rows != 1) throw new DbStateException(); - ps.close(); - } return c; } catch (SQLException e) { tryToClose(rs); @@ -973,26 +948,6 @@ abstract class JdbcDatabase implements Database { } } - public Collection getContactIds(Connection txn) - throws DbException { - PreparedStatement ps = null; - ResultSet rs = null; - try { - String sql = "SELECT contactId FROM contacts"; - ps = txn.prepareStatement(sql); - rs = ps.executeQuery(); - List ids = new ArrayList(); - while (rs.next()) ids.add(new ContactId(rs.getInt(1))); - rs.close(); - ps.close(); - return Collections.unmodifiableList(ids); - } catch (SQLException e) { - tryToClose(rs); - tryToClose(ps); - throw new DbException(e); - } - } - public Collection getContacts(Connection txn) throws DbException { PreparedStatement ps = null; @@ -1151,6 +1106,27 @@ abstract class JdbcDatabase implements Database { } } + public Collection getMessageIds(Connection txn, GroupId g) + throws DbException { + PreparedStatement ps = null; + ResultSet rs = null; + try { + String sql = "SELECT messageId FROM messages WHERE groupId = ?"; + ps = txn.prepareStatement(sql); + ps.setBytes(1, g.getBytes()); + rs = ps.executeQuery(); + List ids = new ArrayList(); + while (rs.next()) ids.add(new MessageId(rs.getBytes(1))); + rs.close(); + ps.close(); + return Collections.unmodifiableList(ids); + } catch (SQLException e) { + tryToClose(rs); + tryToClose(ps); + throw new DbException(e); + } + } + public Map getMessageMetadata(Connection txn, GroupId g) throws DbException { PreparedStatement ps = null; @@ -1309,15 +1285,12 @@ abstract class JdbcDatabase implements Database { ResultSet rs = null; try { String sql = "SELECT m.messageId FROM messages AS m" - + " JOIN groupVisibilities AS gv" - + " ON m.groupId = gv.groupId" + " JOIN statuses AS s" + " ON m.messageId = s.messageId" - + " AND gv.contactId = s.contactId" - + " WHERE gv.contactId = ?" + + " WHERE contactId = ?" + " AND valid = ? AND shared = TRUE AND raw IS NOT NULL" + " AND seen = FALSE AND requested = FALSE" - + " AND s.expiry < ?" + + " AND expiry < ?" + " ORDER BY timestamp DESC LIMIT ?"; ps = txn.prepareStatement(sql); ps.setInt(1, c.getInt()); @@ -1368,15 +1341,12 @@ abstract class JdbcDatabase implements Database { ResultSet rs = null; try { String sql = "SELECT length, m.messageId FROM messages AS m" - + " JOIN groupVisibilities AS gv" - + " ON m.groupId = gv.groupId" + " JOIN statuses AS s" + " ON m.messageId = s.messageId" - + " AND gv.contactId = s.contactId" - + " WHERE gv.contactId = ?" + + " WHERE contactId = ?" + " AND valid = ? AND shared = TRUE AND raw IS NOT NULL" + " AND seen = FALSE" - + " AND s.expiry < ?" + + " AND expiry < ?" + " ORDER BY timestamp DESC"; ps = txn.prepareStatement(sql); ps.setInt(1, c.getInt()); @@ -1454,15 +1424,12 @@ abstract class JdbcDatabase implements Database { ResultSet rs = null; try { String sql = "SELECT length, m.messageId FROM messages AS m" - + " JOIN groupVisibilities AS gv" - + " ON m.groupId = gv.groupId" + " JOIN statuses AS s" + " ON m.messageId = s.messageId" - + " AND gv.contactId = s.contactId" - + " WHERE gv.contactId = ?" + + " WHERE contactId = ?" + " AND valid = ? AND shared = TRUE AND raw IS NOT NULL" + " AND seen = FALSE AND requested = TRUE" - + " AND s.expiry < ?" + + " AND expiry < ?" + " ORDER BY timestamp DESC"; ps = txn.prepareStatement(sql); ps.setInt(1, c.getInt()); @@ -1777,12 +1744,12 @@ abstract class JdbcDatabase implements Database { try { // Update any settings that already exist String sql = "UPDATE settings SET value = ?" - + " WHERE key = ? AND namespace = ?"; + + " WHERE namespace = ? AND key = ?"; ps = txn.prepareStatement(sql); for (Entry e : s.entrySet()) { ps.setString(1, e.getValue()); - ps.setString(2, e.getKey()); - ps.setString(3, namespace); + ps.setString(2, namespace); + ps.setString(3, e.getKey()); ps.addBatch(); } int[] batchAffected = ps.executeBatch(); @@ -1792,15 +1759,15 @@ abstract class JdbcDatabase implements Database { if (rows > 1) throw new DbStateException(); } // Insert any settings that don't already exist - sql = "INSERT INTO settings (key, value, namespace)" + sql = "INSERT INTO settings (namespace, key, value)" + " VALUES (?, ?, ?)"; ps = txn.prepareStatement(sql); int updateIndex = 0, inserted = 0; for (Entry e : s.entrySet()) { if (batchAffected[updateIndex] == 0) { - ps.setString(1, e.getKey()); - ps.setString(2, e.getValue()); - ps.setString(3, namespace); + ps.setString(1, namespace); + ps.setString(2, e.getKey()); + ps.setString(3, e.getValue()); ps.addBatch(); inserted++; } @@ -1976,6 +1943,24 @@ abstract class JdbcDatabase implements Database { } } + public void removeStatus(Connection txn, ContactId c, MessageId m) + throws DbException { + PreparedStatement ps = null; + try { + String sql = "DELETE FROM statuses" + + " WHERE contactId = ? AND messageId = ?"; + ps = txn.prepareStatement(sql); + ps.setInt(1, c.getInt()); + ps.setBytes(2, m.getBytes()); + int affected = ps.executeUpdate(); + if (affected != 1) throw new DbStateException(); + ps.close(); + } catch (SQLException e) { + tryToClose(ps); + throw new DbException(e); + } + } + public void removeTransport(Connection txn, TransportId t) throws DbException { PreparedStatement ps = null; diff --git a/briar-tests/src/org/briarproject/db/DatabaseComponentImplTest.java b/briar-tests/src/org/briarproject/db/DatabaseComponentImplTest.java index 3488bb2d1..f1cc05d64 100644 --- a/briar-tests/src/org/briarproject/db/DatabaseComponentImplTest.java +++ b/briar-tests/src/org/briarproject/db/DatabaseComponentImplTest.java @@ -261,8 +261,6 @@ public class DatabaseComponentImplTest extends BriarTestCase { oneOf(database).mergeMessageMetadata(txn, messageId, metadata); oneOf(database).getVisibility(txn, groupId); will(returnValue(Collections.singletonList(contactId))); - oneOf(database).getContactIds(txn); - will(returnValue(Collections.singletonList(contactId))); oneOf(database).removeOfferedMessage(txn, contactId, messageId); will(returnValue(false)); oneOf(database).addStatus(txn, contactId, messageId, false, false); @@ -1074,11 +1072,9 @@ public class DatabaseComponentImplTest extends BriarTestCase { oneOf(database).addMessage(txn, message, UNKNOWN, false); oneOf(database).getVisibility(txn, groupId); will(returnValue(Collections.singletonList(contactId))); - oneOf(database).getContactIds(txn); - will(returnValue(Collections.singletonList(contactId))); oneOf(database).removeOfferedMessage(txn, contactId, messageId); will(returnValue(false)); - oneOf(database).addStatus(txn, contactId, messageId, false, true); + oneOf(database).addStatus(txn, contactId, messageId, false, false); oneOf(database).raiseAckFlag(txn, contactId, messageId); oneOf(database).commitTransaction(txn); // The message was received and added @@ -1270,6 +1266,11 @@ public class DatabaseComponentImplTest extends BriarTestCase { oneOf(database).containsVisibleGroup(txn, contactId, groupId); will(returnValue(false)); // Not yet visible oneOf(database).addVisibility(txn, contactId, groupId); + oneOf(database).getMessageIds(txn, groupId); + will(returnValue(Collections.singletonList(messageId))); + oneOf(database).removeOfferedMessage(txn, contactId, messageId); + will(returnValue(false)); + oneOf(database).addStatus(txn, contactId, messageId, false, false); oneOf(database).commitTransaction(txn); oneOf(eventBus).broadcast(with(any( GroupVisibilityUpdatedEvent.class))); diff --git a/briar-tests/src/org/briarproject/db/H2DatabaseTest.java b/briar-tests/src/org/briarproject/db/H2DatabaseTest.java index 34a91d63c..995f7ace5 100644 --- a/briar-tests/src/org/briarproject/db/H2DatabaseTest.java +++ b/briar-tests/src/org/briarproject/db/H2DatabaseTest.java @@ -302,44 +302,6 @@ public class H2DatabaseTest extends BriarTestCase { db.close(); } - @Test - public void testSendableMessagesMustBeVisible() throws Exception { - Database db = open(false); - Connection txn = db.startTransaction(); - - // Add a contact, a group and a message - db.addLocalAuthor(txn, localAuthor); - assertEquals(contactId, db.addContact(txn, author, localAuthorId)); - db.addGroup(txn, group); - db.addMessage(txn, message, VALID, true); - db.addStatus(txn, contactId, messageId, false, false); - - // The group is not visible to the contact, so the message - // should not be sendable - Collection ids = db.getMessagesToSend(txn, contactId, - ONE_MEGABYTE); - assertTrue(ids.isEmpty()); - ids = db.getMessagesToOffer(txn, contactId, 100); - assertTrue(ids.isEmpty()); - - // Making the group visible should make the message sendable - db.addVisibility(txn, contactId, groupId); - ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE); - assertEquals(Collections.singletonList(messageId), ids); - ids = db.getMessagesToOffer(txn, contactId, 100); - assertEquals(Collections.singletonList(messageId), ids); - - // Making the group invisible should make the message unsendable - db.removeVisibility(txn, contactId, groupId); - ids = db.getMessagesToSend(txn, contactId, ONE_MEGABYTE); - assertTrue(ids.isEmpty()); - ids = db.getMessagesToOffer(txn, contactId, 100); - assertTrue(ids.isEmpty()); - - db.commitTransaction(txn); - db.close(); - } - @Test public void testMessagesToAck() throws Exception { Database db = open(false); From a6baa5821e932a09878f44da39090aa8e2e3d295 Mon Sep 17 00:00:00 2001 From: akwizgran Date: Wed, 17 Feb 2016 18:10:52 +0000 Subject: [PATCH 3/3] Added active flag to contacts. --- .../android/contact/ContactListFragment.java | 2 +- .../android/forum/ShareForumActivity.java | 2 +- .../org/briarproject/api/contact/Contact.java | 9 ++- .../api/contact/ContactManager.java | 10 ++- .../api/db/DatabaseComponent.java | 10 ++- .../api/event/ContactStatusChangedEvent.java | 23 +++++++ .../contact/ContactManagerImpl.java | 24 +++++-- .../src/org/briarproject/db/Database.java | 8 ++- .../db/DatabaseComponentImpl.java | 14 +++- .../src/org/briarproject/db/JdbcDatabase.java | 43 ++++++++++--- .../briarproject/invitation/Connector.java | 2 +- .../db/DatabaseComponentImplTest.java | 28 +++++--- .../org/briarproject/db/H2DatabaseTest.java | 64 ++++++++++++------- .../sync/SimplexMessagingIntegrationTest.java | 6 +- 14 files changed, 186 insertions(+), 59 deletions(-) create mode 100644 briar-api/src/org/briarproject/api/event/ContactStatusChangedEvent.java diff --git a/briar-android/src/org/briarproject/android/contact/ContactListFragment.java b/briar-android/src/org/briarproject/android/contact/ContactListFragment.java index bd52792c5..b1352dda7 100644 --- a/briar-android/src/org/briarproject/android/contact/ContactListFragment.java +++ b/briar-android/src/org/briarproject/android/contact/ContactListFragment.java @@ -125,7 +125,7 @@ public class ContactListFragment extends BaseEventFragment { long now = System.currentTimeMillis(); List contacts = new ArrayList(); - for (Contact c : contactManager.getContacts()) { + for (Contact c : contactManager.getActiveContacts()) { try { ContactId id = c.getId(); GroupId groupId = diff --git a/briar-android/src/org/briarproject/android/forum/ShareForumActivity.java b/briar-android/src/org/briarproject/android/forum/ShareForumActivity.java index 2d2377119..59821f9a1 100644 --- a/briar-android/src/org/briarproject/android/forum/ShareForumActivity.java +++ b/briar-android/src/org/briarproject/android/forum/ShareForumActivity.java @@ -138,7 +138,7 @@ SelectContactsDialog.Listener { public void run() { try { long now = System.currentTimeMillis(); - contacts = contactManager.getContacts(); + contacts = contactManager.getActiveContacts(); selected = forumSharingManager.getSharedWith(groupId); long duration = System.currentTimeMillis() - now; if (LOG.isLoggable(INFO)) diff --git a/briar-api/src/org/briarproject/api/contact/Contact.java b/briar-api/src/org/briarproject/api/contact/Contact.java index 5c5b9b197..12e1efcbf 100644 --- a/briar-api/src/org/briarproject/api/contact/Contact.java +++ b/briar-api/src/org/briarproject/api/contact/Contact.java @@ -8,11 +8,14 @@ public class Contact { private final ContactId id; private final Author author; private final AuthorId localAuthorId; + private final boolean active; - public Contact(ContactId id, Author author, AuthorId localAuthorId) { + public Contact(ContactId id, Author author, AuthorId localAuthorId, + boolean active) { this.id = id; this.author = author; this.localAuthorId = localAuthorId; + this.active = active; } public ContactId getId() { @@ -27,6 +30,10 @@ public class Contact { return localAuthorId; } + public boolean isActive() { + return active; + } + @Override public int hashCode() { return id.hashCode(); diff --git a/briar-api/src/org/briarproject/api/contact/ContactManager.java b/briar-api/src/org/briarproject/api/contact/ContactManager.java index ffc493477..47095d2ba 100644 --- a/briar-api/src/org/briarproject/api/contact/ContactManager.java +++ b/briar-api/src/org/briarproject/api/contact/ContactManager.java @@ -19,17 +19,21 @@ public interface ContactManager { * Stores a contact associated with the given local and remote pseudonyms, * and returns an ID for the contact. */ - ContactId addContact(Author remote, AuthorId local) throws DbException; + ContactId addContact(Author remote, AuthorId local, boolean active) + throws DbException; /** Returns the contact with the given ID. */ Contact getContact(ContactId c) throws DbException; - /** Returns all contacts. */ - Collection getContacts() throws DbException; + /** Returns all active contacts. */ + Collection getActiveContacts() throws DbException; /** Removes a contact and all associated state. */ void removeContact(ContactId c) throws DbException; + /** Marks a contact as active or inactive. */ + void setContactActive(ContactId c, boolean active) throws DbException; + interface AddContactHook { void addingContact(Transaction txn, Contact c) throws DbException; } diff --git a/briar-api/src/org/briarproject/api/db/DatabaseComponent.java b/briar-api/src/org/briarproject/api/db/DatabaseComponent.java index ca2497694..08bc9692f 100644 --- a/briar-api/src/org/briarproject/api/db/DatabaseComponent.java +++ b/briar-api/src/org/briarproject/api/db/DatabaseComponent.java @@ -59,8 +59,8 @@ public interface DatabaseComponent { * Stores a contact associated with the given local and remote pseudonyms, * and returns an ID for the contact. */ - ContactId addContact(Transaction txn, Author remote, AuthorId local) - throws DbException; + ContactId addContact(Transaction txn, Author remote, AuthorId local, + boolean active) throws DbException; /** * Stores a group. @@ -317,6 +317,12 @@ public interface DatabaseComponent { */ void removeTransport(Transaction txn, TransportId t) throws DbException; + /** + * Marks the given contact as active or inactive. + */ + void setContactActive(Transaction txn, ContactId c, boolean active) + throws DbException; + /** * Marks the given message as shared or unshared. */ diff --git a/briar-api/src/org/briarproject/api/event/ContactStatusChangedEvent.java b/briar-api/src/org/briarproject/api/event/ContactStatusChangedEvent.java new file mode 100644 index 000000000..ddbdbd5db --- /dev/null +++ b/briar-api/src/org/briarproject/api/event/ContactStatusChangedEvent.java @@ -0,0 +1,23 @@ +package org.briarproject.api.event; + +import org.briarproject.api.contact.ContactId; + +/** An event that is broadcast when a contact is marked active or inactive. */ +public class ContactStatusChangedEvent extends Event { + + private final ContactId contactId; + private final boolean active; + + public ContactStatusChangedEvent(ContactId contactId, boolean active) { + this.contactId = contactId; + this.active = active; + } + + public ContactId getContactId() { + return contactId; + } + + public boolean isActive() { + return active; + } +} diff --git a/briar-core/src/org/briarproject/contact/ContactManagerImpl.java b/briar-core/src/org/briarproject/contact/ContactManagerImpl.java index 2fafe8a16..03a4eae72 100644 --- a/briar-core/src/org/briarproject/contact/ContactManagerImpl.java +++ b/briar-core/src/org/briarproject/contact/ContactManagerImpl.java @@ -13,7 +13,9 @@ import org.briarproject.api.identity.AuthorId; import org.briarproject.api.identity.IdentityManager.RemoveIdentityHook; import org.briarproject.api.identity.LocalAuthor; +import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; @@ -41,12 +43,12 @@ class ContactManagerImpl implements ContactManager, RemoveIdentityHook { } @Override - public ContactId addContact(Author remote, AuthorId local) + public ContactId addContact(Author remote, AuthorId local, boolean active) throws DbException { ContactId c; Transaction txn = db.startTransaction(); try { - c = db.addContact(txn, remote, local); + c = db.addContact(txn, remote, local, active); Contact contact = db.getContact(txn, c); for (AddContactHook hook : addHooks) hook.addingContact(txn, contact); @@ -71,7 +73,7 @@ class ContactManagerImpl implements ContactManager, RemoveIdentityHook { } @Override - public Collection getContacts() throws DbException { + public Collection getActiveContacts() throws DbException { Collection contacts; Transaction txn = db.startTransaction(); try { @@ -80,7 +82,9 @@ class ContactManagerImpl implements ContactManager, RemoveIdentityHook { } finally { db.endTransaction(txn); } - return contacts; + List active = new ArrayList(contacts.size()); + for (Contact c : contacts) if (c.isActive()) active.add(c); + return Collections.unmodifiableList(active); } @Override @@ -94,6 +98,18 @@ class ContactManagerImpl implements ContactManager, RemoveIdentityHook { } } + @Override + public void setContactActive(ContactId c, boolean active) + throws DbException { + Transaction txn = db.startTransaction(); + try { + db.setContactActive(txn, c, active); + txn.setComplete(); + } finally { + db.endTransaction(txn); + } + } + private void removeContact(Transaction txn, ContactId c) throws DbException { Contact contact = db.getContact(txn, c); diff --git a/briar-core/src/org/briarproject/db/Database.java b/briar-core/src/org/briarproject/db/Database.java index aef7a1437..2544a9670 100644 --- a/briar-core/src/org/briarproject/db/Database.java +++ b/briar-core/src/org/briarproject/db/Database.java @@ -64,7 +64,7 @@ interface Database { * Stores a contact associated with the given local and remote pseudonyms, * and returns an ID for the contact. */ - ContactId addContact(T txn, Author remote, AuthorId local) + ContactId addContact(T txn, Author remote, AuthorId local, boolean active) throws DbException; /** @@ -446,6 +446,12 @@ interface Database { */ void resetExpiryTime(T txn, ContactId c, MessageId m) throws DbException; + /** + * Marks the given contact as active or inactive. + */ + void setContactActive(T txn, ContactId c, boolean active) + throws DbException; + /** * Marks the given message as shared or unshared. */ diff --git a/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java b/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java index 1e3a18c91..0980962b0 100644 --- a/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java +++ b/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java @@ -16,6 +16,7 @@ import org.briarproject.api.db.NoSuchTransportException; import org.briarproject.api.db.Transaction; import org.briarproject.api.event.ContactAddedEvent; import org.briarproject.api.event.ContactRemovedEvent; +import org.briarproject.api.event.ContactStatusChangedEvent; import org.briarproject.api.event.Event; import org.briarproject.api.event.EventBus; import org.briarproject.api.event.GroupAddedEvent; @@ -136,13 +137,13 @@ class DatabaseComponentImpl implements DatabaseComponent { } public ContactId addContact(Transaction transaction, Author remote, - AuthorId local) throws DbException { + AuthorId local, boolean active) throws DbException { T txn = unbox(transaction); if (!db.containsLocalAuthor(txn, local)) throw new NoSuchLocalAuthorException(); if (db.containsContact(txn, remote.getId(), local)) throw new ContactExistsException(); - ContactId c = db.addContact(txn, remote, local); + ContactId c = db.addContact(txn, remote, local, active); transaction.attach(new ContactAddedEvent(c)); return c; } @@ -580,6 +581,15 @@ class DatabaseComponentImpl implements DatabaseComponent { transaction.attach(new TransportRemovedEvent(t)); } + public void setContactActive(Transaction transaction, ContactId c, + boolean active) throws DbException { + T txn = unbox(transaction); + if (!db.containsContact(txn, c)) + throw new NoSuchContactException(); + db.setContactActive(txn, c, active); + transaction.attach(new ContactStatusChangedEvent(c, active)); + } + public void setMessageShared(Transaction transaction, Message m, boolean shared) throws DbException { T txn = unbox(transaction); diff --git a/briar-core/src/org/briarproject/db/JdbcDatabase.java b/briar-core/src/org/briarproject/db/JdbcDatabase.java index 4a1cca229..7fc836348 100644 --- a/briar-core/src/org/briarproject/db/JdbcDatabase.java +++ b/briar-core/src/org/briarproject/db/JdbcDatabase.java @@ -89,6 +89,7 @@ abstract class JdbcDatabase implements Database { + " name VARCHAR NOT NULL," + " publicKey BINARY NOT NULL," + " localAuthorId HASH NOT NULL," + + " active BOOLEAN NOT NULL," + " PRIMARY KEY (contactId)," + " FOREIGN KEY (localAuthorId)" + " REFERENCES localAuthors (authorId)" @@ -441,20 +442,21 @@ abstract class JdbcDatabase implements Database { return new DeviceId(StringUtils.fromHexString(s.get(DEVICE_ID_KEY))); } - public ContactId addContact(Connection txn, Author remote, AuthorId local) - throws DbException { + public ContactId addContact(Connection txn, Author remote, AuthorId local, + boolean active) throws DbException { PreparedStatement ps = null; ResultSet rs = null; try { // Create a contact row String sql = "INSERT INTO contacts" - + " (authorId, name, publicKey, localAuthorId)" - + " VALUES (?, ?, ?, ?)"; + + " (authorId, name, publicKey, localAuthorId, active)" + + " VALUES (?, ?, ?, ?, ?)"; ps = txn.prepareStatement(sql); ps.setBytes(1, remote.getId().getBytes()); ps.setString(2, remote.getName()); ps.setBytes(3, remote.getPublicKey()); ps.setBytes(4, local.getBytes()); + ps.setBoolean(5, active); int affected = ps.executeUpdate(); if (affected != 1) throw new DbStateException(); ps.close(); @@ -926,7 +928,8 @@ abstract class JdbcDatabase implements Database { PreparedStatement ps = null; ResultSet rs = null; try { - String sql = "SELECT authorId, name, publicKey, localAuthorId" + String sql = "SELECT authorId, name, publicKey," + + " localAuthorId, active" + " FROM contacts" + " WHERE contactId = ?"; ps = txn.prepareStatement(sql); @@ -937,10 +940,11 @@ abstract class JdbcDatabase implements Database { String name = rs.getString(2); byte[] publicKey = rs.getBytes(3); AuthorId localAuthorId = new AuthorId(rs.getBytes(4)); + boolean active = rs.getBoolean(5); rs.close(); ps.close(); Author author = new Author(authorId, name, publicKey); - return new Contact(c, author, localAuthorId); + return new Contact(c, author, localAuthorId, active); } catch (SQLException e) { tryToClose(rs); tryToClose(ps); @@ -954,7 +958,7 @@ abstract class JdbcDatabase implements Database { ResultSet rs = null; try { String sql = "SELECT contactId, authorId, name, publicKey," - + " localAuthorId" + + " localAuthorId, active" + " FROM contacts"; ps = txn.prepareStatement(sql); rs = ps.executeQuery(); @@ -966,7 +970,9 @@ abstract class JdbcDatabase implements Database { byte[] publicKey = rs.getBytes(4); Author author = new Author(authorId, name, publicKey); AuthorId localAuthorId = new AuthorId(rs.getBytes(5)); - contacts.add(new Contact(contactId, author, localAuthorId)); + boolean active = rs.getBoolean(6); + contacts.add(new Contact(contactId, author, localAuthorId, + active)); } rs.close(); ps.close(); @@ -2013,6 +2019,23 @@ abstract class JdbcDatabase implements Database { } } + public void setContactActive(Connection txn, ContactId c, boolean active) + throws DbException { + PreparedStatement ps = null; + try { + String sql = "UPDATE contacts SET active = ? WHERE contactId = ?"; + ps = txn.prepareStatement(sql); + ps.setBoolean(1, active); + ps.setInt(2, c.getInt()); + int affected = ps.executeUpdate(); + if (affected < 0 || affected > 1) throw new DbStateException(); + ps.close(); + } catch (SQLException e) { + tryToClose(ps); + throw new DbException(e); + } + } + public void setMessageShared(Connection txn, MessageId m, boolean shared) throws DbException { PreparedStatement ps = null; @@ -2022,7 +2045,7 @@ abstract class JdbcDatabase implements Database { ps.setBoolean(1, shared); ps.setBytes(2, m.getBytes()); int affected = ps.executeUpdate(); - if (affected < 0) throw new DbStateException(); + if (affected < 0 || affected > 1) throw new DbStateException(); ps.close(); } catch (SQLException e) { tryToClose(ps); @@ -2039,7 +2062,7 @@ abstract class JdbcDatabase implements Database { ps.setInt(1, valid ? VALID.getValue() : INVALID.getValue()); ps.setBytes(2, m.getBytes()); int affected = ps.executeUpdate(); - if (affected < 0) throw new DbStateException(); + if (affected < 0 || affected > 1) throw new DbStateException(); ps.close(); } catch (SQLException e) { tryToClose(ps); diff --git a/briar-core/src/org/briarproject/invitation/Connector.java b/briar-core/src/org/briarproject/invitation/Connector.java index a89aef88a..4bd7fc2ea 100644 --- a/briar-core/src/org/briarproject/invitation/Connector.java +++ b/briar-core/src/org/briarproject/invitation/Connector.java @@ -219,7 +219,7 @@ abstract class Connector extends Thread { long timestamp, boolean alice) throws DbException { // Add the contact to the database contactId = contactManager.addContact(remoteAuthor, - localAuthor.getId()); + localAuthor.getId(), true); // Derive transport keys keyManager.addContact(contactId, master, timestamp, alice); return contactId; diff --git a/briar-tests/src/org/briarproject/db/DatabaseComponentImplTest.java b/briar-tests/src/org/briarproject/db/DatabaseComponentImplTest.java index f1cc05d64..17c27f954 100644 --- a/briar-tests/src/org/briarproject/db/DatabaseComponentImplTest.java +++ b/briar-tests/src/org/briarproject/db/DatabaseComponentImplTest.java @@ -107,7 +107,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { transportId = new TransportId("id"); maxLatency = Integer.MAX_VALUE; contactId = new ContactId(234); - contact = new Contact(contactId, author, localAuthorId); + contact = new Contact(contactId, author, localAuthorId, true); } private DatabaseComponent createDatabaseComponent(Database database, @@ -143,7 +143,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { will(returnValue(true)); oneOf(database).containsContact(txn, authorId, localAuthorId); will(returnValue(false)); - oneOf(database).addContact(txn, author, localAuthorId); + oneOf(database).addContact(txn, author, localAuthorId, true); will(returnValue(contactId)); oneOf(eventBus).broadcast(with(any(ContactAddedEvent.class))); // getContacts() @@ -193,7 +193,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { try { db.addLocalAuthor(transaction, localAuthor); assertEquals(contactId, - db.addContact(transaction, author, localAuthorId)); + db.addContact(transaction, author, localAuthorId, true)); assertEquals(Collections.singletonList(contact), db.getContacts(transaction)); db.addGroup(transaction, group); // First time - listeners called @@ -294,11 +294,11 @@ public class DatabaseComponentImplTest extends BriarTestCase { final EventBus eventBus = context.mock(EventBus.class); context.checking(new Expectations() {{ // Check whether the contact is in the DB (which it's not) - exactly(17).of(database).startTransaction(); + exactly(18).of(database).startTransaction(); will(returnValue(txn)); - exactly(17).of(database).containsContact(txn, contactId); + exactly(18).of(database).containsContact(txn, contactId); will(returnValue(false)); - exactly(17).of(database).abortTransaction(txn); + exactly(18).of(database).abortTransaction(txn); }}); DatabaseComponent db = createDatabaseComponent(database, eventBus, shutdown); @@ -456,6 +456,16 @@ public class DatabaseComponentImplTest extends BriarTestCase { db.endTransaction(transaction); } + transaction = db.startTransaction(); + try { + db.setContactActive(transaction, contactId, true); + fail(); + } catch (NoSuchContactException expected) { + // Expected + } finally { + db.endTransaction(transaction); + } + transaction = db.startTransaction(); try { db.setReorderingWindow(transaction, contactId, transportId, 0, 0, @@ -501,7 +511,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { Transaction transaction = db.startTransaction(); try { - db.addContact(transaction, author, localAuthorId); + db.addContact(transaction, author, localAuthorId, true); fail(); } catch (NoSuchLocalAuthorException expected) { // Expected @@ -755,7 +765,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { will(returnValue(true)); oneOf(database).containsContact(txn, authorId, localAuthorId); will(returnValue(false)); - oneOf(database).addContact(txn, author, localAuthorId); + oneOf(database).addContact(txn, author, localAuthorId, true); will(returnValue(contactId)); oneOf(eventBus).broadcast(with(any(ContactAddedEvent.class))); // endTransaction() @@ -776,7 +786,7 @@ public class DatabaseComponentImplTest extends BriarTestCase { try { db.addLocalAuthor(transaction, localAuthor); assertEquals(contactId, - db.addContact(transaction, author, localAuthorId)); + db.addContact(transaction, author, localAuthorId, true)); transaction.setComplete(); } finally { db.endTransaction(transaction); diff --git a/briar-tests/src/org/briarproject/db/H2DatabaseTest.java b/briar-tests/src/org/briarproject/db/H2DatabaseTest.java index 995f7ace5..5abba7f45 100644 --- a/briar-tests/src/org/briarproject/db/H2DatabaseTest.java +++ b/briar-tests/src/org/briarproject/db/H2DatabaseTest.java @@ -108,7 +108,8 @@ public class H2DatabaseTest extends BriarTestCase { Connection txn = db.startTransaction(); assertFalse(db.containsContact(txn, contactId)); db.addLocalAuthor(txn, localAuthor); - assertEquals(contactId, db.addContact(txn, author, localAuthorId)); + assertEquals(contactId, db.addContact(txn, author, localAuthorId, + true)); assertTrue(db.containsContact(txn, contactId)); assertFalse(db.containsGroup(txn, groupId)); db.addGroup(txn, group); @@ -170,7 +171,8 @@ public class H2DatabaseTest extends BriarTestCase { // Add a contact, a group and a message db.addLocalAuthor(txn, localAuthor); - assertEquals(contactId, db.addContact(txn, author, localAuthorId)); + assertEquals(contactId, db.addContact(txn, author, localAuthorId, + true)); db.addGroup(txn, group); db.addVisibility(txn, contactId, groupId); db.addMessage(txn, message, VALID, true); @@ -207,7 +209,8 @@ public class H2DatabaseTest extends BriarTestCase { // Add a contact, a group and an unvalidated message db.addLocalAuthor(txn, localAuthor); - assertEquals(contactId, db.addContact(txn, author, localAuthorId)); + assertEquals(contactId, db.addContact(txn, author, localAuthorId, + true)); db.addGroup(txn, group); db.addVisibility(txn, contactId, groupId); db.addMessage(txn, message, UNKNOWN, true); @@ -245,7 +248,8 @@ public class H2DatabaseTest extends BriarTestCase { // Add a contact, a group and an unshared message db.addLocalAuthor(txn, localAuthor); - assertEquals(contactId, db.addContact(txn, author, localAuthorId)); + assertEquals(contactId, db.addContact(txn, author, localAuthorId, + true)); db.addGroup(txn, group); db.addVisibility(txn, contactId, groupId); db.addMessage(txn, message, VALID, false); @@ -283,7 +287,8 @@ public class H2DatabaseTest extends BriarTestCase { // Add a contact, a group and a message db.addLocalAuthor(txn, localAuthor); - assertEquals(contactId, db.addContact(txn, author, localAuthorId)); + assertEquals(contactId, db.addContact(txn, author, localAuthorId, + true)); db.addGroup(txn, group); db.addVisibility(txn, contactId, groupId); db.addMessage(txn, message, VALID, true); @@ -309,7 +314,8 @@ public class H2DatabaseTest extends BriarTestCase { // Add a contact and a group db.addLocalAuthor(txn, localAuthor); - assertEquals(contactId, db.addContact(txn, author, localAuthorId)); + assertEquals(contactId, db.addContact(txn, author, localAuthorId, + true)); db.addGroup(txn, group); db.addVisibility(txn, contactId, groupId); @@ -345,7 +351,8 @@ public class H2DatabaseTest extends BriarTestCase { // Add a contact, a group and a message db.addLocalAuthor(txn, localAuthor); - assertEquals(contactId, db.addContact(txn, author, localAuthorId)); + assertEquals(contactId, db.addContact(txn, author, localAuthorId, + true)); db.addGroup(txn, group); db.addVisibility(txn, contactId, groupId); db.addMessage(txn, message, VALID, true); @@ -508,7 +515,8 @@ public class H2DatabaseTest extends BriarTestCase { // Add a contact and a group db.addLocalAuthor(txn, localAuthor); - assertEquals(contactId, db.addContact(txn, author, localAuthorId)); + assertEquals(contactId, db.addContact(txn, author, localAuthorId, + true)); db.addGroup(txn, group); db.addVisibility(txn, contactId, groupId); @@ -527,7 +535,8 @@ public class H2DatabaseTest extends BriarTestCase { // Add a contact db.addLocalAuthor(txn, localAuthor); - assertEquals(contactId, db.addContact(txn, author, localAuthorId)); + assertEquals(contactId, db.addContact(txn, author, localAuthorId, + true)); // The group is not in the database assertFalse(db.containsVisibleMessage(txn, contactId, messageId)); @@ -544,7 +553,8 @@ public class H2DatabaseTest extends BriarTestCase { // Add a contact, a group and a message db.addLocalAuthor(txn, localAuthor); - assertEquals(contactId, db.addContact(txn, author, localAuthorId)); + assertEquals(contactId, db.addContact(txn, author, localAuthorId, + true)); db.addGroup(txn, group); db.addMessage(txn, message, VALID, true); db.addStatus(txn, contactId, messageId, false, false); @@ -563,7 +573,8 @@ public class H2DatabaseTest extends BriarTestCase { // Add a contact and a group db.addLocalAuthor(txn, localAuthor); - assertEquals(contactId, db.addContact(txn, author, localAuthorId)); + assertEquals(contactId, db.addContact(txn, author, localAuthorId, + true)); db.addGroup(txn, group); // The group should not be visible to the contact @@ -598,7 +609,8 @@ public class H2DatabaseTest extends BriarTestCase { // Add a contact and the groups db.addLocalAuthor(txn, localAuthor); - assertEquals(contactId, db.addContact(txn, author, localAuthorId)); + assertEquals(contactId, db.addContact(txn, author, localAuthorId, + true)); for (Group g : groups) db.addGroup(txn, g); // Make the groups visible to the contact @@ -630,7 +642,8 @@ public class H2DatabaseTest extends BriarTestCase { // Add the contact, the transport and the transport keys db.addLocalAuthor(txn, localAuthor); - assertEquals(contactId, db.addContact(txn, author, localAuthorId)); + assertEquals(contactId, db.addContact(txn, author, localAuthorId, + true)); db.addTransport(txn, transportId, 123); db.addTransportKeys(txn, contactId, keys); @@ -691,7 +704,8 @@ public class H2DatabaseTest extends BriarTestCase { // Add the contact, transport and transport keys db.addLocalAuthor(txn, localAuthor); - assertEquals(contactId, db.addContact(txn, author, localAuthorId)); + assertEquals(contactId, db.addContact(txn, author, localAuthorId, + true)); db.addTransport(txn, transportId, 123); db.updateTransportKeys(txn, Collections.singletonMap(contactId, keys)); @@ -726,7 +740,8 @@ public class H2DatabaseTest extends BriarTestCase { // Add the contact, transport and transport keys db.addLocalAuthor(txn, localAuthor); - assertEquals(contactId, db.addContact(txn, author, localAuthorId)); + assertEquals(contactId, db.addContact(txn, author, localAuthorId, + true)); db.addTransport(txn, transportId, 123); db.updateTransportKeys(txn, Collections.singletonMap(contactId, keys)); @@ -762,7 +777,8 @@ public class H2DatabaseTest extends BriarTestCase { assertEquals(Collections.emptyList(), contacts); // Add a contact associated with the local author - assertEquals(contactId, db.addContact(txn, author, localAuthorId)); + assertEquals(contactId, db.addContact(txn, author, localAuthorId, + true)); contacts = db.getContacts(txn, localAuthorId); assertEquals(Collections.singletonList(contactId), contacts); @@ -783,7 +799,8 @@ public class H2DatabaseTest extends BriarTestCase { // Add a contact - initially there should be no offered messages db.addLocalAuthor(txn, localAuthor); - assertEquals(contactId, db.addContact(txn, author, localAuthorId)); + assertEquals(contactId, db.addContact(txn, author, localAuthorId, + true)); assertEquals(0, db.countOfferedMessages(txn, contactId)); // Add some offered messages and count them @@ -921,7 +938,8 @@ public class H2DatabaseTest extends BriarTestCase { // Add a contact db.addLocalAuthor(txn, localAuthor); - assertEquals(contactId, db.addContact(txn, author, localAuthorId)); + assertEquals(contactId, db.addContact(txn, author, localAuthorId, + true)); // Add a group and make it visible to the contact db.addGroup(txn, group); @@ -997,7 +1015,8 @@ public class H2DatabaseTest extends BriarTestCase { // Add a contact and a group db.addLocalAuthor(txn, localAuthor); - assertEquals(contactId, db.addContact(txn, author, localAuthorId)); + assertEquals(contactId, db.addContact(txn, author, localAuthorId, + true)); db.addGroup(txn, group); // The group should not be visible to the contact @@ -1030,8 +1049,8 @@ public class H2DatabaseTest extends BriarTestCase { db.addLocalAuthor(txn, localAuthor1); // Add the same contact for each local pseudonym - ContactId contactId = db.addContact(txn, author, localAuthorId); - ContactId contactId1 = db.addContact(txn, author, localAuthorId1); + ContactId contactId = db.addContact(txn, author, localAuthorId, true); + ContactId contactId1 = db.addContact(txn, author, localAuthorId1, true); // The contacts should be distinct assertNotEquals(contactId, contactId1); @@ -1050,7 +1069,8 @@ public class H2DatabaseTest extends BriarTestCase { // Add a contact, a group and a message db.addLocalAuthor(txn, localAuthor); - assertEquals(contactId, db.addContact(txn, author, localAuthorId)); + assertEquals(contactId, db.addContact(txn, author, localAuthorId, + true)); db.addGroup(txn, group); db.addVisibility(txn, contactId, groupId); db.addMessage(txn, message, VALID, true); diff --git a/briar-tests/src/org/briarproject/sync/SimplexMessagingIntegrationTest.java b/briar-tests/src/org/briarproject/sync/SimplexMessagingIntegrationTest.java index 2c3cc4348..62e9a613b 100644 --- a/briar-tests/src/org/briarproject/sync/SimplexMessagingIntegrationTest.java +++ b/briar-tests/src/org/briarproject/sync/SimplexMessagingIntegrationTest.java @@ -134,7 +134,8 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { // Add Bob as a contact Author bobAuthor = new Author(bobId, "Bob", new byte[MAX_PUBLIC_KEY_LENGTH]); - ContactId contactId = contactManager.addContact(bobAuthor, aliceId); + ContactId contactId = contactManager.addContact(bobAuthor, aliceId, + true); // Derive and store the transport keys keyManager.addContact(contactId, master, timestamp, true); @@ -204,7 +205,8 @@ public class SimplexMessagingIntegrationTest extends BriarTestCase { // Add Alice as a contact Author aliceAuthor = new Author(aliceId, "Alice", new byte[MAX_PUBLIC_KEY_LENGTH]); - ContactId contactId = contactManager.addContact(aliceAuthor, bobId); + ContactId contactId = contactManager.addContact(aliceAuthor, bobId, + true); // Derive and store the transport keys keyManager.addContact(contactId, master, timestamp, false);