/** * * Copyright © 2015 Tomáš Havlas * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jivesoftware.smack.roster; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import org.jivesoftware.smack.DummyConnection; import org.jivesoftware.smack.SmackException.FeatureNotSupportedException; import org.jivesoftware.smack.im.InitSmackIm; import org.jivesoftware.smack.packet.IQ; import org.jivesoftware.smack.packet.IQ.Type; import org.jivesoftware.smack.packet.Presence; import org.jivesoftware.smack.packet.Stanza; import org.jivesoftware.smack.roster.RosterTest.TestRosterListener; import org.jivesoftware.smack.roster.packet.RosterPacket; import org.jivesoftware.smack.roster.packet.RosterPacket.Item; import org.jivesoftware.smack.roster.packet.RosterPacket.ItemType; import org.jivesoftware.smack.roster.packet.SubscriptionPreApproval; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.jxmpp.jid.BareJid; import org.jxmpp.jid.Jid; import org.jxmpp.jid.impl.JidCreate; /** * Tests that verifies the correct behavior of the pre-approval implementation. * * @see Pre-Approving a Subscription Request * @author Tomáš Havlas */ public class SubscriptionPreApprovalTest extends InitSmackIm { private DummyConnection connection; private Roster roster; private TestRosterListener rosterListener; @Before public void setUp() throws Exception { connection = new DummyConnection(); connection.connect(); connection.login(); rosterListener = new TestRosterListener(); roster = Roster.getInstanceFor(connection); roster.addRosterListener(rosterListener); connection.setReplyTimeout(1000 * 60 * 5); } @After public void tearDown() throws Exception { connection.disconnect(); connection = null; } @Test(expected = FeatureNotSupportedException.class) public void testPreApprovalNotSupported() throws Throwable { final Jid contactJID = JidCreate.from("preapproval@example.com"); roster.preApprove(contactJID.asBareJid()); } @Test public void testPreApproveAndCreate() throws Throwable { final BareJid contactJID = JidCreate.bareFrom("preapproval@example.com"); final String contactName = "PreApproval"; final String[] contactGroup = {}; connection.enableStreamFeature(SubscriptionPreApproval.INSTANCE); final PreApproveAndCreateEntryResponder serverSimulator = new PreApproveAndCreateEntryResponder() { @Override void verifyRosterUpdateRequest(final RosterPacket updateRequest) { final Item item = updateRequest.getRosterItems().iterator().next(); assertSame("The provided JID doesn't match the requested!", contactJID, item.getJid()); assertSame("The provided name doesn't match the requested!", contactName, item.getName()); assertSame("The provided group number doesn't match the requested!", 0, item.getGroupNames().size()); } @Override void verifyPreApprovalRequest(Presence preApproval) { assertSame("The provided name doesn't match the requested!", contactJID, preApproval.getTo()); assertSame("The provided presence type is incorrect!", Presence.Type.subscribed, preApproval.getType()); } }; serverSimulator.start(); roster.preApproveAndCreateEntry(contactJID, contactName, contactGroup); serverSimulator.join(); // Check if an error occurred within the simulator final Throwable exception = serverSimulator.getException(); if (exception != null) { throw exception; } rosterListener.waitUntilInvocationOrTimeout(); // Verify the roster entry of the new contact final RosterEntry addedEntry = roster.getEntry(contactJID); assertNotNull("The new contact wasn't added to the roster!", addedEntry); assertTrue("The roster listener wasn't invoked for the new contact!", rosterListener.getAddedAddresses().contains(contactJID)); assertSame("Setup wrong name for the new contact!", contactName, addedEntry.getName()); assertSame("Setup wrong default subscription status!", ItemType.none, addedEntry.getType()); assertSame("The new contact should be member of exactly one group!", 0, addedEntry.getGroups().size()); } /** * This class can be used to simulate the server response for * a pre approve request request. */ private abstract class PreApproveAndCreateEntryResponder extends Thread { private Throwable exception = null; /** * Overwrite this method to check if the received roster update request is valid. * * @param updateRequest the request which would be sent to the server. */ abstract void verifyRosterUpdateRequest(RosterPacket updateRequest); /** * Overwrite this method to check if received pre-approval request is valid * * @param preApproval the request which would be sent to server. */ abstract void verifyPreApprovalRequest(Presence preApproval); @Override public void run() { try { while (true) { final Stanza packet = connection.getSentPacket(); if (packet instanceof RosterPacket && ((IQ) packet).getType() == Type.set) { final RosterPacket rosterRequest = (RosterPacket) packet; // Prepare and process the roster push final RosterPacket rosterPush = new RosterPacket(); final Item item = rosterRequest.getRosterItems().iterator().next(); if (item.getItemType() != ItemType.remove) { item.setItemType(ItemType.none); } rosterPush.setType(Type.set); rosterPush.setTo(connection.getUser()); rosterPush.addRosterItem(item); connection.processStanza(rosterPush); // Create and process the IQ response final IQ response = IQ.createResultIQ(rosterRequest); connection.processStanza(response); // Verify the roster update request if (rosterRequest.getRosterItemCount() != 1) { throw new AssertionError("A roster set MUST contain one and only one element."); } verifyRosterUpdateRequest(rosterRequest); break; } else if (packet instanceof Presence && ((Presence) packet).getType() == Presence.Type.subscribed) { final Presence approval = (Presence) packet; verifyPreApprovalRequest(approval); } } } catch (Throwable e) { exception = e; fail(e.getMessage()); } } /** * Returns the exception or error if something went wrong. * * @return the Throwable exception or error that occurred. */ public Throwable getException() { return exception; } } }