package org.limewire.core.impl.inspections; import java.io.FileOutputStream; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.limewire.core.impl.CoreGlueModule; import org.limewire.core.settings.InspectionsSettings; import org.limewire.gnutella.tests.LimeTestCase; import org.limewire.inspection.Inspectable; import org.limewire.inspection.InspectablePrimitive; import org.limewire.inspection.InspectionPoint; import org.limewire.io.InvalidDataException; import org.limewire.util.StringUtils; import org.mortbay.http.HttpContext; import org.mortbay.http.HttpServer; import org.mortbay.http.SocketListener; import org.mortbay.http.handler.NotFoundHandler; import org.mortbay.http.handler.ResourceHandler; import org.mortbay.util.Resource; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Module; import com.google.inject.Stage; import com.limegroup.gnutella.LimeWireCoreModule; /** * Real world push inspections integration test. Brings up LW Core and * performs real inspections * */ public class InspectionsIntegrationTest extends LimeTestCase { private static final String INSPECTIONS_REQUEST = "/request"; private static final String INSPECTIONS_SUBMIT = "/submit"; private static final String SPEC_FILENAME = "specFile"; /* test inspection points */ @InspectablePrimitive("test primitive") public static int INSPECTION_ONE; @InspectionPoint("test inspectable") public static Inspectable INSPECTION_TWO; @InspectionPoint("throwing inspectable") public static Inspectable INSPECTION_THROW; @InspectionPoint("null inspectable") public static Inspectable INSPECTION_NULL; protected Injector injector; private HttpServer server; private InspectionsCommunicatorImpl ic; public InspectionsIntegrationTest(String name) { super(name); server = new HttpServer(); } @Override protected void setUp() throws Exception { injector = createInjector(getModules()); initializeInspectionPoints(); ensureInspectionsCommunicatorStopped(); initSettings(); } @Override public void tearDown() throws Exception { server.stop(); ensureInspectionsCommunicatorStopped(); } private void ensureInspectionsCommunicatorStopped() { if (ic != null) { ic.stop(); ic = null; } } private void startInspectionsCommunicator() { ic = (InspectionsCommunicatorImpl)injector.getInstance(InspectionsCommunicator.class); ic.initialize(); ic.start(); } private void initSettings() { InspectionsSettings.INSPECTION_SPEC_REQUEST_URL.set("http://localhost:8123/request"); InspectionsSettings.INSPECTION_SPEC_SUBMIT_URL.set("http://localhost:8123/submit"); } private void initializeInspectionPoints() { INSPECTION_ONE = 1; INSPECTION_TWO = new Inspectable() { public int count = 0; @Override public Object inspect() { Map<String, Object> map = new HashMap<String, Object>(); map.put("integer insp", 5); map.put("string insp", "test"); map.put("count value", count++); return map; } }; INSPECTION_THROW = new Inspectable() { @Override public Object inspect() { throw new RuntimeException("error in inspection"); } }; INSPECTION_NULL = new Inspectable() { @Override public Object inspect() { return null; } }; } private Injector createInjector(Module... modules) { return Guice.createInjector(Stage.PRODUCTION, modules); } private Module[] getModules() { List<Module> modules = new ArrayList<Module>(); modules.add(new LimeWireCoreModule()); modules.add(new CoreGlueModule()); return modules.toArray(new Module[modules.size()]); } public void testScheduledRepeatingInspections() throws Exception { List<String> inspections = Collections.singletonList("org.limewire.core.impl.inspections.InspectionsIntegrationTest:INSPECTION_ONE"); long timeToStartInsp = 3L; long interval = 5L; List<InspectionsSpec> specs = Arrays.asList(new InspectionsSpec(inspections, timeToStartInsp, interval)); // start web server and lw services ServerController serverController = startServerWithInspectionSpecs(specs); startInspectionsCommunicator(); // wait for inspection data to arrive at web server //long origTime = System.currentTimeMillis(); // Changing the inspected values in between scheduled inspections // 0-start, 3-first insp, 5-var change, 8-second insp., 10-var change, 13-third insp. Thread.sleep(5000); INSPECTION_ONE++; Thread.sleep(5000); INSPECTION_ONE++; Thread.sleep(5000); // get all the bytes received by webserver List<byte[]> listInspDataEncoded = serverController.getReceivedInspectionData(); assertEquals(3, listInspDataEncoded.size()); InspectionDataContainer listInspData1 = parseInspectionData(listInspDataEncoded.get(0)); InspectionDataContainer listInspData2 = parseInspectionData(listInspDataEncoded.get(1)); InspectionDataContainer listInspData3 = parseInspectionData(listInspDataEncoded.get(2)); assertEquals(1, listInspData1.getResultCount()); assertEquals(1, listInspData2.getResultCount()); assertEquals(1, listInspData3.getResultCount()); // verify each inspection result // TODO make test less fragile and remove sleeps // assertEquals(3, Math.round(((listInspData1.getTimestamp()-origTime)/1000.0))); assertEquals(Integer.valueOf(1), Integer.valueOf(new String((byte[])listInspData1.getData( "org.limewire.core.impl.inspections.InspectionsIntegrationTest:INSPECTION_ONE")))); //assertEquals(8, Math.round(((listInspData2.getTimestamp()-origTime)/1000.0))); assertEquals(Integer.valueOf(2), Integer.valueOf(new String((byte[])listInspData2.getData( "org.limewire.core.impl.inspections.InspectionsIntegrationTest:INSPECTION_ONE")))); //assertEquals(13, Math.round(((listInspData3.getTimestamp()-origTime)/1000.0))); assertEquals(Integer.valueOf(3), Integer.valueOf(new String((byte[])listInspData3.getData( "org.limewire.core.impl.inspections.InspectionsIntegrationTest:INSPECTION_ONE")))); } public void testMultipleInspectionsInOneInspectionsSpec() throws Exception { List<String> inspections = Arrays.asList("org.limewire.core.impl.inspections.InspectionsIntegrationTest:INSPECTION_ONE", "org.limewire.core.impl.inspections.InspectionsIntegrationTest:INSPECTION_TWO"); List<InspectionsSpec> specs = Arrays.asList(new InspectionsSpec(inspections, 5, 0)); // start web server and lw services ServerController serverController = startServerWithInspectionSpecs(specs); startInspectionsCommunicator(); // wait for inspection data to arrive at web server long origTime = System.currentTimeMillis(); Thread.sleep(15000); List<byte[]> listInspDataEncoded = serverController.getReceivedInspectionData(); assertEquals(1, listInspDataEncoded.size()); InspectionDataContainer listInspData1 = parseInspectionData(listInspDataEncoded.get(0)); assertEquals(2, listInspData1.getResultCount()); assertEquals(5, Math.round(((listInspData1.getTimestamp()-origTime)/1000.0))); assertEquals(Integer.valueOf(1), Integer.valueOf(new String((byte[])listInspData1.getData( inspections.get(0))))); Map<?,?> map = (Map<?,?>)listInspData1.getData(inspections.get(1)); int integerInsp = ((Long)map.get("integer insp")).intValue(); String stringInsp = new String((byte[])map.get("string insp")); int countValue = ((Long)map.get("count value")).intValue(); assertEquals(5, integerInsp); assertEquals("test", stringInsp); assertEquals(0, countValue); } @SuppressWarnings("unchecked") public void testScheduledNonExistentInspections() throws Exception { List<String> inspections = Collections.singletonList("org.limewire.core.impl.inspections.InspectionsIntegrationTest:DOES_NOT_EXIST"); long timeToStartInsp = 3L; long interval = 0; List<InspectionsSpec> specs = Arrays.asList(new InspectionsSpec(inspections, timeToStartInsp, interval)); // start web server and lw services ServerController serverController = startServerWithInspectionSpecs(specs); startInspectionsCommunicator(); Thread.sleep(5000); // get all the bytes received by webserver List<byte[]> listInspDataEncoded = serverController.getReceivedInspectionData(); // expecting no inspections results assertEquals(1, listInspDataEncoded.size()); InspectionDataContainer inspData = parseInspectionData(listInspDataEncoded.get(0)); assertEquals(1, inspData.getResultCount()); Map<String, Object> inspresult = (Map<String, Object>)inspData.getData(inspections.get(0)); assertEquals(1, inspresult.size()); assertEquals("java.lang.NoSuchFieldException: DOES_NOT_EXIST", StringUtils.toUTF8String((byte[])inspresult.get("error"))); } /** * Test an inspection point which throws an Exception during the inspect() call. */ public void testThrowingInspection() throws Exception { List<String> inspections = Collections.singletonList("org.limewire.core.impl.inspections.InspectionsIntegrationTest:INSPECTION_THROW"); List<InspectionsSpec> specs = Arrays.asList(new InspectionsSpec(inspections, 5, 0)); // start web server and lw services ServerController serverController = startServerWithInspectionSpecs(specs); startInspectionsCommunicator(); Thread.sleep(15000); List<byte[]> listInspDataEncoded = serverController.getReceivedInspectionData(); // expecting inspection result with error assertEquals(1, listInspDataEncoded.size()); InspectionDataContainer inspData = parseInspectionData(listInspDataEncoded.get(0)); assertEquals(1, inspData.getResultCount()); Map<?, ?> map = (Map<?, ?>)inspData.getData(inspections.get(0)); assertEquals(1, map.size()); assertEquals("java.lang.RuntimeException: error in inspection", StringUtils.toUTF8String((byte[])map.get("error"))); } public void testServerSendsNoInspections() throws Exception { List<InspectionsSpec> specs = Collections.emptyList(); ServerController serverController = startServerWithInspectionSpecs(specs); startInspectionsCommunicator(); Thread.sleep(15000); // get all the bytes received by webserver List<byte[]> listInspDataEncoded = serverController.getReceivedInspectionData(); // expecting no inspections results assertEquals(0, listInspDataEncoded.size()); } public void testServerNotUp() throws Exception { InspectionsCommunicatorImpl ic = (InspectionsCommunicatorImpl)injector.getInstance(InspectionsCommunicator.class); ic.initialize(); ic.start(); Thread.sleep(15000); // todo: insp: what exactly do i test for here? } public void testBadDataFromServer() throws Exception { ServerController serverController = startServerWithContent("sdukfdfgdhsdkfhskhdfsd".getBytes()); startInspectionsCommunicator(); Thread.sleep(15000); // get all the bytes received by webserver List<byte[]> listInspDataEncoded = serverController.getReceivedInspectionData(); // expecting no inspections results assertEquals(0, listInspDataEncoded.size()); } public void testErrorFromServer() throws Exception { ServerController serverController = startServer(_baseDir.getAbsolutePath()); startInspectionsCommunicator(); Thread.sleep(15000); // get all the bytes received by webserver List<byte[]> listInspDataEncoded = serverController.getReceivedInspectionData(); // expecting no inspections results assertEquals(0, listInspDataEncoded.size()); } private ServerController startServerWithContent(byte[] bytes) throws Exception { String serverDir = _baseDir.getAbsolutePath(); writeFile(bytes, serverDir + "/" + SPEC_FILENAME); return startServer(serverDir); } private ServerController startServerWithInspectionSpecs(List<InspectionsSpec> specs) throws Exception { byte[] dataForServerToReturn = InspectionsTestUtils.getGzippedAndBencoded(specs); return startServerWithContent(dataForServerToReturn); } private void writeFile(byte[] bytes, String pathToFileName) throws IOException { FileOutputStream os = new FileOutputStream(pathToFileName); os.write(bytes); os.close(); } private ServerController startServer(String rootContentDir) throws Exception { ServerController requestHandler = new ServerController(); SocketListener listener = new SocketListener(); listener.setPort(8123); listener.setMinThreads(1); server.addListener(listener); HttpContext context = server.addContext(""); context.setResourceBase(rootContentDir); requestHandler.setAcceptRanges(true); requestHandler.setDirAllowed(true); context.addHandler(requestHandler); context.addHandler(new NotFoundHandler()); server.start(); return requestHandler; } private InspectionDataContainer parseInspectionData(byte[] data) throws InvalidDataException { return new InspectionDataContainer(data); } /** * HTTP Request handler code. May override {@link #sendInspectionSpecs} * method to specify behavior than just uploading the expected file. */ private class ServerController extends ResourceHandler { private List<byte[]> inspectionDataEncoded = new ArrayList<byte[]>(); @SuppressWarnings("unchecked") @Override public void handleGet(org.mortbay.http.HttpRequest httpRequest, org.mortbay.http.HttpResponse httpResponse, String s, java.lang.String s1, org.mortbay.util.Resource resource) throws java.io.IOException { super.handleGet(httpRequest, httpResponse, s, s1, resource); Set<String> params = httpRequest.getURI().getParameterNames(); String path = httpRequest.getURI().getPath(); assertTrue(params.containsAll(Arrays.asList("lv", "guid", "urs"))); if (path.equals(INSPECTIONS_REQUEST)) { sendInspectionSpecs(httpRequest, httpResponse); } else if (path.equals(INSPECTIONS_SUBMIT)) { // set success on response httpResponse.setStatus(org.mortbay.http.HttpResponse.__200_OK); int lengthOfData = httpRequest.getContentLength(); byte[] b = new byte[lengthOfData]; assertEquals(lengthOfData, httpRequest.getInputStream().read(b)); inspectionDataEncoded.add(b); } else { fail("Invalid request: " + path); } httpResponse.commit(); httpRequest.setHandled(true); } protected void sendInspectionSpecs(org.mortbay.http.HttpRequest httpRequest, org.mortbay.http.HttpResponse httpResponse) throws IOException { // send back gzipped-bencoded list of maps httpResponse.setStatus(org.mortbay.http.HttpResponse.__200_OK); httpResponse.setContentType("binary/octet-stream"); Resource res = getResource(SPEC_FILENAME); sendData(httpRequest, httpResponse, null, res, true); httpResponse.commit(); httpRequest.setHandled(true); } List<byte []> getReceivedInspectionData() { return inspectionDataEncoded; } } }