diff --git a/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingIntegrationTest.java b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingIntegrationTest.java
index 6a394f6d87a5575b29a9bffc802ad3fe236e49b9..b66b98124d5c99b42996344397e104b42420eb69 100644
--- a/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingIntegrationTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingIntegrationTest.java
@@ -5,7 +5,6 @@ import net.jodah.concurrentunit.Waiter;
 import org.briarproject.bramble.api.contact.Contact;
 import org.briarproject.bramble.api.db.DbException;
 import org.briarproject.bramble.api.db.NoSuchGroupException;
-import org.briarproject.bramble.api.db.Transaction;
 import org.briarproject.bramble.api.event.Event;
 import org.briarproject.bramble.api.event.EventListener;
 import org.briarproject.bramble.api.nullsafety.NotNullByDefault;
@@ -493,26 +492,6 @@ public class BlogSharingIntegrationTest
 		// 1 can again share blog 1 with 0
 		assertTrue(
 				blogSharingManager1.canBeShared(blog1.getId(), contact0From1));
-
-		// re-create local state (simulates sign-out and sign-in)
-		Transaction txn0 = db0.startTransaction(false);
-		((BlogSharingManagerImpl) blogSharingManager0).createLocalState(txn0);
-		db0.commitTransaction(txn0);
-		db0.endTransaction(txn0);
-		Transaction txn1 = db1.startTransaction(false);
-		((BlogSharingManagerImpl) blogSharingManager1).createLocalState(txn1);
-		db1.commitTransaction(txn1);
-		db1.endTransaction(txn1);
-
-		// ensure there's no error with the sessions by checking shareability
-		assertFalse(
-				blogSharingManager0.canBeShared(blog1.getId(), contact1From0));
-		assertTrue(
-				blogSharingManager1.canBeShared(blog1.getId(), contact0From1));
-
-		// contacts should still be able to remove each other without errors
-		contactManager0.removeContact(contactId1From0);
-		contactManager1.removeContact(contactId0From1);
 	}
 
 	@Test
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
new file mode 100644
index 0000000000000000000000000000000000000000..11ef75f1f9872a6466f4aedc935b8c8e968a699a
--- /dev/null
+++ b/briar-core/src/test/java/org/briarproject/briar/sharing/BlogSharingManagerImplTest.java
@@ -0,0 +1,253 @@
+package org.briarproject.briar.sharing;
+
+import org.briarproject.bramble.api.client.ClientHelper;
+import org.briarproject.bramble.api.client.ContactGroupFactory;
+import org.briarproject.bramble.api.contact.Contact;
+import org.briarproject.bramble.api.contact.ContactId;
+import org.briarproject.bramble.api.data.BdfDictionary;
+import org.briarproject.bramble.api.data.BdfEntry;
+import org.briarproject.bramble.api.data.MetadataParser;
+import org.briarproject.bramble.api.db.DatabaseComponent;
+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;
+import org.briarproject.bramble.api.sync.GroupId;
+import org.briarproject.bramble.api.sync.Message;
+import org.briarproject.bramble.api.sync.MessageId;
+import org.briarproject.bramble.test.BrambleMockTestCase;
+import org.briarproject.briar.api.blog.Blog;
+import org.briarproject.briar.api.blog.BlogInvitationResponse;
+import org.briarproject.briar.api.blog.BlogManager;
+import org.briarproject.briar.api.client.MessageTracker;
+import org.briarproject.briar.api.client.SessionId;
+import org.jmock.Expectations;
+import org.jmock.Mockery;
+import org.junit.Test;
+
+import java.util.Collection;
+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.getRandomBytes;
+import static org.briarproject.bramble.test.TestUtils.getRandomId;
+import static org.briarproject.briar.api.blog.BlogSharingManager.CLIENT_ID;
+import static org.briarproject.briar.sharing.SharingConstants.GROUP_KEY_CONTACT_ID;
+
+public class BlogSharingManagerImplTest extends BrambleMockTestCase {
+
+	private final Mockery context = new Mockery();
+	private final BlogSharingManagerImpl blogSharingManager;
+	private final DatabaseComponent db = context.mock(DatabaseComponent.class);
+	private final IdentityManager identityManager =
+			context.mock(IdentityManager.class);
+	private final ClientHelper clientHelper = context.mock(ClientHelper.class);
+	private final SessionEncoder sessionEncoder =
+			context.mock(SessionEncoder.class);
+	private final SessionParser sessionParser =
+			context.mock(SessionParser.class);
+	private final ContactGroupFactory contactGroupFactory =
+			context.mock(ContactGroupFactory.class);
+	private final BlogManager blogManager = context.mock(BlogManager.class);
+
+	private final AuthorId localAuthorId = new AuthorId(getRandomId());
+	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 Contact contact =
+			new Contact(contactId, author, localAuthorId, 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 Blog blog = new Blog(blogGroup, author, false);
+	@SuppressWarnings("unchecked")
+	private final ProtocolEngine<Blog> engine =
+			context.mock(ProtocolEngine.class);
+
+	@SuppressWarnings("unchecked")
+	public BlogSharingManagerImplTest() {
+		MetadataParser metadataParser = context.mock(MetadataParser.class);
+		MessageTracker messageTracker = context.mock(MessageTracker.class);
+		MessageParser<Blog> messageParser = context.mock(MessageParser.class);
+		InvitationFactory<Blog, BlogInvitationResponse> invitationFactory =
+				context.mock(InvitationFactory.class);
+		blogSharingManager =
+				new BlogSharingManagerImpl(db, clientHelper, metadataParser,
+						messageParser, sessionEncoder, sessionParser,
+						messageTracker, contactGroupFactory,
+						engine, invitationFactory, identityManager,
+						blogManager);
+	}
+
+	@Test
+	public void testAddingContactFreshState() throws Exception {
+		Map<MessageId, BdfDictionary> sessions =
+				new HashMap<MessageId, BdfDictionary>(0);
+		testAddingContact(sessions);
+	}
+
+	@Test
+	public void testAddingContactExistingState() throws Exception {
+		Map<MessageId, BdfDictionary> sessions =
+				new HashMap<MessageId, BdfDictionary>(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<MessageId, BdfDictionary>(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<MessageId, BdfDictionary>(0);
+		testRemovingBlog(sessions);
+	}
+
+	@Test
+	public void testRemovingBlogExistingState() throws Exception {
+		Map<MessageId, BdfDictionary> sessions =
+				new HashMap<MessageId, BdfDictionary>(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<MessageId, BdfDictionary>(2);
+		sessions.put(new MessageId(getRandomId()), new BdfDictionary());
+		sessions.put(new MessageId(getRandomId()), new BdfDictionary());
+		testRemovingBlog(sessions);
+	}
+
+	private void testAddingContact(final Map<MessageId, BdfDictionary> sessions)
+			throws Exception {
+		final Transaction txn = new Transaction(null, false);
+		final LocalAuthor localAuthor =
+				new LocalAuthor(localAuthorId, "Local Author",
+						getRandomBytes(MAX_PUBLIC_KEY_LENGTH),
+						getRandomBytes(MAX_PUBLIC_KEY_LENGTH),
+						System.currentTimeMillis());
+		final BdfDictionary meta = BdfDictionary
+				.of(new BdfEntry(GROUP_KEY_CONTACT_ID, contactId.getInt()));
+		final Group localBlogGroup =
+				new Group(new GroupId(getRandomId()), BlogManager.CLIENT_ID,
+						getRandomBytes(42));
+		final Blog localBlog = new Blog(localBlogGroup, localAuthor, false);
+
+		context.checking(new Expectations() {{
+			oneOf(db).getContacts(txn);
+			will(returnValue(contacts));
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			will(returnValue(contactGroup));
+			oneOf(db).containsGroup(txn, contactGroup.getId());
+			will(returnValue(false));
+			oneOf(db).addGroup(txn, contactGroup);
+			oneOf(db).setGroupVisibility(txn, contactId, contactGroup.getId(),
+					SHARED);
+			oneOf(clientHelper)
+					.mergeGroupMetadata(txn, contactGroup.getId(), meta);
+			oneOf(identityManager).getLocalAuthor(txn);
+			will(returnValue(localAuthor));
+			oneOf(blogManager).getPersonalBlog(localAuthor);
+			will(returnValue(localBlog));
+			oneOf(blogManager).getPersonalBlog(author);
+			will(returnValue(blog));
+		}});
+		expectPreShareShareable(txn, contact, localBlog, sessions);
+		expectPreShareShareable(txn, contact, blog, sessions);
+
+		blogSharingManager.createLocalState(txn);
+	}
+
+	private void expectPreShareShareable(final Transaction txn,
+			final Contact contact, final Blog blog,
+			final Map<MessageId, BdfDictionary> sessions) throws Exception {
+		final Group contactGroup =
+				new Group(new GroupId(getRandomId()), CLIENT_ID,
+						getRandomBytes(42));
+		final BdfDictionary sessionDict = new BdfDictionary();
+		final Message message =
+				new Message(new MessageId(getRandomId()), contactGroup.getId(),
+						42L, getRandomBytes(1337));
+		context.checking(new Expectations() {{
+			oneOf(contactGroupFactory)
+					.createContactGroup(CLIENT_ID, contact);
+			will(returnValue(contactGroup));
+			oneOf(sessionParser)
+					.getSessionQuery(new SessionId(blog.getId().getBytes()));
+			will(returnValue(sessionDict));
+			oneOf(clientHelper)
+					.getMessageMetadataAsDictionary(txn, contactGroup.getId(),
+							sessionDict);
+			will(returnValue(sessions));
+			if (sessions.size() == 0) {
+				oneOf(db).addGroup(txn, blog.getGroup());
+				oneOf(db).setGroupVisibility(txn, contact.getId(),
+						blog.getGroup().getId(), SHARED);
+				oneOf(clientHelper)
+						.createMessageForStoringMetadata(contactGroup.getId());
+				will(returnValue(message));
+				oneOf(db).addLocalMessage(txn, message, new Metadata(), false);
+				oneOf(sessionEncoder).encodeSession(with(any(Session.class)));
+				will(returnValue(sessionDict));
+				oneOf(clientHelper).mergeMessageMetadata(txn, message.getId(),
+						sessionDict);
+			}
+		}});
+	}
+
+	private void testRemovingBlog(final Map<MessageId, BdfDictionary> sessions)
+			throws Exception {
+		final Transaction txn = new Transaction(null, false);
+		final BdfDictionary sessionDict = new BdfDictionary();
+		final Session session = new Session(contactGroup.getId(), blog.getId());
+
+		context.checking(new Expectations() {{
+			oneOf(db).getContacts(txn);
+			will(returnValue(contacts));
+			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact);
+			will(returnValue(contactGroup));
+			oneOf(sessionParser)
+					.getSessionQuery(new SessionId(blog.getId().getBytes()));
+			will(returnValue(sessionDict));
+			oneOf(clientHelper)
+					.getMessageMetadataAsDictionary(txn, contactGroup.getId(),
+							sessionDict);
+			will(returnValue(sessions));
+			if (sessions.size() == 1) {
+				oneOf(sessionParser)
+						.parseSession(contactGroup.getId(), sessionDict);
+				will(returnValue(session));
+				oneOf(engine).onLeaveAction(txn, session);
+				will(returnValue(session));
+				oneOf(sessionEncoder).encodeSession(session);
+				will(returnValue(sessionDict));
+				oneOf(clientHelper).mergeMessageMetadata(txn,
+						sessions.keySet().iterator().next(), sessionDict);
+			}
+		}});
+		blogSharingManager.removingBlog(txn, blog);
+	}
+
+}