diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatIntegrationTest.java b/smack-integration-test/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatIntegrationTest.java index 28a9f26b3..9818c09b8 100644 --- a/smack-integration-test/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatIntegrationTest.java +++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/muc/MultiUserChatIntegrationTest.java @@ -16,7 +16,9 @@ */ package org.jivesoftware.smackx.muc; +import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -45,6 +47,7 @@ import org.igniterealtime.smack.inttest.util.SimpleResultSyncPoint; import org.jxmpp.jid.DomainBareJid; import org.jxmpp.jid.EntityBareJid; import org.jxmpp.jid.EntityFullJid; +import org.jxmpp.jid.Jid; import org.jxmpp.jid.impl.JidCreate; import org.jxmpp.jid.parts.Localpart; import org.jxmpp.jid.parts.Resourcepart; @@ -646,6 +649,104 @@ public class MultiUserChatIntegrationTest extends AbstractSmackIntegrationTest { } } + /** + * Asserts that a user who gets kicked receives that change as a presence update + * + *

From XEP-0045 § 8.2:

+ *
+ * The kick is performed based on the occupant's room nickname and is completed by setting the role of a + * participant or visitor to a value of "none". + * + * The service MUST remove the kicked occupant by sending a presence stanza of type "unavailable" to each kicked + * occupant, including status code 307 in the extended presence information, optionally along with the reason (if + * provided) and the roomnick or bare JID of the user who initiated the kick. + *
+ * + * @throws Exception when errors occur + */ + @SmackIntegrationTest + public void mucPresenceTestForGettingKicked() throws Exception { + EntityBareJid mucAddress = getRandomRoom("smack-inttest"); + + MultiUserChat mucAsSeenByOne = mucManagerOne.getMultiUserChat(mucAddress); + MultiUserChat mucAsSeenByTwo = mucManagerTwo.getMultiUserChat(mucAddress); + + createMUC(mucAsSeenByOne, "one-" + randomString); + final Resourcepart nicknameTwo = Resourcepart.from("two-" + randomString); + mucAsSeenByTwo.join(nicknameTwo); + + final ResultSyncPoint resultSyncPoint = new ResultSyncPoint<>(); + mucAsSeenByTwo.addParticipantListener(kickPresence -> resultSyncPoint.signal(kickPresence)); + + mucAsSeenByOne.kickParticipant(nicknameTwo, "Nothing personal. Just a test."); + try { + Presence kickPresence = resultSyncPoint.waitForResult(timeout); + MUCUser mucUser = MUCUser.from(kickPresence); + assertNotNull(mucUser); + assertAll( + () -> assertTrue(mucUser.getStatus().contains(MUCUser.Status.PRESENCE_TO_SELF_110), "Missing self-presence status code in kick presence"), + () -> assertTrue(mucUser.getStatus().contains(MUCUser.Status.KICKED_307), "Missing kick status code in kick presence"), + () -> assertEquals(MUCRole.none, mucUser.getItem().getRole(), "Role other than 'none' in kick presence") + ); + Jid itemJid = mucUser.getItem().getJid(); + if (itemJid != null) { + assertEquals(conTwo.getUser().asEntityFullJidIfPossible(), itemJid, "Incorrect kicked user in kick presence"); + } + } finally { + tryDestroy(mucAsSeenByOne); + } + } + + /** + * Asserts that a user who is present when another user gets kicked receives that change as a presence update + * + *

From XEP-0045 § 8.2:

+ *
+ * ...the service MUST then inform all of the remaining occupants that the kicked occupant is no longer in the room + * by sending presence stanzas of type "unavailable" from the individual's roomnick (<room@service/nick>) to all + * the remaining occupants (just as it does when occupants exit the room of their own volition), including the + * status code and optionally the reason and actor. + *
+ * + * @throws Exception when errors occur + */ + @SmackIntegrationTest + public void mucPresenceTestForWitnessingKick() throws Exception { + EntityBareJid mucAddress = getRandomRoom("smack-inttest"); + + MultiUserChat mucAsSeenByOne = mucManagerOne.getMultiUserChat(mucAddress); + MultiUserChat mucAsSeenByTwo = mucManagerTwo.getMultiUserChat(mucAddress); + MultiUserChat mucAsSeenByThree = mucManagerThree.getMultiUserChat(mucAddress); + + createMUC(mucAsSeenByOne, "one-" + randomString); + final Resourcepart nicknameTwo = Resourcepart.from("two-" + randomString); + final Resourcepart nicknameThree = Resourcepart.from("three-" + randomString); + mucAsSeenByTwo.join(nicknameTwo); + mucAsSeenByThree.join(nicknameThree); + + final ResultSyncPoint resultSyncPoint = new ResultSyncPoint<>(); + mucAsSeenByThree.addParticipantListener(kickPresence -> resultSyncPoint.signal(kickPresence)); + + mucAsSeenByOne.kickParticipant(nicknameTwo, "Nothing personal. Just a test."); + try { + Presence kickPresence = resultSyncPoint.waitForResult(timeout); + MUCUser mucUser = MUCUser.from(kickPresence); + assertNotNull(mucUser); + assertAll( + () -> assertFalse(mucUser.getStatus().contains(MUCUser.Status.PRESENCE_TO_SELF_110), "Incorrect self-presence status code in kick presence"), + () -> assertTrue(mucUser.getStatus().contains(MUCUser.Status.KICKED_307), "Missing kick status code in kick presence"), + () -> assertEquals(MUCRole.none, mucUser.getItem().getRole(), "Role other than 'none' in kick presence") + ); + Jid itemJid = mucUser.getItem().getJid(); + if (itemJid != null) { + assertEquals(conTwo.getUser().asEntityFullJidIfPossible(), itemJid, "Incorrect kicked user in kick presence"); + } + } finally { + tryDestroy(mucAsSeenByOne); + } + + } + @SmackIntegrationTest public void mucDestroyTest() throws TimeoutException, Exception {