package org.limewire.friend.impl.address; import java.io.IOException; import java.util.Collections; import org.jmock.Expectations; import org.jmock.Mockery; import org.jmock.api.Invocation; import org.jmock.lib.action.CustomAction; import org.limewire.friend.api.Friend; import org.limewire.friend.api.FriendConnection; import org.limewire.friend.api.FriendConnectionEvent; import org.limewire.friend.api.FriendPresence; import org.limewire.friend.api.feature.AuthTokenFeature; import org.limewire.friend.api.feature.ConnectBackRequestFeature; import org.limewire.friend.impl.feature.AuthTokenImpl; import org.limewire.io.Address; import org.limewire.io.Connectable; import org.limewire.io.ConnectableImpl; import org.limewire.io.GUID; import org.limewire.listener.CachingEventMulticaster; import org.limewire.listener.CachingEventMulticasterImpl; import org.limewire.net.SocketsManager; import org.limewire.net.address.AddressResolutionObserver; import org.limewire.net.address.BlockingAddressResolutionObserver; import org.limewire.net.address.FirewalledAddress; import org.limewire.util.BaseTestCase; public class FriendAddressResolverTest extends BaseTestCase { private Mockery context; private FriendConnection connection; private SocketsManager socketsManager; private FriendAddressRegistry addressRegistry; private Friend user; private FriendPresence friendPresence; private FriendAddressResolver friendAddressResolver; public FriendAddressResolverTest(String name) { super(name); } @Override protected void setUp() throws Exception { context = new Mockery(); connection = context.mock(FriendConnection.class); socketsManager = context.mock(SocketsManager.class); addressRegistry = new FriendAddressRegistry(); user = context.mock(Friend.class); friendPresence = context.mock(FriendPresence.class); context.checking(new Expectations() {{ allowing(connection).getFriend("me@you.com"); will(returnValue(user)); allowing(connection).getFriend(with(any(String.class))); will(returnValue(null)); allowing(connection).isLoggedIn(); will(returnValue(true)); allowing(connection).isLoggingIn(); will(returnValue(false)); allowing(user).getPresences(); will(returnValue(Collections.singletonMap("me@you.com/resource", friendPresence))); allowing(friendPresence).getFeature(AuthTokenFeature.ID); will(returnValue(new AuthTokenFeature(new AuthTokenImpl(new byte[0])))); }}); CachingEventMulticaster<FriendConnectionEvent> multicaster = new CachingEventMulticasterImpl<FriendConnectionEvent>(); multicaster.broadcast(new FriendConnectionEvent(connection, FriendConnectionEvent.Type.CONNECTED)); friendAddressResolver = new FriendAddressResolver(multicaster, null, socketsManager, addressRegistry); } public void testSuccessfulGetPresence() { addressRegistry.put(new FriendAddress("me@you.com/resource"), ConnectableImpl.INVALID_CONNECTABLE); // with exact same resource id FriendPresence presence = friendAddressResolver.getPresence(new FriendAddress("me@you.com/resource")); assertNotNull(presence); // different, but matching resource id presence = friendAddressResolver.getPresence(new FriendAddress("me@you.com/resource12345")); assertNotNull(presence); } public void testFailedGetPresence() { FriendPresence presence = friendAddressResolver.getPresence(new FriendAddress("me@you.com/resource")); assertNull(presence); addressRegistry.put(new FriendAddress("me@you.com/resource"), ConnectableImpl.INVALID_CONNECTABLE); presence = friendAddressResolver.getPresence(new FriendAddress("me@you.com/differentresource")); assertNull(presence); } public void testCanResolveHasPresence() { addressRegistry.put(new FriendAddress("me@you.com/resource"), ConnectableImpl.INVALID_CONNECTABLE); // exact id assertTrue(friendAddressResolver.canResolve(new FriendAddress("me@you.com/resource"))); // different, but matching resource id assertTrue(friendAddressResolver.canResolve(new FriendAddress("me@you.com/resource1234"))); } public void testCanResolveNoPresence() { assertFalse(friendAddressResolver.canResolve(new FriendAddress("me@you.com/resource"))); } public void testCanResolveWrongAddressType() { assertFalse(friendAddressResolver.canResolve(ConnectableImpl.INVALID_CONNECTABLE)); } public void testResolveNoPresence() { try { friendAddressResolver.resolve(new FriendAddress("hello@world/ivef"), new BlockingAddressResolutionObserver()).getAddress(); fail("io exception for failed resolution expected"); } catch (IOException ie) { } } public void testResolveNoAddressForPresence() { try { friendAddressResolver.resolve(new FriendAddress("me@you.com/resource"), new BlockingAddressResolutionObserver()).getAddress(); fail("io exception for failed resolution expected"); } catch (IOException ie) { } } public void testResolveFirewalledAddressReturnsXMPPFirewalledAddress() throws Exception { final FirewalledAddress firewalledAddress = new FirewalledAddress(ConnectableImpl.INVALID_CONNECTABLE, ConnectableImpl.INVALID_CONNECTABLE, new GUID(), Connectable.EMPTY_SET, 0); addressRegistry.put(new FriendAddress("me@you.com/resource"), firewalledAddress); context.checking(new Expectations() {{ one(socketsManager).canResolve(firewalledAddress); // return false so xmpp firewalled address can be constructed will(returnValue(false)); // advertise connect back feature one(friendPresence).hasFeatures(ConnectBackRequestFeature.ID); will(returnValue(true)); }}); Address address = friendAddressResolver.resolve(new FriendAddress("me@you.com/resource"), new BlockingAddressResolutionObserver()).getAddress(); assertInstanceof(FriendFirewalledAddress.class, address); FriendFirewalledAddress xmppfiFirewalledAddress = (FriendFirewalledAddress)address; assertSame(firewalledAddress, xmppfiFirewalledAddress.getFirewalledAddress()); assertEquals(new FriendAddress("me@you.com/resource"), xmppfiFirewalledAddress.getFriendAddress()); context.assertIsSatisfied(); } public void testResolveFirewalledAddressCheckesSocketsManagerForSameNatAndResolves() throws Exception { final FirewalledAddress firewalledAddress = new FirewalledAddress(ConnectableImpl.INVALID_CONNECTABLE, ConnectableImpl.INVALID_CONNECTABLE, new GUID(), Connectable.EMPTY_SET, 0); final BlockingAddressResolutionObserver observer = new BlockingAddressResolutionObserver(); addressRegistry.put(new FriendAddress("me@you.com/resource"), firewalledAddress); context.checking(new Expectations() {{ one(socketsManager).canResolve(firewalledAddress); // return false so xmpp firewalled address can be constructed will(returnValue(true)); one(socketsManager).resolve(firewalledAddress, observer); will(new CustomAction("call observer") { @Override public Object invoke(Invocation invocation) throws Throwable { ((AddressResolutionObserver)invocation.getParameter(1)).resolved(ConnectableImpl.INVALID_CONNECTABLE); return null; } }); }}); Address address = friendAddressResolver.resolve(new FriendAddress("me@you.com/resource"), observer).getAddress(); assertInstanceof(Connectable.class, address); assertSame(ConnectableImpl.INVALID_CONNECTABLE, address); context.assertIsSatisfied(); } public void testResolveFirewalledAddressAsIs() throws Exception { final FirewalledAddress firewalledAddress = new FirewalledAddress(ConnectableImpl.INVALID_CONNECTABLE, ConnectableImpl.INVALID_CONNECTABLE, new GUID(), Connectable.EMPTY_SET, 0); addressRegistry.put(new FriendAddress("me@you.com/resource"), firewalledAddress); context.checking(new Expectations() {{ one(socketsManager).canResolve(firewalledAddress); // return false so xmpp firewalled address can be constructed will(returnValue(false)); // don't connect back feature, to get standard firewalled address one(friendPresence).hasFeatures(ConnectBackRequestFeature.ID); will(returnValue(false)); }}); Address address = friendAddressResolver.resolve(new FriendAddress("me@you.com/resource"), new BlockingAddressResolutionObserver()).getAddress(); assertInstanceof(FirewalledAddress.class, address); assertSame(firewalledAddress, address); context.assertIsSatisfied(); } public void testResolveConnectable() throws Exception { addressRegistry.put(new FriendAddress("me@you.com/resource"), ConnectableImpl.INVALID_CONNECTABLE); context.checking(new Expectations() {{ never(socketsManager).canResolve(ConnectableImpl.INVALID_CONNECTABLE); // don't connect back feature, to get standard firewalled address never(friendPresence).hasFeatures(ConnectBackRequestFeature.ID); }}); Address address = friendAddressResolver.resolve(new FriendAddress("me@you.com/resource"), new BlockingAddressResolutionObserver()).getAddress(); assertInstanceof(Connectable.class, address); assertSame(ConnectableImpl.INVALID_CONNECTABLE, address); context.assertIsSatisfied(); } }