package com.limegroup.gnutella.xml; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Set; import java.util.Collections; import java.io.ObjectOutputStream; import java.io.BufferedOutputStream; import java.io.FileOutputStream; import junit.framework.Test; import com.limegroup.gnutella.FileDesc; import com.limegroup.gnutella.URN; import com.limegroup.gnutella.metadata.MetaDataReader; import com.limegroup.gnutella.util.CommonUtils; import com.limegroup.gnutella.util.Expand; import com.limegroup.gnutella.util.NameValue; import com.limegroup.gnutella.stubs.FileManagerStub; public class CollectionTest extends com.limegroup.gnutella.util.BaseTestCase { FileDesc[] files = new FileDesc[3]; final String fileLocation = "com/limegroup/gnutella/xml/"; final File mason = CommonUtils.getResourceFile(fileLocation + "nullfile.null"); final File test1 = CommonUtils.getResourceFile(fileLocation + "test1.mp3"); final File test2 = CommonUtils.getResourceFile(fileLocation + "test2.mp3"); final String audioSchemaURI = "http://www.limewire.com/schemas/audio.xsd"; final String videoSchemaURI = "http://www.limewire.com/schemas/video.xsd"; private final String KEY_PREFIX = "audios" + XMLStringUtils.DELIMITER + "audio" + XMLStringUtils.DELIMITER; private final String ARTIST_KEY = KEY_PREFIX + "artist" + XMLStringUtils.DELIMITER; private final String ALBUM_KEY = KEY_PREFIX + "album" + XMLStringUtils.DELIMITER; private final String TITLE_KEY = KEY_PREFIX + "title" + XMLStringUtils.DELIMITER; private final String TRACK_KEY = KEY_PREFIX + "track" + XMLStringUtils.DELIMITER; private final String BITRATE_KEY = KEY_PREFIX + "bitrate" + XMLStringUtils.DELIMITER; public CollectionTest(String name) { super(name); } public static void main(String argv[]) { junit.textui.TestRunner.run(suite()); } public static Test suite() { return buildTestSuite(CollectionTest.class); } protected void setUp() throws Exception { files = new FileDesc[3]; assertTrue("Necessary file nullfile.null cannot be found!", mason.exists()); assertTrue("Necessary file test1.mp3 cannot be found!", test1.exists()); assertTrue("Necessary file test2.mp3 cannot be found!", test2.exists()); Set urns; urns = calculateAndCacheURN(mason); files[0] = new FileDesc(mason, urns, 0); urns = calculateAndCacheURN(test1); files[1] = new FileDesc(test1, urns, 1); urns = calculateAndCacheURN(test2); files[2] = new FileDesc(test2, urns, 2); } public void testAudio() { clearDirectory(); // test construction LimeXMLReplyCollection collection = new LimeXMLReplyCollection(audioSchemaURI); assertEquals(0, collection.getCount()); for(int i = 0; i < files.length; i++) collection.initialize(files[i], Collections.EMPTY_LIST); assertEquals(0, collection.getCount()); for(int i = 0; i < files.length; i++) collection.createIfNecessary(files[i]); assertEquals("LimeXMLCollection count wrong!", 2, collection.getCount()); // test assocation LimeXMLDocument doc = null; doc = collection.getDocForHash(getHash(mason)); assertNull("Mason should not have a doc!", doc); doc = collection.getDocForHash(getHash(test1)); assertNotNull("Test1 should have a doc!", doc); doc = collection.getDocForHash(getHash(test2)); assertNotNull("Test2 should have a doc!", doc); // test keyword generation List keywords = collection.getKeyWords(); assertEquals("Wrong keywords: " + keywords.toString(), 8, keywords.size()); //Note: the Test1 and Test2 both contain the keyword "Movie", so we //check only 7 keywords while there are 8 entries assertTrue("Correct keywords not in map!", (keywords.contains("othertfield") && keywords.contains("otherafield") && keywords.contains("Other") && keywords.contains("tfield") && keywords.contains("afield") && keywords.contains("Vocal") && keywords.contains("Movie") ) ); } public void testVideo() { clearDirectory(); // test construction LimeXMLReplyCollection collection = new LimeXMLReplyCollection(videoSchemaURI); assertEquals(0, collection.getCount()); for(int i = 0; i < files.length; i++) collection.initialize(files[i], Collections.EMPTY_LIST); assertEquals(0, collection.getCount()); for(int i = 0; i < files.length; i++) collection.createIfNecessary(files[i]); assertEquals(0, collection.getCount()); // test assocation LimeXMLDocument doc = null; doc = collection.getDocForHash(getHash(mason)); assertNull("Mason should not have a doc!", doc); doc = collection.getDocForHash(getHash(test1)); assertNull("Test1 should not have a doc!", doc); doc = collection.getDocForHash(getHash(test2)); assertNull("Test2 should not have a doc!", doc); // test keyword generation List keywords = collection.getKeyWords(); assertEquals("Wrong keyword count!", 0, keywords.size()); } public void testMatching() { clearDirectory(); LimeXMLReplyCollection collection = new LimeXMLReplyCollection(audioSchemaURI); assertEquals(0, collection.getCount()); for(int i = 0; i < files.length; i++) collection.initialize(files[i], Collections.EMPTY_LIST); assertEquals(0, collection.getCount()); for(int i = 0; i < files.length; i++) collection.createIfNecessary(files[i]); assertEquals("LimeXMLCollection count wrong!", 2, collection.getCount()); // make sure that a simple match works.... List nameVals = new ArrayList(); nameVals.add(new NameValue(TITLE_KEY, "tfie")); LimeXMLDocument searchDoc = new LimeXMLDocument(nameVals, audioSchemaURI); List results = collection.getMatchingReplies(searchDoc); assertEquals("Not the correct amount of results", 1, results.size()); // Ensure that a search for a matching title doesn't work // if we put it in the artist field ... nameVals = new ArrayList(); nameVals.add(new NameValue(ARTIST_KEY, "tfie")); searchDoc = new LimeXMLDocument(nameVals, audioSchemaURI); results = collection.getMatchingReplies(searchDoc); assertEquals("Not the correct amount of results", 0, results.size()); // make sure a little more complex match works, no mp3 has album but one // has a title beginning with s nameVals.clear(); nameVals.add(new NameValue(ALBUM_KEY, "susheel")); nameVals.add(new NameValue(TITLE_KEY, "o")); searchDoc = new LimeXMLDocument(nameVals, audioSchemaURI); results = collection.getMatchingReplies(searchDoc); assertEquals("Not the correct amount of results", 1, results.size()); // has two matching, one null nameVals.clear(); nameVals.add(new NameValue(TITLE_KEY, "tfield")); nameVals.add(new NameValue(ALBUM_KEY, "ignored")); nameVals.add(new NameValue(ARTIST_KEY, "afield")); searchDoc = new LimeXMLDocument(nameVals, audioSchemaURI); results = collection.getMatchingReplies(searchDoc); assertEquals("Not the correct amount of results", 1, results.size()); // has two matching nameVals.clear(); nameVals.add(new NameValue(TITLE_KEY, "othertf")); nameVals.add(new NameValue(ARTIST_KEY, "otherafi")); searchDoc = new LimeXMLDocument(nameVals, audioSchemaURI); results = collection.getMatchingReplies(searchDoc); assertEquals("Not the correct amount of results", 1, results.size()); // has one off by one.... nameVals.clear(); nameVals.add(new NameValue(TITLE_KEY, "othert")); nameVals.add(new NameValue(ARTIST_KEY, "othra")); searchDoc = new LimeXMLDocument(nameVals, audioSchemaURI); results = collection.getMatchingReplies(searchDoc); assertEquals("Not the correct amount of results", 0, results.size()); // has all nulls, this was a terrible bug in previous versions... nameVals.clear(); nameVals.add(new NameValue(ALBUM_KEY, "swi")); nameVals.add(new NameValue(TRACK_KEY, "ferb")); searchDoc = new LimeXMLDocument(nameVals, audioSchemaURI); results = collection.getMatchingReplies(searchDoc); assertEquals("Not the correct amount of results", 0, results.size()); // has all nulls, this was a terrible bug in previous versions... nameVals.clear(); nameVals.add(new NameValue(TRACK_KEY, "ferb")); searchDoc = new LimeXMLDocument(nameVals, audioSchemaURI); results = collection.getMatchingReplies(searchDoc); assertEquals("Not the correct amount of results", 0, results.size()); // test matching on numeric value ... nameVals.clear(); nameVals.add(new NameValue(BITRATE_KEY, "64")); searchDoc = new LimeXMLDocument(nameVals, audioSchemaURI); results = collection.getMatchingReplies(searchDoc); assertEquals("Not the correct amount of results", 2, results.size()); // test things don't match on partial numeric value... nameVals.clear(); nameVals.add(new NameValue(BITRATE_KEY, "6")); searchDoc = new LimeXMLDocument(nameVals, audioSchemaURI); results = collection.getMatchingReplies(searchDoc); assertEquals("Not the correct amount of results", 0, results.size()); } public void testSerialized() throws Exception { createFiles(); populateDirectory(); LimeXMLReplyCollection audioCollection = new LimeXMLReplyCollection(audioSchemaURI); LimeXMLReplyCollection videoCollection = new LimeXMLReplyCollection(videoSchemaURI); assertEquals(0, audioCollection.getCount()); assertEquals(0, videoCollection.getCount()); for(int i = 0; i < files.length; i++) audioCollection.initialize(files[i], Collections.EMPTY_LIST); assertEquals("LimeXMLCollection count wrong!", 2, audioCollection.getCount()); for(int i = 0; i < files.length; i++) videoCollection.initialize(files[i], Collections.EMPTY_LIST); assertEquals("LimeXMLCollection count wrong!", 2, videoCollection.getCount()); // test assocation assertNull("Mason should not have a doc!", audioCollection.getDocForHash(getHash(mason))); assertNotNull("Test1 should have a doc!", audioCollection.getDocForHash(getHash(test1))); assertNotNull("Test2 should have a doc!", audioCollection.getDocForHash(getHash(test2))); assertNotNull("Mason should have a doc!", videoCollection.getDocForHash(getHash(mason))); assertNull("Test1 should not have a doc!", videoCollection.getDocForHash(getHash(test1))); assertNotNull("Test2 should have a doc!", videoCollection.getDocForHash(getHash(test2))); // test keyword generation List keywords = audioCollection.getKeyWords(); assertEquals("Wrong keyword count!", 8, keywords.size()); assertTrue("Correct keywords not in map!", (keywords.contains("othertfield") && keywords.contains("otherafield") && keywords.contains("Other") && keywords.contains("tfield") && keywords.contains("afield") && keywords.contains("Vocal") && keywords.contains("Movie") ) ); keywords = videoCollection.getKeyWords(); assertEquals("Wrong keyword count!", 4, keywords.size()); assertTrue("Correct keywords not in map!", (keywords.contains("null") && keywords.contains("file") && keywords.contains("susheel") && keywords.contains("daswani") ) ); clearDirectory(); } //test LimeXMLReplyCollection with i18n chars public void testI18NCharsInXML() throws Exception { String[] keywds = {"\u9234\u6728\u6b66\u8535\u69d8", "thestudio", "\u5bae\u672c"}; String dir1 = "director=\"" + keywds[0] + "\""; String dir2 = dir1 + " studio=\"" + keywds[1] + "\""; String dir3 = dir1 + " studio=\"" + keywds[2] + "\""; LimeXMLReplyCollection collection = new LimeXMLReplyCollection(videoSchemaURI); LimeXMLDocument newDoc = new LimeXMLDocument(buildXMLString(dir2)); LimeXMLDocument newDoc2 = new LimeXMLDocument(buildXMLString(dir3)); //addReply calls addKeywords (which uses I18NConvert) collection.addReply(files[0], newDoc); collection.addReply(files[1], newDoc2); //check the keywords. List l = collection.getKeyWords(); assertTrue("Couldn't find all keywords", (l.contains(keywds[0]) && l.contains(keywds[1]) && l.contains(keywds[2]))); //the query document LimeXMLDocument newDocQ = new LimeXMLDocument(buildXMLString(dir1)); LimeXMLDocument newDocQ2 = new LimeXMLDocument(buildXMLString(dir3)); //make sure we get matches that we expect l = collection.getMatchingReplies(newDocQ); assertEquals("should of found two matches", 2, l.size()); l = collection.getMatchingReplies(newDocQ2); assertEquals("should of found only one match", 1, l.size()); //make sure we get the same xml string... assertEquals("didn't get expected xml string", newDoc2.getXMLString(), ((LimeXMLDocument)l.iterator().next()).getXMLString()); //check we get the right docs back from getDocForHash LimeXMLDocument returnDoc = collection.getDocForHash(files[0].getSHA1Urn()); assertEquals("didn't get expected xml string (getDocForHash)", newDoc.getXMLString(), returnDoc.getXMLString()); returnDoc = collection.getDocForHash(files[1].getSHA1Urn()); assertEquals("didn't get expected xml string (getDocForHash)", newDoc2.getXMLString(), returnDoc.getXMLString()); //remove collection.removeDoc(files[1]); l = collection.getMatchingReplies(newDocQ2); assertEquals("should not of found a match", 0, l.size()); //make sure the keywords got deleted as well l = collection.getKeyWords(); assertTrue("unexpected keywords", l.contains(keywds[0]) && l.contains(keywds[1]) && !l.contains(keywds[2])); } // build xml string for video private String buildXMLString(String keyname) { return "<?xml version=\"1.0\"?><videos xsi:noNamespaceSchemaLocation=\"http://www.limewire.com/schemas/video.xsd\"><video " + keyname + "></video></videos>"; } private void clearDirectory() { File dir = new File(LimeXMLProperties.instance().getXMLDocsDir()); if (dir.exists() && dir.isDirectory()) { // clear the files in the directory.... File[] files = dir.listFiles(); for (int i = 0; i < files.length; i++) files[i].delete(); } } private void createFiles() throws Exception { HashMap map = new HashMap(); LimeXMLDocument doc = null; // make audio.collection doc = MetaDataReader.readDocument(test1); map.put(getHash(test1), doc); doc = MetaDataReader.readDocument(test2); map.put(getHash(test2), doc); File marker = CommonUtils.getResourceFile(fileLocation + "nullfile.null"); marker = marker.getParentFile(); write(map, new File(marker, "audio.collection")); // made video.collection List nameVals = new ArrayList(); map = new HashMap(); nameVals.add(new NameValue("videos__video__director__","daswani")); nameVals.add(new NameValue("videos__video__title__","susheel")); doc = new LimeXMLDocument(nameVals, videoSchemaURI); doc.setIdentifier(test2); doc.getXMLString(); map.put(getHash(test2), doc); nameVals = new ArrayList(); nameVals.add(new NameValue("videos__video__director__","file")); nameVals.add(new NameValue("videos__video__title__","null")); doc = new LimeXMLDocument("<?xml version=\"1.0\"?><videos xsi:noNamespaceSchemaLocation=\"http://www.limewire.com/schemas/video.xsd\"><video title=\"null\" director=\"file\" ></video></videos>"); doc.setIdentifier(mason); doc.getXMLString(); map.put(getHash(mason), doc); write(map, new File(marker, "video.collection")); } private void write(Object o, File f) throws Exception { ObjectOutputStream out = new ObjectOutputStream(new BufferedOutputStream(new FileOutputStream(f))); out.writeObject(o); out.flush(); out.close(); } private void populateDirectory() { File audioFile = CommonUtils.getResourceFile(fileLocation + "audio.collection"); File videoFile = CommonUtils.getResourceFile(fileLocation + "video.collection"); File newAudio = new File(LimeXMLProperties.instance().getXMLDocsDir(), "audio.sxml"); File newVideo = new File(LimeXMLProperties.instance().getXMLDocsDir(), "video.sxml"); assertTrue("Necessary file audio.collection cannot be found!", audioFile.exists()); assertTrue("Necessary file video.collection cannot be found!", videoFile.exists()); audioFile.renameTo(newAudio); videoFile.renameTo(newVideo); } private static URN getHash(File f) { try { return URN.createSHA1Urn(f); } catch(IOException ioe) { return null; } catch(InterruptedException ie) { return null; } } }