package com.limegroup.gnutella.library; import java.io.File; import java.io.FileFilter; import java.io.FileOutputStream; import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Future; import junit.framework.Test; import org.limewire.concurrent.ExecutorsHelper; import org.limewire.gnutella.tests.LimeTestCase; import org.limewire.util.PrivilegedAccessor; import org.limewire.util.TestUtils; import com.limegroup.gnutella.URN; import com.limegroup.gnutella.UrnSet; import com.limegroup.gnutella.helpers.UrnHelper; public class CreationTimeCacheTest extends LimeTestCase { private URN hash1, hash2, hash3, hash4; private FileDesc fd1, fd2, fd3, fd4; private LibraryStub libraryStub; private GnutellaFileCollectionStub gnutellaFileCollectionStub; /** * File where urns (currently SHA1 urns) get persisted to */ private static final String CREATION_CACHE_FILE = "createtimes.cache"; private final String FILE_PATH = "com/limegroup/gnutella/util"; public CreationTimeCacheTest(String name) { super(name); } public static Test suite() { return buildTestSuite(CreationTimeCacheTest.class); } public static void main(String[] args) { junit.textui.TestRunner.run(suite()); } @Override public void setUp() throws Exception { hash1 = URN.createSHA1Urn("urn:sha1:GLIQY64M7FSXBSQEZY37FIM5QQSASUSH"); hash2 = URN.createSHA1Urn("urn:sha1:GLIQY64M7FSXBSQEZY37FIM5QQSANITA"); hash3 = URN.createSHA1Urn("urn:sha1:GLIQY64M7FSXBSQEZY37FIM5QQABOALT"); hash4 = URN.createSHA1Urn("urn:sha1:GLIQY64M7FSXBSQEZY37FIM5BERKELEY"); libraryStub = new LibraryStub(); gnutellaFileCollectionStub = new GnutellaFileCollectionStub(); fd1 = new FileDescStub("old", hash1, 0); fd2 = new FileDescStub("middle1", hash2, 1); fd3 = new FileDescStub("middle2", hash3, 2); fd4 = new FileDescStub("young", hash4, 3); gnutellaFileCollectionStub.add(fd1); gnutellaFileCollectionStub.add(fd2); gnutellaFileCollectionStub.add(fd3); gnutellaFileCollectionStub.add(fd4); } ///////////////////////// Actual Tests //////////////////////////// @SuppressWarnings("unchecked") private Map<URN, Long> getUrnToTime(CreationTimeCache cache) throws Exception { Future<?> future = (Future)PrivilegedAccessor.getValue(cache, "deserializer"); Object o = future.get(); return (Map<URN, Long>)PrivilegedAccessor.invokeMethod(o, "getUrnToTime"); } /** Tests that the URN_MAP is derived correctly from the URN_TO_TIME_MAP */ public void testMapCreation() throws Exception { // mock up our own createtimes.txt Map<URN, Long> toSerialize = new HashMap<URN, Long>(); Long old = new Long(1); Long middle = new Long(2); Long young = new Long(3); toSerialize.put(hash1, old); toSerialize.put(hash2, middle); toSerialize.put(hash3, middle); toSerialize.put(hash4, young); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File(_settingsDir, CREATION_CACHE_FILE))); oos.writeObject(toSerialize); oos.close(); // now have the CreationTimeCache read it in CreationTimeCache ctCache = new CreationTimeCache(libraryStub, gnutellaFileCollectionStub); Map map = getUrnToTime(ctCache); assertEquals(toSerialize, map); } public void testMapCreationNoExistingMap() throws Exception { CreationTimeCache creationTimeCache = new CreationTimeCache(libraryStub, gnutellaFileCollectionStub); Map<URN, Long> map = creationTimeCache.createMap(); assertTrue(map.isEmpty()); } /** Tests the getFiles().iterator() method. */ public void testGetFiles() throws Exception { // mock up our own createtimes.txt Map<URN, Long> toSerialize = new HashMap<URN, Long>(); Long old = new Long(1); Long middle = new Long(2); Long young = new Long(3); toSerialize.put(hash1, middle); toSerialize.put(hash2, young); toSerialize.put(hash3, old); toSerialize.put(hash4, middle); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new File(_settingsDir, CREATION_CACHE_FILE))); oos.writeObject(toSerialize); oos.close(); // now have the CreationTimeCache read it in CreationTimeCache ctCache = new CreationTimeCache(libraryStub, gnutellaFileCollectionStub); // is everything mapped correctly from URN to Long? assertEquals(ctCache.getCreationTime(hash1), middle); assertEquals(ctCache.getCreationTime(hash2), young); assertEquals(ctCache.getCreationTime(hash3), old); assertEquals(ctCache.getCreationTime(hash4), middle); { Iterator iter = ctCache.getFiles().iterator(); assertEquals(hash2, iter.next()); URN urn = (URN) iter.next(); assertTrue("was: " + urn, urn.equals(hash1) || urn.equals(hash4)); urn = (URN) iter.next(); assertTrue("was: " + urn, urn.equals(hash1) || urn.equals(hash4)); assertEquals(hash3, iter.next()); assertFalse(iter.hasNext()); } { Iterator iter = ctCache.getFiles(4).iterator(); assertEquals(hash2, iter.next()); URN urn = (URN) iter.next(); assertTrue(urn.equals(hash1) || urn.equals(hash4)); urn = (URN) iter.next(); assertTrue(urn.equals(hash1) || urn.equals(hash4)); assertEquals(hash3, iter.next()); assertFalse(iter.hasNext()); } { Iterator iter = ctCache.getFiles(3).iterator(); assertEquals(hash2, iter.next()); URN urn = (URN) iter.next(); assertTrue(urn.equals(hash1) || urn.equals(hash4)); urn = (URN) iter.next(); assertTrue(urn.equals(hash1) || urn.equals(hash4)); assertFalse(iter.hasNext()); } { Iterator iter = ctCache.getFiles(2).iterator(); assertEquals(hash2, iter.next()); URN urn = (URN) iter.next(); assertTrue(urn.equals(hash1) || urn.equals(hash4)); assertFalse(iter.hasNext()); } { Iterator iter = ctCache.getFiles(1).iterator(); assertEquals(hash2, iter.next()); assertFalse(iter.hasNext()); } { try { ctCache.getFiles(0).iterator(); fail("failed"); } catch (IllegalArgumentException expected) {} } } /** Tests the getFiles().iterator() method. */ public void testSettersAndGetters() throws Exception { Iterator iter = null; Map TIME_MAP = null; Long old = new Long(1); Long middle = new Long(2); Long young = new Long(3); deleteCacheFile(); // should be a empty cache // --------------------------- CreationTimeCache ctCache = new CreationTimeCache(libraryStub, gnutellaFileCollectionStub); assertFalse(ctCache.getFiles().iterator().hasNext()); TIME_MAP = getUrnToTime(ctCache); assertEquals(0, TIME_MAP.size()); ctCache.addTime(hash1, middle.longValue()); ctCache.commitTime(hash1); ctCache.persistCache(); iter = ctCache.getFiles().iterator(); assertEquals(hash1, iter.next()); assertFalse(iter.hasNext()); ctCache = null; // --------------------------- // should have one value // --------------------------- ctCache = new CreationTimeCache(libraryStub, gnutellaFileCollectionStub); // test the deserialization. iter = ctCache.getFiles().iterator(); assertEquals(hash1, iter.next()); assertFalse(iter.hasNext()); TIME_MAP = getUrnToTime(ctCache); assertEquals(1, TIME_MAP.size()); ctCache.addTime(hash2, old.longValue()); ctCache.commitTime(hash2); ctCache.addTime(hash3, young.longValue()); ctCache.commitTime(hash3); ctCache.addTime(hash4, middle.longValue()); ctCache.commitTime(hash4); ctCache.removeTime(hash1); ctCache.persistCache(); iter = ctCache.getFiles().iterator(); assertEquals(hash3, iter.next()); // just clear middle iter.next(); assertEquals(hash2, iter.next()); assertFalse(iter.hasNext()); ctCache = null; // --------------------------- // should have three values // --------------------------- ctCache = new CreationTimeCache(libraryStub, gnutellaFileCollectionStub); // test the deserialization. iter = ctCache.getFiles().iterator(); assertEquals(hash3, iter.next()); assertEquals(hash4, iter.next()); assertEquals(hash2, iter.next()); assertFalse(iter.hasNext()); TIME_MAP = getUrnToTime(ctCache); assertEquals(3, TIME_MAP.size()); ctCache.removeTime(hash3); ctCache.persistCache(); // --------------------------- // should have two values but exclude one // --------------------------- gnutellaFileCollectionStub.remove(fd4); ctCache = new CreationTimeCache(libraryStub, gnutellaFileCollectionStub); // test the deserialization. iter = ctCache.getFiles().iterator(); assertEquals(hash2, iter.next()); assertFalse(iter.hasNext()); TIME_MAP = getUrnToTime(ctCache); assertEquals(1, TIME_MAP.size()); } public void testCommit() throws Exception { CreationTimeCache ctCache = null; Iterator iter = null; Map TIME_MAP = null; Long old = new Long(1); Long middle = new Long(2); Long young = new Long(3); deleteCacheFile(); // should be a empty cache // --------------------------- ctCache = new CreationTimeCache(libraryStub, gnutellaFileCollectionStub); assertFalse(ctCache.getFiles().iterator().hasNext()); TIME_MAP = getUrnToTime(ctCache); assertEquals(0, TIME_MAP.size()); // --------------------------- // make sure that only after something is committed is it returned // via getFiles().iterator() // --------------------------- ctCache.addTime(hash1, middle.longValue()); iter = ctCache.getFiles().iterator(); assertFalse(iter.hasNext()); ctCache.commitTime(hash1); iter = ctCache.getFiles().iterator(); assertEquals(hash1, iter.next()); assertFalse(iter.hasNext()); // --------------------------- // make sure that commiting changes ordering.... // --------------------------- ctCache.addTime(hash2, young.longValue()); ctCache.addTime(hash3, old.longValue()); ctCache.commitTime(hash3); iter = ctCache.getFiles().iterator(); assertEquals(hash1, iter.next()); assertEquals(hash3, iter.next()); assertFalse(iter.hasNext()); ctCache.commitTime(hash2); iter = ctCache.getFiles().iterator(); assertEquals(hash2, iter.next()); assertEquals(hash1, iter.next()); assertEquals(hash3, iter.next()); assertFalse(iter.hasNext()); // --------------------------- } /** * Test read & write of map */ public void testPersistence() throws Exception { deleteCacheFile(); assertTrue("cache should not be present", !cacheExists() ); CreationTimeCache cache = new CreationTimeCache(libraryStub, gnutellaFileCollectionStub); Collection<URN> sha1s = createLotsOfSha1s(cache); assertNotNull("should have some file descs", sha1s); assertGreaterThan("should have some file descs", 0, sha1s.size()); cache.persistCache(); assertTrue("cache should now exist", cacheExists()); for(URN urn : sha1s) { Long cTime = cache.getCreationTime(urn); assertNotNull("file should be present in cache", cTime); } } private Collection<URN> createLotsOfSha1s(CreationTimeCache cache) throws Exception { File path = TestUtils.getResourceFile(FILE_PATH); File[] files = path.listFiles(new FileFilter() { public boolean accept(File file) { return !file.isDirectory(); } }); List<URN> sha1s = new ArrayList<URN>(); for(int i=0; i<files.length; i++) { Set<URN> urns = UrnHelper.calculateAndCacheURN(files[i], new UrnCache(ExecutorsHelper.newProcessingQueue("test"), null)); cache.addTime(UrnSet.getSha1(urns), files[i].lastModified()); sha1s.add(UrnSet.getSha1(urns)); } return sha1s; } private void deleteCacheFile() { File cacheFile = new File(_settingsDir, CREATION_CACHE_FILE); cacheFile.delete(); } /** * Convenience method for making sure that the serialized file exists. */ private boolean cacheExists() { File cacheFile = new File(_settingsDir, CREATION_CACHE_FILE); return cacheFile.exists(); } }