package com.limegroup.gnutella.dht.db; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.atomic.AtomicLong; import junit.framework.Test; import org.jmock.Expectations; import org.jmock.Mockery; import org.jmock.Sequence; import org.jmock.api.Invocation; import org.jmock.lib.action.CustomAction; import org.limewire.core.settings.DHTSettings; import org.limewire.io.GUID; import org.limewire.io.IpPort; import org.limewire.io.IpPortImpl; import org.limewire.io.IpPortSet; import org.limewire.util.BaseTestCase; import com.limegroup.gnutella.PushEndpoint; import com.limegroup.gnutella.PushEndpointCache; public class PushEndpointManagerImplTest extends BaseTestCase { private Mockery context; private PushEndpointCache pushEndpointCache; private PushEndpointService pushEndpointFinder; private SearchListener<PushEndpoint> listener; private PushEndpoint result; private PushEndpointManagerImpl pushEndpointManager; public PushEndpointManagerImplTest(String name) { super(name); } public static Test suite() { return buildTestSuite(PushEndpointManagerImplTest.class); } @Override @SuppressWarnings({ "cast", "unchecked" }) protected void setUp() throws Exception { DHTSettings.ENABLE_PUSH_PROXY_QUERIES.setValue(true); context = new Mockery(); // the players pushEndpointCache = context.mock(PushEndpointCache.class); pushEndpointFinder = context.mock(PushEndpointService.class); listener = (SearchListener<PushEndpoint>)context.mock(SearchListener.class); result = context.mock(PushEndpoint.class); pushEndpointManager = new PushEndpointManagerImpl(pushEndpointCache, pushEndpointFinder); } public void testNoSearchIfPushEndpointInCache() throws Exception { final GUID guid = new GUID(); final IpPortSet proxies = new IpPortSet(new IpPortImpl("192.168.1.1:4545")); context.checking(new Expectations() {{ one(pushEndpointCache).getPushEndpoint(guid); will(returnValue(result)); one(result).getProxies(); will(returnValue(proxies)); one(listener).handleResult(result); never(pushEndpointFinder).findPushEndpoint(guid, listener); }}); pushEndpointManager.findPushEndpoint(guid, listener); context.assertIsSatisfied(); } /** * Cache is empty and two searches are started right away, second one * should fail immediately and not ask trigger a search. */ @SuppressWarnings("unchecked") public void testTimeoutBetweenSearchesIsHonored() throws Exception { final GUID guid = new GUID(); final Sequence sequence = context.sequence("sequence"); context.checking(new Expectations() {{ one(pushEndpointCache).getPushEndpoint(guid); will(returnValue(null)); inSequence(sequence); one(pushEndpointFinder).findPushEndpoint(with(same(guid)), with(any(SearchListener.class))); inSequence(sequence); one(pushEndpointCache).getPushEndpoint(guid); will(returnValue(null)); inSequence(sequence); one(listener).searchFailed(); inSequence(sequence); // zero calls to the finder here // then after the timeout: one(pushEndpointCache).getPushEndpoint(guid); will(returnValue(null)); inSequence(sequence); one(pushEndpointFinder).findPushEndpoint(with(same(guid)), with(any(SearchListener.class))); inSequence(sequence); }}); pushEndpointManager.setTimeBetweenSearches(1000L); // does search pushEndpointManager.findPushEndpoint(guid, listener); // does not search pushEndpointManager.findPushEndpoint(guid, listener); Thread.sleep(1000L); // does search again pushEndpointManager.findPushEndpoint(guid, listener); context.assertIsSatisfied(); } /** * Asserts that {@link PushEndpointManagerImpl#startSearch(org.limewire.io.GUID, SearchListener)} * starts a search and notifies the cache of results. */ @SuppressWarnings("unchecked") public void testSearchIsStartedAndCacheIsNotified() throws Exception { final GUID guid = new GUID(); final IpPort validExternalAddress = new IpPortImpl("129.1.1.1", 4545); context.checking(new Expectations() {{ one(pushEndpointFinder).findPushEndpoint(with(same(guid)), with(any(SearchListener.class))); will(new CustomAction("call listener") { public Object invoke(Invocation invocation) throws Throwable { ((SearchListener<PushEndpoint>)invocation.getParameter(1)).handleResult(result); return null; } }); one(listener).handleResult(result); one(result).updateProxies(true); one(result).getValidExternalAddress(); will(returnValue(validExternalAddress)); one(result).getClientGUID(); will(returnValue(guid.bytes())); one(pushEndpointCache).setAddr(guid.bytes(), validExternalAddress); }}); pushEndpointManager.startSearch(guid, listener); context.assertIsSatisfied(); } public void testPurge() throws Exception { PushEndpointManagerImpl pushEndpointManager = new PushEndpointManagerImpl(null, null); pushEndpointManager.setTimeBetweenSearches(100); ConcurrentMap<GUID, AtomicLong> lastSearchTimeByGUID = pushEndpointManager.getLastSearchTimeByGUID(); // add an entry that should be purged, and one that shouldn't GUID guid1 = new GUID(); GUID guid2 = new GUID(); long currentTime = System.currentTimeMillis(); lastSearchTimeByGUID.put(guid1, new AtomicLong(currentTime)); lastSearchTimeByGUID.put(guid2, new AtomicLong(currentTime + 200)); Thread.sleep(250); pushEndpointManager.purge(); assertEquals(1, lastSearchTimeByGUID.size()); assertTrue(lastSearchTimeByGUID.containsKey(guid2)); assertFalse(lastSearchTimeByGUID.containsKey(guid1)); Thread.sleep(250); pushEndpointManager.purge(); assertTrue(lastSearchTimeByGUID.isEmpty()); } }