package org.buddycloud.channelserver.packetprocessor.iq.namespace.pubsub.set; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import java.util.ArrayList; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import junit.framework.Assert; import org.buddycloud.channelserver.Configuration; import org.buddycloud.channelserver.channel.ChannelManager; import org.buddycloud.channelserver.db.exception.NodeStoreException; import org.buddycloud.channelserver.packetHandler.iq.IQTestHandler; import org.buddycloud.channelserver.packetprocessor.iq.namespace.pubsub.JabberPubsub; import org.buddycloud.channelserver.packetprocessor.iq.namespace.pubsub.PubSubElementProcessorAbstract; import org.buddycloud.channelserver.pubsub.affiliation.Affiliations; import org.buddycloud.channelserver.pubsub.model.NodeMembership; import org.buddycloud.channelserver.pubsub.model.NodeSubscription; import org.buddycloud.channelserver.pubsub.model.impl.NodeMembershipImpl; import org.buddycloud.channelserver.pubsub.subscription.NodeSubscriptionMock; import org.buddycloud.channelserver.pubsub.subscription.Subscriptions; import org.buddycloud.channelserver.utils.node.item.payload.Buddycloud; import org.dom4j.Element; import org.dom4j.tree.BaseElement; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.xmpp.packet.IQ; import org.xmpp.packet.JID; import org.xmpp.packet.Message; import org.xmpp.packet.Packet; import org.xmpp.packet.PacketError; import org.xmpp.resultsetmanagement.ResultSetImpl; public class SubscriptionEventTest extends IQTestHandler { private IQ request; private PubSubElementProcessorAbstract event; private Element element; private BlockingQueue<Packet> queue = new LinkedBlockingQueue<Packet>(); private String subscriber = "francisco@denmark.lit"; private String node = "/user/pamela@denmark.lit/posts"; private JID jid = new JID("juliet@shakespeare.lit"); private ChannelManager dataStore; @Before public void setUp() throws Exception { queue = new LinkedBlockingQueue<Packet>(); event = new SubscriptionEvent(queue, dataStore); request = readStanzaAsIq("/iq/pubsub/subscribe/authorizationPendingGrantReply.stanza"); element = new BaseElement("subscriptions"); element.addAttribute("node", node); dataStore = mock(ChannelManager.class); Configuration.getInstance().putProperty( Configuration.CONFIGURATION_LOCAL_DOMAIN_CHECKER, Boolean.TRUE.toString()); when(dataStore.nodeExists(anyString())).thenReturn(true); NodeMembership membership = new NodeMembershipImpl(node, jid, Subscriptions.subscribed, Affiliations.member, null); when(dataStore.getNodeMembership(anyString(), any(JID.class))) .thenReturn(membership); ArrayList<NodeSubscription> subscribers = new ArrayList<NodeSubscription>(); subscribers.add(new NodeSubscriptionMock(new JID( "romeo@shakespeare.lit"))); subscribers.add(new NodeSubscriptionMock(new JID( "hamlet@shakespeare.lit"))); doReturn(new ResultSetImpl<NodeSubscription>(subscribers)).when( dataStore).getNodeSubscriptionListeners(anyString()); event.setChannelManager(dataStore); } @Test public void testPassingSubscriptionsAsElementNameReturnsTrue() { Element element = new BaseElement("subscriptions"); Assert.assertTrue(event.accept(element)); } @Test public void testPassingNotSubscriptionsAsElementNameReturnsFalse() { Element element = new BaseElement("not-subscriptions"); Assert.assertFalse(event.accept(element)); } @Test public void testNotProvidingNodeAttributeReturnsErrorStanza() throws Exception { BaseElement element = new BaseElement("subscriptions"); event.process(element, jid, request, null); Packet response = queue.poll(); PacketError error = response.getError(); Assert.assertNotNull(error); Assert.assertEquals(PacketError.Type.modify, error.getType()); Assert.assertEquals("nodeid-required", error.getApplicationConditionName()); } @Test public void testNotProvidingSubscriptionChildNodeReturnsErrorStanza() throws Exception { IQ request = toIq(readStanzaAsString( "/iq/pubsub/subscribe/authorizationPendingGrantReply.stanza") .replaceFirst( "<subscription jid='francisco@denmark.lit' subscription='subscribed'/>", "")); event.process(element, jid, request, null); Packet response = queue.poll(); PacketError error = response.getError(); Assert.assertNotNull(error); Assert.assertEquals(PacketError.Type.modify, error.getType()); Assert.assertEquals(PacketError.Condition.bad_request, error.getCondition()); } @Test public void testNotProvidingJidAttributeReturnsErrorStanza() throws Exception { IQ request = toIq(readStanzaAsString( "/iq/pubsub/subscribe/authorizationPendingGrantReply.stanza") .replaceFirst("jid='francisco@denmark.lit'", "")); event.process(element, jid, request, null); Packet response = queue.poll(); PacketError error = response.getError(); Assert.assertNotNull(error); Assert.assertEquals(PacketError.Type.modify, error.getType()); Assert.assertEquals(PacketError.Condition.bad_request, error.getCondition()); } @Test public void testNotProvidingSubscriptionAttributeReturnsErrorStanza() throws Exception { IQ request = toIq(readStanzaAsString( "/iq/pubsub/subscribe/authorizationPendingGrantReply.stanza") .replaceFirst("subscription='subscribed'", "")); event.process(element, jid, request, null); Packet response = queue.poll(); PacketError error = response.getError(); Assert.assertNotNull(error); Assert.assertEquals(PacketError.Type.modify, error.getType()); Assert.assertEquals(PacketError.Condition.bad_request, error.getCondition()); } @SuppressWarnings("unchecked") @Test public void testNodeStoreExceptionResultsInInternalServerErrorStanza() throws Exception { when(dataStore.nodeExists(anyString())).thenThrow( NodeStoreException.class); event.process(element, jid, request, null); Packet response = queue.poll(); PacketError error = response.getError(); Assert.assertNotNull(error); Assert.assertEquals(PacketError.Type.wait, error.getType()); Assert.assertEquals(PacketError.Condition.internal_server_error, error.getCondition()); } @Test public void testNonExistantNodeRetunsErrorStanza() throws Exception { when(dataStore.nodeExists(node)).thenReturn(false); event.process(element, jid, request, null); Packet response = queue.poll(); PacketError error = response.getError(); Assert.assertNotNull(error); Assert.assertEquals(PacketError.Type.cancel, error.getType()); Assert.assertEquals(PacketError.Condition.item_not_found, error.getCondition()); } @Test public void userWithoutSubscriptionReturnsErrorStanza() throws Exception { when(dataStore.getNodeMembership(anyString(), any(JID.class))) .thenReturn( new NodeMembershipImpl(node, jid, Subscriptions.none, Affiliations.none, null)); event.process(element, jid, request, null); Packet response = queue.poll(); PacketError error = response.getError(); Assert.assertNotNull(error); Assert.assertEquals(PacketError.Type.auth, error.getType()); Assert.assertEquals(PacketError.Condition.forbidden, error.getCondition()); } @Test public void userWhoIsntOwnerOrModeratorCantUpdateSubscription() throws Exception { when(dataStore.getNodeMembership(anyString(), any(JID.class))) .thenReturn( new NodeMembershipImpl(node, jid, Subscriptions.subscribed, Affiliations.member, null)); event.process(element, jid, request, null); Packet response = queue.poll(); PacketError error = response.getError(); Assert.assertNotNull(error); Assert.assertEquals(PacketError.Type.auth, error.getType()); Assert.assertEquals(PacketError.Condition.forbidden, error.getCondition()); } @Test public void subscribingUserMustHaveExistingSubscriptionToUpdate() throws Exception { NodeMembership membership = new NodeMembershipImpl(node, new JID( subscriber), Subscriptions.none, Affiliations.owner, null); when(dataStore.getNodeMembership(anyString(), any(JID.class))) .thenReturn(membership); NodeMembership inviteeMemebership = new NodeMembershipImpl(node, new JID(subscriber), Subscriptions.none, Affiliations.owner, null); when(dataStore.getNodeMembership(anyString(), eq(jid))).thenReturn( inviteeMemebership); event.process(element, jid, request, null); Packet response = queue.poll(); PacketError error = response.getError(); Assert.assertNotNull(error); Assert.assertEquals(PacketError.Type.modify, error.getType()); Assert.assertEquals(PacketError.Condition.unexpected_request, error.getCondition()); } @Test public void passingInvalidSubscriptionTypeSetsSubscriptionToNone() throws Exception { IQ request = toIq(readStanzaAsString( "/iq/pubsub/subscribe/authorizationPendingGrantReply.stanza") .replaceFirst("subscription='subscribed'", "subscription='i-can-haz-all-the-items'")); ArgumentCaptor<NodeSubscription> argument = ArgumentCaptor .forClass(NodeSubscription.class); when(dataStore.getNodeMembership(anyString(), any(JID.class))) .thenReturn( new NodeMembershipImpl(node, jid, Subscriptions.subscribed, Affiliations.owner, null)); ArrayList<NodeSubscription> subscribers = new ArrayList<NodeSubscription>(); doReturn(new ResultSetImpl<NodeSubscription>(subscribers)).when( dataStore).getNodeSubscriptionListeners(anyString()); event.process(element, jid, request, null); verify(dataStore, times(1)).addUserSubscription(argument.capture()); NodeSubscription subscription = argument.getValue(); Assert.assertEquals(Subscriptions.none, subscription.getSubscription()); } @Test public void passingValidSubscriptionSendsOutExpectedNotifications() throws Exception { IQ request = toIq(readStanzaAsString( "/iq/pubsub/subscribe/authorizationPendingGrantReply.stanza") .replaceFirst("subscription='subscribed'", "subscription='subscribed'")); NodeMembership membership = new NodeMembershipImpl(node, new JID( subscriber), Subscriptions.subscribed, Affiliations.moderator, null); when(dataStore.getNodeMembership(eq(node), any(JID.class))).thenReturn( membership); event.process(element, jid, request, null); Assert.assertEquals(5, queue.size()); Packet notification = queue.poll(); Assert.assertEquals(request.getFrom().toString(), notification.getTo() .toString()); notification = queue.poll(); Assert.assertEquals("romeo@shakespeare.lit", notification.getTo() .toString()); notification = queue.poll(); Assert.assertEquals("hamlet@shakespeare.lit", notification.getTo() .toString()); notification = queue.poll(); Assert.assertEquals("user1@server1", notification.getTo().toString()); notification = queue.poll(); Assert.assertEquals("user2@server1", notification.getTo().toString()); Assert.assertEquals(node, notification.getElement().element("event") .element("subscription").attributeValue("node")); Assert.assertTrue(notification.toXML().contains( JabberPubsub.NS_PUBSUB_EVENT)); Assert.assertEquals( "subscribed", notification.getElement().element("event") .element("subscription").attributeValue("subscription")); Assert.assertEquals( subscriber, notification.getElement().element("event") .element("subscription").attributeValue("jid")); } @Test public void userCanInviteAnotherUserToNode() throws Exception { JID invitee = new JID("francisco@denmark.lit"); NodeMembership membership = new NodeMembershipImpl(node, invitee, Subscriptions.none, Affiliations.none, null); when(dataStore.getNodeMembership(eq(node), eq(invitee))).thenReturn( membership); IQ request = readStanzaAsIq("/iq/pubsub/subscribe/invite.stanza"); event.process(element, jid, request, null); IQ result = (IQ) queue.poll(); Assert.assertEquals(IQ.Type.result, result.getType()); Assert.assertEquals(5, queue.size()); Message notification = (Message) queue.poll(); Element subscription = notification.getElement().element("event") .element("subscription"); Assert.assertEquals(Subscriptions.invited, Subscriptions .valueOf(subscription.attributeValue("subscription"))); Assert.assertEquals(invitee, new JID(subscription.attributeValue("jid"))); } @Test public void userCanNotInviteAnotherUserIfTheyDontHaveValidSubscription() throws Exception { NodeMembership membership = new NodeMembershipImpl(node, jid, Subscriptions.pending, Affiliations.member, null); when(dataStore.getNodeMembership(anyString(), any(JID.class))) .thenReturn(membership); IQ request = readStanzaAsIq("/iq/pubsub/subscribe/invite.stanza"); event.process(element, jid, request, null); IQ result = (IQ) queue.poll(); Assert.assertEquals(IQ.Type.error, result.getType()); Assert.assertEquals(PacketError.Type.auth, result.getError().getType()); Assert.assertEquals(PacketError.Condition.forbidden, result.getError() .getCondition()); } @Test public void invitedByIsSetAsActorJid() throws Exception { JID invitee = new JID("francisco@denmark.lit"); NodeMembership membership = new NodeMembershipImpl(node, invitee, Subscriptions.none, Affiliations.none, null); when(dataStore.getNodeMembership(eq(node), eq(invitee))).thenReturn( membership); IQ request = readStanzaAsIq("/iq/pubsub/subscribe/invite.stanza"); event.process(element, jid, request, null); ArgumentCaptor<NodeSubscription> subscription = ArgumentCaptor .forClass(NodeSubscription.class); verify(dataStore, times(1)).addUserSubscription(subscription.capture()); Assert.assertEquals(request.getFrom().toBareJID(), subscription .getValue().getInvitedBy().toString()); Assert.assertEquals(Subscriptions.invited, subscription.getValue() .getSubscription()); Assert.assertEquals(node, subscription.getValue().getNodeId()); } @Test public void standardSubscribeDoesNotSetInvitedBy() throws Exception { NodeMembership membership = new NodeMembershipImpl(node, new JID( subscriber), Subscriptions.subscribed, Affiliations.moderator, null); when(dataStore.getNodeMembership(eq(node), any(JID.class))).thenReturn( membership); event.process(element, jid, request, null); IQ result = (IQ) queue.poll(); Assert.assertEquals(IQ.Type.result, result.getType()); ArgumentCaptor<NodeSubscription> subscription = ArgumentCaptor .forClass(NodeSubscription.class); verify(dataStore, times(1)).addUserSubscription(subscription.capture()); Assert.assertNull(subscription.getValue().getInvitedBy()); Assert.assertEquals(Subscriptions.subscribed, subscription.getValue() .getSubscription()); Assert.assertEquals(node, subscription.getValue().getNodeId()); } @Test public void sendsNotificationToInvitedUserIfTheyAreLocal() throws Exception { JID invitee = new JID("francisco@denmark.lit"); NodeMembership membership = new NodeMembershipImpl(node, invitee, Subscriptions.none, Affiliations.none, null); when(dataStore.getNodeMembership(eq(node), eq(invitee))).thenReturn( membership); IQ request = readStanzaAsIq("/iq/pubsub/subscribe/invite.stanza"); event.process(element, jid, request, null); IQ result = (IQ) queue.poll(); Assert.assertEquals(IQ.Type.result, result.getType()); Assert.assertEquals(5, queue.size()); Message notification = (Message) queue.poll(); Element subscription = notification.getElement().element("event") .element("subscription"); Assert.assertEquals(Subscriptions.invited, Subscriptions .valueOf(subscription.attributeValue("subscription"))); Assert.assertEquals(invitee, new JID(subscription.attributeValue("jid"))); queue.poll(); queue.poll(); queue.poll(); Assert.assertEquals(invitee, queue.poll().getTo()); } @Test public void sendsNotificationToInvitedUsersServerIfTheyAreNotLocal() throws Exception { JID invitee = new JID("francisco@denmark.lit"); Configuration.getInstance().remove( Configuration.CONFIGURATION_LOCAL_DOMAIN_CHECKER); Configuration.getInstance().putProperty( Configuration.CONFIGURATION_SERVER_DOMAIN, "shakespeare.lit"); NodeMembership membership = new NodeMembershipImpl(node, invitee, Subscriptions.none, Affiliations.none, null); when(dataStore.getNodeMembership(eq(node), eq(invitee))).thenReturn( membership); IQ request = readStanzaAsIq("/iq/pubsub/subscribe/invite.stanza"); element.addAttribute("node", "/user/pamela@shakespeare.lit/posts"); event.process(element, jid, request, null); IQ result = (IQ) queue.poll(); Assert.assertEquals(IQ.Type.result, result.getType()); Assert.assertEquals(5, queue.size()); Message notification = (Message) queue.poll(); Element subscription = notification.getElement().element("event") .element("subscription"); Assert.assertEquals(Subscriptions.invited, Subscriptions .valueOf(subscription.attributeValue("subscription"))); Assert.assertEquals(invitee, new JID(subscription.attributeValue("jid"))); Assert.assertEquals(jid, new JID(subscription.attributeValue("invited-by"))); queue.poll(); queue.poll(); queue.poll(); Assert.assertEquals(invitee.getDomain(), queue.poll().getTo() .toString()); } @Test public void userCanNotModifyOwnSubscription() throws Exception { IQ request = this.request.createCopy(); NodeMembership membership = new NodeMembershipImpl(node, new JID( subscriber), Subscriptions.subscribed, Affiliations.moderator, null); when(dataStore.getNodeMembership(eq(node), any(JID.class))).thenReturn( membership); event.process(element, new JID("francisco@denmark.lit"), request, null); IQ result = (IQ) queue.poll(); Assert.assertEquals(IQ.Type.error, result.getType()); PacketError error = result.getError(); Assert.assertEquals(PacketError.Type.cancel, error.getType()); Assert.assertEquals(PacketError.Condition.not_allowed, error.getCondition()); Assert.assertEquals(SubscriptionEvent.CAN_NOT_MODIFY_OWN_SUBSCRIPTION, error.getApplicationConditionName()); Assert.assertEquals(Buddycloud.NS_ERROR, error.getApplicationConditionNamespaceURI()); } }