mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-11 18:29:05 +01:00
Merge branch '760-integration-tests-for-private-group-invitation-protocol' into 'master'
Add integration tests for GroupInvitationManager This MR is based on !433. It adds some integration tests for the private group invitation protocol. One of those tests fails at the moment. It does not yet cover all corner cases, so it does not fully address #760, but addresses a part of it. Suggestions for more scenarios to test are welcome. [Wording changed to prevent #760 from being closed automatically based on the description.] See merge request !434
This commit is contained in:
@@ -39,6 +39,7 @@ import org.briarproject.introduction.IntroductionGroupFactory;
|
||||
import org.briarproject.introduction.IntroductionModule;
|
||||
import org.briarproject.lifecycle.LifecycleModule;
|
||||
import org.briarproject.privategroup.PrivateGroupModule;
|
||||
import org.briarproject.privategroup.invitation.GroupInvitationModule;
|
||||
import org.briarproject.properties.PropertiesModule;
|
||||
import org.briarproject.sharing.SharingModule;
|
||||
import org.briarproject.sync.SyncModule;
|
||||
@@ -180,6 +181,7 @@ public abstract class BriarIntegrationTest extends BriarTestCase {
|
||||
component.inject(new CryptoModule.EagerSingletons());
|
||||
component.inject(new ContactModule.EagerSingletons());
|
||||
component.inject(new ForumModule.EagerSingletons());
|
||||
component.inject(new GroupInvitationModule.EagerSingletons());
|
||||
component.inject(new IntroductionModule.EagerSingletons());
|
||||
component.inject(new PropertiesModule.EagerSingletons());
|
||||
component.inject(new PrivateGroupModule.EagerSingletons());
|
||||
|
||||
@@ -14,6 +14,7 @@ import org.briarproject.api.identity.IdentityManager;
|
||||
import org.briarproject.api.introduction.IntroductionManager;
|
||||
import org.briarproject.api.lifecycle.LifecycleManager;
|
||||
import org.briarproject.api.privategroup.PrivateGroupManager;
|
||||
import org.briarproject.api.privategroup.invitation.GroupInvitationManager;
|
||||
import org.briarproject.api.properties.TransportPropertyManager;
|
||||
import org.briarproject.api.sync.SyncSessionFactory;
|
||||
import org.briarproject.blogs.BlogsModule;
|
||||
@@ -78,6 +79,8 @@ public interface BriarIntegrationTestComponent {
|
||||
|
||||
void inject(ForumModule.EagerSingletons init);
|
||||
|
||||
void inject(GroupInvitationModule.EagerSingletons init);
|
||||
|
||||
void inject(IntroductionModule.EagerSingletons init);
|
||||
|
||||
void inject(LifecycleModule.EagerSingletons init);
|
||||
@@ -114,6 +117,8 @@ public interface BriarIntegrationTestComponent {
|
||||
|
||||
ForumManager getForumManager();
|
||||
|
||||
GroupInvitationManager getGroupInvitationManager();
|
||||
|
||||
IntroductionManager getIntroductionManager();
|
||||
|
||||
MessageTracker getMessageTracker();
|
||||
|
||||
@@ -0,0 +1,415 @@
|
||||
package org.briarproject;
|
||||
|
||||
import org.briarproject.api.clients.ProtocolStateException;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.privategroup.GroupMessage;
|
||||
import org.briarproject.api.privategroup.PrivateGroup;
|
||||
import org.briarproject.api.privategroup.PrivateGroupManager;
|
||||
import org.briarproject.api.privategroup.invitation.GroupInvitationItem;
|
||||
import org.briarproject.api.privategroup.invitation.GroupInvitationManager;
|
||||
import org.briarproject.api.privategroup.invitation.GroupInvitationRequest;
|
||||
import org.briarproject.api.privategroup.invitation.GroupInvitationResponse;
|
||||
import org.briarproject.api.sharing.InvitationMessage;
|
||||
import org.briarproject.api.sync.Group;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import static junit.framework.TestCase.fail;
|
||||
import static org.briarproject.TestUtils.assertGroupCount;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
public class GroupInvitationIntegrationTest extends BriarIntegrationTest {
|
||||
|
||||
private PrivateGroup privateGroup0;
|
||||
private PrivateGroupManager groupManager0, groupManager1;
|
||||
private GroupInvitationManager groupInvitationManager0,
|
||||
groupInvitationManager1;
|
||||
|
||||
@Before
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
groupManager0 = c0.getPrivateGroupManager();
|
||||
groupManager1 = c1.getPrivateGroupManager();
|
||||
groupInvitationManager0 = c0.getGroupInvitationManager();
|
||||
groupInvitationManager1 = c1.getGroupInvitationManager();
|
||||
|
||||
privateGroup0 =
|
||||
privateGroupFactory.createPrivateGroup("Testgroup", author0);
|
||||
long joinTime = clock.currentTimeMillis();
|
||||
GroupMessage joinMsg0 = groupMessageFactory
|
||||
.createJoinMessage(privateGroup0.getId(), joinTime, author0);
|
||||
groupManager0.addPrivateGroup(privateGroup0, joinMsg0, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSendInvitation() throws Exception {
|
||||
long timestamp = clock.currentTimeMillis();
|
||||
String msg = "Hi!";
|
||||
sendInvitation(timestamp, msg);
|
||||
|
||||
sync0To1(1, true);
|
||||
|
||||
Collection<GroupInvitationItem> invitations =
|
||||
groupInvitationManager1.getInvitations();
|
||||
assertEquals(1, invitations.size());
|
||||
GroupInvitationItem item = invitations.iterator().next();
|
||||
assertEquals(contact0From1, item.getCreator());
|
||||
assertEquals(privateGroup0, item.getShareable());
|
||||
assertEquals(privateGroup0.getId(), item.getId());
|
||||
assertEquals(privateGroup0.getName(), item.getName());
|
||||
assertFalse(item.isSubscribed());
|
||||
|
||||
Collection<InvitationMessage> messages =
|
||||
groupInvitationManager1.getInvitationMessages(contactId0From1);
|
||||
assertEquals(1, messages.size());
|
||||
GroupInvitationRequest request =
|
||||
(GroupInvitationRequest) messages.iterator().next();
|
||||
assertEquals(msg, request.getMessage());
|
||||
assertEquals(author0, request.getCreator());
|
||||
assertEquals(timestamp, request.getTimestamp());
|
||||
assertEquals(contactId0From1, request.getContactId());
|
||||
assertEquals(privateGroup0.getName(), request.getGroupName());
|
||||
assertFalse(request.isLocal());
|
||||
assertFalse(request.isRead());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvitationDecline() throws Exception {
|
||||
long timestamp = clock.currentTimeMillis();
|
||||
sendInvitation(timestamp, null);
|
||||
|
||||
sync0To1(1, true);
|
||||
assertFalse(groupInvitationManager1.getInvitations().isEmpty());
|
||||
|
||||
groupInvitationManager1
|
||||
.respondToInvitation(contactId0From1, privateGroup0, false);
|
||||
|
||||
Collection<InvitationMessage> messages =
|
||||
groupInvitationManager1.getInvitationMessages(contactId0From1);
|
||||
assertEquals(2, messages.size());
|
||||
boolean foundResponse = false;
|
||||
for (InvitationMessage m : messages) {
|
||||
if (m instanceof GroupInvitationResponse) {
|
||||
foundResponse = true;
|
||||
GroupInvitationResponse response = (GroupInvitationResponse) m;
|
||||
assertEquals(contactId0From1, response.getContactId());
|
||||
assertTrue(response.isLocal());
|
||||
assertFalse(response.wasAccepted());
|
||||
}
|
||||
}
|
||||
assertTrue(foundResponse);
|
||||
|
||||
sync1To0(1, true);
|
||||
|
||||
messages =
|
||||
groupInvitationManager0.getInvitationMessages(contactId1From0);
|
||||
assertEquals(2, messages.size());
|
||||
foundResponse = false;
|
||||
for (InvitationMessage m : messages) {
|
||||
if (m instanceof GroupInvitationResponse) {
|
||||
foundResponse = true;
|
||||
GroupInvitationResponse response = (GroupInvitationResponse) m;
|
||||
assertEquals(contactId0From1, response.getContactId());
|
||||
assertFalse(response.isLocal());
|
||||
assertFalse(response.wasAccepted());
|
||||
}
|
||||
}
|
||||
assertTrue(foundResponse);
|
||||
|
||||
// no invitations are open
|
||||
assertTrue(groupInvitationManager1.getInvitations().isEmpty());
|
||||
// no groups were added
|
||||
assertEquals(0, groupManager1.getPrivateGroups().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvitationAccept() throws Exception {
|
||||
long timestamp = clock.currentTimeMillis();
|
||||
sendInvitation(timestamp, null);
|
||||
|
||||
sync0To1(1, true);
|
||||
assertFalse(groupInvitationManager1.getInvitations().isEmpty());
|
||||
|
||||
groupInvitationManager1
|
||||
.respondToInvitation(contactId0From1, privateGroup0, true);
|
||||
|
||||
Collection<InvitationMessage> messages =
|
||||
groupInvitationManager1.getInvitationMessages(contactId0From1);
|
||||
assertEquals(2, messages.size());
|
||||
boolean foundResponse = false;
|
||||
for (InvitationMessage m : messages) {
|
||||
if (m instanceof GroupInvitationResponse) {
|
||||
foundResponse = true;
|
||||
GroupInvitationResponse response = (GroupInvitationResponse) m;
|
||||
assertTrue(response.wasAccepted());
|
||||
}
|
||||
}
|
||||
assertTrue(foundResponse);
|
||||
|
||||
sync1To0(1, true);
|
||||
|
||||
messages =
|
||||
groupInvitationManager0.getInvitationMessages(contactId1From0);
|
||||
assertEquals(2, messages.size());
|
||||
foundResponse = false;
|
||||
for (InvitationMessage m : messages) {
|
||||
if (m instanceof GroupInvitationResponse) {
|
||||
foundResponse = true;
|
||||
GroupInvitationResponse response = (GroupInvitationResponse) m;
|
||||
assertTrue(response.wasAccepted());
|
||||
}
|
||||
}
|
||||
assertTrue(foundResponse);
|
||||
|
||||
// no invitations are open
|
||||
assertTrue(groupInvitationManager1.getInvitations().isEmpty());
|
||||
// group was added
|
||||
Collection<PrivateGroup> groups = groupManager1.getPrivateGroups();
|
||||
assertEquals(1, groups.size());
|
||||
assertEquals(privateGroup0, groups.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGroupCount() throws Exception {
|
||||
long timestamp = clock.currentTimeMillis();
|
||||
sendInvitation(timestamp, null);
|
||||
|
||||
// 0 has one read outgoing message
|
||||
Group g1 = groupInvitationManager0.getContactGroup(contact1From0);
|
||||
assertGroupCount(messageTracker0, g1.getId(), 1, 0, timestamp);
|
||||
|
||||
sync0To1(1, true);
|
||||
|
||||
// 1 has one unread message
|
||||
Group g0 = groupInvitationManager1.getContactGroup(contact0From1);
|
||||
assertGroupCount(messageTracker1, g0.getId(), 1, 1, timestamp);
|
||||
InvitationMessage m =
|
||||
groupInvitationManager1.getInvitationMessages(contactId0From1)
|
||||
.iterator().next();
|
||||
|
||||
groupInvitationManager1
|
||||
.respondToInvitation(contactId0From1, privateGroup0, true);
|
||||
|
||||
// 1 has two messages, one still unread
|
||||
assertGroupCount(messageTracker1, g0.getId(), 2, 1);
|
||||
|
||||
// now all messages should be read
|
||||
groupInvitationManager1.setReadFlag(g0.getId(), m.getId(), true);
|
||||
assertGroupCount(messageTracker1, g0.getId(), 2, 0);
|
||||
|
||||
sync1To0(1, true);
|
||||
|
||||
// now 0 has two messages, one of them unread
|
||||
assertGroupCount(messageTracker0, g1.getId(), 2, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMultipleInvitations() throws Exception {
|
||||
sendInvitation(clock.currentTimeMillis(), null);
|
||||
|
||||
// invitation is not allowed before the first hasn't been answered
|
||||
assertFalse(groupInvitationManager0
|
||||
.isInvitationAllowed(contact1From0, privateGroup0.getId()));
|
||||
|
||||
// deliver invitation and response
|
||||
sync0To1(1, true);
|
||||
groupInvitationManager1
|
||||
.respondToInvitation(contactId0From1, privateGroup0, false);
|
||||
sync1To0(1, true);
|
||||
|
||||
// after invitation was declined, inviting again is possible
|
||||
assertTrue(groupInvitationManager0
|
||||
.isInvitationAllowed(contact1From0, privateGroup0.getId()));
|
||||
|
||||
// send and accept the second invitation
|
||||
sendInvitation(clock.currentTimeMillis(), "Second Invitation");
|
||||
sync0To1(1, true);
|
||||
groupInvitationManager1
|
||||
.respondToInvitation(contactId0From1, privateGroup0, true);
|
||||
sync1To0(1, true);
|
||||
|
||||
// invitation is not allowed since the member joined the group now
|
||||
assertFalse(groupInvitationManager0
|
||||
.isInvitationAllowed(contact1From0, privateGroup0.getId()));
|
||||
|
||||
// don't allow another invitation request
|
||||
try {
|
||||
sendInvitation(clock.currentTimeMillis(), "Third Invitation");
|
||||
fail();
|
||||
} catch (ProtocolStateException e) {
|
||||
// expected
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected = ProtocolStateException.class)
|
||||
public void testInvitationsWithSameTimestamp() throws Exception {
|
||||
long timestamp = clock.currentTimeMillis();
|
||||
sendInvitation(timestamp, null);
|
||||
sync0To1(1, true);
|
||||
|
||||
groupInvitationManager1
|
||||
.respondToInvitation(contactId0From1, privateGroup0, false);
|
||||
sync1To0(1, true);
|
||||
|
||||
sendInvitation(timestamp, "Second Invitation");
|
||||
sync0To1(1, true);
|
||||
|
||||
groupInvitationManager1
|
||||
.respondToInvitation(contactId0From1, privateGroup0, true);
|
||||
}
|
||||
|
||||
@Test(expected = ProtocolStateException.class)
|
||||
public void testCreatorLeavesBeforeInvitationAccepted() 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 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());
|
||||
groupInvitationManager1
|
||||
.respondToInvitation(contactId0From1, privateGroup0, true);
|
||||
assertEquals(1, groupManager1.getPrivateGroups().size());
|
||||
assertFalse(groupManager1.isDissolved(privateGroup0.getId()));
|
||||
|
||||
// Invitee's join message is delivered to creator
|
||||
sync1To0(1, true);
|
||||
|
||||
// Creator's leave message is delivered to invitee
|
||||
sync0To1(1, true);
|
||||
|
||||
// Group is marked as dissolved
|
||||
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
|
||||
DbException {
|
||||
byte[] signature = groupInvitationFactory.signInvitation(contact1From0,
|
||||
privateGroup0.getId(), timestamp, author0.getPrivateKey());
|
||||
groupInvitationManager0
|
||||
.sendInvitation(privateGroup0.getId(), contactId1From0, msg,
|
||||
timestamp, signature);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,205 @@
|
||||
package org.briarproject;
|
||||
|
||||
import org.briarproject.api.contact.Contact;
|
||||
import org.briarproject.api.contact.ContactId;
|
||||
import org.briarproject.api.db.DbException;
|
||||
import org.briarproject.api.identity.AuthorId;
|
||||
import org.briarproject.api.privategroup.GroupMember;
|
||||
import org.briarproject.api.privategroup.GroupMessage;
|
||||
import org.briarproject.api.privategroup.GroupMessageHeader;
|
||||
import org.briarproject.api.privategroup.JoinMessageHeader;
|
||||
import org.briarproject.api.privategroup.PrivateGroup;
|
||||
import org.briarproject.api.privategroup.PrivateGroupManager;
|
||||
import org.briarproject.api.privategroup.invitation.GroupInvitationManager;
|
||||
import org.briarproject.api.sync.GroupId;
|
||||
import org.briarproject.api.sync.MessageId;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.briarproject.api.identity.Author.Status.OURSELVES;
|
||||
import static org.briarproject.api.privategroup.Visibility.INVISIBLE;
|
||||
import static org.briarproject.api.privategroup.Visibility.REVEALED_BY_CONTACT;
|
||||
import static org.briarproject.api.privategroup.Visibility.REVEALED_BY_US;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* This class tests how PrivateGroupManager and GroupInvitationManager
|
||||
* play together.
|
||||
*/
|
||||
public class PrivateGroupIntegrationTest extends BriarIntegrationTest {
|
||||
|
||||
private GroupId groupId0;
|
||||
private PrivateGroup privateGroup0;
|
||||
private PrivateGroupManager groupManager0, groupManager1, groupManager2;
|
||||
private GroupInvitationManager groupInvitationManager0,
|
||||
groupInvitationManager1, groupInvitationManager2;
|
||||
|
||||
@Before
|
||||
@Override
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
|
||||
groupManager0 = c0.getPrivateGroupManager();
|
||||
groupManager1 = c1.getPrivateGroupManager();
|
||||
groupManager2 = c2.getPrivateGroupManager();
|
||||
groupInvitationManager0 = c0.getGroupInvitationManager();
|
||||
groupInvitationManager1 = c1.getGroupInvitationManager();
|
||||
groupInvitationManager2 = c2.getGroupInvitationManager();
|
||||
|
||||
privateGroup0 =
|
||||
privateGroupFactory.createPrivateGroup("Test Group", author0);
|
||||
groupId0 = privateGroup0.getId();
|
||||
long joinTime = clock.currentTimeMillis();
|
||||
GroupMessage joinMsg0 = groupMessageFactory
|
||||
.createJoinMessage(groupId0, joinTime, author0);
|
||||
groupManager0.addPrivateGroup(privateGroup0, joinMsg0, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMembership() throws Exception {
|
||||
sendInvitation(contactId1From0, clock.currentTimeMillis(), "Hi!");
|
||||
|
||||
// our group has only one member (ourselves)
|
||||
Collection<GroupMember> members = groupManager0.getMembers(groupId0);
|
||||
assertEquals(1, members.size());
|
||||
assertEquals(author0, members.iterator().next().getAuthor());
|
||||
assertEquals(OURSELVES, members.iterator().next().getStatus());
|
||||
|
||||
sync0To1(1, true);
|
||||
groupInvitationManager1
|
||||
.respondToInvitation(contactId0From1, privateGroup0, true);
|
||||
sync1To0(1, true);
|
||||
|
||||
// sync group join messages
|
||||
sync0To1(2, true); // + one invitation protocol join message
|
||||
sync1To0(1, true);
|
||||
|
||||
// now the group has two members
|
||||
members = groupManager0.getMembers(groupId0);
|
||||
assertEquals(2, members.size());
|
||||
for (GroupMember m : members) {
|
||||
if (m.getStatus() == OURSELVES) {
|
||||
assertEquals(author0.getId(), m.getAuthor().getId());
|
||||
} else {
|
||||
assertEquals(author1.getId(), m.getAuthor().getId());
|
||||
}
|
||||
}
|
||||
|
||||
members = groupManager1.getMembers(groupId0);
|
||||
assertEquals(2, members.size());
|
||||
for (GroupMember m : members) {
|
||||
if (m.getStatus() == OURSELVES) {
|
||||
assertEquals(author1.getId(), m.getAuthor().getId());
|
||||
} else {
|
||||
assertEquals(author0.getId(), m.getAuthor().getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRevealContacts() throws Exception {
|
||||
// invite two contacts
|
||||
sendInvitation(contactId1From0, clock.currentTimeMillis(), "Hi 1!");
|
||||
sendInvitation(contactId2From0, clock.currentTimeMillis(), "Hi 2!");
|
||||
sync0To1(1, true);
|
||||
sync0To2(1, true);
|
||||
|
||||
// accept both invitations
|
||||
groupInvitationManager1
|
||||
.respondToInvitation(contactId0From1, privateGroup0, true);
|
||||
groupInvitationManager2
|
||||
.respondToInvitation(contactId0From2, privateGroup0, true);
|
||||
sync1To0(1, true);
|
||||
sync2To0(1, true);
|
||||
|
||||
// sync group join messages
|
||||
sync0To1(2, true); // + one invitation protocol join message
|
||||
assertEquals(2, groupManager1.getMembers(groupId0).size());
|
||||
sync1To0(1, true);
|
||||
assertEquals(2, groupManager0.getMembers(groupId0).size());
|
||||
sync0To2(3, true); // 2 join messages and 1 invite join message
|
||||
assertEquals(3, groupManager2.getMembers(groupId0).size());
|
||||
sync2To0(1, true);
|
||||
assertEquals(3, groupManager0.getMembers(groupId0).size());
|
||||
sync0To1(1, true);
|
||||
assertEquals(3, groupManager1.getMembers(groupId0).size());
|
||||
|
||||
// 1 and 2 add each other as contacts
|
||||
addContacts1And2();
|
||||
|
||||
// their relationship is still invisible
|
||||
assertEquals(INVISIBLE,
|
||||
getGroupMember(groupManager1, author2.getId()).getVisibility());
|
||||
assertEquals(INVISIBLE,
|
||||
getGroupMember(groupManager2, author1.getId()).getVisibility());
|
||||
|
||||
// 1 reveals the contact relationship to 2
|
||||
assertTrue(contactId2From1 != null);
|
||||
groupInvitationManager1.revealRelationship(contactId2From1, groupId0);
|
||||
sync1To2(1, true);
|
||||
sync2To1(1, true);
|
||||
|
||||
// their relationship is now revealed
|
||||
assertEquals(REVEALED_BY_US,
|
||||
getGroupMember(groupManager1, author2.getId()).getVisibility());
|
||||
assertEquals(REVEALED_BY_CONTACT,
|
||||
getGroupMember(groupManager2, author1.getId()).getVisibility());
|
||||
|
||||
// 2 sends a message to the group
|
||||
long time = clock.currentTimeMillis();
|
||||
String body = "This is a test message!";
|
||||
MessageId previousMsgId = groupManager2.getPreviousMsgId(groupId0);
|
||||
GroupMessage msg = groupMessageFactory
|
||||
.createGroupMessage(groupId0, time, null, author2, body,
|
||||
previousMsgId);
|
||||
groupManager2.addLocalMessage(msg);
|
||||
|
||||
// 1 has only the three join messages in the group
|
||||
Collection<GroupMessageHeader> headers =
|
||||
groupManager1.getHeaders(groupId0);
|
||||
assertEquals(3, headers.size());
|
||||
|
||||
// message should sync to 1 without creator (0) being involved
|
||||
sync2To1(1, true);
|
||||
headers = groupManager1.getHeaders(groupId0);
|
||||
assertEquals(4, headers.size());
|
||||
boolean foundPost = false;
|
||||
for (GroupMessageHeader h : headers) {
|
||||
if (h instanceof JoinMessageHeader) continue;
|
||||
foundPost = true;
|
||||
assertEquals(time, h.getTimestamp());
|
||||
assertEquals(groupId0, h.getGroupId());
|
||||
assertEquals(author2.getId(), h.getAuthor().getId());
|
||||
}
|
||||
assertTrue(foundPost);
|
||||
|
||||
// message should sync from 1 to 0 without 2 being involved
|
||||
sync1To0(1, true);
|
||||
headers = groupManager0.getHeaders(groupId0);
|
||||
assertEquals(4, headers.size());
|
||||
}
|
||||
|
||||
private void sendInvitation(ContactId c, long timestamp,
|
||||
@Nullable String msg) throws DbException {
|
||||
Contact contact = contactManager0.getContact(c);
|
||||
byte[] signature = groupInvitationFactory
|
||||
.signInvitation(contact, groupId0, timestamp,
|
||||
author0.getPrivateKey());
|
||||
groupInvitationManager0
|
||||
.sendInvitation(groupId0, c, msg, timestamp, signature);
|
||||
}
|
||||
|
||||
private GroupMember getGroupMember(PrivateGroupManager groupManager,
|
||||
AuthorId a) throws DbException {
|
||||
Collection<GroupMember> members = groupManager.getMembers(groupId0);
|
||||
for (GroupMember m : members) {
|
||||
if (m.getAuthor().getId().equals(a)) return m;
|
||||
}
|
||||
throw new AssertionError();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -74,7 +74,7 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
|
||||
private final Group localGroup;
|
||||
|
||||
@Inject
|
||||
protected GroupInvitationManagerImpl(DatabaseComponent db,
|
||||
GroupInvitationManagerImpl(DatabaseComponent db,
|
||||
ClientHelper clientHelper, MetadataParser metadataParser,
|
||||
MessageTracker messageTracker,
|
||||
ContactGroupFactory contactGroupFactory,
|
||||
|
||||
@@ -148,10 +148,11 @@ class InviteeProtocolEngine extends AbstractProtocolEngine<InviteeSession> {
|
||||
case DISSOLVED:
|
||||
return abort(txn, s); // Invalid in these states
|
||||
case INVITED:
|
||||
case LEFT:
|
||||
return onRemoteLeaveWhenNotSubscribed(txn, s, m);
|
||||
case ACCEPTED:
|
||||
case JOINED:
|
||||
case LEFT:
|
||||
return onRemoteLeave(txn, s, m);
|
||||
return onRemoteLeaveWhenSubscribed(txn, s, m);
|
||||
case ERROR:
|
||||
return s; // Ignored in this state
|
||||
default:
|
||||
@@ -260,8 +261,23 @@ class InviteeProtocolEngine extends AbstractProtocolEngine<InviteeSession> {
|
||||
s.getInviteTimestamp(), JOINED);
|
||||
}
|
||||
|
||||
private InviteeSession onRemoteLeave(Transaction txn, InviteeSession s,
|
||||
LeaveMessage m) throws DbException, FormatException {
|
||||
private InviteeSession onRemoteLeaveWhenNotSubscribed(Transaction txn,
|
||||
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
|
||||
if (m.getTimestamp() <= s.getInviteTimestamp()) return abort(txn, s);
|
||||
// The dependency, if any, must be the last remote message
|
||||
|
||||
@@ -8,7 +8,6 @@ import org.briarproject.api.clients.BdfMessageContext;
|
||||
import org.briarproject.api.data.BdfDictionary;
|
||||
import org.briarproject.api.data.BdfList;
|
||||
import org.briarproject.api.identity.Author;
|
||||
import org.briarproject.api.identity.AuthorFactory;
|
||||
import org.briarproject.api.identity.AuthorId;
|
||||
import org.briarproject.api.sync.InvalidMessageException;
|
||||
import org.briarproject.api.sync.MessageId;
|
||||
@@ -29,9 +28,6 @@ import static org.junit.Assert.assertFalse;
|
||||
|
||||
public class ForumPostValidatorTest extends ValidatorTestCase {
|
||||
|
||||
private final AuthorFactory authorFactory =
|
||||
context.mock(AuthorFactory.class);
|
||||
|
||||
private final MessageId parentId = new MessageId(TestUtils.getRandomId());
|
||||
private final String authorName =
|
||||
TestUtils.getRandomString(MAX_AUTHOR_NAME_LENGTH);
|
||||
|
||||
Reference in New Issue
Block a user