diff --git a/briar-api/src/org/briarproject/api/db/DatabaseComponent.java b/briar-api/src/org/briarproject/api/db/DatabaseComponent.java index d3dbace30d300d794fa593ab6ecec34f0ff4d7cb..328b978697aa578c746e513583b9b686a9460d79 100644 --- a/briar-api/src/org/briarproject/api/db/DatabaseComponent.java +++ b/briar-api/src/org/briarproject/api/db/DatabaseComponent.java @@ -176,6 +176,14 @@ public interface DatabaseComponent { */ Collection<Contact> getContacts(Transaction txn) throws DbException; + /** + * Returns a possibly empty collection of contacts with the given author ID. + * <p/> + * Read-only. + */ + Collection<Contact> getContactsByAuthorId(Transaction txn, AuthorId remote) + throws DbException; + /** * Returns all contacts associated with the given local pseudonym. * <p/> diff --git a/briar-core/src/org/briarproject/db/Database.java b/briar-core/src/org/briarproject/db/Database.java index b0be3b20bf706bef7a7ea84145e8d8759dcb70ac..0eb51b3173e77157beb1a82113249dd88378ade4 100644 --- a/briar-core/src/org/briarproject/db/Database.java +++ b/briar-core/src/org/briarproject/db/Database.java @@ -216,6 +216,14 @@ interface Database<T> { */ Collection<Contact> getContacts(T txn) throws DbException; + /** + * Returns a possibly empty collection of contacts with the given author ID. + * <p/> + * Read-only. + */ + Collection<Contact> getContactsByAuthorId(T txn, AuthorId remote) + throws DbException; + /** * Returns all contacts associated with the given local pseudonym. * <p/> diff --git a/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java b/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java index 01a2d9a96df25e5a22800ba37b888a66d729bf26..6e7d75aa4449f18f48b3d33c2750b9100e87f824 100644 --- a/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java +++ b/briar-core/src/org/briarproject/db/DatabaseComponentImpl.java @@ -359,6 +359,12 @@ class DatabaseComponentImpl<T> implements DatabaseComponent { return db.getContacts(txn); } + public Collection<Contact> getContactsByAuthorId(Transaction transaction, + AuthorId remote) throws DbException { + T txn = unbox(transaction); + return db.getContactsByAuthorId(txn, remote); + } + public Collection<ContactId> getContacts(Transaction transaction, AuthorId a) 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 640bc019db323237a7ae5f30ff3ae6b1adb82390..24d07373f8511b47b34ebae694420ee7f973a383 100644 --- a/briar-core/src/org/briarproject/db/JdbcDatabase.java +++ b/briar-core/src/org/briarproject/db/JdbcDatabase.java @@ -1020,7 +1020,7 @@ abstract class JdbcDatabase implements Database<Connection> { } } - public Collection<ContactId> getContacts(Connection txn, AuthorId a) + public Collection<ContactId> getContacts(Connection txn, AuthorId local) throws DbException { PreparedStatement ps = null; ResultSet rs = null; @@ -1028,7 +1028,7 @@ abstract class JdbcDatabase implements Database<Connection> { String sql = "SELECT contactId FROM contacts" + " WHERE localAuthorId = ?"; ps = txn.prepareStatement(sql); - ps.setBytes(1, a.getBytes()); + ps.setBytes(1, local.getBytes()); rs = ps.executeQuery(); List<ContactId> ids = new ArrayList<ContactId>(); while (rs.next()) ids.add(new ContactId(rs.getInt(1))); @@ -1042,6 +1042,40 @@ abstract class JdbcDatabase implements Database<Connection> { } } + public Collection<Contact> getContactsByAuthorId(Connection txn, + AuthorId remote) throws DbException { + PreparedStatement ps = null; + ResultSet rs = null; + try { + String sql = "SELECT contactId, name, publicKey," + + " localAuthorId, verified, active" + + " FROM contacts" + + " WHERE authorId = ?"; + ps = txn.prepareStatement(sql); + ps.setBytes(1, remote.getBytes()); + rs = ps.executeQuery(); + List<Contact> contacts = new ArrayList<Contact>(); + while (rs.next()) { + ContactId c = new ContactId(rs.getInt(1)); + String name = rs.getString(2); + byte[] publicKey = rs.getBytes(3); + AuthorId localAuthorId = new AuthorId(rs.getBytes(4)); + boolean verified = rs.getBoolean(5); + boolean active = rs.getBoolean(6); + Author author = new Author(remote, name, publicKey); + contacts.add(new Contact(c, author, localAuthorId, verified, + active)); + } + rs.close(); + ps.close(); + return Collections.unmodifiableList(contacts); + } catch (SQLException e) { + tryToClose(rs); + tryToClose(ps); + throw new DbException(e); + } + } + public Group getGroup(Connection txn, GroupId g) throws DbException { PreparedStatement ps = null; ResultSet rs = null; diff --git a/briar-core/src/org/briarproject/identity/IdentityManagerImpl.java b/briar-core/src/org/briarproject/identity/IdentityManagerImpl.java index 4d16b0683712f290f2779fcd95ccaa9b5c99cbc0..0901025840a0e0155deebfa7a4431d5deca99b7d 100644 --- a/briar-core/src/org/briarproject/identity/IdentityManagerImpl.java +++ b/briar-core/src/org/briarproject/identity/IdentityManagerImpl.java @@ -130,17 +130,18 @@ class IdentityManagerImpl implements IdentityManager { @Override public Status getAuthorStatus(Transaction txn, AuthorId authorId) throws DbException { + // Compare to the IDs of the user's identities - for (LocalAuthor a : db.getLocalAuthors(txn)) + for (LocalAuthor a : db.getLocalAuthors(txn)) { if (a.getId().equals(authorId)) return OURSELVES; - // Compare to the IDs of contacts' identities - for (Contact c : db.getContacts(txn)) { - if (c.getAuthor().getId().equals(authorId)) { - if (c.isVerified()) return VERIFIED; - else return UNVERIFIED; - } } - return UNKNOWN; + + Collection<Contact> contacts = db.getContactsByAuthorId(txn, authorId); + if (contacts.isEmpty()) return UNKNOWN; + for (Contact c : contacts) { + if (c.isVerified()) return VERIFIED; + } + return UNVERIFIED; } } diff --git a/briar-tests/src/org/briarproject/db/H2DatabaseTest.java b/briar-tests/src/org/briarproject/db/H2DatabaseTest.java index 259db68353bfc3af771c6b8288367211f8126b9c..ffe2917779757949f1929ecccd76c2bb35212449 100644 --- a/briar-tests/src/org/briarproject/db/H2DatabaseTest.java +++ b/briar-tests/src/org/briarproject/db/H2DatabaseTest.java @@ -784,6 +784,33 @@ public class H2DatabaseTest extends BriarTestCase { db.close(); } + @Test + public void testGetContactsByAuthorId() throws Exception { + Database<Connection> db = open(false); + Connection txn = db.startTransaction(); + + // Add a local author - no contacts should be associated + db.addLocalAuthor(txn, localAuthor); + + // Add a contact associated with the local author + assertEquals(contactId, db.addContact(txn, author, localAuthorId, + true, true)); + + // Ensure contact is returned from database by Author ID + Collection<Contact> contacts = + db.getContactsByAuthorId(txn, author.getId()); + assertEquals(1, contacts.size()); + assertEquals(contactId, contacts.iterator().next().getId()); + + // Ensure no contacts are returned after contact was deleted + db.removeContact(txn, contactId); + contacts = db.getContactsByAuthorId(txn, author.getId()); + assertEquals(0, contacts.size()); + + db.commitTransaction(txn); + db.close(); + } + @Test public void testGetContactsByLocalAuthorId() throws Exception { Database<Connection> db = open(false); diff --git a/briar-tests/src/org/briarproject/identity/IdentityManagerImplTest.java b/briar-tests/src/org/briarproject/identity/IdentityManagerImplTest.java index c04567a0a41253fe1b91eb0bf76d41a50d8aed10..9939e8f023c319c3eee6884e72d1ce10b7687186 100644 --- a/briar-tests/src/org/briarproject/identity/IdentityManagerImplTest.java +++ b/briar-tests/src/org/briarproject/identity/IdentityManagerImplTest.java @@ -1,14 +1,116 @@ package org.briarproject.identity; import org.briarproject.BriarTestCase; +import org.briarproject.TestUtils; +import org.briarproject.api.contact.Contact; +import org.briarproject.api.contact.ContactId; +import org.briarproject.api.db.DatabaseComponent; +import org.briarproject.api.db.DbException; +import org.briarproject.api.db.Transaction; +import org.briarproject.api.identity.Author; +import org.briarproject.api.identity.AuthorId; +import org.briarproject.api.identity.IdentityManager; +import org.briarproject.api.identity.LocalAuthor; +import org.jmock.Expectations; +import org.jmock.Mockery; import org.junit.Test; +import java.util.ArrayList; +import java.util.Collection; + +import static org.briarproject.api.identity.Author.Status.OURSELVES; +import static org.briarproject.api.identity.Author.Status.UNKNOWN; +import static org.briarproject.api.identity.Author.Status.UNVERIFIED; +import static org.briarproject.api.identity.Author.Status.VERIFIED; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; public class IdentityManagerImplTest extends BriarTestCase { + private final Mockery context; + private final IdentityManager identityManager; + private final DatabaseComponent db; + private final Transaction txn; + + public IdentityManagerImplTest() { + context = new Mockery(); + db = context.mock(DatabaseComponent.class); + txn = new Transaction(null, false); + identityManager = new IdentityManagerImpl(db); + } + @Test public void testUnitTestsExist() { - fail(); // FIXME: Write tests + fail(); // FIXME: Write more tests + } + + @Test + public void testGetAuthorStatus() throws DbException { + AuthorId authorId = new AuthorId(TestUtils.getRandomId()); + final Collection<LocalAuthor> localAuthors = new ArrayList<>(); + LocalAuthor localAuthor = + new LocalAuthor(new AuthorId(TestUtils.getRandomId()), + TestUtils.getRandomString(8), + TestUtils.getRandomBytes(42), + TestUtils.getRandomBytes(42), 0); + localAuthors.add(localAuthor); + Collection<Contact> contacts = new ArrayList<>(); + + checkAuthorStatusContext(localAuthors, authorId, contacts); + assertEquals(UNKNOWN, identityManager.getAuthorStatus(authorId)); + + // add one unverified contact + Author author = new Author(authorId, TestUtils.getRandomString(8), + TestUtils.getRandomBytes(42)); + Contact contact = + new Contact(new ContactId(1), author, localAuthor.getId(), + false, true); + contacts.add(contact); + + checkAuthorStatusContext(localAuthors, authorId, contacts); + assertEquals(UNVERIFIED, identityManager.getAuthorStatus(authorId)); + + // add one verified contact + Contact contact2 = + new Contact(new ContactId(1), author, localAuthor.getId(), + true, true); + contacts.add(contact2); + + checkAuthorStatusContext(localAuthors, authorId, contacts); + assertEquals(VERIFIED, identityManager.getAuthorStatus(authorId)); + + // add ourselves to the local authors + LocalAuthor localAuthor2 = + new LocalAuthor(authorId, + TestUtils.getRandomString(8), + TestUtils.getRandomBytes(42), + TestUtils.getRandomBytes(42), 0); + localAuthors.add(localAuthor2); + + context.checking(new Expectations() {{ + oneOf(db).startTransaction(false); + will(returnValue(txn)); + oneOf(db).getLocalAuthors(txn); + will(returnValue(localAuthors)); + oneOf(db).endTransaction(txn); + }}); + assertEquals(OURSELVES, identityManager.getAuthorStatus(authorId)); + + context.assertIsSatisfied(); + } + + private void checkAuthorStatusContext( + final Collection<LocalAuthor> localAuthors, final AuthorId authorId, + final Collection<Contact> contacts) throws DbException { + context.checking(new Expectations() {{ + oneOf(db).startTransaction(false); + will(returnValue(txn)); + oneOf(db).getLocalAuthors(txn); + will(returnValue(localAuthors)); + oneOf(db).getContactsByAuthorId(txn, authorId); + will(returnValue(contacts)); + oneOf(db).endTransaction(txn); + }}); } + }