mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-26 03:40:56 +01:00
Update the storage service.
This commit is contained in:
@@ -12,6 +12,8 @@ import org.thoughtcrime.securesms.contacts.sync.StorageSyncHelper.MergeResult;
|
||||
import org.thoughtcrime.securesms.util.Conversions;
|
||||
import org.whispersystems.signalservice.api.push.SignalServiceAddress;
|
||||
import org.whispersystems.signalservice.api.storage.SignalContactRecord;
|
||||
import org.whispersystems.signalservice.api.storage.SignalGroupV1Record;
|
||||
import org.whispersystems.signalservice.api.storage.SignalRecord;
|
||||
import org.whispersystems.signalservice.api.storage.SignalStorageRecord;
|
||||
import org.whispersystems.signalservice.api.util.UuidUtil;
|
||||
|
||||
@@ -78,12 +80,12 @@ public final class StorageSyncHelperTest {
|
||||
|
||||
assertEquals(setOf(remote1), result.getLocalContactInserts());
|
||||
assertTrue(result.getLocalContactUpdates().isEmpty());
|
||||
assertEquals(setOf(local1), result.getRemoteContactInserts());
|
||||
assertTrue(result.getRemoteContactUpdates().isEmpty());
|
||||
assertEquals(setOf(SignalStorageRecord.forContact(local1)), result.getRemoteInserts());
|
||||
assertTrue(result.getRemoteUpdates().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveConflict_sameAsRemote() {
|
||||
public void resolveConflict_contact_sameAsRemote() {
|
||||
SignalContactRecord remote1 = contact(1, UUID_A, E164_A, "a");
|
||||
SignalContactRecord local1 = contact(2, UUID_A, E164_A, "a");
|
||||
|
||||
@@ -93,12 +95,27 @@ public final class StorageSyncHelperTest {
|
||||
|
||||
assertTrue(result.getLocalContactInserts().isEmpty());
|
||||
assertEquals(setOf(contactUpdate(local1, expectedMerge)), result.getLocalContactUpdates());
|
||||
assertTrue(result.getRemoteContactInserts().isEmpty());
|
||||
assertTrue(result.getRemoteContactUpdates().isEmpty());
|
||||
assertTrue(result.getRemoteInserts().isEmpty());
|
||||
assertTrue(result.getRemoteUpdates().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveConflict_sameAsLocal() {
|
||||
public void resolveConflict_group_sameAsRemote() {
|
||||
SignalGroupV1Record remote1 = groupV1(1, 1, true, false);
|
||||
SignalGroupV1Record local1 = groupV1(2, 1, true, false);
|
||||
|
||||
MergeResult result = StorageSyncHelper.resolveConflict(recordSetOf(remote1), recordSetOf(local1));
|
||||
|
||||
SignalGroupV1Record expectedMerge = groupV1(1, 1, true, false);
|
||||
|
||||
assertTrue(result.getLocalContactInserts().isEmpty());
|
||||
assertEquals(setOf(groupV1Update(local1, expectedMerge)), result.getLocalGroupV1Updates());
|
||||
assertTrue(result.getRemoteInserts().isEmpty());
|
||||
assertTrue(result.getRemoteUpdates().isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveConflict_contact_sameAsLocal() {
|
||||
SignalContactRecord remote1 = contact(1, UUID_A, E164_A, null);
|
||||
SignalContactRecord local1 = contact(2, UUID_A, E164_A, "a");
|
||||
|
||||
@@ -108,8 +125,23 @@ public final class StorageSyncHelperTest {
|
||||
|
||||
assertTrue(result.getLocalContactInserts().isEmpty());
|
||||
assertTrue(result.getLocalContactUpdates().isEmpty());
|
||||
assertTrue(result.getRemoteContactInserts().isEmpty());
|
||||
assertEquals(setOf(contactUpdate(remote1, expectedMerge)), result.getRemoteContactUpdates());
|
||||
assertTrue(result.getRemoteInserts().isEmpty());
|
||||
assertEquals(setOf(recordUpdate(remote1, expectedMerge)), result.getRemoteUpdates());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void resolveConflict_group_sameAsLocal() {
|
||||
SignalGroupV1Record remote1 = groupV1(1, 1, true, false);
|
||||
SignalGroupV1Record local1 = groupV1(2, 1, true, true);
|
||||
|
||||
MergeResult result = StorageSyncHelper.resolveConflict(recordSetOf(remote1), recordSetOf(local1));
|
||||
|
||||
SignalGroupV1Record expectedMerge = groupV1(2, 1, true, true);
|
||||
|
||||
assertTrue(result.getLocalContactInserts().isEmpty());
|
||||
assertTrue(result.getLocalGroupV1Updates().isEmpty());
|
||||
assertTrue(result.getRemoteInserts().isEmpty());
|
||||
assertEquals(setOf(recordUpdate(remote1, expectedMerge)), result.getRemoteUpdates());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -138,26 +170,28 @@ public final class StorageSyncHelperTest {
|
||||
SignalContactRecord remote3 = contact(5, UUID_C, E164_C, "c");
|
||||
SignalContactRecord local3 = contact(6, UUID_D, E164_D, "d");
|
||||
|
||||
SignalStorageRecord unknownRemote = unknown(7);
|
||||
SignalStorageRecord unknownLocal = unknown(8);
|
||||
SignalGroupV1Record remote4 = groupV1(7, 1, true, false);
|
||||
SignalGroupV1Record local4 = groupV1(8, 1, false, true);
|
||||
|
||||
StorageSyncHelper.setTestKeyGenerator(new TestGenerator(999));
|
||||
SignalStorageRecord unknownRemote = unknown(9);
|
||||
SignalStorageRecord unknownLocal = unknown(10);
|
||||
|
||||
Set<SignalStorageRecord> remoteOnly = recordSetOf(remote1, remote2, remote3);
|
||||
Set<SignalStorageRecord> localOnly = recordSetOf(local1, local2, local3);
|
||||
StorageSyncHelper.setTestKeyGenerator(new TestGenerator(111, 222));
|
||||
|
||||
remoteOnly.add(unknownRemote);
|
||||
localOnly.add(unknownLocal);
|
||||
Set<SignalStorageRecord> remoteOnly = recordSetOf(remote1, remote2, remote3, remote4, unknownRemote);
|
||||
Set<SignalStorageRecord> localOnly = recordSetOf(local1, local2, local3, local4, unknownLocal);
|
||||
|
||||
MergeResult result = StorageSyncHelper.resolveConflict(remoteOnly, localOnly);
|
||||
|
||||
SignalContactRecord merge1 = contact(2, UUID_A, E164_A, "a");
|
||||
SignalContactRecord merge2 = contact(999, UUID_B, E164_B, "b");
|
||||
SignalContactRecord merge2 = contact(111, UUID_B, E164_B, "b");
|
||||
SignalGroupV1Record merge4 = groupV1(222, 1, true, true);
|
||||
|
||||
assertEquals(setOf(remote3), result.getLocalContactInserts());
|
||||
assertEquals(setOf(contactUpdate(local2, merge2)), result.getLocalContactUpdates());
|
||||
assertEquals(setOf(local3), result.getRemoteContactInserts());
|
||||
assertEquals(setOf(contactUpdate(remote1, merge1), contactUpdate(remote2, merge2)), result.getRemoteContactUpdates());
|
||||
assertEquals(setOf(groupV1Update(local4, merge4)), result.getLocalGroupV1Updates());
|
||||
assertEquals(setOf(SignalStorageRecord.forContact(local3)), result.getRemoteInserts());
|
||||
assertEquals(setOf(recordUpdate(remote1, merge1), recordUpdate(remote2, merge2), recordUpdate(remote4, merge4)), result.getRemoteUpdates());
|
||||
assertEquals(setOf(unknownRemote), result.getLocalUnknownInserts());
|
||||
assertEquals(setOf(unknownLocal), result.getLocalUnknownDeletes());
|
||||
}
|
||||
@@ -169,7 +203,8 @@ public final class StorageSyncHelperTest {
|
||||
.setIdentityKey(byteArray(2))
|
||||
.setIdentityState(SignalContactRecord.IdentityState.VERIFIED)
|
||||
.setProfileKey(byteArray(3))
|
||||
.setProfileName("profile name A")
|
||||
.setGivenName("AFirst")
|
||||
.setFamilyName("ALast")
|
||||
.setUsername("username A")
|
||||
.setNickname("nickname A")
|
||||
.setProfileSharingEnabled(true)
|
||||
@@ -179,7 +214,8 @@ public final class StorageSyncHelperTest {
|
||||
.setIdentityKey(byteArray(99))
|
||||
.setIdentityState(SignalContactRecord.IdentityState.DEFAULT)
|
||||
.setProfileKey(byteArray(999))
|
||||
.setProfileName("profile name B")
|
||||
.setGivenName("BFirst")
|
||||
.setFamilyName("BLast")
|
||||
.setUsername("username B")
|
||||
.setNickname("nickname B")
|
||||
.setProfileSharingEnabled(false)
|
||||
@@ -192,7 +228,8 @@ public final class StorageSyncHelperTest {
|
||||
assertArrayEquals(byteArray(2), merged.getIdentityKey().get());
|
||||
assertEquals(SignalContactRecord.IdentityState.VERIFIED, merged.getIdentityState());
|
||||
assertArrayEquals(byteArray(3), merged.getProfileKey().get());
|
||||
assertEquals("profile name A", merged.getProfileName().get());
|
||||
assertEquals("AFirst", merged.getGivenName().get());
|
||||
assertEquals("ALast", merged.getFamilyName().get());
|
||||
assertEquals("username A", merged.getUsername().get());
|
||||
assertEquals("nickname B", merged.getNickname().get());
|
||||
assertTrue(merged.isProfileSharingEnabled());
|
||||
@@ -202,14 +239,16 @@ public final class StorageSyncHelperTest {
|
||||
public void mergeContacts_fillInGaps() {
|
||||
SignalContactRecord remote = new SignalContactRecord.Builder(byteArray(1), new SignalServiceAddress(UUID_A, null))
|
||||
.setBlocked(true)
|
||||
.setProfileName("profile name A")
|
||||
.setGivenName("AFirst")
|
||||
.setFamilyName("")
|
||||
.setProfileSharingEnabled(true)
|
||||
.build();
|
||||
SignalContactRecord local = new SignalContactRecord.Builder(byteArray(2), new SignalServiceAddress(UUID_B, E164_B))
|
||||
.setBlocked(false)
|
||||
.setIdentityKey(byteArray(2))
|
||||
.setProfileKey(byteArray(3))
|
||||
.setProfileName("profile name B")
|
||||
.setGivenName("BFirst")
|
||||
.setFamilyName("BLast")
|
||||
.setUsername("username B")
|
||||
.setProfileSharingEnabled(false)
|
||||
.build();
|
||||
@@ -221,41 +260,47 @@ public final class StorageSyncHelperTest {
|
||||
assertArrayEquals(byteArray(2), merged.getIdentityKey().get());
|
||||
assertEquals(SignalContactRecord.IdentityState.DEFAULT, merged.getIdentityState());
|
||||
assertArrayEquals(byteArray(3), merged.getProfileKey().get());
|
||||
assertEquals("profile name A", merged.getProfileName().get());
|
||||
assertEquals("AFirst", merged.getGivenName().get());
|
||||
assertEquals("", merged.getFamilyName().get());
|
||||
assertEquals("username B", merged.getUsername().get());
|
||||
assertTrue(merged.isProfileSharingEnabled());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createWriteOperation_generic() {
|
||||
List<byte[]> localKeys = byteListOf(1, 2, 3, 4);
|
||||
List<byte[]> localKeys = byteListOf(1, 2, 3, 4, 100);
|
||||
SignalContactRecord insert1 = contact(6, UUID_A, E164_A, "a" );
|
||||
SignalContactRecord old1 = contact(1, UUID_B, E164_B, "b" );
|
||||
SignalContactRecord new1 = contact(5, UUID_B, E164_B, "z" );
|
||||
SignalContactRecord insert2 = contact(7, UUID_C, E164_C, "c" );
|
||||
SignalContactRecord old2 = contact(2, UUID_D, E164_D, "d" );
|
||||
SignalContactRecord new2 = contact(8, UUID_D, E164_D, "z2");
|
||||
SignalStorageRecord unknownInsert = unknown(9);
|
||||
SignalStorageRecord unknownDelete = unknown(10);
|
||||
SignalGroupV1Record insert3 = groupV1(9, 1, true, true);
|
||||
SignalGroupV1Record old3 = groupV1(100, 1, true, true);
|
||||
SignalGroupV1Record new3 = groupV1(10, 1, false, true);
|
||||
SignalStorageRecord unknownInsert = unknown(11);
|
||||
SignalStorageRecord unknownDelete = unknown(12);
|
||||
|
||||
StorageSyncHelper.WriteOperationResult result = StorageSyncHelper.createWriteOperation(1,
|
||||
localKeys,
|
||||
new MergeResult(setOf(insert2),
|
||||
setOf(contactUpdate(old2, new2)),
|
||||
setOf(insert1),
|
||||
setOf(contactUpdate(old1, new1)),
|
||||
setOf(insert3),
|
||||
setOf(groupV1Update(old3, new3)),
|
||||
setOf(unknownInsert),
|
||||
setOf(unknownDelete)));
|
||||
setOf(unknownDelete),
|
||||
recordSetOf(insert1, insert3),
|
||||
setOf(recordUpdate(old1, new1), recordUpdate(old3, new3))));
|
||||
|
||||
assertEquals(2, result.getManifest().getVersion());
|
||||
assertByteListEquals(byteListOf(3, 4, 5, 6, 7, 8, 9), result.getManifest().getStorageKeys());
|
||||
assertTrue(recordSetOf(insert1, new1).containsAll(result.getInserts()));
|
||||
assertEquals(2, result.getInserts().size());
|
||||
assertByteListEquals(byteListOf(1), result.getDeletes());
|
||||
assertByteListEquals(byteListOf(3, 4, 5, 6, 7, 8, 9, 10, 11), result.getManifest().getStorageKeys());
|
||||
assertTrue(recordSetOf(insert1, new1, insert3, new3).containsAll(result.getInserts()));
|
||||
assertEquals(4, result.getInserts().size());
|
||||
assertByteListEquals(byteListOf(1, 100), result.getDeletes());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void contacts_with_same_profile_key_contents_are_equal() {
|
||||
public void ContactUpdate_equals_sameProfileKeys() {
|
||||
byte[] profileKey = new byte[32];
|
||||
byte[] profileKeyCopy = profileKey.clone();
|
||||
|
||||
@@ -269,7 +314,7 @@ public final class StorageSyncHelperTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
public void contacts_with_different_profile_key_contents_are_not_equal() {
|
||||
public void ContactUpdate_equals_differentProfileKeys() {
|
||||
byte[] profileKey = new byte[32];
|
||||
byte[] profileKeyCopy = profileKey.clone();
|
||||
profileKeyCopy[0] = 1;
|
||||
@@ -283,41 +328,33 @@ public final class StorageSyncHelperTest {
|
||||
assertTrue(contactUpdate(a, b).profileKeyChanged());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void contacts_with_same_identity_key_contents_are_equal() {
|
||||
byte[] profileKey = new byte[32];
|
||||
byte[] profileKeyCopy = profileKey.clone();
|
||||
|
||||
SignalContactRecord a = contactBuilder(1, UUID_A, E164_A, "a").setIdentityKey(profileKey).build();
|
||||
SignalContactRecord b = contactBuilder(1, UUID_A, E164_A, "a").setIdentityKey(profileKeyCopy).build();
|
||||
|
||||
assertEquals(a, b);
|
||||
assertEquals(a.hashCode(), b.hashCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void contacts_with_different_identity_key_contents_are_not_equal() {
|
||||
byte[] profileKey = new byte[32];
|
||||
byte[] profileKeyCopy = profileKey.clone();
|
||||
profileKeyCopy[0] = 1;
|
||||
|
||||
SignalContactRecord a = contactBuilder(1, UUID_A, E164_A, "a").setIdentityKey(profileKey).build();
|
||||
SignalContactRecord b = contactBuilder(1, UUID_A, E164_A, "a").setIdentityKey(profileKeyCopy).build();
|
||||
|
||||
assertNotEquals(a, b);
|
||||
assertNotEquals(a.hashCode(), b.hashCode());
|
||||
}
|
||||
|
||||
@SafeVarargs
|
||||
private static <E> Set<E> setOf(E... values) {
|
||||
return Sets.newHashSet(values);
|
||||
}
|
||||
|
||||
private static Set<SignalStorageRecord> recordSetOf(SignalContactRecord... contactRecords) {
|
||||
private static Set<SignalStorageRecord> recordSetOf(SignalRecord... records) {
|
||||
LinkedHashSet<SignalStorageRecord> storageRecords = new LinkedHashSet<>();
|
||||
|
||||
for (SignalContactRecord contactRecord : contactRecords) {
|
||||
storageRecords.add(SignalStorageRecord.forContact(contactRecord.getKey(), contactRecord));
|
||||
for (SignalRecord record : records) {
|
||||
if (record instanceof SignalContactRecord) {
|
||||
storageRecords.add(SignalStorageRecord.forContact(record.getKey(), (SignalContactRecord) record));
|
||||
} else if (record instanceof SignalGroupV1Record) {
|
||||
storageRecords.add(SignalStorageRecord.forGroupV1(record.getKey(), (SignalGroupV1Record) record));
|
||||
} else {
|
||||
storageRecords.add(SignalStorageRecord.forUnknown(record.getKey(), UNKNOWN_TYPE));
|
||||
}
|
||||
}
|
||||
|
||||
return storageRecords;
|
||||
}
|
||||
|
||||
private static Set<SignalStorageRecord> recordSetOf(SignalGroupV1Record... groupRecords) {
|
||||
LinkedHashSet<SignalStorageRecord> storageRecords = new LinkedHashSet<>();
|
||||
|
||||
for (SignalGroupV1Record contactRecord : groupRecords) {
|
||||
storageRecords.add(SignalStorageRecord.forGroupV1(contactRecord.getKey(), contactRecord));
|
||||
}
|
||||
|
||||
return storageRecords;
|
||||
@@ -329,7 +366,7 @@ public final class StorageSyncHelperTest {
|
||||
String profileName)
|
||||
{
|
||||
return new SignalContactRecord.Builder(byteArray(key), new SignalServiceAddress(uuid, e164))
|
||||
.setProfileName(profileName);
|
||||
.setGivenName(profileName);
|
||||
}
|
||||
|
||||
private static SignalContactRecord contact(int key,
|
||||
@@ -340,10 +377,30 @@ public final class StorageSyncHelperTest {
|
||||
return contactBuilder(key, uuid, e164, profileName).build();
|
||||
}
|
||||
|
||||
private static SignalGroupV1Record groupV1(int key,
|
||||
int groupId,
|
||||
boolean blocked,
|
||||
boolean profileSharing)
|
||||
{
|
||||
return new SignalGroupV1Record.Builder(byteArray(key), byteArray(groupId)).setBlocked(blocked).setProfileSharingEnabled(profileSharing).build();
|
||||
}
|
||||
|
||||
private static StorageSyncHelper.ContactUpdate contactUpdate(SignalContactRecord oldContact, SignalContactRecord newContact) {
|
||||
return new StorageSyncHelper.ContactUpdate(oldContact, newContact);
|
||||
}
|
||||
|
||||
private static StorageSyncHelper.GroupV1Update groupV1Update(SignalGroupV1Record oldGroup, SignalGroupV1Record newGroup) {
|
||||
return new StorageSyncHelper.GroupV1Update(oldGroup, newGroup);
|
||||
}
|
||||
|
||||
private static StorageSyncHelper.RecordUpdate recordUpdate(SignalContactRecord oldContact, SignalContactRecord newContact) {
|
||||
return new StorageSyncHelper.RecordUpdate(SignalStorageRecord.forContact(oldContact), SignalStorageRecord.forContact(newContact));
|
||||
}
|
||||
|
||||
private static StorageSyncHelper.RecordUpdate recordUpdate(SignalGroupV1Record oldGroup, SignalGroupV1Record newGroup) {
|
||||
return new StorageSyncHelper.RecordUpdate(SignalStorageRecord.forGroupV1(oldGroup), SignalStorageRecord.forGroupV1(newGroup));
|
||||
}
|
||||
|
||||
private static SignalStorageRecord unknown(int key) {
|
||||
return SignalStorageRecord.forUnknown(byteArray(key), UNKNOWN_TYPE);
|
||||
}
|
||||
@@ -372,15 +429,17 @@ public final class StorageSyncHelperTest {
|
||||
}
|
||||
|
||||
private static class TestGenerator implements StorageSyncHelper.KeyGenerator {
|
||||
private final byte[] key;
|
||||
private final int[] keys;
|
||||
|
||||
private TestGenerator(int key) {
|
||||
this.key = byteArray(key);
|
||||
private int index = 0;
|
||||
|
||||
private TestGenerator(int... keys) {
|
||||
this.keys = keys;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull byte[] generate() {
|
||||
return key;
|
||||
return byteArray(keys[index++]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user