diff --git a/briar-android-tests/src/test/java/org/briarproject/ForumManagerTest.java b/briar-android-tests/src/test/java/org/briarproject/ForumManagerTest.java
index 59c88d4d7fe03b492aad603783d4718ee1abf50b..b1824191d41afe6c40f0116b27165f94165f9341 100644
--- a/briar-android-tests/src/test/java/org/briarproject/ForumManagerTest.java
+++ b/briar-android-tests/src/test/java/org/briarproject/ForumManagerTest.java
@@ -2,13 +2,30 @@ package org.briarproject;
 
 import junit.framework.Assert;
 
-import org.briarproject.api.db.DatabaseComponent;
+import net.jodah.concurrentunit.Waiter;
+
+import org.briarproject.api.contact.Contact;
+import org.briarproject.api.contact.ContactId;
+import org.briarproject.api.contact.ContactManager;
+import org.briarproject.api.crypto.SecretKey;
+import org.briarproject.api.db.DbException;
+import org.briarproject.api.event.Event;
+import org.briarproject.api.event.EventListener;
+import org.briarproject.api.event.MessageStateChangedEvent;
 import org.briarproject.api.forum.Forum;
 import org.briarproject.api.forum.ForumManager;
 import org.briarproject.api.forum.ForumPost;
 import org.briarproject.api.forum.ForumPostFactory;
 import org.briarproject.api.forum.ForumPostHeader;
+import org.briarproject.api.forum.ForumSharingManager;
+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.sync.GroupId;
+import org.briarproject.api.sync.SyncSession;
+import org.briarproject.api.sync.SyncSessionFactory;
+import org.briarproject.api.system.Clock;
 import org.briarproject.contact.ContactModule;
 import org.briarproject.crypto.CryptoModule;
 import org.briarproject.forum.ForumModule;
@@ -17,55 +34,101 @@ import org.briarproject.properties.PropertiesModule;
 import org.briarproject.sync.SyncModule;
 import org.briarproject.transport.TransportModule;
 import org.briarproject.util.StringUtils;
+import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
 import java.io.File;
+import java.io.IOException;
 import java.util.Collection;
+import java.util.concurrent.TimeoutException;
+import java.util.logging.Logger;
 
 import javax.inject.Inject;
 
 import static junit.framework.Assert.assertEquals;
-import static junit.framework.Assert.assertNotNull;
 import static junit.framework.Assert.assertNull;
 import static junit.framework.TestCase.assertFalse;
+import static org.briarproject.TestPluginsModule.MAX_LATENCY;
+import static org.briarproject.api.identity.AuthorConstants.MAX_PUBLIC_KEY_LENGTH;
+import static org.briarproject.api.sync.ValidationManager.State.DELIVERED;
+import static org.briarproject.api.sync.ValidationManager.State.INVALID;
+import static org.briarproject.api.sync.ValidationManager.State.PENDING;
+import static org.briarproject.api.sync.ValidationManager.State.VALID;
 import static org.junit.Assert.assertTrue;
 
 public class ForumManagerTest {
 
+	private LifecycleManager lifecycleManager0, lifecycleManager1;
+	private SyncSessionFactory sync0, sync1;
+	private ForumManager forumManager0, forumManager1;
+	private ContactManager contactManager0, contactManager1;
+	private ContactId contactId0,contactId1;
+	private IdentityManager identityManager0, identityManager1;
+	private LocalAuthor author0, author1;
+	private Forum forum0;
+
 	@Inject
-	protected ForumManager forumManager;
+	Clock clock;
 	@Inject
-	protected ForumPostFactory forumPostFactory;
+	AuthorFactory authorFactory;
 	@Inject
-	protected DatabaseComponent db;
+	ForumPostFactory forumPostFactory;
+
+	// objects accessed from background threads need to be volatile
+	private volatile ForumSharingManager forumSharingManager0;
+	private volatile ForumSharingManager forumSharingManager1;
+	private volatile Waiter validationWaiter;
+	private volatile Waiter deliveryWaiter;
 
 	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 static final Logger LOG =
+			Logger.getLogger(ForumSharingIntegrationTest.class.getName());
+
+	private ForumManagerTestComponent t0, t1;
 
 	@Before
 	public void setUp() throws Exception {
+		ForumManagerTestComponent component =
+				DaggerForumManagerTestComponent.builder().build();
+		component.inject(this);
+		injectEagerSingletons(component);
 
 		assertTrue(testDir.mkdirs());
-		File tDir = new File(testDir, "db");
+		File t0Dir = new File(testDir, SHARER);
+		t0 = DaggerForumManagerTestComponent.builder()
+				.testDatabaseModule(new TestDatabaseModule(t0Dir)).build();
+		injectEagerSingletons(t0);
+		File t1Dir = new File(testDir, INVITEE);
+		t1 = DaggerForumManagerTestComponent.builder()
+				.testDatabaseModule(new TestDatabaseModule(t1Dir)).build();
+		injectEagerSingletons(t1);
 
-		ForumManagerTestComponent component =
-				DaggerForumManagerTestComponent.builder()
-						.testDatabaseModule(new TestDatabaseModule(tDir))
-						.build();
+		identityManager0 = t0.getIdentityManager();
+		identityManager1 = t1.getIdentityManager();
+		contactManager0 = t0.getContactManager();
+		contactManager1 = t1.getContactManager();
+		forumManager0 = t0.getForumManager();
+		forumManager1 = t1.getForumManager();
+		forumSharingManager0 = t0.getForumSharingManager();
+		forumSharingManager1 = t1.getForumSharingManager();
+		sync0 = t0.getSyncSessionFactory();
+		sync1 = t1.getSyncSessionFactory();
 
-		component.inject(new LifecycleModule.EagerSingletons());
-		component.inject(new ForumModule.EagerSingletons());
-		component.inject(new CryptoModule.EagerSingletons());
-		component.inject(new ContactModule.EagerSingletons());
-		component.inject(new TransportModule.EagerSingletons());
-		component.inject(new SyncModule.EagerSingletons());
-		component.inject(new PropertiesModule.EagerSingletons());
-		component.inject(this);
+		// initialize waiters fresh for each test
+		validationWaiter = new Waiter();
+		deliveryWaiter = new Waiter();
 	}
 
-	ForumPost createForumPost(GroupId groupId, ForumPost parent, String body,
-			long ms)
-			throws Exception {
+	private ForumPost createForumPost(GroupId groupId, ForumPost parent,
+			String body, long ms) throws Exception {
 		return forumPostFactory.createAnonymousPost(groupId, ms,
 				parent == null ? null : parent.getMessage().getId(),
 				"text/plain", StringUtils.toUtf8(body));
@@ -73,13 +136,12 @@ public class ForumManagerTest {
 
 	@Test
 	public void testForumPost() throws Exception {
-		assertFalse(db.open());
-		assertNotNull(forumManager);
-		Forum forum = forumManager.addForum("TestForum");
-		assertEquals(1, forumManager.getForums().size());
-		final long ms1 = System.currentTimeMillis() - 1000L;
+		startLifecycles();
+		Forum forum = forumManager0.addForum("TestForum");
+		assertEquals(1, forumManager0.getForums().size());
+		final long ms1 = clock.currentTimeMillis() - 1000L;
 		final String body1 = "some forum text";
-		final long ms2 = System.currentTimeMillis();
+		final long ms2 = clock.currentTimeMillis();
 		final String body2 = "some other forum text";
 		ForumPost post1 =
 				createForumPost(forum.getGroup().getId(), null, body1, ms1);
@@ -87,16 +149,16 @@ public class ForumManagerTest {
 		ForumPost post2 =
 				createForumPost(forum.getGroup().getId(), post1, body2, ms2);
 		assertEquals(ms2, post2.getMessage().getTimestamp());
-		forumManager.addLocalPost(post1);
-		forumManager.setReadFlag(post1.getMessage().getId(), true);
-		forumManager.addLocalPost(post2);
-		forumManager.setReadFlag(post2.getMessage().getId(), false);
+		forumManager0.addLocalPost(post1);
+		forumManager0.setReadFlag(post1.getMessage().getId(), true);
+		forumManager0.addLocalPost(post2);
+		forumManager0.setReadFlag(post2.getMessage().getId(), false);
 		Collection<ForumPostHeader> headers =
-				forumManager.getPostHeaders(forum.getGroup().getId());
+				forumManager0.getPostHeaders(forum.getGroup().getId());
 		assertEquals(2, headers.size());
 		for (ForumPostHeader h : headers) {
 			final String hBody =
-					StringUtils.fromUtf8(forumManager.getPostBody(h.getId()));
+					StringUtils.fromUtf8(forumManager0.getPostBody(h.getId()));
 
 			boolean isPost1 = h.getId().equals(post1.getMessage().getId());
 			boolean isPost2 = h.getId().equals(post2.getMessage().getId());
@@ -114,8 +176,258 @@ public class ForumManagerTest {
 				assertFalse(h.isRead());
 			}
 		}
-		forumManager.removeForum(forum);
-		assertEquals(0, forumManager.getForums().size());
-		db.close();
+		forumManager0.removeForum(forum);
+		assertEquals(0, forumManager0.getForums().size());
+		stopLifecycles();
 	}
+
+	@Test
+	public void testForumPostDelivery() throws Exception {
+		startLifecycles();
+		defaultInit();
+
+		// share forum
+		GroupId g = forum0.getId();
+		forumSharingManager0.sendForumInvitation(g, contactId1, null);
+		sync0To1();
+		deliveryWaiter.await(TIMEOUT, 1);
+		Contact c0 = contactManager1.getContact(contactId0);
+		forumSharingManager1.respondToInvitation(forum0, c0, true);
+		sync1To0();
+		deliveryWaiter.await(TIMEOUT, 1);
+
+		// add one forum post
+		long time = clock.currentTimeMillis();
+		ForumPost post1 = createForumPost(g, null, "a", time);
+		forumManager0.addLocalPost(post1);
+		assertEquals(1, forumManager0.getPostHeaders(g).size());
+		assertEquals(0, forumManager1.getPostHeaders(g).size());
+
+		// send post to 1
+		sync0To1();
+		deliveryWaiter.await(TIMEOUT, 1);
+		assertEquals(1, forumManager1.getPostHeaders(g).size());
+
+		stopLifecycles();
+	}
+
+	@Test
+	public void testForumPostDeliveredAfterParent() throws Exception {
+		startLifecycles();
+		defaultInit();
+
+		// share forum
+		GroupId g = forum0.getId();
+		forumSharingManager0.sendForumInvitation(g, contactId1, null);
+		sync0To1();
+		deliveryWaiter.await(TIMEOUT, 1);
+		Contact c0 = contactManager1.getContact(contactId0);
+		forumSharingManager1.respondToInvitation(forum0, c0, true);
+		sync1To0();
+		deliveryWaiter.await(TIMEOUT, 1);
+
+		// add one forum post without the parent
+		long time = clock.currentTimeMillis();
+		ForumPost post1 = createForumPost(g, null, "a", time);
+		ForumPost post2 = createForumPost(g, post1, "a", time);
+		forumManager0.addLocalPost(post2);
+		assertEquals(1, forumManager0.getPostHeaders(g).size());
+		assertEquals(0, forumManager1.getPostHeaders(g).size());
+
+		// send post to 1 without waiting for message delivery
+		sync0To1();
+		validationWaiter.await(TIMEOUT, 1);
+		assertEquals(0, forumManager1.getPostHeaders(g).size());
+
+		// now add the parent post as well
+		forumManager0.addLocalPost(post1);
+		assertEquals(2, forumManager0.getPostHeaders(g).size());
+		assertEquals(0, forumManager1.getPostHeaders(g).size());
+
+		// and send it over to 1 and wait for a second message to be delivered
+		sync0To1();
+		deliveryWaiter.await(TIMEOUT, 2);
+		assertEquals(2, forumManager1.getPostHeaders(g).size());
+
+		stopLifecycles();
+	}
+
+	@Test
+	public void testForumPostWithParentInOtherGroup() throws Exception {
+		startLifecycles();
+		defaultInit();
+
+		// share forum
+		GroupId g = forum0.getId();
+		forumSharingManager0.sendForumInvitation(g, contactId1, null);
+		sync0To1();
+		deliveryWaiter.await(TIMEOUT, 1);
+		Contact c0 = contactManager1.getContact(contactId0);
+		forumSharingManager1.respondToInvitation(forum0, c0, true);
+		sync1To0();
+		deliveryWaiter.await(TIMEOUT, 1);
+
+		// share a second forum
+		Forum forum1 = forumManager0.addForum("Test Forum1");
+		GroupId g1 = forum1.getId();
+		forumSharingManager0.sendForumInvitation(g1, contactId1, null);
+		sync0To1();
+		deliveryWaiter.await(TIMEOUT, 1);
+		forumSharingManager1.respondToInvitation(forum1, c0, true);
+		sync1To0();
+		deliveryWaiter.await(TIMEOUT, 1);
+
+		// add one forum post with a parent in another forum
+		long time = clock.currentTimeMillis();
+		ForumPost post1 = createForumPost(g1, null, "a", time);
+		ForumPost post = createForumPost(g, post1, "b", time);
+		forumManager0.addLocalPost(post);
+		assertEquals(1, forumManager0.getPostHeaders(g).size());
+		assertEquals(0, forumManager1.getPostHeaders(g).size());
+
+		// send posts to 1
+		sync0To1();
+		validationWaiter.await(TIMEOUT, 1);
+		assertEquals(1, forumManager0.getPostHeaders(g).size());
+		assertEquals(0, forumManager1.getPostHeaders(g).size());
+
+		// now also add the parent post which is in another group
+		forumManager0.addLocalPost(post1);
+		assertEquals(1, forumManager0.getPostHeaders(g1).size());
+		assertEquals(0, forumManager1.getPostHeaders(g1).size());
+
+		// send posts to 1
+		sync0To1();
+		deliveryWaiter.await(TIMEOUT, 1);
+		assertEquals(1, forumManager0.getPostHeaders(g).size());
+		assertEquals(1, forumManager0.getPostHeaders(g1).size());
+		// the next line is critical, makes sure post doesn't show up
+		assertEquals(0, forumManager1.getPostHeaders(g).size());
+		assertEquals(1, forumManager1.getPostHeaders(g1).size());
+
+		stopLifecycles();
+	}
+
+	@After
+	public void tearDown() throws Exception {
+		TestUtils.deleteTestDirectory(testDir);
+	}
+
+	private class Listener implements EventListener {
+		public void eventOccurred(Event e) {
+			if (e instanceof MessageStateChangedEvent) {
+				MessageStateChangedEvent event = (MessageStateChangedEvent) e;
+				if (!event.isLocal()) {
+					if (event.getState() == DELIVERED) {
+						deliveryWaiter.resume();
+					} else if (event.getState() == VALID ||
+							event.getState() == INVALID ||
+							event.getState() == PENDING) {
+						validationWaiter.resume();
+					}
+				}
+			}
+		}
+	}
+
+	private void defaultInit() throws DbException {
+		addDefaultIdentities();
+		addDefaultContacts();
+		addForum();
+		listenToEvents();
+	}
+
+	private void addDefaultIdentities() throws DbException {
+		author0 = authorFactory.createLocalAuthor(SHARER,
+				TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH),
+				TestUtils.getRandomBytes(123));
+		identityManager0.addLocalAuthor(author0);
+		author1 = authorFactory.createLocalAuthor(INVITEE,
+				TestUtils.getRandomBytes(MAX_PUBLIC_KEY_LENGTH),
+				TestUtils.getRandomBytes(123));
+		identityManager1.addLocalAuthor(author1);
+	}
+
+	private void addDefaultContacts() throws DbException {
+		// sharer adds invitee as contact
+		contactId1 = contactManager0.addContact(author1,
+				author0.getId(), master, clock.currentTimeMillis(), true,
+				true
+		);
+		// invitee adds sharers back
+		contactId0 = contactManager1.addContact(author0,
+				author1.getId(), master, clock.currentTimeMillis(), true,
+				true
+		);
+	}
+
+	private void addForum() throws DbException {
+		forum0 = forumManager0.addForum("Test Forum");
+	}
+
+	private void listenToEvents() {
+		Listener listener0 = new Listener();
+		t0.getEventBus().addListener(listener0);
+		Listener listener1 = new Listener();
+		t1.getEventBus().addListener(listener1);
+	}
+
+	private void sync0To1() throws IOException, TimeoutException {
+		deliverMessage(sync0, contactId0, sync1, contactId1, "0 to 1");
+	}
+
+	private void sync1To0() throws IOException, TimeoutException {
+		deliverMessage(sync1, contactId1, sync0, contactId0, "1 to 0");
+	}
+
+	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();
+	}
+
+	private void startLifecycles() throws InterruptedException {
+		// Start the lifecycle manager and wait for it to finish
+		lifecycleManager0 = t0.getLifecycleManager();
+		lifecycleManager1 = t1.getLifecycleManager();
+		lifecycleManager0.startServices();
+		lifecycleManager1.startServices();
+		lifecycleManager0.waitForStartup();
+		lifecycleManager1.waitForStartup();
+	}
+
+	private void stopLifecycles() throws InterruptedException {
+		// Clean up
+		lifecycleManager0.stopServices();
+		lifecycleManager1.stopServices();
+		lifecycleManager0.waitForShutdown();
+		lifecycleManager1.waitForShutdown();
+	}
+
+	private void injectEagerSingletons(ForumManagerTestComponent component) {
+		component.inject(new LifecycleModule.EagerSingletons());
+		component.inject(new ForumModule.EagerSingletons());
+		component.inject(new CryptoModule.EagerSingletons());
+		component.inject(new ContactModule.EagerSingletons());
+		component.inject(new TransportModule.EagerSingletons());
+		component.inject(new SyncModule.EagerSingletons());
+		component.inject(new PropertiesModule.EagerSingletons());
+	}
+
 }
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 cac69fb0df0754b6af1ada181fb29512d27d2e8b..8a9e5fc6db41a653e6e9737a39874cb89dce6b4c 100644
--- a/briar-android-tests/src/test/java/org/briarproject/ForumManagerTestComponent.java
+++ b/briar-android-tests/src/test/java/org/briarproject/ForumManagerTestComponent.java
@@ -1,5 +1,12 @@
 package org.briarproject;
 
+import org.briarproject.api.contact.ContactManager;
+import org.briarproject.api.event.EventBus;
+import org.briarproject.api.forum.ForumManager;
+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.clients.ClientsModule;
 import org.briarproject.contact.ContactModule;
 import org.briarproject.crypto.CryptoModule;
@@ -55,4 +62,18 @@ public interface ForumManagerTestComponent {
 
 	void inject(TransportModule.EagerSingletons init);
 
+	LifecycleManager getLifecycleManager();
+
+	EventBus getEventBus();
+
+	IdentityManager getIdentityManager();
+
+	ContactManager getContactManager();
+
+	ForumSharingManager getForumSharingManager();
+
+	ForumManager getForumManager();
+
+	SyncSessionFactory getSyncSessionFactory();
+
 }
diff --git a/briar-core/src/org/briarproject/forum/ForumPostValidator.java b/briar-core/src/org/briarproject/forum/ForumPostValidator.java
index 6dbc68e96f6ff5ff8a8134d1b663ba5ea5f29ed8..e0a86a7b8c14a18560971f50477a8cc4cdbc2d4f 100644
--- a/briar-core/src/org/briarproject/forum/ForumPostValidator.java
+++ b/briar-core/src/org/briarproject/forum/ForumPostValidator.java
@@ -2,8 +2,8 @@ package org.briarproject.forum;
 
 import org.briarproject.api.FormatException;
 import org.briarproject.api.UniqueId;
-import org.briarproject.api.clients.ClientHelper;
 import org.briarproject.api.clients.BdfMessageContext;
+import org.briarproject.api.clients.ClientHelper;
 import org.briarproject.api.crypto.CryptoComponent;
 import org.briarproject.api.crypto.KeyParser;
 import org.briarproject.api.crypto.PublicKey;
@@ -16,10 +16,13 @@ import org.briarproject.api.identity.AuthorFactory;
 import org.briarproject.api.sync.Group;
 import org.briarproject.api.sync.InvalidMessageException;
 import org.briarproject.api.sync.Message;
+import org.briarproject.api.sync.MessageId;
 import org.briarproject.api.system.Clock;
 import org.briarproject.clients.BdfMessageValidator;
 
 import java.security.GeneralSecurityException;
+import java.util.Collection;
+import java.util.Collections;
 
 import static org.briarproject.api.forum.ForumConstants.MAX_CONTENT_TYPE_LENGTH;
 import static org.briarproject.api.forum.ForumConstants.MAX_FORUM_POST_BODY_LENGTH;
@@ -96,10 +99,14 @@ class ForumPostValidator extends BdfMessageValidator {
 				throw new InvalidMessageException("Invalid public key");
 			}
 		}
-		// Return the metadata
+		// Return the metadata and dependencies
 		BdfDictionary meta = new BdfDictionary();
+		Collection<MessageId> dependencies = null;
 		meta.put("timestamp", m.getTimestamp());
-		if (parent != null) meta.put("parent", parent);
+		if (parent != null) {
+			meta.put("parent", parent);
+			dependencies = Collections.singletonList(new MessageId(parent));
+		}
 		if (author != null) {
 			BdfDictionary authorMeta = new BdfDictionary();
 			authorMeta.put("id", author.getId());
@@ -109,6 +116,6 @@ class ForumPostValidator extends BdfMessageValidator {
 		}
 		meta.put("contentType", contentType);
 		meta.put("read", false);
-		return new BdfMessageContext(meta);
+		return new BdfMessageContext(meta, dependencies);
 	}
 }