package org.limewire.core.impl.search; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.HashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import org.jmock.Expectations; import org.jmock.Mockery; import org.jmock.lib.legacy.ClassImposteriser; import org.limewire.core.api.Category; import org.limewire.core.api.endpoint.RemoteHost; import org.limewire.core.impl.search.RemoteFileDescAdapter.AltLocRemoteHost; import org.limewire.core.impl.search.RemoteFileDescAdapter.RfdRemoteHost; import org.limewire.friend.api.Friend; import org.limewire.friend.api.FriendPresence; import org.limewire.friend.api.feature.AddressFeature; import org.limewire.io.Address; import org.limewire.io.Connectable; import org.limewire.io.ConnectableImpl; import org.limewire.io.IpPort; import org.limewire.util.BaseTestCase; import com.limegroup.gnutella.RemoteFileDesc; import com.limegroup.gnutella.URN; import com.limegroup.gnutella.xml.LimeXMLDocument; public class RemoteFileDescAdapterTest extends BaseTestCase { public RemoteFileDescAdapterTest(String name) { super(name); } /** * Tests the most basic methods of the RemoteFileDescAdapter. */ public void testBasics() throws Exception { Mockery context = new Mockery(); final RemoteFileDesc remoteFileDesc1 = context.mock(RemoteFileDesc.class); final Set<IpPort> ipPorts = new HashSet<IpPort>(); final Address address1 = context.mock(Address.class); final byte[] guid1 = new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; final String fileName1 = "remote file name 1.txt"; final long fileSize = 1234L; final URN urn1 = URN.createUrnFromString("urn:sha1:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA1"); context.checking(new Expectations() { { allowing(remoteFileDesc1).getAddress(); will(returnValue(address1)); allowing(remoteFileDesc1).getClientGUID(); will(returnValue(guid1)); allowing(address1).getAddressDescription(); will(returnValue("address 1 description")); allowing(remoteFileDesc1).getFileName(); will(returnValue(fileName1)); allowing(remoteFileDesc1).getSize(); will(returnValue(fileSize)); allowing(remoteFileDesc1).getXMLDocument(); will(returnValue(null)); allowing(remoteFileDesc1).getCreationTime(); will(returnValue(5678L)); allowing(remoteFileDesc1).getSHA1Urn(); will(returnValue(urn1)); allowing(remoteFileDesc1).isSpam(); will(returnValue(false)); } }); RemoteFileDescAdapter remoteFileDescAdapter1 = new RemoteFileDescAdapter(remoteFileDesc1, ipPorts); assertEquals(Category.DOCUMENT, remoteFileDescAdapter1.getCategory()); assertEquals("txt", remoteFileDescAdapter1.getFileExtension()); assertEquals(fileName1, remoteFileDescAdapter1.getFileName()); assertEquals(fileSize, remoteFileDescAdapter1.getSize()); assertEquals(remoteFileDesc1, remoteFileDescAdapter1.getRfd()); assertEquals(urn1, remoteFileDescAdapter1.getUrn()); assertFalse(remoteFileDescAdapter1.isLicensed()); assertFalse(remoteFileDescAdapter1.isSpam()); context.assertIsSatisfied(); } /** * Tests the getRelevance of the RemoteFileDescAdapter. */ public void testGetRelevance() throws Exception { final Mockery context = new Mockery() {{ setImposteriser(ClassImposteriser.INSTANCE); }}; // Consistency across executions assertEquals(createRFDAdapter(context, true, true, 10, true).getRelevance(), createRFDAdapter(context, true, true, 10, true).getRelevance()); // Consistency across same execution RemoteFileDescAdapter rfdAdapter = createRFDAdapter(context, true, true, 10, true); assertEquals(rfdAdapter.getRelevance(), rfdAdapter.getRelevance()); // An XMPP friend result should have greater relevance than a Gnutella one assertGreaterThan(createRFDAdapter(context, true, true, 0, true).getRelevance(), createRFDAdapter(context, false, true, 0, false).getRelevance()); assertGreaterThan(createRFDAdapter(context, true, true, 0, false).getRelevance(), createRFDAdapter(context, false, false, 0, false).getRelevance()); assertGreaterThan(createRFDAdapter(context, true, true, 1, true).getRelevance(), createRFDAdapter(context, false, false, 0, false).getRelevance()); // Altlocs increase relevance, (currently only one factored in though) assertGreaterThan(createRFDAdapter(context, false, false, 0, true).getRelevance(), createRFDAdapter(context, false, false, 1, false).getRelevance()); assertGreaterThan(createRFDAdapter(context, true, true, 0, true).getRelevance(), createRFDAdapter(context, true, true, 1, true).getRelevance()); // Browseable is better than non browsable assertGreaterThan(createRFDAdapter(context, true, false, 1, true).getRelevance(), createRFDAdapter(context, true, true, 0, true).getRelevance()); // Try with lots of altlocs, return is irrelevant. createRFDAdapter(context, true, true, 30, false).getRelevance(); // Test altlocs are not factored into calculation after some point assertEquals(createRFDAdapter(context, true, true, 100, true).getRelevance(), createRFDAdapter(context, true, true, 99, true).getRelevance()); context.assertIsSatisfied(); } private RemoteFileDescAdapter createRFDAdapter(final Mockery context, final boolean anonymous, final boolean canBrowseHost, final int altlocs, final boolean firstAltLocConnectable) { final RemoteFileDesc rfd = context.mock(RemoteFileDesc.class); final Set<IpPort> locs = new HashSet<IpPort>(); final FriendPresence friendPresence; if (anonymous) { friendPresence = null; } else { friendPresence = context.mock(FriendPresence.class); } context.checking(new Expectations() { { // Fill the locs list with alternating IpPort and Connectable instances for ( int i=0 ; i<altlocs ; i++ ) { IpPort loc; if ((i%1 == 0) == firstAltLocConnectable) { loc = context.mock(Connectable.class); } else { loc = context.mock(IpPort.class); } InetAddress addr = context.mock(InetAddress.class); allowing(loc).getInetAddress(); will(returnValue(addr)); allowing(addr).getAddress(); will(returnValue(new byte[]{24,101,1,(byte) (i % 255)})); allowing(addr).getHostAddress(); will(returnValue("24.101.1." + (i % 255))); allowing(loc); locs.add(loc); allowing(addr); } allowing(rfd).getClientGUID(); will(returnValue(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 })); if (!anonymous) { Friend friend = context.mock(Friend.class); allowing(friendPresence).getFriend(); will(returnValue(friend)); allowing(friend).isAnonymous(); will(returnValue(false)); allowing(friend); } allowing(rfd).isBrowseHostEnabled(); will(returnValue(canBrowseHost)); allowing(rfd); } }); RemoteFileDescAdapter rfdAdapter; if (!anonymous) { rfdAdapter = new RemoteFileDescAdapter(rfd, locs, friendPresence); } else { rfdAdapter = new RemoteFileDescAdapter(rfd, locs); } return rfdAdapter; } /** * Mostly internal based test for testing forward compatibility for * supporting relevances of new RemoteHost types. */ public void testGetRelevanceWithAlternateHostTypes() { final Mockery context = new Mockery() {{ setImposteriser(ClassImposteriser.INSTANCE); }}; final RemoteFileDesc rfd = context.mock(RemoteFileDesc.class); final Set<IpPort> locs = new HashSet<IpPort>(); context.checking(new Expectations() {{ allowing(rfd).getClientGUID(); will(returnValue(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 })); allowing(rfd); }}); RemoteFileDescAdapter rfdAdapter = new RemoteFileDescAdapter(rfd, locs) { @Override public List<RemoteHost> getSources() { List<RemoteHost> list = new LinkedList<RemoteHost>(); // Host without relevance list.add(context.mock(RemoteHost.class)); final RelevantRemoteHost host = context.mock(RelevantRemoteHost.class); context.checking(new Expectations() {{ allowing(host).getRelevance(); will(returnValue(99)); }}); // New host type with other relevance list.add(host); return list; } }; assertEquals(99, rfdAdapter.getRelevance()); context.assertIsSatisfied(); } /** * Tests {@link RemoteFileDescAdapter#getSources()} under various loads. */ public void testGetSources() { final Mockery context = new Mockery() {{ setImposteriser(ClassImposteriser.INSTANCE); }}; final RemoteFileDesc rfd = context.mock(RemoteFileDesc.class); final FriendPresence friendPresence = context.mock(FriendPresence.class); final Set<IpPort> locs = new HashSet<IpPort>(); final Address address = context.mock(Address.class); final Connectable connectable = context.mock(Connectable.class); final IpPort ipPort = context.mock(IpPort.class); context.checking(new Expectations() {{ allowing(rfd).getClientGUID(); will(returnValue(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 })); allowing(friendPresence).getFeature(AddressFeature.ID); will(returnValue(new AddressFeature(address))); allowing(rfd).getAddress(); will(returnValue(address)); allowing(address); allowing(rfd); allowing(connectable); allowing(ipPort).getAddress(); will(returnValue("hello")); allowing(ipPort); }}); // Make sure the sources list contains a RemoteHost for the rfd and the single altloc // ensure the address' are correctly set. Use a Connectable for the altloc. locs.add(connectable); RemoteFileDescAdapter anonRfdAdapter = new RemoteFileDescAdapter(rfd, locs); Iterable<RemoteHost> hosts1 = anonRfdAdapter.getSources(); locs.remove(connectable); boolean rfdRemoteHostFound = false; boolean altLocFound = false; for ( RemoteHost host : hosts1 ) { if (host instanceof RfdRemoteHost) { assertSame(address, host.getFriendPresence().getFeature(AddressFeature.ID).getFeature()); rfdRemoteHostFound = true; } else if (host instanceof AltLocRemoteHost) { assertSame(connectable, host.getFriendPresence().getFeature(AddressFeature.ID).getFeature()); altLocFound = true; } } assertTrue(rfdRemoteHostFound); assertTrue(altLocFound); // Make sure the sources list contains a RemoteHost for the friend and the single altloc // ensure the address' are correctly set. Use a regular IpPort instead of Connectable. locs.add(ipPort); RemoteFileDescAdapter friendRfdAdapter = new RemoteFileDescAdapter(rfd, locs, friendPresence); Iterable<RemoteHost> hosts2 = friendRfdAdapter.getSources(); locs.remove(ipPort); rfdRemoteHostFound = false; altLocFound = false; for ( RemoteHost host : hosts2 ) { if (host instanceof RfdRemoteHost) { assertSame(address, host.getFriendPresence().getFeature(AddressFeature.ID).getFeature()); rfdRemoteHostFound = true; } else if (host instanceof AltLocRemoteHost) { Connectable addressCollected = (Connectable) host.getFriendPresence().getFeature(AddressFeature.ID).getFeature(); assertSame("hello", addressCollected.getAddress()); altLocFound = true; } } assertTrue(rfdRemoteHostFound); assertTrue(altLocFound); // Test duplicate getSources() call, ensure they are the same Iterable<RemoteHost> hosts2repeat = friendRfdAdapter.getSources(); rfdRemoteHostFound = false; altLocFound = false; for ( RemoteHost host : hosts2repeat ) { if (host instanceof RfdRemoteHost) { assertSame(address, host.getFriendPresence().getFeature(AddressFeature.ID).getFeature()); rfdRemoteHostFound = true; } else if (host instanceof AltLocRemoteHost) { Connectable addressCollected = (Connectable) host.getFriendPresence().getFeature(AddressFeature.ID).getFeature(); assertSame("hello", addressCollected.getAddress()); altLocFound = true; } } assertTrue(rfdRemoteHostFound); assertTrue(altLocFound); context.assertIsSatisfied(); } /** * Tests that the altlocs are preserved through construction. */ public void testGetAltLocs() { Mockery context = new Mockery() {{ setImposteriser(ClassImposteriser.INSTANCE); }}; RemoteFileDescAdapter rfdAdapter = createRFDAdapter(context, true, true, 16, true); List<IpPort> alts = rfdAdapter.getAlts(); assertEquals(16, alts.size()); } /** * Ensures the extension and the filename are properly retrieved from * the rfd. */ public void testGetFileNameInfo() { final Mockery context = new Mockery(); final RemoteFileDesc rfd = context.mock(RemoteFileDesc.class); final Set<IpPort> locs = new HashSet<IpPort>(); context.checking(new Expectations() {{ allowing(rfd).getClientGUID(); will(returnValue(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 })); allowing(rfd).getFileName(); will(returnValue("Giant Guitar.JPG")); allowing(rfd); }}); RemoteFileDescAdapter rfdAdapter = new RemoteFileDescAdapter(rfd, locs); assertEquals("JPG", rfdAdapter.getFileExtension()); assertEquals("Giant Guitar.JPG", rfdAdapter.getFileName()); assertEquals(Category.IMAGE, rfdAdapter.getCategory()); context.assertIsSatisfied(); } /** * Tests {@link RemoteFileDescAdapter#isLicensed()} under various conditions. */ public void testIsLicensed() { final Mockery context = new Mockery() {{ setImposteriser(ClassImposteriser.INSTANCE); }}; final RemoteFileDesc rfdWithNull1 = context.mock(RemoteFileDesc.class); final RemoteFileDesc rfdWithNull2 = context.mock(RemoteFileDesc.class); final RemoteFileDesc rfdGood = context.mock(RemoteFileDesc.class); final Set<IpPort> locs = new HashSet<IpPort>(); context.checking(new Expectations() {{ allowing(rfdWithNull1).getClientGUID(); will(returnValue(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 })); allowing(rfdWithNull2).getClientGUID(); will(returnValue(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 })); allowing(rfdGood).getClientGUID(); will(returnValue(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 })); allowing(rfdWithNull1).getXMLDocument(); will(returnValue(null)); LimeXMLDocument document = context.mock(LimeXMLDocument.class); allowing(rfdWithNull2).getXMLDocument(); will(returnValue(document)); allowing(document).getLicenseString(); will(returnValue(null)); LimeXMLDocument document2 = context.mock(LimeXMLDocument.class); allowing(rfdGood).getXMLDocument(); will(returnValue(document2)); allowing(document2).getLicenseString(); will(returnValue("GPL")); allowing(rfdWithNull1); allowing(rfdWithNull2); allowing(rfdGood); }}); RemoteFileDescAdapter rfdAdapterWithNull1 = new RemoteFileDescAdapter(rfdWithNull1, locs); assertFalse(rfdAdapterWithNull1.isLicensed()); RemoteFileDescAdapter rfdAdapterWithNull2 = new RemoteFileDescAdapter(rfdWithNull2, locs); assertFalse(rfdAdapterWithNull2.isLicensed()); RemoteFileDescAdapter rfdAdapterGood = new RemoteFileDescAdapter(rfdGood, locs); assertTrue(rfdAdapterGood.isLicensed()); context.assertIsSatisfied(); } /** * Tests a few of the methods that delegate to the rfd and ensure they pass on the correct * values. */ public void testRfdDelegates() { Mockery context = new Mockery(); final RemoteFileDesc rfd = context.mock(RemoteFileDesc.class); final Set<IpPort> locs = new HashSet<IpPort>(); context.checking(new Expectations() {{ allowing(rfd).getClientGUID(); will(returnValue(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 })); allowing(rfd).getSize(); will(returnValue(Long.MAX_VALUE-3)); one(rfd).isSpam(); will(returnValue(true)); one(rfd).isSpam(); will(returnValue(false)); allowing(rfd); }}); RemoteFileDescAdapter rfdAdapter = new RemoteFileDescAdapter(rfd, locs); assertSame(rfd, rfdAdapter.getRfd()); assertEquals(Long.MAX_VALUE-3, rfdAdapter.getSize()); assertTrue(rfdAdapter.isSpam()); assertFalse(rfdAdapter.isSpam()); context.assertIsSatisfied(); } /** * Tests {@link RemoteFileDescAdapter#getUrn()} and ensures it passes on the URN included with the RFD. */ public void testGetUrn() throws IOException { Mockery context = new Mockery(); final RemoteFileDesc rfd = context.mock(RemoteFileDesc.class); final Set<IpPort> locs = new HashSet<IpPort>(); final URN urn = URN.createSHA1Urn("urn:sha1:XXSTHIPQGSSZTS5FJUPAKPZWUGYQYPFB"); context.checking(new Expectations() {{ allowing(rfd).getClientGUID(); will(returnValue(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 })); allowing(rfd).getSHA1Urn(); will(returnValue(urn)); allowing(rfd); }}); RemoteFileDescAdapter rfdAdapter = new RemoteFileDescAdapter(rfd, locs); assertEquals(urn, rfdAdapter.getUrn()); context.assertIsSatisfied(); } /** * Tests {@link RemoteFileDescAdapter#getUrn()} and ensures it passes on the URN included with the RFD. * @throws IOException */ public void testGetMagnetUrl() { Mockery context = new Mockery(); final RemoteFileDesc rfd = context.mock(RemoteFileDesc.class); final Set<IpPort> locs = new HashSet<IpPort>(); context.checking(new Expectations() {{ allowing(rfd).getClientGUID(); will(returnValue(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 })); allowing(rfd); }}); RemoteFileDescAdapter rfdAdapter = new RemoteFileDescAdapter(rfd, locs); assertNotNull(rfdAdapter.getMagnetURL()); assertGreaterThan(0, rfdAdapter.getMagnetURL().length()); assertTrue(rfdAdapter.getMagnetURL().startsWith("magnet")); context.assertIsSatisfied(); } public void testToString() { Mockery context = new Mockery(); final RemoteFileDesc rfd = context.mock(RemoteFileDesc.class); final Set<IpPort> locs = new HashSet<IpPort>(); context.checking(new Expectations() {{ allowing(rfd).getClientGUID(); will(returnValue(new byte[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 })); allowing(rfd); }}); RemoteFileDescAdapter rfdAdapter1 = new RemoteFileDescAdapter(rfd, locs); assertNotNull(rfdAdapter1.toString()); } /** * Tests the functionality of {@link RfdRemoteHost}. */ public void testRfdRemoteHost() { final Mockery context = new Mockery(); final RemoteFileDesc rfd = context.mock(RemoteFileDesc.class); final FriendPresence friendPresence = context.mock(FriendPresence.class); final Friend friend = context.mock(Friend.class); context.checking(new Expectations() {{ exactly(3).of(friendPresence).getFriend(); will(returnValue(friend)); exactly(3).of(friend).isAnonymous(); will(returnValue(true)); exactly(1).of(rfd).isBrowseHostEnabled(); will(returnValue(true)); allowing(rfd); }}); RemoteHost remoteHost = new RfdRemoteHost(friendPresence, rfd); assertSame(friendPresence, remoteHost.getFriendPresence()); assertTrue(remoteHost.isBrowseHostEnabled()); assertFalse(remoteHost.isChatEnabled()); assertFalse(remoteHost.isSharingEnabled()); context.assertIsSatisfied(); } /** * Tests the class {@link AltLocRemoteHost} and ensures it can be constructed, * accessed, and that the returns are sane. */ public void testAltLocRemoteHost() throws UnknownHostException { IpPort ipPort = new ConnectableImpl("akzp.com", 55, false); RemoteHost remoteHost = new AltLocRemoteHost(ipPort); // The outcome of these functions is never determinate for an AltLoc // so it is a matter of app behaviour preference what they return // therefore ignore the result but make sure they do not cause // exceptions. remoteHost.isBrowseHostEnabled(); remoteHost.isChatEnabled(); remoteHost.isSharingEnabled(); assertNotNull(remoteHost.getFriendPresence()); assertEquals(55, ((Connectable)remoteHost.getFriendPresence().getFeature(AddressFeature.ID).getFeature()).getPort()); } }