package org.limewire.gnutella.tests; import java.io.File; import java.io.FileFilter; 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.HashSet; import java.util.List; import java.util.Set; import junit.framework.Assert; import org.hamcrest.BaseMatcher; import org.hamcrest.Description; import org.hamcrest.Matcher; import org.limewire.inject.GuiceUtils; import org.limewire.io.IOUtils; import org.limewire.io.IpPort; import org.limewire.listener.ListenerSupport; import org.limewire.net.TLSManager; import org.limewire.net.address.AddressEvent; import org.limewire.util.AssertComparisons; import org.limewire.util.Base32; import org.limewire.util.FileUtils; import org.limewire.util.StringUtils; import org.limewire.util.TestUtils; 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.ActivityCallback; import com.limegroup.gnutella.LifecycleManager; import com.limegroup.gnutella.LimeWireCoreModule; import com.limegroup.gnutella.NetworkManager; import com.limegroup.gnutella.URN; import com.limegroup.gnutella.connection.BlockingConnectionFactory; import com.limegroup.gnutella.connection.BlockingConnectionFactoryImpl; public class LimeTestUtils { /** Returns a directory that has a bunch of files. */ public static File getDirectoryWithLotsOfFiles() { File file = TestUtils.getResourceFile("org/limewire/gnutella/tests/TestFileNumber54806.tmp"); Assert.assertTrue(file.exists()); File parent = file.getParentFile(); Assert.assertTrue(parent.exists()); return parent; } 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(callbackClass, true, modules); } /** * Wraps {@link #createInjector(Module, Class) createInjector(Module, ActivityCallbackStub.class)}. */ public static Injector createInjector(Module... modules) { return createInjector(ActivityCallbackStub.class, true, modules); } /** * Creates the Guice injector without eagerly loading EagerSingletons. */ public static Injector createInjectorNonEagerly(Class<? extends ActivityCallback> callbackClass, Module... modules) { return createInjector(callbackClass, false, modules); } /** * Creates the Guice injector without eagerly loading EagerSingletons. */ public static Injector createInjectorNonEagerly(Module... modules) { return createInjector(ActivityCallbackStub.class, false, modules); } private static Injector createInjector(Class<? extends ActivityCallback> callbackClass, boolean loadEager, Module...modules) { Module combinedReplacements = Modules.combine(modules); Module combinedOriginals = Modules.combine(new LimeWireCoreModule(callbackClass), new BlockingConnectionFactoryModule()); Module replaced = Modules.override(combinedOriginals).with(combinedReplacements); Injector injector = Guice.createInjector(Stage.DEVELOPMENT, replaced); if(loadEager) GuiceUtils.loadEagerSingletons(injector); return injector; } /** * 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 */ private static Injector createInjectorAndStart(Class<? extends ActivityCallback> callbackClass, Module...modules) { // Use PRODUCTION to ensure all Services are created. Injector injector = createInjector(callbackClass, true, 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(StringUtils.toAsciiBytes("CONNECT ")); 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)); } } /** * Creates a module for the objects that will inject all @Inject members in * the object. */ public static Module createModule(final Object... objects) { return new AbstractModule() { @Override protected void configure() { for(Object object : objects) { requestInjection(object); } } }; } private static List<File> getBuildFolders(File root) { final List<File> paths = new ArrayList<File>(); // add all components that have a build/classes dir. root.listFiles(new FileFilter() { @Override public boolean accept(File pathname) { File classes = new File(pathname, "build/classes"); if(classes.exists()) { paths.add(classes); } return false; } }); return paths; } /** * Returns all non-test build folders. */ public static List<File> getBuildFolders(Class clazz) throws Exception { File f = TestUtils.getResourceInPackage(clazz.getSimpleName() + ".class", clazz).getCanonicalFile(); // step out to find the root folder of the component int packageDepth = StringUtils.countOccurrences(clazz.getName(), '.'); // + 1 to back out of top level package for (int i = 0; i < packageDepth + 1; i++) { f = f.getParentFile(); } // f now == <something>/limewire/[private-]components/component/build/tests // we want to back out to <something>/limewire // build/ component/ components/ limewire/ f = f.getParentFile().getParentFile().getParentFile().getParentFile(); final List<File> paths = new ArrayList<File>(); paths.addAll(getBuildFolders(new File(f, "components"))); paths.addAll(getBuildFolders(new File(f, "private-components"))); if (paths.size() < 10) { throw new IOException("didn't find all classes: " + paths); } return paths; } /** * Returns all non-test class files. */ public static Set<File> getAllClassFiles(Class clazz) throws Exception { List<File> buildFolders = getBuildFolders(clazz); Set<File> classFiles = new HashSet<File>(); for (File buildFolder : buildFolders) { classFiles.addAll(Arrays.asList(FileUtils.getFilesRecursive(buildFolder, "class"))); } return classFiles; } }