summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTobias Markmann <tm@ayena.de>2017-04-03 14:02:33 (GMT)
committerKevin Smith <kevin.smith@isode.com>2017-04-10 08:54:25 (GMT)
commitebd98c32281e2c2689480357f7e8ce6084e16384 (patch)
tree6e14aaf6211a79966edfe3e4536d6bb899a9eeeb /Swift/Controllers/Chat/UnitTest
parent0b4c4ade26c7ff77ba7f8b4ae83e4bd3581bf345 (diff)
downloadswift-ebd98c32281e2c2689480357f7e8ce6084e16384.zip
swift-ebd98c32281e2c2689480357f7e8ce6084e16384.tar.bz2
Ignore incoming duplicates of messages
This might happen with some servers and their MUC implementation which send you not only the original message but also multiple carbon copies of it for MUC PM conversations. This change will ignore any message that has the same non-empty message ID as the previously incoming message. Test-Information: Added unit test to verify new behaviour. Tested in a MUC where the server would send you the original message and multiple carbon copies of the message. Previously the chat view would show and incoming MUC PM message 4 times. Now it’s only shown once. Builds and tests pass on macOS 10.12.4. Change-Id: Ie7bd29dacc00f8f3962131a529b52a69ff09bd6c
Diffstat (limited to 'Swift/Controllers/Chat/UnitTest')
-rw-r--r--Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp40
-rw-r--r--Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp2
2 files changed, 41 insertions, 1 deletions
diff --git a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
index 2f77ec7..d104fbd 100644
--- a/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
+++ b/Swift/Controllers/Chat/UnitTest/ChatsManagerTest.cpp
@@ -108,60 +108,61 @@ class ChatsManagerTest : public CppUnit::TestFixture {
CPPUNIT_TEST(testSecondWindow);
CPPUNIT_TEST(testUnbindRebind);
CPPUNIT_TEST(testNoDuplicateUnbind);
CPPUNIT_TEST(testThreeMUCWindows);
CPPUNIT_TEST(testChatControllerPresenceAccessUpdatedOnRemoveFromRoster);
CPPUNIT_TEST(testChatControllerPresenceAccessUpdatedOnAddToRoster);
CPPUNIT_TEST(testChatControllerPresenceAccessUpdatedOnSubscriptionChangeToBoth);
CPPUNIT_TEST(testChatControllerPresenceAccessUpdatedOnSubscriptionChangeToFrom);
CPPUNIT_TEST(testChatControllerFullJIDBindingOnMessageAndNotReceipt);
CPPUNIT_TEST(testChatControllerFullJIDBindingOnTypingAndNotActive);
CPPUNIT_TEST(testLocalMUCServiceDiscoveryResetOnDisconnect);
CPPUNIT_TEST(testPresenceChangeDoesNotReplaceMUCInvite);
CPPUNIT_TEST(testNotSplittingMUCPresenceJoinLeaveLinesOnChatStateNotifications);
// MUC PM Tests
CPPUNIT_TEST(testChatControllerPMPresenceHandling);
CPPUNIT_TEST(testChatControllerMucPmUnavailableErrorHandling);
// Highlighting tests
CPPUNIT_TEST(testChatControllerHighlightingNotificationTesting);
CPPUNIT_TEST(testChatControllerHighlightingNotificationDeduplicateSounds);
CPPUNIT_TEST(testChatControllerHighlightingNotificationKeyword);
CPPUNIT_TEST(testChatControllerMeMessageHandling);
CPPUNIT_TEST(testRestartingMUCComponentCrash);
CPPUNIT_TEST(testChatControllerMeMessageHandlingInMUC);
// Carbons tests
CPPUNIT_TEST(testCarbonsForwardedIncomingMessageToSecondResource);
CPPUNIT_TEST(testCarbonsForwardedOutgoingMessageFromSecondResource);
+ CPPUNIT_TEST(testCarbonsForwardedIncomingDuplicates);
CPPUNIT_TEST_SUITE_END();
public:
void setUp() {
mocks_ = new MockRepository();
notifier_ = std::unique_ptr<DummyNotifier>(new DummyNotifier());
jid_ = JID("test@test.com/resource");
stanzaChannel_ = new DummyStanzaChannel();
iqRouter_ = new IQRouter(stanzaChannel_);
eventController_ = new EventController();
chatWindowFactory_ = mocks_->InterfaceMock<ChatWindowFactory>();
joinMUCWindowFactory_ = mocks_->InterfaceMock<JoinMUCWindowFactory>();
xmppRoster_ = new XMPPRosterImpl();
mucRegistry_ = new MUCRegistry();
nickResolver_ = new NickResolver(jid_.toBare(), xmppRoster_, nullptr, mucRegistry_);
presenceOracle_ = new PresenceOracle(stanzaChannel_, xmppRoster_);
serverDiscoInfo_ = std::make_shared<DiscoInfo>();
presenceSender_ = new StanzaChannelPresenceSender(stanzaChannel_);
directedPresenceSender_ = new DirectedPresenceSender(presenceSender_);
mucManager_ = new MUCManager(stanzaChannel_, iqRouter_, directedPresenceSender_, mucRegistry_);
uiEventStream_ = new UIEventStream();
entityCapsProvider_ = new DummyEntityCapsProvider();
chatListWindowFactory_ = mocks_->InterfaceMock<ChatListWindowFactory>();
mucSearchWindowFactory_ = mocks_->InterfaceMock<MUCSearchWindowFactory>();
settings_ = new DummySettingsProvider();
profileSettings_ = new ProfileSettingsProvider("a", settings_);
chatListWindow_ = new MockChatListWindow();
ftManager_ = new DummyFileTransferManager();
ftOverview_ = new FileTransferOverview(ftManager_);
@@ -1238,60 +1239,99 @@ public:
originalMessage->setBody(forwardedBody);
originalMessage->addPayload(std::make_shared<DeliveryReceiptRequest>());
auto messageWrapper = createCarbonsMessage(std::make_shared<CarbonsSent>(), originalMessage);
manager_->handleIncomingMessage(messageWrapper);
CPPUNIT_ASSERT_EQUAL(forwardedBody, MockChatWindow::bodyFromMessage(window->lastAddedMessage_));
CPPUNIT_ASSERT_EQUAL(true, window->lastAddedMessageSenderIsSelf_);
CPPUNIT_ASSERT_EQUAL(size_t(1), window->receiptChanges_.size());
CPPUNIT_ASSERT_EQUAL(ChatWindow::ReceiptRequested, window->receiptChanges_[0].second);
}
// incoming carbons message for the received delivery receipt to the other resource
{
auto originalMessage = std::make_shared<Message>();
originalMessage->setFrom(messageJID);
originalMessage->setTo(jid2);
originalMessage->setType(Message::Chat);
originalMessage->addPayload(std::make_shared<DeliveryReceipt>("abcdefg123456"));
auto messageWrapper = createCarbonsMessage(std::make_shared<CarbonsReceived>(), originalMessage);
manager_->handleIncomingMessage(messageWrapper);
CPPUNIT_ASSERT_EQUAL(size_t(2), window->receiptChanges_.size());
CPPUNIT_ASSERT_EQUAL(ChatWindow::ReceiptReceived, window->receiptChanges_[1].second);
}
}
+ void testCarbonsForwardedIncomingDuplicates() {
+ JID messageJID("testling@test.com/resource1");
+ JID jid2 = jid_.toBare().withResource("someOtherResource");
+
+ MockChatWindow* window = new MockChatWindow();
+ mocks_->ExpectCall(chatWindowFactory_, ChatWindowFactory::createChatWindow).With(messageJID, uiEventStream_).Return(window);
+
+ std::shared_ptr<Message> message(new Message());
+ message->setFrom(messageJID);
+ std::string body("This is a legible message. >HEH@)oeueu");
+ message->setBody(body);
+ manager_->handleIncomingMessage(message);
+ CPPUNIT_ASSERT_EQUAL(body, MockChatWindow::bodyFromMessage(window->lastAddedMessage_));
+
+ // incoming carbons message from another resource and duplicate of it
+ {
+ auto originalMessage = std::make_shared<Message>();
+ originalMessage->setFrom(messageJID);
+ originalMessage->setTo(jid2);
+ originalMessage->setID("BDD82F0B-2523-48BF-B8CA-17B23A314BC2");
+ originalMessage->setType(Message::Chat);
+ std::string forwardedBody = "Some further text.";
+ originalMessage->setBody(forwardedBody);
+
+ auto messageWrapper = createCarbonsMessage(std::make_shared<CarbonsReceived>(), originalMessage);
+
+ manager_->handleIncomingMessage(messageWrapper);
+
+ CPPUNIT_ASSERT_EQUAL(forwardedBody, MockChatWindow::bodyFromMessage(window->lastAddedMessage_));
+ CPPUNIT_ASSERT_EQUAL(false, window->lastAddedMessageSenderIsSelf_);
+ window->resetLastMessages();
+
+ messageWrapper = createCarbonsMessage(std::make_shared<CarbonsReceived>(), originalMessage);
+ manager_->handleIncomingMessage(messageWrapper);
+ CPPUNIT_ASSERT_EQUAL(std::string(), MockChatWindow::bodyFromMessage(window->lastAddedMessage_));
+ CPPUNIT_ASSERT_EQUAL(false, window->lastAddedMessageSenderIsSelf_);
+ }
+ }
+
private:
std::shared_ptr<Message> makeDeliveryReceiptTestMessage(const JID& from, const std::string& id) {
std::shared_ptr<Message> message = std::make_shared<Message>();
message->setFrom(from);
message->setID(id);
message->setBody("This will cause the window to open");
message->addPayload(std::make_shared<DeliveryReceiptRequest>());
return message;
}
size_t st(int i) {
return static_cast<size_t>(i);
}
void handleHighlightAction(const HighlightAction& action) {
handledHighlightActions_++;
if (action.getSoundFilePath()) {
soundsPlayed_.insert(action.getSoundFilePath().get_value_or(""));
}
}
private:
JID jid_;
std::unique_ptr<DummyNotifier> notifier_;
ChatsManager* manager_;
DummyStanzaChannel* stanzaChannel_;
IQRouter* iqRouter_;
EventController* eventController_;
ChatWindowFactory* chatWindowFactory_;
JoinMUCWindowFactory* joinMUCWindowFactory_;
diff --git a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
index 59c3a87..e7b4b3e 100644
--- a/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
+++ b/Swift/Controllers/Chat/UnitTest/MUCControllerTest.cpp
@@ -412,61 +412,61 @@ public:
alterations.push_back(MUCOccupant("Bert", MUCOccupant::Moderator, MUCOccupant::Owner));
alterations.push_back(MUCOccupant("Kev", MUCOccupant::Participant, MUCOccupant::Outcast));
alterations.push_back(MUCOccupant("Bert", MUCOccupant::Visitor, MUCOccupant::NoAffiliation));
alterations.push_back(MUCOccupant("Remko", MUCOccupant::NoRole, MUCOccupant::NoAffiliation));
alterations.push_back(MUCOccupant("Ernie", MUCOccupant::Visitor, MUCOccupant::Outcast));
for (const auto& alteration : alterations) {
/* perform an alteration to a user's role and affiliation */
occupant_map::iterator occupant = occupants.find(alteration.getNick());
CPPUNIT_ASSERT(occupant != occupants.end());
const JID jid = jidFromOccupant(occupant->second);
/* change the affiliation, leave the role in place */
muc_->changeAffiliation(jid, alteration.getAffiliation());
occupant->second = MUCOccupant(occupant->first, occupant->second.getRole(), alteration.getAffiliation());
testRoleAffiliationStatesVerify(occupants);
/* change the role, leave the affiliation in place */
muc_->changeOccupantRole(jid, alteration.getRole());
occupant->second = MUCOccupant(occupant->first, alteration.getRole(), occupant->second.getAffiliation());
testRoleAffiliationStatesVerify(occupants);
}
}
void testSubjectChangeCorrect() {
joinCompleted();
{
Message::ref message = std::make_shared<Message>();
message->setType(Message::Groupchat);
message->setTo(self_);
message->setFrom(mucJID_.withResource("SomeNickname"));
- message->setID(iqChannel_->getNewIQID());
+ message->setID("3FB99C56-7C92-4755-91B0-9C0098BC7AE0");
message->setSubject("New Room Subject");
controller_->handleIncomingMessage(std::make_shared<MessageEvent>(message));
CPPUNIT_ASSERT_EQUAL(std::string("The room subject is now: New Room Subject"), std::dynamic_pointer_cast<ChatWindow::ChatTextMessagePart>(window_->lastAddedSystemMessage_.getParts()[0])->text);
}
}
/*
* Test that message stanzas with subject element and non-empty body element do not cause a subject change.
*/
void testSubjectChangeIncorrectA() {
joinCompleted();
{
Message::ref message = std::make_shared<Message>();
message->setType(Message::Groupchat);
message->setTo(self_);
message->setFrom(mucJID_.withResource("SomeNickname"));
message->setID(iqChannel_->getNewIQID());
message->setSubject("New Room Subject");
message->setBody("Some body text that prevents this stanza from being a subject change.");
controller_->handleIncomingMessage(std::make_shared<MessageEvent>(message));
CPPUNIT_ASSERT_EQUAL(std::string("Trying to enter room teaparty@rooms.wonderland.lit"), std::dynamic_pointer_cast<ChatWindow::ChatTextMessagePart>(window_->lastAddedSystemMessage_.getParts()[0])->text);
}
}
/*
* Test that message stanzas with subject element and thread element do not cause a subject change.
*/