diff --git a/src/main/java/org/jivesoftware/smackx/pubsub/PubSubIntegrationTest.java b/src/main/java/org/jivesoftware/smackx/pubsub/PubSubIntegrationTest.java index 174caa3..76e7e86 100644 --- a/src/main/java/org/jivesoftware/smackx/pubsub/PubSubIntegrationTest.java +++ b/src/main/java/org/jivesoftware/smackx/pubsub/PubSubIntegrationTest.java @@ -26,6 +26,7 @@ import org.jivesoftware.smack.XMPPException.XMPPErrorException; import org.jivesoftware.smack.packet.*; import org.jivesoftware.smackx.geoloc.packet.GeoLocation; +import org.jivesoftware.smackx.pubsub.PubSubException.NotAPubSubNodeException; import org.jivesoftware.smackx.pubsub.packet.PubSub; import org.jivesoftware.smackx.xdata.packet.DataForm; import org.jxmpp.jid.DomainBareJid; @@ -47,9 +48,8 @@ public class PubSubIntegrationTest extends AbstractSmackIntegrationTest { private final PubSubManager pubSubManagerOne; private final PubSubManager pubSubManagerTwo; - public PubSubIntegrationTest(SmackIntegrationTestEnvironment environment) - throws TestNotPossibleException, NoResponseException, XMPPErrorException, - NotConnectedException, InterruptedException { + public PubSubIntegrationTest(SmackIntegrationTestEnvironment environment) throws TestNotPossibleException, + NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { super(environment); DomainBareJid pubSubService = PubSubManager.getPubSubService(conOne); if (pubSubService == null) { @@ -65,59 +65,61 @@ public PubSubIntegrationTest(SmackIntegrationTestEnvironment environment) /** * Asserts that an item can be published to a node with default configuration. * - * @throws NoResponseException if there was no response from the remote entity. - * @throws XMPPErrorException if there was an XMPP error returned. + * @throws NoResponseException if there was no response from the remote + * entity. + * @throws XMPPErrorException if there was an XMPP error returned. * @throws NotConnectedException if the XMPP connection is not connected. - * @throws InterruptedException if the calling thread was interrupted. + * @throws InterruptedException if the calling thread was interrupted. */ @SmackIntegrationTest - public void publishItemTest() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { + public void publishItemTest() + throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { final String nodename = "sinttest-publish-item-nodename-" + testRunId; final String needle = "test content " + Math.random(); LeafNode node = pubSubManagerOne.createNode(nodename); try { // Publish a new item. - node.publish( new PayloadItem<>( GeoLocation.builder().setDescription( needle ).build() ) ); + node.publish(new PayloadItem<>(GeoLocation.builder().setDescription(needle).build())); - // Retrieve items and assert that the item that was just published is among them. + // Retrieve items and assert that the item that was just published is among + // them. final List items = node.getItems(); - assertTrue( items.stream().anyMatch( stanza -> stanza.toXML( "" ).toString().contains( needle ) ) ); - } - finally { - pubSubManagerOne.deleteNode( nodename ); + assertTrue(items.stream().anyMatch(stanza -> stanza.toXML("").toString().contains(needle))); + } finally { + pubSubManagerOne.deleteNode(nodename); } } /** * Asserts that one can subscribe to an existing node. * - * @throws NoResponseException if there was no response from the remote entity. - * @throws XMPPErrorException if there was an XMPP error returned. + * @throws NoResponseException if there was no response from the remote + * entity. + * @throws XMPPErrorException if there was an XMPP error returned. * @throws NotConnectedException if the XMPP connection is not connected. - * @throws InterruptedException if the calling thread was interrupted. + * @throws InterruptedException if the calling thread was interrupted. */ @SmackIntegrationTest - public void subscribeTest() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { + public void subscribeTest() + throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { final String nodename = "sinttest-subscribe-nodename-" + testRunId; pubSubManagerOne.createNode(nodename); try { // Subscribe to the node, using a different user than the owner of the node. final Node subscriberNode = pubSubManagerTwo.getNode(nodename); final EntityBareJid subscriber = conTwo.getUser().asEntityBareJid(); - final Subscription subscription = subscriberNode.subscribe( subscriber ); - assertNotNull( subscription ); + final Subscription subscription = subscriberNode.subscribe(subscriber); + assertNotNull(subscription); - // Assert that subscription is correctly reported when the subscriber requests its subscriptions. - final List subscriptions = pubSubManagerTwo.getNode( nodename ).getSubscriptions(); - assertNotNull( subscriptions ); - assertTrue( subscriptions.stream().anyMatch( s -> subscriber.equals(s.getJid())) ); - } - catch ( PubSubException.NotAPubSubNodeException e ) - { + // Assert that subscription is correctly reported when the subscriber requests + // its subscriptions. + final List subscriptions = pubSubManagerTwo.getNode(nodename).getSubscriptions(); + assertNotNull(subscriptions); + assertTrue(subscriptions.stream().anyMatch(s -> subscriber.equals(s.getJid()))); + } catch (PubSubException.NotAPubSubNodeException e) { throw new AssertionError("The published item was not received by the subscriber.", e); - } - finally { - pubSubManagerOne.deleteNode( nodename ); + } finally { + pubSubManagerOne.deleteNode(nodename); } } @@ -125,45 +127,48 @@ public void subscribeTest() throws NoResponseException, XMPPErrorException, NotC * Asserts that the server returns a 'bad request' error to a subscription * request in which the JIDs do not match. * - *

From XEP-0060 § 6.1.3.1:

- *
- * If the specified JID is a bare JID or full JID, the service MUST at a - * minimum check the bare JID portion against the bare JID portion of the - * 'from' attribute on the received IQ request to make sure that the - * requesting entity has the same identity as the JID which is being - * requested to be added to the subscriber list. - * - * If the bare JID portions of the JIDs do not match as described above and - * the requesting entity does not have some kind of admin or proxy privilege - * as defined by the implementation, the service MUST return a - * <bad-request/> error (...) - *
+ *

+ * From XEP-0060 § 6.1.3.1: + *

+ *
If the specified JID is a bare JID or full JID, the service MUST + * at a minimum check the bare JID portion against the bare JID portion of the + * 'from' attribute on the received IQ request to make sure that the requesting + * entity has the same identity as the JID which is being requested to be added + * to the subscriber list. * - * @throws NoResponseException if there was no response from the remote entity. - * @throws XMPPErrorException if there was an XMPP error returned. - * @throws NotConnectedException if the XMPP connection is not connected. - * @throws InterruptedException if the calling thread was interrupted. - * @throws XmppStringprepException if the hard-coded test JID cannot be instantiated. - * @throws PubSubException.NotAPubSubNodeException if the node cannot be accessed. + * If the bare JID portions of the JIDs do not match as described above and the + * requesting entity does not have some kind of admin or proxy privilege as + * defined by the implementation, the service MUST return a <bad-request/> + * error (...)
+ * + * @throws NoResponseException if there was no response from + * the remote entity. + * @throws XMPPErrorException if there was an XMPP error + * returned. + * @throws NotConnectedException if the XMPP connection is not + * connected. + * @throws InterruptedException if the calling thread was + * interrupted. + * @throws XmppStringprepException if the hard-coded test JID + * cannot be instantiated. + * @throws PubSubException.NotAPubSubNodeException if the node cannot be + * accessed. */ @SmackIntegrationTest - public void subscribeJIDsDoNotMatchTest() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, XmppStringprepException, PubSubException.NotAPubSubNodeException - { + public void subscribeJIDsDoNotMatchTest() throws NoResponseException, XMPPErrorException, NotConnectedException, + InterruptedException, XmppStringprepException, PubSubException.NotAPubSubNodeException { final String nodename = "sinttest-subscribe-nodename-" + testRunId; pubSubManagerOne.createNode(nodename); try { // Subscribe to the node, using a different user than the owner of the node. final Node subscriberNode = pubSubManagerTwo.getNode(nodename); - final EntityBareJid subscriber = JidCreate.entityBareFrom( "this-jid-does-not-match@example.org" ); - subscriberNode.subscribe( subscriber ); - fail( "The server should have returned a error, but did not." ); - } - catch ( XMPPErrorException e ) - { - assertEquals( StanzaError.Condition.bad_request, e.getStanzaError().getCondition() ); - } - finally { - pubSubManagerOne.deleteNode( nodename ); + final EntityBareJid subscriber = JidCreate.entityBareFrom("this-jid-does-not-match@example.org"); + subscriberNode.subscribe(subscriber); + fail("The server should have returned a error, but did not."); + } catch (XMPPErrorException e) { + assertEquals(StanzaError.Condition.bad_request, e.getStanzaError().getCondition()); + } finally { + pubSubManagerOne.deleteNode(nodename); } } @@ -171,45 +176,50 @@ public void subscribeJIDsDoNotMatchTest() throws NoResponseException, XMPPErrorE * Asserts that the server returns a 'not-authorized' error to a subscription * request where required presence subscription is missing. * - *

From XEP-0060 § 6.1.3.2:

- *
- * For nodes with an access model of "presence", if the requesting entity is - * not subscribed to the owner's presence then the pubsub service MUST - * respond with a <not-authorized/> error (...) - *
+ *

+ * From XEP-0060 § 6.1.3.2: + *

+ *
For nodes with an access model of "presence", if the requesting + * entity is not subscribed to the owner's presence then the pubsub service MUST + * respond with a <not-authorized/> error (...)
* - * @throws NoResponseException if there was no response from the remote entity. - * @throws XMPPErrorException if there was an XMPP error returned. - * @throws NotConnectedException if the XMPP connection is not connected. - * @throws InterruptedException if the calling thread was interrupted. - * @throws PubSubException.NotAPubSubNodeException if the node cannot be accessed. - * @throws TestNotPossibleException if the server does not support the functionality required for this test. + * @throws NoResponseException if there was no response from + * the remote entity. + * @throws XMPPErrorException if there was an XMPP error + * returned. + * @throws NotConnectedException if the XMPP connection is not + * connected. + * @throws InterruptedException if the calling thread was + * interrupted. + * @throws PubSubException.NotAPubSubNodeException if the node cannot be + * accessed. + * @throws TestNotPossibleException if the server does not + * support the functionality + * required for this test. */ @SmackIntegrationTest - public void subscribePresenceSubscriptionRequiredTest() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, PubSubException.NotAPubSubNodeException, TestNotPossibleException - { + public void subscribePresenceSubscriptionRequiredTest() + throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, + PubSubException.NotAPubSubNodeException, TestNotPossibleException { final String nodename = "sinttest-subscribe-nodename-" + testRunId; final ConfigureForm defaultConfiguration = pubSubManagerOne.getDefaultConfiguration(); final ConfigureForm config = new ConfigureForm(defaultConfiguration.createAnswerForm()); config.setAccessModel(AccessModel.presence); try { - pubSubManagerOne.createNode( nodename, config ); - } catch ( XMPPErrorException e ) { - throw new TestNotPossibleException( "Access model 'presence' not supported on the server." ); + pubSubManagerOne.createNode(nodename, config); + } catch (XMPPErrorException e) { + throw new TestNotPossibleException("Access model 'presence' not supported on the server."); } try { // Subscribe to the node, using a different user than the owner of the node. final Node subscriberNode = pubSubManagerTwo.getNode(nodename); final EntityBareJid subscriber = conTwo.getUser().asEntityBareJid(); - subscriberNode.subscribe( subscriber ); - fail( "The server should have returned a error, but did not." ); - } - catch ( XMPPErrorException e ) - { - assertEquals( StanzaError.Condition.not_authorized, e.getStanzaError().getCondition() ); - } - finally { - pubSubManagerOne.deleteNode( nodename ); + subscriberNode.subscribe(subscriber); + fail("The server should have returned a error, but did not."); + } catch (XMPPErrorException e) { + assertEquals(StanzaError.Condition.not_authorized, e.getStanzaError().getCondition()); + } finally { + pubSubManagerOne.deleteNode(nodename); } } @@ -217,45 +227,49 @@ public void subscribePresenceSubscriptionRequiredTest() throws NoResponseExcepti * Asserts that the server returns a 'not-authorized' error to a subscription * request where required roster items are missing. * - *

From XEP-0060 § 6.1.3.3:

- *
- * For nodes with an access model of "roster", if the requesting entity is - * not in one of the authorized roster groups then the pubsub service MUST - * respond with a <not-authorized/> error (...) - *
+ *

+ * From XEP-0060 § 6.1.3.3: + *

+ *
For nodes with an access model of "roster", if the requesting + * entity is not in one of the authorized roster groups then the pubsub service + * MUST respond with a <not-authorized/> error (...)
* - * @throws NoResponseException if there was no response from the remote entity. - * @throws XMPPErrorException if there was an XMPP error returned. - * @throws NotConnectedException if the XMPP connection is not connected. - * @throws InterruptedException if the calling thread was interrupted. - * @throws PubSubException.NotAPubSubNodeException if the node cannot be accessed. - * @throws TestNotPossibleException if the server does not support the functionality required for this test. + * @throws NoResponseException if there was no response from + * the remote entity. + * @throws XMPPErrorException if there was an XMPP error + * returned. + * @throws NotConnectedException if the XMPP connection is not + * connected. + * @throws InterruptedException if the calling thread was + * interrupted. + * @throws PubSubException.NotAPubSubNodeException if the node cannot be + * accessed. + * @throws TestNotPossibleException if the server does not + * support the functionality + * required for this test. */ @SmackIntegrationTest - public void subscribeNotInRosterGroupTest() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, PubSubException.NotAPubSubNodeException, TestNotPossibleException - { + public void subscribeNotInRosterGroupTest() throws NoResponseException, XMPPErrorException, NotConnectedException, + InterruptedException, PubSubException.NotAPubSubNodeException, TestNotPossibleException { final String nodename = "sinttest-subscribe-nodename-" + testRunId; final ConfigureForm defaultConfiguration = pubSubManagerOne.getDefaultConfiguration(); final ConfigureForm config = new ConfigureForm(defaultConfiguration.createAnswerForm()); config.setAccessModel(AccessModel.roster); try { - pubSubManagerOne.createNode( nodename, config ); - } catch ( XMPPErrorException e ) { - throw new TestNotPossibleException( "Access model 'roster' not supported on the server." ); + pubSubManagerOne.createNode(nodename, config); + } catch (XMPPErrorException e) { + throw new TestNotPossibleException("Access model 'roster' not supported on the server."); } try { // Subscribe to the node, using a different user than the owner of the node. final Node subscriberNode = pubSubManagerTwo.getNode(nodename); final EntityBareJid subscriber = conTwo.getUser().asEntityBareJid(); - subscriberNode.subscribe( subscriber ); - fail( "The server should have returned a error, but did not." ); - } - catch ( XMPPErrorException e ) - { - assertEquals( StanzaError.Condition.not_authorized, e.getStanzaError().getCondition() ); - } - finally { - pubSubManagerOne.deleteNode( nodename ); + subscriberNode.subscribe(subscriber); + fail("The server should have returned a error, but did not."); + } catch (XMPPErrorException e) { + assertEquals(StanzaError.Condition.not_authorized, e.getStanzaError().getCondition()); + } finally { + pubSubManagerOne.deleteNode(nodename); } } @@ -263,47 +277,51 @@ public void subscribeNotInRosterGroupTest() throws NoResponseException, XMPPErro * Asserts that the server returns a 'not-allowed' error to a subscription * request where required whitelisting is missing. * - *

From XEP-0060 § 6.1.3.4:

- *
- * For nodes with a node access model of "whitelist", if the requesting - * entity is not on the whitelist then the service MUST return a - * <not-allowed/> error, specifying a pubsub-specific error condition - * of <closed-node/>. - *
+ *

+ * From XEP-0060 § 6.1.3.4: + *

+ *
For nodes with a node access model of "whitelist", if the + * requesting entity is not on the whitelist then the service MUST return a + * <not-allowed/> error, specifying a pubsub-specific error condition of + * <closed-node/>.
* - * @throws NoResponseException if there was no response from the remote entity. - * @throws XMPPErrorException if there was an XMPP error returned. - * @throws NotConnectedException if the XMPP connection is not connected. - * @throws InterruptedException if the calling thread was interrupted. - * @throws PubSubException.NotAPubSubNodeException if the node cannot be accessed. - * @throws TestNotPossibleException if the server does not support the functionality required for this test. + * @throws NoResponseException if there was no response from + * the remote entity. + * @throws XMPPErrorException if there was an XMPP error + * returned. + * @throws NotConnectedException if the XMPP connection is not + * connected. + * @throws InterruptedException if the calling thread was + * interrupted. + * @throws PubSubException.NotAPubSubNodeException if the node cannot be + * accessed. + * @throws TestNotPossibleException if the server does not + * support the functionality + * required for this test. */ @SmackIntegrationTest - public void subscribeNotOnWhitelistTest() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, PubSubException.NotAPubSubNodeException, TestNotPossibleException - { + public void subscribeNotOnWhitelistTest() throws NoResponseException, XMPPErrorException, NotConnectedException, + InterruptedException, PubSubException.NotAPubSubNodeException, TestNotPossibleException { final String nodename = "sinttest-subscribe-nodename-" + testRunId; final ConfigureForm defaultConfiguration = pubSubManagerOne.getDefaultConfiguration(); final ConfigureForm config = new ConfigureForm(defaultConfiguration.createAnswerForm()); config.setAccessModel(AccessModel.whitelist); try { - pubSubManagerOne.createNode( nodename, config ); - } catch ( XMPPErrorException e ) { - throw new TestNotPossibleException( "Access model 'whitelist' not supported on the server." ); + pubSubManagerOne.createNode(nodename, config); + } catch (XMPPErrorException e) { + throw new TestNotPossibleException("Access model 'whitelist' not supported on the server."); } try { // Subscribe to the node, using a different user than the owner of the node. final Node subscriberNode = pubSubManagerTwo.getNode(nodename); final EntityBareJid subscriber = conTwo.getUser().asEntityBareJid(); - subscriberNode.subscribe( subscriber ); - fail( "The server should have returned a error, but did not." ); - } - catch ( XMPPErrorException e ) - { - assertEquals( StanzaError.Condition.not_allowed, e.getStanzaError().getCondition() ); - assertNotNull( e.getStanzaError().getExtension( "closed-node", "http://jabber.org/protocol/pubsub#errors" )); - } - finally { - pubSubManagerOne.deleteNode( nodename ); + subscriberNode.subscribe(subscriber); + fail("The server should have returned a error, but did not."); + } catch (XMPPErrorException e) { + assertEquals(StanzaError.Condition.not_allowed, e.getStanzaError().getCondition()); + assertNotNull(e.getStanzaError().getExtension("closed-node", "http://jabber.org/protocol/pubsub#errors")); + } finally { + pubSubManagerOne.deleteNode(nodename); } } @@ -311,89 +329,103 @@ public void subscribeNotOnWhitelistTest() throws NoResponseException, XMPPErrorE * Asserts that the server returns a 'not-authorized' error to a subscription * request when the subscriber already has a pending subscription. * - *

From XEP-0060 § 6.1.3.7:

- *
- * If the requesting entity has a pending subscription, the service MUST - * return a <not-authorized/> error to the subscriber, specifying a + *

+ * From XEP-0060 § 6.1.3.7: + *

+ *
If the requesting entity has a pending subscription, the service + * MUST return a <not-authorized/> error to the subscriber, specifying a * pubsub-specific error condition of <pending-subscription/>. *
* - * @throws NoResponseException if there was no response from the remote entity. - * @throws XMPPErrorException if there was an XMPP error returned. - * @throws NotConnectedException if the XMPP connection is not connected. - * @throws InterruptedException if the calling thread was interrupted. - * @throws PubSubException.NotAPubSubNodeException if the node cannot be accessed. - * @throws TestNotPossibleException if the server does not support the functionality required for this test. + * @throws NoResponseException if there was no response from + * the remote entity. + * @throws XMPPErrorException if there was an XMPP error + * returned. + * @throws NotConnectedException if the XMPP connection is not + * connected. + * @throws InterruptedException if the calling thread was + * interrupted. + * @throws PubSubException.NotAPubSubNodeException if the node cannot be + * accessed. + * @throws TestNotPossibleException if the server does not + * support the functionality + * required for this test. */ @SmackIntegrationTest - public void subscribePendingSubscriptionTest() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, PubSubException.NotAPubSubNodeException, TestNotPossibleException - { + public void subscribePendingSubscriptionTest() + throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, + PubSubException.NotAPubSubNodeException, TestNotPossibleException { final String nodename = "sinttest-subscribe-nodename-" + testRunId; final ConfigureForm defaultConfiguration = pubSubManagerOne.getDefaultConfiguration(); final ConfigureForm config = new ConfigureForm(defaultConfiguration.createAnswerForm()); config.setAccessModel(AccessModel.authorize); try { - pubSubManagerOne.createNode( nodename, config ); - } catch ( XMPPErrorException e ) { - throw new TestNotPossibleException( "Access model 'authorize' not supported on the server." ); + pubSubManagerOne.createNode(nodename, config); + } catch (XMPPErrorException e) { + throw new TestNotPossibleException("Access model 'authorize' not supported on the server."); } try { // Subscribe to the node, using a different user than the owner of the node. final Node subscriberNode = pubSubManagerTwo.getNode(nodename); final EntityBareJid subscriber = conTwo.getUser().asEntityBareJid(); - subscriberNode.subscribe( subscriber ); - subscriberNode.subscribe( subscriber ); - fail( "The server should have returned a error, but did not." ); - } - catch ( XMPPErrorException e ) - { - assertEquals( StanzaError.Condition.not_authorized, e.getStanzaError().getCondition() ); - assertNotNull( e.getStanzaError().getExtension( "pending-subscription", "http://jabber.org/protocol/pubsub#errors" )); - } - finally { - pubSubManagerOne.deleteNode( nodename ); + subscriberNode.subscribe(subscriber); + subscriberNode.subscribe(subscriber); + fail("The server should have returned a error, but did not."); + } catch (XMPPErrorException e) { + assertEquals(StanzaError.Condition.not_authorized, e.getStanzaError().getCondition()); + assertNotNull(e.getStanzaError().getExtension("pending-subscription", + "http://jabber.org/protocol/pubsub#errors")); + } finally { + pubSubManagerOne.deleteNode(nodename); } } /** - * Asserts that the server returns a pending notification to the subscriber - * when subscribing to a node that requires authorization + * Asserts that the server returns a pending notification to the subscriber when + * subscribing to a node that requires authorization * - *

From XEP-0060 § 6.1.4:

- *
- * Because the subscription request may or may not be approved, the service - * MUST return a pending notification to the subscriber. - *
+ *

+ * From XEP-0060 § 6.1.4: + *

+ *
Because the subscription request may or may not be approved, the + * service MUST return a pending notification to the subscriber.
* - * @throws NoResponseException if there was no response from the remote entity. - * @throws XMPPErrorException if there was an XMPP error returned. - * @throws NotConnectedException if the XMPP connection is not connected. - * @throws InterruptedException if the calling thread was interrupted. - * @throws PubSubException.NotAPubSubNodeException if the node cannot be accessed. - * @throws TestNotPossibleException if the server does not support the functionality required for this test. + * @throws NoResponseException if there was no response from + * the remote entity. + * @throws XMPPErrorException if there was an XMPP error + * returned. + * @throws NotConnectedException if the XMPP connection is not + * connected. + * @throws InterruptedException if the calling thread was + * interrupted. + * @throws PubSubException.NotAPubSubNodeException if the node cannot be + * accessed. + * @throws TestNotPossibleException if the server does not + * support the functionality + * required for this test. */ @SmackIntegrationTest - public void subscribeApprovalRequiredGeneratesNotificationTest() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, PubSubException.NotAPubSubNodeException, TestNotPossibleException - { + public void subscribeApprovalRequiredGeneratesNotificationTest() + throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, + PubSubException.NotAPubSubNodeException, TestNotPossibleException { final String nodename = "sinttest-subscribe-nodename-" + testRunId; final ConfigureForm defaultConfiguration = pubSubManagerOne.getDefaultConfiguration(); final ConfigureForm config = new ConfigureForm(defaultConfiguration.createAnswerForm()); config.setAccessModel(AccessModel.authorize); try { - pubSubManagerOne.createNode( nodename, config ); - } catch ( XMPPErrorException e ) { - throw new TestNotPossibleException( "Access model 'authorize' not supported on the server." ); + pubSubManagerOne.createNode(nodename, config); + } catch (XMPPErrorException e) { + throw new TestNotPossibleException("Access model 'authorize' not supported on the server."); } try { // Subscribe to the node, using a different user than the owner of the node. final Node subscriberNode = pubSubManagerTwo.getNode(nodename); final EntityBareJid subscriber = conTwo.getUser().asEntityBareJid(); - final Subscription result = subscriberNode.subscribe( subscriber ); + final Subscription result = subscriberNode.subscribe(subscriber); - assertEquals( Subscription.State.pending, result.getState() ); - } - finally { - pubSubManagerOne.deleteNode( nodename ); + assertEquals(Subscription.State.pending, result.getState()); + } finally { + pubSubManagerOne.deleteNode(nodename); } } @@ -401,50 +433,57 @@ public void subscribeApprovalRequiredGeneratesNotificationTest() throws NoRespon * Asserts that the server returns non-null, unique subscription IDs when * subscribing twice to the same node (with different options). * - *

From XEP-0060 § 6.1.6:

- *
- * If multiple subscriptions for the same JID are allowed, the service MUST - * use the 'subid' attribute to differentiate between subscriptions for the - * same entity (therefore the SubID MUST be unique for each node+JID + *

+ * From XEP-0060 § 6.1.6: + *

+ *
If multiple subscriptions for the same JID are allowed, the + * service MUST use the 'subid' attribute to differentiate between subscriptions + * for the same entity (therefore the SubID MUST be unique for each node+JID * combination and the SubID MUST be present on the <subscription/> - * element any time it is sent to the subscriber). - *
+ * element any time it is sent to the subscriber).
* - * @throws NoResponseException if there was no response from the remote entity. - * @throws XMPPErrorException if there was an XMPP error returned. - * @throws NotConnectedException if the XMPP connection is not connected. - * @throws InterruptedException if the calling thread was interrupted. - * @throws PubSubException.NotAPubSubNodeException if the node cannot be accessed. - * @throws TestNotPossibleException if the server does not support the functionality required for this test. + * @throws NoResponseException if there was no response from + * the remote entity. + * @throws XMPPErrorException if there was an XMPP error + * returned. + * @throws NotConnectedException if the XMPP connection is not + * connected. + * @throws InterruptedException if the calling thread was + * interrupted. + * @throws PubSubException.NotAPubSubNodeException if the node cannot be + * accessed. + * @throws TestNotPossibleException if the server does not + * support the functionality + * required for this test. */ @SmackIntegrationTest - public void subscribeMultipleSubscriptionsTest() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, PubSubException.NotAPubSubNodeException, TestNotPossibleException - { - if ( !pubSubManagerOne.getSupportedFeatures().containsFeature( PubSubFeature.multi_subscribe ) ) { - throw new TestNotPossibleException( "Feature 'multi-subscribe' not supported on the server." ); + public void subscribeMultipleSubscriptionsTest() + throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, + PubSubException.NotAPubSubNodeException, TestNotPossibleException { + if (!pubSubManagerOne.getSupportedFeatures().containsFeature(PubSubFeature.multi_subscribe)) { + throw new TestNotPossibleException("Feature 'multi-subscribe' not supported on the server."); } final String nodename = "sinttest-multisubscribe-nodename-" + testRunId; - pubSubManagerOne.createNode( nodename ); + pubSubManagerOne.createNode(nodename); try { // Subscribe to the node twice, using different configuration final Node subscriberNode = pubSubManagerTwo.getNode(nodename); final EntityBareJid subscriber = conTwo.getUser().asEntityBareJid(); - final SubscribeForm formA = new SubscribeForm( DataForm.Type.submit ); - formA.setDigestFrequency( 1 ); - final SubscribeForm formB = new SubscribeForm( DataForm.Type.submit ); - formB.setDigestFrequency( 2 ); + final SubscribeForm formA = new SubscribeForm(DataForm.Type.submit); + formA.setDigestFrequency(1); + final SubscribeForm formB = new SubscribeForm(DataForm.Type.submit); + formB.setDigestFrequency(2); - final Subscription subscriptionA = subscriberNode.subscribe( subscriber, formA ); - final Subscription subscriptionB = subscriberNode.subscribe( subscriber, formB ); + final Subscription subscriptionA = subscriberNode.subscribe(subscriber, formA); + final Subscription subscriptionB = subscriberNode.subscribe(subscriber, formB); - assertNotNull( subscriptionA.getId() ); - assertNotNull( subscriptionB.getId() ); - assertNotEquals( subscriptionA.getId(), subscriptionB.getId() ); - } - finally { - pubSubManagerOne.deleteNode( nodename ); + assertNotNull(subscriptionA.getId()); + assertNotNull(subscriptionB.getId()); + assertNotEquals(subscriptionA.getId(), subscriptionB.getId()); + } finally { + pubSubManagerOne.deleteNode(nodename); } } @@ -452,50 +491,58 @@ public void subscribeMultipleSubscriptionsTest() throws NoResponseException, XMP * Asserts that the server returns non-null, unique subscription IDs when * subscribing twice to the same node (with different options). * - *

From XEP-0060 § 6.1.6:

- *
- * If the service does not allow multiple subscriptions for the same entity - * and it receives an additional subscription request, the service MUST - * return the current subscription state (as if the subscription was just - * approved). - *
+ *

+ * From XEP-0060 § 6.1.6: + *

+ *
If the service does not allow multiple subscriptions for the + * same entity and it receives an additional subscription request, the service + * MUST return the current subscription state (as if the subscription was just + * approved).
* - * @throws NoResponseException if there was no response from the remote entity. - * @throws XMPPErrorException if there was an XMPP error returned. - * @throws NotConnectedException if the XMPP connection is not connected. - * @throws InterruptedException if the calling thread was interrupted. - * @throws PubSubException.NotAPubSubNodeException if the node cannot be accessed. - * @throws TestNotPossibleException if the server does not support the functionality required for this test. + * @throws NoResponseException if there was no response from + * the remote entity. + * @throws XMPPErrorException if there was an XMPP error + * returned. + * @throws NotConnectedException if the XMPP connection is not + * connected. + * @throws InterruptedException if the calling thread was + * interrupted. + * @throws PubSubException.NotAPubSubNodeException if the node cannot be + * accessed. + * @throws TestNotPossibleException if the server does not + * support the functionality + * required for this test. */ @SmackIntegrationTest - public void subscribeMultipleSubscriptionNotSupportedTest() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, PubSubException.NotAPubSubNodeException, TestNotPossibleException - { - if ( pubSubManagerOne.getSupportedFeatures().containsFeature( PubSubFeature.multi_subscribe ) ) { - throw new TestNotPossibleException( "Feature 'multi-subscribe' allowed on the server (this test verifies behavior for when it's not)." ); + public void subscribeMultipleSubscriptionNotSupportedTest() + throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, + PubSubException.NotAPubSubNodeException, TestNotPossibleException { + if (pubSubManagerOne.getSupportedFeatures().containsFeature(PubSubFeature.multi_subscribe)) { + throw new TestNotPossibleException( + "Feature 'multi-subscribe' allowed on the server (this test verifies behavior for when it's not)."); } final String nodename = "sinttest-multisubscribe-nodename-" + testRunId; - pubSubManagerOne.createNode( nodename ); + pubSubManagerOne.createNode(nodename); try { // Subscribe to the node twice, using different configuration final Node subscriberNode = pubSubManagerTwo.getNode(nodename); final EntityBareJid subscriber = conTwo.getUser().asEntityBareJid(); - final SubscribeForm formA = new SubscribeForm( DataForm.Type.submit ); - formA.setDigestFrequency( 1 ); - final SubscribeForm formB = new SubscribeForm( DataForm.Type.submit ); - formB.setDigestFrequency( 2 ); + final SubscribeForm formA = new SubscribeForm(DataForm.Type.submit); + formA.setDigestFrequency(1); + final SubscribeForm formB = new SubscribeForm(DataForm.Type.submit); + formB.setDigestFrequency(2); - final Subscription subscriptionA = subscriberNode.subscribe( subscriber, formA ); - final Subscription subscriptionB = subscriberNode.subscribe( subscriber, formB ); + final Subscription subscriptionA = subscriberNode.subscribe(subscriber, formA); + final Subscription subscriptionB = subscriberNode.subscribe(subscriber, formB); // A poor-man's "equal" - final String normalizedRepresentationA = subscriptionA.toXML( XmlEnvironment.EMPTY ).toString(); - final String normalizedRepresentationB = subscriptionB.toXML( XmlEnvironment.EMPTY ).toString(); - assertEquals( normalizedRepresentationA, normalizedRepresentationB ); - } - finally { - pubSubManagerOne.deleteNode( nodename ); + final String normalizedRepresentationA = subscriptionA.toXML(XmlEnvironment.EMPTY).toString(); + final String normalizedRepresentationB = subscriptionB.toXML(XmlEnvironment.EMPTY).toString(); + assertEquals(normalizedRepresentationA, normalizedRepresentationB); + } finally { + pubSubManagerOne.deleteNode(nodename); } } @@ -503,130 +550,142 @@ public void subscribeMultipleSubscriptionNotSupportedTest() throws NoResponseExc * Asserts that one can unsubscribe from a node (when a previous subscription * existed). * - *

From XEP-0060 § 6.2.2:

- *
- * If the request can be successfully processed, the service MUST return an IQ result (...) - *
+ *

+ * From XEP-0060 § 6.2.2: + *

+ *
If the request can be successfully processed, the service MUST + * return an IQ result (...)
* - * @throws NoResponseException if there was no response from the remote entity. - * @throws XMPPErrorException if there was an XMPP error returned. - * @throws NotConnectedException if the XMPP connection is not connected. - * @throws InterruptedException if the calling thread was interrupted. - * @throws PubSubException.NotAPubSubNodeException If an error occurred while creating the node. + * @throws NoResponseException if there was no response from + * the remote entity. + * @throws XMPPErrorException if there was an XMPP error + * returned. + * @throws NotConnectedException if the XMPP connection is not + * connected. + * @throws InterruptedException if the calling thread was + * interrupted. + * @throws PubSubException.NotAPubSubNodeException If an error occurred while + * creating the node. */ @SmackIntegrationTest - public void unsubscribeTest() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, PubSubException.NotAPubSubNodeException - { + public void unsubscribeTest() throws NoResponseException, XMPPErrorException, NotConnectedException, + InterruptedException, PubSubException.NotAPubSubNodeException { final String nodename = "sinttest-unsubscribe-nodename-" + testRunId; pubSubManagerOne.createNode(nodename); try { // Subscribe to the node, using a different user than the owner of the node. - final Node subscriberNode = pubSubManagerTwo.getNode( nodename ); + final Node subscriberNode = pubSubManagerTwo.getNode(nodename); final EntityBareJid subscriber = conTwo.getUser().asEntityBareJid(); - subscriberNode.subscribe( subscriber ); + subscriberNode.subscribe(subscriber); try { - subscriberNode.unsubscribe( subscriber.asEntityBareJidString() ); - } - catch ( NoResponseException | XMPPErrorException e ) { - throw new AssertionError( "Unsubscribe from a node failed.", e ); + subscriberNode.unsubscribe(subscriber.asEntityBareJidString()); + } catch (NoResponseException | XMPPErrorException e) { + throw new AssertionError("Unsubscribe from a node failed.", e); } - } - finally { - pubSubManagerOne.deleteNode( nodename ); + } finally { + pubSubManagerOne.deleteNode(nodename); } } /** - * Asserts that the server returns a 'bad request' response when not - * specifying a subscription ID when unsubscribing from a node to which - * more than one subscriptions exist. - * - *

From XEP-0060 § 6.2.3.1:

- *
- * If the requesting entity has multiple subscriptions to the node but does - * not specify a subscription ID, the service MUST return a - * <bad-request/> error (...) - *
+ * Asserts that the server returns a 'bad request' response when not specifying + * a subscription ID when unsubscribing from a node to which more than one + * subscriptions exist. * - * @throws NoResponseException if there was no response from the remote entity. - * @throws XMPPErrorException if there was an XMPP error returned. - * @throws NotConnectedException if the XMPP connection is not connected. - * @throws InterruptedException if the calling thread was interrupted. - * @throws PubSubException.NotAPubSubNodeException if the node cannot be accessed. - * @throws TestNotPossibleException if the server does not support the functionality required for this test. + *

+ * From XEP-0060 § 6.2.3.1: + *

+ *
If the requesting entity has multiple subscriptions to the node + * but does not specify a subscription ID, the service MUST return a + * <bad-request/> error (...)
+ * + * @throws NoResponseException if there was no response from + * the remote entity. + * @throws XMPPErrorException if there was an XMPP error + * returned. + * @throws NotConnectedException if the XMPP connection is not + * connected. + * @throws InterruptedException if the calling thread was + * interrupted. + * @throws PubSubException.NotAPubSubNodeException if the node cannot be + * accessed. + * @throws TestNotPossibleException if the server does not + * support the functionality + * required for this test. */ @SmackIntegrationTest - public void unsubscribeNoSubscriptionIDTest() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, PubSubException.NotAPubSubNodeException, TestNotPossibleException - { - if ( !pubSubManagerOne.getSupportedFeatures().containsFeature( PubSubFeature.multi_subscribe ) ) { - throw new TestNotPossibleException( "Feature 'multi-subscribe' not supported on the server." ); + public void unsubscribeNoSubscriptionIDTest() throws NoResponseException, XMPPErrorException, NotConnectedException, + InterruptedException, PubSubException.NotAPubSubNodeException, TestNotPossibleException { + if (!pubSubManagerOne.getSupportedFeatures().containsFeature(PubSubFeature.multi_subscribe)) { + throw new TestNotPossibleException("Feature 'multi-subscribe' not supported on the server."); } final String nodename = "sinttest-unsubscribe-nodename-" + testRunId; - pubSubManagerOne.createNode( nodename ); + pubSubManagerOne.createNode(nodename); try { // Subscribe to the node twice, using different configuration final Node subscriberNode = pubSubManagerTwo.getNode(nodename); final EntityBareJid subscriber = conTwo.getUser().asEntityBareJid(); - final SubscribeForm formA = new SubscribeForm( DataForm.Type.submit ); - formA.setDigestFrequency( 1 ); - final SubscribeForm formB = new SubscribeForm( DataForm.Type.submit ); - formB.setDigestFrequency( 2 ); + final SubscribeForm formA = new SubscribeForm(DataForm.Type.submit); + formA.setDigestFrequency(1); + final SubscribeForm formB = new SubscribeForm(DataForm.Type.submit); + formB.setDigestFrequency(2); - subscriberNode.subscribe( subscriber, formA ); - subscriberNode.subscribe( subscriber, formB ); + subscriberNode.subscribe(subscriber, formA); + subscriberNode.subscribe(subscriber, formB); try { - subscriberNode.unsubscribe( subscriber.asEntityBareJidString() ); - fail( "The server should have returned a error, but did not." ); + subscriberNode.unsubscribe(subscriber.asEntityBareJidString()); + fail("The server should have returned a error, but did not."); + } catch (XMPPErrorException e) { + assertEquals(StanzaError.Condition.bad_request, e.getStanzaError().getCondition()); } - catch ( XMPPErrorException e ) { - assertEquals( StanzaError.Condition.bad_request, e.getStanzaError().getCondition() ); - } - } - finally { - pubSubManagerOne.deleteNode( nodename ); + } finally { + pubSubManagerOne.deleteNode(nodename); } } /** - * Asserts that the server returns an error response when unsubscribing from - * a node without having a subscription. + * Asserts that the server returns an error response when unsubscribing from a + * node without having a subscription. * - *

From XEP-0060 § 6.2.3.2:

- *
- * If the value of the 'jid' attribute does not specify an existing - * subscriber, the pubsub service MUST return an error stanza - *
+ *

+ * From XEP-0060 § 6.2.3.2: + *

+ *
If the value of the 'jid' attribute does not specify an existing + * subscriber, the pubsub service MUST return an error stanza
* - * @throws NoResponseException if there was no response from the remote entity. - * @throws XMPPErrorException if there was an XMPP error returned. - * @throws NotConnectedException if the XMPP connection is not connected. - * @throws InterruptedException if the calling thread was interrupted. - * @throws PubSubException.NotAPubSubNodeException if the node cannot be accessed. + * @throws NoResponseException if there was no response from + * the remote entity. + * @throws XMPPErrorException if there was an XMPP error + * returned. + * @throws NotConnectedException if the XMPP connection is not + * connected. + * @throws InterruptedException if the calling thread was + * interrupted. + * @throws PubSubException.NotAPubSubNodeException if the node cannot be + * accessed. */ @SmackIntegrationTest - public void unsubscribeNoSuchSubscriberTest() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, PubSubException.NotAPubSubNodeException - { + public void unsubscribeNoSuchSubscriberTest() throws NoResponseException, XMPPErrorException, NotConnectedException, + InterruptedException, PubSubException.NotAPubSubNodeException { final String nodename = "sinttest-unsubscribe-nodename-" + testRunId; - pubSubManagerOne.createNode( nodename ); + pubSubManagerOne.createNode(nodename); try { // Subscribe to the node twice, using different configuration - final Node subscriberNode = pubSubManagerTwo.getNode( nodename ); + final Node subscriberNode = pubSubManagerTwo.getNode(nodename); final EntityBareJid subscriber = conTwo.getUser().asEntityBareJid(); - subscriberNode.unsubscribe( subscriber.asEntityBareJidString() ); - fail( "The server should have returned an error, but did not." ); - } - catch ( XMPPErrorException e ) { + subscriberNode.unsubscribe(subscriber.asEntityBareJidString()); + fail("The server should have returned an error, but did not."); + } catch (XMPPErrorException e) { // SHOULD be (but that's not a 'MUST') - } - finally { - pubSubManagerOne.deleteNode( nodename ); + } finally { + pubSubManagerOne.deleteNode(nodename); } } @@ -634,42 +693,47 @@ public void unsubscribeNoSuchSubscriberTest() throws NoResponseException, XMPPEr * Asserts that the server returns a 'forbidden' error response when * unsubscribing a JID from a node for which the issuer has no authority. * - *

From XEP-0060 § 6.2.3.3:

- *
- * If the requesting entity is prohibited from unsubscribing the specified - * JID, the service MUST return a <forbidden/> error. + *

+ * From XEP-0060 § 6.2.3.3: + *

+ *
If the requesting entity is prohibited from unsubscribing the + * specified JID, the service MUST return a <forbidden/> error. *
* - * @throws NoResponseException if there was no response from the remote entity. - * @throws XMPPErrorException if there was an XMPP error returned. - * @throws NotConnectedException if the XMPP connection is not connected. - * @throws InterruptedException if the calling thread was interrupted. - * @throws PubSubException.NotAPubSubNodeException if the node cannot be accessed. + * @throws NoResponseException if there was no response from + * the remote entity. + * @throws XMPPErrorException if there was an XMPP error + * returned. + * @throws NotConnectedException if the XMPP connection is not + * connected. + * @throws InterruptedException if the calling thread was + * interrupted. + * @throws PubSubException.NotAPubSubNodeException if the node cannot be + * accessed. */ @SmackIntegrationTest - public void unsubscribeInsufficientPrivilegesTest() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, PubSubException.NotAPubSubNodeException - { + public void unsubscribeInsufficientPrivilegesTest() throws NoResponseException, XMPPErrorException, + NotConnectedException, InterruptedException, PubSubException.NotAPubSubNodeException { final String nodename = "sinttest-unsubscribe-nodename-" + testRunId; - final PubSubManager pubSubManagerThree = PubSubManager.getInstanceFor(conThree, PubSubManager.getPubSubService(conThree)); + final PubSubManager pubSubManagerThree = PubSubManager.getInstanceFor(conThree, + PubSubManager.getPubSubService(conThree)); pubSubManagerOne.createNode(nodename); try { // Subscribe to the node, using a different user than the owner of the node. - final Node subscriberNode = pubSubManagerTwo.getNode( nodename ); + final Node subscriberNode = pubSubManagerTwo.getNode(nodename); final EntityBareJid subscriber = conTwo.getUser().asEntityBareJid(); - subscriberNode.subscribe( subscriber ); + subscriberNode.subscribe(subscriber); - final Node unprivilegedNode = pubSubManagerThree.getNode( nodename ); + final Node unprivilegedNode = pubSubManagerThree.getNode(nodename); try { - unprivilegedNode.unsubscribe( subscriber.asEntityBareJidString() ); - fail( "The server should have returned a error, but did not." ); + unprivilegedNode.unsubscribe(subscriber.asEntityBareJidString()); + fail("The server should have returned a error, but did not."); + } catch (XMPPErrorException e) { + assertEquals(StanzaError.Condition.forbidden, e.getStanzaError().getCondition()); } - catch ( XMPPErrorException e ) { - assertEquals( StanzaError.Condition.forbidden, e.getStanzaError().getCondition() ); - } - } - finally { - pubSubManagerOne.deleteNode( nodename ); + } finally { + pubSubManagerOne.deleteNode(nodename); } } @@ -677,90 +741,100 @@ public void unsubscribeInsufficientPrivilegesTest() throws NoResponseException, * Asserts that the server returns an 'item-not-found' error response when * unsubscribing from a node that does not exist. * - *

From XEP-0060 § 6.2.3.4:

- *
- * If the node does not exist, the pubsub service MUST return an - * <item-not-found/> error. - *
+ *

+ * From XEP-0060 § 6.2.3.4: + *

+ *
If the node does not exist, the pubsub service MUST return an + * <item-not-found/> error.
* - * @throws NoResponseException if there was no response from the remote entity. - * @throws XMPPErrorException if there was an XMPP error returned. + * @throws NoResponseException if there was no response from the remote + * entity. + * @throws XMPPErrorException if there was an XMPP error returned. * @throws NotConnectedException if the XMPP connection is not connected. - * @throws InterruptedException if the calling thread was interrupted. + * @throws InterruptedException if the calling thread was interrupted. */ @SmackIntegrationTest - public void unsubscribeNodeDoesNotExistTest() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException - { + public void unsubscribeNodeDoesNotExistTest() + throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { final String nodename = "sinttest-unsubscribe-nodename-" + testRunId; try { - // Smack righteously doesn't facilitate unsubscribing from a non-existing node. Manually crafting stanza: - final UnsubscribeExtension ext = new UnsubscribeExtension( conOne.getUser().asEntityBareJid().asEntityBareJidString(), "I-dont-exist", null ); - final PubSub unsubscribe = PubSub.createPubsubPacket( pubSubManagerOne.getServiceJid(), IQ.Type.set, ext ); + // Smack righteously doesn't facilitate unsubscribing from a non-existing node. + // Manually crafting stanza: + final UnsubscribeExtension ext = new UnsubscribeExtension( + conOne.getUser().asEntityBareJid().asEntityBareJidString(), "I-dont-exist", null); + final PubSub unsubscribe = PubSub.createPubsubPacket(pubSubManagerOne.getServiceJid(), IQ.Type.set, ext); try { pubSubManagerOne.sendPubsubPacket(unsubscribe); - fail( "The server should have returned a error, but did not." ); + fail("The server should have returned a error, but did not."); + } catch (XMPPErrorException e) { + assertEquals(StanzaError.Condition.item_not_found, e.getStanzaError().getCondition()); } - catch ( XMPPErrorException e ) { - assertEquals( StanzaError.Condition.item_not_found, e.getStanzaError().getCondition() ); - } - } - finally { - pubSubManagerOne.deleteNode( nodename ); + } finally { + pubSubManagerOne.deleteNode(nodename); } } /** - * Asserts that the server returns a 'not_acceptable' response when - * specifying a non-existing subscription ID when unsubscribing from a node - * to which at least one subscription (with an ID) exists. - * - *

From XEP-0060 § 6.2.3.5:

- *
- * (...) If the subscriber originally subscribed with a SubID but the - * unsubscribe request includes a SubID that is not valid or current for the + * Asserts that the server returns a 'not_acceptable' response when specifying a + * non-existing subscription ID when unsubscribing from a node to which at least + * one subscription (with an ID) exists. + * + *

+ * From XEP-0060 § 6.2.3.5: + *

+ *
(...) If the subscriber originally subscribed with a SubID but + * the unsubscribe request includes a SubID that is not valid or current for the * subscriber, the service MUST return a <not-acceptable/> error (...) *
* - * @throws NoResponseException if there was no response from the remote entity. - * @throws XMPPErrorException if there was an XMPP error returned. - * @throws NotConnectedException if the XMPP connection is not connected. - * @throws InterruptedException if the calling thread was interrupted. - * @throws PubSubException.NotAPubSubNodeException if the node cannot be accessed. - * @throws TestNotPossibleException if the server does not support the functionality required for this test. + * @throws NoResponseException if there was no response from + * the remote entity. + * @throws XMPPErrorException if there was an XMPP error + * returned. + * @throws NotConnectedException if the XMPP connection is not + * connected. + * @throws InterruptedException if the calling thread was + * interrupted. + * @throws PubSubException.NotAPubSubNodeException if the node cannot be + * accessed. + * @throws TestNotPossibleException if the server does not + * support the functionality + * required for this test. */ @SmackIntegrationTest - public void unsubscribeBadSubscriptionIDTest() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, PubSubException.NotAPubSubNodeException, TestNotPossibleException - { - // Depending on multi-subscribe is a fail-safe way to be sure that subscription IDs will exist. - if ( !pubSubManagerOne.getSupportedFeatures().containsFeature( PubSubFeature.multi_subscribe ) ) { - throw new TestNotPossibleException( "Feature 'multi-subscribe' not supported on the server." ); + public void unsubscribeBadSubscriptionIDTest() + throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, + PubSubException.NotAPubSubNodeException, TestNotPossibleException { + // Depending on multi-subscribe is a fail-safe way to be sure that subscription + // IDs will exist. + if (!pubSubManagerOne.getSupportedFeatures().containsFeature(PubSubFeature.multi_subscribe)) { + throw new TestNotPossibleException("Feature 'multi-subscribe' not supported on the server."); } final String nodename = "sinttest-unsubscribe-nodename-" + testRunId; - pubSubManagerOne.createNode( nodename ); + pubSubManagerOne.createNode(nodename); try { // Subscribe to the node twice, using different configuration final Node subscriberNode = pubSubManagerTwo.getNode(nodename); final EntityBareJid subscriber = conTwo.getUser().asEntityBareJid(); - final SubscribeForm formA = new SubscribeForm( DataForm.Type.submit ); - formA.setDigestFrequency( 1 ); - final SubscribeForm formB = new SubscribeForm( DataForm.Type.submit ); - formB.setDigestFrequency( 2 ); + final SubscribeForm formA = new SubscribeForm(DataForm.Type.submit); + formA.setDigestFrequency(1); + final SubscribeForm formB = new SubscribeForm(DataForm.Type.submit); + formB.setDigestFrequency(2); - subscriberNode.subscribe( subscriber, formA ); - subscriberNode.subscribe( subscriber, formB ); + subscriberNode.subscribe(subscriber, formA); + subscriberNode.subscribe(subscriber, formB); try { - subscriberNode.unsubscribe( subscriber.asEntityBareJidString(), "this-is-not-an-existing-subscription-id" ); - fail( "The server should have returned a error, but did not." ); + subscriberNode.unsubscribe(subscriber.asEntityBareJidString(), + "this-is-not-an-existing-subscription-id"); + fail("The server should have returned a error, but did not."); + } catch (XMPPErrorException e) { + assertEquals(StanzaError.Condition.not_acceptable, e.getStanzaError().getCondition()); } - catch ( XMPPErrorException e ) { - assertEquals( StanzaError.Condition.not_acceptable, e.getStanzaError().getCondition() ); - } - } - finally { - pubSubManagerOne.deleteNode( nodename ); + } finally { + pubSubManagerOne.deleteNode(nodename); } } @@ -768,82 +842,86 @@ public void unsubscribeBadSubscriptionIDTest() throws NoResponseException, XMPPE * Asserts that an empty subscriptions collection is returned when an entity * requests its subscriptions from a node that it is not subscribed to. * - *

From XEP-0060 § 5.6:

- *
- * If the requesting entity has no subscriptions, the pubsub service MUST - * return an empty <subscriptions/> element. - *
+ *

+ * From XEP-0060 § 5.6: + *

+ *
If the requesting entity has no subscriptions, the pubsub + * service MUST return an empty <subscriptions/> element.
* - * @throws NoResponseException if there was no response from the remote entity. - * @throws XMPPErrorException if there was an XMPP error returned. - * @throws NotConnectedException if the XMPP connection is not connected. - * @throws InterruptedException if the calling thread was interrupted. - * @throws PubSubException.NotAPubSubNodeException if the node cannot be accessed. + * @throws NoResponseException if there was no response from + * the remote entity. + * @throws XMPPErrorException if there was an XMPP error + * returned. + * @throws NotConnectedException if the XMPP connection is not + * connected. + * @throws InterruptedException if the calling thread was + * interrupted. + * @throws PubSubException.NotAPubSubNodeException if the node cannot be + * accessed. */ @SmackIntegrationTest - public void getEmptySubscriptionsTest() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, PubSubException.NotAPubSubNodeException - { + public void getEmptySubscriptionsTest() throws NoResponseException, XMPPErrorException, NotConnectedException, + InterruptedException, PubSubException.NotAPubSubNodeException { final String nodename = "sinttest-get-empty-subscriptions-test-nodename-" + testRunId; pubSubManagerOne.createNode(nodename); try { // Assert that subscriptions for a non-subscriber is reported as an empty list. - final List subscriptions = pubSubManagerTwo.getNode( nodename ).getSubscriptions(); - assertNotNull( subscriptions ); - assertTrue( subscriptions.isEmpty() ); - } - finally { - pubSubManagerOne.deleteNode( nodename ); + final List subscriptions = pubSubManagerTwo.getNode(nodename).getSubscriptions(); + assertNotNull(subscriptions); + assertTrue(subscriptions.isEmpty()); + } finally { + pubSubManagerOne.deleteNode(nodename); } } /** * Asserts that one receives a published item, after subscribing to a node. * - * @throws NoResponseException if there was no response from the remote entity. - * @throws XMPPErrorException if there was an XMPP error returned. + * @throws NoResponseException if there was no response from the remote + * entity. + * @throws XMPPErrorException if there was an XMPP error returned. * @throws NotConnectedException if the XMPP connection is not connected. - * @throws InterruptedException if the calling thread was interrupted. - * @throws ExecutionException if waiting for the response was interrupted. - * @throws PubSubException if the involved node is not a pubsub node. + * @throws InterruptedException if the calling thread was interrupted. + * @throws ExecutionException if waiting for the response was interrupted. + * @throws PubSubException if the involved node is not a pubsub node. */ @SmackIntegrationTest - public void receivePublishedItemTest() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, ExecutionException, PubSubException - { + public void receivePublishedItemTest() throws NoResponseException, XMPPErrorException, NotConnectedException, + InterruptedException, ExecutionException, PubSubException { final String nodename = "sinttest-receive-published-item-nodename-" + testRunId; final String needle = "test content " + Math.random(); LeafNode publisherNode = pubSubManagerOne.createNode(nodename); try { final Node subscriberNode = pubSubManagerTwo.getNode(nodename); final EntityBareJid subscriber = conTwo.getUser().asEntityBareJid(); - subscriberNode.subscribe( subscriber ); + subscriberNode.subscribe(subscriber); final CompletableFuture result = new CompletableFuture<>(); - conTwo.addAsyncStanzaListener( result::complete, stanza -> stanza.toXML( "" ).toString().contains( needle ) ); + conTwo.addAsyncStanzaListener(result::complete, stanza -> stanza.toXML("").toString().contains(needle)); - publisherNode.publish( new PayloadItem<>( GeoLocation.builder().setDescription( needle ).build() ) ); + publisherNode.publish(new PayloadItem<>(GeoLocation.builder().setDescription(needle).build())); - assertNotNull( result.get( conOne.getReplyTimeout(), TimeUnit.MILLISECONDS ) ); - } - catch ( TimeoutException e ) - { + assertNotNull(result.get(conOne.getReplyTimeout(), TimeUnit.MILLISECONDS)); + } catch (TimeoutException e) { throw new AssertionError("The published item was not received by the subscriber.", e); - } - finally { - pubSubManagerOne.deleteNode( nodename ); + } finally { + pubSubManagerOne.deleteNode(nodename); } } /** - * Asserts that an event notification (publication without item) can be published to - * a node that is both 'notification-only' as well as 'transient'. + * Asserts that an event notification (publication without item) can be + * published to a node that is both 'notification-only' as well as 'transient'. * - * @throws NoResponseException if there was no response from the remote entity. - * @throws XMPPErrorException if there was an XMPP error returned. + * @throws NoResponseException if there was no response from the remote + * entity. + * @throws XMPPErrorException if there was an XMPP error returned. * @throws NotConnectedException if the XMPP connection is not connected. - * @throws InterruptedException if the calling thread was interrupted. + * @throws InterruptedException if the calling thread was interrupted. */ @SmackIntegrationTest - public void transientNotificationOnlyNodeWithoutItemTest() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { + public void transientNotificationOnlyNodeWithoutItemTest() + throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { final String nodename = "sinttest-transient-notificationonly-withoutitem-nodename-" + testRunId; ConfigureForm defaultConfiguration = pubSubManagerOne.getDefaultConfiguration(); ConfigureForm config = new ConfigureForm(defaultConfiguration.createAnswerForm()); @@ -855,32 +933,35 @@ public void transientNotificationOnlyNodeWithoutItemTest() throws NoResponseExce try { LeafNode leafNode = (LeafNode) node; leafNode.publish(); - } - finally { + } finally { pubSubManagerOne.deleteNode(nodename); } } /** - * Asserts that an error is returned when a publish request to a node that is both - * 'notification-only' as well as 'transient' contains an item element. - * - *

From XEP-0060 § 7.1.3.6:

- *
- * If the event type is notification + transient and the publisher provides an item, - * the service MUST bounce the publication request with a <bad-request/> error - * and a pubsub-specific error condition of <item-forbidden/>. - *
+ * Asserts that an error is returned when a publish request to a node that is + * both 'notification-only' as well as 'transient' contains an item element. + * + *

+ * From XEP-0060 § 7.1.3.6: + *

+ *
If the event type is notification + transient and the publisher + * provides an item, the service MUST bounce the publication request with a + * <bad-request/> error and a pubsub-specific error condition of + * <item-forbidden/>.
* - * @throws NoResponseException if there was no response from the remote entity. - * @throws XMPPErrorException if there was an XMPP error returned. + * @throws NoResponseException if there was no response from the remote + * entity. + * @throws XMPPErrorException if there was an XMPP error returned. * @throws NotConnectedException if the XMPP connection is not connected. - * @throws InterruptedException if the calling thread was interrupted. - * @see - * 7.1.3.6 Request Does Not Match Configuration + * @throws InterruptedException if the calling thread was interrupted. + * @see + * 7.1.3.6 Request Does Not Match Configuration */ @SmackIntegrationTest - public void transientNotificationOnlyNodeWithItemTest() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { + public void transientNotificationOnlyNodeWithItemTest() + throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { final String nodename = "sinttest-transient-notificationonly-withitem-nodename-" + testRunId; final String itemId = "sinttest-transient-notificationonly-withitem-itemid-" + testRunId; @@ -892,14 +973,20 @@ public void transientNotificationOnlyNodeWithItemTest() throws NoResponseExcepti config.setPersistentItems(false); Node node = pubSubManagerOne.createNode(nodename, config); - // Add a dummy payload. If there is no payload, but just an item ID, then ejabberd will *not* return an error, - // which I believe to be non-compliant behavior (although, granted, the XEP is not very clear about this). A user - // which sends an empty item with ID to an node that is configured to be notification-only and transient probably - // does something wrong, as the item's ID will never appear anywhere. Hence it would be nice if the user would be - // made aware of this issue by returning an error. Sadly ejabberd does not do so. - // See also https://github.com/processone/ejabberd/issues/2864#issuecomment-500741915 - final StandardExtensionElement dummyPayload = StandardExtensionElement.builder("dummy-payload", - SmackConfiguration.SMACK_URL_STRING).setText(testRunId).build(); + // Add a dummy payload. If there is no payload, but just an item ID, then + // ejabberd will *not* return an error, + // which I believe to be non-compliant behavior (although, granted, the XEP is + // not very clear about this). A user + // which sends an empty item with ID to an node that is configured to be + // notification-only and transient probably + // does something wrong, as the item's ID will never appear anywhere. Hence it + // would be nice if the user would be + // made aware of this issue by returning an error. Sadly ejabberd does not do + // so. + // See also + // https://github.com/processone/ejabberd/issues/2864#issuecomment-500741915 + final StandardExtensionElement dummyPayload = StandardExtensionElement + .builder("dummy-payload", SmackConfiguration.SMACK_URL_STRING).setText(testRunId).build(); try { XMPPErrorException e = assertThrows(XMPPErrorException.class, () -> { @@ -909,9 +996,9 @@ public void transientNotificationOnlyNodeWithItemTest() throws NoResponseExcepti leafNode.publish(item); }); assertEquals(StanzaError.Type.MODIFY, e.getStanzaError().getType()); - assertNotNull(e.getStanzaError().getExtension("item-forbidden", "http://jabber.org/protocol/pubsub#errors")); - } - finally { + assertNotNull( + e.getStanzaError().getExtension("item-forbidden", "http://jabber.org/protocol/pubsub#errors")); + } finally { pubSubManagerOne.deleteNode(nodename); } } @@ -935,16 +1022,61 @@ public void transientNotificationOnlyNodeWithItemTest() throws NoResponseExcepti */ @SmackIntegrationTest - public void deleteNonExistentNodeTest() throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { + public void deleteNonExistentNodeTest() + throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { final String nodename = "sinttest-delete-node-that-does-not-exist-" + testRunId; try { // Delete an non existent node pubSubManagerOne.deleteNode(nodename); fail("The server should have returned a error, but did not."); - - } - catch (XMPPErrorException e){ + + } catch (XMPPErrorException e) { assertEquals(StanzaError.Condition.item_not_found, e.getStanzaError().getCondition()); } } + + /** + * Assert that the server send a notification to subscribers when deleting a + * node that exist + * + *

+ * From XEP-0060 § 8.4.2: + *

+ *
In order to delete a node, a node owner MUST send a node + * deletion request, consisting of a <delete/> element whose 'node' + * attribute specifies the NodeID of the node to be deleted + * + * @throws NoResponseException if there was no response from + * the remote entity. + * @throws XMPPErrorException if there was an XMPP error + * returned. + * @throws NotConnectedException if the XMPP connection is not + * connected. + * @throws InterruptedException if the calling thread was + * interrupted. + * @throws PubSubException.NotAPubSubNodeException if the node cannot be + * accessed. + */ + @SmackIntegrationTest + public void deleteNodeAndNotifySubscribersTest() throws NoResponseException, XMPPErrorException, + NotConnectedException, InterruptedException, TimeoutException, ExecutionException, NotAPubSubNodeException { + final String nodename = "sinttest-delete-node-that-exist-" + testRunId; + final String needle = ""; + final String delete_confirm = ""; + final String regex = "#^." + needle + "." + delete_confirm + ".$#"; + try { + pubSubManagerOne.createNode(nodename); + final Node subscriberNode = pubSubManagerTwo.getNode(nodename); + final EntityBareJid subscriber = conTwo.getUser().asEntityBareJid(); + subscriberNode.subscribe(subscriber); + final CompletableFuture result = new CompletableFuture<>(); + conTwo.addAsyncStanzaListener(result::complete, stanza -> stanza.toXML("").toString().matches(regex)); + // Delete an existent node + pubSubManagerOne.deleteNode(nodename); + assertNotNull(result.get(conOne.getReplyTimeout(), TimeUnit.MILLISECONDS)); + } + catch (TimeoutException e) { + throw new AssertionError("The published item was not received by the subscriber.", e); + } + } }