diff --git a/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/AbstractSmackIntegrationTest.java b/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/AbstractSmackIntegrationTest.java index befb94c08..593d5b847 100644 --- a/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/AbstractSmackIntegrationTest.java +++ b/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/AbstractSmackIntegrationTest.java @@ -20,7 +20,15 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; +import org.jivesoftware.smack.StanzaListener; import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.filter.AndFilter; +import org.jivesoftware.smack.filter.FromMatchesFilter; +import org.jivesoftware.smack.filter.PresenceTypeFilter; +import org.jivesoftware.smack.packet.Stanza; +import org.jivesoftware.smack.util.Async.ThrowingRunnable; + +import org.igniterealtime.smack.inttest.util.SimpleResultSyncPoint; public abstract class AbstractSmackIntegrationTest extends AbstractSmackIntTest { @@ -58,4 +66,48 @@ public abstract class AbstractSmackIntegrationTest extends AbstractSmackIntTest connectionsLocal.add(conThree); this.connections = Collections.unmodifiableList(connectionsLocal); } + + /** + * Perform action and wait until conA observes a presence form conB. + *
+ * This method is usually used so that 'action' performs an operation that changes one entities + * features/nodes/capabilities, and we want to check that another connection is able to observe this change, and use + * that new "thing" that was added to the connection. + *
+ *+ * Note that this method is a workaround at best and not reliable. Because it is not guaranteed that any XEP-0030 + * related manager, e.g. EntityCapsManager, already processed the presence when this method returns. + *
+ * TODO: Come up with a better solution. + * + * @param conA the connection to observe the presence on. + * @param conB the connection sending the presence + * @param action the action to perform. + * @throws Exception in case of an exception. + */ + protected void performActionAndWaitForPresence(XMPPConnection conA, XMPPConnection conB, ThrowingRunnable action) + throws Exception { + final SimpleResultSyncPoint presenceReceivedSyncPoint = new SimpleResultSyncPoint(); + final StanzaListener presenceListener = new StanzaListener() { + @Override + public void processStanza(Stanza packet) { + presenceReceivedSyncPoint.signal(); + } + }; + + // Add a stanzaListener to listen for incoming presence + conA.addAsyncStanzaListener(presenceListener, new AndFilter( + PresenceTypeFilter.AVAILABLE, + FromMatchesFilter.create(conB.getUser()) + )); + + action.runOrThrow(); + + try { + // wait for the dummy feature to get sent via presence + presenceReceivedSyncPoint.waitForResult(timeout); + } finally { + conA.removeAsyncStanzaListener(presenceListener); + } + } } diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smackx/caps/EntityCapsTest.java b/smack-integration-test/src/main/java/org/jivesoftware/smackx/caps/EntityCapsTest.java index 0a0110882..2ab7110a4 100644 --- a/smack-integration-test/src/main/java/org/jivesoftware/smackx/caps/EntityCapsTest.java +++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/caps/EntityCapsTest.java @@ -31,6 +31,7 @@ import org.jivesoftware.smack.SmackException.NoResponseException; import org.jivesoftware.smack.SmackException.NotConnectedException; import org.jivesoftware.smack.SmackException.NotLoggedInException; import org.jivesoftware.smack.StanzaListener; +import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.XMPPException.XMPPErrorException; import org.jivesoftware.smack.filter.AndFilter; @@ -40,6 +41,7 @@ import org.jivesoftware.smack.filter.PresenceTypeFilter; import org.jivesoftware.smack.filter.StanzaTypeFilter; import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smack.roster.RosterUtil; +import org.jivesoftware.smack.util.Async.ThrowingRunnable; import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; import org.jivesoftware.smackx.disco.packet.DiscoverInfo; @@ -49,7 +51,6 @@ import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment; import org.igniterealtime.smack.inttest.annotations.AfterClass; import org.igniterealtime.smack.inttest.annotations.BeforeClass; import org.igniterealtime.smack.inttest.annotations.SmackIntegrationTest; -import org.igniterealtime.smack.inttest.util.SimpleResultSyncPoint; public class EntityCapsTest extends AbstractSmackIntegrationTest { @@ -143,26 +144,7 @@ public class EntityCapsTest extends AbstractSmackIntegrationTest { }, new AndFilter(new StanzaTypeFilter(DiscoverInfo.class), IQTypeFilter.GET)); - final SimpleResultSyncPoint presenceReceivedSyncPoint = new SimpleResultSyncPoint(); - final StanzaListener presenceListener = new StanzaListener() { - @Override - public void processStanza(Stanza packet) { - presenceReceivedSyncPoint.signal(); - } - }; - - // Add a stanzaListener to listen for incoming presence - conOne.addAsyncStanzaListener(presenceListener, PresenceTypeFilter.AVAILABLE); - - // add a bogus feature so that con1 ver won't match con0's - sdmTwo.addFeature(dummyFeature); - - try { - // wait for the dummy feature to get sent via presence - presenceReceivedSyncPoint.waitForResult(timeout); - } finally { - conOne.removeAsyncStanzaListener(presenceListener); - } + addFeatureAndWaitForPresence(conOne, conTwo, dummyFeature); dropCapsCache(); // discover that @@ -181,10 +163,10 @@ public class EntityCapsTest extends AbstractSmackIntegrationTest { } @SmackIntegrationTest - public void testCapsChanged() { + public void testCapsChanged() throws Exception { final String dummyFeature = getNewDummyFeature(); String nodeVerBefore = EntityCapsManager.getNodeVersionByJid(conTwo.getUser()); - sdmTwo.addFeature(dummyFeature); + addFeatureAndWaitForPresence(conOne, conTwo, dummyFeature); String nodeVerAfter = EntityCapsManager.getNodeVersionByJid(conTwo.getUser()); assertFalse(nodeVerBefore.equals(nodeVerAfter)); @@ -229,4 +211,24 @@ public class EntityCapsTest extends AbstractSmackIntegrationTest { private static void dropCapsCache() { EntityCapsManager.CAPS_CACHE.clear(); } + + /** + * Adds 'feature' to conB and waits until conA observes a presence form conB. + * + * @param conA the connection to observe the presence on. + * @param conB the connection to add the feature to. + * @param feature the feature to add. + * @throws Exception in case of an exception. + */ + private void addFeatureAndWaitForPresence(XMPPConnection conA, XMPPConnection conB, String feature) + throws Exception { + final ServiceDiscoveryManager sdmB = ServiceDiscoveryManager.getInstanceFor(conB); + ThrowingRunnable action = new ThrowingRunnable() { + @Override + public void runOrThrow() throws Exception { + sdmB.addFeature(feature); + } + }; + performActionAndWaitForPresence(conA, conB, action); + } } diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smackx/softwareInfo/SoftwareInfoIntegrationTest.java b/smack-integration-test/src/main/java/org/jivesoftware/smackx/softwareInfo/SoftwareInfoIntegrationTest.java index e2e37fae5..f289c96be 100644 --- a/smack-integration-test/src/main/java/org/jivesoftware/smackx/softwareInfo/SoftwareInfoIntegrationTest.java +++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/softwareInfo/SoftwareInfoIntegrationTest.java @@ -16,13 +16,14 @@ */ package org.jivesoftware.smackx.softwareInfo; -import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; import org.jivesoftware.smack.parsing.SmackParsingException; +import org.jivesoftware.smack.util.Async.ThrowingRunnable; import org.jivesoftware.smack.xml.XmlPullParserException; import org.jivesoftware.smackx.mediaelement.element.MediaElement; import org.jivesoftware.smackx.softwareinfo.SoftwareInfoManager; @@ -54,9 +55,14 @@ public class SoftwareInfoIntegrationTest extends AbstractSmackIntegrationTest { @SmackIntegrationTest public void test() throws Exception { SoftwareInfoForm softwareInfoSent = createSoftwareInfoForm(); - sim1.publishSoftwareInformationForm(softwareInfoSent); + performActionAndWaitForPresence(conTwo, conOne, new ThrowingRunnable() { + @Override + public void runOrThrow() throws Exception { + sim1.publishSoftwareInformationForm(softwareInfoSent); + } + }); SoftwareInfoForm softwareInfoFormReceived = sim2.fromJid(conOne.getUser()); - assertTrue(softwareInfoFormReceived.equals(softwareInfoSent)); + assertEquals(softwareInfoSent, softwareInfoFormReceived); } private static SoftwareInfoForm createSoftwareInfoForm() throws URISyntaxException {