package com.limegroup.bittorrent.swarm; import java.io.File; import java.io.IOException; import java.net.URI; import java.security.NoSuchAlgorithmException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import junit.framework.Test; import org.limewire.collection.Range; import org.limewire.http.reactor.LimeConnectingIOReactorFactory; import org.limewire.swarm.SwarmCoordinator; import org.limewire.swarm.SwarmCoordinatorListener; import org.limewire.swarm.SwarmFileSystem; import org.limewire.swarm.SwarmSourceType; import org.limewire.swarm.Swarmer; import org.limewire.swarm.http.SwarmHttpSource; import org.limewire.swarm.http.SwarmHttpSourceDownloader; import org.limewire.swarm.impl.EchoSwarmCoordinatorListener; import org.limewire.swarm.impl.SwarmerImpl; import org.limewire.util.AssertComparisons; import org.limewire.util.FileUtils; import org.limewire.util.TestUtils; import com.google.inject.Guice; import com.google.inject.Injector; import com.limegroup.bittorrent.BTContext; import com.limegroup.bittorrent.BTMetaInfo; import com.limegroup.bittorrent.BTMetaInfoFactory; import com.limegroup.bittorrent.FileServer; import com.limegroup.bittorrent.TorrentContext; import com.limegroup.bittorrent.TorrentFileSystem; import com.limegroup.bittorrent.disk.DiskManagerFactory; import com.limegroup.bittorrent.disk.LoggingDiskListener; import com.limegroup.bittorrent.disk.TorrentDiskManager; import com.limegroup.bittorrent.handshaking.piecestrategy.LargestGapStartPieceStrategy; import com.limegroup.bittorrent.handshaking.piecestrategy.PieceStrategy; import com.limegroup.bittorrent.handshaking.piecestrategy.RandomGapStrategy; import com.limegroup.bittorrent.handshaking.piecestrategy.RandomPieceStrategy; import com.limegroup.gnutella.LimeWireCoreModule; import com.limegroup.gnutella.stubs.ActivityCallbackStub; import com.limegroup.gnutella.util.LimeTestCase; public class BTSwarmCoordinatorTest extends LimeTestCase { private static final int TEST_PORT = 8080; /** * A directory containing the torrent data for this unit test. */ public static final File TORRENT_DIR = TestUtils .getResourceFile("org/limewire/swarm/bittorrent/public_html/torrents"); /** * A directory containing the torrent data for this unit test. */ public static final File FILE_DIR = TestUtils .getResourceFile("org/limewire/swarm/bittorrent/public_html"); private FileServer fileServer = null; private Injector injector; private BTMetaInfoFactory metaInfoFactory; public BTSwarmCoordinatorTest(String name) { super(name); } public static Test suite() { return buildTestSuite(BTSwarmCoordinatorTest.class); } @Override protected void setUp() throws Exception { injector = Guice.createInjector(new LimeWireCoreModule(ActivityCallbackStub.class)); metaInfoFactory = injector.getInstance(BTMetaInfoFactory.class); fileServer = new FileServer(TEST_PORT, FILE_DIR); fileServer.start(); } @Override protected void tearDown() throws Exception { fileServer.stop(); fileServer.destroy(); } public void testSingleFileTorrent() throws Exception { File torrentFile = getFile("test-single-webseed-single-file-no-peer.torrent"); final BTMetaInfo metaInfo = metaInfoFactory.createMetaInfo(torrentFile); final TorrentContext torrentContext = new BTContext(metaInfo, new DiskManagerFactory()); TorrentFileSystem torrentFileSystem = torrentContext.getFileSystem(); File completeFile = torrentFileSystem.getCompleteFile(); completeFile.delete(); File downloadedFile = torrentFileSystem.getIncompleteFiles().get(0); downloadedFile.delete(); completeFile.deleteOnExit(); downloadedFile.deleteOnExit(); final Swarmer swarmer = createSwarmer(torrentContext, null); swarmer.start(); long totalSize = torrentFileSystem.getTotalSize(); URI uri = metaInfo.getWebSeeds()[0]; swarmer.addSource(new SwarmHttpSource(uri, totalSize)); assertDownload(swarmer, "8055d620ba0c507c1af957b43648c99f", downloadedFile, 44425); } public void testMultiFileTorrentDefaultPieceStrategy() throws Exception { File torrentFile = getFile("test-single-webseed-multiple-file-no-peer.torrent"); final BTMetaInfo metaInfo = metaInfoFactory.createMetaInfo(torrentFile); final TorrentContext torrentContext = new BTContext(metaInfo, new DiskManagerFactory()); TorrentFileSystem torrentFileSystem = torrentContext.getFileSystem(); File completeFile = torrentFileSystem.getCompleteFile(); completeFile.delete(); File downloadedFile1 = torrentFileSystem.getIncompleteFiles().get(0); File downloadedFile2 = torrentFileSystem.getIncompleteFiles().get(1); downloadedFile1.delete(); downloadedFile2.delete(); completeFile.deleteOnExit(); downloadedFile1.deleteOnExit(); downloadedFile2.deleteOnExit(); final Swarmer swarmer = createSwarmer(torrentContext, null); swarmer.start(); long totalSize = torrentFileSystem.getTotalSize(); URI uri = metaInfo.getWebSeeds()[0]; swarmer.addSource(new SwarmHttpSource(uri, totalSize)); assertDownload(swarmer, "8055d620ba0c507c1af957b43648c99f", downloadedFile1, 44425); assertDownload(swarmer, "db1dc452e77d30ce14acca6bac8c66bc", downloadedFile2, 411090); } public void testMultiFileTorrentRandomGapStrategy() throws Exception { File torrentFile = getFile("test-single-webseed-multiple-file-no-peer.torrent"); final BTMetaInfo metaInfo = metaInfoFactory.createMetaInfo(torrentFile); final TorrentContext torrentContext = new BTContext(metaInfo, new DiskManagerFactory()); TorrentFileSystem torrentFileSystem = torrentContext.getFileSystem(); File completeFile = torrentFileSystem.getCompleteFile(); completeFile.delete(); File downloadedFile1 = torrentFileSystem.getIncompleteFiles().get(0); File downloadedFile2 = torrentFileSystem.getIncompleteFiles().get(1); downloadedFile1.delete(); downloadedFile2.delete(); completeFile.deleteOnExit(); downloadedFile1.deleteOnExit(); downloadedFile2.deleteOnExit(); final Swarmer swarmer = createSwarmer(torrentContext, new RandomGapStrategy(metaInfo)); swarmer.start(); long totalSize = torrentFileSystem.getTotalSize(); URI uri = metaInfo.getWebSeeds()[0]; swarmer.addSource(new SwarmHttpSource(uri, totalSize)); assertDownload(swarmer, "8055d620ba0c507c1af957b43648c99f", downloadedFile1, 44425); assertDownload(swarmer, "db1dc452e77d30ce14acca6bac8c66bc", downloadedFile2, 411090); } public void testMultiFileTorrentLargestGapStartPieceStrategy() throws Exception { File torrentFile = getFile("test-single-webseed-multiple-file-no-peer.torrent"); final BTMetaInfo metaInfo = metaInfoFactory.createMetaInfo(torrentFile); final TorrentContext torrentContext = new BTContext(metaInfo, new DiskManagerFactory()); TorrentFileSystem torrentFileSystem = torrentContext.getFileSystem(); File completeFile = torrentFileSystem.getCompleteFile(); completeFile.delete(); File downloadedFile1 = torrentFileSystem.getIncompleteFiles().get(0); File downloadedFile2 = torrentFileSystem.getIncompleteFiles().get(1); downloadedFile1.delete(); downloadedFile2.delete(); completeFile.deleteOnExit(); downloadedFile1.deleteOnExit(); downloadedFile2.deleteOnExit(); final Swarmer swarmer = createSwarmer(torrentContext, new LargestGapStartPieceStrategy( metaInfo)); swarmer.start(); long totalSize = torrentFileSystem.getTotalSize(); URI uri = metaInfo.getWebSeeds()[0]; swarmer.addSource(new SwarmHttpSource(uri, totalSize)); assertDownload(swarmer, "8055d620ba0c507c1af957b43648c99f", downloadedFile1, 44425); assertDownload(swarmer, "db1dc452e77d30ce14acca6bac8c66bc", downloadedFile2, 411090); } public void testVuzeCreatedTorrent() throws Exception { File torrentFile = getFile("test_vuze_getright.torrent"); final BTMetaInfo metaInfo = metaInfoFactory.createMetaInfo(torrentFile); final TorrentContext torrentContext = new BTContext(metaInfo, new DiskManagerFactory()); TorrentFileSystem torrentFileSystem = torrentContext.getFileSystem(); File completeFile = torrentFileSystem.getCompleteFile(); completeFile.delete(); File downloadedFile1 = torrentFileSystem.getIncompleteFiles().get(0); downloadedFile1.delete(); completeFile.deleteOnExit(); downloadedFile1.deleteOnExit(); final Swarmer swarmer = createSwarmer(torrentContext, new LargestGapStartPieceStrategy( metaInfo)); swarmer.start(); long totalSize = torrentFileSystem.getTotalSize(); URI uri1 = metaInfo.getWebSeeds()[0]; URI uri2 = metaInfo.getWebSeeds()[1]; swarmer.addSource(new SwarmHttpSource(uri1, totalSize)); swarmer.addSource(new SwarmHttpSource(uri2, totalSize)); assertDownload(swarmer, "8055d620ba0c507c1af957b43648c99f", downloadedFile1, 44425); } public void testMultipleWebseedSingleFileTorrent() throws Exception { File torrentFile = getFile("test-multiple-webseed-single-file-no-peer.torrent"); final BTMetaInfo metaInfo = metaInfoFactory.createMetaInfo(torrentFile); final TorrentContext torrentContext = new BTContext(metaInfo, new DiskManagerFactory()); TorrentFileSystem torrentFileSystem = torrentContext.getFileSystem(); File completeFile = torrentFileSystem.getCompleteFile(); completeFile.delete(); File downloadedFile1 = torrentFileSystem.getIncompleteFiles().get(0); downloadedFile1.delete(); completeFile.deleteOnExit(); downloadedFile1.deleteOnExit(); final Swarmer swarmer = createSwarmer(torrentContext, new LargestGapStartPieceStrategy( metaInfo)); swarmer.start(); long totalSize = torrentFileSystem.getTotalSize(); URI uri1 = metaInfo.getWebSeeds()[0]; URI uri2 = metaInfo.getWebSeeds()[1]; URI uri3 = metaInfo.getWebSeeds()[2]; swarmer.addSource(new SwarmHttpSource(uri1, totalSize)); swarmer.addSource(new SwarmHttpSource(uri2, totalSize)); swarmer.addSource(new SwarmHttpSource(uri3, totalSize)); assertDownload(swarmer, "8055d620ba0c507c1af957b43648c99f", downloadedFile1, 44425); } private File getFile(String fileName) { File torrentFile = new File(TORRENT_DIR.getAbsoluteFile() + "/" + fileName); return torrentFile; } private Swarmer createSwarmer(TorrentContext torrentContext, PieceStrategy pieceStrategy) throws IOException { if (pieceStrategy == null) { pieceStrategy = new RandomPieceStrategy(torrentContext.getMetaInfo()); } TorrentFileSystem torrentFileSystem = torrentContext.getFileSystem(); TorrentDiskManager torrentDiskManager = torrentContext.getDiskManager(); torrentDiskManager.open(new LoggingDiskListener()); final BTSwarmCoordinator btCoordinator = new BTSwarmCoordinator(torrentContext .getMetaInfo(), torrentFileSystem, torrentDiskManager, pieceStrategy); btCoordinator.addListener(new EchoSwarmCoordinatorListener()); Swarmer swarmer = new SwarmerImpl(btCoordinator); swarmer.register(SwarmSourceType.HTTP, new SwarmHttpSourceDownloader(injector .getInstance(LimeConnectingIOReactorFactory.class), btCoordinator, "LimeTest/1.1")); return swarmer; } /** * Asserts that the given file has the correct size, and matches the given * md5sum. */ private void assertDownload(Swarmer swarmer, String md5, File file, long fileSize) throws InterruptedException, NoSuchAlgorithmException, IOException { SwarmCoordinator swarmCoordinator = swarmer.getCoordinator(); final CountDownLatch countDownLatch = new CountDownLatch(1); swarmCoordinator.addListener(new SwarmCoordinatorListener() { @Override public void blockLeased(SwarmCoordinator swarmCoordinator, Range block) { } @Override public void blockPending(SwarmCoordinator swarmCoordinator, Range block) { } @Override public void blockUnleased(SwarmCoordinator swarmCoordinator, Range block) { } @Override public void blockUnpending(SwarmCoordinator swarmCoordinator, Range block) { } @Override public void blockVerificationFailed(SwarmCoordinator swarmCoordinator, Range block) { } @Override public void blockVerified(SwarmCoordinator swarmCoordinator, Range block) { } @Override public void blockWritten(SwarmCoordinator swarmCoordinator, Range block) { } @Override public void downloadCompleted(SwarmCoordinator swarmCoordinator, SwarmFileSystem fileSystem) { countDownLatch.countDown(); } }); countDownLatch.await(5, TimeUnit.SECONDS); AssertComparisons.assertTrue(file.exists()); AssertComparisons.assertEquals(fileSize, file.length()); String testmd5 = FileUtils.getMD5(file); AssertComparisons.assertEquals(md5, testmd5); } // TODO test better variety of torrent files. // TODO test larger torrent files. }