From b0b932a01c900a6d161d7f5aefb4de7429ede16f Mon Sep 17 00:00:00 2001 From: Torsten Grote Date: Fri, 18 Nov 2016 18:03:00 -0200 Subject: [PATCH 1/2] Add unit tests for group invitation client --- .../GroupInvitationManagerImplTest.java | 924 ++++++++++++++++++ 1 file changed, 924 insertions(+) create mode 100644 briar-tests/src/org/briarproject/privategroup/invitation/GroupInvitationManagerImplTest.java diff --git a/briar-tests/src/org/briarproject/privategroup/invitation/GroupInvitationManagerImplTest.java b/briar-tests/src/org/briarproject/privategroup/invitation/GroupInvitationManagerImplTest.java new file mode 100644 index 000000000..93ffeb3bf --- /dev/null +++ b/briar-tests/src/org/briarproject/privategroup/invitation/GroupInvitationManagerImplTest.java @@ -0,0 +1,924 @@ +package org.briarproject.privategroup.invitation; + +import org.briarproject.BriarMockTestCase; +import org.briarproject.TestUtils; +import org.briarproject.api.FormatException; +import org.briarproject.api.clients.ClientHelper; +import org.briarproject.api.clients.ContactGroupFactory; +import org.briarproject.api.clients.MessageTracker; +import org.briarproject.api.clients.SessionId; +import org.briarproject.api.contact.Contact; +import org.briarproject.api.contact.ContactId; +import org.briarproject.api.data.BdfDictionary; +import org.briarproject.api.data.BdfEntry; +import org.briarproject.api.data.BdfList; +import org.briarproject.api.data.MetadataParser; +import org.briarproject.api.db.DatabaseComponent; +import org.briarproject.api.db.DbException; +import org.briarproject.api.db.Metadata; +import org.briarproject.api.db.Transaction; +import org.briarproject.api.identity.Author; +import org.briarproject.api.identity.AuthorId; +import org.briarproject.api.privategroup.PrivateGroup; +import org.briarproject.api.privategroup.PrivateGroupFactory; +import org.briarproject.api.privategroup.PrivateGroupManager; +import org.briarproject.api.privategroup.invitation.GroupInvitationItem; +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.briarproject.api.sync.GroupId; +import org.briarproject.api.sync.Message; +import org.briarproject.api.sync.MessageId; +import org.jetbrains.annotations.Nullable; +import org.jmock.AbstractExpectations; +import org.jmock.Expectations; +import org.jmock.lib.legacy.ClassImposteriser; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +import static junit.framework.TestCase.fail; +import static org.briarproject.TestUtils.getRandomBytes; +import static org.briarproject.TestUtils.getRandomId; +import static org.briarproject.TestUtils.getRandomString; +import static org.briarproject.api.privategroup.invitation.GroupInvitationManager.CLIENT_ID; +import static org.briarproject.api.sync.Group.Visibility.SHARED; +import static org.briarproject.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH; +import static org.briarproject.privategroup.invitation.GroupInvitationConstants.GROUP_KEY_CONTACT_ID; +import static org.briarproject.privategroup.invitation.MessageType.ABORT; +import static org.briarproject.privategroup.invitation.MessageType.INVITE; +import static org.briarproject.privategroup.invitation.MessageType.JOIN; +import static org.briarproject.privategroup.invitation.MessageType.LEAVE; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +public class GroupInvitationManagerImplTest extends BriarMockTestCase { + + private final GroupInvitationManagerImpl groupInvitationManager; + private final DatabaseComponent db = context.mock(DatabaseComponent.class); + private final ClientHelper clientHelper = context.mock(ClientHelper.class); + private final ContactGroupFactory contactGroupFactory = + context.mock(ContactGroupFactory.class); + private final PrivateGroupFactory privateGroupFactory = + context.mock(PrivateGroupFactory.class); + private final PrivateGroupManager privateGroupManager = + context.mock(PrivateGroupManager.class); + private final MessageParser messageParser = + context.mock(MessageParser.class); + private final SessionParser sessionParser = + context.mock(SessionParser.class); + private final SessionEncoder sessionEncoder = + context.mock(SessionEncoder.class); + private final ProtocolEngineFactory engineFactory = + context.mock(ProtocolEngineFactory.class); + private final CreatorProtocolEngine creatorEngine; + private final InviteeProtocolEngine inviteeEngine; + private final PeerProtocolEngine peerEngine; + private final CreatorSession creatorSession; + private final InviteeSession inviteeSession; + private final PeerSession peerSession; + private final Group localGroup = + new Group(new GroupId(getRandomId()), CLIENT_ID, getRandomBytes(5)); + private final Transaction txn = new Transaction(null, false); + private final ContactId contactId = new ContactId(0); + private final Author author = + new Author(new AuthorId(getRandomId()), getRandomString(5), + getRandomBytes(5)); + private final Contact contact = + new Contact(contactId, author, new AuthorId(getRandomId()), true, + true); + private final Group contactGroup = + new Group(new GroupId(getRandomId()), CLIENT_ID, getRandomBytes(5)); + private final Group privateGroup = + new Group(new GroupId(getRandomId()), CLIENT_ID, getRandomBytes(5)); + private final BdfDictionary meta = BdfDictionary.of(new BdfEntry("f", "o")); + private final Message message = + new Message(new MessageId(getRandomId()), contactGroup.getId(), + 0L, getRandomBytes(MESSAGE_HEADER_LENGTH + 1)); + private final BdfList body = new BdfList(); + private final Message storageMessage = + new Message(new MessageId(getRandomId()), contactGroup.getId(), + 0L, getRandomBytes(MESSAGE_HEADER_LENGTH + 1)); + + public GroupInvitationManagerImplTest() { + context.setImposteriser(ClassImposteriser.INSTANCE); + creatorEngine = context.mock(CreatorProtocolEngine.class); + inviteeEngine = context.mock(InviteeProtocolEngine.class); + peerEngine = context.mock(PeerProtocolEngine.class); + + creatorSession = context.mock(CreatorSession.class); + inviteeSession = context.mock(InviteeSession.class); + peerSession = context.mock(PeerSession.class); + + context.checking(new Expectations() {{ + oneOf(engineFactory).createCreatorEngine(); + will(returnValue(creatorEngine)); + oneOf(engineFactory).createInviteeEngine(); + will(returnValue(inviteeEngine)); + oneOf(engineFactory).createPeerEngine(); + will(returnValue(peerEngine)); + oneOf(contactGroupFactory).createLocalGroup(CLIENT_ID); + will(returnValue(localGroup)); + }}); + MetadataParser metadataParser = context.mock(MetadataParser.class); + MessageTracker messageTracker = context.mock(MessageTracker.class); + groupInvitationManager = + new GroupInvitationManagerImpl(db, clientHelper, metadataParser, + messageTracker, contactGroupFactory, + privateGroupFactory, privateGroupManager, messageParser, + sessionParser, sessionEncoder, engineFactory); + } + + @Test + public void testCreateLocalState() throws Exception { + context.checking(new Expectations() {{ + oneOf(db).addGroup(txn, localGroup); + oneOf(db).getContacts(txn); + will(returnValue(Collections.singletonList(contact))); + }}); + expectAddingContact(contact, true); + groupInvitationManager.createLocalState(txn); + } + + private void expectAddingContact(final Contact c, + final boolean contactExists) throws Exception { + context.checking(new Expectations() {{ + oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, c); + will(returnValue(contactGroup)); + oneOf(db).containsGroup(txn, contactGroup.getId()); + will(returnValue(contactExists)); + }}); + if (contactExists) return; + + final BdfDictionary meta = BdfDictionary + .of(new BdfEntry(GROUP_KEY_CONTACT_ID, c.getId().getInt())); + context.checking(new Expectations() {{ + oneOf(db).addGroup(txn, contactGroup); + oneOf(db).setGroupVisibility(txn, c.getId(), contactGroup.getId(), + SHARED); + oneOf(clientHelper) + .mergeGroupMetadata(txn, contactGroup.getId(), meta); + oneOf(db).getGroups(txn, PrivateGroupManager.CLIENT_ID); + will(returnValue(Collections.singletonList(privateGroup))); + oneOf(privateGroupManager) + .isMember(txn, privateGroup.getId(), c.getAuthor()); + will(returnValue(true)); + }}); + expectAddingMember(privateGroup.getId(), c); + } + + private void expectAddingMember(final GroupId g, final Contact c) + throws Exception { + context.checking(new Expectations() {{ + oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, c); + will(returnValue(contactGroup)); + }}); + expectGetSession(Collections.emptyMap(), + new SessionId(g.getBytes())); + + context.checking(new Expectations() {{ + oneOf(peerEngine).onMemberAddedAction(with(equal(txn)), + with(any(PeerSession.class))); + will(returnValue(peerSession)); + }}); + expectStoreSession(peerSession, storageMessage.getId()); + expectCreateStorageId(); + } + + private void expectCreateStorageId() throws DbException { + context.checking(new Expectations() {{ + oneOf(clientHelper) + .createMessageForStoringMetadata(contactGroup.getId()); + will(returnValue(storageMessage)); + oneOf(db).addLocalMessage(txn, storageMessage, new Metadata(), + false); + }}); + } + + private void expectStoreSession(final Session session, + final MessageId storageId) throws Exception { + context.checking(new Expectations() {{ + oneOf(sessionEncoder).encodeSession(session); + will(returnValue(meta)); + oneOf(clientHelper).mergeMessageMetadata(txn, storageId, meta); + }}); + } + + private void expectGetSession(final Map result, + final SessionId sessionId) throws Exception { + final BdfDictionary query = BdfDictionary.of(new BdfEntry("q", "u")); + context.checking(new Expectations() {{ + oneOf(sessionParser).getSessionQuery(sessionId); + will(returnValue(query)); + oneOf(clientHelper) + .getMessageMetadataAsDictionary(txn, contactGroup.getId(), + query); + will(returnValue(result)); + }}); + } + + @Test + public void testAddingContact() throws Exception { + expectAddingContact(contact, false); + groupInvitationManager.addingContact(txn, contact); + } + + @Test + public void testRemovingContact() throws Exception { + context.checking(new Expectations() {{ + oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact); + will(returnValue(contactGroup)); + oneOf(db).removeGroup(txn, contactGroup); + }}); + groupInvitationManager.removingContact(txn, contact); + } + + @Test(expected = FormatException.class) + public void testIncomingUnknownMessage() throws Exception { + expectFirstIncomingMessage(Role.INVITEE, ABORT); + groupInvitationManager.incomingMessage(txn, message, body, meta); + } + + @Test + public void testIncomingFirstInviteMessage() throws Exception { + expectFirstIncomingMessage(Role.INVITEE, INVITE); + groupInvitationManager.incomingMessage(txn, message, body, meta); + } + + @Test + public void testIncomingFirstJoinMessage() throws Exception { + expectFirstIncomingMessage(Role.PEER, JOIN); + groupInvitationManager.incomingMessage(txn, message, body, meta); + } + + @Test + public void testIncomingInviteMessage() throws Exception { + expectIncomingMessage(Role.INVITEE, INVITE); + groupInvitationManager.incomingMessage(txn, message, body, meta); + } + + @Test + public void testIncomingJoinMessage() throws Exception { + expectIncomingMessage(Role.INVITEE, JOIN); + groupInvitationManager.incomingMessage(txn, message, body, meta); + } + + @Test + public void testIncomingJoinMessageForCreator() throws Exception { + expectIncomingMessage(Role.CREATOR, JOIN); + groupInvitationManager.incomingMessage(txn, message, body, meta); + } + + @Test + public void testIncomingLeaveMessage() throws Exception { + expectIncomingMessage(Role.INVITEE, LEAVE); + groupInvitationManager.incomingMessage(txn, message, body, meta); + } + + @Test + public void testIncomingAbortMessage() throws Exception { + expectIncomingMessage(Role.INVITEE, ABORT); + groupInvitationManager.incomingMessage(txn, message, body, meta); + } + + private void expectFirstIncomingMessage(Role role, MessageType type) + throws Exception { + expectIncomingMessage(role, type, + Collections.emptyMap()); + } + + private void expectIncomingMessage(Role role, MessageType type) + throws Exception { + BdfDictionary state = BdfDictionary.of(new BdfEntry("state", "test")); + Map states = + Collections.singletonMap(storageMessage.getId(), state); + expectIncomingMessage(role, type, states); + } + + private void expectIncomingMessage(final Role role, + final MessageType type, final Map states) + throws Exception { + final MessageMetadata messageMetadata = + context.mock(MessageMetadata.class); + context.checking(new Expectations() {{ + oneOf(messageParser).parseMetadata(meta); + will(returnValue(messageMetadata)); + oneOf(messageMetadata).getPrivateGroupId(); + will(returnValue(privateGroup.getId())); + }}); + expectGetSession(states, + new SessionId(privateGroup.getId().getBytes())); + + Session session; + if (states.isEmpty()) { + session = expectHandleFirstMessage(role, messageMetadata, type); + if (session != null) { + expectCreateStorageId(); + expectStoreSession(session, storageMessage.getId()); + } + } else { + assertEquals(1, states.size()); + session = expectHandleMessage(role, messageMetadata, + states.values().iterator().next(), type); + expectStoreSession(session, storageMessage.getId()); + } + } + + @Nullable + private Session expectHandleFirstMessage(Role role, + final MessageMetadata messageMetadata, final MessageType type) + throws Exception { + context.checking(new Expectations() {{ + oneOf(messageMetadata).getPrivateGroupId(); + will(returnValue(privateGroup.getId())); + oneOf(messageMetadata).getMessageType(); + will(returnValue(type)); + }}); + if (type == ABORT || type == LEAVE) return null; + + AbstractProtocolEngine engine; + Session session; + if (type == INVITE) { + assertEquals(Role.INVITEE, role); + engine = inviteeEngine; + session = inviteeSession; + } else if (type == JOIN) { + assertEquals(Role.PEER, role); + engine = peerEngine; + session = peerSession; + } else { + throw new RuntimeException(); + } + expectIndividualMessage(type, engine, session); + return session; + } + + @Nullable + private Session expectHandleMessage(final Role role, + final MessageMetadata messageMetadata, final BdfDictionary state, + final MessageType type) throws Exception { + context.checking(new Expectations() {{ + oneOf(messageMetadata).getMessageType(); + will(returnValue(type)); + oneOf(sessionParser).getRole(state); + will(returnValue(role)); + }}); + if (role == Role.CREATOR) { + context.checking(new Expectations() {{ + oneOf(sessionParser) + .parseCreatorSession(contactGroup.getId(), state); + will(returnValue(creatorSession)); + }}); + expectIndividualMessage(type, creatorEngine, creatorSession); + return creatorSession; + } else if (role == Role.INVITEE) { + context.checking(new Expectations() {{ + oneOf(sessionParser) + .parseInviteeSession(contactGroup.getId(), state); + will(returnValue(inviteeSession)); + }}); + expectIndividualMessage(type, inviteeEngine, inviteeSession); + return inviteeSession; + } else if (role == Role.PEER) { + context.checking(new Expectations() {{ + oneOf(sessionParser) + .parsePeerSession(contactGroup.getId(), state); + will(returnValue(peerSession)); + }}); + expectIndividualMessage(type, peerEngine, peerSession); + return peerSession; + } else { + fail(); + throw new RuntimeException(); + } + } + + private void expectIndividualMessage( + final MessageType type, final ProtocolEngine engine, + final S session) throws Exception { + if (type == INVITE) { + final InviteMessage msg = context.mock(InviteMessage.class); + context.checking(new Expectations() {{ + oneOf(messageParser).parseInviteMessage(message, body); + will(returnValue(msg)); + oneOf(engine).onInviteMessage(with(equal(txn)), + with(AbstractExpectations.anything()), + with(equal(msg))); + will(returnValue(session)); + }}); + } else if (type == JOIN) { + final JoinMessage msg = context.mock(JoinMessage.class); + context.checking(new Expectations() {{ + oneOf(messageParser).parseJoinMessage(message, body); + will(returnValue(msg)); + oneOf(engine).onJoinMessage(with(equal(txn)), + with(AbstractExpectations.anything()), + with(equal(msg))); + will(returnValue(session)); + }}); + } else if (type == LEAVE) { + final LeaveMessage msg = context.mock(LeaveMessage.class); + context.checking(new Expectations() {{ + oneOf(messageParser).parseLeaveMessage(message, body); + will(returnValue(msg)); + oneOf(engine).onLeaveMessage(with(equal(txn)), + with(AbstractExpectations.anything()), + with(equal(msg))); + will(returnValue(session)); + }}); + } else if (type == ABORT) { + final AbortMessage msg = context.mock(AbortMessage.class); + context.checking(new Expectations() {{ + oneOf(messageParser).parseAbortMessage(message, body); + will(returnValue(msg)); + oneOf(engine).onAbortMessage(with(equal(txn)), + with(AbstractExpectations.anything()), + with(equal(msg))); + will(returnValue(session)); + }}); + } else { + fail(); + } + } + + @Test + public void testSendFirstInvitation() throws Exception { + final String msg = "Invitation text for first invitation"; + final long time = 42L; + final byte[] signature = TestUtils.getRandomBytes(42); + Map states = Collections.emptyMap(); + + expectGetSession(states, + new SessionId(privateGroup.getId().getBytes())); + context.checking(new Expectations() {{ + oneOf(db).startTransaction(false); + will(returnValue(txn)); + oneOf(db).getContact(txn, contactId); + will(returnValue(contact)); + oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact); + will(returnValue(contactGroup)); + }}); + expectCreateStorageId(); + context.checking(new Expectations() {{ + oneOf(creatorEngine).onInviteAction(with(same(txn)), + with(any(CreatorSession.class)), with(equal(msg)), + with(equal(time)), with(equal(signature))); + will(returnValue(creatorSession)); + }}); + expectStoreSession(creatorSession, storageMessage.getId()); + context.checking(new Expectations() {{ + oneOf(db).commitTransaction(txn); + oneOf(db).endTransaction(txn); + }}); + groupInvitationManager.sendInvitation(privateGroup.getId(), contactId, + msg, time, signature); + } + + @Test + public void testSendSubsequentInvitation() throws Exception { + final String msg = "Invitation text for subsequent invitation"; + final long time = 43L; + final byte[] signature = TestUtils.getRandomBytes(43); + final BdfDictionary state = + BdfDictionary.of(new BdfEntry("state", "test")); + Map states = + Collections.singletonMap(storageMessage.getId(), state); + + expectGetSession(states, + new SessionId(privateGroup.getId().getBytes())); + context.checking(new Expectations() {{ + oneOf(db).startTransaction(false); + will(returnValue(txn)); + oneOf(db).getContact(txn, contactId); + will(returnValue(contact)); + oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact); + will(returnValue(contactGroup)); + oneOf(sessionParser) + .parseCreatorSession(contactGroup.getId(), state); + will(returnValue(creatorSession)); + oneOf(creatorEngine).onInviteAction(with(same(txn)), + with(any(CreatorSession.class)), with(equal(msg)), + with(equal(time)), with(equal(signature))); + will(returnValue(creatorSession)); + }}); + expectStoreSession(creatorSession, storageMessage.getId()); + context.checking(new Expectations() {{ + oneOf(db).commitTransaction(txn); + oneOf(db).endTransaction(txn); + }}); + groupInvitationManager.sendInvitation(privateGroup.getId(), contactId, + msg, time, signature); + } + + @Test(expected = IllegalArgumentException.class) + public void testRespondToInvitationWithoutSession() throws Exception { + final SessionId sessionId = new SessionId(getRandomId()); + + context.checking(new Expectations() {{ + oneOf(db).startTransaction(false); + will(returnValue(txn)); + oneOf(db).getContact(txn, contactId); + will(returnValue(contact)); + oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact); + will(returnValue(contactGroup)); + oneOf(db).endTransaction(txn); + }}); + expectGetSession(Collections.emptyMap(), + sessionId); + + groupInvitationManager.respondToInvitation(contactId, sessionId, true); + } + + @Test + public void testAcceptInvitationWithSession() throws Exception { + final boolean accept = true; + SessionId sessionId = new SessionId(getRandomId()); + BdfDictionary state = BdfDictionary.of(new BdfEntry("f", "o")); + Map states = + Collections.singletonMap(storageMessage.getId(), state); + + expectRespondToInvitation(states, sessionId, accept); + groupInvitationManager + .respondToInvitation(contactId, sessionId, accept); + } + + @Test + public void testDeclineInvitationWithSession() throws Exception { + final boolean accept = false; + SessionId sessionId = new SessionId(getRandomId()); + BdfDictionary state = BdfDictionary.of(new BdfEntry("f", "o")); + Map states = + Collections.singletonMap(storageMessage.getId(), state); + + expectRespondToInvitation(states, sessionId, accept); + groupInvitationManager + .respondToInvitation(contactId, sessionId, accept); + } + + @Test + public void testRespondToInvitationWithGroupId() throws Exception { + final boolean accept = true; + final PrivateGroup g = context.mock(PrivateGroup.class); + SessionId sessionId = new SessionId(privateGroup.getId().getBytes()); + BdfDictionary state = BdfDictionary.of(new BdfEntry("f", "o")); + Map states = + Collections.singletonMap(storageMessage.getId(), state); + + context.checking(new Expectations() {{ + oneOf(g).getId(); + will(returnValue(privateGroup.getId())); + }}); + expectRespondToInvitation(states, sessionId, accept); + groupInvitationManager.respondToInvitation(contactId, g, accept); + } + + private void expectRespondToInvitation( + final Map states, + final SessionId sessionId, final boolean accept) throws Exception { + expectGetSession(states, sessionId); + context.checking(new Expectations() {{ + oneOf(db).startTransaction(false); + will(returnValue(txn)); + oneOf(db).getContact(txn, contactId); + will(returnValue(contact)); + oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact); + will(returnValue(contactGroup)); + }}); + + if (states.isEmpty()) return; + assertEquals(1, states.size()); + + final BdfDictionary state = states.values().iterator().next(); + context.checking(new Expectations() {{ + oneOf(sessionParser) + .parseInviteeSession(contactGroup.getId(), state); + will(returnValue(inviteeSession)); + if (accept) oneOf(inviteeEngine).onJoinAction(txn, inviteeSession); + else oneOf(inviteeEngine).onLeaveAction(txn, inviteeSession); + will(returnValue(inviteeSession)); + oneOf(db).commitTransaction(txn); + oneOf(db).endTransaction(txn); + }}); + expectStoreSession(inviteeSession, storageMessage.getId()); + } + + @Test + public void testRevealRelationship() throws Exception { + SessionId sessionId = new SessionId(privateGroup.getId().getBytes()); + final BdfDictionary state = BdfDictionary.of(new BdfEntry("f", "o")); + Map states = + Collections.singletonMap(storageMessage.getId(), state); + + context.checking(new Expectations() {{ + oneOf(db).startTransaction(false); + will(returnValue(txn)); + oneOf(db).getContact(txn, contactId); + will(returnValue(contact)); + oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact); + will(returnValue(contactGroup)); + oneOf(sessionParser).parsePeerSession(contactGroup.getId(), state); + will(returnValue(peerSession)); + oneOf(peerEngine).onJoinAction(txn, peerSession); + will(returnValue(peerSession)); + oneOf(db).commitTransaction(txn); + oneOf(db).endTransaction(txn); + }}); + expectGetSession(states, sessionId); + expectStoreSession(peerSession, storageMessage.getId()); + + groupInvitationManager + .revealRelationship(contactId, privateGroup.getId()); + } + + @Test(expected = IllegalArgumentException.class) + public void testRevealRelationshipWithoutSession() throws Exception { + SessionId sessionId = new SessionId(privateGroup.getId().getBytes()); + + context.checking(new Expectations() {{ + oneOf(db).startTransaction(false); + will(returnValue(txn)); + oneOf(db).getContact(txn, contactId); + will(returnValue(contact)); + oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact); + will(returnValue(contactGroup)); + oneOf(db).endTransaction(txn); + }}); + expectGetSession(Collections.emptyMap(), + sessionId); + + groupInvitationManager + .revealRelationship(contactId, privateGroup.getId()); + } + + @Test + public void testGetInvitationMessages() throws Exception { + final BdfDictionary query = new BdfDictionary(); + final BdfDictionary d1 = BdfDictionary.of(new BdfEntry("m1", "d")); + final BdfDictionary d2 = BdfDictionary.of(new BdfEntry("m2", "d")); + final Map results = new HashMap<>(); + results.put(message.getId(), d1); + results.put(storageMessage.getId(), d2); + long time1 = 1L, time2 = 2L; + final MessageMetadata meta1 = + new MessageMetadata(INVITE, privateGroup.getId(), time1, true, + true, true, true); + final MessageMetadata meta2 = + new MessageMetadata(JOIN, privateGroup.getId(), time2, true, + true, true, true); + final BdfList list1 = BdfList.of(1); + + context.checking(new Expectations() {{ + oneOf(db).startTransaction(true); + will(returnValue(txn)); + oneOf(db).getContact(txn, contactId); + will(returnValue(contact)); + oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact); + will(returnValue(contactGroup)); + oneOf(messageParser).getMessagesVisibleInUiQuery(); + will(returnValue(query)); + oneOf(clientHelper) + .getMessageMetadataAsDictionary(txn, contactGroup.getId(), + query); + will(returnValue(results)); + // first message + oneOf(messageParser).parseMetadata(d1); + will(returnValue(meta1)); + oneOf(db).getMessageStatus(txn, contactId, message.getId()); + oneOf(clientHelper).getMessage(txn, message.getId()); + will(returnValue(message)); + oneOf(clientHelper).toList(message); + will(returnValue(list1)); + oneOf(messageParser).parseInviteMessage(message, list1); + // second message + oneOf(messageParser).parseMetadata(d2); + will(returnValue(meta2)); + oneOf(db).getMessageStatus(txn, contactId, storageMessage.getId()); + // end transaction + oneOf(db).commitTransaction(txn); + oneOf(db).endTransaction(txn); + }}); + + Collection messages = + groupInvitationManager.getInvitationMessages(contactId); + assertEquals(2, messages.size()); + for (InvitationMessage m : messages) { + assertEquals(contactGroup.getId(), m.getGroupId()); + assertEquals(contactId, m.getContactId()); + if (m.getId().equals(message.getId())) { + assertTrue(m instanceof GroupInvitationRequest); + assertEquals(time1, m.getTimestamp()); + } else if (m.getId().equals(storageMessage.getId())) { + assertTrue(m instanceof GroupInvitationResponse); + assertEquals(time2, m.getTimestamp()); + } + } + } + + @Test + public void testGetInvitations() throws Exception { + final BdfDictionary query = new BdfDictionary(); + BdfDictionary d1 = BdfDictionary.of(new BdfEntry("m1", "d")); + BdfDictionary d2 = BdfDictionary.of(new BdfEntry("m2", "d")); + final Map results = new HashMap<>(); + results.put(message.getId(), d1); + results.put(storageMessage.getId(), d2); + final BdfList list1 = BdfList.of(1); + final BdfList list2 = BdfList.of(2); + long time1 = 1L, time2 = 2L; + final InviteMessage m1 = + new InviteMessage(message.getId(), contactGroup.getId(), + privateGroup.getId(), time1, "test", author, + getRandomBytes(5), null, getRandomBytes(5)); + final InviteMessage m2 = + new InviteMessage(message.getId(), contactGroup.getId(), + privateGroup.getId(), time2, "test", author, + getRandomBytes(5), null, getRandomBytes(5)); + final PrivateGroup g = context.mock(PrivateGroup.class); + + context.checking(new Expectations() {{ + oneOf(messageParser).getInvitesAvailableToAnswerQuery(); + will(returnValue(query)); + oneOf(db).startTransaction(true); + will(returnValue(txn)); + oneOf(db).getContacts(txn); + will(returnValue(Collections.singletonList(contact))); + oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact); + will(returnValue(contactGroup)); + oneOf(clientHelper) + .getMessageMetadataAsDictionary(txn, contactGroup.getId(), + query); + will(returnValue(results)); + // message 1 + oneOf(clientHelper).getMessage(txn, message.getId()); + will(returnValue(message)); + oneOf(clientHelper).toList(message); + will(returnValue(list1)); + oneOf(messageParser).parseInviteMessage(message, list1); + will(returnValue(m1)); + oneOf(privateGroupFactory) + .createPrivateGroup(m1.getGroupName(), m1.getCreator(), + m1.getSalt()); + will(returnValue(g)); + // message 2 + oneOf(clientHelper).getMessage(txn, storageMessage.getId()); + will(returnValue(storageMessage)); + oneOf(clientHelper).toList(storageMessage); + will(returnValue(list2)); + oneOf(messageParser).parseInviteMessage(storageMessage, list2); + will(returnValue(m2)); + oneOf(privateGroupFactory) + .createPrivateGroup(m2.getGroupName(), m2.getCreator(), + m2.getSalt()); + will(returnValue(g)); + // end transaction + oneOf(db).commitTransaction(txn); + oneOf(db).endTransaction(txn); + }}); + + Collection items = + groupInvitationManager.getInvitations(); + assertEquals(2, items.size()); + for (GroupInvitationItem i : items) { + assertEquals(contact, i.getCreator()); + assertEquals(author, i.getCreator().getAuthor()); + } + } + + @Test + public void testIsInvitationAllowed() throws Exception { + expectIsInvitationAllowed(CreatorState.START); + assertTrue(groupInvitationManager + .isInvitationAllowed(contact, privateGroup.getId())); + } + + @Test + public void testIsNotInvitationAllowed() throws Exception { + expectIsInvitationAllowed(CreatorState.DISSOLVED); + assertFalse(groupInvitationManager + .isInvitationAllowed(contact, privateGroup.getId())); + + expectIsInvitationAllowed(CreatorState.ERROR); + assertFalse(groupInvitationManager + .isInvitationAllowed(contact, privateGroup.getId())); + + expectIsInvitationAllowed(CreatorState.INVITED); + assertFalse(groupInvitationManager + .isInvitationAllowed(contact, privateGroup.getId())); + + expectIsInvitationAllowed(CreatorState.JOINED); + assertFalse(groupInvitationManager + .isInvitationAllowed(contact, privateGroup.getId())); + + expectIsInvitationAllowed(CreatorState.LEFT); + assertFalse(groupInvitationManager + .isInvitationAllowed(contact, privateGroup.getId())); + } + + private void expectIsInvitationAllowed(final CreatorState state) + throws Exception { + final SessionId sessionId = + new SessionId(privateGroup.getId().getBytes()); + final BdfDictionary meta = BdfDictionary.of(new BdfEntry("m", "d")); + final Map results = new HashMap<>(); + results.put(message.getId(), meta); + + expectGetSession(results, sessionId); + context.checking(new Expectations() {{ + oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact); + will(returnValue(contactGroup)); + oneOf(db).startTransaction(true); + will(returnValue(txn)); + oneOf(sessionParser) + .parseCreatorSession(contactGroup.getId(), meta); + will(returnValue(creatorSession)); + oneOf(creatorSession).getState(); + will(returnValue(state)); + oneOf(db).commitTransaction(txn); + oneOf(db).endTransaction(txn); + }}); + } + + @Test + public void testAddingMember() throws Exception { + expectAddingMember(privateGroup.getId(), contact); + context.checking(new Expectations() {{ + oneOf(db).getContactsByAuthorId(txn, author.getId()); + will(returnValue(Collections.singletonList(contact))); + }}); + groupInvitationManager.addingMember(txn, privateGroup.getId(), author); + } + + @Test + public void testRemovingGroupEndsSessions() throws Exception { + final Contact contact2 = + new Contact(new ContactId(2), author, author.getId(), true, + true); + final Contact contact3 = + new Contact(new ContactId(3), author, author.getId(), true, + true); + final Collection contacts = new ArrayList<>(); + contacts.add(contact); + contacts.add(contact2); + contacts.add(contact3); + final MessageId mId2 = new MessageId(getRandomId()); + final MessageId mId3 = new MessageId(getRandomId()); + final BdfDictionary meta1 = BdfDictionary.of(new BdfEntry("m1", "d")); + final BdfDictionary meta2 = BdfDictionary.of(new BdfEntry("m2", "d")); + final BdfDictionary meta3 = BdfDictionary.of(new BdfEntry("m3", "d")); + + expectGetSession( + Collections.singletonMap(storageMessage.getId(), meta1), + new SessionId(privateGroup.getId().getBytes())); + expectGetSession( + Collections.singletonMap(mId2, meta2), + new SessionId(privateGroup.getId().getBytes())); + expectGetSession( + Collections.singletonMap(mId3, meta3), + new SessionId(privateGroup.getId().getBytes())); + context.checking(new Expectations() {{ + oneOf(db).getContacts(txn); + will(returnValue(contacts)); + oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact); + will(returnValue(contactGroup)); + oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact2); + will(returnValue(contactGroup)); + oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact3); + will(returnValue(contactGroup)); + // session 1 + oneOf(sessionParser).getRole(meta1); + will(returnValue(Role.CREATOR)); + oneOf(sessionParser) + .parseCreatorSession(contactGroup.getId(), meta1); + will(returnValue(creatorSession)); + oneOf(creatorEngine).onLeaveAction(txn, creatorSession); + will(returnValue(creatorSession)); + // session 2 + oneOf(sessionParser).getRole(meta2); + will(returnValue(Role.INVITEE)); + oneOf(sessionParser) + .parseInviteeSession(contactGroup.getId(), meta2); + will(returnValue(inviteeSession)); + oneOf(inviteeEngine).onLeaveAction(txn, inviteeSession); + will(returnValue(inviteeSession)); + // session 3 + oneOf(sessionParser).getRole(meta3); + will(returnValue(Role.PEER)); + oneOf(sessionParser) + .parsePeerSession(contactGroup.getId(), meta3); + will(returnValue(peerSession)); + oneOf(peerEngine).onLeaveAction(txn, peerSession); + will(returnValue(peerSession)); + }}); + expectStoreSession(creatorSession, storageMessage.getId()); + expectStoreSession(inviteeSession, mId2); + expectStoreSession(peerSession, mId3); + groupInvitationManager.removingGroup(txn, privateGroup.getId()); + } + +} From 90124e00ca95f5550593400f080639953570549d Mon Sep 17 00:00:00 2001 From: akwizgran Date: Tue, 29 Nov 2016 11:36:12 +0000 Subject: [PATCH 2/2] Addressed review comments. --- .../GroupInvitationManagerImplTest.java | 427 ++++++++---------- 1 file changed, 200 insertions(+), 227 deletions(-) diff --git a/briar-tests/src/org/briarproject/privategroup/invitation/GroupInvitationManagerImplTest.java b/briar-tests/src/org/briarproject/privategroup/invitation/GroupInvitationManagerImplTest.java index 93ffeb3bf..8cd1b54b7 100644 --- a/briar-tests/src/org/briarproject/privategroup/invitation/GroupInvitationManagerImplTest.java +++ b/briar-tests/src/org/briarproject/privategroup/invitation/GroupInvitationManagerImplTest.java @@ -36,7 +36,7 @@ import org.jmock.Expectations; import org.jmock.lib.legacy.ClassImposteriser; import org.junit.Test; -import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -46,6 +46,8 @@ import static junit.framework.TestCase.fail; import static org.briarproject.TestUtils.getRandomBytes; import static org.briarproject.TestUtils.getRandomId; import static org.briarproject.TestUtils.getRandomString; +import static org.briarproject.api.privategroup.PrivateGroupConstants.GROUP_SALT_LENGTH; +import static org.briarproject.api.privategroup.PrivateGroupConstants.MAX_GROUP_NAME_LENGTH; import static org.briarproject.api.privategroup.invitation.GroupInvitationManager.CLIENT_ID; import static org.briarproject.api.sync.Group.Visibility.SHARED; import static org.briarproject.api.sync.SyncConstants.MESSAGE_HEADER_LENGTH; @@ -60,7 +62,6 @@ import static org.junit.Assert.assertTrue; public class GroupInvitationManagerImplTest extends BriarMockTestCase { - private final GroupInvitationManagerImpl groupInvitationManager; private final DatabaseComponent db = context.mock(DatabaseComponent.class); private final ClientHelper clientHelper = context.mock(ClientHelper.class); private final ContactGroupFactory contactGroupFactory = @@ -77,12 +78,17 @@ public class GroupInvitationManagerImplTest extends BriarMockTestCase { context.mock(SessionEncoder.class); private final ProtocolEngineFactory engineFactory = context.mock(ProtocolEngineFactory.class); + private final CreatorProtocolEngine creatorEngine; private final InviteeProtocolEngine inviteeEngine; private final PeerProtocolEngine peerEngine; private final CreatorSession creatorSession; private final InviteeSession inviteeSession; private final PeerSession peerSession; + private final MessageMetadata messageMetadata; + + private final GroupInvitationManagerImpl groupInvitationManager; + private final Group localGroup = new Group(new GroupId(getRandomId()), CLIENT_ID, getRandomBytes(5)); private final Transaction txn = new Transaction(null, false); @@ -97,14 +103,23 @@ public class GroupInvitationManagerImplTest extends BriarMockTestCase { new Group(new GroupId(getRandomId()), CLIENT_ID, getRandomBytes(5)); private final Group privateGroup = new Group(new GroupId(getRandomId()), CLIENT_ID, getRandomBytes(5)); - private final BdfDictionary meta = BdfDictionary.of(new BdfEntry("f", "o")); + private final BdfDictionary meta = BdfDictionary.of(new BdfEntry("m", "e")); private final Message message = new Message(new MessageId(getRandomId()), contactGroup.getId(), 0L, getRandomBytes(MESSAGE_HEADER_LENGTH + 1)); - private final BdfList body = new BdfList(); + private final BdfList body = BdfList.of("body"); + private final SessionId sessionId = + new SessionId(privateGroup.getId().getBytes()); private final Message storageMessage = new Message(new MessageId(getRandomId()), contactGroup.getId(), 0L, getRandomBytes(MESSAGE_HEADER_LENGTH + 1)); + private final BdfDictionary bdfSession = + BdfDictionary.of(new BdfEntry("f", "o")); + private final Map oneResult = + Collections.singletonMap(storageMessage.getId(), bdfSession); + private final Map noResults = + Collections.emptyMap(); + public GroupInvitationManagerImplTest() { context.setImposteriser(ClassImposteriser.INSTANCE); @@ -116,6 +131,8 @@ public class GroupInvitationManagerImplTest extends BriarMockTestCase { inviteeSession = context.mock(InviteeSession.class); peerSession = context.mock(PeerSession.class); + messageMetadata = context.mock(MessageMetadata.class); + context.checking(new Expectations() {{ oneOf(engineFactory).createCreatorEngine(); will(returnValue(creatorEngine)); @@ -179,11 +196,11 @@ public class GroupInvitationManagerImplTest extends BriarMockTestCase { oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, c); will(returnValue(contactGroup)); }}); - expectGetSession(Collections.emptyMap(), - new SessionId(g.getBytes())); + expectGetSession(noResults, new SessionId(g.getBytes()), + contactGroup.getId()); context.checking(new Expectations() {{ - oneOf(peerEngine).onMemberAddedAction(with(equal(txn)), + oneOf(peerEngine).onMemberAddedAction(with(txn), with(any(PeerSession.class))); will(returnValue(peerSession)); }}); @@ -210,16 +227,16 @@ public class GroupInvitationManagerImplTest extends BriarMockTestCase { }}); } - private void expectGetSession(final Map result, - final SessionId sessionId) throws Exception { + private void expectGetSession(final Map results, + final SessionId sessionId, final GroupId contactGroupId) + throws Exception { final BdfDictionary query = BdfDictionary.of(new BdfEntry("q", "u")); context.checking(new Expectations() {{ oneOf(sessionParser).getSessionQuery(sessionId); will(returnValue(query)); - oneOf(clientHelper) - .getMessageMetadataAsDictionary(txn, contactGroup.getId(), - query); - will(returnValue(result)); + oneOf(clientHelper).getMessageMetadataAsDictionary(txn, + contactGroupId, query); + will(returnValue(results)); }}); } @@ -289,45 +306,39 @@ public class GroupInvitationManagerImplTest extends BriarMockTestCase { private void expectFirstIncomingMessage(Role role, MessageType type) throws Exception { - expectIncomingMessage(role, type, - Collections.emptyMap()); + expectParseMessageMetadata(); + expectGetSession(noResults, sessionId, contactGroup.getId()); + Session session = expectHandleFirstMessage(role, messageMetadata, type); + if (session != null) { + expectCreateStorageId(); + expectStoreSession(session, storageMessage.getId()); + } } - private void expectIncomingMessage(Role role, MessageType type) - throws Exception { - BdfDictionary state = BdfDictionary.of(new BdfEntry("state", "test")); - Map states = - Collections.singletonMap(storageMessage.getId(), state); - expectIncomingMessage(role, type, states); - } - - private void expectIncomingMessage(final Role role, - final MessageType type, final Map states) - throws Exception { - final MessageMetadata messageMetadata = - context.mock(MessageMetadata.class); + private void expectParseMessageMetadata() throws Exception { context.checking(new Expectations() {{ oneOf(messageParser).parseMetadata(meta); will(returnValue(messageMetadata)); oneOf(messageMetadata).getPrivateGroupId(); will(returnValue(privateGroup.getId())); }}); - expectGetSession(states, - new SessionId(privateGroup.getId().getBytes())); - Session session; - if (states.isEmpty()) { - session = expectHandleFirstMessage(role, messageMetadata, type); - if (session != null) { - expectCreateStorageId(); - expectStoreSession(session, storageMessage.getId()); - } - } else { - assertEquals(1, states.size()); - session = expectHandleMessage(role, messageMetadata, - states.values().iterator().next(), type); - expectStoreSession(session, storageMessage.getId()); - } + } + + private void expectIncomingMessage(Role role, MessageType type) + throws Exception { + BdfDictionary bdfSession = BdfDictionary.of(new BdfEntry("f", "o")); + expectIncomingMessageWithSession(role, type, bdfSession); + } + + private void expectIncomingMessageWithSession(final Role role, + final MessageType type, final BdfDictionary bdfSession) + throws Exception { + expectParseMessageMetadata(); + expectGetSession(oneResult, sessionId, contactGroup.getId()); + Session session = expectHandleMessage(role, messageMetadata, bdfSession, + type); + expectStoreSession(session, storageMessage.getId()); } @Nullable @@ -353,7 +364,7 @@ public class GroupInvitationManagerImplTest extends BriarMockTestCase { engine = peerEngine; session = peerSession; } else { - throw new RuntimeException(); + throw new AssertionError(); } expectIndividualMessage(type, engine, session); return session; @@ -394,8 +405,7 @@ public class GroupInvitationManagerImplTest extends BriarMockTestCase { expectIndividualMessage(type, peerEngine, peerSession); return peerSession; } else { - fail(); - throw new RuntimeException(); + throw new AssertionError(); } } @@ -407,9 +417,8 @@ public class GroupInvitationManagerImplTest extends BriarMockTestCase { context.checking(new Expectations() {{ oneOf(messageParser).parseInviteMessage(message, body); will(returnValue(msg)); - oneOf(engine).onInviteMessage(with(equal(txn)), - with(AbstractExpectations.anything()), - with(equal(msg))); + oneOf(engine).onInviteMessage(with(txn), + with(AbstractExpectations.anything()), with(msg)); will(returnValue(session)); }}); } else if (type == JOIN) { @@ -417,9 +426,8 @@ public class GroupInvitationManagerImplTest extends BriarMockTestCase { context.checking(new Expectations() {{ oneOf(messageParser).parseJoinMessage(message, body); will(returnValue(msg)); - oneOf(engine).onJoinMessage(with(equal(txn)), - with(AbstractExpectations.anything()), - with(equal(msg))); + oneOf(engine).onJoinMessage(with(txn), + with(AbstractExpectations.anything()), with(msg)); will(returnValue(session)); }}); } else if (type == LEAVE) { @@ -427,9 +435,8 @@ public class GroupInvitationManagerImplTest extends BriarMockTestCase { context.checking(new Expectations() {{ oneOf(messageParser).parseLeaveMessage(message, body); will(returnValue(msg)); - oneOf(engine).onLeaveMessage(with(equal(txn)), - with(AbstractExpectations.anything()), - with(equal(msg))); + oneOf(engine).onLeaveMessage(with(txn), + with(AbstractExpectations.anything()), with(msg)); will(returnValue(session)); }}); } else if (type == ABORT) { @@ -437,9 +444,8 @@ public class GroupInvitationManagerImplTest extends BriarMockTestCase { context.checking(new Expectations() {{ oneOf(messageParser).parseAbortMessage(message, body); will(returnValue(msg)); - oneOf(engine).onAbortMessage(with(equal(txn)), - with(AbstractExpectations.anything()), - with(equal(msg))); + oneOf(engine).onAbortMessage(with(txn), + with(AbstractExpectations.anything()), with(msg)); will(returnValue(session)); }}); } else { @@ -451,11 +457,9 @@ public class GroupInvitationManagerImplTest extends BriarMockTestCase { public void testSendFirstInvitation() throws Exception { final String msg = "Invitation text for first invitation"; final long time = 42L; - final byte[] signature = TestUtils.getRandomBytes(42); - Map states = Collections.emptyMap(); + final byte[] signature = getRandomBytes(42); - expectGetSession(states, - new SessionId(privateGroup.getId().getBytes())); + expectGetSession(noResults, sessionId, contactGroup.getId()); context.checking(new Expectations() {{ oneOf(db).startTransaction(false); will(returnValue(txn)); @@ -466,9 +470,9 @@ public class GroupInvitationManagerImplTest extends BriarMockTestCase { }}); expectCreateStorageId(); context.checking(new Expectations() {{ - oneOf(creatorEngine).onInviteAction(with(same(txn)), - with(any(CreatorSession.class)), with(equal(msg)), - with(equal(time)), with(equal(signature))); + oneOf(creatorEngine).onInviteAction(with(txn), + with(any(CreatorSession.class)), with(msg), with(time), + with(signature)); will(returnValue(creatorSession)); }}); expectStoreSession(creatorSession, storageMessage.getId()); @@ -484,14 +488,9 @@ public class GroupInvitationManagerImplTest extends BriarMockTestCase { public void testSendSubsequentInvitation() throws Exception { final String msg = "Invitation text for subsequent invitation"; final long time = 43L; - final byte[] signature = TestUtils.getRandomBytes(43); - final BdfDictionary state = - BdfDictionary.of(new BdfEntry("state", "test")); - Map states = - Collections.singletonMap(storageMessage.getId(), state); + final byte[] signature = getRandomBytes(43); - expectGetSession(states, - new SessionId(privateGroup.getId().getBytes())); + expectGetSession(oneResult, sessionId, contactGroup.getId()); context.checking(new Expectations() {{ oneOf(db).startTransaction(false); will(returnValue(txn)); @@ -500,11 +499,11 @@ public class GroupInvitationManagerImplTest extends BriarMockTestCase { oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact); will(returnValue(contactGroup)); oneOf(sessionParser) - .parseCreatorSession(contactGroup.getId(), state); + .parseCreatorSession(contactGroup.getId(), bdfSession); will(returnValue(creatorSession)); - oneOf(creatorEngine).onInviteAction(with(same(txn)), - with(any(CreatorSession.class)), with(equal(msg)), - with(equal(time)), with(equal(signature))); + oneOf(creatorEngine).onInviteAction(with(txn), + with(any(CreatorSession.class)), with(msg), with(time), + with(signature)); will(returnValue(creatorSession)); }}); expectStoreSession(creatorSession, storageMessage.getId()); @@ -529,59 +528,48 @@ public class GroupInvitationManagerImplTest extends BriarMockTestCase { will(returnValue(contactGroup)); oneOf(db).endTransaction(txn); }}); - expectGetSession(Collections.emptyMap(), - sessionId); + expectGetSession(noResults, sessionId, contactGroup.getId()); groupInvitationManager.respondToInvitation(contactId, sessionId, true); } @Test public void testAcceptInvitationWithSession() throws Exception { - final boolean accept = true; - SessionId sessionId = new SessionId(getRandomId()); - BdfDictionary state = BdfDictionary.of(new BdfEntry("f", "o")); - Map states = - Collections.singletonMap(storageMessage.getId(), state); - - expectRespondToInvitation(states, sessionId, accept); + expectRespondToInvitation(sessionId, true); groupInvitationManager - .respondToInvitation(contactId, sessionId, accept); + .respondToInvitation(contactId, sessionId, true); } @Test public void testDeclineInvitationWithSession() throws Exception { - final boolean accept = false; - SessionId sessionId = new SessionId(getRandomId()); - BdfDictionary state = BdfDictionary.of(new BdfEntry("f", "o")); - Map states = - Collections.singletonMap(storageMessage.getId(), state); - - expectRespondToInvitation(states, sessionId, accept); + expectRespondToInvitation(sessionId, false); groupInvitationManager - .respondToInvitation(contactId, sessionId, accept); + .respondToInvitation(contactId, sessionId, false); } @Test - public void testRespondToInvitationWithGroupId() throws Exception { - final boolean accept = true; - final PrivateGroup g = context.mock(PrivateGroup.class); - SessionId sessionId = new SessionId(privateGroup.getId().getBytes()); - BdfDictionary state = BdfDictionary.of(new BdfEntry("f", "o")); - Map states = - Collections.singletonMap(storageMessage.getId(), state); + public void testAcceptInvitationWithGroupId() throws Exception { + PrivateGroup pg = new PrivateGroup(privateGroup, + getRandomString(MAX_GROUP_NAME_LENGTH), author, + getRandomBytes(GROUP_SALT_LENGTH)); - context.checking(new Expectations() {{ - oneOf(g).getId(); - will(returnValue(privateGroup.getId())); - }}); - expectRespondToInvitation(states, sessionId, accept); - groupInvitationManager.respondToInvitation(contactId, g, accept); + expectRespondToInvitation(sessionId, true); + groupInvitationManager.respondToInvitation(contactId, pg, true); } - private void expectRespondToInvitation( - final Map states, - final SessionId sessionId, final boolean accept) throws Exception { - expectGetSession(states, sessionId); + @Test + public void testDeclineInvitationWithGroupId() throws Exception { + PrivateGroup pg = new PrivateGroup(privateGroup, + getRandomString(MAX_GROUP_NAME_LENGTH), author, + getRandomBytes(GROUP_SALT_LENGTH)); + + expectRespondToInvitation(sessionId, false); + groupInvitationManager.respondToInvitation(contactId, pg, false); + } + + private void expectRespondToInvitation(final SessionId sessionId, + final boolean accept) throws Exception { + expectGetSession(oneResult, sessionId, contactGroup.getId()); context.checking(new Expectations() {{ oneOf(db).startTransaction(false); will(returnValue(txn)); @@ -589,15 +577,8 @@ public class GroupInvitationManagerImplTest extends BriarMockTestCase { will(returnValue(contact)); oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact); will(returnValue(contactGroup)); - }}); - - if (states.isEmpty()) return; - assertEquals(1, states.size()); - - final BdfDictionary state = states.values().iterator().next(); - context.checking(new Expectations() {{ oneOf(sessionParser) - .parseInviteeSession(contactGroup.getId(), state); + .parseInviteeSession(contactGroup.getId(), bdfSession); will(returnValue(inviteeSession)); if (accept) oneOf(inviteeEngine).onJoinAction(txn, inviteeSession); else oneOf(inviteeEngine).onLeaveAction(txn, inviteeSession); @@ -610,11 +591,6 @@ public class GroupInvitationManagerImplTest extends BriarMockTestCase { @Test public void testRevealRelationship() throws Exception { - SessionId sessionId = new SessionId(privateGroup.getId().getBytes()); - final BdfDictionary state = BdfDictionary.of(new BdfEntry("f", "o")); - Map states = - Collections.singletonMap(storageMessage.getId(), state); - context.checking(new Expectations() {{ oneOf(db).startTransaction(false); will(returnValue(txn)); @@ -622,14 +598,15 @@ public class GroupInvitationManagerImplTest extends BriarMockTestCase { will(returnValue(contact)); oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact); will(returnValue(contactGroup)); - oneOf(sessionParser).parsePeerSession(contactGroup.getId(), state); + oneOf(sessionParser) + .parsePeerSession(contactGroup.getId(), bdfSession); will(returnValue(peerSession)); oneOf(peerEngine).onJoinAction(txn, peerSession); will(returnValue(peerSession)); oneOf(db).commitTransaction(txn); oneOf(db).endTransaction(txn); }}); - expectGetSession(states, sessionId); + expectGetSession(oneResult, sessionId, contactGroup.getId()); expectStoreSession(peerSession, storageMessage.getId()); groupInvitationManager @@ -638,8 +615,6 @@ public class GroupInvitationManagerImplTest extends BriarMockTestCase { @Test(expected = IllegalArgumentException.class) public void testRevealRelationshipWithoutSession() throws Exception { - SessionId sessionId = new SessionId(privateGroup.getId().getBytes()); - context.checking(new Expectations() {{ oneOf(db).startTransaction(false); will(returnValue(txn)); @@ -649,8 +624,7 @@ public class GroupInvitationManagerImplTest extends BriarMockTestCase { will(returnValue(contactGroup)); oneOf(db).endTransaction(txn); }}); - expectGetSession(Collections.emptyMap(), - sessionId); + expectGetSession(noResults, sessionId, contactGroup.getId()); groupInvitationManager .revealRelationship(contactId, privateGroup.getId()); @@ -658,20 +632,19 @@ public class GroupInvitationManagerImplTest extends BriarMockTestCase { @Test public void testGetInvitationMessages() throws Exception { - final BdfDictionary query = new BdfDictionary(); - final BdfDictionary d1 = BdfDictionary.of(new BdfEntry("m1", "d")); - final BdfDictionary d2 = BdfDictionary.of(new BdfEntry("m2", "d")); - final Map results = new HashMap<>(); - results.put(message.getId(), d1); - results.put(storageMessage.getId(), d2); + final BdfDictionary query = BdfDictionary.of(new BdfEntry("q", "u")); + final MessageId messageId2 = new MessageId(TestUtils.getRandomId()); + final BdfDictionary meta2 = BdfDictionary.of(new BdfEntry("m2", "e")); + final Map results = new HashMap<>(); + results.put(message.getId(), meta); + results.put(messageId2, meta2); long time1 = 1L, time2 = 2L; - final MessageMetadata meta1 = + final MessageMetadata messageMetadata1 = new MessageMetadata(INVITE, privateGroup.getId(), time1, true, true, true, true); - final MessageMetadata meta2 = + final MessageMetadata messageMetadata2 = new MessageMetadata(JOIN, privateGroup.getId(), time2, true, true, true, true); - final BdfList list1 = BdfList.of(1); context.checking(new Expectations() {{ oneOf(db).startTransaction(true); @@ -682,23 +655,22 @@ public class GroupInvitationManagerImplTest extends BriarMockTestCase { will(returnValue(contactGroup)); oneOf(messageParser).getMessagesVisibleInUiQuery(); will(returnValue(query)); - oneOf(clientHelper) - .getMessageMetadataAsDictionary(txn, contactGroup.getId(), - query); + oneOf(clientHelper).getMessageMetadataAsDictionary(txn, + contactGroup.getId(), query); will(returnValue(results)); // first message - oneOf(messageParser).parseMetadata(d1); - will(returnValue(meta1)); + oneOf(messageParser).parseMetadata(meta); + will(returnValue(messageMetadata1)); oneOf(db).getMessageStatus(txn, contactId, message.getId()); oneOf(clientHelper).getMessage(txn, message.getId()); will(returnValue(message)); oneOf(clientHelper).toList(message); - will(returnValue(list1)); - oneOf(messageParser).parseInviteMessage(message, list1); + will(returnValue(body)); + oneOf(messageParser).parseInviteMessage(message, body); // second message - oneOf(messageParser).parseMetadata(d2); - will(returnValue(meta2)); - oneOf(db).getMessageStatus(txn, contactId, storageMessage.getId()); + oneOf(messageParser).parseMetadata(meta2); + will(returnValue(messageMetadata2)); + oneOf(db).getMessageStatus(txn, contactId, messageId2); // end transaction oneOf(db).commitTransaction(txn); oneOf(db).endTransaction(txn); @@ -713,33 +685,39 @@ public class GroupInvitationManagerImplTest extends BriarMockTestCase { if (m.getId().equals(message.getId())) { assertTrue(m instanceof GroupInvitationRequest); assertEquals(time1, m.getTimestamp()); - } else if (m.getId().equals(storageMessage.getId())) { + } else if (m.getId().equals(messageId2)) { assertTrue(m instanceof GroupInvitationResponse); assertEquals(time2, m.getTimestamp()); + } else { + throw new AssertionError(); } } } @Test public void testGetInvitations() throws Exception { - final BdfDictionary query = new BdfDictionary(); - BdfDictionary d1 = BdfDictionary.of(new BdfEntry("m1", "d")); - BdfDictionary d2 = BdfDictionary.of(new BdfEntry("m2", "d")); - final Map results = new HashMap<>(); - results.put(message.getId(), d1); - results.put(storageMessage.getId(), d2); - final BdfList list1 = BdfList.of(1); - final BdfList list2 = BdfList.of(2); + final BdfDictionary query = BdfDictionary.of(new BdfEntry("q", "u")); + final MessageId messageId2 = new MessageId(TestUtils.getRandomId()); + final BdfDictionary meta2 = BdfDictionary.of(new BdfEntry("m2", "e")); + final Map results = new HashMap<>(); + results.put(message.getId(), meta); + results.put(messageId2, meta2); + final Message message2 = new Message(messageId2, contactGroup.getId(), + 0L, getRandomBytes(MESSAGE_HEADER_LENGTH + 1)); long time1 = 1L, time2 = 2L; - final InviteMessage m1 = + final String groupName = getRandomString(MAX_GROUP_NAME_LENGTH); + final byte[] salt = getRandomBytes(GROUP_SALT_LENGTH); + final InviteMessage inviteMessage1 = new InviteMessage(message.getId(), contactGroup.getId(), - privateGroup.getId(), time1, "test", author, - getRandomBytes(5), null, getRandomBytes(5)); - final InviteMessage m2 = + privateGroup.getId(), time1, groupName, author, salt, + null, getRandomBytes(5)); + final InviteMessage inviteMessage2 = new InviteMessage(message.getId(), contactGroup.getId(), - privateGroup.getId(), time2, "test", author, - getRandomBytes(5), null, getRandomBytes(5)); - final PrivateGroup g = context.mock(PrivateGroup.class); + privateGroup.getId(), time2, groupName, author, salt, + null, getRandomBytes(5)); + final PrivateGroup pg = new PrivateGroup(privateGroup, groupName, + author, salt); + final BdfList body2 = BdfList.of("body2"); context.checking(new Expectations() {{ oneOf(messageParser).getInvitesAvailableToAnswerQuery(); @@ -750,32 +728,29 @@ public class GroupInvitationManagerImplTest extends BriarMockTestCase { will(returnValue(Collections.singletonList(contact))); oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact); will(returnValue(contactGroup)); - oneOf(clientHelper) - .getMessageMetadataAsDictionary(txn, contactGroup.getId(), - query); + oneOf(clientHelper).getMessageMetadataAsDictionary(txn, + contactGroup.getId(), query); will(returnValue(results)); // message 1 oneOf(clientHelper).getMessage(txn, message.getId()); will(returnValue(message)); oneOf(clientHelper).toList(message); - will(returnValue(list1)); - oneOf(messageParser).parseInviteMessage(message, list1); - will(returnValue(m1)); - oneOf(privateGroupFactory) - .createPrivateGroup(m1.getGroupName(), m1.getCreator(), - m1.getSalt()); - will(returnValue(g)); + will(returnValue(body)); + oneOf(messageParser).parseInviteMessage(message, body); + will(returnValue(inviteMessage1)); + oneOf(privateGroupFactory).createPrivateGroup(groupName, author, + salt); + will(returnValue(pg)); // message 2 - oneOf(clientHelper).getMessage(txn, storageMessage.getId()); - will(returnValue(storageMessage)); - oneOf(clientHelper).toList(storageMessage); - will(returnValue(list2)); - oneOf(messageParser).parseInviteMessage(storageMessage, list2); - will(returnValue(m2)); - oneOf(privateGroupFactory) - .createPrivateGroup(m2.getGroupName(), m2.getCreator(), - m2.getSalt()); - will(returnValue(g)); + oneOf(clientHelper).getMessage(txn, messageId2); + will(returnValue(message2)); + oneOf(clientHelper).toList(message2); + will(returnValue(body2)); + oneOf(messageParser).parseInviteMessage(message2, body2); + will(returnValue(inviteMessage2)); + oneOf(privateGroupFactory).createPrivateGroup(groupName, author, + salt); + will(returnValue(pg)); // end transaction oneOf(db).commitTransaction(txn); oneOf(db).endTransaction(txn); @@ -787,6 +762,8 @@ public class GroupInvitationManagerImplTest extends BriarMockTestCase { for (GroupInvitationItem i : items) { assertEquals(contact, i.getCreator()); assertEquals(author, i.getCreator().getAuthor()); + assertEquals(privateGroup.getId(), i.getId()); + assertEquals(groupName, i.getName()); } } @@ -822,20 +799,14 @@ public class GroupInvitationManagerImplTest extends BriarMockTestCase { private void expectIsInvitationAllowed(final CreatorState state) throws Exception { - final SessionId sessionId = - new SessionId(privateGroup.getId().getBytes()); - final BdfDictionary meta = BdfDictionary.of(new BdfEntry("m", "d")); - final Map results = new HashMap<>(); - results.put(message.getId(), meta); - - expectGetSession(results, sessionId); + expectGetSession(oneResult, sessionId, contactGroup.getId()); context.checking(new Expectations() {{ oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact); will(returnValue(contactGroup)); oneOf(db).startTransaction(true); will(returnValue(txn)); oneOf(sessionParser) - .parseCreatorSession(contactGroup.getId(), meta); + .parseCreatorSession(contactGroup.getId(), bdfSession); will(returnValue(creatorSession)); oneOf(creatorSession).getState(); will(returnValue(state)); @@ -856,68 +827,70 @@ public class GroupInvitationManagerImplTest extends BriarMockTestCase { @Test public void testRemovingGroupEndsSessions() throws Exception { - final Contact contact2 = - new Contact(new ContactId(2), author, author.getId(), true, - true); - final Contact contact3 = - new Contact(new ContactId(3), author, author.getId(), true, - true); - final Collection contacts = new ArrayList<>(); - contacts.add(contact); - contacts.add(contact2); - contacts.add(contact3); - final MessageId mId2 = new MessageId(getRandomId()); - final MessageId mId3 = new MessageId(getRandomId()); - final BdfDictionary meta1 = BdfDictionary.of(new BdfEntry("m1", "d")); - final BdfDictionary meta2 = BdfDictionary.of(new BdfEntry("m2", "d")); - final BdfDictionary meta3 = BdfDictionary.of(new BdfEntry("m3", "d")); + final Contact contact2 = new Contact(new ContactId(2), author, + author.getId(), true, true); + final Contact contact3 = new Contact(new ContactId(3), author, + author.getId(), true, true); + final Collection contacts = + Arrays.asList(contact, contact2, contact3); + + final Group contactGroup2 = new Group(new GroupId(getRandomId()), + CLIENT_ID, getRandomBytes(5)); + final Group contactGroup3 = new Group(new GroupId(getRandomId()), + CLIENT_ID, getRandomBytes(5)); + + final MessageId storageId2 = new MessageId(getRandomId()); + final MessageId storageId3 = new MessageId(getRandomId()); + final BdfDictionary bdfSession2 = + BdfDictionary.of(new BdfEntry("f2", "o")); + final BdfDictionary bdfSession3 = + BdfDictionary.of(new BdfEntry("f3", "o")); + + expectGetSession(oneResult, sessionId, contactGroup.getId()); + expectGetSession(Collections.singletonMap(storageId2, bdfSession2), + sessionId, contactGroup2.getId()); + expectGetSession(Collections.singletonMap(storageId3, bdfSession3), + sessionId, contactGroup3.getId()); - expectGetSession( - Collections.singletonMap(storageMessage.getId(), meta1), - new SessionId(privateGroup.getId().getBytes())); - expectGetSession( - Collections.singletonMap(mId2, meta2), - new SessionId(privateGroup.getId().getBytes())); - expectGetSession( - Collections.singletonMap(mId3, meta3), - new SessionId(privateGroup.getId().getBytes())); context.checking(new Expectations() {{ oneOf(db).getContacts(txn); will(returnValue(contacts)); oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact); will(returnValue(contactGroup)); oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact2); - will(returnValue(contactGroup)); + will(returnValue(contactGroup2)); oneOf(contactGroupFactory).createContactGroup(CLIENT_ID, contact3); - will(returnValue(contactGroup)); + will(returnValue(contactGroup3)); // session 1 - oneOf(sessionParser).getRole(meta1); + oneOf(sessionParser).getRole(bdfSession); will(returnValue(Role.CREATOR)); oneOf(sessionParser) - .parseCreatorSession(contactGroup.getId(), meta1); + .parseCreatorSession(contactGroup.getId(), bdfSession); will(returnValue(creatorSession)); oneOf(creatorEngine).onLeaveAction(txn, creatorSession); will(returnValue(creatorSession)); // session 2 - oneOf(sessionParser).getRole(meta2); + oneOf(sessionParser).getRole(bdfSession2); will(returnValue(Role.INVITEE)); oneOf(sessionParser) - .parseInviteeSession(contactGroup.getId(), meta2); + .parseInviteeSession(contactGroup2.getId(), bdfSession2); will(returnValue(inviteeSession)); oneOf(inviteeEngine).onLeaveAction(txn, inviteeSession); will(returnValue(inviteeSession)); // session 3 - oneOf(sessionParser).getRole(meta3); + oneOf(sessionParser).getRole(bdfSession3); will(returnValue(Role.PEER)); oneOf(sessionParser) - .parsePeerSession(contactGroup.getId(), meta3); + .parsePeerSession(contactGroup3.getId(), bdfSession3); will(returnValue(peerSession)); oneOf(peerEngine).onLeaveAction(txn, peerSession); will(returnValue(peerSession)); }}); + expectStoreSession(creatorSession, storageMessage.getId()); - expectStoreSession(inviteeSession, mId2); - expectStoreSession(peerSession, mId3); + expectStoreSession(inviteeSession, storageId2); + expectStoreSession(peerSession, storageId3); + groupInvitationManager.removingGroup(txn, privateGroup.getId()); }