mirror of
https://code.briarproject.org/briar/briar.git
synced 2026-02-15 20:29:52 +01:00
[core] allow messages from private group sessions with responses get deleted
This commit is contained in:
@@ -38,6 +38,11 @@ enum CreatorState implements State {
|
|||||||
return visibility;
|
return visibility;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAwaitingResponse() {
|
||||||
|
return this == INVITED;
|
||||||
|
}
|
||||||
|
|
||||||
static CreatorState fromValue(int value) throws FormatException {
|
static CreatorState fromValue(int value) throws FormatException {
|
||||||
for (CreatorState s : values()) if (s.value == value) return s;
|
for (CreatorState s : values()) if (s.value == value) return s;
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ import org.briarproject.briar.client.ConversationClientImpl;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Map.Entry;
|
import java.util.Map.Entry;
|
||||||
@@ -369,7 +370,8 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<ConversationMessageHeader> getMessageHeaders(Transaction txn,
|
public Collection<ConversationMessageHeader> getMessageHeaders(
|
||||||
|
Transaction txn,
|
||||||
ContactId c) throws DbException {
|
ContactId c) throws DbException {
|
||||||
try {
|
try {
|
||||||
Contact contact = db.getContact(txn, c);
|
Contact contact = db.getContact(txn, c);
|
||||||
@@ -633,8 +635,98 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
|
|||||||
@Override
|
@Override
|
||||||
public boolean deleteAllMessages(Transaction txn, ContactId c)
|
public boolean deleteAllMessages(Transaction txn, ContactId c)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
// TODO actually delete messages (#1627 and #1629)
|
// get ID of the contact group
|
||||||
return getMessageIds(txn, c).size() == 0;
|
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)
|
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 static class StoredSession {
|
||||||
|
|
||||||
private final MessageId storageId;
|
private final MessageId storageId;
|
||||||
@@ -660,4 +777,14 @@ class GroupInvitationManagerImpl extends ConversationClientImpl
|
|||||||
this.bdfSession = bdfSession;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,6 +40,11 @@ enum InviteeState implements State {
|
|||||||
return visibility;
|
return visibility;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAwaitingResponse() {
|
||||||
|
return this == INVITED;
|
||||||
|
}
|
||||||
|
|
||||||
static InviteeState fromValue(int value) throws FormatException {
|
static InviteeState fromValue(int value) throws FormatException {
|
||||||
for (InviteeState s : values()) if (s.value == value) return s;
|
for (InviteeState s : values()) if (s.value == value) return s;
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
|
|||||||
@@ -40,6 +40,11 @@ enum PeerState implements State {
|
|||||||
return visibility;
|
return visibility;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isAwaitingResponse() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
static PeerState fromValue(int value) throws FormatException {
|
static PeerState fromValue(int value) throws FormatException {
|
||||||
for (PeerState s : values()) if (s.value == value) return s;
|
for (PeerState s : values()) if (s.value == value) return s;
|
||||||
throw new FormatException();
|
throw new FormatException();
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ interface SessionParser {
|
|||||||
|
|
||||||
Role getRole(BdfDictionary d) throws FormatException;
|
Role getRole(BdfDictionary d) throws FormatException;
|
||||||
|
|
||||||
|
boolean isSession(BdfDictionary d);
|
||||||
|
|
||||||
CreatorSession parseCreatorSession(GroupId contactGroupId, BdfDictionary d)
|
CreatorSession parseCreatorSession(GroupId contactGroupId, BdfDictionary d)
|
||||||
throws FormatException;
|
throws FormatException;
|
||||||
|
|
||||||
|
|||||||
@@ -48,6 +48,11 @@ class SessionParserImpl implements SessionParser {
|
|||||||
return Role.fromValue(d.getLong(SESSION_KEY_ROLE).intValue());
|
return Role.fromValue(d.getLong(SESSION_KEY_ROLE).intValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isSession(BdfDictionary d) {
|
||||||
|
return d.getBoolean(SESSION_KEY_IS_SESSION, false);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CreatorSession parseCreatorSession(GroupId contactGroupId,
|
public CreatorSession parseCreatorSession(GroupId contactGroupId,
|
||||||
BdfDictionary d) throws FormatException {
|
BdfDictionary d) throws FormatException {
|
||||||
|
|||||||
@@ -7,4 +7,6 @@ interface State {
|
|||||||
int getValue();
|
int getValue();
|
||||||
|
|
||||||
Visibility getVisibility();
|
Visibility getVisibility();
|
||||||
|
|
||||||
|
boolean isAwaitingResponse();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import static org.junit.Assert.fail;
|
|||||||
public class GroupInvitationIntegrationTest
|
public class GroupInvitationIntegrationTest
|
||||||
extends BriarIntegrationTest<BriarIntegrationTestComponent> {
|
extends BriarIntegrationTest<BriarIntegrationTestComponent> {
|
||||||
|
|
||||||
private PrivateGroup privateGroup0;
|
private PrivateGroup privateGroup;
|
||||||
private PrivateGroupManager groupManager0, groupManager1;
|
private PrivateGroupManager groupManager0, groupManager1;
|
||||||
private GroupInvitationManager groupInvitationManager0,
|
private GroupInvitationManager groupInvitationManager0,
|
||||||
groupInvitationManager1;
|
groupInvitationManager1;
|
||||||
@@ -46,12 +46,12 @@ public class GroupInvitationIntegrationTest
|
|||||||
groupInvitationManager0 = c0.getGroupInvitationManager();
|
groupInvitationManager0 = c0.getGroupInvitationManager();
|
||||||
groupInvitationManager1 = c1.getGroupInvitationManager();
|
groupInvitationManager1 = c1.getGroupInvitationManager();
|
||||||
|
|
||||||
privateGroup0 =
|
privateGroup =
|
||||||
privateGroupFactory.createPrivateGroup("Testgroup", author0);
|
privateGroupFactory.createPrivateGroup("Testgroup", author0);
|
||||||
long joinTime = clock.currentTimeMillis();
|
long joinTime = clock.currentTimeMillis();
|
||||||
GroupMessage joinMsg0 = groupMessageFactory
|
GroupMessage joinMsg0 = groupMessageFactory
|
||||||
.createJoinMessage(privateGroup0.getId(), joinTime, author0);
|
.createJoinMessage(privateGroup.getId(), joinTime, author0);
|
||||||
groupManager0.addPrivateGroup(privateGroup0, joinMsg0, true);
|
groupManager0.addPrivateGroup(privateGroup, joinMsg0, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -90,21 +90,19 @@ public class GroupInvitationIntegrationTest
|
|||||||
assertEquals(1, invitations.size());
|
assertEquals(1, invitations.size());
|
||||||
GroupInvitationItem item = invitations.iterator().next();
|
GroupInvitationItem item = invitations.iterator().next();
|
||||||
assertEquals(contact0From1, item.getCreator());
|
assertEquals(contact0From1, item.getCreator());
|
||||||
assertEquals(privateGroup0, item.getShareable());
|
assertEquals(privateGroup, item.getShareable());
|
||||||
assertEquals(privateGroup0.getId(), item.getId());
|
assertEquals(privateGroup.getId(), item.getId());
|
||||||
assertEquals(privateGroup0.getName(), item.getName());
|
assertEquals(privateGroup.getName(), item.getName());
|
||||||
assertFalse(item.isSubscribed());
|
assertFalse(item.isSubscribed());
|
||||||
|
|
||||||
Collection<ConversationMessageHeader> messages =
|
Collection<ConversationMessageHeader> messages = getMessages0From1();
|
||||||
db1.transactionWithResult(true, txn -> groupInvitationManager1
|
|
||||||
.getMessageHeaders(txn, contactId0From1));
|
|
||||||
assertEquals(1, messages.size());
|
assertEquals(1, messages.size());
|
||||||
GroupInvitationRequest request =
|
GroupInvitationRequest request =
|
||||||
(GroupInvitationRequest) messages.iterator().next();
|
(GroupInvitationRequest) messages.iterator().next();
|
||||||
assertEquals(text, request.getText());
|
assertEquals(text, request.getText());
|
||||||
assertEquals(author0, request.getNameable().getCreator());
|
assertEquals(author0, request.getNameable().getCreator());
|
||||||
assertEquals(timestamp, request.getTimestamp());
|
assertEquals(timestamp, request.getTimestamp());
|
||||||
assertEquals(privateGroup0.getName(), request.getNameable().getName());
|
assertEquals(privateGroup.getName(), request.getNameable().getName());
|
||||||
assertFalse(request.isLocal());
|
assertFalse(request.isLocal());
|
||||||
assertFalse(request.isRead());
|
assertFalse(request.isRead());
|
||||||
assertFalse(request.canBeOpened());
|
assertFalse(request.canBeOpened());
|
||||||
@@ -120,18 +118,16 @@ public class GroupInvitationIntegrationTest
|
|||||||
assertFalse(groupInvitationManager1.getInvitations().isEmpty());
|
assertFalse(groupInvitationManager1.getInvitations().isEmpty());
|
||||||
|
|
||||||
groupInvitationManager1
|
groupInvitationManager1
|
||||||
.respondToInvitation(contactId0From1, privateGroup0, false);
|
.respondToInvitation(contactId0From1, privateGroup, false);
|
||||||
|
|
||||||
Collection<ConversationMessageHeader> messages =
|
Collection<ConversationMessageHeader> messages = getMessages0From1();
|
||||||
db1.transactionWithResult(true, txn -> groupInvitationManager1
|
|
||||||
.getMessageHeaders(txn, contactId0From1));
|
|
||||||
assertEquals(2, messages.size());
|
assertEquals(2, messages.size());
|
||||||
boolean foundResponse = false;
|
boolean foundResponse = false;
|
||||||
for (ConversationMessageHeader m : messages) {
|
for (ConversationMessageHeader m : messages) {
|
||||||
if (m instanceof GroupInvitationResponse) {
|
if (m instanceof GroupInvitationResponse) {
|
||||||
foundResponse = true;
|
foundResponse = true;
|
||||||
GroupInvitationResponse response = (GroupInvitationResponse) m;
|
GroupInvitationResponse response = (GroupInvitationResponse) m;
|
||||||
assertEquals(privateGroup0.getId(), response.getShareableId());
|
assertEquals(privateGroup.getId(), response.getShareableId());
|
||||||
assertTrue(response.isLocal());
|
assertTrue(response.isLocal());
|
||||||
assertFalse(response.wasAccepted());
|
assertFalse(response.wasAccepted());
|
||||||
}
|
}
|
||||||
@@ -140,16 +136,14 @@ public class GroupInvitationIntegrationTest
|
|||||||
|
|
||||||
sync1To0(1, true);
|
sync1To0(1, true);
|
||||||
|
|
||||||
messages = db0.transactionWithResult(true, txn ->
|
messages = getMessages1From0();
|
||||||
groupInvitationManager0
|
|
||||||
.getMessageHeaders(txn, contactId1From0));
|
|
||||||
assertEquals(2, messages.size());
|
assertEquals(2, messages.size());
|
||||||
foundResponse = false;
|
foundResponse = false;
|
||||||
for (ConversationMessageHeader m : messages) {
|
for (ConversationMessageHeader m : messages) {
|
||||||
if (m instanceof GroupInvitationResponse) {
|
if (m instanceof GroupInvitationResponse) {
|
||||||
foundResponse = true;
|
foundResponse = true;
|
||||||
GroupInvitationResponse response = (GroupInvitationResponse) m;
|
GroupInvitationResponse response = (GroupInvitationResponse) m;
|
||||||
assertEquals(privateGroup0.getId(), response.getShareableId());
|
assertEquals(privateGroup.getId(), response.getShareableId());
|
||||||
assertFalse(response.isLocal());
|
assertFalse(response.isLocal());
|
||||||
assertFalse(response.wasAccepted());
|
assertFalse(response.wasAccepted());
|
||||||
}
|
}
|
||||||
@@ -168,9 +162,7 @@ public class GroupInvitationIntegrationTest
|
|||||||
sendInvitation(timestamp, null);
|
sendInvitation(timestamp, null);
|
||||||
|
|
||||||
// check that invitation message state is correct
|
// check that invitation message state is correct
|
||||||
Collection<ConversationMessageHeader> messages =
|
Collection<ConversationMessageHeader> messages = getMessages1From0();
|
||||||
db0.transactionWithResult(true, txn -> groupInvitationManager0
|
|
||||||
.getMessageHeaders(txn, contactId1From0));
|
|
||||||
assertEquals(1, messages.size());
|
assertEquals(1, messages.size());
|
||||||
assertMessageState(messages.iterator().next(), true, false, false);
|
assertMessageState(messages.iterator().next(), true, false, false);
|
||||||
|
|
||||||
@@ -178,11 +170,9 @@ public class GroupInvitationIntegrationTest
|
|||||||
assertFalse(groupInvitationManager1.getInvitations().isEmpty());
|
assertFalse(groupInvitationManager1.getInvitations().isEmpty());
|
||||||
|
|
||||||
groupInvitationManager1
|
groupInvitationManager1
|
||||||
.respondToInvitation(contactId0From1, privateGroup0, true);
|
.respondToInvitation(contactId0From1, privateGroup, true);
|
||||||
|
|
||||||
messages = db1.transactionWithResult(true,
|
messages = getMessages0From1();
|
||||||
txn -> groupInvitationManager1
|
|
||||||
.getMessageHeaders(txn, contactId0From1));
|
|
||||||
assertEquals(2, messages.size());
|
assertEquals(2, messages.size());
|
||||||
boolean foundResponse = false;
|
boolean foundResponse = false;
|
||||||
for (ConversationMessageHeader m : messages) {
|
for (ConversationMessageHeader m : messages) {
|
||||||
@@ -190,11 +180,11 @@ public class GroupInvitationIntegrationTest
|
|||||||
foundResponse = true;
|
foundResponse = true;
|
||||||
GroupInvitationResponse response = (GroupInvitationResponse) m;
|
GroupInvitationResponse response = (GroupInvitationResponse) m;
|
||||||
assertMessageState(response, true, false, false);
|
assertMessageState(response, true, false, false);
|
||||||
assertEquals(privateGroup0.getId(), response.getShareableId());
|
assertEquals(privateGroup.getId(), response.getShareableId());
|
||||||
assertTrue(response.wasAccepted());
|
assertTrue(response.wasAccepted());
|
||||||
} else {
|
} else {
|
||||||
GroupInvitationRequest request = (GroupInvitationRequest) m;
|
GroupInvitationRequest request = (GroupInvitationRequest) m;
|
||||||
assertEquals(privateGroup0, request.getNameable());
|
assertEquals(privateGroup, request.getNameable());
|
||||||
assertTrue(request.wasAnswered());
|
assertTrue(request.wasAnswered());
|
||||||
assertTrue(request.canBeOpened());
|
assertTrue(request.canBeOpened());
|
||||||
}
|
}
|
||||||
@@ -203,16 +193,14 @@ public class GroupInvitationIntegrationTest
|
|||||||
|
|
||||||
sync1To0(1, true);
|
sync1To0(1, true);
|
||||||
|
|
||||||
messages = db1.transactionWithResult(true, txn ->
|
messages = getMessages1From0();
|
||||||
groupInvitationManager0
|
|
||||||
.getMessageHeaders(txn, contactId1From0));
|
|
||||||
assertEquals(2, messages.size());
|
assertEquals(2, messages.size());
|
||||||
foundResponse = false;
|
foundResponse = false;
|
||||||
for (ConversationMessageHeader m : messages) {
|
for (ConversationMessageHeader m : messages) {
|
||||||
if (m instanceof GroupInvitationResponse) {
|
if (m instanceof GroupInvitationResponse) {
|
||||||
foundResponse = true;
|
foundResponse = true;
|
||||||
GroupInvitationResponse response = (GroupInvitationResponse) m;
|
GroupInvitationResponse response = (GroupInvitationResponse) m;
|
||||||
assertEquals(privateGroup0.getId(), response.getShareableId());
|
assertEquals(privateGroup.getId(), response.getShareableId());
|
||||||
assertTrue(response.wasAccepted());
|
assertTrue(response.wasAccepted());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -223,7 +211,7 @@ public class GroupInvitationIntegrationTest
|
|||||||
// group was added
|
// group was added
|
||||||
Collection<PrivateGroup> groups = groupManager1.getPrivateGroups();
|
Collection<PrivateGroup> groups = groupManager1.getPrivateGroups();
|
||||||
assertEquals(1, groups.size());
|
assertEquals(1, groups.size());
|
||||||
assertEquals(privateGroup0, groups.iterator().next());
|
assertEquals(privateGroup, groups.iterator().next());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -240,12 +228,10 @@ public class GroupInvitationIntegrationTest
|
|||||||
// 1 has one unread message
|
// 1 has one unread message
|
||||||
Group g0 = groupInvitationManager1.getContactGroup(contact0From1);
|
Group g0 = groupInvitationManager1.getContactGroup(contact0From1);
|
||||||
assertGroupCount(messageTracker1, g0.getId(), 1, 1, timestamp);
|
assertGroupCount(messageTracker1, g0.getId(), 1, 1, timestamp);
|
||||||
ConversationMessageHeader m = db1.transactionWithResult(true, txn ->
|
ConversationMessageHeader m = getMessages0From1().iterator().next();
|
||||||
groupInvitationManager1.getMessageHeaders(txn, contactId0From1)
|
|
||||||
.iterator().next());
|
|
||||||
|
|
||||||
groupInvitationManager1
|
groupInvitationManager1
|
||||||
.respondToInvitation(contactId0From1, privateGroup0, true);
|
.respondToInvitation(contactId0From1, privateGroup, true);
|
||||||
|
|
||||||
// 1 has two messages, one still unread
|
// 1 has two messages, one still unread
|
||||||
assertGroupCount(messageTracker1, g0.getId(), 2, 1);
|
assertGroupCount(messageTracker1, g0.getId(), 2, 1);
|
||||||
@@ -266,28 +252,28 @@ public class GroupInvitationIntegrationTest
|
|||||||
|
|
||||||
// invitation is not allowed before the first hasn't been answered
|
// invitation is not allowed before the first hasn't been answered
|
||||||
assertFalse(groupInvitationManager0
|
assertFalse(groupInvitationManager0
|
||||||
.isInvitationAllowed(contact1From0, privateGroup0.getId()));
|
.isInvitationAllowed(contact1From0, privateGroup.getId()));
|
||||||
|
|
||||||
// deliver invitation and response
|
// deliver invitation and response
|
||||||
sync0To1(1, true);
|
sync0To1(1, true);
|
||||||
groupInvitationManager1
|
groupInvitationManager1
|
||||||
.respondToInvitation(contactId0From1, privateGroup0, false);
|
.respondToInvitation(contactId0From1, privateGroup, false);
|
||||||
sync1To0(1, true);
|
sync1To0(1, true);
|
||||||
|
|
||||||
// after invitation was declined, inviting again is possible
|
// after invitation was declined, inviting again is possible
|
||||||
assertTrue(groupInvitationManager0
|
assertTrue(groupInvitationManager0
|
||||||
.isInvitationAllowed(contact1From0, privateGroup0.getId()));
|
.isInvitationAllowed(contact1From0, privateGroup.getId()));
|
||||||
|
|
||||||
// send and accept the second invitation
|
// send and accept the second invitation
|
||||||
sendInvitation(clock.currentTimeMillis(), "Second Invitation");
|
sendInvitation(clock.currentTimeMillis(), "Second Invitation");
|
||||||
sync0To1(1, true);
|
sync0To1(1, true);
|
||||||
groupInvitationManager1
|
groupInvitationManager1
|
||||||
.respondToInvitation(contactId0From1, privateGroup0, true);
|
.respondToInvitation(contactId0From1, privateGroup, true);
|
||||||
sync1To0(1, true);
|
sync1To0(1, true);
|
||||||
|
|
||||||
// invitation is not allowed since the member joined the group now
|
// invitation is not allowed since the member joined the group now
|
||||||
assertFalse(groupInvitationManager0
|
assertFalse(groupInvitationManager0
|
||||||
.isInvitationAllowed(contact1From0, privateGroup0.getId()));
|
.isInvitationAllowed(contact1From0, privateGroup.getId()));
|
||||||
|
|
||||||
// don't allow another invitation request
|
// don't allow another invitation request
|
||||||
try {
|
try {
|
||||||
@@ -305,14 +291,14 @@ public class GroupInvitationIntegrationTest
|
|||||||
sync0To1(1, true);
|
sync0To1(1, true);
|
||||||
|
|
||||||
groupInvitationManager1
|
groupInvitationManager1
|
||||||
.respondToInvitation(contactId0From1, privateGroup0, false);
|
.respondToInvitation(contactId0From1, privateGroup, false);
|
||||||
sync1To0(1, true);
|
sync1To0(1, true);
|
||||||
|
|
||||||
sendInvitation(timestamp, "Second Invitation");
|
sendInvitation(timestamp, "Second Invitation");
|
||||||
sync0To1(1, true);
|
sync0To1(1, true);
|
||||||
|
|
||||||
groupInvitationManager1
|
groupInvitationManager1
|
||||||
.respondToInvitation(contactId0From1, privateGroup0, true);
|
.respondToInvitation(contactId0From1, privateGroup, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = ProtocolStateException.class)
|
@Test(expected = ProtocolStateException.class)
|
||||||
@@ -325,7 +311,7 @@ public class GroupInvitationIntegrationTest
|
|||||||
|
|
||||||
// Creator leaves group
|
// Creator leaves group
|
||||||
assertEquals(1, groupManager0.getPrivateGroups().size());
|
assertEquals(1, groupManager0.getPrivateGroups().size());
|
||||||
groupManager0.removePrivateGroup(privateGroup0.getId());
|
groupManager0.removePrivateGroup(privateGroup.getId());
|
||||||
assertEquals(0, groupManager0.getPrivateGroups().size());
|
assertEquals(0, groupManager0.getPrivateGroups().size());
|
||||||
|
|
||||||
// Creator's leave message is delivered to invitee
|
// Creator's leave message is delivered to invitee
|
||||||
@@ -335,7 +321,7 @@ public class GroupInvitationIntegrationTest
|
|||||||
// thrown as the action has failed
|
// thrown as the action has failed
|
||||||
assertEquals(0, groupManager1.getPrivateGroups().size());
|
assertEquals(0, groupManager1.getPrivateGroups().size());
|
||||||
groupInvitationManager1
|
groupInvitationManager1
|
||||||
.respondToInvitation(contactId0From1, privateGroup0, true);
|
.respondToInvitation(contactId0From1, privateGroup, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -348,7 +334,7 @@ public class GroupInvitationIntegrationTest
|
|||||||
|
|
||||||
// Creator leaves group
|
// Creator leaves group
|
||||||
assertEquals(1, groupManager0.getPrivateGroups().size());
|
assertEquals(1, groupManager0.getPrivateGroups().size());
|
||||||
groupManager0.removePrivateGroup(privateGroup0.getId());
|
groupManager0.removePrivateGroup(privateGroup.getId());
|
||||||
assertEquals(0, groupManager0.getPrivateGroups().size());
|
assertEquals(0, groupManager0.getPrivateGroups().size());
|
||||||
|
|
||||||
// Creator's leave message is delivered to invitee
|
// Creator's leave message is delivered to invitee
|
||||||
@@ -361,7 +347,7 @@ public class GroupInvitationIntegrationTest
|
|||||||
// as the action has succeeded
|
// as the action has succeeded
|
||||||
assertEquals(0, groupManager1.getPrivateGroups().size());
|
assertEquals(0, groupManager1.getPrivateGroups().size());
|
||||||
groupInvitationManager1
|
groupInvitationManager1
|
||||||
.respondToInvitation(contactId0From1, privateGroup0, false);
|
.respondToInvitation(contactId0From1, privateGroup, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -375,15 +361,15 @@ public class GroupInvitationIntegrationTest
|
|||||||
|
|
||||||
// Creator leaves group
|
// Creator leaves group
|
||||||
assertEquals(1, groupManager0.getPrivateGroups().size());
|
assertEquals(1, groupManager0.getPrivateGroups().size());
|
||||||
groupManager0.removePrivateGroup(privateGroup0.getId());
|
groupManager0.removePrivateGroup(privateGroup.getId());
|
||||||
assertEquals(0, groupManager0.getPrivateGroups().size());
|
assertEquals(0, groupManager0.getPrivateGroups().size());
|
||||||
|
|
||||||
// Invitee accepts invitation
|
// Invitee accepts invitation
|
||||||
assertEquals(0, groupManager1.getPrivateGroups().size());
|
assertEquals(0, groupManager1.getPrivateGroups().size());
|
||||||
groupInvitationManager1
|
groupInvitationManager1
|
||||||
.respondToInvitation(contactId0From1, privateGroup0, true);
|
.respondToInvitation(contactId0From1, privateGroup, true);
|
||||||
assertEquals(1, groupManager1.getPrivateGroups().size());
|
assertEquals(1, groupManager1.getPrivateGroups().size());
|
||||||
assertFalse(groupManager1.isDissolved(privateGroup0.getId()));
|
assertFalse(groupManager1.isDissolved(privateGroup.getId()));
|
||||||
|
|
||||||
// Invitee's join message is delivered to creator
|
// Invitee's join message is delivered to creator
|
||||||
sync1To0(1, true);
|
sync1To0(1, true);
|
||||||
@@ -392,7 +378,7 @@ public class GroupInvitationIntegrationTest
|
|||||||
sync0To1(1, true);
|
sync0To1(1, true);
|
||||||
|
|
||||||
// Group is marked as dissolved
|
// Group is marked as dissolved
|
||||||
assertTrue(groupManager1.isDissolved(privateGroup0.getId()));
|
assertTrue(groupManager1.isDissolved(privateGroup.getId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@@ -406,13 +392,13 @@ public class GroupInvitationIntegrationTest
|
|||||||
|
|
||||||
// Creator leaves group
|
// Creator leaves group
|
||||||
assertEquals(1, groupManager0.getPrivateGroups().size());
|
assertEquals(1, groupManager0.getPrivateGroups().size());
|
||||||
groupManager0.removePrivateGroup(privateGroup0.getId());
|
groupManager0.removePrivateGroup(privateGroup.getId());
|
||||||
assertEquals(0, groupManager0.getPrivateGroups().size());
|
assertEquals(0, groupManager0.getPrivateGroups().size());
|
||||||
|
|
||||||
// Invitee declines invitation
|
// Invitee declines invitation
|
||||||
assertEquals(0, groupManager1.getPrivateGroups().size());
|
assertEquals(0, groupManager1.getPrivateGroups().size());
|
||||||
groupInvitationManager1
|
groupInvitationManager1
|
||||||
.respondToInvitation(contactId0From1, privateGroup0, false);
|
.respondToInvitation(contactId0From1, privateGroup, false);
|
||||||
assertEquals(0, groupManager1.getPrivateGroups().size());
|
assertEquals(0, groupManager1.getPrivateGroups().size());
|
||||||
|
|
||||||
// Invitee's leave message is delivered to creator
|
// Invitee's leave message is delivered to creator
|
||||||
@@ -434,7 +420,7 @@ public class GroupInvitationIntegrationTest
|
|||||||
// Invitee responds to invitation
|
// Invitee responds to invitation
|
||||||
assertEquals(0, groupManager1.getPrivateGroups().size());
|
assertEquals(0, groupManager1.getPrivateGroups().size());
|
||||||
groupInvitationManager1
|
groupInvitationManager1
|
||||||
.respondToInvitation(contactId0From1, privateGroup0, true);
|
.respondToInvitation(contactId0From1, privateGroup, true);
|
||||||
assertEquals(1, groupManager1.getPrivateGroups().size());
|
assertEquals(1, groupManager1.getPrivateGroups().size());
|
||||||
|
|
||||||
// Invitee's (sharing) join message is delivered to creator
|
// Invitee's (sharing) join message is delivered to creator
|
||||||
@@ -448,11 +434,11 @@ public class GroupInvitationIntegrationTest
|
|||||||
|
|
||||||
// Creator leaves group
|
// Creator leaves group
|
||||||
assertEquals(1, groupManager0.getPrivateGroups().size());
|
assertEquals(1, groupManager0.getPrivateGroups().size());
|
||||||
groupManager0.removePrivateGroup(privateGroup0.getId());
|
groupManager0.removePrivateGroup(privateGroup.getId());
|
||||||
assertEquals(0, groupManager0.getPrivateGroups().size());
|
assertEquals(0, groupManager0.getPrivateGroups().size());
|
||||||
|
|
||||||
// Invitee leaves group
|
// Invitee leaves group
|
||||||
groupManager1.removePrivateGroup(privateGroup0.getId());
|
groupManager1.removePrivateGroup(privateGroup.getId());
|
||||||
assertEquals(0, groupManager1.getPrivateGroups().size());
|
assertEquals(0, groupManager1.getPrivateGroups().size());
|
||||||
|
|
||||||
// Creator's leave message is delivered to invitee
|
// Creator's leave message is delivered to invitee
|
||||||
@@ -462,13 +448,148 @@ public class GroupInvitationIntegrationTest
|
|||||||
sync1To0(1, true);
|
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)
|
private void sendInvitation(long timestamp, @Nullable String text)
|
||||||
throws DbException {
|
throws DbException {
|
||||||
byte[] signature = groupInvitationFactory.signInvitation(contact1From0,
|
byte[] signature = groupInvitationFactory.signInvitation(contact1From0,
|
||||||
privateGroup0.getId(), timestamp, author0.getPrivateKey());
|
privateGroup.getId(), timestamp, author0.getPrivateKey());
|
||||||
groupInvitationManager0
|
groupInvitationManager0.sendInvitation(privateGroup.getId(),
|
||||||
.sendInvitation(privateGroup0.getId(), contactId1From0, text,
|
contactId1From0, text, timestamp, signature);
|
||||||
timestamp, signature);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user