From 8c00f2417bfa45fbf18114f1fe94c19d2e0821ec Mon Sep 17 00:00:00 2001
From: akwizgran <michael@briarproject.org>
Date: Fri, 13 Apr 2018 13:10:02 +0100
Subject: [PATCH] Add client version to groups table.

---
 .../bramble/api/db/DatabaseComponent.java     |  3 +-
 .../briarproject/bramble/api/sync/Group.java  | 12 ++++++-
 .../briarproject/bramble/test/TestUtils.java  |  9 ++---
 .../org/briarproject/bramble/db/Database.java |  3 +-
 .../bramble/db/DatabaseComponentImpl.java     |  6 ++--
 .../briarproject/bramble/db/JdbcDatabase.java | 35 +++++++++++--------
 .../bramble/sync/GroupFactoryImpl.java        |  2 +-
 .../bramble/db/DatabaseComponentImplTest.java |  8 +++--
 .../bramble/db/DatabasePerformanceTest.java   |  6 ++--
 .../bramble/db/JdbcDatabaseTest.java          | 22 ++++++++++--
 .../TransportPropertyManagerImplTest.java     | 20 +++++------
 .../TransportPropertyValidatorTest.java       |  5 +--
 .../sync/ValidationManagerImplTest.java       |  2 +-
 .../briar/blog/BlogManagerImpl.java           |  2 +-
 .../briar/forum/ForumManagerImpl.java         |  2 +-
 .../privategroup/PrivateGroupManagerImpl.java |  2 +-
 .../GroupInvitationManagerImpl.java           |  3 +-
 .../briar/blog/BlogManagerImplTest.java       |  5 ++-
 .../briar/blog/BlogPostValidatorTest.java     |  2 +-
 .../briar/feed/FeedManagerImplTest.java       |  5 +--
 .../AbstractProtocolEngineTest.java           |  4 ++-
 .../GroupInvitationManagerImplTest.java       | 13 +++----
 .../sharing/BlogSharingManagerImplTest.java   | 12 ++++---
 23 files changed, 116 insertions(+), 67 deletions(-)

diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java
index 8835b75262..5e50efdc29 100644
--- a/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java
+++ b/bramble-api/src/main/java/org/briarproject/bramble/api/db/DatabaseComponent.java
@@ -241,7 +241,8 @@ public interface DatabaseComponent {
 	 * <p/>
 	 * Read-only.
 	 */
-	Collection<Group> getGroups(Transaction txn, ClientId c) throws DbException;
+	Collection<Group> getGroups(Transaction txn, ClientId c, int clientVersion)
+			throws DbException;
 
 	/**
 	 * Returns the given group's visibility to the given contact, or
diff --git a/bramble-api/src/main/java/org/briarproject/bramble/api/sync/Group.java b/bramble-api/src/main/java/org/briarproject/bramble/api/sync/Group.java
index 5ffe422c2a..40d2da6ff8 100644
--- a/bramble-api/src/main/java/org/briarproject/bramble/api/sync/Group.java
+++ b/bramble-api/src/main/java/org/briarproject/bramble/api/sync/Group.java
@@ -17,13 +17,16 @@ public class Group {
 
 	private final GroupId id;
 	private final ClientId clientId;
+	private final int clientVersion;
 	private final byte[] descriptor;
 
-	public Group(GroupId id, ClientId clientId, byte[] descriptor) {
+	public Group(GroupId id, ClientId clientId, int clientVersion,
+			byte[] descriptor) {
 		if (descriptor.length > MAX_GROUP_DESCRIPTOR_LENGTH)
 			throw new IllegalArgumentException();
 		this.id = id;
 		this.clientId = clientId;
+		this.clientVersion = clientVersion;
 		this.descriptor = descriptor;
 	}
 
@@ -41,6 +44,13 @@ public class Group {
 		return clientId;
 	}
 
+	/**
+	 * Returns the version of the client to which the group belongs.
+	 */
+	public int getClientVersion() {
+		return clientVersion;
+	}
+
 	/**
 	 * Returns the group's descriptor.
 	 */
diff --git a/bramble-api/src/test/java/org/briarproject/bramble/test/TestUtils.java b/bramble-api/src/test/java/org/briarproject/bramble/test/TestUtils.java
index 3ce8d15499..0bff1a547d 100644
--- a/bramble-api/src/test/java/org/briarproject/bramble/test/TestUtils.java
+++ b/bramble-api/src/test/java/org/briarproject/bramble/test/TestUtils.java
@@ -117,15 +117,16 @@ public class TestUtils {
 		return new Author(id, FORMAT_VERSION, name, publicKey);
 	}
 
-	public static Group getGroup(ClientId clientId) {
+	public static Group getGroup(ClientId clientId, int clientVersion) {
 		int descriptorLength = 1 + random.nextInt(MAX_GROUP_DESCRIPTOR_LENGTH);
-		return getGroup(clientId, descriptorLength);
+		return getGroup(clientId, clientVersion, descriptorLength);
 	}
 
-	public static Group getGroup(ClientId clientId, int descriptorLength) {
+	public static Group getGroup(ClientId clientId, int clientVersion,
+			int descriptorLength) {
 		GroupId groupId = new GroupId(getRandomId());
 		byte[] descriptor = getRandomBytes(descriptorLength);
-		return new Group(groupId, clientId, descriptor);
+		return new Group(groupId, clientId, clientVersion, descriptor);
 	}
 
 	public static Message getMessage(GroupId groupId) {
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java b/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java
index 0c3b2b1bcc..7a132510fc 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/db/Database.java
@@ -266,7 +266,8 @@ interface Database<T> {
 	 * <p/>
 	 * Read-only.
 	 */
-	Collection<Group> getGroups(T txn, ClientId c) throws DbException;
+	Collection<Group> getGroups(T txn, ClientId c, int clientVersion)
+			throws DbException;
 
 	/**
 	 * Returns the given group's visibility to the given contact, or
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java
index 3661039aa8..b24567bf30 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/db/DatabaseComponentImpl.java
@@ -435,10 +435,10 @@ class DatabaseComponentImpl<T> implements DatabaseComponent {
 	}
 
 	@Override
-	public Collection<Group> getGroups(Transaction transaction, ClientId c)
-			throws DbException {
+	public Collection<Group> getGroups(Transaction transaction, ClientId c,
+			int clientVersion) throws DbException {
 		T txn = unbox(transaction);
-		return db.getGroups(txn, c);
+		return db.getGroups(txn, c, clientVersion);
 	}
 
 	@Override
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java
index dd0e928a85..3bffa85296 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/db/JdbcDatabase.java
@@ -117,6 +117,7 @@ abstract class JdbcDatabase implements Database<Connection> {
 			"CREATE TABLE groups"
 					+ " (groupId _HASH NOT NULL,"
 					+ " clientId _STRING NOT NULL,"
+					+ " clientVersion INT NOT NULL,"
 					+ " descriptor _BINARY NOT NULL,"
 					+ " PRIMARY KEY (groupId))";
 
@@ -275,9 +276,9 @@ abstract class JdbcDatabase implements Database<Connection> {
 			"CREATE INDEX IF NOT EXISTS contactsByAuthorId"
 					+ " ON contacts (authorId)";
 
-	private static final String INDEX_GROUPS_BY_CLIENT_ID =
-			"CREATE INDEX IF NOT EXISTS groupsByClientId"
-					+ " ON groups (clientId)";
+	private static final String INDEX_GROUPS_BY_CLIENT_ID_CLIENT_VERSION =
+			"CREATE INDEX IF NOT EXISTS groupsByClientIdClientVersion"
+					+ " ON groups (clientId, clientVersion)";
 
 	private static final String INDEX_MESSAGE_METADATA_BY_GROUP_ID_STATE =
 			"CREATE INDEX IF NOT EXISTS messageMetadataByGroupIdState"
@@ -444,7 +445,7 @@ abstract class JdbcDatabase implements Database<Connection> {
 		try {
 			s = txn.createStatement();
 			s.executeUpdate(INDEX_CONTACTS_BY_AUTHOR_ID);
-			s.executeUpdate(INDEX_GROUPS_BY_CLIENT_ID);
+			s.executeUpdate(INDEX_GROUPS_BY_CLIENT_ID_CLIENT_VERSION);
 			s.executeUpdate(INDEX_MESSAGE_METADATA_BY_GROUP_ID_STATE);
 			s.executeUpdate(INDEX_MESSAGE_DEPENDENCIES_BY_DEPENDENCY_ID);
 			s.executeUpdate(INDEX_STATUSES_BY_CONTACT_ID_GROUP_ID);
@@ -612,12 +613,14 @@ abstract class JdbcDatabase implements Database<Connection> {
 	public void addGroup(Connection txn, Group g) throws DbException {
 		PreparedStatement ps = null;
 		try {
-			String sql = "INSERT INTO groups (groupId, clientId, descriptor)"
-					+ " VALUES (?, ?, ?)";
+			String sql = "INSERT INTO groups"
+					+ " (groupId, clientId, clientVersion, descriptor)"
+					+ " VALUES (?, ?, ?, ?)";
 			ps = txn.prepareStatement(sql);
 			ps.setBytes(1, g.getId().getBytes());
 			ps.setString(2, g.getClientId().getString());
-			ps.setBytes(3, g.getDescriptor());
+			ps.setInt(3, g.getClientVersion());
+			ps.setBytes(4, g.getDescriptor());
 			int affected = ps.executeUpdate();
 			if (affected != 1) throw new DbStateException();
 			ps.close();
@@ -1346,17 +1349,18 @@ abstract class JdbcDatabase implements Database<Connection> {
 		PreparedStatement ps = null;
 		ResultSet rs = null;
 		try {
-			String sql = "SELECT clientId, descriptor FROM groups"
-					+ " WHERE groupId = ?";
+			String sql = "SELECT clientId, clientVersion, descriptor"
+					+ " FROM groups WHERE groupId = ?";
 			ps = txn.prepareStatement(sql);
 			ps.setBytes(1, g.getBytes());
 			rs = ps.executeQuery();
 			if (!rs.next()) throw new DbStateException();
 			ClientId clientId = new ClientId(rs.getString(1));
-			byte[] descriptor = rs.getBytes(2);
+			int clientVersion = rs.getInt(2);
+			byte[] descriptor = rs.getBytes(3);
 			rs.close();
 			ps.close();
-			return new Group(g, clientId, descriptor);
+			return new Group(g, clientId, clientVersion, descriptor);
 		} catch (SQLException e) {
 			tryToClose(rs);
 			tryToClose(ps);
@@ -1365,21 +1369,22 @@ abstract class JdbcDatabase implements Database<Connection> {
 	}
 
 	@Override
-	public Collection<Group> getGroups(Connection txn, ClientId c)
-			throws DbException {
+	public Collection<Group> getGroups(Connection txn, ClientId c,
+			int clientVersion) throws DbException {
 		PreparedStatement ps = null;
 		ResultSet rs = null;
 		try {
 			String sql = "SELECT groupId, descriptor FROM groups"
-					+ " WHERE clientId = ?";
+					+ " WHERE clientId = ? AND clientVersion = ?";
 			ps = txn.prepareStatement(sql);
 			ps.setString(1, c.getString());
+			ps.setInt(2, clientVersion);
 			rs = ps.executeQuery();
 			List<Group> groups = new ArrayList<>();
 			while (rs.next()) {
 				GroupId id = new GroupId(rs.getBytes(1));
 				byte[] descriptor = rs.getBytes(2);
-				groups.add(new Group(id, c, descriptor));
+				groups.add(new Group(id, c, clientVersion, descriptor));
 			}
 			rs.close();
 			ps.close();
diff --git a/bramble-core/src/main/java/org/briarproject/bramble/sync/GroupFactoryImpl.java b/bramble-core/src/main/java/org/briarproject/bramble/sync/GroupFactoryImpl.java
index e7bc4e16e6..6f12e6ff8f 100644
--- a/bramble-core/src/main/java/org/briarproject/bramble/sync/GroupFactoryImpl.java
+++ b/bramble-core/src/main/java/org/briarproject/bramble/sync/GroupFactoryImpl.java
@@ -34,6 +34,6 @@ class GroupFactoryImpl implements GroupFactory {
 		byte[] hash = crypto.hash(LABEL, new byte[] {FORMAT_VERSION},
 				StringUtils.toUtf8(c.getString()), clientVersionBytes,
 				descriptor);
-		return new Group(new GroupId(hash), c, descriptor);
+		return new Group(new GroupId(hash), c, clientVersion, descriptor);
 	}
 }
diff --git a/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java
index ae3e203405..5d08264f7d 100644
--- a/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java
+++ b/bramble-core/src/test/java/org/briarproject/bramble/db/DatabaseComponentImplTest.java
@@ -89,6 +89,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
 
 	private final Object txn = new Object();
 	private final ClientId clientId;
+	private final int clientVersion;
 	private final GroupId groupId;
 	private final Group group;
 	private final Author author;
@@ -106,7 +107,8 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
 
 	public DatabaseComponentImplTest() {
 		clientId = getClientId();
-		group = getGroup(clientId);
+		clientVersion = 123;
+		group = getGroup(clientId, clientVersion);
 		groupId = group.getId();
 		author = getAuthor();
 		localAuthor = getLocalAuthor();
@@ -175,7 +177,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
 			oneOf(database).containsGroup(txn, groupId);
 			will(returnValue(true));
 			// getGroups()
-			oneOf(database).getGroups(txn, clientId);
+			oneOf(database).getGroups(txn, clientId, clientVersion);
 			will(returnValue(singletonList(group)));
 			// removeGroup()
 			oneOf(database).containsGroup(txn, groupId);
@@ -215,7 +217,7 @@ public class DatabaseComponentImplTest extends BrambleMockTestCase {
 			db.addGroup(transaction, group); // First time - listeners called
 			db.addGroup(transaction, group); // Second time - not called
 			assertEquals(singletonList(group),
-					db.getGroups(transaction, clientId));
+					db.getGroups(transaction, clientId, clientVersion));
 			db.removeGroup(transaction, group);
 			db.removeContact(transaction, contactId);
 			db.removeLocalAuthor(transaction, localAuthor.getId());
diff --git a/bramble-core/src/test/java/org/briarproject/bramble/db/DatabasePerformanceTest.java b/bramble-core/src/test/java/org/briarproject/bramble/db/DatabasePerformanceTest.java
index 389f7c1c3a..e46a75b684 100644
--- a/bramble-core/src/test/java/org/briarproject/bramble/db/DatabasePerformanceTest.java
+++ b/bramble-core/src/test/java/org/briarproject/bramble/db/DatabasePerformanceTest.java
@@ -267,7 +267,7 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
 		String name = "getGroups(T, ClientId)";
 		benchmark(name, db -> {
 			Connection txn = db.startTransaction();
-			db.getGroups(txn, pickRandom(clientIds));
+			db.getGroups(txn, pickRandom(clientIds), 123);
 			db.commitTransaction(txn);
 		});
 	}
@@ -550,7 +550,7 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
 			contacts.add(db.getContact(txn, c));
 			contactGroups.put(c, new ArrayList<>());
 			for (int j = 0; j < GROUPS_PER_CONTACT; j++) {
-				Group g = getGroup(clientIds.get(j % CLIENTS));
+				Group g = getGroup(clientIds.get(j % CLIENTS), 123);
 				groups.add(g);
 				messageMeta.put(g.getId(), new ArrayList<>());
 				contactGroups.get(c).add(g);
@@ -584,7 +584,7 @@ public abstract class DatabasePerformanceTest extends BrambleTestCase {
 			}
 		}
 		for (int i = 0; i < LOCAL_GROUPS; i++) {
-			Group g = getGroup(clientIds.get(i % CLIENTS));
+			Group g = getGroup(clientIds.get(i % CLIENTS), 123);
 			groups.add(g);
 			messageMeta.put(g.getId(), new ArrayList<>());
 			groupMessages.put(g.getId(), new ArrayList<>());
diff --git a/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java b/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java
index 97268d16b3..71f7b29854 100644
--- a/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java
+++ b/bramble-core/src/test/java/org/briarproject/bramble/db/JdbcDatabaseTest.java
@@ -82,6 +82,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
 	private final File testDir = TestUtils.getTestDirectory();
 	private final GroupId groupId;
 	private final ClientId clientId;
+	private final int clientVersion;
 	private final Group group;
 	private final Author author;
 	private final LocalAuthor localAuthor;
@@ -96,7 +97,8 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
 
 	JdbcDatabaseTest() throws Exception {
 		clientId = getClientId();
-		group = getGroup(clientId);
+		clientVersion = 123;
+		group = getGroup(clientId, clientVersion);
 		groupId = group.getId();
 		author = getAuthor();
 		localAuthor = getLocalAuthor();
@@ -1460,7 +1462,7 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
 		db.addMessage(txn, message, PENDING, true, contactId);
 
 		// Add a second group
-		Group group1 = getGroup(clientId);
+		Group group1 = getGroup(clientId, 123);
 		GroupId groupId1 = group1.getId();
 		db.addGroup(txn, group1);
 
@@ -1828,6 +1830,22 @@ public abstract class JdbcDatabaseTest extends BrambleTestCase {
 		db.close();
 	}
 
+	@Test
+	public void testGetGroups() throws Exception {
+		Database<Connection> db = open(false);
+		Connection txn = db.startTransaction();
+
+		assertEquals(emptyList(), db.getGroups(txn, clientId, clientVersion));
+		db.addGroup(txn, group);
+		assertEquals(singletonList(group),
+				db.getGroups(txn, clientId, clientVersion));
+		db.removeGroup(txn, groupId);
+		assertEquals(emptyList(), db.getGroups(txn, clientId, clientVersion));
+
+		db.commitTransaction(txn);
+		db.close();
+	}
+
 	@Test
 	public void testExceptionHandling() throws Exception {
 		Database<Connection> db = open(false);
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 9702c2d511..1f690b14e5 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
@@ -51,7 +51,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
 			context.mock(ContactGroupFactory.class);
 	private final Clock clock = context.mock(Clock.class);
 
-	private final Group localGroup = getGroup(CLIENT_ID);
+	private final Group localGroup = getGroup(CLIENT_ID, CLIENT_VERSION);
 	private final LocalAuthor localAuthor = getLocalAuthor();
 	private final BdfDictionary fooPropertiesDict = BdfDictionary.of(
 			new BdfEntry("fooKey1", "fooValue1"),
@@ -90,8 +90,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
 		Contact contact1 = getContact(true);
 		Contact contact2 = getContact(true);
 		List<Contact> contacts = Arrays.asList(contact1, contact2);
-		Group contactGroup1 = getGroup(CLIENT_ID);
-		Group contactGroup2 = getGroup(CLIENT_ID);
+		Group contactGroup1 = getGroup(CLIENT_ID, CLIENT_VERSION);
+		Group contactGroup2 = getGroup(CLIENT_ID, CLIENT_VERSION);
 
 		context.checking(new Expectations() {{
 			oneOf(db).containsGroup(txn, localGroup.getId());
@@ -144,7 +144,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
 	public void testCreatesContactGroupWhenAddingContact() throws Exception {
 		Transaction txn = new Transaction(null, false);
 		Contact contact = getContact(true);
-		Group contactGroup = getGroup(CLIENT_ID);
+		Group contactGroup = getGroup(CLIENT_ID, CLIENT_VERSION);
 
 		context.checking(new Expectations() {{
 			// Create the group and share it with the contact
@@ -172,7 +172,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
 	public void testRemovesGroupWhenRemovingContact() throws Exception {
 		Transaction txn = new Transaction(null, false);
 		Contact contact = getContact(true);
-		Group contactGroup = getGroup(CLIENT_ID);
+		Group contactGroup = getGroup(CLIENT_ID, CLIENT_VERSION);
 
 		context.checking(new Expectations() {{
 			oneOf(contactGroupFactory).createContactGroup(CLIENT_ID,
@@ -307,7 +307,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
 	@Test
 	public void testStoresRemotePropertiesWithVersion0() throws Exception {
 		Contact contact = getContact(true);
-		Group contactGroup = getGroup(CLIENT_ID);
+		Group contactGroup = getGroup(CLIENT_ID, CLIENT_VERSION);
 		Transaction txn = new Transaction(null, false);
 		Map<TransportId, TransportProperties> properties =
 				new LinkedHashMap<>();
@@ -421,8 +421,8 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
 		Contact contact3 = getContact(true);
 		List<Contact> contacts =
 				Arrays.asList(contact1, contact2, contact3);
-		Group contactGroup2 = getGroup(CLIENT_ID);
-		Group contactGroup3 = getGroup(CLIENT_ID);
+		Group contactGroup2 = getGroup(CLIENT_ID, CLIENT_VERSION);
+		Group contactGroup3 = getGroup(CLIENT_ID, CLIENT_VERSION);
 		Map<MessageId, BdfDictionary> messageMetadata3 =
 				new LinkedHashMap<>();
 		// A remote update for another transport should be ignored
@@ -524,7 +524,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
 	public void testMergingNewPropertiesCreatesUpdate() throws Exception {
 		Transaction txn = new Transaction(null, false);
 		Contact contact = getContact(true);
-		Group contactGroup = getGroup(CLIENT_ID);
+		Group contactGroup = getGroup(CLIENT_ID, CLIENT_VERSION);
 
 		context.checking(new Expectations() {{
 			oneOf(db).startTransaction(false);
@@ -559,7 +559,7 @@ public class TransportPropertyManagerImplTest extends BrambleMockTestCase {
 	public void testMergingUpdatedPropertiesCreatesUpdate() throws Exception {
 		Transaction txn = new Transaction(null, false);
 		Contact contact = getContact(true);
-		Group contactGroup = getGroup(CLIENT_ID);
+		Group contactGroup = getGroup(CLIENT_ID, CLIENT_VERSION);
 		BdfDictionary oldMetadata = BdfDictionary.of(
 				new BdfEntry("transportId", "foo"),
 				new BdfEntry("version", 1),
diff --git a/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyValidatorTest.java b/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyValidatorTest.java
index cd8424897f..600fb2ef8e 100644
--- a/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyValidatorTest.java
+++ b/bramble-core/src/test/java/org/briarproject/bramble/properties/TransportPropertyValidatorTest.java
@@ -18,7 +18,8 @@ import org.junit.Test;
 import java.io.IOException;
 
 import static org.briarproject.bramble.api.plugin.TransportId.MAX_TRANSPORT_ID_LENGTH;
-import static org.briarproject.bramble.test.TestUtils.getClientId;
+import static org.briarproject.bramble.api.properties.TransportPropertyManager.CLIENT_ID;
+import static org.briarproject.bramble.api.properties.TransportPropertyManager.CLIENT_VERSION;
 import static org.briarproject.bramble.test.TestUtils.getGroup;
 import static org.briarproject.bramble.test.TestUtils.getMessage;
 import static org.briarproject.bramble.test.TestUtils.getTransportId;
@@ -42,7 +43,7 @@ public class TransportPropertyValidatorTest extends BrambleMockTestCase {
 		transportProperties = new TransportProperties();
 		transportProperties.put("foo", "bar");
 
-		group = getGroup(getClientId());
+		group = getGroup(CLIENT_ID, CLIENT_VERSION);
 		message = getMessage(group.getId());
 
 		MetadataEncoder metadataEncoder = context.mock(MetadataEncoder.class);
diff --git a/bramble-core/src/test/java/org/briarproject/bramble/sync/ValidationManagerImplTest.java b/bramble-core/src/test/java/org/briarproject/bramble/sync/ValidationManagerImplTest.java
index a3a23d4aef..c6be26f21e 100644
--- a/bramble-core/src/test/java/org/briarproject/bramble/sync/ValidationManagerImplTest.java
+++ b/bramble-core/src/test/java/org/briarproject/bramble/sync/ValidationManagerImplTest.java
@@ -56,7 +56,7 @@ public class ValidationManagerImplTest extends BrambleMockTestCase {
 	private final MessageId messageId = new MessageId(getRandomId());
 	private final MessageId messageId1 = new MessageId(getRandomId());
 	private final MessageId messageId2 = new MessageId(getRandomId());
-	private final Group group = getGroup(clientId);
+	private final Group group = getGroup(clientId, 123);
 	private final GroupId groupId = group.getId();
 	private final long timestamp = System.currentTimeMillis();
 	private final byte[] raw = new byte[123];
diff --git a/briar-core/src/main/java/org/briarproject/briar/blog/BlogManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/blog/BlogManagerImpl.java
index c7b119ef0c..dab2efccb1 100644
--- a/briar-core/src/main/java/org/briarproject/briar/blog/BlogManagerImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/blog/BlogManagerImpl.java
@@ -425,7 +425,7 @@ class BlogManagerImpl extends BdfIncomingMessageHook implements BlogManager,
 			Collection<Group> groups;
 			Transaction txn = db.startTransaction(true);
 			try {
-				groups = db.getGroups(txn, CLIENT_ID);
+				groups = db.getGroups(txn, CLIENT_ID, CLIENT_VERSION);
 				for (Group g : groups) {
 					blogs.add(blogFactory.parseBlog(g));
 				}
diff --git a/briar-core/src/main/java/org/briarproject/briar/forum/ForumManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/forum/ForumManagerImpl.java
index cdd2ba064b..edac994cda 100644
--- a/briar-core/src/main/java/org/briarproject/briar/forum/ForumManagerImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/forum/ForumManagerImpl.java
@@ -188,7 +188,7 @@ class ForumManagerImpl extends BdfIncomingMessageHook implements ForumManager {
 			Collection<Group> groups;
 			Transaction txn = db.startTransaction(true);
 			try {
-				groups = db.getGroups(txn, CLIENT_ID);
+				groups = db.getGroups(txn, CLIENT_ID, CLIENT_VERSION);
 				db.commitTransaction(txn);
 			} finally {
 				db.endTransaction(txn);
diff --git a/briar-core/src/main/java/org/briarproject/briar/privategroup/PrivateGroupManagerImpl.java b/briar-core/src/main/java/org/briarproject/briar/privategroup/PrivateGroupManagerImpl.java
index 20ea827a31..63b6807d17 100644
--- a/briar-core/src/main/java/org/briarproject/briar/privategroup/PrivateGroupManagerImpl.java
+++ b/briar-core/src/main/java/org/briarproject/briar/privategroup/PrivateGroupManagerImpl.java
@@ -271,7 +271,7 @@ class PrivateGroupManagerImpl extends BdfIncomingMessageHook
 		Collection<Group> groups;
 		Transaction txn = db.startTransaction(true);
 		try {
-			groups = db.getGroups(txn, CLIENT_ID);
+			groups = db.getGroups(txn, CLIENT_ID, CLIENT_VERSION);
 			db.commitTransaction(txn);
 		} finally {
 			db.endTransaction(txn);
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 3c02de9f46..a03c384094 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
@@ -122,7 +122,8 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
 			throw new AssertionError(e);
 		}
 		// If the contact belongs to any private groups, create a peer session
-		for (Group pg : db.getGroups(txn, PrivateGroupManager.CLIENT_ID)) {
+		for (Group pg : db.getGroups(txn, PrivateGroupManager.CLIENT_ID,
+				PrivateGroupManager.CLIENT_VERSION)) {
 			if (privateGroupManager.isMember(txn, pg.getId(), c.getAuthor()))
 				addingMember(txn, pg.getId(), c);
 		}
diff --git a/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerImplTest.java b/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerImplTest.java
index bbd905705a..3f636748a4 100644
--- a/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerImplTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/blog/BlogManagerImplTest.java
@@ -14,6 +14,7 @@ import org.briarproject.bramble.api.db.Transaction;
 import org.briarproject.bramble.api.identity.Author;
 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.Message;
 import org.briarproject.bramble.api.sync.MessageId;
 import org.briarproject.briar.api.blog.Blog;
@@ -49,6 +50,7 @@ import static org.briarproject.briar.api.blog.BlogConstants.KEY_TIME_RECEIVED;
 import static org.briarproject.briar.api.blog.BlogConstants.KEY_TYPE;
 import static org.briarproject.briar.api.blog.BlogConstants.MAX_BLOG_COMMENT_LENGTH;
 import static org.briarproject.briar.api.blog.BlogManager.CLIENT_ID;
+import static org.briarproject.briar.api.blog.BlogManager.CLIENT_VERSION;
 import static org.briarproject.briar.api.blog.MessageType.COMMENT;
 import static org.briarproject.briar.api.blog.MessageType.POST;
 import static org.briarproject.briar.api.blog.MessageType.WRAPPED_COMMENT;
@@ -866,7 +868,8 @@ public class BlogManagerImplTest extends BriarTestCase {
 	}
 
 	private Blog createBlog(LocalAuthor localAuthor, boolean rssFeed) {
-		return new Blog(getGroup(CLIENT_ID), localAuthor, rssFeed);
+		Group group = getGroup(CLIENT_ID, CLIENT_VERSION);
+		return new Blog(group, localAuthor, rssFeed);
 	}
 
 	private BdfList authorToBdfList(Author a) {
diff --git a/briar-core/src/test/java/org/briarproject/briar/blog/BlogPostValidatorTest.java b/briar-core/src/test/java/org/briarproject/briar/blog/BlogPostValidatorTest.java
index f2ca321d7f..77290aa7aa 100644
--- a/briar-core/src/test/java/org/briarproject/briar/blog/BlogPostValidatorTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/blog/BlogPostValidatorTest.java
@@ -64,7 +64,7 @@ public class BlogPostValidatorTest extends BriarTestCase {
 	private final String body = getRandomString(42);
 
 	public BlogPostValidatorTest() {
-		group = getGroup(CLIENT_ID);
+		group = getGroup(CLIENT_ID, CLIENT_VERSION);
 		descriptor = group.getDescriptor();
 		author = getAuthor();
 		authorList = BdfList.of(
diff --git a/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerImplTest.java b/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerImplTest.java
index 05a17fee5f..4074cebe61 100644
--- a/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerImplTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/feed/FeedManagerImplTest.java
@@ -61,9 +61,10 @@ public class FeedManagerImplTest extends BrambleMockTestCase {
 	private final Clock clock = context.mock(Clock.class);
 	private final Dns noDnsLookups = context.mock(Dns.class);
 
-	private final Group localGroup = getGroup(CLIENT_ID);
+	private final Group localGroup = getGroup(CLIENT_ID, CLIENT_VERSION);
 	private final GroupId localGroupId = localGroup.getId();
-	private final Group blogGroup = getGroup(BlogManager.CLIENT_ID);
+	private final Group blogGroup =
+			getGroup(BlogManager.CLIENT_ID, BlogManager.CLIENT_VERSION);
 	private final GroupId blogGroupId = blogGroup.getId();
 	private final LocalAuthor localAuthor = getLocalAuthor();
 	private final Blog blog = new Blog(blogGroup, localAuthor, true);
diff --git a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngineTest.java b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngineTest.java
index f7c630f655..3ae2fb61e4 100644
--- a/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngineTest.java
+++ b/briar-core/src/test/java/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngineTest.java
@@ -33,6 +33,7 @@ import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.GROU
 import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_INVITATION_MSG_LENGTH;
 import static org.briarproject.briar.api.privategroup.PrivateGroupConstants.MAX_GROUP_NAME_LENGTH;
 import static org.briarproject.briar.api.privategroup.PrivateGroupManager.CLIENT_ID;
+import static org.briarproject.briar.api.privategroup.PrivateGroupManager.CLIENT_VERSION;
 import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.GROUP_KEY_CONTACT_ID;
 import static org.briarproject.briar.privategroup.invitation.MessageType.ABORT;
 import static org.briarproject.briar.privategroup.invitation.MessageType.INVITE;
@@ -64,7 +65,8 @@ public abstract class AbstractProtocolEngineTest extends BrambleMockTestCase {
 
 	protected final Transaction txn = new Transaction(null, false);
 	protected final GroupId contactGroupId = new GroupId(getRandomId());
-	protected final Group privateGroupGroup = getGroup(CLIENT_ID);
+	protected final Group privateGroupGroup =
+			getGroup(CLIENT_ID, CLIENT_VERSION);
 	protected final GroupId privateGroupId = privateGroupGroup.getId();
 	protected final Author author = getAuthor();
 	protected final PrivateGroup privateGroup =
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 c225d056dc..543af95b11 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
@@ -99,9 +99,9 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 	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 Group localGroup = getGroup(CLIENT_ID, CLIENT_VERSION);
+	private final Group contactGroup = getGroup(CLIENT_ID, CLIENT_VERSION);
+	private final Group privateGroup = getGroup(CLIENT_ID, CLIENT_VERSION);
 	private final BdfDictionary meta = BdfDictionary.of(new BdfEntry("m", "e"));
 	private final Message message =
 			new Message(new MessageId(getRandomId()), contactGroup.getId(),
@@ -194,7 +194,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 					SHARED);
 			oneOf(clientHelper)
 					.mergeGroupMetadata(txn, contactGroup.getId(), meta);
-			oneOf(db).getGroups(txn, PrivateGroupManager.CLIENT_ID);
+			oneOf(db).getGroups(txn, PrivateGroupManager.CLIENT_ID,
+					PrivateGroupManager.CLIENT_VERSION);
 			will(returnValue(Collections.singletonList(privateGroup)));
 			oneOf(privateGroupManager)
 					.isMember(txn, privateGroup.getId(), c.getAuthor());
@@ -854,8 +855,8 @@ public class GroupInvitationManagerImplTest extends BrambleMockTestCase {
 		Collection<Contact> contacts =
 				Arrays.asList(contact, contact2, contact3);
 
-		Group contactGroup2 = getGroup(CLIENT_ID);
-		Group contactGroup3 = getGroup(CLIENT_ID);
+		Group contactGroup2 = getGroup(CLIENT_ID, CLIENT_VERSION);
+		Group contactGroup3 = getGroup(CLIENT_ID, CLIENT_VERSION);
 
 		MessageId storageId2 = new MessageId(getRandomId());
 		MessageId storageId3 = new MessageId(getRandomId());
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 46a9cb5e96..db3b6af2cc 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
@@ -65,11 +65,13 @@ public class BlogSharingManagerImplTest extends BrambleMockTestCase {
 			new Contact(contactId, author, localAuthor.getId(), true, true);
 	private final Collection<Contact> contacts =
 			Collections.singletonList(contact);
-	private final Group localGroup = getGroup(CLIENT_ID);
-	private final Group contactGroup = getGroup(CLIENT_ID);
-	private final Group blogGroup = getGroup(BlogManager.CLIENT_ID);
+	private final Group localGroup = getGroup(CLIENT_ID, CLIENT_VERSION);
+	private final Group contactGroup = getGroup(CLIENT_ID, CLIENT_VERSION);
+	private final Group blogGroup =
+			getGroup(BlogManager.CLIENT_ID, BlogManager.CLIENT_VERSION);
 	private final Blog blog = new Blog(blogGroup, author, false);
-	private final Group localBlogGroup = getGroup(BlogManager.CLIENT_ID);
+	private final Group localBlogGroup =
+			getGroup(BlogManager.CLIENT_ID, BlogManager.CLIENT_VERSION);
 	private final Blog localBlog = new Blog(localBlogGroup, localAuthor, false);
 	@SuppressWarnings("unchecked")
 	private final ProtocolEngine<Blog> engine =
@@ -225,7 +227,7 @@ public class BlogSharingManagerImplTest extends BrambleMockTestCase {
 	private void expectPreShareShareable(Transaction txn, Contact contact,
 			Blog blog, Map<MessageId, BdfDictionary> sessions)
 			throws Exception {
-		Group contactGroup = getGroup(CLIENT_ID);
+		Group contactGroup = getGroup(CLIENT_ID, CLIENT_VERSION);
 		BdfDictionary sessionDict = new BdfDictionary();
 		Message message = new Message(new MessageId(getRandomId()),
 				contactGroup.getId(), 42L, getRandomBytes(1337));
-- 
GitLab