From 7655ac17f251efa3796b5121b8208770769200ee Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Mon, 19 Dec 2016 14:35:09 +0100 Subject: [PATCH] Re-activate EntityCaps integration test --- .../provisioning/IoTProvisioningManager.java | 6 +- .../smackx/entitycaps/EntityCapsTest.java | 147 ------------ .../smackx/caps/EntityCapsManager.java | 6 +- .../org/jivesoftware/smack/roster/Roster.java | 19 ++ .../jivesoftware/smack/roster/RosterUtil.java | 43 ++++ .../smack/inttest/AbstractSmackIntTest.java | 48 +++- .../inttest/AbstractSmackIntegrationTest.java | 11 +- .../AbstractSmackLowLevelIntegrationTest.java | 4 +- .../smack/inttest/Configuration.java | 6 +- .../SmackIntegrationTestFramework.java | 26 ++- .../java/org/jivesoftware/smack/ChatTest.java | 4 +- .../smackx/caps/EntityCapsTest.java | 210 ++++++++++++++++++ .../smackx/caps/package-info.java | 1 + .../smackx/iot/IoTControlIntegrationTest.java | 4 +- .../smackx/iot/IoTDataIntegrationTest.java | 2 +- .../muc/MultiUserChatIntegrationTest.java | 2 +- 16 files changed, 358 insertions(+), 181 deletions(-) delete mode 100644 smack-extensions/src/integration-test/java/org/jivesoftware/smackx/entitycaps/EntityCapsTest.java create mode 100644 smack-integration-test/src/main/java/org/jivesoftware/smackx/caps/EntityCapsTest.java create mode 120000 smack-integration-test/src/main/java/org/jivesoftware/smackx/caps/package-info.java diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/iot/provisioning/IoTProvisioningManager.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/iot/provisioning/IoTProvisioningManager.java index 5069c7ee6..21e853930 100644 --- a/smack-experimental/src/main/java/org/jivesoftware/smackx/iot/provisioning/IoTProvisioningManager.java +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/iot/provisioning/IoTProvisioningManager.java @@ -45,7 +45,6 @@ import org.jivesoftware.smack.packet.Presence; import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smack.roster.AbstractPresenceEventListener; import org.jivesoftware.smack.roster.Roster; -import org.jivesoftware.smack.roster.RosterEntry; import org.jivesoftware.smack.roster.SubscribeListener; import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; import org.jivesoftware.smackx.disco.packet.DiscoverInfo; @@ -353,10 +352,7 @@ public final class IoTProvisioningManager extends Manager { } public boolean iAmFriendOf(BareJid otherJid) { - RosterEntry entry = roster.getEntry(otherJid); - if (entry == null) return false; - - return entry.canSeeHisPresence(); + return roster.iAmSubscribedTo(otherJid); } public void sendFriendshipRequest(BareJid bareJid) throws NotConnectedException, InterruptedException { diff --git a/smack-extensions/src/integration-test/java/org/jivesoftware/smackx/entitycaps/EntityCapsTest.java b/smack-extensions/src/integration-test/java/org/jivesoftware/smackx/entitycaps/EntityCapsTest.java deleted file mode 100644 index 4e39fec37..000000000 --- a/smack-extensions/src/integration-test/java/org/jivesoftware/smackx/entitycaps/EntityCapsTest.java +++ /dev/null @@ -1,147 +0,0 @@ -package org.jivesoftware.smackx.entitycaps; - -import org.jivesoftware.smack.PacketListener; -import org.jivesoftware.smack.SmackConfiguration; -import org.jivesoftware.smack.TCPConnection; -import org.jivesoftware.smack.XMPPException; -import org.jivesoftware.smack.filter.AndFilter; -import org.jivesoftware.smack.filter.StanzaTypeFilter; -import org.jivesoftware.smack.filter.IQTypeFilter; -import org.jivesoftware.smack.packet.IQ; -import org.jivesoftware.smack.packet.Packet; -import org.jivesoftware.smack.test.SmackTestCase; -import org.jivesoftware.smackx.ServiceDiscoveryManager; -import org.jivesoftware.smackx.packet.DiscoverInfo; - -public class EntityCapsTest extends SmackTestCase { - - private static final String DISCOVER_TEST_FEATURE = "entityCapsTest"; - - XMPPTCPConnection con0; - XMPPTCPConnection con1; - EntityCapsManager ecm0; - EntityCapsManager ecm1; - ServiceDiscoveryManager sdm0; - ServiceDiscoveryManager sdm1; - - private boolean discoInfoSend = false; - - public EntityCapsTest(String arg0) { - super(arg0); - } - - @Override - protected int getMaxConnections() { - return 2; - } - - @Override - protected void setUp() throws Exception { - super.setUp(); - SmackConfiguration.setAutoEnableEntityCaps(true); - con0 = getConnection(0); - con1 = getConnection(1); - ecm0 = EntityCapsManager.getInstanceFor(getConnection(0)); - ecm1 = EntityCapsManager.getInstanceFor(getConnection(1)); - sdm0 = ServiceDiscoveryManager.getInstanceFor(con0); - sdm1 = ServiceDiscoveryManager.getInstanceFor(con1); - letsAllBeFriends(); - } - - public void testLocalEntityCaps() throws InterruptedException { - DiscoverInfo info = EntityCapsManager.getDiscoveryInfoByNodeVer(ecm1.getLocalNodeVer()); - assertFalse(info.containsFeature(DISCOVER_TEST_FEATURE)); - - dropWholeEntityCapsCache(); - - // This should cause a new presence stanza from con1 with and updated - // 'ver' String - sdm1.addFeature(DISCOVER_TEST_FEATURE); - - // Give the server some time to handle the stanza and send it to con0 - Thread.sleep(2000); - - // The presence stanza should get received by con0 and the data should - // be recorded in the map - // Note that while both connections use the same static Entity Caps - // cache, - // it's assured that *not* con1 added the data to the Entity Caps cache. - // Every time the entities features - // and identities change only a new caps 'ver' is calculated and send - // with the presence stanza - // The other connection has to receive this stanza and record the - // information in order for this test to succeed. - info = EntityCapsManager.getDiscoveryInfoByNodeVer(ecm1.getLocalNodeVer()); - assertNotNull(info); - assertTrue(info.containsFeature(DISCOVER_TEST_FEATURE)); - } - - /** - * Test if entity caps actually prevent a disco info request and reply - * - * @throws XMPPException - * - */ - public void testPreventDiscoInfo() throws XMPPException { - con0.addPacketSendingListener(new PacketListener() { - - @Override - public void processPacket(Packet packet) { - discoInfoSend = true; - } - - }, new AndFilter(new StanzaTypeFilter(DiscoverInfo.class), new IQTypeFilter(IQ.Type.get))); - - // add a bogus feature so that con1 ver won't match con0's - sdm1.addFeature(DISCOVER_TEST_FEATURE); - - dropCapsCache(); - // discover that - DiscoverInfo info = sdm0.discoverInfo(con1.getUser()); - // that discovery should cause a disco#info - assertTrue(discoInfoSend); - assertTrue(info.containsFeature(DISCOVER_TEST_FEATURE)); - discoInfoSend = false; - - // discover that - info = sdm0.discoverInfo(con1.getUser()); - // that discovery shouldn't cause a disco#info - assertFalse(discoInfoSend); - assertTrue(info.containsFeature(DISCOVER_TEST_FEATURE)); - } - - public void testCapsChanged() { - String nodeVerBefore = EntityCapsManager.getNodeVersionByJid(con1.getUser()); - sdm1.addFeature(DISCOVER_TEST_FEATURE); - String nodeVerAfter = EntityCapsManager.getNodeVersionByJid(con1.getUser()); - - assertFalse(nodeVerBefore.equals(nodeVerAfter)); - } - - public void testEntityCaps() throws XMPPException, InterruptedException { - dropWholeEntityCapsCache(); - sdm1.addFeature(DISCOVER_TEST_FEATURE); - - Thread.sleep(3000); - - DiscoverInfo info = sdm0.discoverInfo(con1.getUser()); - assertTrue(info.containsFeature(DISCOVER_TEST_FEATURE)); - - String u1ver = EntityCapsManager.getNodeVersionByJid(con1.getUser()); - assertNotNull(u1ver); - - DiscoverInfo entityInfo = EntityCapsManager.caps.get(u1ver); - assertNotNull(entityInfo); - - assertEquals(info.toXML(), entityInfo.toXML()); - } - - private static void dropWholeEntityCapsCache() { - EntityCapsManager.caps.clear(); - EntityCapsManager.jidCaps.clear(); - } - - private static void dropCapsCache() { - EntityCapsManager.caps.clear(); - } -} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/caps/EntityCapsManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/caps/EntityCapsManager.java index e1d2fbb40..d3854fbb7 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/caps/EntityCapsManager.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/caps/EntityCapsManager.java @@ -101,7 +101,7 @@ public final class EntityCapsManager extends Manager { /** * Map of "node + '#' + hash" to DiscoverInfo data */ - private static final LruCache CAPS_CACHE = new LruCache(1000); + static final LruCache CAPS_CACHE = new LruCache(1000); /** * Map of Full JID -> DiscoverInfo/null. In case of c2s connection the @@ -109,7 +109,7 @@ public final class EntityCapsManager extends Manager { * link-local connection the key is formed as user@host (no resource) In * case of a server or component the key is formed as domain */ - private static final LruCache JID_TO_NODEVER_CACHE = new LruCache<>(10000); + static final LruCache JID_TO_NODEVER_CACHE = new LruCache<>(10000); static { XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener() { @@ -159,7 +159,7 @@ public final class EntityCapsManager extends Manager { * the user (Full JID) * @return the node version (node#ver) or null */ - public static String getNodeVersionByJid(String jid) { + public static String getNodeVersionByJid(Jid jid) { NodeVerHash nvh = JID_TO_NODEVER_CACHE.get(jid); if (nvh != null) { return nvh.nodeVer; diff --git a/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java b/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java index c372d689d..4cefb6130 100644 --- a/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java +++ b/smack-im/src/main/java/org/jivesoftware/smack/roster/Roster.java @@ -1099,6 +1099,25 @@ public final class Roster extends Manager { return entry.canSeeMyPresence(); } + /** + * Check if the XMPP entity this roster belongs to is subscribed to the presence of the given JID. + * + * @param jid the jid to check. + * @return true if we are subscribed to the presence of the given jid. + * @since 4.2 + */ + public boolean iAmSubscribedTo(Jid jid) { + if (jid == null) { + return false; + } + BareJid bareJid = jid.asBareJid(); + RosterEntry entry = getEntry(bareJid); + if (entry == null) { + return false; + } + return entry.canSeeHisPresence(); + } + /** * Sets if the roster will be loaded from the server when logging in for newly created instances * of {@link Roster}. diff --git a/smack-im/src/main/java/org/jivesoftware/smack/roster/RosterUtil.java b/smack-im/src/main/java/org/jivesoftware/smack/roster/RosterUtil.java index bf1a15eff..0b3cd3a11 100644 --- a/smack-im/src/main/java/org/jivesoftware/smack/roster/RosterUtil.java +++ b/smack-im/src/main/java/org/jivesoftware/smack/roster/RosterUtil.java @@ -26,6 +26,7 @@ import java.util.concurrent.locks.ReentrantLock; import org.jivesoftware.smack.SmackException.NotConnectedException; import org.jivesoftware.smack.SmackException.NotLoggedInException; import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.packet.Presence; import org.jxmpp.jid.BareJid; import org.jxmpp.jid.Jid; @@ -111,4 +112,46 @@ public class RosterUtil { } } + public static void ensureSubscribed(XMPPConnection connectionOne, XMPPConnection connectionTwo, long timeout) + throws NotLoggedInException, NotConnectedException, InterruptedException, TimeoutException { + ensureSubscribedTo(connectionOne, connectionTwo, timeout); + ensureSubscribedTo(connectionTwo, connectionOne, timeout); + } + + public static void ensureSubscribedTo(XMPPConnection connectionOne, XMPPConnection connectionTwo, long timeout) + throws NotLoggedInException, NotConnectedException, InterruptedException, TimeoutException { + Date deadline = new Date(System.currentTimeMillis() + timeout); + ensureSubscribedTo(connectionOne, connectionTwo, deadline); + } + + public static void ensureSubscribedTo(final XMPPConnection connectionOne, final XMPPConnection connectionTwo, + final Date deadline) + throws NotLoggedInException, NotConnectedException, InterruptedException, TimeoutException { + final Roster rosterOne = Roster.getInstanceFor(connectionOne); + final BareJid jidTwo = connectionTwo.getUser().asBareJid(); + + if (rosterOne.iAmSubscribedTo(jidTwo)) + return; + + final BareJid jidOne = connectionOne.getUser().asBareJid(); + final SubscribeListener subscribeListener = new SubscribeListener() { + @Override + public SubscribeAnswer processSubscribe(Jid from, Presence subscribeRequest) { + if (from.equals(jidOne)) { + return SubscribeAnswer.Approve; + } + return null; + } + }; + final Roster rosterTwo = Roster.getInstanceFor(connectionTwo); + + rosterTwo.addSubscribeListener(subscribeListener); + try { + rosterOne.sendSubscriptionRequest(jidTwo); + waitUntilOtherEntityIsSubscribed(rosterTwo, jidOne, deadline); + } + finally { + rosterTwo.removeSubscribeListener(subscribeListener); + } + } } diff --git a/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/AbstractSmackIntTest.java b/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/AbstractSmackIntTest.java index 8c8e93536..ef7f6d5fb 100644 --- a/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/AbstractSmackIntTest.java +++ b/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/AbstractSmackIntTest.java @@ -1,6 +1,6 @@ /** * - * Copyright 2015 Florian Schmaus + * Copyright 2015-2016 Florian Schmaus * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,12 +17,58 @@ package org.igniterealtime.smack.inttest; import java.util.Random; +import java.util.concurrent.TimeoutException; import java.util.logging.Logger; +import org.jivesoftware.smack.PacketCollector; +import org.jivesoftware.smack.SmackException.NoResponseException; +import org.jivesoftware.smack.SmackException.NotConnectedException; +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.XMPPException.XMPPErrorException; +import org.jivesoftware.smack.filter.StanzaFilter; + public abstract class AbstractSmackIntTest { protected static final Logger LOGGER = Logger.getLogger(AbstractSmackIntTest.class.getName()); protected static final Random INSECURE_RANDOM = new Random(); + protected final String testRunId; + + protected final long timeout; + + protected AbstractSmackIntTest(String testRunId, long timeout) { + this.testRunId = testRunId; + this.timeout = timeout; + } + + protected void performActionAndWaitUntilStanzaReceived(Runnable action, XMPPConnection connection, StanzaFilter filter) + throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { + PacketCollector.Configuration configuration = PacketCollector.newConfiguration().setStanzaFilter( + filter).setSize(1); + PacketCollector collector = connection.createPacketCollector(configuration); + + try { + action.run(); + collector.nextResultOrThrow(timeout); + } + finally { + collector.cancel(); + } + } + + protected void waitUntilTrue(Condition condition) throws TimeoutException, NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { + final long deadline = System.currentTimeMillis() + timeout; + do { + if (condition.evaluate()) { + return; + } + Thread.yield(); + } while (System.currentTimeMillis() <= deadline); + throw new TimeoutException("Timeout waiting for condition to become true. Timeout was " + timeout + " ms."); + } + + protected interface Condition { + boolean evaluate() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException; + } } 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 d3f62d619..e6cac85ee 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 @@ -40,19 +40,10 @@ public abstract class AbstractSmackIntegrationTest extends AbstractSmackIntTest */ protected final XMPPConnection connection; - protected final String testRunId; - - protected final long defaultTimeout; - public AbstractSmackIntegrationTest(SmackIntegrationTestEnvironment environment) { + super(environment.testRunId, environment.configuration.replyTimeout); this.connection = this.conOne = environment.conOne; this.conTwo = environment.conTwo; this.conThree = environment.conThree; - if (environment.configuration.replyTimeout > 0) { - this.defaultTimeout = environment.configuration.replyTimeout; - } else { - this.defaultTimeout = 2 * 60 * 1000; - } - this.testRunId = environment.testRunId; } } diff --git a/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/AbstractSmackLowLevelIntegrationTest.java b/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/AbstractSmackLowLevelIntegrationTest.java index 6b631e78e..81ddb7b4b 100644 --- a/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/AbstractSmackLowLevelIntegrationTest.java +++ b/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/AbstractSmackLowLevelIntegrationTest.java @@ -36,14 +36,12 @@ public abstract class AbstractSmackLowLevelIntegrationTest extends AbstractSmack */ protected final Configuration configuration; - protected final String testRunId; - protected final DomainBareJid service; public AbstractSmackLowLevelIntegrationTest(SmackIntegrationTestEnvironment environment) { + super(environment.testRunId, environment.configuration.replyTimeout); this.environment = environment; this.configuration = environment.configuration; - this.testRunId = environment.testRunId; this.service = configuration.service; } diff --git a/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/Configuration.java b/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/Configuration.java index 02210e2a0..814b1b4f2 100644 --- a/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/Configuration.java +++ b/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/Configuration.java @@ -83,7 +83,11 @@ public final class Configuration { "'service' must be set. Either via 'properties' files or via system property 'sinttest.service'."); this.serviceTlsPin = serviceTlsPin; this.securityMode = securityMode; - this.replyTimeout = replyTimeout; + if (replyTimeout > 0) { + this.replyTimeout = replyTimeout; + } else { + this.replyTimeout = 60000; + } this.debug = debug; if (StringUtils.isNotEmpty(adminAccountUsername, adminAccountPassword)) { accountRegistration = AccountRegistration.serviceAdministration; diff --git a/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/SmackIntegrationTestFramework.java b/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/SmackIntegrationTestFramework.java index 018684c32..5989a92b4 100644 --- a/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/SmackIntegrationTestFramework.java +++ b/smack-integration-test/src/main/java/org/igniterealtime/smack/inttest/SmackIntegrationTestFramework.java @@ -95,9 +95,14 @@ public class SmackIntegrationTestFramework { LOGGER.info("Could not run " + testNotPossible.testMethod.getName() + " because: " + testNotPossible.testNotPossibleException.getMessage()); } + final int successfulTests = testRunResult.successfulTests.size(); + final int availableTests = testRunResult.getNumberOfAvailableTests(); + final int possibleTests = testRunResult.getNumberOfPossibleTests(); LOGGER.info("SmackIntegrationTestFramework[" + testRunResult.testRunId + ']' + ": Finished [" - + testRunResult.successfulTests.size() + '/' + testRunResult.numberOfTests + ']'); + + successfulTests + '/' + possibleTests + "] (of " + availableTests + " available tests)"); if (!testRunResult.failedIntegrationTests.isEmpty()) { + final int failedTests = testRunResult.failedIntegrationTests.size(); + LOGGER.warning("The following " + failedTests + " tests failed!"); for (FailedTest failedTest : testRunResult.failedIntegrationTests) { final Method method = failedTest.testMethod; final String className = method.getDeclaringClass().getName(); @@ -106,6 +111,8 @@ public class SmackIntegrationTestFramework { LOGGER.severe(className + CLASS_METHOD_SEP + methodName + " failed: " + cause); } System.exit(2); + } else { + LOGGER.info("All possible Smack Integration Tests completed successfully. \\o/"); } System.exit(0); } @@ -251,7 +258,9 @@ public class SmackIntegrationTestFramework { continue; } - testRunResult.numberOfTests.addAndGet(smackIntegrationTestMethods.size()); + final int detectedTestMethodsCount = smackIntegrationTestMethods.size(); + testRunResult.numberOfAvailableTests.addAndGet(detectedTestMethodsCount); + testRunResult.numberOfPossibleTests.addAndGet(detectedTestMethodsCount); AbstractSmackIntTest test; switch (testType) { @@ -274,6 +283,7 @@ public class SmackIntegrationTestFramework { Throwable cause = e.getCause(); if (cause instanceof TestNotPossibleException) { testRunResult.impossibleTestClasses.put(testClass, cause.getMessage()); + testRunResult.numberOfPossibleTests.addAndGet(-detectedTestMethodsCount); } else { throwFatalException(cause); @@ -306,6 +316,7 @@ public class SmackIntegrationTestFramework { Throwable cause = e.getCause(); if (cause instanceof TestNotPossibleException) { testRunResult.impossibleTestClasses.put(testClass, cause.getMessage()); + testRunResult.numberOfPossibleTests.addAndGet(-detectedTestMethodsCount); } else { throwFatalException(cause); @@ -622,7 +633,8 @@ public class SmackIntegrationTestFramework { private final List failedIntegrationTests = Collections.synchronizedList(new LinkedList()); private final List impossibleTestMethods = Collections.synchronizedList(new LinkedList()); private final Map, String> impossibleTestClasses = new HashMap<>(); - private final AtomicInteger numberOfTests = new AtomicInteger(); + private final AtomicInteger numberOfAvailableTests = new AtomicInteger(); + private final AtomicInteger numberOfPossibleTests = new AtomicInteger(); private TestRunResult() { } @@ -631,8 +643,12 @@ public class SmackIntegrationTestFramework { return testRunId; } - public int getNumberOfTests() { - return numberOfTests.get(); + public int getNumberOfAvailableTests() { + return numberOfAvailableTests.get(); + } + + public int getNumberOfPossibleTests() { + return numberOfPossibleTests.get(); } public List getSuccessfulTests() { diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smack/ChatTest.java b/smack-integration-test/src/main/java/org/jivesoftware/smack/ChatTest.java index f097d199f..0e17c5e76 100644 --- a/smack-integration-test/src/main/java/org/jivesoftware/smack/ChatTest.java +++ b/smack-integration-test/src/main/java/org/jivesoftware/smack/ChatTest.java @@ -55,12 +55,12 @@ public class ChatTest extends AbstractSmackIntegrationTest { } @BeforeClass - public static void setUp() { + public void setUp() { JivePropertiesManager.setJavaObjectEnabled(true); } @AfterClass - public static void tearDown() { + public void tearDown() { JivePropertiesManager.setJavaObjectEnabled(false); } 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 new file mode 100644 index 000000000..b623b7004 --- /dev/null +++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/caps/EntityCapsTest.java @@ -0,0 +1,210 @@ +/** + * + * Copyright 2013-2016 Florian Schmaus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jivesoftware.smackx.caps; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.util.HashSet; +import java.util.Set; +import java.util.concurrent.TimeoutException; +import java.util.concurrent.atomic.AtomicInteger; + +import org.igniterealtime.smack.inttest.AbstractSmackIntegrationTest; +import org.igniterealtime.smack.inttest.SmackIntegrationTest; +import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment; +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.XMPPException; +import org.jivesoftware.smack.XMPPException.XMPPErrorException; +import org.jivesoftware.smack.filter.AndFilter; +import org.jivesoftware.smack.filter.FromMatchesFilter; +import org.jivesoftware.smack.filter.IQTypeFilter; +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.smackx.disco.ServiceDiscoveryManager; +import org.jivesoftware.smackx.disco.packet.DiscoverInfo; +import org.junit.AfterClass; +import org.junit.BeforeClass; + +public class EntityCapsTest extends AbstractSmackIntegrationTest { + + private final EntityCapsManager ecmTwo; + private final ServiceDiscoveryManager sdmOne; + private final ServiceDiscoveryManager sdmTwo; + + private boolean discoInfoSend = false; + + public EntityCapsTest(SmackIntegrationTestEnvironment environment) { + super(environment); + ecmTwo = EntityCapsManager.getInstanceFor(environment.conTwo); + sdmOne = ServiceDiscoveryManager.getInstanceFor(environment.conOne); + sdmTwo = ServiceDiscoveryManager.getInstanceFor(environment.conTwo); + } + + private final AtomicInteger dummyFeatureId = new AtomicInteger(); + private final Set dummyFeatures = new HashSet<>(); + + private String getNewDummyFeature() { + String dummyFeature = "entityCapsTest" + dummyFeatureId.incrementAndGet(); + dummyFeatures.add(dummyFeature); + return dummyFeature; + } + + @BeforeClass + public void setUp() throws NotLoggedInException, NotConnectedException, InterruptedException, TimeoutException { + RosterUtil.ensureSubscribed(conOne, conTwo, timeout); + } + + @AfterClass + public void tearDown() throws NotConnectedException, InterruptedException { + RosterUtil.ensureNotSubscribedToEachOther(conOne, conTwo); + ServiceDiscoveryManager[] sdms = new ServiceDiscoveryManager[] { sdmOne, sdmTwo }; + for (ServiceDiscoveryManager sdm : sdms) { + for (String dummyFeature : dummyFeatures) { + sdm.removeFeature(dummyFeature); + } + } + } + + @SmackIntegrationTest + public void testLocalEntityCaps() throws InterruptedException, NoResponseException, XMPPErrorException, NotConnectedException { + final String dummyFeature = getNewDummyFeature(); + DiscoverInfo info = EntityCapsManager.getDiscoveryInfoByNodeVer(ecmTwo.getLocalNodeVer()); + assertFalse(info.containsFeature(dummyFeature)); + + dropWholeEntityCapsCache(); + + performActionAndWaitUntilStanzaReceived(new Runnable() { + @Override + public void run() { + // This should cause a new presence stanza from con1 with and updated + // 'ver' String + sdmTwo.addFeature(dummyFeature); + } + }, conOne, new AndFilter(PresenceTypeFilter.AVAILABLE, FromMatchesFilter.create(conTwo.getUser()))); + + // The presence stanza should get received by con0 and the data should + // be recorded in the map + // Note that while both connections use the same static Entity Caps + // cache, + // it's assured that *not* con1 added the data to the Entity Caps cache. + // Every time the entities features + // and identities change only a new caps 'ver' is calculated and send + // with the presence stanza + // The other connection has to receive this stanza and record the + // information in order for this test to succeed. + info = EntityCapsManager.getDiscoveryInfoByNodeVer(ecmTwo.getLocalNodeVer()); + assertNotNull(info); + assertTrue(info.containsFeature(dummyFeature)); + } + + /** + * Test if entity caps actually prevent a disco info request and reply. + * + * @throws XMPPException + * @throws InterruptedException + * @throws NotConnectedException + * @throws NoResponseException + * + */ + @SmackIntegrationTest + public void testPreventDiscoInfo() throws XMPPException, NoResponseException, NotConnectedException, InterruptedException { + final String dummyFeature = getNewDummyFeature(); + conOne.addPacketSendingListener(new StanzaListener() { + + @Override + public void processPacket(Stanza stanza) { + discoInfoSend = true; + } + + }, new AndFilter(new StanzaTypeFilter(DiscoverInfo.class), IQTypeFilter.GET)); + + // add a bogus feature so that con1 ver won't match con0's + sdmTwo.addFeature(dummyFeature); + + dropCapsCache(); + // discover that + DiscoverInfo info = sdmOne.discoverInfo(conTwo.getUser()); + // that discovery should cause a disco#info + assertTrue(discoInfoSend); + assertTrue(info.containsFeature(dummyFeature)); + discoInfoSend = false; + + // discover that + info = sdmOne.discoverInfo(conTwo.getUser()); + // that discovery shouldn't cause a disco#info + assertFalse(discoInfoSend); + assertTrue(info.containsFeature(dummyFeature)); + } + + @SmackIntegrationTest + public void testCapsChanged() { + final String dummyFeature = getNewDummyFeature(); + String nodeVerBefore = EntityCapsManager.getNodeVersionByJid(conTwo.getUser()); + sdmTwo.addFeature(dummyFeature); + String nodeVerAfter = EntityCapsManager.getNodeVersionByJid(conTwo.getUser()); + + assertFalse(nodeVerBefore.equals(nodeVerAfter)); + } + + @SmackIntegrationTest + public void testEntityCaps() throws XMPPException, InterruptedException, NoResponseException, NotConnectedException, TimeoutException { + final String dummyFeature = getNewDummyFeature(); + + dropWholeEntityCapsCache(); + + performActionAndWaitUntilStanzaReceived(new Runnable() { + @Override + public void run() { + sdmTwo.addFeature(dummyFeature); + } + }, connection, new AndFilter(PresenceTypeFilter.AVAILABLE, FromMatchesFilter.create(conTwo.getUser()))); + + waitUntilTrue(new Condition() { + @Override + public boolean evaluate() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { + DiscoverInfo info = sdmOne.discoverInfo(conTwo.getUser()); + return info.containsFeature(dummyFeature); + } + }); + DiscoverInfo info = sdmOne.discoverInfo(conTwo.getUser()); + + String u1ver = EntityCapsManager.getNodeVersionByJid(conTwo.getUser()); + assertNotNull(u1ver); + + DiscoverInfo entityInfo = EntityCapsManager.CAPS_CACHE.get(u1ver); + assertNotNull(entityInfo); + + assertEquals(info.toXML(), entityInfo.toXML()); + } + + private static void dropWholeEntityCapsCache() { + EntityCapsManager.CAPS_CACHE.clear(); + EntityCapsManager.JID_TO_NODEVER_CACHE.clear(); + } + + private static void dropCapsCache() { + EntityCapsManager.CAPS_CACHE.clear(); + } +} diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smackx/caps/package-info.java b/smack-integration-test/src/main/java/org/jivesoftware/smackx/caps/package-info.java new file mode 120000 index 000000000..65b39fb44 --- /dev/null +++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/caps/package-info.java @@ -0,0 +1 @@ +../../../../../../../../smack-extensions/src/main/java/org/jivesoftware/smackx/caps/package-info.java \ No newline at end of file diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smackx/iot/IoTControlIntegrationTest.java b/smack-integration-test/src/main/java/org/jivesoftware/smackx/iot/IoTControlIntegrationTest.java index 36cb5a527..2e1f6eca5 100644 --- a/smack-integration-test/src/main/java/org/jivesoftware/smackx/iot/IoTControlIntegrationTest.java +++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/iot/IoTControlIntegrationTest.java @@ -81,7 +81,7 @@ public class IoTControlIntegrationTest extends AbstractSmackIntegrationTest { IoTControlManagerOne.installThing(controlThing); try { - RosterIntegrationTest.ensureBothAccountsAreSubscribedToEachOther(conOne, conTwo, defaultTimeout); + RosterIntegrationTest.ensureBothAccountsAreSubscribedToEachOther(conOne, conTwo, timeout); SetData data = new SetBoolData(testRunId, true); IoTSetResponse response = IoTControlManagerTwo.setUsingIq(conOne.getUser(), data); @@ -92,6 +92,6 @@ public class IoTControlIntegrationTest extends AbstractSmackIntegrationTest { RosterIntegrationTest.ensureBothAccountsAreNotInEachOthersRoster(conOne, conTwo); } - syncPoint.waitForResult(defaultTimeout); + syncPoint.waitForResult(timeout); } } diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smackx/iot/IoTDataIntegrationTest.java b/smack-integration-test/src/main/java/org/jivesoftware/smackx/iot/IoTDataIntegrationTest.java index 67edcb7b0..e7dbc4013 100644 --- a/smack-integration-test/src/main/java/org/jivesoftware/smackx/iot/IoTDataIntegrationTest.java +++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/iot/IoTDataIntegrationTest.java @@ -73,7 +73,7 @@ public class IoTDataIntegrationTest extends AbstractSmackIntegrationTest { List values; try { - RosterIntegrationTest.ensureBothAccountsAreSubscribedToEachOther(conOne, conTwo, defaultTimeout); + RosterIntegrationTest.ensureBothAccountsAreSubscribedToEachOther(conOne, conTwo, timeout); values = iotDataManagerTwo.requestMomentaryValuesReadOut(conOne.getUser()); } 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 1951b431d..b96a49c93 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 @@ -88,7 +88,7 @@ public class MultiUserChatIntegrationTest extends AbstractSmackIntegrationTest { mucAsSeenByTwo.join(Resourcepart.from("two-" + randomString)); mucAsSeenByOne.sendMessage(mucMessage); - resultSyncPoint.waitForResult(defaultTimeout); + resultSyncPoint.waitForResult(timeout); mucAsSeenByOne.leave(); mucAsSeenByTwo.leave();