package com.limegroup.gnutella.version; import java.io.*; import java.net.*; import java.util.*; import junit.framework.Test; import com.limegroup.gnutella.*; import com.limegroup.gnutella.stubs.ActivityCallbackStub; import com.limegroup.gnutella.messages.*; import com.limegroup.gnutella.messages.vendor.*; import com.limegroup.gnutella.util.*; import com.limegroup.gnutella.settings.UpdateSettings; /** * Tests to make sure updates are sent, requested, etc... */ public class InterClientTest extends ClientSideTestCase { public InterClientTest(String name) { super(name); } public static Test suite() { return buildTestSuite(InterClientTest.class); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } static UpdateRequest dummy = new UpdateRequest(); public void setUp() throws Exception { setEmpty(); } /** * Simple test to make sure that if someone sends a CapabilitiesVM * with a greater version than we have, that we request the new version. * And that we don't request if someone doesn't send it. */ public void testRequestIsSent() throws Exception { drain(testUP[0]); assertEquals(0, UpdateHandler.instance().getLatestId()); testUP[0].send(getCVM(1)); testUP[0].flush(); // We should get an UpdateRequest. Message m = getFirstInstanceOfMessageType(testUP[0], UpdateRequest.class); assertNotNull(m); assertInstanceof(UpdateRequest.class, m); setCurrentId(10); assertEquals(10, UpdateHandler.instance().getLatestId()); testUP[0].send(getCVM(5)); testUP[0].flush(); // we shouldn't get a message, since they said they had 5 & we know of 10. m = getFirstInstanceOfMessageType(testUP[0], UpdateRequest.class); assertNull(m); // Now if they send with 11, we'll request. testUP[0].send(getCVM(11)); testUP[0].flush(); m = getFirstInstanceOfMessageType(testUP[0], UpdateRequest.class); assertNotNull(m); assertInstanceof(UpdateRequest.class, m); } /** * Tests that a response is sent in response to a rquest. */ public void testResponseIsSent() throws Exception { drain(testUP[0]); assertEquals(0, UpdateHandler.instance().getLatestId()); // We should get no response, since we have no data to give. testUP[0].send(new UpdateRequest()); testUP[0].flush(); Message m = getFirstInstanceOfMessageType(testUP[0], UpdateResponse.class); assertNull(m); // Alright, set some current bytes so we can do some testing. byte[] data = setCurrent(-10); testUP[0].send(new UpdateRequest()); testUP[0].flush(); m = getFirstInstanceOfMessageType(testUP[0], UpdateResponse.class); assertNotNull(m); assertInstanceof(UpdateResponse.class, m); assertEquals(data, payload(m)); } /** * Tests that valid versions are used. */ public void testValidVersion() throws Exception { drain(testUP[0]); setCurrentId(-11); assertEquals(-11, UpdateHandler.instance().getLatestId()); // Get the -10 file. byte[] b = readFile(-10); testUP[0].send(UpdateResponse.createUpdateResponse(b,dummy)); testUP[0].flush(); Thread.sleep(1000); // let it process. assertEquals(-10, UpdateHandler.instance().getLatestId()); // Make sure we got a new CapabilitiesVM. Message m = getFirstInstanceOfMessageType(testUP[0], CapabilitiesVM.class); assertNotNull(m); // TODO: is 65526 right? assertEquals(65526, ((CapabilitiesVM)m).supportsUpdate()); } /** * Tests that older versions are ignored. */ public void testOlderVersionsIgnored() throws Exception { drain(testUP[0]); setCurrentId(-9); assertEquals(-9, UpdateHandler.instance().getLatestId()); // Get the -10 file. byte[] b = readFile(-10); testUP[0].send(UpdateResponse.createUpdateResponse(b,dummy)); testUP[0].flush(); Thread.sleep(1000); // let it process. assertEquals(-9, UpdateHandler.instance().getLatestId()); } /** * Test that invalid signatures are ignored. */ public void testInvalidSignaturesIgnored() throws Exception { drain(testUP[0]); setCurrentId(-11); assertEquals(-11, UpdateHandler.instance().getLatestId()); // Get the -10 file. byte[] b = readFile(-10); b[0] = '0'; // break the sig. testUP[0].send(UpdateResponse.createUpdateResponse(b,dummy)); testUP[0].flush(); Thread.sleep(1000); // let it process. assertEquals(-11, UpdateHandler.instance().getLatestId()); } /** * Tests that invalid bytes break verification. */ public void testInvalidBytesIgnored() throws Exception { drain(testUP[0]); setCurrentId(-11); assertEquals(-11, UpdateHandler.instance().getLatestId()); // Get the -10 file. byte[] b = readFile(-10); b[b.length-1] = '0'; // break the data. testUP[0].send(UpdateResponse.createUpdateResponse(b,dummy)); testUP[0].flush(); Thread.sleep(1000); // let it process. assertEquals(-11, UpdateHandler.instance().getLatestId()); } /** * Test invalid XML ignored. */ public void testInvalidXMLIgnored() throws Exception { drain(testUP[0]); setCurrentId(-11); assertEquals(-11, UpdateHandler.instance().getLatestId()); // Get the -9 file. byte[] b = readFile(-9); testUP[0].send(UpdateResponse.createUpdateResponse(b,dummy)); testUP[0].flush(); Thread.sleep(1000); // let it process. assertEquals(-11, UpdateHandler.instance().getLatestId()); } /** * Tests that updates are sent out when versions come in. */ public void testUpdatesSentToGUI() throws Exception { drain(testUP[0]); setCurrentId(-11); assertEquals(-11, UpdateHandler.instance().getLatestId()); MyActivityCallback cb = (MyActivityCallback)RouterService.getCallback(); cb.lastUpdate = null; // Get the -8 file. byte[] b = readFile(-8); testUP[0].send(UpdateResponse.createUpdateResponse(b,dummy)); testUP[0].flush(); Thread.sleep(1000); // let it process. assertEquals(-8, UpdateHandler.instance().getLatestId()); // since version still == @version@, it wasn't sent to the callback. assertNull(cb.lastUpdate); setEmpty(); setCurrentId(-11); assertEquals(-11, UpdateHandler.instance().getLatestId()); setVersion("3.0.0"); // Set the update style to zero to ensure the message is not ignored UpdateSettings.UPDATE_STYLE.setValue(0); // Get the -8 file. b = readFile(-8); testUP[0].send(UpdateResponse.createUpdateResponse(b,dummy)); testUP[0].flush(); Thread.sleep(1000); // let it process. assertEquals(-8, UpdateHandler.instance().getLatestId()); assertNotNull(cb.lastUpdate); } public void testCompressedResponse() throws Exception { drain(testUP[0]); assertEquals(0, UpdateHandler.instance().getLatestId()); // We should get no response, since we have no data to give. UpdateRequestStub request = new UpdateRequestStub(2,true,true); testUP[0].send(new UpdateRequest()); testUP[0].flush(); Message m = getFirstInstanceOfMessageType(testUP[0], UpdateResponse.class); assertNull(m); // Alright, set some current bytes so we can do some testing. byte[] data = setCurrent(-10); testUP[0].send(request); testUP[0].flush(); m = getFirstInstanceOfMessageType(testUP[0], UpdateResponse.class); assertNotNull(m); assertInstanceof(UpdateResponse.class, m); byte [] payload = payload(m); GGEP g = new GGEP(payload,0,null); assertEquals(g.getBytes("C"),data); assertFalse(g.hasKey("U")); } public void testUncompressedGGEPResponse() throws Exception { drain(testUP[0]); assertEquals(0, UpdateHandler.instance().getLatestId()); // We should get no response, since we have no data to give. testUP[0].send(new UpdateRequest()); testUP[0].flush(); Message m = getFirstInstanceOfMessageType(testUP[0], UpdateResponse.class); assertNull(m); UpdateRequestStub request = new UpdateRequestStub(2,true,false); byte[] data = setCurrent(-10); testUP[0].send(request); testUP[0].flush(); m = getFirstInstanceOfMessageType(testUP[0], UpdateResponse.class); assertNotNull(m); assertInstanceof(UpdateResponse.class, m); byte [] payload = payload(m); GGEP g = new GGEP(payload,0,null); assertEquals(g.getBytes("U"),data); assertFalse(g.hasKey("C")); } /** * tests that a request with higher version w/o GGEP gets responded to properly */ public void testHigherVersionNoGGEP() throws Exception { drain(testUP[0]); assertEquals(0, UpdateHandler.instance().getLatestId()); // We should get no response, since we have no data to give. testUP[0].send(new UpdateRequest()); testUP[0].flush(); Message m = getFirstInstanceOfMessageType(testUP[0], UpdateResponse.class); assertNull(m); UpdateRequestStub request = new UpdateRequestStub(2,false,false); byte[] data = setCurrent(-10); testUP[0].send(request); testUP[0].flush(); m = getFirstInstanceOfMessageType(testUP[0], UpdateResponse.class); assertNotNull(m); assertEquals(data,payload(m)); } private static void setCurrentId(int i) throws Exception { PrivilegedAccessor.setValue(UpdateHandler.instance(), "_lastId", new Integer(i)); } private static void setCurrentBytes(byte[] b) throws Exception { PrivilegedAccessor.setValue(UpdateHandler.instance(), "_lastBytes", b); } private static void setCurrentInfo(UpdateInformation info) throws Exception { PrivilegedAccessor.setValue(UpdateHandler.instance(), "_updateInfo", null); } private static byte[] setCurrent(int i) throws Exception { setCurrentId(i); byte[] b = readFile(i); assertNotNull(b); setCurrentBytes(b); return b; } private static void setEmpty() throws Exception { setCurrentId(0); setCurrentBytes(null); setCurrentInfo(null); } private static byte[] readFile(int i) throws Exception { File f = CommonUtils.getResourceFile("com/limegroup/gnutella/version/test_" + i + ".xml"); assertTrue(f.exists()); assertTrue(f.isFile()); return FileUtils.readFileFully(f); } private static void setVersion(String v) throws Exception { PrivilegedAccessor.setValue(CommonUtils.class, "testVersion", v); } private static byte[] payload(Message m) throws Exception { assertInstanceof("not a vendor message!", VendorMessage.class, m); return (byte[])PrivilegedAccessor.invokeMethod(m, "getPayload", null); } private static Message getCVM(int i) throws Exception { return CapabilitiesVMStubHelper.makeUpdateVM(i); } ////////////////////////////////////////////////////////////////// // method for ClientSideTestCase. public static Integer numUPs() { return new Integer(1); } public static ActivityCallback getActivityCallback() { return new MyActivityCallback(); } private static class MyActivityCallback extends ActivityCallbackStub { UpdateInformation lastUpdate; public void updateAvailable(UpdateInformation info) { lastUpdate = info; } } static byte [] derivePayload(boolean hasGGEP, boolean requestsCompressed) throws Exception { if (!hasGGEP) return DataUtils.EMPTY_BYTE_ARRAY; GGEP g = new GGEP(); if (requestsCompressed) g.put("C"); else g.put("X"); //put something else ByteArrayOutputStream baos = new ByteArrayOutputStream(); g.write(baos); return baos.toByteArray(); } private static class UpdateRequestStub extends VendorMessage{ public int version; public boolean hasGGEP,requestsCompressed; public UpdateRequestStub(int version, boolean hasGGEP, boolean requestsCompressed) throws Exception { super(F_LIME_VENDOR_ID, F_UPDATE_REQ, version, derivePayload(hasGGEP, requestsCompressed)); this.version = version; this.hasGGEP = hasGGEP; this.requestsCompressed = requestsCompressed; } public int getVersion() { return version; } public boolean hasGGEP() { return hasGGEP; } public boolean requestsCompressed() { return requestsCompressed; } } }