diff --git a/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java index 9f4a5bb528cb55d8c79777507199068879264788..541224ecd4511092cb41e01cdbf3539b4b231b5c 100644 --- a/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java +++ b/bramble-core/src/main/java/org/briarproject/bramble/properties/TransportPropertyManagerImpl.java @@ -64,6 +64,7 @@ class TransportPropertyManagerImpl implements TransportPropertyManager, @Override public void createLocalState(Transaction txn) throws DbException { + if (db.containsGroup(txn, localGroup.getId())) return; db.addGroup(txn, localGroup); // Ensure we've set things up for any pre-existing contacts for (Contact c : db.getContacts(txn)) addingContact(txn, c); diff --git a/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyManagerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyManagerImplTest.java index 33a738557cca792f904540098d9f2c64c4743932..7f4868f49a14eb8d825114c082f86ecce2782ca3 100644 --- a/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyManagerImplTest.java +++ b/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyManagerImplTest.java @@ -96,6 +96,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase { Group contactGroup1 = getGroup(), contactGroup2 = getGroup(); context.checking(new Expectations() {{ + oneOf(db).containsGroup(txn, localGroup.getId()); + will(returnValue(false)); oneOf(db).addGroup(txn, localGroup); oneOf(db).getContacts(txn); will(returnValue(contacts)); @@ -127,7 +129,21 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase { } @Test - public void testCreatesGroupWhenAddingContact() throws Exception { + public void testDoesNotCreateGroupsAtStartupIfAlreadyCreated() + throws Exception { + Transaction txn = new Transaction(null, false); + + context.checking(new Expectations() {{ + oneOf(db).containsGroup(txn, localGroup.getId()); + will(returnValue(true)); + }}); + + TransportPropertyManagerImpl t = createInstance(); + t.createLocalState(txn); + } + + @Test + public void testCreatesContactGroupWhenAddingContact() throws Exception { Transaction txn = new Transaction(null, false); Contact contact = getContact(true); Group contactGroup = getGroup(); diff --git a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionManagerImpl.java index 053c0760581769477c57cc5c107192a16a9142e2..51ffb23d5caae80dddb813b4184d1d3d27ca243c 100644 --- a/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/introduction/IntroductionManagerImpl.java @@ -106,7 +106,9 @@ class IntroductionManagerImpl extends ConversationClientImpl @Override public void createLocalState(Transaction txn) throws DbException { - db.addGroup(txn, introductionGroupFactory.createLocalGroup()); + Group localGroup = introductionGroupFactory.createLocalGroup(); + if (db.containsGroup(txn, localGroup.getId())) return; + db.addGroup(txn, localGroup); // Ensure we've set things up for any pre-existing contacts for (Contact c : db.getContacts(txn)) addingContact(txn, c); } diff --git a/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java index c67d5913568770b3d45cf6b0e6d163a86073fbac..859658a7d9afb1b356e46d549a4de9d7a50c3cc1 100644 --- a/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/messaging/MessagingManagerImpl.java @@ -54,6 +54,11 @@ class MessagingManagerImpl extends ConversationClientImpl @Override public void createLocalState(Transaction txn) throws DbException { + // Create a local group to indicate that we've set this client up + Group localGroup = contactGroupFactory.createLocalGroup(CLIENT_ID, + CLIENT_VERSION); + if (db.containsGroup(txn, localGroup.getId())) return; + db.addGroup(txn, localGroup); // Ensure we've set things up for any pre-existing contacts for (Contact c : db.getContacts(txn)) addingContact(txn, c); } diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java index 0125b5e53ea5c3dead9346f5fa24a22948068535..446c4b6a4790ffa4a19d88554403c86de61b74cd 100644 --- a/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImpl.java @@ -96,6 +96,11 @@ class GroupInvitationManagerImpl extends ConversationClientImpl @Override public void createLocalState(Transaction txn) throws DbException { + // Create a local group to indicate that we've set this client up + Group localGroup = contactGroupFactory.createLocalGroup(CLIENT_ID, + CLIENT_VERSION); + if (db.containsGroup(txn, localGroup.getId())) return; + db.addGroup(txn, localGroup); // Ensure we've set things up for any pre-existing contacts for (Contact c : db.getContacts(txn)) addingContact(txn, c); } diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingManagerImpl.java index 4c7863cd5b631bbaf9cd10dd1ee9d53d5417a4e1..f0086e856c0a12c99fa85a2394592d6b3a2333cc 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/BlogSharingManagerImpl.java @@ -61,6 +61,9 @@ class BlogSharingManagerImpl extends SharingManagerImpl<Blog> */ @Override public void addingContact(Transaction txn, Contact c) throws DbException { + // Return if we've already set things up for this contact + if (db.containsGroup(txn, getContactGroup(c).getId())) return; + // creates a group to share with the contact super.addingContact(txn, c); diff --git a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java index b70fb74eaf3939733355483a232c8fcd50f9fbd0..1c7bcd0dd0aa80dc74555c1d75abee60a9624491 100644 --- a/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java +++ b/briar-core/src/main/java/org/briarproject/briar/sharing/SharingManagerImpl.java @@ -84,6 +84,11 @@ abstract class SharingManagerImpl<S extends Shareable> @Override public void createLocalState(Transaction txn) throws DbException { + // Create a local group to indicate that we've set this client up + Group localGroup = contactGroupFactory.createLocalGroup(getClientId(), + getClientVersion()); + if (db.containsGroup(txn, localGroup.getId())) return; + db.addGroup(txn, localGroup); // Ensure we've set things up for any pre-existing contacts for (Contact c : db.getContacts(txn)) addingContact(txn, c); } diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java index c0e3b116b4c15ae5ffbc5c14fbc024aa879754e5..e2a1ae4022fdbbfa63e59c0254f337acb545958e 100644 --- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/GroupInvitationManagerImplTest.java @@ -46,6 +46,9 @@ import javax.annotation.Nullable; import static junit.framework.TestCase.fail; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; import static org.briarproject.bramble.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH; +import static org.briarproject.bramble.test.TestUtils.getAuthor; +import static org.briarproject.bramble.test.TestUtils.getGroup; +import static org.briarproject.bramble.test.TestUtils.getMessage; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getRandomId; import static org.briarproject.bramble.util.StringUtils.getRandomString; @@ -93,16 +96,12 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase { private final Transaction txn = new Transaction(null, false); private final ContactId contactId = new ContactId(0); - private final Author author = - new Author(new AuthorId(getRandomId()), getRandomString(5), - getRandomBytes(5)); - private final Contact contact = - new Contact(contactId, author, new AuthorId(getRandomId()), true, - true); - private final Group contactGroup = - new Group(new GroupId(getRandomId()), CLIENT_ID, getRandomBytes(5)); - private final Group privateGroup = - new Group(new GroupId(getRandomId()), CLIENT_ID, getRandomBytes(5)); + private final Author author = getAuthor(); + private final Contact contact = new Contact(contactId, author, + new AuthorId(getRandomId()), true, true); + private final Group localGroup = getGroup(CLIENT_ID); + private final Group contactGroup = getGroup(CLIENT_ID); + private final Group privateGroup = getGroup(CLIENT_ID); private final BdfDictionary meta = BdfDictionary.of(new BdfEntry("m", "e")); private final Message message = new Message(new MessageId(getRandomId()), contactGroup.getId(), @@ -110,9 +109,7 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase { private final BdfList body = BdfList.of("body"); private final SessionId sessionId = new SessionId(privateGroup.getId().getBytes()); - private final Message storageMessage = - new Message(new MessageId(getRandomId()), contactGroup.getId(), - 0L, getRandomBytes(MESSAGE_HEADER_LENGTH + 1)); + private final Message storageMessage = getMessage(contactGroup.getId()); private final BdfDictionary bdfSession = BdfDictionary.of(new BdfEntry("f", "o")); private final Map<MessageId, BdfDictionary> oneResult = @@ -151,8 +148,14 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase { } @Test - public void testCreateLocalState() throws Exception { + public void testCreateLocalStateFirstTime() throws Exception { context.checking(new Expectations() {{ + oneOf(contactGroupFactory).createLocalGroup(CLIENT_ID, + CLIENT_VERSION); + will(returnValue(localGroup)); + oneOf(db).containsGroup(txn, localGroup.getId()); + will(returnValue(false)); + oneOf(db).addGroup(txn, localGroup); oneOf(db).getContacts(txn); will(returnValue(Collections.singletonList(contact))); }}); @@ -160,6 +163,18 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase { groupInvitationManager.createLocalState(txn); } + @Test + public void testCreateLocalStateSubsequentTime() throws Exception { + context.checking(new Expectations() {{ + oneOf(contactGroupFactory).createLocalGroup(CLIENT_ID, + CLIENT_VERSION); + will(returnValue(localGroup)); + oneOf(db).containsGroup(txn, localGroup.getId()); + will(returnValue(true)); + }}); + groupInvitationManager.createLocalState(txn); + } + private void expectAddingContact(Contact c, boolean contactExists) throws Exception { context.checking(new Expectations() {{ diff --git a/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingManagerImplTest.java b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingManagerImplTest.java index 22e9bbf6198502557237954f6d9a427354a2827f..9500d9938195dd305d98ad785767af3a82af492f 100644 --- a/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingManagerImplTest.java +++ b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingManagerImplTest.java @@ -12,7 +12,6 @@ import org.briarproject.bramble.api.db.DbException; import org.briarproject.bramble.api.db.Metadata; import org.briarproject.bramble.api.db.Transaction; import org.briarproject.bramble.api.identity.Author; -import org.briarproject.bramble.api.identity.AuthorId; import org.briarproject.bramble.api.identity.IdentityManager; import org.briarproject.bramble.api.identity.LocalAuthor; import org.briarproject.bramble.api.sync.Group; @@ -34,8 +33,10 @@ import java.util.Collections; import java.util.HashMap; import java.util.Map; -import static org.briarproject.bramble.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH; import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; +import static org.briarproject.bramble.test.TestUtils.getAuthor; +import static org.briarproject.bramble.test.TestUtils.getGroup; +import static org.briarproject.bramble.test.TestUtils.getLocalAuthor; import static org.briarproject.bramble.test.TestUtils.getRandomBytes; import static org.briarproject.bramble.test.TestUtils.getRandomId; import static org.briarproject.briar.api.blog.BlogSharingManager.CLIENT_ID; @@ -58,22 +59,19 @@ public class BlogSharingManagerImplTest extends BrambleMockTestCase { context.mock(ContactGroupFactory.class); private final BlogManager blogManager = context.mock(BlogManager.class); - private final AuthorId localAuthorId = new AuthorId(getRandomId()); + private final LocalAuthor localAuthor = getLocalAuthor(); private final ContactId contactId = new ContactId(0); - private final AuthorId authorId = new AuthorId(getRandomId()); - private final Author author = new Author(authorId, "Author", - getRandomBytes(MAX_PUBLIC_KEY_LENGTH)); + private final Author author = getAuthor(); private final Contact contact = - new Contact(contactId, author, localAuthorId, true, true); + new Contact(contactId, author, localAuthor.getId(), true, true); private final Collection<Contact> contacts = Collections.singletonList(contact); - private final Group contactGroup = - new Group(new GroupId(getRandomId()), CLIENT_ID, - getRandomBytes(42)); - private final Group blogGroup = - new Group(new GroupId(getRandomId()), BlogManager.CLIENT_ID, - getRandomBytes(42)); + private final Group localGroup = getGroup(CLIENT_ID); + private final Group contactGroup = getGroup(CLIENT_ID); + private final Group blogGroup = getGroup(BlogManager.CLIENT_ID); private final Blog blog = new Blog(blogGroup, author, false); + private final Group localBlogGroup = getGroup(BlogManager.CLIENT_ID); + private final Blog localBlog = new Blog(localBlogGroup, localAuthor, false); @SuppressWarnings("unchecked") private final ProtocolEngine<Blog> engine = context.mock(ProtocolEngine.class); @@ -94,75 +92,54 @@ public class BlogSharingManagerImplTest extends BrambleMockTestCase { } @Test - public void testAddingContactFreshState() throws Exception { - Map<MessageId, BdfDictionary> sessions = new HashMap<>(0); - testAddingContact(sessions); - } - - @Test - public void testAddingContactExistingState() throws Exception { - Map<MessageId, BdfDictionary> sessions = new HashMap<>(1); - sessions.put(new MessageId(getRandomId()), new BdfDictionary()); - testAddingContact(sessions); - } - - @Test(expected = DbException.class) - public void testAddingContactMultipleSessions() throws Exception { - Map<MessageId, BdfDictionary> sessions = new HashMap<>(2); - sessions.put(new MessageId(getRandomId()), new BdfDictionary()); - sessions.put(new MessageId(getRandomId()), new BdfDictionary()); - testAddingContact(sessions); - } - - @Test - public void testRemovingBlogFreshState() throws Exception { - Map<MessageId, BdfDictionary> sessions = new HashMap<>(0); - testRemovingBlog(sessions); - } - - @Test - public void testRemovingBlogExistingState() throws Exception { - Map<MessageId, BdfDictionary> sessions = new HashMap<>(1); - sessions.put(new MessageId(getRandomId()), new BdfDictionary()); - testRemovingBlog(sessions); - } - - @Test(expected = DbException.class) - public void testRemovingBlogMultipleSessions() throws Exception { - Map<MessageId, BdfDictionary> sessions = new HashMap<>(2); - sessions.put(new MessageId(getRandomId()), new BdfDictionary()); - sessions.put(new MessageId(getRandomId()), new BdfDictionary()); - testRemovingBlog(sessions); - } - - private void testAddingContact(Map<MessageId, BdfDictionary> sessions) + public void testCreateLocalStateFirstTimeWithExistingContactNotSetUp() throws Exception { Transaction txn = new Transaction(null, false); - LocalAuthor localAuthor = - new LocalAuthor(localAuthorId, "Local Author", - getRandomBytes(MAX_PUBLIC_KEY_LENGTH), - getRandomBytes(MAX_PUBLIC_KEY_LENGTH), - System.currentTimeMillis()); - BdfDictionary meta = BdfDictionary - .of(new BdfEntry(GROUP_KEY_CONTACT_ID, contactId.getInt())); - Group localBlogGroup = - new Group(new GroupId(getRandomId()), BlogManager.CLIENT_ID, - getRandomBytes(42)); - Blog localBlog = new Blog(localBlogGroup, localAuthor, false); context.checking(new Expectations() {{ + // The local group doesn't exist - we need to set things up + oneOf(contactGroupFactory).createLocalGroup(CLIENT_ID, + CLIENT_VERSION); + will(returnValue(localGroup)); + oneOf(db).containsGroup(txn, localGroup.getId()); + will(returnValue(false)); + oneOf(db).addGroup(txn, localGroup); + // Get contacts oneOf(db).getContacts(txn); will(returnValue(contacts)); + }}); + // Set things up for the contact + expectAddingContact(txn); + + blogSharingManager.createLocalState(txn); + } + + private void expectAddingContact(Transaction txn) throws Exception { + BdfDictionary meta = BdfDictionary.of( + new BdfEntry(GROUP_KEY_CONTACT_ID, contactId.getInt())); + Map<MessageId, BdfDictionary> sessions = Collections.emptyMap(); + + context.checking(new Expectations() {{ + // Check for contact group in BlogSharingManagerImpl oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, CLIENT_VERSION, contact); will(returnValue(contactGroup)); oneOf(db).containsGroup(txn, contactGroup.getId()); will(returnValue(false)); + // Check for contact group again in SharingManagerImpl + oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, + CLIENT_VERSION, contact); + will(returnValue(contactGroup)); + oneOf(db).containsGroup(txn, contactGroup.getId()); + will(returnValue(false)); + // Create the contact group and share it with the contact oneOf(db).addGroup(txn, contactGroup); oneOf(db).setGroupVisibility(txn, contactId, contactGroup.getId(), SHARED); + // Attach the contact ID to the group oneOf(clientHelper) .mergeGroupMetadata(txn, contactGroup.getId(), meta); + // Get our blog and the contact's blog oneOf(identityManager).getLocalAuthor(txn); will(returnValue(localAuthor)); oneOf(blogManager).getPersonalBlog(localAuthor); @@ -170,12 +147,84 @@ public class BlogSharingManagerImplTest extends BrambleMockTestCase { oneOf(blogManager).getPersonalBlog(author); will(returnValue(blog)); }}); + // Pre-share our blog with the contact and vice versa expectPreShareShareable(txn, contact, localBlog, sessions); expectPreShareShareable(txn, contact, blog, sessions); + } + + @Test + public void testCreateLocalStateFirstTimeWithExistingContactAlreadySetUp() + throws Exception { + Transaction txn = new Transaction(null, false); + + context.checking(new Expectations() {{ + // The local group doesn't exist - we need to set things up + oneOf(contactGroupFactory).createLocalGroup(CLIENT_ID, + CLIENT_VERSION); + will(returnValue(localGroup)); + oneOf(db).containsGroup(txn, localGroup.getId()); + will(returnValue(false)); + oneOf(db).addGroup(txn, localGroup); + // Get contacts + oneOf(db).getContacts(txn); + will(returnValue(contacts)); + // The contact has already been set up + oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, + CLIENT_VERSION, contact); + will(returnValue(contactGroup)); + oneOf(db).containsGroup(txn, contactGroup.getId()); + will(returnValue(true)); + }}); + + blogSharingManager.createLocalState(txn); + } + + @Test + public void testCreateLocalStateSubsequentTime() throws Exception { + Transaction txn = new Transaction(null, false); + + context.checking(new Expectations() {{ + // The local group exists - everything has been set up + oneOf(contactGroupFactory).createLocalGroup(CLIENT_ID, + CLIENT_VERSION); + will(returnValue(localGroup)); + oneOf(db).containsGroup(txn, localGroup.getId()); + will(returnValue(true)); + }}); blogSharingManager.createLocalState(txn); } + @Test + public void testAddingContact() throws Exception { + Transaction txn = new Transaction(null, false); + + expectAddingContact(txn); + + blogSharingManager.addingContact(txn, contact); + } + + @Test + public void testRemovingBlogFreshState() throws Exception { + Map<MessageId, BdfDictionary> sessions = new HashMap<>(0); + testRemovingBlog(sessions); + } + + @Test + public void testRemovingBlogExistingState() throws Exception { + Map<MessageId, BdfDictionary> sessions = new HashMap<>(1); + sessions.put(new MessageId(getRandomId()), new BdfDictionary()); + testRemovingBlog(sessions); + } + + @Test(expected = DbException.class) + public void testRemovingBlogMultipleSessions() throws Exception { + Map<MessageId, BdfDictionary> sessions = new HashMap<>(2); + sessions.put(new MessageId(getRandomId()), new BdfDictionary()); + sessions.put(new MessageId(getRandomId()), new BdfDictionary()); + testRemovingBlog(sessions); + } + private void expectPreShareShareable(Transaction txn, Contact contact, Blog blog, Map<MessageId, BdfDictionary> sessions) throws Exception {