513 lines
33 KiB
Java
513 lines
33 KiB
Java
package org.thoughtcrime.securesms.groups.v2.processing;
|
|
|
|
import org.junit.Before;
|
|
import org.junit.Test;
|
|
import org.signal.storageservice.protos.groups.local.DecryptedGroup;
|
|
import org.signal.storageservice.protos.groups.local.DecryptedGroupChange;
|
|
import org.signal.storageservice.protos.groups.local.DecryptedMember;
|
|
import org.signal.storageservice.protos.groups.local.DecryptedString;
|
|
import org.thoughtcrime.securesms.logging.Log;
|
|
import org.thoughtcrime.securesms.testutil.LogRecorder;
|
|
import org.whispersystems.signalservice.api.util.UuidUtil;
|
|
|
|
import java.util.UUID;
|
|
|
|
import static java.util.Arrays.asList;
|
|
import static java.util.Collections.emptyList;
|
|
import static java.util.Collections.singletonList;
|
|
import static org.hamcrest.CoreMatchers.is;
|
|
import static org.junit.Assert.assertEquals;
|
|
import static org.junit.Assert.assertNotNull;
|
|
import static org.junit.Assert.assertNull;
|
|
import static org.junit.Assert.assertSame;
|
|
import static org.junit.Assert.assertThat;
|
|
import static org.junit.Assert.assertTrue;
|
|
import static org.thoughtcrime.securesms.groups.v2.processing.GroupStateMapper.LATEST;
|
|
|
|
public final class GroupStateMapperTest {
|
|
|
|
private static final UUID KNOWN_EDITOR = UUID.randomUUID();
|
|
|
|
@Before
|
|
public void setup() {
|
|
Log.initialize(new LogRecorder());
|
|
}
|
|
|
|
@Test
|
|
public void unknown_group_with_no_states_to_update() {
|
|
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(null, emptyList()), 10);
|
|
|
|
assertThat(advanceGroupStateResult.getProcessedLogEntries(), is(emptyList()));
|
|
assertTrue(advanceGroupStateResult.getNewGlobalGroupState().getServerHistory().isEmpty());
|
|
assertNull(advanceGroupStateResult.getNewGlobalGroupState().getLocalState());
|
|
}
|
|
|
|
@Test
|
|
public void known_group_with_no_states_to_update() {
|
|
DecryptedGroup currentState = state(0);
|
|
|
|
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(currentState, emptyList()), 10);
|
|
|
|
assertThat(advanceGroupStateResult.getProcessedLogEntries(), is(emptyList()));
|
|
assertTrue(advanceGroupStateResult.getNewGlobalGroupState().getServerHistory().isEmpty());
|
|
assertSame(currentState, advanceGroupStateResult.getNewGlobalGroupState().getLocalState());
|
|
}
|
|
|
|
@Test
|
|
public void unknown_group_single_state_to_update() {
|
|
ServerGroupLogEntry log0 = serverLogEntry(0);
|
|
|
|
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(null, singletonList(log0)), 10);
|
|
|
|
assertThat(advanceGroupStateResult.getProcessedLogEntries(), is(singletonList(asLocal(log0))));
|
|
assertTrue(advanceGroupStateResult.getNewGlobalGroupState().getServerHistory().isEmpty());
|
|
assertEquals(log0.getGroup(), advanceGroupStateResult.getNewGlobalGroupState().getLocalState());
|
|
}
|
|
|
|
@Test
|
|
public void known_group_single_state_to_update() {
|
|
DecryptedGroup currentState = state(0);
|
|
ServerGroupLogEntry log1 = serverLogEntry(1);
|
|
|
|
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(currentState, singletonList(log1)), 1);
|
|
|
|
assertThat(advanceGroupStateResult.getProcessedLogEntries(), is(singletonList(asLocal(log1))));
|
|
assertTrue(advanceGroupStateResult.getNewGlobalGroupState().getServerHistory().isEmpty());
|
|
assertEquals(log1.getGroup(), advanceGroupStateResult.getNewGlobalGroupState().getLocalState());
|
|
}
|
|
|
|
@Test
|
|
public void known_group_two_states_to_update() {
|
|
DecryptedGroup currentState = state(0);
|
|
ServerGroupLogEntry log1 = serverLogEntry(1);
|
|
ServerGroupLogEntry log2 = serverLogEntry(2);
|
|
|
|
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(currentState, asList(log1, log2)), 2);
|
|
|
|
assertThat(advanceGroupStateResult.getProcessedLogEntries(), is(asList(asLocal(log1), asLocal(log2))));
|
|
assertTrue(advanceGroupStateResult.getNewGlobalGroupState().getServerHistory().isEmpty());
|
|
assertEquals(log2.getGroup(), advanceGroupStateResult.getNewGlobalGroupState().getLocalState());
|
|
}
|
|
|
|
@Test
|
|
public void known_group_two_states_to_update_already_on_one() {
|
|
DecryptedGroup currentState = state(1);
|
|
ServerGroupLogEntry log1 = serverLogEntry(1);
|
|
ServerGroupLogEntry log2 = serverLogEntry(2);
|
|
|
|
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(currentState, asList(log1, log2)), 2);
|
|
|
|
assertThat(advanceGroupStateResult.getProcessedLogEntries(), is(singletonList(asLocal(log2))));
|
|
assertTrue(advanceGroupStateResult.getNewGlobalGroupState().getServerHistory().isEmpty());
|
|
assertEquals(log2.getGroup(), advanceGroupStateResult.getNewGlobalGroupState().getLocalState());
|
|
}
|
|
|
|
@Test
|
|
public void known_group_three_states_to_update_stop_at_2() {
|
|
DecryptedGroup currentState = state(0);
|
|
ServerGroupLogEntry log1 = serverLogEntry(1);
|
|
ServerGroupLogEntry log2 = serverLogEntry(2);
|
|
ServerGroupLogEntry log3 = serverLogEntry(3);
|
|
|
|
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(currentState, asList(log1, log2, log3)), 2);
|
|
|
|
assertThat(advanceGroupStateResult.getProcessedLogEntries(), is(asList(asLocal(log1), asLocal(log2))));
|
|
assertNewState(new GlobalGroupState(log2.getGroup(), singletonList(log3)), advanceGroupStateResult.getNewGlobalGroupState());
|
|
assertEquals(log2.getGroup(), advanceGroupStateResult.getNewGlobalGroupState().getLocalState());
|
|
}
|
|
|
|
@Test
|
|
public void known_group_three_states_to_update_update_latest() {
|
|
DecryptedGroup currentState = state(0);
|
|
ServerGroupLogEntry log1 = serverLogEntry(1);
|
|
ServerGroupLogEntry log2 = serverLogEntry(2);
|
|
ServerGroupLogEntry log3 = serverLogEntry(3);
|
|
|
|
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(currentState, asList(log1, log2, log3)), LATEST);
|
|
|
|
assertThat(advanceGroupStateResult.getProcessedLogEntries(), is(asList(asLocal(log1), asLocal(log2), asLocal(log3))));
|
|
assertNewState(new GlobalGroupState(log3.getGroup(), emptyList()), advanceGroupStateResult.getNewGlobalGroupState());
|
|
assertEquals(log3.getGroup(), advanceGroupStateResult.getNewGlobalGroupState().getLocalState());
|
|
}
|
|
|
|
@Test
|
|
public void apply_maximum_group_revisions() {
|
|
DecryptedGroup currentState = state(Integer.MAX_VALUE - 2);
|
|
ServerGroupLogEntry log1 = serverLogEntry(Integer.MAX_VALUE - 1);
|
|
ServerGroupLogEntry log2 = serverLogEntry(Integer.MAX_VALUE);
|
|
|
|
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(currentState, asList(log1, log2)), LATEST);
|
|
|
|
assertThat(advanceGroupStateResult.getProcessedLogEntries(), is(asList(asLocal(log1), asLocal(log2))));
|
|
assertNewState(new GlobalGroupState(log2.getGroup(), emptyList()), advanceGroupStateResult.getNewGlobalGroupState());
|
|
assertEquals(log2.getGroup(), advanceGroupStateResult.getNewGlobalGroupState().getLocalState());
|
|
}
|
|
|
|
@Test
|
|
public void unknown_group_single_state_to_update_with_missing_change() {
|
|
ServerGroupLogEntry log0 = serverLogEntryWholeStateOnly(0);
|
|
|
|
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(null, singletonList(log0)), 10);
|
|
|
|
assertThat(advanceGroupStateResult.getProcessedLogEntries(), is(singletonList(asLocal(log0))));
|
|
assertTrue(advanceGroupStateResult.getNewGlobalGroupState().getServerHistory().isEmpty());
|
|
assertEquals(log0.getGroup(), advanceGroupStateResult.getNewGlobalGroupState().getLocalState());
|
|
}
|
|
|
|
@Test
|
|
public void known_group_single_state_to_update_with_missing_change() {
|
|
DecryptedGroup currentState = state(0);
|
|
ServerGroupLogEntry log1 = serverLogEntryWholeStateOnly(1);
|
|
|
|
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(currentState, singletonList(log1)), 1);
|
|
|
|
assertThat(advanceGroupStateResult.getProcessedLogEntries(), is(singletonList(localLogEntryNoEditor(1))));
|
|
assertTrue(advanceGroupStateResult.getNewGlobalGroupState().getServerHistory().isEmpty());
|
|
assertEquals(log1.getGroup(), advanceGroupStateResult.getNewGlobalGroupState().getLocalState());
|
|
}
|
|
|
|
@Test
|
|
public void known_group_three_states_to_update_update_latest_handle_missing_change() {
|
|
DecryptedGroup currentState = state(0);
|
|
ServerGroupLogEntry log1 = serverLogEntry(1);
|
|
ServerGroupLogEntry log2 = serverLogEntryWholeStateOnly(2);
|
|
ServerGroupLogEntry log3 = serverLogEntry(3);
|
|
|
|
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(currentState, asList(log1, log2, log3)), LATEST);
|
|
|
|
assertThat(advanceGroupStateResult.getProcessedLogEntries(), is(asList(asLocal(log1), localLogEntryNoEditor(2), asLocal(log3))));
|
|
assertNewState(new GlobalGroupState(log3.getGroup(), emptyList()), advanceGroupStateResult.getNewGlobalGroupState());
|
|
assertEquals(log3.getGroup(), advanceGroupStateResult.getNewGlobalGroupState().getLocalState());
|
|
}
|
|
|
|
@Test
|
|
public void known_group_three_states_to_update_update_latest_handle_gap_with_no_changes() {
|
|
DecryptedGroup currentState = state(0);
|
|
ServerGroupLogEntry log1 = serverLogEntry(1);
|
|
ServerGroupLogEntry log3 = serverLogEntry(3);
|
|
|
|
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(currentState, asList(log1, log3)), LATEST);
|
|
|
|
assertThat(advanceGroupStateResult.getProcessedLogEntries(), is(asList(asLocal(log1), asLocal(log3))));
|
|
assertNewState(new GlobalGroupState(log3.getGroup(), emptyList()), advanceGroupStateResult.getNewGlobalGroupState());
|
|
assertEquals(log3.getGroup(), advanceGroupStateResult.getNewGlobalGroupState().getLocalState());
|
|
}
|
|
|
|
@Test
|
|
public void known_group_three_states_to_update_update_latest_handle_gap_with_changes() {
|
|
DecryptedGroup currentState = state(0);
|
|
ServerGroupLogEntry log1 = serverLogEntry(1);
|
|
DecryptedGroup state3a = DecryptedGroup.newBuilder()
|
|
.setRevision(3)
|
|
.setTitle("Group Revision " + 3)
|
|
.build();
|
|
DecryptedGroup state3 = DecryptedGroup.newBuilder()
|
|
.setRevision(3)
|
|
.setTitle("Group Revision " + 3)
|
|
.setAvatar("Lost Avatar Update")
|
|
.build();
|
|
ServerGroupLogEntry log3 = new ServerGroupLogEntry(state3, change(3));
|
|
DecryptedGroup state4 = DecryptedGroup.newBuilder()
|
|
.setRevision(4)
|
|
.setTitle("Group Revision " + 4)
|
|
.setAvatar("Lost Avatar Update")
|
|
.build();
|
|
ServerGroupLogEntry log4 = new ServerGroupLogEntry(state4, change(4));
|
|
|
|
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(currentState, asList(log1, log3, log4)), LATEST);
|
|
|
|
assertThat(advanceGroupStateResult.getProcessedLogEntries(), is(asList(asLocal(log1),
|
|
new LocalGroupLogEntry(state3a, log3.getChange()),
|
|
new LocalGroupLogEntry(state3, DecryptedGroupChange.newBuilder()
|
|
.setRevision(3)
|
|
.setNewAvatar(DecryptedString.newBuilder().setValue("Lost Avatar Update"))
|
|
.build()),
|
|
asLocal(log4))));
|
|
|
|
assertNewState(new GlobalGroupState(log4.getGroup(), emptyList()), advanceGroupStateResult.getNewGlobalGroupState());
|
|
assertEquals(log4.getGroup(), advanceGroupStateResult.getNewGlobalGroupState().getLocalState());
|
|
}
|
|
|
|
@Test
|
|
public void updates_with_all_changes_missing() {
|
|
DecryptedGroup currentState = state(5);
|
|
ServerGroupLogEntry log6 = serverLogEntryWholeStateOnly(6);
|
|
ServerGroupLogEntry log7 = serverLogEntryWholeStateOnly(7);
|
|
ServerGroupLogEntry log8 = serverLogEntryWholeStateOnly(8);
|
|
|
|
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(currentState, asList(log6, log7, log8)), LATEST);
|
|
|
|
assertThat(advanceGroupStateResult.getProcessedLogEntries(), is(asList(localLogEntryNoEditor(6), localLogEntryNoEditor(7), localLogEntryNoEditor(8))));
|
|
assertNewState(new GlobalGroupState(log8.getGroup(), emptyList()), advanceGroupStateResult.getNewGlobalGroupState());
|
|
assertEquals(log8.getGroup(), advanceGroupStateResult.getNewGlobalGroupState().getLocalState());
|
|
}
|
|
|
|
@Test
|
|
public void updates_with_all_group_states_missing() {
|
|
DecryptedGroup currentState = state(6);
|
|
ServerGroupLogEntry log7 = logEntryMissingState(7);
|
|
ServerGroupLogEntry log8 = logEntryMissingState(8);
|
|
ServerGroupLogEntry log9 = logEntryMissingState(9);
|
|
|
|
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(currentState, asList(log7, log8, log9)), LATEST);
|
|
|
|
assertThat(advanceGroupStateResult.getProcessedLogEntries(), is(asList(asLocal(serverLogEntry(7)), asLocal(serverLogEntry(8)), asLocal(serverLogEntry(9)))));
|
|
assertNewState(new GlobalGroupState(state(9), emptyList()), advanceGroupStateResult.getNewGlobalGroupState());
|
|
assertEquals(state(9), advanceGroupStateResult.getNewGlobalGroupState().getLocalState());
|
|
}
|
|
|
|
@Test
|
|
public void updates_with_a_server_mismatch_inserts_additional_update() {
|
|
DecryptedGroup currentState = state(6);
|
|
ServerGroupLogEntry log7 = serverLogEntry(7);
|
|
DecryptedMember newMember = DecryptedMember.newBuilder()
|
|
.setUuid(UuidUtil.toByteString(UUID.randomUUID()))
|
|
.build();
|
|
DecryptedGroup state7b = DecryptedGroup.newBuilder()
|
|
.setRevision(8)
|
|
.setTitle("Group Revision " + 8)
|
|
.build();
|
|
DecryptedGroup state8 = DecryptedGroup.newBuilder()
|
|
.setRevision(8)
|
|
.setTitle("Group Revision " + 8)
|
|
.addMembers(newMember)
|
|
.build();
|
|
ServerGroupLogEntry log8 = new ServerGroupLogEntry(state8,
|
|
change(8) );
|
|
ServerGroupLogEntry log9 = new ServerGroupLogEntry(DecryptedGroup.newBuilder()
|
|
.setRevision(9)
|
|
.addMembers(newMember)
|
|
.setTitle("Group Revision " + 9)
|
|
.build(),
|
|
change(9) );
|
|
|
|
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(currentState, asList(log7, log8, log9)), LATEST);
|
|
|
|
assertThat(advanceGroupStateResult.getProcessedLogEntries(), is(asList(asLocal(log7),
|
|
new LocalGroupLogEntry(state7b, log8.getChange()),
|
|
new LocalGroupLogEntry(state8, DecryptedGroupChange.newBuilder()
|
|
.setRevision(8)
|
|
.addNewMembers(newMember)
|
|
.build()),
|
|
asLocal(log9))));
|
|
assertNewState(new GlobalGroupState(log9.getGroup(), emptyList()), advanceGroupStateResult.getNewGlobalGroupState());
|
|
assertEquals(log9.getGroup(), advanceGroupStateResult.getNewGlobalGroupState().getLocalState());
|
|
}
|
|
|
|
@Test
|
|
public void local_up_to_date_no_repair_necessary() {
|
|
DecryptedGroup currentState = state(6);
|
|
ServerGroupLogEntry log6 = serverLogEntryWholeStateOnly(6);
|
|
|
|
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(currentState, singletonList(log6)), LATEST);
|
|
|
|
assertThat(advanceGroupStateResult.getProcessedLogEntries(), is(emptyList()));
|
|
assertNewState(new GlobalGroupState(state(6), emptyList()), advanceGroupStateResult.getNewGlobalGroupState());
|
|
assertEquals(state(6), advanceGroupStateResult.getNewGlobalGroupState().getLocalState());
|
|
}
|
|
|
|
@Test
|
|
public void no_repair_change_is_posted_if_the_local_state_is_a_placeholder() {
|
|
DecryptedGroup currentState = DecryptedGroup.newBuilder()
|
|
.setRevision(GroupStateMapper.PLACEHOLDER_REVISION)
|
|
.setTitle("Incorrect group title, Revision " + 6)
|
|
.build();
|
|
ServerGroupLogEntry log6 = serverLogEntry(6);
|
|
|
|
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(currentState, singletonList(log6)), LATEST);
|
|
|
|
assertThat(advanceGroupStateResult.getProcessedLogEntries(), is(singletonList(asLocal(log6))));
|
|
assertTrue(advanceGroupStateResult.getNewGlobalGroupState().getServerHistory().isEmpty());
|
|
assertEquals(log6.getGroup(), advanceGroupStateResult.getNewGlobalGroupState().getLocalState());
|
|
}
|
|
|
|
@Test
|
|
public void clears_changes_duplicated_in_the_placeholder() {
|
|
UUID newMemberUuid = UUID.randomUUID();
|
|
DecryptedMember newMember = DecryptedMember.newBuilder()
|
|
.setUuid(UuidUtil.toByteString(newMemberUuid))
|
|
.build();
|
|
DecryptedMember existingMember = DecryptedMember.newBuilder()
|
|
.setUuid(UuidUtil.toByteString(UUID.randomUUID()))
|
|
.build();
|
|
DecryptedGroup currentState = DecryptedGroup.newBuilder()
|
|
.setRevision(GroupStateMapper.PLACEHOLDER_REVISION)
|
|
.setTitle("Group Revision " + 8)
|
|
.addMembers(newMember)
|
|
.build();
|
|
ServerGroupLogEntry log8 = new ServerGroupLogEntry(DecryptedGroup.newBuilder()
|
|
.setRevision(8)
|
|
.addMembers(newMember)
|
|
.addMembers(existingMember)
|
|
.setTitle("Group Revision " + 8)
|
|
.build(),
|
|
DecryptedGroupChange.newBuilder()
|
|
.setRevision(8)
|
|
.setEditor(UuidUtil.toByteString(newMemberUuid))
|
|
.addNewMembers(newMember)
|
|
.build());
|
|
|
|
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(currentState, singletonList(log8)), LATEST);
|
|
|
|
assertNotNull(log8.getGroup());
|
|
assertThat(advanceGroupStateResult.getProcessedLogEntries(), is(emptyList()));
|
|
assertNewState(new GlobalGroupState(log8.getGroup(), emptyList()), advanceGroupStateResult.getNewGlobalGroupState());
|
|
assertEquals(log8.getGroup(), advanceGroupStateResult.getNewGlobalGroupState().getLocalState());
|
|
}
|
|
|
|
@Test
|
|
public void clears_changes_duplicated_in_a_non_placeholder() {
|
|
UUID editorUuid = UUID.randomUUID();
|
|
UUID newMemberUuid = UUID.randomUUID();
|
|
DecryptedMember newMember = DecryptedMember.newBuilder()
|
|
.setUuid(UuidUtil.toByteString(newMemberUuid))
|
|
.build();
|
|
DecryptedMember existingMember = DecryptedMember.newBuilder()
|
|
.setUuid(UuidUtil.toByteString(UUID.randomUUID()))
|
|
.build();
|
|
DecryptedGroup currentState = DecryptedGroup.newBuilder()
|
|
.setRevision(8)
|
|
.setTitle("Group Revision " + 8)
|
|
.addMembers(existingMember)
|
|
.build();
|
|
ServerGroupLogEntry log8 = new ServerGroupLogEntry(DecryptedGroup.newBuilder()
|
|
.setRevision(8)
|
|
.addMembers(existingMember)
|
|
.addMembers(newMember)
|
|
.setTitle("Group Revision " + 8)
|
|
.build(),
|
|
DecryptedGroupChange.newBuilder()
|
|
.setRevision(8)
|
|
.setEditor(UuidUtil.toByteString(editorUuid))
|
|
.addNewMembers(existingMember)
|
|
.addNewMembers(newMember)
|
|
.build());
|
|
|
|
DecryptedGroupChange expectedChange = DecryptedGroupChange.newBuilder()
|
|
.setRevision(8)
|
|
.setEditor(UuidUtil.toByteString(editorUuid))
|
|
.addNewMembers(newMember)
|
|
.build();
|
|
|
|
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(currentState, singletonList(log8)), LATEST);
|
|
|
|
assertNotNull(log8.getGroup());
|
|
assertThat(advanceGroupStateResult.getProcessedLogEntries(), is(singletonList(new LocalGroupLogEntry(log8.getGroup(), expectedChange))));
|
|
assertNewState(new GlobalGroupState(log8.getGroup(), emptyList()), advanceGroupStateResult.getNewGlobalGroupState());
|
|
assertEquals(log8.getGroup(), advanceGroupStateResult.getNewGlobalGroupState().getLocalState());
|
|
}
|
|
|
|
@Test
|
|
public void notices_changes_in_avatar_and_title_but_not_members_in_placeholder() {
|
|
UUID newMemberUuid = UUID.randomUUID();
|
|
DecryptedMember newMember = DecryptedMember.newBuilder()
|
|
.setUuid(UuidUtil.toByteString(newMemberUuid))
|
|
.build();
|
|
DecryptedMember existingMember = DecryptedMember.newBuilder()
|
|
.setUuid(UuidUtil.toByteString(UUID.randomUUID()))
|
|
.build();
|
|
DecryptedGroup currentState = DecryptedGroup.newBuilder()
|
|
.setRevision(GroupStateMapper.PLACEHOLDER_REVISION)
|
|
.setTitle("Incorrect group title")
|
|
.setAvatar("Incorrect group avatar")
|
|
.addMembers(newMember)
|
|
.build();
|
|
ServerGroupLogEntry log8 = new ServerGroupLogEntry(DecryptedGroup.newBuilder()
|
|
.setRevision(8)
|
|
.addMembers(newMember)
|
|
.addMembers(existingMember)
|
|
.setTitle("Group Revision " + 8)
|
|
.setAvatar("Group Avatar " + 8)
|
|
.build(),
|
|
DecryptedGroupChange.newBuilder()
|
|
.setRevision(8)
|
|
.setEditor(UuidUtil.toByteString(newMemberUuid))
|
|
.addNewMembers(newMember)
|
|
.build());
|
|
|
|
DecryptedGroupChange expectedChange = DecryptedGroupChange.newBuilder()
|
|
.setRevision(8)
|
|
.setNewTitle(DecryptedString.newBuilder().setValue("Group Revision " + 8))
|
|
.setNewAvatar(DecryptedString.newBuilder().setValue("Group Avatar " + 8))
|
|
.build();
|
|
|
|
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(currentState, singletonList(log8)), LATEST);
|
|
|
|
assertNotNull(log8.getGroup());
|
|
assertThat(advanceGroupStateResult.getProcessedLogEntries(), is(singletonList(new LocalGroupLogEntry(log8.getGroup(), expectedChange))));
|
|
assertNewState(new GlobalGroupState(log8.getGroup(), emptyList()), advanceGroupStateResult.getNewGlobalGroupState());
|
|
assertEquals(log8.getGroup(), advanceGroupStateResult.getNewGlobalGroupState().getLocalState());
|
|
}
|
|
|
|
@Test
|
|
public void no_actual_change() {
|
|
DecryptedGroup currentState = state(0);
|
|
ServerGroupLogEntry log1 = serverLogEntry(1);
|
|
ServerGroupLogEntry log2 = new ServerGroupLogEntry(DecryptedGroup.newBuilder(log1.getGroup())
|
|
.setRevision(2)
|
|
.build(),
|
|
DecryptedGroupChange.newBuilder()
|
|
.setRevision(2)
|
|
.setEditor(UuidUtil.toByteString(KNOWN_EDITOR))
|
|
.setNewTitle(DecryptedString.newBuilder().setValue(log1.getGroup().getTitle()))
|
|
.build());
|
|
|
|
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(currentState, asList(log1, log2)), 2);
|
|
|
|
assertThat(advanceGroupStateResult.getProcessedLogEntries(), is(asList(asLocal(log1),
|
|
new LocalGroupLogEntry(log2.getGroup(), DecryptedGroupChange.newBuilder()
|
|
.setRevision(2)
|
|
.setEditor(UuidUtil.toByteString(KNOWN_EDITOR))
|
|
.build()))));
|
|
assertTrue(advanceGroupStateResult.getNewGlobalGroupState().getServerHistory().isEmpty());
|
|
assertEquals(log2.getGroup(), advanceGroupStateResult.getNewGlobalGroupState().getLocalState());
|
|
}
|
|
|
|
private static void assertNewState(GlobalGroupState expected, GlobalGroupState actual) {
|
|
assertEquals(expected.getLocalState(), actual.getLocalState());
|
|
assertThat(actual.getServerHistory(), is(expected.getServerHistory()));
|
|
}
|
|
|
|
private static ServerGroupLogEntry serverLogEntry(int revision) {
|
|
return new ServerGroupLogEntry(state(revision), change(revision));
|
|
}
|
|
|
|
private static LocalGroupLogEntry localLogEntryNoEditor(int revision) {
|
|
return new LocalGroupLogEntry(state(revision), changeNoEditor(revision));
|
|
}
|
|
|
|
private static ServerGroupLogEntry serverLogEntryWholeStateOnly(int revision) {
|
|
return new ServerGroupLogEntry(state(revision), null);
|
|
}
|
|
|
|
private static ServerGroupLogEntry logEntryMissingState(int revision) {
|
|
return new ServerGroupLogEntry(null, change(revision));
|
|
}
|
|
|
|
private static DecryptedGroup state(int revision) {
|
|
return DecryptedGroup.newBuilder()
|
|
.setRevision(revision)
|
|
.setTitle("Group Revision " + revision)
|
|
.build();
|
|
}
|
|
|
|
private static DecryptedGroupChange change(int revision) {
|
|
return DecryptedGroupChange.newBuilder()
|
|
.setRevision(revision)
|
|
.setEditor(UuidUtil.toByteString(KNOWN_EDITOR))
|
|
.setNewTitle(DecryptedString.newBuilder().setValue("Group Revision " + revision))
|
|
.build();
|
|
}
|
|
|
|
private static DecryptedGroupChange changeNoEditor(int revision) {
|
|
return DecryptedGroupChange.newBuilder()
|
|
.setRevision(revision)
|
|
.setNewTitle(DecryptedString.newBuilder().setValue("Group Revision " + revision))
|
|
.build();
|
|
}
|
|
|
|
private static LocalGroupLogEntry asLocal(ServerGroupLogEntry logEntry) {
|
|
assertNotNull(logEntry.getGroup());
|
|
return new LocalGroupLogEntry(logEntry.getGroup(), logEntry.getChange());
|
|
}
|
|
} |