diff --git a/briar-android-tests/src/test/java/org/briarproject/BlogSharingIntegrationTest.java b/briar-android-tests/src/test/java/org/briarproject/BlogSharingIntegrationTest.java new file mode 100644 index 0000000000000000000000000000000000000000..96a114d74f9421d85f5f5369e842077376b13086 --- /dev/null +++ b/briar-android-tests/src/test/java/org/briarproject/BlogSharingIntegrationTest.java @@ -0,0 +1,658 @@ +package org.briarproject; + +import net.jodah.concurrentunit.Waiter; + +import org.briarproject.api.blogs.Blog; +import org.briarproject.api.blogs.BlogInvitationRequest; +import org.briarproject.api.blogs.BlogInvitationResponse; +import org.briarproject.api.blogs.BlogManager; +import org.briarproject.api.blogs.BlogPostFactory; +import org.briarproject.api.blogs.BlogSharingManager; +import org.briarproject.api.contact.Contact; +import org.briarproject.api.contact.ContactId; +import org.briarproject.api.contact.ContactManager; +import org.briarproject.api.crypto.CryptoComponent; +import org.briarproject.api.crypto.KeyPair; +import org.briarproject.api.crypto.SecretKey; +import org.briarproject.api.db.DbException; +import org.briarproject.api.event.BlogInvitationReceivedEvent; +import org.briarproject.api.event.BlogInvitationResponseReceivedEvent; +import org.briarproject.api.event.Event; +import org.briarproject.api.event.EventListener; +import org.briarproject.api.event.MessageStateChangedEvent; +import org.briarproject.api.identity.AuthorFactory; +import org.briarproject.api.identity.IdentityManager; +import org.briarproject.api.identity.LocalAuthor; +import org.briarproject.api.lifecycle.LifecycleManager; +import org.briarproject.api.sharing.InvitationMessage; +import org.briarproject.api.sync.ClientId; +import org.briarproject.api.sync.SyncSession; +import org.briarproject.api.sync.SyncSessionFactory; +import org.briarproject.api.sync.ValidationManager.State; +import org.briarproject.api.system.Clock; +import org.briarproject.blogs.BlogsModule; +import org.briarproject.contact.ContactModule; +import org.briarproject.crypto.CryptoModule; +import org.briarproject.lifecycle.LifecycleModule; +import org.briarproject.properties.PropertiesModule; +import org.briarproject.sharing.SharingModule; +import org.briarproject.sync.SyncModule; +import org.briarproject.transport.TransportModule; +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.concurrent.TimeoutException; +import java.util.logging.Logger; + +import javax.inject.Inject; + +import static org.briarproject.TestPluginsModule.MAX_LATENCY; +import static org.briarproject.api.sync.ValidationManager.State.DELIVERED; +import static org.briarproject.api.sync.ValidationManager.State.INVALID; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class BlogSharingIntegrationTest extends BriarTestCase { + + private LifecycleManager lifecycleManager0, lifecycleManager1, + lifecycleManager2; + private SyncSessionFactory sync0, sync1, sync2; + private BlogManager blogManager0, blogManager1; + private ContactManager contactManager0, contactManager1, contactManager2; + private Contact contact1, contact2, contact01, contact02; + private ContactId contactId1, contactId2, contactId01, contactId02; + private IdentityManager identityManager0, identityManager1, + identityManager2; + private LocalAuthor author0, author1, author2; + private Blog blog0, blog1, blog2; + private SharerListener listener0, listener2; + private InviteeListener listener1; + + @Inject + Clock clock; + @Inject + AuthorFactory authorFactory; + @Inject + BlogPostFactory blogPostFactory; + @Inject + CryptoComponent cryptoComponent; + + // objects accessed from background threads need to be volatile + private volatile BlogSharingManager blogSharingManager0; + private volatile BlogSharingManager blogSharingManager1; + private volatile BlogSharingManager blogSharingManager2; + private volatile Waiter eventWaiter; + private volatile Waiter msgWaiter; + + private final File testDir = TestUtils.getTestDirectory(); + private final SecretKey master = TestUtils.getSecretKey(); + private final int TIMEOUT = 15000; + private final String SHARER = "Sharer"; + private final String INVITEE = "Invitee"; + private final String CONTACT2 = "Contact2"; + + private static final Logger LOG = + Logger.getLogger(BlogSharingIntegrationTest.class.getName()); + + private BlogSharingIntegrationTestComponent t0, t1, t2; + + @Rule + public ExpectedException thrown = ExpectedException.none(); + + @Before + public void setUp() { + BlogSharingIntegrationTestComponent component = + DaggerBlogSharingIntegrationTestComponent.builder().build(); + component.inject(this); + injectEagerSingletons(component); + + assertTrue(testDir.mkdirs()); + File t0Dir = new File(testDir, SHARER); + t0 = DaggerBlogSharingIntegrationTestComponent.builder() + .testDatabaseModule(new TestDatabaseModule(t0Dir)).build(); + injectEagerSingletons(t0); + File t1Dir = new File(testDir, INVITEE); + t1 = DaggerBlogSharingIntegrationTestComponent.builder() + .testDatabaseModule(new TestDatabaseModule(t1Dir)).build(); + injectEagerSingletons(t1); + File t2Dir = new File(testDir, CONTACT2); + t2 = DaggerBlogSharingIntegrationTestComponent.builder() + .testDatabaseModule(new TestDatabaseModule(t2Dir)).build(); + injectEagerSingletons(t2); + + identityManager0 = t0.getIdentityManager(); + identityManager1 = t1.getIdentityManager(); + identityManager2 = t2.getIdentityManager(); + contactManager0 = t0.getContactManager(); + contactManager1 = t1.getContactManager(); + contactManager2 = t2.getContactManager(); + blogManager0 = t0.getBlogManager(); + blogManager1 = t1.getBlogManager(); + blogSharingManager0 = t0.getBlogSharingManager(); + blogSharingManager1 = t1.getBlogSharingManager(); + blogSharingManager2 = t2.getBlogSharingManager(); + sync0 = t0.getSyncSessionFactory(); + sync1 = t1.getSyncSessionFactory(); + sync2 = t2.getSyncSessionFactory(); + + // initialize waiters fresh for each test + eventWaiter = new Waiter(); + msgWaiter = new Waiter(); + } + + @Test + public void testPersonalBlogCannotBeSharedWithOwner() throws Exception { + startLifecycles(); + defaultInit(true); + + assertFalse(blogSharingManager0.canBeShared(blog1.getId(), contact1)); + assertFalse(blogSharingManager0.canBeShared(blog2.getId(), contact2)); + assertFalse(blogSharingManager1.canBeShared(blog0.getId(), contact01)); + assertFalse(blogSharingManager2.canBeShared(blog0.getId(), contact02)); + + // create invitation + blogSharingManager0 + .sendInvitation(blog1.getId(), contactId1, "Hi!"); + + // sync invitation + sync0To1(); + // make sure the invitee ignored the request for their own blog + assertFalse(listener1.requestReceived); + + stopLifecycles(); + } + + @Test + public void testSuccessfulSharing() throws Exception { + startLifecycles(); + + // initialize and let invitee accept all requests + defaultInit(true); + + // send invitation + blogSharingManager0 + .sendInvitation(blog2.getId(), contactId1, "Hi!"); + + // invitee has own blog and that of the sharer + assertEquals(2, blogManager1.getBlogs().size()); + + // sync first request message + sync0To1(); + eventWaiter.await(TIMEOUT, 1); + assertTrue(listener1.requestReceived); + + // sync response back + sync1To0(); + eventWaiter.await(TIMEOUT, 1); + assertTrue(listener0.responseReceived); + + // blog was added successfully + assertEquals(0, blogSharingManager0.getInvited().size()); + assertEquals(3, blogManager1.getBlogs().size()); + + // invitee has one invitation message from sharer + List<InvitationMessage> list = + new ArrayList<>(blogSharingManager1 + .getInvitationMessages(contactId01)); + assertEquals(2, list.size()); + // check other things are alright with the message + for (InvitationMessage m : list) { + if (m instanceof BlogInvitationRequest) { + BlogInvitationRequest invitation = + (BlogInvitationRequest) m; + assertFalse(invitation.isAvailable()); + assertEquals(blog2.getAuthor().getName(), + invitation.getBlogAuthorName()); + assertEquals(contactId1, invitation.getContactId()); + assertEquals("Hi!", invitation.getMessage()); + } else { + BlogInvitationResponse response = + (BlogInvitationResponse) m; + assertEquals(contactId01, response.getContactId()); + assertTrue(response.wasAccepted()); + assertTrue(response.isLocal()); + } + } + // sharer has own invitation message and response + assertEquals(2, + blogSharingManager0.getInvitationMessages(contactId1) + .size()); + // blog can not be shared again + assertFalse(blogSharingManager0.canBeShared(blog2.getId(), contact1)); + assertFalse(blogSharingManager1.canBeShared(blog2.getId(), contact01)); + + stopLifecycles(); + } + + @Test + public void testDeclinedSharing() throws Exception { + startLifecycles(); + + // initialize and let invitee deny all requests + defaultInit(false); + + // send invitation + blogSharingManager0 + .sendInvitation(blog2.getId(), contactId1, null); + + // sync first request message + sync0To1(); + eventWaiter.await(TIMEOUT, 1); + assertTrue(listener1.requestReceived); + + // sync response back + sync1To0(); + eventWaiter.await(TIMEOUT, 1); + assertTrue(listener0.responseReceived); + + // blog was not added + assertEquals(0, blogSharingManager0.getInvited().size()); + assertEquals(2, blogManager1.getBlogs().size()); + // blog is no longer available to invitee who declined + assertEquals(0, blogSharingManager1.getInvited().size()); + + // invitee has one invitation message from sharer and one response + List<InvitationMessage> list = + new ArrayList<>(blogSharingManager1 + .getInvitationMessages(contactId01)); + assertEquals(2, list.size()); + // check things are alright with the message + for (InvitationMessage m : list) { + if (m instanceof BlogInvitationRequest) { + BlogInvitationRequest invitation = + (BlogInvitationRequest) m; + assertFalse(invitation.isAvailable()); + assertEquals(blog2.getAuthor().getName(), + invitation.getBlogAuthorName()); + assertEquals(contactId1, invitation.getContactId()); + assertEquals(null, invitation.getMessage()); + } else { + BlogInvitationResponse response = + (BlogInvitationResponse) m; + assertEquals(contactId01, response.getContactId()); + assertFalse(response.wasAccepted()); + assertTrue(response.isLocal()); + } + } + // sharer has own invitation message and response + assertEquals(2, + blogSharingManager0.getInvitationMessages(contactId1) + .size()); + // blog can be shared again + assertTrue(blogSharingManager0.canBeShared(blog2.getId(), contact1)); + + stopLifecycles(); + } + + @Test + public void testInviteeLeavesAfterFinished() throws Exception { + startLifecycles(); + + // initialize and let invitee accept all requests + defaultInit(true); + + // send invitation + blogSharingManager0 + .sendInvitation(blog2.getId(), contactId1, "Hi!"); + + // sync first request message + sync0To1(); + eventWaiter.await(TIMEOUT, 1); + assertTrue(listener1.requestReceived); + + // sync response back + sync1To0(); + eventWaiter.await(TIMEOUT, 1); + assertTrue(listener0.responseReceived); + + // blog was added successfully + assertEquals(0, blogSharingManager0.getInvited().size()); + assertEquals(3, blogManager1.getBlogs().size()); + assertTrue(blogManager1.getBlogs().contains(blog2)); + + // sharer shares blog with invitee + assertTrue(blogSharingManager0.getSharedWith(blog2.getId()) + .contains(contact1)); + // invitee gets blog shared by sharer + assertTrue(blogSharingManager1.getSharedBy(blog2.getId()) + .contains(contact01)); + + // invitee un-subscribes from blog + blogManager1.removeBlog(blog2); + + // send leave message to sharer + sync1To0(); + + // blog is gone + assertEquals(0, blogSharingManager0.getInvited().size()); + assertEquals(2, blogManager1.getBlogs().size()); + + // sharer no longer shares blog with invitee + assertFalse(blogSharingManager0.getSharedWith(blog2.getId()) + .contains(contact1)); + // invitee no longer gets blog shared by sharer + assertFalse(blogSharingManager1.getSharedBy(blog2.getId()) + .contains(contact01)); + // blog can be shared again + assertTrue(blogSharingManager0.canBeShared(blog2.getId(), contact1)); + assertTrue(blogSharingManager1.canBeShared(blog2.getId(), contact01)); + + stopLifecycles(); + } + + @Test + public void testInvitationForExistingBlog() throws Exception { + startLifecycles(); + + // initialize and let invitee accept all requests + defaultInit(true); + + // 1 and 2 are adding each other + contactManager1.addContact(author2, + author1.getId(), master, clock.currentTimeMillis(), true, + true + ); + contactManager2.addContact(author1, + author2.getId(), master, clock.currentTimeMillis(), true, + true + ); + assertEquals(3, blogManager1.getBlogs().size()); + + // sharer sends invitation for 2's blog to 1 + blogSharingManager0 + .sendInvitation(blog2.getId(), contactId1, "Hi!"); + + // sync first request message + sync0To1(); + eventWaiter.await(TIMEOUT, 1); + assertTrue(listener1.requestReceived); + + // make sure blog2 is shared by 0 + Collection<Contact> contacts = + blogSharingManager1.getSharedBy(blog2.getId()); + assertEquals(1, contacts.size()); + assertTrue(contacts.contains(contact01)); + + // make sure 1 knows that they have blog2 already + Collection<InvitationMessage> messages = + blogSharingManager1.getInvitationMessages(contactId01); + assertEquals(2, messages.size()); + assertEquals(blog2, blogManager1.getBlog(blog2.getId())); + + // sync response back + sync1To0(); + eventWaiter.await(TIMEOUT, 1); + assertTrue(listener0.responseReceived); + + // blog was not added, because it was there already + assertEquals(0, blogSharingManager0.getInvited().size()); + assertEquals(3, blogManager1.getBlogs().size()); + + stopLifecycles(); + } + + + @After + public void tearDown() throws InterruptedException { + TestUtils.deleteTestDirectory(testDir); + } + + private class SharerListener implements EventListener { + + volatile boolean requestReceived = false; + volatile boolean responseReceived = false; + + public void eventOccurred(Event e) { + if (e instanceof MessageStateChangedEvent) { + MessageStateChangedEvent event = (MessageStateChangedEvent) e; + State s = event.getState(); + ClientId c = event.getClientId(); + if ((s == DELIVERED || s == INVALID) && + c.equals(blogSharingManager0.getClientId()) && + !event.isLocal()) { + LOG.info("TEST: Sharer received message in group " + + event.getMessage().getGroupId().hashCode()); + msgWaiter.resume(); + } else if (s == DELIVERED && !event.isLocal() && + c.equals(blogManager0.getClientId())) { + LOG.info("TEST: Sharer received blog post"); + msgWaiter.resume(); + } + } else if (e instanceof BlogInvitationResponseReceivedEvent) { + BlogInvitationResponseReceivedEvent event = + (BlogInvitationResponseReceivedEvent) e; + eventWaiter.assertEquals(contactId1, event.getContactId()); + responseReceived = true; + eventWaiter.resume(); + } + // this is only needed for tests where a blog is re-shared + else if (e instanceof BlogInvitationReceivedEvent) { + BlogInvitationReceivedEvent event = + (BlogInvitationReceivedEvent) e; + eventWaiter.assertEquals(contactId1, event.getContactId()); + requestReceived = true; + Blog b = event.getBlog(); + try { + Contact c = contactManager0.getContact(contactId1); + blogSharingManager0.respondToInvitation(b, c, true); + } catch (DbException ex) { + eventWaiter.rethrow(ex); + } finally { + eventWaiter.resume(); + } + } + } + } + + private class InviteeListener implements EventListener { + + volatile boolean requestReceived = false; + volatile boolean responseReceived = false; + + private final boolean accept, answer; + + InviteeListener(boolean accept, boolean answer) { + this.accept = accept; + this.answer = answer; + } + + InviteeListener(boolean accept) { + this(accept, true); + } + + public void eventOccurred(Event e) { + if (e instanceof MessageStateChangedEvent) { + MessageStateChangedEvent event = (MessageStateChangedEvent) e; + State s = event.getState(); + ClientId c = event.getClientId(); + if ((s == DELIVERED || s == INVALID) && + c.equals(blogSharingManager0.getClientId()) && + !event.isLocal()) { + LOG.info("TEST: Invitee received message in group " + + event.getMessage().getGroupId().hashCode()); + msgWaiter.resume(); + } else if (s == DELIVERED && !event.isLocal() && + c.equals(blogManager0.getClientId())) { + LOG.info("TEST: Invitee received blog post"); + msgWaiter.resume(); + } + } else if (e instanceof BlogInvitationReceivedEvent) { + BlogInvitationReceivedEvent event = + (BlogInvitationReceivedEvent) e; + requestReceived = true; + if (!answer) return; + Blog b = event.getBlog(); + try { + eventWaiter.assertEquals(1, + blogSharingManager1.getInvited().size()); + Contact c = + contactManager1.getContact(event.getContactId()); + blogSharingManager1.respondToInvitation(b, c, accept); + } catch (DbException ex) { + eventWaiter.rethrow(ex); + } finally { + eventWaiter.resume(); + } + } + // this is only needed for tests where a blog is re-shared + else if (e instanceof BlogInvitationResponseReceivedEvent) { + BlogInvitationResponseReceivedEvent event = + (BlogInvitationResponseReceivedEvent) e; + eventWaiter.assertEquals(contactId01, event.getContactId()); + responseReceived = true; + eventWaiter.resume(); + } + } + } + + private void startLifecycles() throws InterruptedException { + // Start the lifecycle manager and wait for it to finish + lifecycleManager0 = t0.getLifecycleManager(); + lifecycleManager1 = t1.getLifecycleManager(); + lifecycleManager2 = t2.getLifecycleManager(); + lifecycleManager0.startServices(); + lifecycleManager1.startServices(); + lifecycleManager2.startServices(); + lifecycleManager0.waitForStartup(); + lifecycleManager1.waitForStartup(); + lifecycleManager2.waitForStartup(); + } + + private void stopLifecycles() throws InterruptedException { + // Clean up + lifecycleManager0.stopServices(); + lifecycleManager1.stopServices(); + lifecycleManager2.stopServices(); + lifecycleManager0.waitForShutdown(); + lifecycleManager1.waitForShutdown(); + lifecycleManager2.waitForShutdown(); + } + + private void defaultInit(boolean accept) throws DbException { + addDefaultIdentities(); + addDefaultContacts(); + getPersonalBlogOfSharer(); + listenToEvents(accept); + } + + private void addDefaultIdentities() throws DbException { + KeyPair keyPair = cryptoComponent.generateSignatureKeyPair(); + author0 = authorFactory.createLocalAuthor(SHARER, + keyPair.getPublic().getEncoded(), + keyPair.getPrivate().getEncoded()); + identityManager0.addLocalAuthor(author0); + + keyPair = cryptoComponent.generateSignatureKeyPair(); + author1 = authorFactory.createLocalAuthor(INVITEE, + keyPair.getPublic().getEncoded(), + keyPair.getPrivate().getEncoded()); + identityManager1.addLocalAuthor(author1); + + keyPair = cryptoComponent.generateSignatureKeyPair(); + author2 = authorFactory.createLocalAuthor(CONTACT2, + keyPair.getPublic().getEncoded(), + keyPair.getPrivate().getEncoded()); + identityManager2.addLocalAuthor(author2); + } + + private void addDefaultContacts() throws DbException { + // sharer adds invitee as contact + contactId1 = contactManager0.addContact(author1, + author0.getId(), master, clock.currentTimeMillis(), true, + true + ); + contact1 = contactManager0.getContact(contactId1); + // sharer adds second contact + contactId2 = contactManager0.addContact(author2, + author0.getId(), master, clock.currentTimeMillis(), true, + true + ); + contact2 = contactManager0.getContact(contactId2); + // contacts add sharer back + contactId01 = contactManager1.addContact(author0, + author1.getId(), master, clock.currentTimeMillis(), true, + true + ); + contact01 = contactManager1.getContact(contactId01); + contactId02 = contactManager2.addContact(author0, + author2.getId(), master, clock.currentTimeMillis(), true, + true + ); + contact02 = contactManager2.getContact(contactId02); + } + + private void getPersonalBlogOfSharer() throws DbException { + blog0 = blogManager0.getPersonalBlog(author0); + blog1 = blogManager0.getPersonalBlog(author1); + blog2 = blogManager0.getPersonalBlog(author2); + } + + private void listenToEvents(boolean accept) { + listener0 = new SharerListener(); + t0.getEventBus().addListener(listener0); + listener1 = new InviteeListener(accept); + t1.getEventBus().addListener(listener1); + listener2 = new SharerListener(); + t2.getEventBus().addListener(listener2); + } + + private void sync0To1() throws IOException, TimeoutException { + deliverMessage(sync0, contactId01, sync1, contactId1, + "Sharer to Invitee"); + } + + private void sync1To0() throws IOException, TimeoutException { + deliverMessage(sync1, contactId1, sync0, contactId01, + "Invitee to Sharer"); + } + + private void deliverMessage(SyncSessionFactory fromSync, ContactId fromId, + SyncSessionFactory toSync, ContactId toId, String debug) + throws IOException, TimeoutException { + + if (debug != null) LOG.info("TEST: Sending message from " + debug); + + ByteArrayOutputStream out = new ByteArrayOutputStream(); + // Create an outgoing sync session + SyncSession sessionFrom = + fromSync.createSimplexOutgoingSession(toId, MAX_LATENCY, out); + // Write whatever needs to be written + sessionFrom.run(); + out.close(); + + ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray()); + // Create an incoming sync session + SyncSession sessionTo = toSync.createIncomingSession(fromId, in); + // Read whatever needs to be read + sessionTo.run(); + in.close(); + + // wait for message to actually arrive + msgWaiter.await(TIMEOUT, 1); + } + + private void injectEagerSingletons( + BlogSharingIntegrationTestComponent component) { + + component.inject(new LifecycleModule.EagerSingletons()); + component.inject(new BlogsModule.EagerSingletons()); + component.inject(new CryptoModule.EagerSingletons()); + component.inject(new ContactModule.EagerSingletons()); + component.inject(new TransportModule.EagerSingletons()); + component.inject(new SharingModule.EagerSingletons()); + component.inject(new SyncModule.EagerSingletons()); + component.inject(new PropertiesModule.EagerSingletons()); + } + +} diff --git a/briar-android-tests/src/test/java/org/briarproject/BlogSharingIntegrationTestComponent.java b/briar-android-tests/src/test/java/org/briarproject/BlogSharingIntegrationTestComponent.java new file mode 100644 index 0000000000000000000000000000000000000000..1f738830e5082e215803fe1c31ff700eb04dd3bd --- /dev/null +++ b/briar-android-tests/src/test/java/org/briarproject/BlogSharingIntegrationTestComponent.java @@ -0,0 +1,100 @@ +package org.briarproject; + +import org.briarproject.api.blogs.BlogManager; +import org.briarproject.api.blogs.BlogSharingManager; +import org.briarproject.api.clients.ClientHelper; +import org.briarproject.api.clients.MessageQueueManager; +import org.briarproject.api.clients.PrivateGroupFactory; +import org.briarproject.api.contact.ContactManager; +import org.briarproject.api.db.DatabaseComponent; +import org.briarproject.api.event.EventBus; +import org.briarproject.api.forum.ForumManager; +import org.briarproject.api.identity.IdentityManager; +import org.briarproject.api.lifecycle.LifecycleManager; +import org.briarproject.api.sync.SyncSessionFactory; +import org.briarproject.blogs.BlogsModule; +import org.briarproject.clients.ClientsModule; +import org.briarproject.contact.ContactModule; +import org.briarproject.crypto.CryptoModule; +import org.briarproject.data.DataModule; +import org.briarproject.db.DatabaseModule; +import org.briarproject.event.EventModule; +import org.briarproject.forum.ForumModule; +import org.briarproject.identity.IdentityModule; +import org.briarproject.lifecycle.LifecycleModule; +import org.briarproject.properties.PropertiesModule; +import org.briarproject.sharing.SharingModule; +import org.briarproject.sync.SyncModule; +import org.briarproject.system.SystemModule; +import org.briarproject.transport.TransportModule; + +import javax.inject.Singleton; + +import dagger.Component; + +@Singleton +@Component(modules = { + TestDatabaseModule.class, + TestPluginsModule.class, + TestSeedProviderModule.class, + ClientsModule.class, + ContactModule.class, + CryptoModule.class, + DataModule.class, + DatabaseModule.class, + EventModule.class, + BlogsModule.class, + ForumModule.class, + IdentityModule.class, + LifecycleModule.class, + PropertiesModule.class, + SharingModule.class, + SyncModule.class, + SystemModule.class, + TransportModule.class +}) +interface BlogSharingIntegrationTestComponent { + + void inject(BlogSharingIntegrationTest testCase); + + void inject(ContactModule.EagerSingletons init); + + void inject(CryptoModule.EagerSingletons init); + + void inject(BlogsModule.EagerSingletons init); + + void inject(LifecycleModule.EagerSingletons init); + + void inject(PropertiesModule.EagerSingletons init); + + void inject(SharingModule.EagerSingletons init); + + void inject(SyncModule.EagerSingletons init); + + void inject(TransportModule.EagerSingletons init); + + LifecycleManager getLifecycleManager(); + + EventBus getEventBus(); + + IdentityManager getIdentityManager(); + + ContactManager getContactManager(); + + BlogSharingManager getBlogSharingManager(); + + BlogManager getBlogManager(); + + SyncSessionFactory getSyncSessionFactory(); + + /* the following methods are only needed to manually construct messages */ + + DatabaseComponent getDatabaseComponent(); + + PrivateGroupFactory getPrivateGroupFactory(); + + ClientHelper getClientHelper(); + + MessageQueueManager getMessageQueueManager(); + +} diff --git a/briar-android-tests/src/test/java/org/briarproject/ForumManagerTestComponent.java b/briar-android-tests/src/test/java/org/briarproject/ForumManagerTestComponent.java index 7e74d841b01a425caec7deac4ce9235d3c77767a..74c771488f832a608ebf66ee610a0e5fd6e1ddc2 100644 --- a/briar-android-tests/src/test/java/org/briarproject/ForumManagerTestComponent.java +++ b/briar-android-tests/src/test/java/org/briarproject/ForumManagerTestComponent.java @@ -7,6 +7,7 @@ import org.briarproject.api.forum.ForumSharingManager; import org.briarproject.api.identity.IdentityManager; import org.briarproject.api.lifecycle.LifecycleManager; import org.briarproject.api.sync.SyncSessionFactory; +import org.briarproject.blogs.BlogsModule; import org.briarproject.clients.ClientsModule; import org.briarproject.contact.ContactModule; import org.briarproject.crypto.CryptoModule; @@ -38,6 +39,7 @@ import dagger.Component; DatabaseModule.class, EventModule.class, ForumModule.class, + BlogsModule.class, IdentityModule.class, LifecycleModule.class, PropertiesModule.class, @@ -46,7 +48,7 @@ import dagger.Component; SystemModule.class, TransportModule.class }) -public interface ForumManagerTestComponent { +interface ForumManagerTestComponent { void inject(ForumManagerTest testCase); diff --git a/briar-android-tests/src/test/java/org/briarproject/ForumSharingIntegrationTestComponent.java b/briar-android-tests/src/test/java/org/briarproject/ForumSharingIntegrationTestComponent.java index 8e3ecdf9f6b5ce55cf19f5ef51a135f65bda6eea..6f3da3c1c0c05abbb5cad6132a0665b35c8154d7 100644 --- a/briar-android-tests/src/test/java/org/briarproject/ForumSharingIntegrationTestComponent.java +++ b/briar-android-tests/src/test/java/org/briarproject/ForumSharingIntegrationTestComponent.java @@ -11,6 +11,7 @@ import org.briarproject.api.forum.ForumSharingManager; import org.briarproject.api.identity.IdentityManager; import org.briarproject.api.lifecycle.LifecycleManager; import org.briarproject.api.sync.SyncSessionFactory; +import org.briarproject.blogs.BlogsModule; import org.briarproject.clients.ClientsModule; import org.briarproject.contact.ContactModule; import org.briarproject.crypto.CryptoModule; @@ -42,6 +43,7 @@ import dagger.Component; DatabaseModule.class, EventModule.class, ForumModule.class, + BlogsModule.class, IdentityModule.class, LifecycleModule.class, PropertiesModule.class, @@ -50,7 +52,7 @@ import dagger.Component; SystemModule.class, TransportModule.class }) -public interface ForumSharingIntegrationTestComponent { +interface ForumSharingIntegrationTestComponent { void inject(ForumSharingIntegrationTest testCase); diff --git a/briar-api/src/org/briarproject/api/blogs/BlogManager.java b/briar-api/src/org/briarproject/api/blogs/BlogManager.java index 7d6188feda24f7c3fdaf06b28460c0878c467676..f39a90d629fc6a244854cb2f1737b72a9c435161 100644 --- a/briar-api/src/org/briarproject/api/blogs/BlogManager.java +++ b/briar-api/src/org/briarproject/api/blogs/BlogManager.java @@ -36,7 +36,7 @@ public interface BlogManager { Collection<Blog> getBlogs(LocalAuthor localAuthor) throws DbException; /** Returns only the personal blog of the given author. */ - Blog getPersonalBlog(Author author) throws DbException; + Blog getPersonalBlog(Author author); /** Returns all blogs to which the user subscribes. */ Collection<Blog> getBlogs() throws DbException; diff --git a/briar-api/src/org/briarproject/api/identity/IdentityManager.java b/briar-api/src/org/briarproject/api/identity/IdentityManager.java index e89f49d8ac0ea279093234cdcfeba0e4a3113fc4..3c2b10953c4ff7e31ab886913f3c54c5a6a66bba 100644 --- a/briar-api/src/org/briarproject/api/identity/IdentityManager.java +++ b/briar-api/src/org/briarproject/api/identity/IdentityManager.java @@ -20,6 +20,12 @@ public interface IdentityManager { /** Returns the local pseudonym with the given ID. */ LocalAuthor getLocalAuthor(AuthorId a) throws DbException; + /** Returns the main local identity. */ + LocalAuthor getLocalAuthor() throws DbException; + + /** Returns the main local identity within the given Transaction. */ + LocalAuthor getLocalAuthor(Transaction txn) throws DbException; + /** Returns all local pseudonyms. */ Collection<LocalAuthor> getLocalAuthors() throws DbException; diff --git a/briar-core/src/org/briarproject/blogs/BlogFactoryImpl.java b/briar-core/src/org/briarproject/blogs/BlogFactoryImpl.java index 9a3e0583aa1f04952920139ea626f43d44e72de3..68fbe1258e9f09e16730c9578208c8773badd3b2 100644 --- a/briar-core/src/org/briarproject/blogs/BlogFactoryImpl.java +++ b/briar-core/src/org/briarproject/blogs/BlogFactoryImpl.java @@ -69,7 +69,7 @@ class BlogFactoryImpl implements BlogFactory { Author a = authorFactory.createAuthor(blog.getString(1), blog.getRaw(2)); // TODO change permanent depending on how this will be used - boolean permanent = false; + boolean permanent = true; return new Blog(g, blog.getString(0), description, a, permanent); } diff --git a/briar-core/src/org/briarproject/blogs/BlogManagerImpl.java b/briar-core/src/org/briarproject/blogs/BlogManagerImpl.java index a35bc0bc7fbad33d9b2928941fec1e91668ab16a..5a20d8934f07417394e330b206cdbf8d1c4eb613 100644 --- a/briar-core/src/org/briarproject/blogs/BlogManagerImpl.java +++ b/briar-core/src/org/briarproject/blogs/BlogManagerImpl.java @@ -282,7 +282,7 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager, } @Override - public Blog getPersonalBlog(Author author) throws DbException { + public Blog getPersonalBlog(Author author) { return blogFactory.createPersonalBlog(author); } diff --git a/briar-core/src/org/briarproject/identity/IdentityManagerImpl.java b/briar-core/src/org/briarproject/identity/IdentityManagerImpl.java index bd14c334076b222f0218b5783118e3a5cd915c11..235448b461f32b32212b9e6d9b2ffb976b911b28 100644 --- a/briar-core/src/org/briarproject/identity/IdentityManagerImpl.java +++ b/briar-core/src/org/briarproject/identity/IdentityManagerImpl.java @@ -10,9 +10,7 @@ import org.briarproject.api.identity.IdentityManager; import org.briarproject.api.identity.LocalAuthor; import java.util.Collection; -import java.util.HashSet; import java.util.List; -import java.util.Set; import java.util.concurrent.CopyOnWriteArrayList; import javax.inject.Inject; @@ -69,12 +67,22 @@ class IdentityManagerImpl implements IdentityManager { return author; } + @Override + public LocalAuthor getLocalAuthor() throws DbException { + return getLocalAuthors().iterator().next(); + } + + @Override + public LocalAuthor getLocalAuthor(Transaction txn) throws DbException { + return getLocalAuthors(txn).iterator().next(); + } + @Override public Collection<LocalAuthor> getLocalAuthors() throws DbException { Collection<LocalAuthor> authors; Transaction txn = db.startTransaction(true); try { - authors = db.getLocalAuthors(txn); + authors = getLocalAuthors(txn); txn.setComplete(); } finally { db.endTransaction(txn); @@ -82,6 +90,12 @@ class IdentityManagerImpl implements IdentityManager { return authors; } + private Collection<LocalAuthor> getLocalAuthors(Transaction txn) + throws DbException { + + return db.getLocalAuthors(txn); + } + @Override public void removeLocalAuthor(AuthorId a) throws DbException { Transaction txn = db.startTransaction(false); diff --git a/briar-core/src/org/briarproject/sharing/BlogSharingManagerImpl.java b/briar-core/src/org/briarproject/sharing/BlogSharingManagerImpl.java index 19f9eef34dfc269ded88f7e2afc40ebf2e3f59f1..7c1ce43bbb0301f8d34f86ece817362d4e66906b 100644 --- a/briar-core/src/org/briarproject/sharing/BlogSharingManagerImpl.java +++ b/briar-core/src/org/briarproject/sharing/BlogSharingManagerImpl.java @@ -26,6 +26,8 @@ import org.briarproject.api.event.BlogInvitationReceivedEvent; import org.briarproject.api.event.BlogInvitationResponseReceivedEvent; import org.briarproject.api.identity.Author; import org.briarproject.api.identity.AuthorFactory; +import org.briarproject.api.identity.IdentityManager; +import org.briarproject.api.identity.LocalAuthor; import org.briarproject.api.sharing.InvitationMessage; import org.briarproject.api.sync.ClientId; import org.briarproject.api.sync.GroupId; @@ -50,6 +52,8 @@ class BlogSharingManagerImpl extends "bee438b5de0b3a685badc4e49d76e72d" + "21e01c4b569a775112756bdae267a028")); + @Inject + IdentityManager identityManager; private final BlogManager blogManager; private final SFactory sFactory; @@ -84,10 +88,19 @@ class BlogSharingManagerImpl extends } @Override - public boolean canBeShared(GroupId g, Contact c) throws DbException { - Blog b = blogManager.getPersonalBlog(c.getAuthor()); + protected boolean canBeShared(Transaction txn, GroupId g, Contact c) + throws DbException { + + // check if g is our personal blog + LocalAuthor author = identityManager.getLocalAuthor(txn); + Blog b = blogManager.getPersonalBlog(author); if (b.getId().equals(g)) return false; - return super.canBeShared(g, c); + + // check if g is c's personal blog + b = blogManager.getPersonalBlog(c.getAuthor()); + if (b.getId().equals(g)) return false; + + return super.canBeShared(txn, g, c); } @Override diff --git a/briar-core/src/org/briarproject/sharing/BlogSharingValidator.java b/briar-core/src/org/briarproject/sharing/BlogSharingValidator.java index 26b89bb52c512c118e02ea5075226e42b5829eda..1a9f0ada3897cc22be668afd7c47c44cf7ea6f34 100644 --- a/briar-core/src/org/briarproject/sharing/BlogSharingValidator.java +++ b/briar-core/src/org/briarproject/sharing/BlogSharingValidator.java @@ -58,7 +58,7 @@ class BlogSharingValidator extends BdfMessageValidator { checkLength(name, 1, MAX_BLOG_TITLE_LENGTH); String desc = body.getString(3); - checkLength(desc, 1, MAX_BLOG_DESC_LENGTH); + checkLength(desc, 0, MAX_BLOG_DESC_LENGTH); BdfList author = body.getList(4); checkSize(author, 2); diff --git a/briar-core/src/org/briarproject/sharing/SharingManagerImpl.java b/briar-core/src/org/briarproject/sharing/SharingManagerImpl.java index 5f6fd4d4111bc697df381907d57aea7ccebdbf5b..24b2b5223d50dc0e83c3904f8d806fddc2988617 100644 --- a/briar-core/src/org/briarproject/sharing/SharingManagerImpl.java +++ b/briar-core/src/org/briarproject/sharing/SharingManagerImpl.java @@ -500,7 +500,7 @@ abstract class SharingManagerImpl<S extends Shareable, I extends Invitation, IS return canBeShared; } - private boolean canBeShared(Transaction txn, GroupId g, Contact c) + protected boolean canBeShared(Transaction txn, GroupId g, Contact c) throws DbException { try {