mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-17 05:09:53 +01:00
Fixed a bug in the group invitation protocol, added tests.
This commit is contained in:
@@ -265,8 +265,8 @@ public class GroupInvitationIntegrationTest extends BriarIntegrationTest {
|
|||||||
.respondToInvitation(contactId0From1, privateGroup0, true);
|
.respondToInvitation(contactId0From1, privateGroup0, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test(expected = ProtocolStateException.class)
|
||||||
public void testCreatorLeavesBeforeInvitationAnswered() throws Exception {
|
public void testCreatorLeavesBeforeInvitationAccepted() throws Exception {
|
||||||
// Creator invites invitee to join group
|
// Creator invites invitee to join group
|
||||||
sendInvitation(clock.currentTimeMillis(), null);
|
sendInvitation(clock.currentTimeMillis(), null);
|
||||||
|
|
||||||
@@ -278,7 +278,54 @@ public class GroupInvitationIntegrationTest extends BriarIntegrationTest {
|
|||||||
groupManager0.removePrivateGroup(privateGroup0.getId());
|
groupManager0.removePrivateGroup(privateGroup0.getId());
|
||||||
assertEquals(0, groupManager0.getPrivateGroups().size());
|
assertEquals(0, groupManager0.getPrivateGroups().size());
|
||||||
|
|
||||||
// Invitee responds to invitation
|
// Creator's leave message is delivered to invitee
|
||||||
|
sync0To1(1, true);
|
||||||
|
|
||||||
|
// Invitee accepts invitation, but it's no longer open - exception is
|
||||||
|
// thrown as the action has failed
|
||||||
|
assertEquals(0, groupManager1.getPrivateGroups().size());
|
||||||
|
groupInvitationManager1
|
||||||
|
.respondToInvitation(contactId0From1, privateGroup0, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreatorLeavesBeforeInvitationDeclined() throws Exception {
|
||||||
|
// Creator invites invitee to join group
|
||||||
|
sendInvitation(clock.currentTimeMillis(), null);
|
||||||
|
|
||||||
|
// Creator's invite message is delivered to invitee
|
||||||
|
sync0To1(1, true);
|
||||||
|
|
||||||
|
// Creator leaves group
|
||||||
|
assertEquals(1, groupManager0.getPrivateGroups().size());
|
||||||
|
groupManager0.removePrivateGroup(privateGroup0.getId());
|
||||||
|
assertEquals(0, groupManager0.getPrivateGroups().size());
|
||||||
|
|
||||||
|
// Creator's leave message is delivered to invitee
|
||||||
|
sync0To1(1, true);
|
||||||
|
|
||||||
|
// Invitee declines invitation, but it's no longer open - no exception
|
||||||
|
// as the action has succeeded
|
||||||
|
assertEquals(0, groupManager1.getPrivateGroups().size());
|
||||||
|
groupInvitationManager1
|
||||||
|
.respondToInvitation(contactId0From1, privateGroup0, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreatorLeavesConcurrentlyWithInvitationAccepted()
|
||||||
|
throws Exception {
|
||||||
|
// Creator invites invitee to join group
|
||||||
|
sendInvitation(clock.currentTimeMillis(), null);
|
||||||
|
|
||||||
|
// Creator's invite message is delivered to invitee
|
||||||
|
sync0To1(1, true);
|
||||||
|
|
||||||
|
// Creator leaves group
|
||||||
|
assertEquals(1, groupManager0.getPrivateGroups().size());
|
||||||
|
groupManager0.removePrivateGroup(privateGroup0.getId());
|
||||||
|
assertEquals(0, groupManager0.getPrivateGroups().size());
|
||||||
|
|
||||||
|
// Invitee accepts invitation
|
||||||
assertEquals(0, groupManager1.getPrivateGroups().size());
|
assertEquals(0, groupManager1.getPrivateGroups().size());
|
||||||
groupInvitationManager1
|
groupInvitationManager1
|
||||||
.respondToInvitation(contactId0From1, privateGroup0, true);
|
.respondToInvitation(contactId0From1, privateGroup0, true);
|
||||||
@@ -293,7 +340,67 @@ public class GroupInvitationIntegrationTest extends BriarIntegrationTest {
|
|||||||
|
|
||||||
// Group is marked as dissolved
|
// Group is marked as dissolved
|
||||||
assertTrue(groupManager1.isDissolved(privateGroup0.getId()));
|
assertTrue(groupManager1.isDissolved(privateGroup0.getId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreatorLeavesConcurrentlyWithInvitationDeclined()
|
||||||
|
throws Exception {
|
||||||
|
// Creator invites invitee to join group
|
||||||
|
sendInvitation(clock.currentTimeMillis(), null);
|
||||||
|
|
||||||
|
// Creator's invite message is delivered to invitee
|
||||||
|
sync0To1(1, true);
|
||||||
|
|
||||||
|
// Creator leaves group
|
||||||
|
assertEquals(1, groupManager0.getPrivateGroups().size());
|
||||||
|
groupManager0.removePrivateGroup(privateGroup0.getId());
|
||||||
|
assertEquals(0, groupManager0.getPrivateGroups().size());
|
||||||
|
|
||||||
|
// Invitee declines invitation
|
||||||
|
assertEquals(0, groupManager1.getPrivateGroups().size());
|
||||||
|
groupInvitationManager1
|
||||||
|
.respondToInvitation(contactId0From1, privateGroup0, false);
|
||||||
|
assertEquals(0, groupManager1.getPrivateGroups().size());
|
||||||
|
|
||||||
|
// Invitee's leave message is delivered to creator
|
||||||
|
sync1To0(1, true);
|
||||||
|
|
||||||
|
// Creator's leave message is delivered to invitee
|
||||||
|
sync0To1(1, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreatorLeavesConcurrentlyWithMemberLeaving()
|
||||||
|
throws Exception {
|
||||||
|
// Creator invites invitee to join group
|
||||||
|
sendInvitation(clock.currentTimeMillis(), null);
|
||||||
|
|
||||||
|
// Creator's invite message is delivered to invitee
|
||||||
|
sync0To1(1, true);
|
||||||
|
|
||||||
|
// Invitee responds to invitation
|
||||||
|
assertEquals(0, groupManager1.getPrivateGroups().size());
|
||||||
|
groupInvitationManager1
|
||||||
|
.respondToInvitation(contactId0From1, privateGroup0, true);
|
||||||
|
assertEquals(1, groupManager1.getPrivateGroups().size());
|
||||||
|
|
||||||
|
// Invitee's join message is delivered to creator
|
||||||
|
sync1To0(1, true);
|
||||||
|
|
||||||
|
// Creator leaves group
|
||||||
|
assertEquals(1, groupManager0.getPrivateGroups().size());
|
||||||
|
groupManager0.removePrivateGroup(privateGroup0.getId());
|
||||||
|
assertEquals(0, groupManager0.getPrivateGroups().size());
|
||||||
|
|
||||||
|
// Invitee leaves group
|
||||||
|
groupManager1.removePrivateGroup(privateGroup0.getId());
|
||||||
|
assertEquals(0, groupManager1.getPrivateGroups().size());
|
||||||
|
|
||||||
|
// Creator's leave message is delivered to invitee
|
||||||
|
sync0To1(1, true);
|
||||||
|
|
||||||
|
// Invitee's leave message is delivered to creator
|
||||||
|
sync1To0(1, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendInvitation(long timestamp, @Nullable String msg) throws
|
private void sendInvitation(long timestamp, @Nullable String msg) throws
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
|
|||||||
private final Group localGroup;
|
private final Group localGroup;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
protected GroupInvitationManagerImpl(DatabaseComponent db,
|
GroupInvitationManagerImpl(DatabaseComponent db,
|
||||||
ClientHelper clientHelper, MetadataParser metadataParser,
|
ClientHelper clientHelper, MetadataParser metadataParser,
|
||||||
MessageTracker messageTracker,
|
MessageTracker messageTracker,
|
||||||
ContactGroupFactory contactGroupFactory,
|
ContactGroupFactory contactGroupFactory,
|
||||||
|
|||||||
@@ -148,10 +148,11 @@ class InviteeProtocolEngine extends AbstractProtocolEngine<InviteeSession> {
|
|||||||
case DISSOLVED:
|
case DISSOLVED:
|
||||||
return abort(txn, s); // Invalid in these states
|
return abort(txn, s); // Invalid in these states
|
||||||
case INVITED:
|
case INVITED:
|
||||||
|
case LEFT:
|
||||||
|
return onRemoteLeaveWhenNotSubscribed(txn, s, m);
|
||||||
case ACCEPTED:
|
case ACCEPTED:
|
||||||
case JOINED:
|
case JOINED:
|
||||||
case LEFT:
|
return onRemoteLeaveWhenSubscribed(txn, s, m);
|
||||||
return onRemoteLeave(txn, s, m);
|
|
||||||
case ERROR:
|
case ERROR:
|
||||||
return s; // Ignored in this state
|
return s; // Ignored in this state
|
||||||
default:
|
default:
|
||||||
@@ -260,8 +261,23 @@ class InviteeProtocolEngine extends AbstractProtocolEngine<InviteeSession> {
|
|||||||
s.getInviteTimestamp(), JOINED);
|
s.getInviteTimestamp(), JOINED);
|
||||||
}
|
}
|
||||||
|
|
||||||
private InviteeSession onRemoteLeave(Transaction txn, InviteeSession s,
|
private InviteeSession onRemoteLeaveWhenNotSubscribed(Transaction txn,
|
||||||
LeaveMessage m) throws DbException, FormatException {
|
InviteeSession s, LeaveMessage m)
|
||||||
|
throws DbException, FormatException {
|
||||||
|
// The timestamp must be higher than the last invite message, if any
|
||||||
|
if (m.getTimestamp() <= s.getInviteTimestamp()) return abort(txn, s);
|
||||||
|
// The dependency, if any, must be the last remote message
|
||||||
|
if (!isValidDependency(s, m.getPreviousMessageId()))
|
||||||
|
return abort(txn, s);
|
||||||
|
// Move to the DISSOLVED state
|
||||||
|
return new InviteeSession(s.getContactGroupId(), s.getPrivateGroupId(),
|
||||||
|
s.getLastLocalMessageId(), m.getId(), s.getLocalTimestamp(),
|
||||||
|
s.getInviteTimestamp(), DISSOLVED);
|
||||||
|
}
|
||||||
|
|
||||||
|
private InviteeSession onRemoteLeaveWhenSubscribed(Transaction txn,
|
||||||
|
InviteeSession s, LeaveMessage m)
|
||||||
|
throws DbException, FormatException {
|
||||||
// The timestamp must be higher than the last invite message, if any
|
// The timestamp must be higher than the last invite message, if any
|
||||||
if (m.getTimestamp() <= s.getInviteTimestamp()) return abort(txn, s);
|
if (m.getTimestamp() <= s.getInviteTimestamp()) return abort(txn, s);
|
||||||
// The dependency, if any, must be the last remote message
|
// The dependency, if any, must be the last remote message
|
||||||
|
|||||||
Reference in New Issue
Block a user