diff --git a/briar-tests/src/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngineTest.java b/briar-tests/src/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngineTest.java new file mode 100644 index 0000000000000000000000000000000000000000..930941cd034dfae16a7c27a6b688150ea6022ab0 --- /dev/null +++ b/briar-tests/src/org/briarproject/briar/privategroup/invitation/AbstractProtocolEngineTest.java @@ -0,0 +1,204 @@ +package org.briarproject.briar.privategroup.invitation; + +import org.briarproject.BriarMockTestCase; +import org.briarproject.bramble.api.client.ClientHelper; +import org.briarproject.bramble.api.contact.ContactId; +import org.briarproject.bramble.api.data.BdfDictionary; +import org.briarproject.bramble.api.data.BdfEntry; +import org.briarproject.bramble.api.db.DatabaseComponent; +import org.briarproject.bramble.api.db.Transaction; +import org.briarproject.bramble.api.identity.Author; +import org.briarproject.bramble.api.identity.AuthorId; +import org.briarproject.bramble.api.identity.IdentityManager; +import org.briarproject.bramble.api.sync.Group; +import org.briarproject.bramble.api.sync.GroupId; +import org.briarproject.bramble.api.sync.Message; +import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.bramble.api.system.Clock; +import org.briarproject.briar.api.client.MessageTracker; +import org.briarproject.briar.api.privategroup.GroupMessageFactory; +import org.briarproject.briar.api.privategroup.PrivateGroup; +import org.briarproject.briar.api.privategroup.PrivateGroupFactory; +import org.briarproject.briar.api.privategroup.PrivateGroupManager; +import org.jmock.Expectations; + +import static org.briarproject.TestUtils.getRandomBytes; +import static org.briarproject.TestUtils.getRandomId; +import static org.briarproject.briar.api.privategroup.invitation.GroupInvitationManager.CLIENT_ID; +import static org.briarproject.briar.privategroup.invitation.GroupInvitationConstants.GROUP_KEY_CONTACT_ID; +import static org.briarproject.briar.privategroup.invitation.MessageType.ABORT; +import static org.briarproject.briar.privategroup.invitation.MessageType.INVITE; +import static org.briarproject.briar.privategroup.invitation.MessageType.JOIN; +import static org.briarproject.briar.privategroup.invitation.MessageType.LEAVE; +import static org.junit.Assert.assertEquals; + +public abstract class AbstractProtocolEngineTest extends BriarMockTestCase { + + protected final DatabaseComponent db = + context.mock(DatabaseComponent.class); + protected final ClientHelper clientHelper = + context.mock(ClientHelper.class); + protected final PrivateGroupFactory privateGroupFactory = + context.mock(PrivateGroupFactory.class); + protected final PrivateGroupManager privateGroupManager = + context.mock(PrivateGroupManager.class); + protected final MessageParser messageParser = + context.mock(MessageParser.class); + protected final GroupMessageFactory groupMessageFactory = + context.mock(GroupMessageFactory.class); + protected final IdentityManager identityManager = + context.mock(IdentityManager.class); + protected final MessageEncoder messageEncoder = + context.mock(MessageEncoder.class); + protected final MessageTracker messageTracker = + context.mock(MessageTracker.class); + protected final Clock clock = context.mock(Clock.class); + + protected final Transaction txn = new Transaction(null, false); + protected final GroupId contactGroupId = new GroupId(getRandomId()); + protected final GroupId privateGroupId = new GroupId(getRandomId()); + protected final Group privateGroupGroup = + new Group(privateGroupId, CLIENT_ID, getRandomBytes(5)); + private final AuthorId authorId = new AuthorId(getRandomId()); + protected final Author author = + new Author(authorId, "Author", getRandomBytes(12)); + protected final PrivateGroup privateGroup = + new PrivateGroup(privateGroupGroup, "Private Group", author, + getRandomBytes(8)); + protected final byte[] signature = getRandomBytes(42); + protected final MessageId lastLocalMessageId = new MessageId(getRandomId()); + protected final MessageId lastRemoteMessageId = + new MessageId(getRandomId()); + protected final long localTimestamp = 3L; + protected final long inviteTimestamp = 6L; + protected final long messageTimestamp = inviteTimestamp + 1; + protected final MessageId messageId = new MessageId(getRandomId()); + protected final Message message = + new Message(messageId, contactGroupId, messageTimestamp, + getRandomBytes(42)); + private final BdfDictionary meta = + BdfDictionary.of(new BdfEntry("me", "ta")); + protected final ContactId contactId = new ContactId(5); + + protected void assertSessionConstantsUnchanged(Session s1, Session s2) { + assertEquals(s1.getRole(), s2.getRole()); + assertEquals(s1.getContactGroupId(), s2.getContactGroupId()); + assertEquals(s1.getPrivateGroupId(), s2.getPrivateGroupId()); + } + + protected void assertSessionRecordedSentMessage(Session s) { + assertEquals(messageId, s.getLastLocalMessageId()); + assertEquals(lastRemoteMessageId, s.getLastRemoteMessageId()); + assertEquals(messageTimestamp, s.getLocalTimestamp()); + assertEquals(inviteTimestamp, s.getInviteTimestamp()); + } + + protected void expectGetLocalTimestamp(final long time) { + context.checking(new Expectations() {{ + oneOf(clock).currentTimeMillis(); + will(returnValue(time)); + }}); + } + + protected void expectSendInviteMessage(final String msg) + throws Exception { + context.checking(new Expectations() {{ + oneOf(messageEncoder) + .encodeInviteMessage(contactGroupId, privateGroupId, + inviteTimestamp, privateGroup.getName(), author, + privateGroup.getSalt(), msg, signature); + will(returnValue(message)); + }}); + expectSendMessage(INVITE, true); + } + + protected void expectSendJoinMessage(final JoinMessage m) throws Exception { + expectGetLocalTimestamp(messageTimestamp); + context.checking(new Expectations() {{ + oneOf(messageEncoder).encodeJoinMessage(m.getContactGroupId(), + m.getPrivateGroupId(), m.getTimestamp(), + lastLocalMessageId); + will(returnValue(message)); + }}); + expectSendMessage(JOIN, false); + } + + protected void expectSendLeaveMessage() throws Exception { + expectGetLocalTimestamp(messageTimestamp); + context.checking(new Expectations() {{ + oneOf(messageEncoder) + .encodeLeaveMessage(contactGroupId, privateGroupId, + messageTimestamp, lastLocalMessageId); + will(returnValue(message)); + }}); + expectSendMessage(LEAVE, false); + } + + protected void expectSendAbortMessage() throws Exception { + expectGetLocalTimestamp(messageTimestamp); + context.checking(new Expectations() {{ + oneOf(messageEncoder) + .encodeAbortMessage(contactGroupId, privateGroupId, + messageTimestamp); + will(returnValue(message)); + }}); + expectSendMessage(ABORT, false); + } + + private void expectSendMessage(final MessageType type, + final boolean visible) throws Exception { + context.checking(new Expectations() {{ + oneOf(messageEncoder).encodeMetadata(type, privateGroupId, + message.getTimestamp(), true, true, visible, false); + will(returnValue(meta)); + oneOf(clientHelper).addLocalMessage(txn, message, meta, true); + }}); + } + + protected void expectSetPrivateGroupVisibility(final Group.Visibility v) + throws Exception { + expectGetContactId(); + context.checking(new Expectations() {{ + oneOf(db).setGroupVisibility(txn, contactId, privateGroupId, v); + }}); + } + + protected void expectGetContactId() throws Exception { + final BdfDictionary groupMeta = BdfDictionary + .of(new BdfEntry(GROUP_KEY_CONTACT_ID, contactId.getInt())); + context.checking(new Expectations() {{ + oneOf(clientHelper) + .getGroupMetadataAsDictionary(txn, contactGroupId); + will(returnValue(groupMeta)); + }}); + } + + protected void expectIsSubscribedPrivateGroup() + throws Exception { + context.checking(new Expectations() {{ + oneOf(db).containsGroup(txn, privateGroupId); + will(returnValue(true)); + oneOf(db).getGroup(txn, privateGroupId); + will(returnValue(privateGroupGroup)); + }}); + } + + protected void expectIsNotSubscribedPrivateGroup() + throws Exception { + context.checking(new Expectations() {{ + oneOf(db).containsGroup(txn, privateGroupId); + will(returnValue(false)); + }}); + } + + protected void expectMarkMessageVisibleInUi(final MessageId m, + final boolean visible) + throws Exception { + final BdfDictionary d = new BdfDictionary(); + context.checking(new Expectations() {{ + oneOf(messageEncoder).setVisibleInUi(d, visible); + oneOf(clientHelper).mergeMessageMetadata(txn, m, d); + }}); + } + +} diff --git a/briar-tests/src/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngineTest.java b/briar-tests/src/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngineTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d8bcdc3fd2573ce103e261c55d44465ca9a0fcf1 --- /dev/null +++ b/briar-tests/src/org/briarproject/briar/privategroup/invitation/CreatorProtocolEngineTest.java @@ -0,0 +1,488 @@ +package org.briarproject.briar.privategroup.invitation; + +import org.briarproject.bramble.api.sync.MessageId; +import org.briarproject.briar.api.client.ProtocolStateException; +import org.jmock.Expectations; +import org.junit.Test; + +import static org.briarproject.TestUtils.getRandomId; +import static org.briarproject.bramble.api.sync.Group.Visibility.INVISIBLE; +import static org.briarproject.bramble.api.sync.Group.Visibility.SHARED; +import static org.briarproject.briar.privategroup.invitation.CreatorState.DISSOLVED; +import static org.briarproject.briar.privategroup.invitation.CreatorState.ERROR; +import static org.briarproject.briar.privategroup.invitation.CreatorState.INVITED; +import static org.briarproject.briar.privategroup.invitation.CreatorState.JOINED; +import static org.briarproject.briar.privategroup.invitation.CreatorState.LEFT; +import static org.briarproject.briar.privategroup.invitation.CreatorState.START; +import static org.junit.Assert.assertEquals; + +public class CreatorProtocolEngineTest extends AbstractProtocolEngineTest { + + private final CreatorProtocolEngine engine = + new CreatorProtocolEngine(db, clientHelper, privateGroupManager, + privateGroupFactory, groupMessageFactory, identityManager, + messageParser, messageEncoder, messageTracker, clock); + private final JoinMessage joinMessage = + new JoinMessage(new MessageId(getRandomId()), contactGroupId, + privateGroupId, 0L, lastRemoteMessageId); + private final LeaveMessage leaveMessage = + new LeaveMessage(new MessageId(getRandomId()), contactGroupId, + privateGroupId, 0L, lastRemoteMessageId); + + private CreatorSession getDefaultSession(CreatorState state) { + return new CreatorSession(contactGroupId, privateGroupId, + lastLocalMessageId, lastRemoteMessageId, localTimestamp, + inviteTimestamp, state); + } + + // onInviteAction + + @Test + public void testOnInviteActionFromStart() throws Exception { + CreatorSession session = + new CreatorSession(contactGroupId, privateGroupId); + String message = "Invitation Message"; + + expectOnLocalInvite(message); + CreatorSession newSession = + engine.onInviteAction(txn, session, message, inviteTimestamp, + signature); + assertEquals(INVITED, newSession.getState()); + assertEquals(messageId, newSession.getLastLocalMessageId()); + assertEquals(null, newSession.getLastRemoteMessageId()); + assertEquals(messageTimestamp, newSession.getLocalTimestamp()); + assertEquals(inviteTimestamp, newSession.getInviteTimestamp()); + assertSessionConstantsUnchanged(session, newSession); + } + + @Test + public void testOnInviteActionFromStartWithNullMessage() throws Exception { + CreatorSession session = + new CreatorSession(contactGroupId, privateGroupId); + + expectOnLocalInvite(null); + CreatorSession newSession = + engine.onInviteAction(txn, session, null, inviteTimestamp, + signature); + assertEquals(INVITED, newSession.getState()); + assertEquals(messageId, newSession.getLastLocalMessageId()); + assertEquals(null, newSession.getLastRemoteMessageId()); + assertEquals(messageTimestamp, newSession.getLocalTimestamp()); + assertEquals(inviteTimestamp, newSession.getInviteTimestamp()); + assertSessionConstantsUnchanged(session, newSession); + } + + private void expectOnLocalInvite(final String msg) throws Exception { + context.checking(new Expectations() {{ + oneOf(db).getGroup(txn, privateGroupId); + will(returnValue(privateGroupGroup)); + oneOf(privateGroupFactory).parsePrivateGroup(privateGroupGroup); + will(returnValue(privateGroup)); + oneOf(messageTracker).trackOutgoingMessage(txn, message); + }}); + expectSendInviteMessage(msg); + expectGetLocalTimestamp(messageTimestamp); + } + + @Test(expected = ProtocolStateException.class) + public void testOnInviteActionFromInvited() throws Exception { + engine.onInviteAction(txn, getDefaultSession(INVITED), null, + inviteTimestamp, signature); + } + + @Test(expected = ProtocolStateException.class) + public void testOnInviteActionFromJoined() throws Exception { + engine.onInviteAction(txn, getDefaultSession(JOINED), null, + inviteTimestamp, signature); + } + + @Test(expected = ProtocolStateException.class) + public void testOnInviteActionFromLeft() throws Exception { + engine.onInviteAction(txn, getDefaultSession(LEFT), null, + inviteTimestamp, signature); + } + + @Test(expected = ProtocolStateException.class) + public void testOnInviteActionFromDissolved() throws Exception { + engine.onInviteAction(txn, getDefaultSession(DISSOLVED), null, + inviteTimestamp, signature); + } + + @Test(expected = ProtocolStateException.class) + public void testOnInviteActionFromError() throws Exception { + engine.onInviteAction(txn, getDefaultSession(ERROR), null, + inviteTimestamp, signature); + } + + // onJoinAction + + @Test(expected = UnsupportedOperationException.class) + public void testOnJoinActionFails() throws Exception { + engine.onJoinAction(txn, getDefaultSession(START)); + } + + // onLeaveAction + + @Test + public void testOnLeaveActionFromStart() throws Exception { + CreatorSession session = getDefaultSession(START); + assertEquals(session, engine.onLeaveAction(txn, session)); + } + + @Test + public void testOnLeaveActionFromDissolved() throws Exception { + CreatorSession session = getDefaultSession(DISSOLVED); + assertEquals(session, engine.onLeaveAction(txn, session)); + } + + @Test + public void testOnLeaveActionFromError() throws Exception { + CreatorSession session = getDefaultSession(ERROR); + assertEquals(session, engine.onLeaveAction(txn, session)); + } + + @Test + public void testOnLeaveActionFromInvited() throws Exception { + CreatorSession session = getDefaultSession(INVITED); + + expectOnLocalLeave(); + CreatorSession newSession = engine.onLeaveAction(txn, session); + assertEquals(DISSOLVED, newSession.getState()); + assertEquals(messageId, newSession.getLastLocalMessageId()); + assertEquals(lastRemoteMessageId, newSession.getLastRemoteMessageId()); + assertEquals(messageTimestamp, newSession.getLocalTimestamp()); + assertEquals(inviteTimestamp, newSession.getInviteTimestamp()); + assertSessionConstantsUnchanged(session, newSession); + } + + @Test + public void testOnLeaveActionFromJoined() throws Exception { + CreatorSession session = getDefaultSession(JOINED); + + expectOnLocalLeave(); + CreatorSession newSession = engine.onLeaveAction(txn, session); + assertEquals(DISSOLVED, newSession.getState()); + assertEquals(messageId, newSession.getLastLocalMessageId()); + assertEquals(lastRemoteMessageId, newSession.getLastRemoteMessageId()); + assertEquals(messageTimestamp, newSession.getLocalTimestamp()); + assertEquals(inviteTimestamp, newSession.getInviteTimestamp()); + assertSessionConstantsUnchanged(session, newSession); + } + + @Test + public void testOnLeaveActionFromLeft() throws Exception { + CreatorSession session = getDefaultSession(LEFT); + + expectOnLocalLeave(); + CreatorSession newSession = engine.onLeaveAction(txn, session); + assertEquals(DISSOLVED, newSession.getState()); + assertEquals(messageId, newSession.getLastLocalMessageId()); + assertEquals(lastRemoteMessageId, newSession.getLastRemoteMessageId()); + assertEquals(messageTimestamp, newSession.getLocalTimestamp()); + assertEquals(inviteTimestamp, newSession.getInviteTimestamp()); + assertSessionConstantsUnchanged(session, newSession); + } + + private void expectOnLocalLeave() throws Exception { + expectSetPrivateGroupVisibility(INVISIBLE); + expectSendLeaveMessage(); + } + + // onMemberAddedAction + + @Test + public void testOnMemberAddedAction() throws Exception { + CreatorSession session = getDefaultSession(START); + assertEquals(session, engine.onMemberAddedAction(txn, session)); + + session = getDefaultSession(INVITED); + assertEquals(session, engine.onMemberAddedAction(txn, session)); + + session = getDefaultSession(JOINED); + assertEquals(session, engine.onMemberAddedAction(txn, session)); + + session = getDefaultSession(LEFT); + assertEquals(session, engine.onMemberAddedAction(txn, session)); + + session = getDefaultSession(DISSOLVED); + assertEquals(session, engine.onMemberAddedAction(txn, session)); + + session = getDefaultSession(ERROR); + assertEquals(session, engine.onMemberAddedAction(txn, session)); + } + + // onInviteMessage + + @Test + public void testOnInviteMessageInAnyState() throws Exception { + InviteMessage inviteMessage = + new InviteMessage(new MessageId(getRandomId()), contactGroupId, + privateGroupId, inviteTimestamp, privateGroup.getName(), + author, privateGroup.getSalt(), null, signature); + + expectIsSubscribedPrivateGroup(); + expectSendAbortMessage(); + CreatorSession session = getDefaultSession(LEFT); + CreatorSession newSession = + engine.onInviteMessage(txn, session, inviteMessage); + assertEquals(ERROR, newSession.getState()); + + expectIsSubscribedPrivateGroup(); + expectSendAbortMessage(); + session = getDefaultSession(START); + newSession = + engine.onInviteMessage(txn, session, inviteMessage); + assertEquals(ERROR, newSession.getState()); + assertSessionRecordedSentMessage(newSession); + assertSessionConstantsUnchanged(session, newSession); + } + + // onJoinMessage + + @Test + public void testOnJoinMessageFromStart() throws Exception { + CreatorSession session = getDefaultSession(START); + + expectIsSubscribedPrivateGroup(); + expectSendAbortMessage(); + CreatorSession newSession = + engine.onJoinMessage(txn, session, joinMessage); + assertEquals(ERROR, newSession.getState()); + assertSessionRecordedSentMessage(newSession); + assertSessionConstantsUnchanged(session, newSession); + } + + @Test + public void testOnJoinMessageFromJoined() throws Exception { + CreatorSession session = getDefaultSession(JOINED); + + expectIsSubscribedPrivateGroup(); + expectSendAbortMessage(); + CreatorSession newSession = + engine.onJoinMessage(txn, session, joinMessage); + assertEquals(ERROR, newSession.getState()); + assertSessionRecordedSentMessage(newSession); + assertSessionConstantsUnchanged(session, newSession); + } + + @Test + public void testOnJoinMessageFromLeft() throws Exception { + CreatorSession session = getDefaultSession(LEFT); + + expectIsSubscribedPrivateGroup(); + expectSendAbortMessage(); + CreatorSession newSession = + engine.onJoinMessage(txn, session, joinMessage); + assertEquals(ERROR, newSession.getState()); + assertSessionRecordedSentMessage(newSession); + assertSessionConstantsUnchanged(session, newSession); + } + + @Test + public void testOnJoinMessageFromInvitedWithWrongTimestamp() + throws Exception { + CreatorSession session = getDefaultSession(INVITED); + + expectIsSubscribedPrivateGroup(); + expectSendAbortMessage(); + CreatorSession newSession = + engine.onJoinMessage(txn, session, joinMessage); + assertEquals(ERROR, newSession.getState()); + assertSessionRecordedSentMessage(newSession); + assertSessionConstantsUnchanged(session, newSession); + } + + @Test + public void testOnJoinMessageFromInvitedWithInvalidDependency() + throws Exception { + CreatorSession session = getDefaultSession(INVITED); + JoinMessage invalidJoinMessage = + new JoinMessage(messageId, contactGroupId, privateGroupId, + inviteTimestamp + 1, messageId); + + expectIsSubscribedPrivateGroup(); + expectSendAbortMessage(); + CreatorSession newSession = + engine.onJoinMessage(txn, session, invalidJoinMessage); + assertEquals(ERROR, newSession.getState()); + assertSessionRecordedSentMessage(newSession); + assertSessionConstantsUnchanged(session, newSession); + } + + @Test + public void testOnJoinMessageFromInvited() throws Exception { + CreatorSession session = getDefaultSession(INVITED); + JoinMessage properJoinMessage = + new JoinMessage(new MessageId(getRandomId()), contactGroupId, + privateGroupId, inviteTimestamp + 1, + lastRemoteMessageId); + + expectSendJoinMessage(properJoinMessage); + expectMarkMessageVisibleInUi(properJoinMessage.getId(), true); + context.checking(new Expectations() {{ + oneOf(messageTracker) + .trackMessage(txn, contactGroupId, inviteTimestamp + 1, + false); + }}); + expectGetContactId(); + expectSetPrivateGroupVisibility(SHARED); + CreatorSession newSession = + engine.onJoinMessage(txn, session, properJoinMessage); + assertEquals(JOINED, newSession.getState()); + assertEquals(messageId, newSession.getLastLocalMessageId()); + assertEquals(properJoinMessage.getId(), + newSession.getLastRemoteMessageId()); + assertEquals(messageTimestamp, newSession.getLocalTimestamp()); + assertEquals(inviteTimestamp, newSession.getInviteTimestamp()); + assertSessionConstantsUnchanged(session, newSession); + } + + @Test + public void testOnJoinMessageFromDissolved() throws Exception { + CreatorSession session = getDefaultSession(DISSOLVED); + assertEquals(session, engine.onJoinMessage(txn, session, joinMessage)); + } + + @Test + public void testOnJoinMessageFromError() throws Exception { + CreatorSession session = getDefaultSession(ERROR); + assertEquals(session, engine.onJoinMessage(txn, session, joinMessage)); + } + + // onLeaveMessage + + @Test + public void testOnLeaveMessageFromStart() throws Exception { + LeaveMessage leaveMessage = + new LeaveMessage(messageId, contactGroupId, privateGroupId, + inviteTimestamp, lastLocalMessageId); + CreatorSession session = getDefaultSession(START); + + expectIsSubscribedPrivateGroup(); + expectSendAbortMessage(); + CreatorSession newSession = + engine.onLeaveMessage(txn, session, leaveMessage); + assertEquals(ERROR, newSession.getState()); + assertSessionRecordedSentMessage(newSession); + assertSessionConstantsUnchanged(session, newSession); + } + + @Test + public void testOnLeaveMessageFromLeft() throws Exception { + CreatorSession session = getDefaultSession(LEFT); + + expectIsSubscribedPrivateGroup(); + expectSendAbortMessage(); + CreatorSession newSession = + engine.onLeaveMessage(txn, session, leaveMessage); + assertEquals(ERROR, newSession.getState()); + assertSessionRecordedSentMessage(newSession); + assertSessionConstantsUnchanged(session, newSession); + } + + @Test + public void testOnLeaveMessageFromInvitedWithWrongTime() throws Exception { + CreatorSession session = getDefaultSession(INVITED); + + expectIsSubscribedPrivateGroup(); + expectSendAbortMessage(); + CreatorSession newSession = + engine.onLeaveMessage(txn, session, leaveMessage); + assertEquals(ERROR, newSession.getState()); + assertSessionRecordedSentMessage(newSession); + assertSessionConstantsUnchanged(session, newSession); + } + + @Test + public void testOnLeaveMessageFromInvitedWithWrongDependency() + throws Exception { + LeaveMessage invalidLeaveMessage = + new LeaveMessage(messageId, contactGroupId, privateGroupId, + inviteTimestamp + 1, lastLocalMessageId); + CreatorSession session = getDefaultSession(INVITED); + + expectIsSubscribedPrivateGroup(); + expectSendAbortMessage(); + CreatorSession newSession = + engine.onLeaveMessage(txn, session, invalidLeaveMessage); + assertEquals(ERROR, newSession.getState()); + assertSessionRecordedSentMessage(newSession); + assertSessionConstantsUnchanged(session, newSession); + } + + @Test + public void testOnLeaveMessageFromInvited() + throws Exception { + LeaveMessage properLeaveMessage = + new LeaveMessage(new MessageId(getRandomId()), contactGroupId, + privateGroupId, inviteTimestamp + 1, + lastRemoteMessageId); + CreatorSession session = getDefaultSession(INVITED); + + expectMarkMessageVisibleInUi(properLeaveMessage.getId(), true); + context.checking(new Expectations() {{ + oneOf(messageTracker) + .trackMessage(txn, contactGroupId, inviteTimestamp + 1, + false); + }}); + expectGetContactId(); + CreatorSession newSession = + engine.onLeaveMessage(txn, session, properLeaveMessage); + assertEquals(START, newSession.getState()); + assertEquals(lastLocalMessageId, newSession.getLastLocalMessageId()); + assertEquals(properLeaveMessage.getId(), + newSession.getLastRemoteMessageId()); + assertEquals(localTimestamp, newSession.getLocalTimestamp()); + assertEquals(inviteTimestamp, newSession.getInviteTimestamp()); + assertSessionConstantsUnchanged(session, newSession); + } + + @Test + public void testOnLeaveMessageFromDissolved() throws Exception { + CreatorSession session = getDefaultSession(DISSOLVED); + assertEquals(session, + engine.onLeaveMessage(txn, session, leaveMessage)); + } + + @Test + public void testOnLeaveMessageFromError() throws Exception { + CreatorSession session = getDefaultSession(ERROR); + assertEquals(session, + engine.onLeaveMessage(txn, session, leaveMessage)); + } + + // onAbortMessage + + @Test + public void testOnAbortMessageWhenNotSubscribed() throws Exception { + AbortMessage abortMessage = + new AbortMessage(messageId, contactGroupId, privateGroupId, + inviteTimestamp + 1); + CreatorSession session = getDefaultSession(START); + + expectIsNotSubscribedPrivateGroup(); + expectSendAbortMessage(); + CreatorSession newSession = + engine.onAbortMessage(txn, session, abortMessage); + assertEquals(ERROR, newSession.getState()); + assertSessionRecordedSentMessage(newSession); + assertSessionConstantsUnchanged(session, newSession); + } + + @Test + public void testOnAbortMessageWhenSubscribed() throws Exception { + AbortMessage abortMessage = + new AbortMessage(messageId, contactGroupId, privateGroupId, + inviteTimestamp + 1); + CreatorSession session = getDefaultSession(START); + + expectIsSubscribedPrivateGroup(); + expectSendAbortMessage(); + CreatorSession newSession = + engine.onAbortMessage(txn, session, abortMessage); + assertEquals(ERROR, newSession.getState()); + assertSessionRecordedSentMessage(newSession); + assertSessionConstantsUnchanged(session, newSession); + } + +}