package com.limegroup.gnutella; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketTimeoutException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.hamcrest.Matcher; import org.limewire.io.IOUtils; import org.limewire.io.IpPort; import org.limewire.nio.NIODispatcher; import org.limewire.util.AssertComparisons; import org.limewire.util.Base32; import org.limewire.net.TLSManager; import org.limewire.net.address.AddressEvent; import org.limewire.listener.ListenerSupport; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Injector; import com.google.inject.Module; import com.google.inject.Stage; import com.google.inject.TypeLiteral; import com.google.inject.util.Modules; import com.limegroup.gnutella.connection.BlockingConnectionFactory; import com.limegroup.gnutella.connection.BlockingConnectionFactoryImpl; import com.limegroup.gnutella.stubs.ActivityCallbackStub; import com.limegroup.gnutella.stubs.NetworkManagerStub; @SuppressWarnings("deprecation") public class LimeTestUtils { public static void waitForNIO() throws InterruptedException { Future<?> future = NIODispatcher.instance().getScheduledExecutorService().submit(new Runnable() { public void run() { } }); try { future.get(); } catch(ExecutionException ee) { throw new IllegalStateException(ee); } // the runnable is run at the beginning of the processing cycle so // we need a second runnable to make sure the cycle has been completed future = NIODispatcher.instance().getScheduledExecutorService().submit(new Runnable() { public void run() { } }); try { future.get(); } catch(ExecutionException ee) { throw new IllegalStateException(ee); } } public static void setActivityCallBack(ActivityCallback cb) throws Exception { throw new RuntimeException("fix me"); } public static void readBytes(InputStream in, long count) throws IOException { for (long i = 0; i < count; i++) { try { if (in.read() == -1) { throw new AssertionError("Unexpected end of stream after " + i + " bytes"); } } catch (SocketTimeoutException e) { throw new AssertionError("Timeout while reading " + count + " bytes (read " + i + " bytes)"); } } } /** * generate a dummy repeating String of the specified length */ public static String generateRepeatingStringByLength(String stringtoRepeat, int length) { StringBuilder longStr = new StringBuilder(); while (longStr.length() < length) { longStr.append(stringtoRepeat); } return longStr.substring(0, length); } /** * Simple copy. Horrible performance for large files. * Good performance for alphabets. */ public static void copyFile(File source, File dest) throws Exception { FileInputStream fis = new FileInputStream(source); try { FileOutputStream fos = new FileOutputStream(dest); try { int read = fis.read(); while(read != -1) { fos.write(read); read = fis.read(); } } finally { fos.close(); } } finally { fis.close(); } } /** * Creates subdirs in tmp dir and ensures that they are deleted on JVM * exit. */ public static File[] createTmpDirs(String... dirs) { File tmpDir = new File(System.getProperty("java.io.tmpdir")); AssertComparisons.assertTrue(tmpDir.isDirectory()); return createDirs(tmpDir, dirs); } /** * Creates <code>dirs</code> as subdirs of <code>parent</code> and ensures * that they are deleted on JVM exit. */ public static File[] createDirs(File parent, String... dirs) { List<File> list = new ArrayList<File>(dirs.length); for (String name : dirs) { File dir = new File(parent, name); AssertComparisons.assertTrue(dir.mkdirs() || dir.exists()); // Make sure it's clean! deleteFiles(dir.listFiles()); list.add(dir); while (!dir.equals(parent)) { dir.deleteOnExit(); dir = dir.getParentFile(); } } return list.toArray(new File[list.size()]); } /** Deletes all files listed. */ public static void deleteFiles(File...files) { for(int i = 0; i < files.length; i++) files[i].delete(); } /** * Creates the Guice injector with the limewire default modules and the * test module that can override bindings in the former modules. * * @param module the test modules that can override bindings * @param callbackClass the class that is used as a callback * @return the injector */ public static Injector createInjector(Class<? extends ActivityCallback> callbackClass, Module...modules) { return createInjector(Stage.DEVELOPMENT, callbackClass, modules); } public static Injector createInjector(Stage stage, Class<? extends ActivityCallback> callbackClass, Module...modules) { Module combinedReplacements = Modules.combine(modules); Module combinedOriginals = Modules.combine(new LimeWireCoreModule(callbackClass), new BlockingConnectionFactoryModule()); Module replaced = Modules.override(combinedOriginals).with(combinedReplacements); return Guice.createInjector(stage, replaced); } /** * Wraps {@link #createInjector(Module, Class) createInjector(Module, ActivityCallbackStub.class)}. */ public static Injector createInjector(Module... modules) { return createInjector(ActivityCallbackStub.class, modules); } public static Injector createInjector(Stage stage, Module... modules) { return createInjector(stage, ActivityCallbackStub.class, modules); } /** * Creates the Guice injector with the limewire default modules and the * test module that can override bindings in the former modules. * * Also starts the {@link LifecycleManager}. * * @param module the test modules that can override bindings * @param callbackClass the class that is used as a callback * @return the injector */ public static Injector createInjectorAndStart(Class<? extends ActivityCallback> callbackClass, Module...modules) { // Use PRODUCTION to ensure all Services are created. Injector injector = createInjector(Stage.PRODUCTION, callbackClass, modules); LifecycleManager lifecycleManager = injector.getInstance(LifecycleManager.class); lifecycleManager.start(); return injector; } /** * Wraps {@link #createInjectorAndStart(Module, Class) createInjectorAndStart(Module, ActivityCallbackStub.class)}. */ public static Injector createInjectorAndStart(Module...modules) { return createInjectorAndStart(ActivityCallbackStub.class, modules); } public static class NetworkManagerStubModule extends AbstractModule { private final NetworkManagerStub networkManagerStub; public NetworkManagerStubModule(NetworkManagerStub networkManagerStub) { this.networkManagerStub = networkManagerStub; } @Override protected void configure() { bind(NetworkManager.class).toInstance(networkManagerStub); bind(TLSManager.class).toInstance(networkManagerStub); bind(new TypeLiteral<ListenerSupport<AddressEvent>>(){}).toInstance(networkManagerStub); } } public static class BlockingConnectionFactoryModule extends AbstractModule { @Override protected void configure() { bind(BlockingConnectionFactory.class).to(BlockingConnectionFactoryImpl.class); } } /** * Establishes an incoming connection. It is necessary to send a proper * connect back string. We ignore exceptions because various components * may have been stubbed out in the specific test case. * @param port where to establish the connection to. */ public static void establishIncoming(int port) { Socket s = null; try { s = new Socket(); s.connect(new InetSocketAddress("127.0.0.1",port)); s.getOutputStream().write("CONNECT ".getBytes()); s.getOutputStream().flush(); s.close(); } catch (IOException ignore) {} finally { IOUtils.close(s); } } public static String getRelativeRequest(URN urn) { return getRelativeRequest(urn.httpStringValue()); } public static String getRelativeRequest(String urn) { return "/uri-res/N2R?" + urn; } public static String getRequest(IpPort host, URN urn) { return getRequest(host.getAddress(), host.getPort(), urn); } public static String getRequest(IpPort host, String urn) { return getRequest(host.getAddress(), host.getPort(), urn); } public static String getRequest(String host, int port, URN urn) { return getRequest(host + ":" + port, urn); } public static String getRequest(String host, int port, String urn) { return getRequest(host + ":" + port, urn); } public static String getRequest(String hostAndPort, URN urn) { return getRequest(hostAndPort, urn.httpStringValue()); } public static String getRequest(String hostAndPort, String urn) { return "http://" + hostAndPort + getRelativeRequest(urn); } /** * @return a <tt>Matcher</tt> to use with JMock that compares byte [] * using Arrays.equals */ public static Matcher<byte []> createByteMatcher(byte [] toMatch) { return new ByteMatcher(toMatch.clone()); } private static class ByteMatcher extends BaseMatcher<byte []> { private final byte[] toMatch; ByteMatcher(byte [] toMatch) { this.toMatch = toMatch.clone(); } public boolean matches(Object item) { if (! (item instanceof byte [])) return false; byte [] b = (byte [])item; return Arrays.equals(toMatch,b); } public void describeTo(Description description) { description.appendText("byte [] matcher for "+Base32.encode(toMatch)); } } }