Join group via invite link.

This commit is contained in:
Alan Evans
2020-08-26 12:51:25 -03:00
committed by GitHub
parent b58376920f
commit 860f06ec9e
45 changed files with 2488 additions and 271 deletions

View File

@@ -1035,6 +1035,15 @@ public final class GroupsV2UpdateMessageProducerTest {
assertThat(describeChange(change), is(singletonList("Alice approved a request to join the group from Bob.")));
}
@Test
public void you_approved_another_join_request() {
DecryptedGroupChange change = changeBy(you)
.approveRequest(alice)
.build();
assertThat(describeChange(change), is(singletonList("You approved a request to join the group from Alice.")));
}
@Test
public void unknown_approved_your_join_request() {
DecryptedGroupChange change = changeByUnknown()
@@ -1071,6 +1080,24 @@ public final class GroupsV2UpdateMessageProducerTest {
assertThat(describeChange(change), is(singletonList("Your request to join the group has been denied by an admin.")));
}
@Test
public void you_cancelled_your_join_request() {
DecryptedGroupChange change = changeBy(you)
.denyRequest(you)
.build();
assertThat(describeChange(change), is(singletonList("You canceled your request to join the group.")));
}
@Test
public void member_cancelled_their_join_request() {
DecryptedGroupChange change = changeBy(alice)
.denyRequest(alice)
.build();
assertThat(describeChange(change), is(singletonList("Alice canceled their request to join the group.")));
}
@Test
public void unknown_denied_your_join_request() {
DecryptedGroupChange change = changeByUnknown()

View File

@@ -197,6 +197,10 @@ public final class GroupStateMapperTest {
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)
@@ -213,11 +217,11 @@ public final class GroupStateMapperTest {
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(currentState, asList(log1, log3, log4)), LATEST);
assertThat(advanceGroupStateResult.getProcessedLogEntries(), is(asList(asLocal(log1),
asLocal(log3),
new LocalGroupLogEntry(state3a, log3.getChange()),
new LocalGroupLogEntry(state3, DecryptedGroupChange.newBuilder()
.setRevision(3)
.setNewAvatar(DecryptedString.newBuilder().setValue("Lost Avatar Update"))
.build()),
.setRevision(3)
.setNewAvatar(DecryptedString.newBuilder().setValue("Lost Avatar Update"))
.build()),
asLocal(log4))));
assertNewState(new GlobalGroupState(log4.getGroup(), emptyList()), advanceGroupStateResult.getNewGlobalGroupState());
@@ -259,11 +263,16 @@ public final class GroupStateMapperTest {
DecryptedMember newMember = DecryptedMember.newBuilder()
.setUuid(UuidUtil.toByteString(UUID.randomUUID()))
.build();
ServerGroupLogEntry log8 = new ServerGroupLogEntry(DecryptedGroup.newBuilder()
.setRevision(8)
.addMembers(newMember)
.setTitle("Group Revision " + 8)
.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)
@@ -275,11 +284,11 @@ public final class GroupStateMapperTest {
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(currentState, asList(log7, log8, log9)), LATEST);
assertThat(advanceGroupStateResult.getProcessedLogEntries(), is(asList(asLocal(log7),
asLocal(log8),
asLocal(new ServerGroupLogEntry(log8.getGroup(), DecryptedGroupChange.newBuilder()
.setRevision(8)
.addNewMembers(newMember)
.build())),
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());
@@ -298,18 +307,136 @@ public final class GroupStateMapperTest {
}
@Test
public void local_on_same_revision_but_incorrect_repair_necessary() {
public void no_repair_change_is_posted_if_the_local_state_is_a_placeholder() {
DecryptedGroup currentState = DecryptedGroup.newBuilder()
.setRevision(6)
.setRevision(GroupStateMapper.PLACEHOLDER_REVISION)
.setTitle("Incorrect group title, Revision " + 6)
.build();
ServerGroupLogEntry log6 = serverLogEntryWholeStateOnly(6);
ServerGroupLogEntry log6 = serverLogEntry(6);
AdvanceGroupStateResult advanceGroupStateResult = GroupStateMapper.partiallyAdvanceGroupState(new GlobalGroupState(currentState, singletonList(log6)), LATEST);
assertThat(advanceGroupStateResult.getProcessedLogEntries(), is(singletonList(localLogEntryNoEditor(6))));
assertNewState(new GlobalGroupState(state(6), emptyList()), advanceGroupStateResult.getNewGlobalGroupState());
assertEquals(state(6), advanceGroupStateResult.getNewGlobalGroupState().getLocalState());
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());
}
private static void assertNewState(GlobalGroupState expected, GlobalGroupState actual) {

View File

@@ -0,0 +1,133 @@
package org.thoughtcrime.securesms.groups.v2.processing;
import org.junit.Test;
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.assertThat;
public final class StateChainTest {
private static final int BAD_DELTA = 256;
private final StateChain<Character, Integer> stateChain = new StateChain<>(
(c, d) -> {
if (d == BAD_DELTA) return null;
return (char) (c + d);
},
(a, b) -> a - b,
(a, b)->a==b);
@Test
public void push_one_state_pair() {
stateChain.push('A', 0);
assertThat(stateChain.getList(), is(singletonList(pair('A', 0))));
}
@Test
public void push_two_state_pairs() {
stateChain.push('A', 0);
stateChain.push('B', 1);
assertThat(stateChain.getList(), is(asList(pair('A', 0),
pair('B', 1))));
}
@Test
public void push_two_state_pairs_null_first_delta() {
stateChain.push('A', null);
stateChain.push('B', 1);
assertThat(stateChain.getList(), is(asList(pair('A', null),
pair('B', 1))));
}
@Test
public void push_two_state_pairs_with_missing_delta() {
stateChain.push('A', 0);
stateChain.push('B', null);
assertThat(stateChain.getList(), is(asList(pair('A', 0),
pair('B', 1))));
}
@Test
public void push_two_state_pairs_with_missing_state() {
stateChain.push('A', 0);
stateChain.push(null, 1);
assertThat(stateChain.getList(), is(asList(pair('A', 0),
pair('B', 1))));
}
@Test
public void push_one_state_pairs_with_missing_state_and_delta() {
stateChain.push(null, null);
assertThat(stateChain.getList(), is(emptyList()));
}
@Test
public void push_two_state_pairs_with_missing_state_and_delta() {
stateChain.push('A', 0);
stateChain.push(null, null);
assertThat(stateChain.getList(), is(singletonList(pair('A', 0))));
}
@Test
public void push_two_state_pairs_that_do_not_match() {
stateChain.push('D', 0);
stateChain.push('E', 2);
assertThat(stateChain.getList(), is(asList(pair('D', 0),
pair('F', 2),
pair('E', -1))));
}
@Test
public void push_one_state_pair_null_delta() {
stateChain.push('A', null);
assertThat(stateChain.getList(), is(singletonList(pair('A', null))));
}
@Test
public void push_two_state_pairs_with_no_diff() {
stateChain.push('Z', null);
stateChain.push('Z', 0);
assertThat(stateChain.getList(), is(singletonList(pair('Z', null))));
}
@Test
public void push_one_state_pair_null_state() {
stateChain.push(null, 1);
assertThat(stateChain.getList(), is(emptyList()));
}
@Test
public void bad_delta_results_in_reconstruction() {
stateChain.push('C', 0);
stateChain.push('F', BAD_DELTA);
assertThat(stateChain.getList(), is(asList(pair('C', 0),
pair('F', 3))));
}
@Test
public void bad_delta_and_no_state_results_in_change_ignore() {
stateChain.push('C', 0);
stateChain.push(null, BAD_DELTA);
assertThat(stateChain.getList(), is(singletonList(pair('C', 0))));
}
private static StateChain.Pair<Character, Integer> pair(char c, Integer i) {
return new StateChain.Pair<>(c, i);
}
}