package org.buddycloud.channelserver.packetprocessor.iq.namespace.pubsub.set; import java.util.ArrayList; import java.util.Date; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.TimeUnit; import junit.framework.Assert; import org.buddycloud.channelserver.Configuration; import org.buddycloud.channelserver.channel.ChannelManager; import org.buddycloud.channelserver.db.ClosableIteratorImpl; import org.buddycloud.channelserver.db.exception.NodeStoreException; import org.buddycloud.channelserver.packetHandler.iq.IQTestHandler; import org.buddycloud.channelserver.packetprocessor.iq.namespace.pubsub.PubSubElementProcessorAbstract; import org.buddycloud.channelserver.pubsub.affiliation.Affiliations; import org.buddycloud.channelserver.pubsub.model.NodeItem; import org.buddycloud.channelserver.pubsub.model.NodeSubscription; import org.buddycloud.channelserver.pubsub.model.impl.NodeItemImpl; import org.buddycloud.channelserver.pubsub.model.impl.NodeMembershipImpl; import org.buddycloud.channelserver.pubsub.model.impl.NodeSubscriptionImpl; import org.buddycloud.channelserver.pubsub.subscription.Subscriptions; import org.dom4j.Element; import org.dom4j.tree.BaseElement; import org.junit.Before; import org.junit.Test; import org.mockito.Mockito; import org.xmpp.packet.IQ; import org.xmpp.packet.JID; import org.xmpp.packet.Packet; import org.xmpp.packet.PacketError; import org.xmpp.resultsetmanagement.ResultSetImpl; public class ItemDeleteTest extends IQTestHandler { private IQ request; private ChannelManager channelManager; private PubSubElementProcessorAbstract itemDelete; private JID jid = new JID("juliet@shakespeare.lit"); private Element element; private BlockingQueue<Packet> queue = new LinkedBlockingQueue<Packet>(); private String node = "/user/capulet@shakespeare.lit/posts"; private String payload; @Before public void setUp() throws Exception { channelManager = Mockito.mock(ChannelManager.class); Configuration.getInstance().putProperty( Configuration.CONFIGURATION_LOCAL_DOMAIN_CHECKER, Boolean.TRUE.toString()); queue = new LinkedBlockingQueue<Packet>(); itemDelete = new ItemDelete(queue, channelManager); request = readStanzaAsIq("/iq/pubsub/item/delete/request.stanza"); element = new BaseElement("retract"); element.addAttribute("node", node); Mockito.when( channelManager.getNodeMembership(Mockito.anyString(), Mockito.any(JID.class))).thenReturn( new NodeMembershipImpl(node, jid, Subscriptions.subscribed, Affiliations.member, null)); payload = readStanzaAsString("/iq/pubsub/item/item.payload"); } @Test public void testPassingRetractAsElementNameReturnsTrue() { Element element = new BaseElement("retract"); Assert.assertTrue(itemDelete.accept(element)); } @Test public void testPassingNotRetractAsElementNameReturnsFalse() { Element element = new BaseElement("not-retract"); Assert.assertFalse(itemDelete.accept(element)); } @Test public void testPassingNoNodeResultsInErrorStanza() throws Exception { Element element = new BaseElement("retract"); itemDelete.process(element, jid, request, null); Packet response = queue.poll(100, TimeUnit.MILLISECONDS); PacketError error = response.getError(); Assert.assertNotNull(error); Assert.assertEquals(PacketError.Type.modify, error.getType()); Assert.assertEquals("nodeid-required", error.getApplicationConditionName()); } @Test public void testNodeStoreExceptionReturnsErrorStanza() throws Exception { Mockito.doThrow(new NodeStoreException()).when(channelManager) .nodeExists(node); itemDelete.process(element, jid, request, null); Packet response = queue.poll(100, TimeUnit.MILLISECONDS); PacketError error = response.getError(); Assert.assertNotNull(error); Assert.assertEquals(PacketError.Condition.internal_server_error, error.getCondition()); Assert.assertEquals(PacketError.Type.wait, error.getType()); } @Test public void testProvidingNodeWhichDoesntExistReturnsError() throws Exception { Mockito.when(channelManager.nodeExists(node)).thenReturn(false); itemDelete.setChannelManager(channelManager); itemDelete.process(element, jid, request, null); Packet response = queue.poll(100, TimeUnit.MILLISECONDS); 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 testProvidingInvalidStanzaReturnsError() throws Exception { Mockito.when(channelManager.nodeExists(node)).thenReturn(true); itemDelete.setChannelManager(channelManager); IQ request = toIq(readStanzaAsString("/iq/pubsub/item/delete/request.stanza")); request.getChildElement().element("retract").element("item").detach(); itemDelete.process(element, jid, request, null); Packet response = queue.poll(100, TimeUnit.MILLISECONDS); 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 testNotProvidingItemIdReturnsError() throws Exception { Mockito.when(channelManager.nodeExists(node)).thenReturn(true); itemDelete.setChannelManager(channelManager); IQ request = toIq(readStanzaAsString("/iq/pubsub/item/delete/request.stanza")); request.getChildElement().element("retract").element("item") .attribute("id").detach(); itemDelete.process(element, jid, request, null); Packet response = queue.poll(100, TimeUnit.MILLISECONDS); PacketError error = response.getError(); Assert.assertNotNull(error); Assert.assertEquals(PacketError.Type.modify, error.getType()); Assert.assertEquals("item-required", error.getApplicationConditionName()); } @Test public void testProvidingEmptyItemIdReturnsError() throws Exception { Mockito.when(channelManager.nodeExists(node)).thenReturn(true); itemDelete.setChannelManager(channelManager); request = toIq(readStanzaAsString( "/iq/pubsub/item/delete/request.stanza").replaceFirst( "item-id", "")); itemDelete.process(element, jid, request, null); Packet response = queue.poll(100, TimeUnit.MILLISECONDS); PacketError error = response.getError(); Assert.assertNotNull(error); Assert.assertEquals(PacketError.Type.modify, error.getType()); Assert.assertEquals("item-required", error.getApplicationConditionName()); } @Test public void itemWhichDoesntExistReturnsItemNotFoundError() throws Exception { Mockito.when(channelManager.nodeExists(node)).thenReturn(true); Mockito.when(channelManager.getNodeItem(node, "item-id")).thenReturn( null); itemDelete.setChannelManager(channelManager); itemDelete.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 testInvalidPayloadMessageReturnsErrorStanza() throws Exception { NodeItem nodeItem = new NodeItemImpl(node, "item-id", new Date(), payload.replaceFirst("<content>", ""), "12345") { }; Mockito.when(channelManager.nodeExists(node)).thenReturn(true); Mockito.when(channelManager.getNodeItem(node, "item-id")).thenReturn( nodeItem); itemDelete.setChannelManager(channelManager); itemDelete.process(element, jid, request, null); Packet response = queue.poll(100, TimeUnit.MILLISECONDS); 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 userDoesNotOwnItemCanNotDelete() throws Exception { String payload = readStanzaAsString("/iq/pubsub/item/item.payload"); NodeItem nodeItem = new NodeItemImpl(node, "item-id", new Date(), payload.replace("juliet@shakespeare.lit", "romeo@shakespeare.lit"), "12345"); Mockito.when(channelManager.nodeExists(node)).thenReturn(true); Mockito.when(channelManager.getNodeItem(node, "item-id")).thenReturn( nodeItem); itemDelete.setChannelManager(channelManager); itemDelete.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 testUserDoesNotOwnNodeCanNotDelete() throws Exception { NodeItem nodeItem = new NodeItemImpl(node, "item-id", new Date(), payload, "12345"); Mockito.when(channelManager.nodeExists(node)).thenReturn(true); Mockito.when( channelManager.getNodeItem(Mockito.anyString(), Mockito.anyString())).thenReturn(nodeItem); itemDelete.process(element, jid, request, null); Packet response = queue.poll(100, TimeUnit.MILLISECONDS); PacketError error = response.getError(); Assert.assertNotNull(error); Assert.assertEquals(PacketError.Type.auth, error.getType()); Assert.assertEquals(PacketError.Condition.forbidden, error.getCondition()); } @Test public void testSuccessfulRequestSendsResponseStanza() throws Exception { NodeItem nodeItem = new NodeItemImpl(node, "item-id", new Date(), payload.replaceAll("romeo@shakespeare.lit", "juliet@shakespeare.lit"), "12345"); Mockito.when(channelManager.nodeExists(node)).thenReturn(true); Mockito.when( channelManager.getNodeItem(Mockito.anyString(), Mockito.anyString())).thenReturn(nodeItem); itemDelete.setChannelManager(channelManager); itemDelete.process(element, jid, request, null); Mockito.verify(channelManager).deleteNodeItemById(node, "item-id"); IQ response = (IQ) queue.poll(); Assert.assertEquals(IQ.Type.result.toString(), response.getElement() .attribute("type").getValue()); // Check that no notifications are sent Packet notification = queue.poll(); Assert.assertNull(notification); } @Test public void testRequestingNotificationsSendsRetractionNotifications() throws Exception { NodeItem nodeItem = new NodeItemImpl(node, "item-id", new Date(), payload.replaceAll("romeo@shakespeare.lit", "juliet@shakespeare.lit"), "12345"); request = toIq(readStanzaAsString( "/iq/pubsub/item/delete/request.stanza").replaceFirst( "<retract", "<retract notify='true'")); ArrayList<NodeSubscription> subscriptions = new ArrayList<NodeSubscription>(); NodeSubscriptionImpl subscription1 = new NodeSubscriptionImpl(node, new JID("romeo@shakespeare.lit"), Subscriptions.pending, null); NodeSubscriptionImpl subscription2 = new NodeSubscriptionImpl(node, new JID("juliet@shakespeare.lit"), Subscriptions.subscribed, null); subscriptions.add(subscription1); subscriptions.add(subscription2); Mockito.when(channelManager.nodeExists(node)).thenReturn(true); Mockito.when(channelManager.getNodeItem(node, "item-id")).thenReturn( nodeItem); Mockito.doReturn(new ResultSetImpl<NodeSubscription>(subscriptions)) .when(channelManager).getNodeSubscriptionListeners(node); itemDelete.setChannelManager(channelManager); itemDelete.process(element, jid, request, null); Mockito.verify(channelManager).deleteNodeItemById(node, "item-id"); IQ response = (IQ) queue.poll(); Assert.assertEquals(IQ.Type.result.toString(), response.getElement() .attribute("type").getValue()); // Check that one notification is sent (on subscriber + 2 admins) Assert.assertEquals(3, queue.size()); Packet notification = queue.poll(); Assert.assertNotNull(notification); Assert.assertEquals("item-id", notification.getElement().element("event").element("items") .element("retract").attributeValue("id")); } @Test public void testNoNotifyAttributeStillSendsNotifications() throws Exception { NodeItem nodeItem = new NodeItemImpl(node, "item-id", new Date(), payload.replaceAll("romeo@shakespeare.lit", "juliet@shakespeare.lit"), "12345"); IQ request = toIq(readStanzaAsString("/iq/pubsub/item/delete/request.stanza")); request.getChildElement().element("retract").element("item") .attribute("notify").detach(); ArrayList<NodeSubscription> subscriptions = new ArrayList<NodeSubscription>(); NodeSubscriptionImpl subscription1 = new NodeSubscriptionImpl(node, new JID("romeo@shakespeare.lit"), Subscriptions.pending, null); NodeSubscriptionImpl subscription2 = new NodeSubscriptionImpl(node, new JID("juliet@shakespeare.lit"), Subscriptions.subscribed, null); subscriptions.add(subscription1); subscriptions.add(subscription2); Mockito.when(channelManager.nodeExists(node)).thenReturn(true); Mockito.when(channelManager.getNodeItem(node, "item-id")).thenReturn( nodeItem); Mockito.doReturn(new ResultSetImpl<NodeSubscription>(subscriptions)) .when(channelManager).getNodeSubscriptionListeners(node); itemDelete.setChannelManager(channelManager); itemDelete.process(element, jid, request, null); Mockito.verify(channelManager).deleteNodeItemById(node, "item-id"); // Check that one notification is sent (on subscriber + 2 admins) Assert.assertEquals(4, queue.size()); } @Test public void doesNotRequestThreadWhenDealingWithReply() throws Exception { NodeItem nodeItem = new NodeItemImpl(node, "item-id", new Date(), payload, "12345"); ArrayList<NodeSubscription> subscriptions = new ArrayList<NodeSubscription>(); NodeSubscriptionImpl subscription1 = new NodeSubscriptionImpl(node, new JID("romeo@shakespeare.lit"), Subscriptions.pending, null); subscriptions.add(subscription1); Mockito.when(channelManager.nodeExists(node)).thenReturn(true); Mockito.when(channelManager.getNodeItem(node, "item-id")).thenReturn( nodeItem); Mockito.doThrow(Exception.class) .when(channelManager) .getNodeItemReplies(Mockito.anyString(), Mockito.anyString(), Mockito.anyString(), Mockito.anyBoolean(), Mockito.anyInt()); Mockito.doReturn(new ResultSetImpl<NodeSubscription>(subscriptions)) .when(channelManager).getNodeSubscriptionListeners(node); itemDelete.setChannelManager(channelManager); itemDelete.process(element, jid, request, null); } @Test public void requestsThreadWhenDeletingParentPost() throws Exception { Mockito.when( channelManager.getNodeMembership(Mockito.anyString(), Mockito.any(JID.class))).thenReturn( new NodeMembershipImpl(node, jid, Subscriptions.subscribed, Affiliations.owner, null)); NodeItem nodeItem = new NodeItemImpl(node, "item-id", new Date(), payload); ArrayList<NodeSubscription> subscriptions = new ArrayList<NodeSubscription>(); ArrayList<NodeItem> replies = new ArrayList<NodeItem>(); replies.add(new NodeItemImpl(node, "2", new Date(), payload)); replies.add(new NodeItemImpl(node, "1", new Date(), payload)); Mockito.when(channelManager.nodeExists(node)).thenReturn(true); Mockito.when(channelManager.getNodeItem(node, "item-id")).thenReturn( nodeItem); Mockito.when(channelManager.getNodeItemReplies(Mockito.eq(node), Mockito.eq("item-id"), Mockito.anyString(), Mockito.anyBoolean(), Mockito.eq(-1))).thenReturn(new ClosableIteratorImpl<NodeItem>(replies .iterator())); Mockito.doReturn(new ResultSetImpl<NodeSubscription>(subscriptions)) .when(channelManager).getNodeSubscriptionListeners(node); itemDelete.process(element, jid, request, null); Assert.assertEquals(7, queue.size()); Assert.assertEquals(IQ.Type.result, ((IQ) queue.poll()).getType()); Packet notification = queue.poll(); Assert.assertNotNull(notification); Assert.assertEquals("message", notification.getElement().getName()); Assert.assertEquals("user1@server1", notification.getTo().toString()); Assert.assertEquals("2", notification.getElement().element("event").element("items") .element("retract").attributeValue("id")); notification = queue.poll(); Assert.assertNotNull(notification); Assert.assertEquals("2", notification.getElement().element("event").element("items") .element("retract").attributeValue("id")); notification = queue.poll(); Assert.assertNotNull(notification); Assert.assertEquals("message", notification.getElement().getName()); Assert.assertEquals("user1@server1", notification.getTo().toString()); Assert.assertEquals("1", notification.getElement().element("event").element("items") .element("retract").attributeValue("id")); notification = queue.poll(); Assert.assertNotNull(notification); Assert.assertEquals("message", notification.getElement().getName()); Assert.assertEquals("user2@server1", notification.getTo().toString()); Assert.assertEquals("1", notification.getElement().element("event").element("items") .element("retract").attributeValue("id")); /* Lastly the originally deleted post */ notification = queue.poll(); Assert.assertNotNull(notification); Assert.assertEquals("message", notification.getElement().getName()); Assert.assertEquals("user1@server1", notification.getTo().toString()); Assert.assertEquals("item-id", notification.getElement().element("event").element("items") .element("retract").attributeValue("id")); notification = queue.poll(); Assert.assertNotNull(notification); Assert.assertEquals("item-id", notification.getElement().element("event").element("items") .element("retract").attributeValue("id")); } @Test public void canDeleteItemUsingAFullItemId() throws Exception { NodeItem nodeItem = new NodeItemImpl(node, "item-id", new Date(), payload.replaceAll("romeo@shakespeare.lit", "juliet@shakespeare.lit"), "item-id"); Mockito.when(channelManager.nodeExists(node)).thenReturn(true); Mockito.when( channelManager.getNodeItem(Mockito.eq("/user/capulet@shakespeare.lit/posts"), Mockito.eq("item-id"))).thenReturn(nodeItem); IQ request = toIq(readStanzaAsString("/iq/pubsub/item/delete/request-full-id.stanza")); itemDelete.setChannelManager(channelManager); itemDelete.process(element, jid, request, null); Mockito.verify(channelManager).deleteNodeItemById(node, "item-id"); IQ response = (IQ) queue.poll(); Assert.assertEquals(IQ.Type.result.toString(), response.getElement() .attribute("type").getValue()); // Check that no notifications are sent Packet notification = queue.poll(); Assert.assertNull(notification); } }