mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-04-19 06:24:34 +02:00
Merge branch '1627-delete-completed-privategroup-sessions' into 'master'
Delete conversation messages belonging to completed private group sessions Closes #1627 See merge request briar/briar!1167
This commit is contained in:
@@ -139,7 +139,7 @@
|
||||
<string name="dialog_title_delete_all_messages">Confirm Message Deletion</string>
|
||||
<string name="dialog_message_delete_all_messages">Are you sure that you want to delete all messages?</string>
|
||||
<string name="dialog_title_not_all_messages_deleted">Could not delete all messages</string>
|
||||
<string name="dialog_message_not_all_messages_deleted">Messages related to introductions or invitations cannot be deleted at the moment.</string>
|
||||
<string name="dialog_message_not_all_messages_deleted">Messages related to ongoing introductions or invitations cannot be deleted until they conclude.</string>
|
||||
<string name="delete_contact">Delete contact</string>
|
||||
<string name="dialog_title_delete_contact">Confirm Contact Deletion</string>
|
||||
<string name="dialog_message_delete_contact">Are you sure that you want to remove this contact and all messages exchanged with this contact?</string>
|
||||
|
||||
+5
@@ -38,6 +38,11 @@ enum CreatorState implements State {
|
||||
return visibility;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAwaitingResponse() {
|
||||
return this == INVITED;
|
||||
}
|
||||
|
||||
static CreatorState fromValue(int value) throws FormatException {
|
||||
for (CreatorState s : values()) if (s.value == value) return s;
|
||||
throw new FormatException();
|
||||
|
||||
+130
-3
@@ -40,6 +40,7 @@ import org.briarproject.briar.client.ConversationClientImpl;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
@@ -369,7 +370,8 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ConversationMessageHeader> getMessageHeaders(Transaction txn,
|
||||
public Collection<ConversationMessageHeader> getMessageHeaders(
|
||||
Transaction txn,
|
||||
ContactId c) throws DbException {
|
||||
try {
|
||||
Contact contact = db.getContact(txn, c);
|
||||
@@ -633,8 +635,98 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
|
||||
@Override
|
||||
public boolean deleteAllMessages(Transaction txn, ContactId c)
|
||||
throws DbException {
|
||||
// TODO actually delete messages (#1627 and #1629)
|
||||
return getMessageIds(txn, c).size() == 0;
|
||||
// get ID of the contact group
|
||||
GroupId g = getContactGroup(db.getContact(txn, c)).getId();
|
||||
|
||||
// get metadata for all messages in the
|
||||
// (these are sessions *and* protocol messages)
|
||||
Map<MessageId, BdfDictionary> metadata;
|
||||
try {
|
||||
metadata = clientHelper.getMessageMetadataAsDictionary(txn, g);
|
||||
} catch (FormatException e) {
|
||||
throw new DbException(e);
|
||||
}
|
||||
|
||||
// get all sessions and their states
|
||||
Map<GroupId, DeletableSession> sessions = new HashMap<>();
|
||||
for (BdfDictionary d : metadata.values()) {
|
||||
if (!sessionParser.isSession(d)) continue;
|
||||
Session session;
|
||||
try {
|
||||
Role role = sessionParser.getRole(d);
|
||||
if (role == CREATOR) {
|
||||
session = sessionParser.parseCreatorSession(g, d);
|
||||
} else if (role == INVITEE) {
|
||||
session = sessionParser.parseInviteeSession(g, d);
|
||||
} else if (role == PEER) {
|
||||
session = sessionParser.parsePeerSession(g, d);
|
||||
} else throw new AssertionError("unknown role");
|
||||
} catch (FormatException e) {
|
||||
throw new DbException(e);
|
||||
}
|
||||
sessions.put(session.getPrivateGroupId(),
|
||||
new DeletableSession(session.getState()));
|
||||
}
|
||||
|
||||
// assign protocol messages to their sessions
|
||||
for (Entry<MessageId, BdfDictionary> entry : metadata.entrySet()) {
|
||||
// skip all sessions, we are only interested in messages
|
||||
BdfDictionary d = entry.getValue();
|
||||
if (sessionParser.isSession(d)) continue;
|
||||
|
||||
// parse message metadata and skip messages not visible in UI
|
||||
MessageMetadata m;
|
||||
try {
|
||||
m = messageParser.parseMetadata(d);
|
||||
} catch (FormatException e) {
|
||||
throw new DbException(e);
|
||||
}
|
||||
if (!m.isVisibleInConversation()) continue;
|
||||
|
||||
// add visible messages to session
|
||||
DeletableSession session = sessions.get(m.getPrivateGroupId());
|
||||
session.messages.add(entry.getKey());
|
||||
}
|
||||
|
||||
// get a set of all messages which were not ACKed by the contact
|
||||
Set<MessageId> notAcked = new HashSet<>();
|
||||
for (MessageStatus status : db.getMessageStatus(txn, c, g)) {
|
||||
if (!status.isSeen()) notAcked.add(status.getMessageId());
|
||||
}
|
||||
boolean allDeleted =
|
||||
deleteCompletedSessions(txn, sessions.values(), notAcked);
|
||||
recalculateGroupCount(txn, g);
|
||||
return allDeleted;
|
||||
}
|
||||
|
||||
private boolean deleteCompletedSessions(Transaction txn,
|
||||
Collection<DeletableSession> sessions, Set<MessageId> notAcked)
|
||||
throws DbException {
|
||||
// find completed sessions to delete
|
||||
boolean allDeleted = true;
|
||||
for (DeletableSession session : sessions) {
|
||||
if (session.state.isAwaitingResponse()) {
|
||||
allDeleted = false;
|
||||
continue;
|
||||
}
|
||||
// we can only delete sessions
|
||||
// where delivery of all messages was confirmed (aka ACKed)
|
||||
boolean allAcked = true;
|
||||
for (MessageId m : session.messages) {
|
||||
if (notAcked.contains(m)) {
|
||||
allAcked = false;
|
||||
allDeleted = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (allAcked) {
|
||||
for (MessageId m : session.messages) {
|
||||
db.deleteMessage(txn, m);
|
||||
db.deleteMessageMetadata(txn, m);
|
||||
}
|
||||
}
|
||||
}
|
||||
return allDeleted;
|
||||
}
|
||||
|
||||
private Set<MessageId> getMessageIds(Transaction txn, ContactId c)
|
||||
@@ -650,6 +742,31 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
|
||||
}
|
||||
}
|
||||
|
||||
private void recalculateGroupCount(Transaction txn, GroupId g)
|
||||
throws DbException {
|
||||
BdfDictionary query = messageParser.getMessagesVisibleInUiQuery();
|
||||
Map<MessageId, BdfDictionary> results;
|
||||
try {
|
||||
results =
|
||||
clientHelper.getMessageMetadataAsDictionary(txn, g, query);
|
||||
} catch (FormatException e) {
|
||||
throw new DbException(e);
|
||||
}
|
||||
int msgCount = 0;
|
||||
int unreadCount = 0;
|
||||
for (Entry<MessageId, BdfDictionary> entry : results.entrySet()) {
|
||||
MessageMetadata meta;
|
||||
try {
|
||||
meta = messageParser.parseMetadata(entry.getValue());
|
||||
} catch (FormatException e) {
|
||||
throw new DbException(e);
|
||||
}
|
||||
msgCount++;
|
||||
if (!meta.isRead()) unreadCount++;
|
||||
}
|
||||
messageTracker.resetGroupCount(txn, g, msgCount, unreadCount);
|
||||
}
|
||||
|
||||
private static class StoredSession {
|
||||
|
||||
private final MessageId storageId;
|
||||
@@ -660,4 +777,14 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
|
||||
this.bdfSession = bdfSession;
|
||||
}
|
||||
}
|
||||
|
||||
private static class DeletableSession {
|
||||
|
||||
private final State state;
|
||||
private final List<MessageId> messages = new ArrayList<>();
|
||||
|
||||
private DeletableSession(State state) {
|
||||
this.state = state;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -40,6 +40,11 @@ enum InviteeState implements State {
|
||||
return visibility;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAwaitingResponse() {
|
||||
return this == INVITED;
|
||||
}
|
||||
|
||||
static InviteeState fromValue(int value) throws FormatException {
|
||||
for (InviteeState s : values()) if (s.value == value) return s;
|
||||
throw new FormatException();
|
||||
|
||||
@@ -40,6 +40,11 @@ enum PeerState implements State {
|
||||
return visibility;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isAwaitingResponse() {
|
||||
return false;
|
||||
}
|
||||
|
||||
static PeerState fromValue(int value) throws FormatException {
|
||||
for (PeerState s : values()) if (s.value == value) return s;
|
||||
throw new FormatException();
|
||||
|
||||
+2
@@ -15,6 +15,8 @@ interface SessionParser {
|
||||
|
||||
Role getRole(BdfDictionary d) throws FormatException;
|
||||
|
||||
boolean isSession(BdfDictionary d);
|
||||
|
||||
CreatorSession parseCreatorSession(GroupId contactGroupId, BdfDictionary d)
|
||||
throws FormatException;
|
||||
|
||||
|
||||
+5
@@ -48,6 +48,11 @@ class SessionParserImpl implements SessionParser {
|
||||
return Role.fromValue(d.getLong(SESSION_KEY_ROLE).intValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSession(BdfDictionary d) {
|
||||
return d.getBoolean(SESSION_KEY_IS_SESSION, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CreatorSession parseCreatorSession(GroupId contactGroupId,
|
||||
BdfDictionary d) throws FormatException {
|
||||
|
||||
@@ -7,4 +7,6 @@ interface State {
|
||||
int getValue();
|
||||
|
||||
Visibility getVisibility();
|
||||
|
||||
boolean isAwaitingResponse();
|
||||
}
|
||||
|
||||
+183
-62
@@ -31,7 +31,7 @@ import static org.junit.Assert.fail;
|
||||
public class GroupInvitationIntegrationTest
|
||||
extends BriarIntegrationTest<BriarIntegrationTestComponent> {
|
||||
|
||||
private PrivateGroup privateGroup0;
|
||||
private PrivateGroup privateGroup;
|
||||
private PrivateGroupManager groupManager0, groupManager1;
|
||||
private GroupInvitationManager groupInvitationManager0,
|
||||
groupInvitationManager1;
|
||||
@@ -46,12 +46,12 @@ public class GroupInvitationIntegrationTest
|
||||
groupInvitationManager0 = c0.getGroupInvitationManager();
|
||||
groupInvitationManager1 = c1.getGroupInvitationManager();
|
||||
|
||||
privateGroup0 =
|
||||
privateGroup =
|
||||
privateGroupFactory.createPrivateGroup("Testgroup", author0);
|
||||
long joinTime = clock.currentTimeMillis();
|
||||
GroupMessage joinMsg0 = groupMessageFactory
|
||||
.createJoinMessage(privateGroup0.getId(), joinTime, author0);
|
||||
groupManager0.addPrivateGroup(privateGroup0, joinMsg0, true);
|
||||
.createJoinMessage(privateGroup.getId(), joinTime, author0);
|
||||
groupManager0.addPrivateGroup(privateGroup, joinMsg0, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -90,21 +90,19 @@ public class GroupInvitationIntegrationTest
|
||||
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());
|
||||
assertEquals(privateGroup, item.getShareable());
|
||||
assertEquals(privateGroup.getId(), item.getId());
|
||||
assertEquals(privateGroup.getName(), item.getName());
|
||||
assertFalse(item.isSubscribed());
|
||||
|
||||
Collection<ConversationMessageHeader> messages =
|
||||
db1.transactionWithResult(true, txn -> groupInvitationManager1
|
||||
.getMessageHeaders(txn, contactId0From1));
|
||||
Collection<ConversationMessageHeader> messages = getMessages0From1();
|
||||
assertEquals(1, messages.size());
|
||||
GroupInvitationRequest request =
|
||||
(GroupInvitationRequest) messages.iterator().next();
|
||||
assertEquals(text, request.getText());
|
||||
assertEquals(author0, request.getNameable().getCreator());
|
||||
assertEquals(timestamp, request.getTimestamp());
|
||||
assertEquals(privateGroup0.getName(), request.getNameable().getName());
|
||||
assertEquals(privateGroup.getName(), request.getNameable().getName());
|
||||
assertFalse(request.isLocal());
|
||||
assertFalse(request.isRead());
|
||||
assertFalse(request.canBeOpened());
|
||||
@@ -120,18 +118,16 @@ public class GroupInvitationIntegrationTest
|
||||
assertFalse(groupInvitationManager1.getInvitations().isEmpty());
|
||||
|
||||
groupInvitationManager1
|
||||
.respondToInvitation(contactId0From1, privateGroup0, false);
|
||||
.respondToInvitation(contactId0From1, privateGroup, false);
|
||||
|
||||
Collection<ConversationMessageHeader> messages =
|
||||
db1.transactionWithResult(true, txn -> groupInvitationManager1
|
||||
.getMessageHeaders(txn, contactId0From1));
|
||||
Collection<ConversationMessageHeader> messages = getMessages0From1();
|
||||
assertEquals(2, messages.size());
|
||||
boolean foundResponse = false;
|
||||
for (ConversationMessageHeader m : messages) {
|
||||
if (m instanceof GroupInvitationResponse) {
|
||||
foundResponse = true;
|
||||
GroupInvitationResponse response = (GroupInvitationResponse) m;
|
||||
assertEquals(privateGroup0.getId(), response.getShareableId());
|
||||
assertEquals(privateGroup.getId(), response.getShareableId());
|
||||
assertTrue(response.isLocal());
|
||||
assertFalse(response.wasAccepted());
|
||||
}
|
||||
@@ -140,16 +136,14 @@ public class GroupInvitationIntegrationTest
|
||||
|
||||
sync1To0(1, true);
|
||||
|
||||
messages = db0.transactionWithResult(true, txn ->
|
||||
groupInvitationManager0
|
||||
.getMessageHeaders(txn, contactId1From0));
|
||||
messages = getMessages1From0();
|
||||
assertEquals(2, messages.size());
|
||||
foundResponse = false;
|
||||
for (ConversationMessageHeader m : messages) {
|
||||
if (m instanceof GroupInvitationResponse) {
|
||||
foundResponse = true;
|
||||
GroupInvitationResponse response = (GroupInvitationResponse) m;
|
||||
assertEquals(privateGroup0.getId(), response.getShareableId());
|
||||
assertEquals(privateGroup.getId(), response.getShareableId());
|
||||
assertFalse(response.isLocal());
|
||||
assertFalse(response.wasAccepted());
|
||||
}
|
||||
@@ -168,9 +162,7 @@ public class GroupInvitationIntegrationTest
|
||||
sendInvitation(timestamp, null);
|
||||
|
||||
// check that invitation message state is correct
|
||||
Collection<ConversationMessageHeader> messages =
|
||||
db0.transactionWithResult(true, txn -> groupInvitationManager0
|
||||
.getMessageHeaders(txn, contactId1From0));
|
||||
Collection<ConversationMessageHeader> messages = getMessages1From0();
|
||||
assertEquals(1, messages.size());
|
||||
assertMessageState(messages.iterator().next(), true, false, false);
|
||||
|
||||
@@ -178,11 +170,9 @@ public class GroupInvitationIntegrationTest
|
||||
assertFalse(groupInvitationManager1.getInvitations().isEmpty());
|
||||
|
||||
groupInvitationManager1
|
||||
.respondToInvitation(contactId0From1, privateGroup0, true);
|
||||
.respondToInvitation(contactId0From1, privateGroup, true);
|
||||
|
||||
messages = db1.transactionWithResult(true,
|
||||
txn -> groupInvitationManager1
|
||||
.getMessageHeaders(txn, contactId0From1));
|
||||
messages = getMessages0From1();
|
||||
assertEquals(2, messages.size());
|
||||
boolean foundResponse = false;
|
||||
for (ConversationMessageHeader m : messages) {
|
||||
@@ -190,11 +180,11 @@ public class GroupInvitationIntegrationTest
|
||||
foundResponse = true;
|
||||
GroupInvitationResponse response = (GroupInvitationResponse) m;
|
||||
assertMessageState(response, true, false, false);
|
||||
assertEquals(privateGroup0.getId(), response.getShareableId());
|
||||
assertEquals(privateGroup.getId(), response.getShareableId());
|
||||
assertTrue(response.wasAccepted());
|
||||
} else {
|
||||
GroupInvitationRequest request = (GroupInvitationRequest) m;
|
||||
assertEquals(privateGroup0, request.getNameable());
|
||||
assertEquals(privateGroup, request.getNameable());
|
||||
assertTrue(request.wasAnswered());
|
||||
assertTrue(request.canBeOpened());
|
||||
}
|
||||
@@ -203,16 +193,14 @@ public class GroupInvitationIntegrationTest
|
||||
|
||||
sync1To0(1, true);
|
||||
|
||||
messages = db1.transactionWithResult(true, txn ->
|
||||
groupInvitationManager0
|
||||
.getMessageHeaders(txn, contactId1From0));
|
||||
messages = getMessages1From0();
|
||||
assertEquals(2, messages.size());
|
||||
foundResponse = false;
|
||||
for (ConversationMessageHeader m : messages) {
|
||||
if (m instanceof GroupInvitationResponse) {
|
||||
foundResponse = true;
|
||||
GroupInvitationResponse response = (GroupInvitationResponse) m;
|
||||
assertEquals(privateGroup0.getId(), response.getShareableId());
|
||||
assertEquals(privateGroup.getId(), response.getShareableId());
|
||||
assertTrue(response.wasAccepted());
|
||||
}
|
||||
}
|
||||
@@ -223,7 +211,7 @@ public class GroupInvitationIntegrationTest
|
||||
// group was added
|
||||
Collection<PrivateGroup> groups = groupManager1.getPrivateGroups();
|
||||
assertEquals(1, groups.size());
|
||||
assertEquals(privateGroup0, groups.iterator().next());
|
||||
assertEquals(privateGroup, groups.iterator().next());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -240,12 +228,10 @@ public class GroupInvitationIntegrationTest
|
||||
// 1 has one unread message
|
||||
Group g0 = groupInvitationManager1.getContactGroup(contact0From1);
|
||||
assertGroupCount(messageTracker1, g0.getId(), 1, 1, timestamp);
|
||||
ConversationMessageHeader m = db1.transactionWithResult(true, txn ->
|
||||
groupInvitationManager1.getMessageHeaders(txn, contactId0From1)
|
||||
.iterator().next());
|
||||
ConversationMessageHeader m = getMessages0From1().iterator().next();
|
||||
|
||||
groupInvitationManager1
|
||||
.respondToInvitation(contactId0From1, privateGroup0, true);
|
||||
.respondToInvitation(contactId0From1, privateGroup, true);
|
||||
|
||||
// 1 has two messages, one still unread
|
||||
assertGroupCount(messageTracker1, g0.getId(), 2, 1);
|
||||
@@ -266,28 +252,28 @@ public class GroupInvitationIntegrationTest
|
||||
|
||||
// invitation is not allowed before the first hasn't been answered
|
||||
assertFalse(groupInvitationManager0
|
||||
.isInvitationAllowed(contact1From0, privateGroup0.getId()));
|
||||
.isInvitationAllowed(contact1From0, privateGroup.getId()));
|
||||
|
||||
// deliver invitation and response
|
||||
sync0To1(1, true);
|
||||
groupInvitationManager1
|
||||
.respondToInvitation(contactId0From1, privateGroup0, false);
|
||||
.respondToInvitation(contactId0From1, privateGroup, false);
|
||||
sync1To0(1, true);
|
||||
|
||||
// after invitation was declined, inviting again is possible
|
||||
assertTrue(groupInvitationManager0
|
||||
.isInvitationAllowed(contact1From0, privateGroup0.getId()));
|
||||
.isInvitationAllowed(contact1From0, privateGroup.getId()));
|
||||
|
||||
// send and accept the second invitation
|
||||
sendInvitation(clock.currentTimeMillis(), "Second Invitation");
|
||||
sync0To1(1, true);
|
||||
groupInvitationManager1
|
||||
.respondToInvitation(contactId0From1, privateGroup0, true);
|
||||
.respondToInvitation(contactId0From1, privateGroup, true);
|
||||
sync1To0(1, true);
|
||||
|
||||
// invitation is not allowed since the member joined the group now
|
||||
assertFalse(groupInvitationManager0
|
||||
.isInvitationAllowed(contact1From0, privateGroup0.getId()));
|
||||
.isInvitationAllowed(contact1From0, privateGroup.getId()));
|
||||
|
||||
// don't allow another invitation request
|
||||
try {
|
||||
@@ -305,14 +291,14 @@ public class GroupInvitationIntegrationTest
|
||||
sync0To1(1, true);
|
||||
|
||||
groupInvitationManager1
|
||||
.respondToInvitation(contactId0From1, privateGroup0, false);
|
||||
.respondToInvitation(contactId0From1, privateGroup, false);
|
||||
sync1To0(1, true);
|
||||
|
||||
sendInvitation(timestamp, "Second Invitation");
|
||||
sync0To1(1, true);
|
||||
|
||||
groupInvitationManager1
|
||||
.respondToInvitation(contactId0From1, privateGroup0, true);
|
||||
.respondToInvitation(contactId0From1, privateGroup, true);
|
||||
}
|
||||
|
||||
@Test(expected = ProtocolStateException.class)
|
||||
@@ -325,7 +311,7 @@ public class GroupInvitationIntegrationTest
|
||||
|
||||
// Creator leaves group
|
||||
assertEquals(1, groupManager0.getPrivateGroups().size());
|
||||
groupManager0.removePrivateGroup(privateGroup0.getId());
|
||||
groupManager0.removePrivateGroup(privateGroup.getId());
|
||||
assertEquals(0, groupManager0.getPrivateGroups().size());
|
||||
|
||||
// Creator's leave message is delivered to invitee
|
||||
@@ -335,7 +321,7 @@ public class GroupInvitationIntegrationTest
|
||||
// thrown as the action has failed
|
||||
assertEquals(0, groupManager1.getPrivateGroups().size());
|
||||
groupInvitationManager1
|
||||
.respondToInvitation(contactId0From1, privateGroup0, true);
|
||||
.respondToInvitation(contactId0From1, privateGroup, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -348,7 +334,7 @@ public class GroupInvitationIntegrationTest
|
||||
|
||||
// Creator leaves group
|
||||
assertEquals(1, groupManager0.getPrivateGroups().size());
|
||||
groupManager0.removePrivateGroup(privateGroup0.getId());
|
||||
groupManager0.removePrivateGroup(privateGroup.getId());
|
||||
assertEquals(0, groupManager0.getPrivateGroups().size());
|
||||
|
||||
// Creator's leave message is delivered to invitee
|
||||
@@ -361,7 +347,7 @@ public class GroupInvitationIntegrationTest
|
||||
// as the action has succeeded
|
||||
assertEquals(0, groupManager1.getPrivateGroups().size());
|
||||
groupInvitationManager1
|
||||
.respondToInvitation(contactId0From1, privateGroup0, false);
|
||||
.respondToInvitation(contactId0From1, privateGroup, false);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -375,15 +361,15 @@ public class GroupInvitationIntegrationTest
|
||||
|
||||
// Creator leaves group
|
||||
assertEquals(1, groupManager0.getPrivateGroups().size());
|
||||
groupManager0.removePrivateGroup(privateGroup0.getId());
|
||||
groupManager0.removePrivateGroup(privateGroup.getId());
|
||||
assertEquals(0, groupManager0.getPrivateGroups().size());
|
||||
|
||||
// Invitee accepts invitation
|
||||
assertEquals(0, groupManager1.getPrivateGroups().size());
|
||||
groupInvitationManager1
|
||||
.respondToInvitation(contactId0From1, privateGroup0, true);
|
||||
.respondToInvitation(contactId0From1, privateGroup, true);
|
||||
assertEquals(1, groupManager1.getPrivateGroups().size());
|
||||
assertFalse(groupManager1.isDissolved(privateGroup0.getId()));
|
||||
assertFalse(groupManager1.isDissolved(privateGroup.getId()));
|
||||
|
||||
// Invitee's join message is delivered to creator
|
||||
sync1To0(1, true);
|
||||
@@ -392,7 +378,7 @@ public class GroupInvitationIntegrationTest
|
||||
sync0To1(1, true);
|
||||
|
||||
// Group is marked as dissolved
|
||||
assertTrue(groupManager1.isDissolved(privateGroup0.getId()));
|
||||
assertTrue(groupManager1.isDissolved(privateGroup.getId()));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -406,13 +392,13 @@ public class GroupInvitationIntegrationTest
|
||||
|
||||
// Creator leaves group
|
||||
assertEquals(1, groupManager0.getPrivateGroups().size());
|
||||
groupManager0.removePrivateGroup(privateGroup0.getId());
|
||||
groupManager0.removePrivateGroup(privateGroup.getId());
|
||||
assertEquals(0, groupManager0.getPrivateGroups().size());
|
||||
|
||||
// Invitee declines invitation
|
||||
assertEquals(0, groupManager1.getPrivateGroups().size());
|
||||
groupInvitationManager1
|
||||
.respondToInvitation(contactId0From1, privateGroup0, false);
|
||||
.respondToInvitation(contactId0From1, privateGroup, false);
|
||||
assertEquals(0, groupManager1.getPrivateGroups().size());
|
||||
|
||||
// Invitee's leave message is delivered to creator
|
||||
@@ -434,7 +420,7 @@ public class GroupInvitationIntegrationTest
|
||||
// Invitee responds to invitation
|
||||
assertEquals(0, groupManager1.getPrivateGroups().size());
|
||||
groupInvitationManager1
|
||||
.respondToInvitation(contactId0From1, privateGroup0, true);
|
||||
.respondToInvitation(contactId0From1, privateGroup, true);
|
||||
assertEquals(1, groupManager1.getPrivateGroups().size());
|
||||
|
||||
// Invitee's (sharing) join message is delivered to creator
|
||||
@@ -448,11 +434,11 @@ public class GroupInvitationIntegrationTest
|
||||
|
||||
// Creator leaves group
|
||||
assertEquals(1, groupManager0.getPrivateGroups().size());
|
||||
groupManager0.removePrivateGroup(privateGroup0.getId());
|
||||
groupManager0.removePrivateGroup(privateGroup.getId());
|
||||
assertEquals(0, groupManager0.getPrivateGroups().size());
|
||||
|
||||
// Invitee leaves group
|
||||
groupManager1.removePrivateGroup(privateGroup0.getId());
|
||||
groupManager1.removePrivateGroup(privateGroup.getId());
|
||||
assertEquals(0, groupManager1.getPrivateGroups().size());
|
||||
|
||||
// Creator's leave message is delivered to invitee
|
||||
@@ -462,13 +448,148 @@ public class GroupInvitationIntegrationTest
|
||||
sync1To0(1, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeletingAllMessagesWhenCompletingSession()
|
||||
throws Exception {
|
||||
// send invitation
|
||||
sendInvitation(clock.currentTimeMillis(), null);
|
||||
sync0To1(1, true);
|
||||
|
||||
// messages can not be deleted
|
||||
assertFalse(deleteAllMessages1From0());
|
||||
assertEquals(1, getMessages1From0().size());
|
||||
assertFalse(deleteAllMessages0From1());
|
||||
assertEquals(1, getMessages0From1().size());
|
||||
|
||||
// respond
|
||||
groupInvitationManager1
|
||||
.respondToInvitation(contactId0From1, privateGroup, true);
|
||||
sync1To0(1, true);
|
||||
|
||||
// check group count
|
||||
Group g1From0 = groupInvitationManager0.getContactGroup(contact1From0);
|
||||
Group g0From1 = groupInvitationManager1.getContactGroup(contact0From1);
|
||||
assertGroupCount(messageTracker0, g1From0.getId(), 2, 1);
|
||||
assertGroupCount(messageTracker1, g0From1.getId(), 2, 1);
|
||||
|
||||
// messages can be deleted now by creator, invitee needs to wait for ACK
|
||||
assertTrue(deleteAllMessages1From0());
|
||||
assertEquals(0, getMessages1From0().size());
|
||||
assertTrue(deleteAllMessages1From0()); // a second time nothing happens
|
||||
assertGroupCount(messageTracker0, g1From0.getId(), 0, 0);
|
||||
|
||||
// trying to delete fails for invitee
|
||||
assertFalse(deleteAllMessages0From1());
|
||||
assertEquals(2, getMessages0From1().size());
|
||||
|
||||
// creator sends JOIN message and ACK for response
|
||||
sync0To1(1, true);
|
||||
|
||||
// now invitee can also delete messages
|
||||
assertTrue(deleteAllMessages0From1());
|
||||
assertEquals(0, getMessages0From1().size());
|
||||
assertTrue(deleteAllMessages0From1()); // a second time nothing happens
|
||||
assertGroupCount(messageTracker1, g0From1.getId(), 0, 0);
|
||||
|
||||
// invitee now leaves
|
||||
groupManager1.removePrivateGroup(privateGroup.getId());
|
||||
sync1To0(1, true);
|
||||
|
||||
// no new messages to delete
|
||||
assertEquals(0, getMessages1From0().size());
|
||||
assertEquals(0, getMessages0From1().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeletingAllMessagesWhenDeclining() throws Exception {
|
||||
// send invitation
|
||||
sendInvitation(clock.currentTimeMillis(), null);
|
||||
sync0To1(1, true);
|
||||
|
||||
// respond
|
||||
groupInvitationManager1
|
||||
.respondToInvitation(contactId0From1, privateGroup, false);
|
||||
sync1To0(1, true);
|
||||
|
||||
// check group count
|
||||
Group g1From0 = groupInvitationManager0.getContactGroup(contact1From0);
|
||||
Group g0From1 = groupInvitationManager1.getContactGroup(contact0From1);
|
||||
assertGroupCount(messageTracker0, g1From0.getId(), 2, 1);
|
||||
assertGroupCount(messageTracker1, g0From1.getId(), 2, 1);
|
||||
|
||||
// messages can be deleted now by creator, invitee needs to wait for ACK
|
||||
assertTrue(deleteAllMessages1From0());
|
||||
assertEquals(0, getMessages1From0().size());
|
||||
assertTrue(deleteAllMessages1From0()); // a second time nothing happens
|
||||
|
||||
// trying to delete fails for invitee
|
||||
assertFalse(deleteAllMessages0From1());
|
||||
assertEquals(2, getMessages0From1().size());
|
||||
|
||||
// creator sends ACK
|
||||
sendAcks(c0, c1, contactId1From0, 1);
|
||||
|
||||
// now invitee can also delete messages
|
||||
assertTrue(deleteAllMessages0From1());
|
||||
assertEquals(0, getMessages0From1().size());
|
||||
assertTrue(deleteAllMessages0From1()); // a second time nothing happens
|
||||
assertGroupCount(messageTracker1, g0From1.getId(), 0, 0);
|
||||
|
||||
// creator can re-invite
|
||||
sendInvitation(clock.currentTimeMillis(), null);
|
||||
sync0To1(1, true);
|
||||
|
||||
// now new messages can not be deleted anymore
|
||||
assertFalse(deleteAllMessages1From0());
|
||||
assertFalse(deleteAllMessages0From1());
|
||||
|
||||
// responding again
|
||||
groupInvitationManager1
|
||||
.respondToInvitation(contactId0From1, privateGroup, false);
|
||||
sync1To0(1, true);
|
||||
|
||||
// creator sends ACK
|
||||
sendAcks(c0, c1, contactId1From0, 1);
|
||||
|
||||
// asserting group counts
|
||||
assertGroupCount(messageTracker1, g0From1.getId(), 2, 1);
|
||||
assertGroupCount(messageTracker0, g1From0.getId(), 2, 1);
|
||||
|
||||
// deleting is possible again
|
||||
assertTrue(deleteAllMessages1From0());
|
||||
assertTrue(deleteAllMessages0From1());
|
||||
assertGroupCount(messageTracker1, g0From1.getId(), 0, 0);
|
||||
assertGroupCount(messageTracker0, g1From0.getId(), 0, 0);
|
||||
}
|
||||
|
||||
private Collection<ConversationMessageHeader> getMessages1From0()
|
||||
throws DbException {
|
||||
return db0.transactionWithResult(true, txn -> groupInvitationManager0
|
||||
.getMessageHeaders(txn, contactId1From0));
|
||||
}
|
||||
|
||||
private Collection<ConversationMessageHeader> getMessages0From1()
|
||||
throws DbException {
|
||||
return db1.transactionWithResult(true, txn -> groupInvitationManager1
|
||||
.getMessageHeaders(txn, contactId0From1));
|
||||
}
|
||||
|
||||
private boolean deleteAllMessages1From0() throws DbException {
|
||||
return db0.transactionWithResult(false, txn -> groupInvitationManager0
|
||||
.deleteAllMessages(txn, contactId1From0));
|
||||
}
|
||||
|
||||
private boolean deleteAllMessages0From1() throws DbException {
|
||||
return db1.transactionWithResult(false, txn -> groupInvitationManager1
|
||||
.deleteAllMessages(txn, contactId0From1));
|
||||
}
|
||||
|
||||
private void sendInvitation(long timestamp, @Nullable String text)
|
||||
throws DbException {
|
||||
byte[] signature = groupInvitationFactory.signInvitation(contact1From0,
|
||||
privateGroup0.getId(), timestamp, author0.getPrivateKey());
|
||||
groupInvitationManager0
|
||||
.sendInvitation(privateGroup0.getId(), contactId1From0, text,
|
||||
timestamp, signature);
|
||||
privateGroup.getId(), timestamp, author0.getPrivateKey());
|
||||
groupInvitationManager0.sendInvitation(privateGroup.getId(),
|
||||
contactId1From0, text, timestamp, signature);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user