package com.limegroup.gnutella.version; import java.io.ByteArrayInputStream; import java.io.File; import java.util.Arrays; import java.util.List; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicReference; import junit.framework.Test; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; import org.apache.http.client.methods.HttpGet; import org.apache.http.params.HttpConnectionParams; import org.apache.http.params.HttpParams; import org.hamcrest.Description; import org.hamcrest.TypeSafeMatcher; import org.jmock.Expectations; import org.jmock.Mockery; import org.jmock.Sequence; import org.limewire.core.settings.UpdateSettings; import org.limewire.gnutella.tests.LimeTestCase; import org.limewire.gnutella.tests.LimeTestUtils; import org.limewire.security.SettingsProvider; import org.limewire.util.Clock; import org.limewire.util.CommonUtils; import com.google.inject.AbstractModule; import com.google.inject.Injector; import com.google.inject.name.Names; import com.limegroup.gnutella.ActivityCallback; import com.limegroup.gnutella.ApplicationServices; import com.limegroup.gnutella.ClockStub; import com.limegroup.gnutella.ConnectionManager; import com.limegroup.gnutella.DownloadManager; import com.limegroup.gnutella.NetworkUpdateSanityChecker; import com.limegroup.gnutella.ReplyHandler; import com.limegroup.gnutella.NetworkUpdateSanityChecker.RequestType; import com.limegroup.gnutella.http.HttpClientListener; import com.limegroup.gnutella.http.HttpExecutor; import com.limegroup.gnutella.messages.vendor.CapabilitiesVMFactory; import com.limegroup.gnutella.stubs.ScheduledExecutorServiceStub; import com.limegroup.gnutella.version.UpdateHandlerImpl.UpdateType; public class UpdateHandlerTest extends LimeTestCase { public UpdateHandlerTest(String name) { super(name); } public static Test suite() { return buildTestSuite(UpdateHandlerTest.class); } private Injector injector; private Mockery mockery; private ImmediateExecutor backgroundExecutor; private ActivityCallback activityCallback; private HttpExecutor httpExecutor; private CapabilitiesVMFactory capabilitiesVmFactory; private ConnectionManager connectionManager; private ApplicationServices applicationServices; private UpdateCollectionFactory updateCollectionFactory; private ClockStub clock; private DownloadManager downloadManager; private SettingsProvider settingsProvider; private UpdateMessageVerifier updateMessageVerifier; private NetworkUpdateSanityChecker networkUpdateSanityChecker; private byte[] guid; private File saveFile; @Override public void setUp() { mockery = new Mockery(); activityCallback = mockery.mock(ActivityCallback.class); httpExecutor = mockery.mock(HttpExecutor.class); capabilitiesVmFactory = mockery.mock(CapabilitiesVMFactory.class); connectionManager = mockery.mock(ConnectionManager.class); applicationServices = mockery.mock(ApplicationServices.class); updateCollectionFactory = mockery.mock(UpdateCollectionFactory.class); downloadManager = mockery.mock(DownloadManager.class); backgroundExecutor = new ImmediateExecutor(); updateMessageVerifier = mockery.mock(UpdateMessageVerifier.class); networkUpdateSanityChecker = mockery.mock(NetworkUpdateSanityChecker.class); guid = new byte[16]; clock = new ClockStub(); settingsProvider = new SettingsProvider() { public long getChangePeriod() { return Long.MAX_VALUE; } public long getGracePeriod() { return Long.MAX_VALUE - 1; } }; injector = LimeTestUtils.createInjectorNonEagerly(new AbstractModule() { @Override public void configure() { bind(ScheduledExecutorService.class).annotatedWith( Names.named("backgroundExecutor")).toInstance(backgroundExecutor); bind(ActivityCallback.class).toInstance(activityCallback); bind(HttpExecutor.class).toInstance(httpExecutor); bind(CapabilitiesVMFactory.class).toInstance(capabilitiesVmFactory); bind(ConnectionManager.class).toInstance(connectionManager); bind(ApplicationServices.class).toInstance(applicationServices); bind(UpdateCollectionFactory.class).toInstance(updateCollectionFactory); bind(Clock.class).toInstance(clock); bind(DownloadManager.class).toInstance(downloadManager); bind(SettingsProvider.class).toInstance(settingsProvider); bind(UpdateMessageVerifier.class).toInstance(updateMessageVerifier); bind(NetworkUpdateSanityChecker.class).toInstance(networkUpdateSanityChecker); } }); saveFile = new File(CommonUtils.getUserSettingsDir(), "version.xml"); saveFile.delete(); assertFalse(saveFile.exists()); } /** tests that we set up bindings correctly */ public void testBindings() throws Exception { mockery.checking(new Expectations() { { ignoring(activityCallback); ignoring(httpExecutor); ignoring(capabilitiesVmFactory); ignoring(connectionManager); ignoring(applicationServices); ignoring(updateCollectionFactory); ignoring(downloadManager); } }); UpdateHandlerImpl updateHandler = (UpdateHandlerImpl) injector .getInstance(UpdateHandler.class); assertEquals("http://update0.limewire.com/v2/update.def", updateHandler.getTimeoutUrl()); List<String> maxUrls = updateHandler.getMaxUrls(); for (int i = 0; i < 10; i++) assertEquals("http://update" + (i + 1) + ".limewire.com/v2/update.def", maxUrls.get(i)); assertEquals(10, maxUrls.size()); } public void testMaxTriggersHttpAfterSmallDelay() { final AtomicReference<HttpClientListener> httpClientListenerRef = new AtomicReference<HttpClientListener>(); final UpdateCollection updateCollection = mockery.mock(UpdateCollection.class); final HttpGet method = new HttpGet(); final HttpResponse response = mockery.mock(HttpResponse.class); final StatusLine statusLine = mockery.mock(StatusLine.class); final Sequence requestSequence = mockery.sequence("Request Sequence"); mockery.checking(new Expectations() { { one(updateMessageVerifier).getVerifiedData(new byte[0]); will(returnValue("asdf\n")); inSequence(requestSequence); one(updateCollectionFactory).createUpdateCollection("asdf\n"); will(returnValue(updateCollection)); inSequence(requestSequence); atLeast(1).of(updateCollection).getId(); will(returnValue(UpdateHandlerImpl.IGNORE_ID)); inSequence(requestSequence); allowing(applicationServices).getMyGUID(); will(returnValue(guid)); inSequence(requestSequence); } }); UpdateHandlerImpl h = (UpdateHandlerImpl) injector.getInstance(UpdateHandler.class); assertEquals(0, h.getLatestId()); h.setMaxUrls(Arrays.asList("http://127.0.0.1:9999/update.def")); h.setSilentPeriodForMaxHttpRequest(0); backgroundExecutor.scheduled = null; clock.setNow(12345); h.handleNewData(new byte[0], null); assertGreaterThanOrEquals(1000 * 60, backgroundExecutor.getInitialDelay()); assertLessThanOrEquals(1000 * 60 * 31, backgroundExecutor.getInitialDelay()); assertEquals(-1, backgroundExecutor.getPeriod()); assertNotNull(backgroundExecutor.scheduled); mockery.checking(new Expectations() { { one(httpExecutor).execute(with(new TypeSafeMatcher<HttpGet>() { public void describeTo(org.hamcrest.Description description) { description.appendText("httpMethod"); } @Override public boolean matchesSafely(HttpGet item) { assertEquals("GET", item.getMethod()); assertTrue(item.getURI().toString(), item.getURI().toString() .startsWith("http://127.0.0.1:9999/update.def?")); return true; } }), with(new TypeSafeMatcher<HttpParams>() { public void describeTo(org.hamcrest.Description description) { } @Override public boolean matchesSafely(HttpParams item) { assertEquals(10000, HttpConnectionParams.getConnectionTimeout(item)); assertEquals(10000, HttpConnectionParams.getSoTimeout(item)); return true; } }), with(new TypeSafeMatcher<HttpClientListener>() { public void describeTo(Description description) { } @Override public boolean matchesSafely(HttpClientListener item) { httpClientListenerRef.set(item); return true; } })); inSequence(requestSequence); } }); backgroundExecutor.scheduled.run(); assertNotNull(httpClientListenerRef.get()); mockery.checking(new Expectations() { { atLeast(1).of(response).getStatusLine(); will(returnValue(statusLine)); inSequence(requestSequence); atLeast(1).of(statusLine).getStatusCode(); will(returnValue(100)); inSequence(requestSequence); one(httpExecutor).releaseResources(with(same(response))); inSequence(requestSequence); } }); httpClientListenerRef.get().requestComplete(method, response); assertEquals(12345, UpdateSettings.LAST_HTTP_FAILOVER.getValue()); assertEquals(0, h.getLatestId()); assertFalse(saveFile.exists()); mockery.assertIsSatisfied(); } public void testNetworkMaxIsNotSavedToDiskAndNotForwarded() throws Exception { final UpdateCollection updateCollection = mockery.mock(UpdateCollection.class); mockery.checking(new Expectations() { { one(updateMessageVerifier).getVerifiedData(new byte[0]); will(returnValue("asdf\n")); one(updateCollectionFactory).createUpdateCollection("asdf\n"); will(returnValue(updateCollection)); allowing(applicationServices).getMyGUID(); will(returnValue(guid)); atLeast(1).of(updateCollection).getId(); will(returnValue(UpdateHandlerImpl.IGNORE_ID)); } }); UpdateHandlerImpl h = (UpdateHandlerImpl) injector.getInstance(UpdateHandler.class); assertEquals(0, h.getLatestId()); h.setSilentPeriodForMaxHttpRequest(0); backgroundExecutor.scheduled = null; clock.setNow(12345); h.handleNewData(new byte[0], null); assertNotNull(backgroundExecutor.scheduled); assertEquals(0, h.getLatestId()); assertFalse(saveFile.exists()); Thread.sleep(5000); // sleep a bit just to make sure it didn't take a // while to save. assertEquals(0, h.getLatestId()); assertFalse(saveFile.exists()); mockery.assertIsSatisfied(); } public void testHttpMaxIsSavedToDiskAndForwards() throws Exception { final AtomicReference<HttpClientListener> httpClientListenerRef = new AtomicReference<HttpClientListener>(); final UpdateCollection updateCollection = mockery.mock(UpdateCollection.class); final Sequence requestSequence = mockery.sequence("Request Sequence"); mockery.checking(new Expectations() { { one(updateMessageVerifier).getVerifiedData(new byte[0]); will(returnValue("asdf\n")); inSequence(requestSequence); one(updateCollectionFactory).createUpdateCollection("asdf\n"); will(returnValue(updateCollection)); inSequence(requestSequence); atLeast(1).of(updateCollection).getId(); will(returnValue(UpdateHandlerImpl.IGNORE_ID)); inSequence(requestSequence); allowing(applicationServices).getMyGUID(); will(returnValue(guid)); inSequence(requestSequence); } }); UpdateHandlerImpl h = (UpdateHandlerImpl) injector.getInstance(UpdateHandler.class); assertEquals(0, h.getLatestId()); h.setMaxUrls(Arrays.asList("http://127.0.0.1:9999/update.def")); h.setSilentPeriodForMaxHttpRequest(0); backgroundExecutor.scheduled = null; clock.setNow(12345); h.handleNewData(new byte[0], null); assertNotNull(backgroundExecutor.scheduled); mockery.checking(new Expectations() { { one(httpExecutor).execute(with(new TypeSafeMatcher<HttpGet>() { public void describeTo(org.hamcrest.Description description) { description.appendText("httpMethod"); } @Override public boolean matchesSafely(HttpGet item) { assertEquals("GET", item.getMethod()); assertTrue(item.getURI().toString(), item.getURI().toString() .startsWith("http://127.0.0.1:9999/update.def?")); return true; } }), with(new TypeSafeMatcher<HttpParams>() { public void describeTo(org.hamcrest.Description description) { } @Override public boolean matchesSafely(HttpParams item) { assertEquals(10000, HttpConnectionParams.getConnectionTimeout(item)); assertEquals(10000, HttpConnectionParams.getSoTimeout(item)); return true; } }), with(new TypeSafeMatcher<HttpClientListener>() { public void describeTo(Description description) { } @Override public boolean matchesSafely(HttpClientListener item) { httpClientListenerRef.set(item); return true; } })); inSequence(requestSequence); } }); backgroundExecutor.scheduled.run(); assertNotNull(httpClientListenerRef.get()); final HttpGet method = new HttpGet(); final HttpResponse response = mockery.mock(HttpResponse.class); final StatusLine statusLine = mockery.mock(StatusLine.class); final HttpEntity httpEntity = mockery.mock(HttpEntity.class); final UpdateCollection httpCollection = mockery.mock(UpdateCollection.class); mockery.checking(new Expectations() { { atLeast(1).of(response).getStatusLine(); will(returnValue(statusLine)); inSequence(requestSequence); atLeast(1).of(statusLine).getStatusCode(); will(returnValue(200)); inSequence(requestSequence); atLeast(1).of(response).getEntity(); will(returnValue(httpEntity)); inSequence(requestSequence); one(httpEntity).getContent(); byte [] b = new byte[1]; ByteArrayInputStream bis = new ByteArrayInputStream(b); will(returnValue(bis)); inSequence(requestSequence); one(updateMessageVerifier).inflateNetworkData(with(LimeTestUtils.createByteMatcher(b))); byte[] inflated = new byte[2]; inSequence(requestSequence); will(returnValue(inflated)); one(httpExecutor).releaseResources(with(same(response))); inSequence(requestSequence); one(updateMessageVerifier).getVerifiedData(with(same(inflated))); inSequence(requestSequence); will(returnValue("http response")); one(updateCollectionFactory).createUpdateCollection("http response"); inSequence(requestSequence); will(returnValue(httpCollection)); atLeast(1).of(httpCollection).getId(); inSequence(requestSequence); will(returnValue(UpdateHandlerImpl.IGNORE_ID)); one(httpCollection).getTimestamp(); inSequence(requestSequence); will(returnValue(54321L)); one(capabilitiesVmFactory).updateCapabilities(); inSequence(requestSequence); one(connectionManager).sendUpdatedCapabilities(); inSequence(requestSequence); } }); httpClientListenerRef.get().requestComplete(method, response); assertEquals(12345, UpdateSettings.LAST_HTTP_FAILOVER.getValue()); assertEquals(54321L, UpdateSettings.LAST_UPDATE_TIMESTAMP.getValue()); assertEquals(UpdateHandlerImpl.IGNORE_ID, h.getLatestId()); assertTrue(saveFile.exists()); mockery.assertIsSatisfied(); } public void testHttpRequestOverridesLocalIfEqual() throws Exception { final AtomicReference<HttpClientListener> httpClientListenerRef = new AtomicReference<HttpClientListener>(); final UpdateCollection updateCollection = mockery.mock(UpdateCollection.class); final Sequence requestSequence = mockery.sequence("Request Sequence"); mockery.checking(new Expectations() { { one(updateMessageVerifier).getVerifiedData(new byte[0]); will(returnValue("asdf\n")); inSequence(requestSequence); one(updateCollectionFactory).createUpdateCollection("asdf\n"); will(returnValue(updateCollection)); inSequence(requestSequence); atLeast(1).of(updateCollection).getId(); will(returnValue(UpdateHandlerImpl.IGNORE_ID)); inSequence(requestSequence); allowing(applicationServices).getMyGUID(); will(returnValue(guid)); inSequence(requestSequence); } }); UpdateHandlerImpl h = (UpdateHandlerImpl) injector.getInstance(UpdateHandler.class); assertEquals(0, h.getLatestId()); h.setMaxUrls(Arrays.asList("http://127.0.0.1:9999/update.def")); h.setSilentPeriodForMaxHttpRequest(0); backgroundExecutor.scheduled = null; clock.setNow(12345); h.handleNewData(new byte[0], null); assertNotNull(backgroundExecutor.scheduled); mockery.checking(new Expectations() { { one(httpExecutor).execute(with(new TypeSafeMatcher<HttpGet>() { public void describeTo(org.hamcrest.Description description) { description.appendText("httpMethod"); } @Override public boolean matchesSafely(HttpGet item) { assertEquals("GET", item.getMethod()); assertTrue(item.getURI().toString(), item.getURI().toString() .startsWith("http://127.0.0.1:9999/update.def?")); return true; } }), with(new TypeSafeMatcher<HttpParams>() { public void describeTo(org.hamcrest.Description description) { } @Override public boolean matchesSafely(HttpParams item) { assertEquals(10000, HttpConnectionParams.getConnectionTimeout(item)); assertEquals(10000, HttpConnectionParams.getSoTimeout(item)); return true; } }), with(new TypeSafeMatcher<HttpClientListener>() { public void describeTo(Description description) { } @Override public boolean matchesSafely(HttpClientListener item) { httpClientListenerRef.set(item); return true; } })); inSequence(requestSequence); } }); backgroundExecutor.scheduled.run(); assertNotNull(httpClientListenerRef.get()); final HttpGet method = new HttpGet(); final HttpResponse response = mockery.mock(HttpResponse.class); final StatusLine statusLine = mockery.mock(StatusLine.class); final HttpEntity httpEntity = mockery.mock(HttpEntity.class); final UpdateCollection httpCollection = mockery.mock(UpdateCollection.class); mockery.checking(new Expectations() { { atLeast(1).of(response).getStatusLine(); will(returnValue(statusLine)); inSequence(requestSequence); atLeast(1).of(statusLine).getStatusCode(); will(returnValue(200)); inSequence(requestSequence); atLeast(1).of(response).getEntity(); will(returnValue(httpEntity)); inSequence(requestSequence); one(httpEntity).getContent(); byte [] b = new byte[1]; ByteArrayInputStream bis = new ByteArrayInputStream(b); will(returnValue(bis)); inSequence(requestSequence); one(updateMessageVerifier).inflateNetworkData(with(LimeTestUtils.createByteMatcher(b))); byte[] inflated = new byte[2]; inSequence(requestSequence); will(returnValue(inflated)); one(httpExecutor).releaseResources(with(same(response))); inSequence(requestSequence); one(updateMessageVerifier).getVerifiedData(with(same(inflated))); inSequence(requestSequence); will(returnValue("http response")); one(updateCollectionFactory).createUpdateCollection("http response"); inSequence(requestSequence); will(returnValue(httpCollection)); atLeast(1).of(httpCollection).getId(); inSequence(requestSequence); will(returnValue(0)); one(httpCollection).getTimestamp(); inSequence(requestSequence); will(returnValue(54321L)); one(capabilitiesVmFactory).updateCapabilities(); inSequence(requestSequence); one(connectionManager).sendUpdatedCapabilities(); inSequence(requestSequence); } }); httpClientListenerRef.get().requestComplete(method, response); assertEquals(12345, UpdateSettings.LAST_HTTP_FAILOVER.getValue()); assertEquals(54321L, UpdateSettings.LAST_UPDATE_TIMESTAMP.getValue()); assertEquals(0, h.getLatestId()); assertTrue(saveFile.exists()); mockery.assertIsSatisfied(); } public void testAfterMaxFromHttpNewMaxFromNetworkDoesntRetrigger() throws Exception { final AtomicReference<HttpClientListener> httpClientListenerRef = new AtomicReference<HttpClientListener>(); final UpdateCollection updateCollection = mockery.mock(UpdateCollection.class); final Sequence requestSequence = mockery.sequence("Request Sequence"); mockery.checking(new Expectations() { { one(updateMessageVerifier).getVerifiedData(new byte[0]); will(returnValue("asdf\n")); inSequence(requestSequence); one(updateCollectionFactory).createUpdateCollection("asdf\n"); will(returnValue(updateCollection)); inSequence(requestSequence); atLeast(1).of(updateCollection).getId(); will(returnValue(UpdateHandlerImpl.IGNORE_ID)); inSequence(requestSequence); allowing(applicationServices).getMyGUID(); will(returnValue(guid)); inSequence(requestSequence); } }); UpdateHandlerImpl h = (UpdateHandlerImpl) injector.getInstance(UpdateHandler.class); assertEquals(0, h.getLatestId()); h.setMaxUrls(Arrays.asList("http://127.0.0.1:9999/update.def")); h.setSilentPeriodForMaxHttpRequest(0); backgroundExecutor.scheduled = null; clock.setNow(12345); h.handleNewData(new byte[0], null); assertNotNull(backgroundExecutor.scheduled); mockery.checking(new Expectations() { { one(httpExecutor).execute(with(new TypeSafeMatcher<HttpGet>() { public void describeTo(org.hamcrest.Description description) { description.appendText("httpMethod"); } @Override public boolean matchesSafely(HttpGet item) { assertEquals("GET", item.getMethod()); assertTrue(item.getURI().toString(), item.getURI().toString() .startsWith("http://127.0.0.1:9999/update.def?")); return true; } }), with(new TypeSafeMatcher<HttpParams>() { public void describeTo(org.hamcrest.Description description) { } @Override public boolean matchesSafely(HttpParams item) { assertEquals(10000, HttpConnectionParams.getConnectionTimeout(item)); assertEquals(10000, HttpConnectionParams.getSoTimeout(item)); return true; } }), with(new TypeSafeMatcher<HttpClientListener>() { public void describeTo(Description description) { } @Override public boolean matchesSafely(HttpClientListener item) { httpClientListenerRef.set(item); return true; } })); inSequence(requestSequence); } }); backgroundExecutor.scheduled.run(); assertNotNull(httpClientListenerRef.get()); final HttpGet method = new HttpGet(); final HttpResponse response = mockery.mock(HttpResponse.class); final StatusLine statusLine = mockery.mock(StatusLine.class); final HttpEntity httpEntity = mockery.mock(HttpEntity.class); final UpdateCollection httpCollection = mockery.mock(UpdateCollection.class); mockery.checking(new Expectations() { { atLeast(1).of(response).getStatusLine(); will(returnValue(statusLine)); inSequence(requestSequence); atLeast(1).of(statusLine).getStatusCode(); will(returnValue(200)); inSequence(requestSequence); atLeast(1).of(response).getEntity(); will(returnValue(httpEntity)); inSequence(requestSequence); one(httpEntity).getContent(); byte [] b = new byte[1]; ByteArrayInputStream bis = new ByteArrayInputStream(b); will(returnValue(bis)); inSequence(requestSequence); one(updateMessageVerifier).inflateNetworkData(with(any(byte [].class))); byte[] inflated = new byte[2]; inSequence(requestSequence); will(returnValue(inflated)); one(httpExecutor).releaseResources(with(same(response))); inSequence(requestSequence); one(updateMessageVerifier).getVerifiedData(with(same(inflated))); inSequence(requestSequence); will(returnValue("http response")); one(updateCollectionFactory).createUpdateCollection("http response"); inSequence(requestSequence); will(returnValue(httpCollection)); atLeast(1).of(httpCollection).getId(); inSequence(requestSequence); will(returnValue(UpdateHandlerImpl.IGNORE_ID)); one(httpCollection).getTimestamp(); inSequence(requestSequence); will(returnValue(54321L)); one(capabilitiesVmFactory).updateCapabilities(); inSequence(requestSequence); one(connectionManager).sendUpdatedCapabilities(); inSequence(requestSequence); } }); httpClientListenerRef.get().requestComplete(method, response); assertEquals(12345, UpdateSettings.LAST_HTTP_FAILOVER.getValue()); assertEquals(54321L, UpdateSettings.LAST_UPDATE_TIMESTAMP.getValue()); assertEquals(UpdateHandlerImpl.IGNORE_ID, h.getLatestId()); assertTrue(saveFile.exists()); clock.setNow(999999); saveFile.delete(); backgroundExecutor.clear(); final UpdateCollection secondUpdateCollection = mockery.mock(UpdateCollection.class); mockery.checking(new Expectations() { { one(updateMessageVerifier).getVerifiedData(new byte[0]); will(returnValue("asdf\n")); inSequence(requestSequence); one(updateCollectionFactory).createUpdateCollection("asdf\n"); will(returnValue(secondUpdateCollection)); inSequence(requestSequence); atLeast(1).of(secondUpdateCollection).getId(); will(returnValue(UpdateHandlerImpl.IGNORE_ID)); inSequence(requestSequence); } }); h.handleNewData(new byte[0], null); assertEquals(12345, UpdateSettings.LAST_HTTP_FAILOVER.getValue()); assertEquals(54321L, UpdateSettings.LAST_UPDATE_TIMESTAMP.getValue()); assertEquals(UpdateHandlerImpl.IGNORE_ID, h.getLatestId()); assertFalse(saveFile.exists()); assertNull(backgroundExecutor.getRunnable()); mockery.assertIsSatisfied(); } public void testFailedHttpRequestUpdatesFailoverTime() throws Exception { final AtomicReference<HttpClientListener> httpClientListenerRef = new AtomicReference<HttpClientListener>(); final UpdateCollection updateCollection = mockery.mock(UpdateCollection.class); final byte[] data = new byte[0]; final String verified = ""; mockery.checking(new Expectations() { { one(updateMessageVerifier).getVerifiedData(data); will(returnValue(verified)); one(updateCollectionFactory).createUpdateCollection(verified); will(returnValue(updateCollection)); atLeast(1).of(updateCollection).getId(); will(returnValue(UpdateHandlerImpl.IGNORE_ID)); allowing(applicationServices).getMyGUID(); will(returnValue(guid)); } }); UpdateHandlerImpl h = injector.getInstance(UpdateHandlerImpl.class); assertEquals(0, h.getLatestId()); h.setMaxUrls(Arrays.asList("http://127.0.0.1:9999/update.def")); h.setSilentPeriodForMaxHttpRequest(0); backgroundExecutor.scheduled = null; clock.setNow(12345); h.handleNewData(data, null); assertNotNull(backgroundExecutor.scheduled); mockery.checking(new Expectations() { { one(httpExecutor).execute(with(new TypeSafeMatcher<HttpGet>() { public void describeTo(org.hamcrest.Description description) { description.appendText("httpMethod"); } @Override public boolean matchesSafely(HttpGet item) { assertEquals("GET", item.getMethod()); assertTrue(item.getURI().toString(), item.getURI().toString() .startsWith("http://127.0.0.1:9999/update.def?")); return true; } }), with(new TypeSafeMatcher<HttpParams>() { public void describeTo(org.hamcrest.Description description) { } @Override public boolean matchesSafely(HttpParams item) { assertEquals(10000, HttpConnectionParams.getConnectionTimeout(item)); assertEquals(10000, HttpConnectionParams.getSoTimeout(item)); return true; } }), with(new TypeSafeMatcher<HttpClientListener>() { public void describeTo(Description description) { } @Override public boolean matchesSafely(HttpClientListener item) { httpClientListenerRef.set(item); return true; } })); } }); backgroundExecutor.scheduled.run(); assertNotNull(httpClientListenerRef.get()); final HttpGet method = new HttpGet(); final HttpResponse response = mockery.mock(HttpResponse.class); mockery.checking(new Expectations() { { one(httpExecutor).releaseResources(response); } }); httpClientListenerRef.get().requestFailed(method, response, null); assertEquals(12345, UpdateSettings.LAST_HTTP_FAILOVER.getValue()); assertEquals(0, h.getLatestId()); assertFalse(saveFile.exists()); mockery.assertIsSatisfied(); } public void testBadHttpBodyUpdatesFailoverTime() throws Exception { final AtomicReference<HttpClientListener> httpClientListenerRef = new AtomicReference<HttpClientListener>(); final UpdateCollection updateCollection = mockery.mock(UpdateCollection.class); final byte[] data = new byte[0]; final String verified = ""; mockery.checking(new Expectations() { { one(updateMessageVerifier).getVerifiedData(data); will(returnValue(verified)); one(updateCollectionFactory).createUpdateCollection(verified); will(returnValue(updateCollection)); atLeast(1).of(updateCollection).getId(); will(returnValue(UpdateHandlerImpl.IGNORE_ID)); allowing(applicationServices).getMyGUID(); will(returnValue(guid)); } }); UpdateHandlerImpl h = injector.getInstance(UpdateHandlerImpl.class); assertEquals(0, h.getLatestId()); h.setMaxUrls(Arrays.asList("http://127.0.0.1:9999/update.def")); h.setSilentPeriodForMaxHttpRequest(0); backgroundExecutor.scheduled = null; clock.setNow(12345); h.handleNewData(data, null); assertNotNull(backgroundExecutor.scheduled); mockery.checking(new Expectations() { { one(httpExecutor).execute(with(new TypeSafeMatcher<HttpGet>() { public void describeTo(org.hamcrest.Description description) { description.appendText("httpMethod"); } @Override public boolean matchesSafely(HttpGet item) { assertEquals("GET", item.getMethod()); assertTrue(item.getURI().toString(), item.getURI().toString() .startsWith("http://127.0.0.1:9999/update.def?")); return true; } }), with(new TypeSafeMatcher<HttpParams>() { public void describeTo(org.hamcrest.Description description) { } @Override public boolean matchesSafely(HttpParams item) { assertEquals(10000, HttpConnectionParams.getConnectionTimeout(item)); assertEquals(10000, HttpConnectionParams.getSoTimeout(item)); return true; } }), with(new TypeSafeMatcher<HttpClientListener>() { public void describeTo(Description description) { } @Override public boolean matchesSafely(HttpClientListener item) { httpClientListenerRef.set(item); return true; } })); } }); backgroundExecutor.scheduled.run(); assertNotNull(httpClientListenerRef.get()); final HttpGet method = new HttpGet(); final HttpResponse response = mockery.mock(HttpResponse.class); final StatusLine statusLine = mockery.mock(StatusLine.class); mockery.checking(new Expectations() { { atLeast(1).of(response).getStatusLine(); will(returnValue(statusLine)); atLeast(1).of(statusLine).getStatusCode(); will(returnValue(200)); atLeast(1).of(response).getEntity(); will(returnValue(null)); one(httpExecutor).releaseResources(response); } }); httpClientListenerRef.get().requestComplete(method, response); assertEquals(12345, UpdateSettings.LAST_HTTP_FAILOVER.getValue()); assertEquals(0, h.getLatestId()); assertFalse(saveFile.exists()); mockery.assertIsSatisfied(); } public void testNullDataFromNetworkIsInvalid() { final ReplyHandler handler = mockery.mock(ReplyHandler.class); mockery.checking(new Expectations() { { one(networkUpdateSanityChecker).handleInvalidResponse(handler, RequestType.VERSION); } }); UpdateHandlerImpl h = injector.getInstance(UpdateHandlerImpl.class); h.handleDataInternal(null, UpdateType.FROM_NETWORK, handler); mockery.assertIsSatisfied(); } public void testUnverifiableDataFromNetworkIsInvalid() { final byte[] data = new byte[0]; final ReplyHandler handler = mockery.mock(ReplyHandler.class); mockery.checking(new Expectations() { { one(updateMessageVerifier).getVerifiedData(data); will(returnValue(null)); one(networkUpdateSanityChecker).handleInvalidResponse(handler, RequestType.VERSION); } }); UpdateHandlerImpl h = injector.getInstance(UpdateHandlerImpl.class); h.handleDataInternal(data, UpdateType.FROM_NETWORK, handler); mockery.assertIsSatisfied(); } public void testVerifiedDataFromNetworkIsValid() { final byte[] data = new byte[0]; final String verified = ""; final ReplyHandler handler = mockery.mock(ReplyHandler.class); final UpdateCollection updateCollection = mockery.mock(UpdateCollection.class); final int id = 12345; mockery.checking(new Expectations() { { one(updateMessageVerifier).getVerifiedData(data); will(returnValue(verified)); one(networkUpdateSanityChecker).handleValidResponse(handler, RequestType.VERSION); one(updateCollectionFactory).createUpdateCollection(verified); will(returnValue(updateCollection)); atLeast(1).of(updateCollection).getId(); will(returnValue(id)); // The ID is not IGNORE_ID and the update type is FROM_NETWORK, // so the update will be stored and propagated one(updateCollection).getTimestamp(); will(returnValue(System.currentTimeMillis())); one(capabilitiesVmFactory).updateCapabilities(); one(connectionManager).sendUpdatedCapabilities(); } }); UpdateHandlerImpl h = injector.getInstance(UpdateHandlerImpl.class); assertLessThan(id, h.getLatestId()); h.handleDataInternal(data, UpdateType.FROM_NETWORK, handler); assertEquals(id, h.getLatestId()); mockery.assertIsSatisfied(); } public void testVerifiedDataFromDiskIsNotSanityChecked() { final byte[] data = new byte[0]; final String verified = ""; final ReplyHandler handler = mockery.mock(ReplyHandler.class); final UpdateCollection updateCollection = mockery.mock(UpdateCollection.class); final int id = 12345; mockery.checking(new Expectations() { { one(updateMessageVerifier).getVerifiedData(data); will(returnValue(verified)); one(updateCollectionFactory).createUpdateCollection(verified); will(returnValue(updateCollection)); atLeast(1).of(updateCollection).getId(); will(returnValue(id)); // The ID is not IGNORE_ID and the update type is FROM_DISK, // so the update will be stored but not propagated one(updateCollection).getTimestamp(); will(returnValue(System.currentTimeMillis())); } }); UpdateHandlerImpl h = injector.getInstance(UpdateHandlerImpl.class); assertLessThan(id, h.getLatestId()); h.handleDataInternal(data, UpdateType.FROM_DISK, handler); assertEquals(id, h.getLatestId()); mockery.assertIsSatisfied(); } private class ImmediateExecutor extends ScheduledExecutorServiceStub { private volatile Runnable scheduled; private volatile long initialDelay = -1; private volatile long period = -1; private volatile TimeUnit timeUnit; Runnable getRunnable() { return scheduled; } long getInitialDelay() { return initialDelay; } long getPeriod() { return period; } TimeUnit getTimeUnit() { return timeUnit; } void clear() { scheduled = null; initialDelay = -1; period = -1; timeUnit = null; } @Override public void execute(Runnable command) { command.run(); } @Override public ScheduledFuture<?> schedule(Runnable command, long delay, TimeUnit unit) { scheduled = command; this.initialDelay = delay; return null; } @Override public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit) { scheduled = command; this.initialDelay = -1; this.period = period; this.timeUnit = unit; return null; } @Override public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit) { scheduled = command; this.initialDelay = -1; this.period = delay; this.timeUnit = unit; return null; } } }