package com.limegroup.gnutella.library; import java.io.File; import java.util.ArrayList; import java.util.List; import junit.framework.Test; import org.limewire.core.settings.SearchSettings; import org.limewire.io.GUID; import org.limewire.util.MediaType; import com.limegroup.gnutella.Response; import com.limegroup.gnutella.messages.QueryRequest; import com.limegroup.gnutella.xml.LimeXMLDocument; /** * Integration tests for query handling */ public class KeywordIndexFileManagerIntegrationTest extends FileManagerTestCase { public KeywordIndexFileManagerIntegrationTest(String name) { super(name); } public static Test suite() { return buildTestSuite(KeywordIndexFileManagerIntegrationTest.class); } /** * Test plaintext searching to ensure that shared files' metadata is searched. * * This tests the following scenarios with 1 contrived audio file and its * corresponding metadata: * * 1. Exact match of metadata field * 2. Prefix match of metadata field * 3. Prefix match of metadata field with varying case * 4. All keywords in search are in at least 1 field of metadata * 5. All keywords in search are NOT found in any metadata NOR file name - should not match * 6. Metadata field text + additional text should not match (negative test) * 7. Exact or Prefix match of filename should still show up as result (regression) * 8. Search term that matches both file name and metadata * should return only 1 result * 9. Removing file from file manager results in both exact matches * and prefix matches failing (negative test) * 10. Exact or Prefix match of filename should still show up as result (regression) * */ public void testMetadataResultsForPlaintextQuerySingleFile() throws Exception { waitForLoad(); // test a query where the filename is meaningless but XML matches. File f1 = createNewNamedTestFile(10, "meaningless"); LimeXMLDocument d1 = limeXMLDocumentFactory.createLimeXMLDocument(FileManagerTestUtils.buildAudioXMLString( "artist=\"Sammy B\" album=\"Jazz in A minor\" genre=\"mean Median Standard Deviation\" ")); List<LimeXMLDocument> l1 = new ArrayList<LimeXMLDocument>(); l1.add(d1); FileListChangedEvent result = addIfShared(f1, l1); assertTrue(result.toString(), result.getType() == FileListChangedEvent.Type.ADDED); assertEquals(d1, result.getFileDesc().getLimeXMLDocuments().get(0)); // test exact match of keywords in metadata Response[] responses = keywordIndex.query(queryRequestFactory.createRequery("Sammy B")); assertEquals(1, responses.length); assertEquals(d1.getXMLString(), responses[0].getDocument().getXMLString()); // test exact match on album in metadata responses = keywordIndex.query(queryRequestFactory.createQuery("Jazz in A minor")); assertEquals(1, responses.length); assertEquals(d1.getXMLString(), responses[0].getDocument().getXMLString()); // test searching metadata fields with prefixes responses = keywordIndex.query(queryRequestFactory.createQuery("Sam")); assertEquals(1, responses.length); assertEquals(d1.getXMLString(), responses[0].getDocument().getXMLString()); responses = keywordIndex.query(queryRequestFactory.createQuery("Ja")); assertEquals(1, responses.length); assertEquals(d1.getXMLString(), responses[0].getDocument().getXMLString()); // test searching metadata fields with prefixes of varying case responses = keywordIndex.query(queryRequestFactory.createQuery("sAm")); assertEquals(1, responses.length); assertEquals(d1.getXMLString(), responses[0].getDocument().getXMLString()); responses = keywordIndex.query(queryRequestFactory.createQuery("jaZZ In")); assertEquals(1, responses.length); assertEquals(d1.getXMLString(), responses[0].getDocument().getXMLString()); // matching: all of the search term's keywords are contained // in at least 1 metadata field responses = keywordIndex.query(queryRequestFactory.createQuery("median standard deviation")); assertEquals(1, responses.length); assertEquals(d1.getXMLString(), responses[0].getDocument().getXMLString()); responses = keywordIndex.query(queryRequestFactory.createQuery("A Minor")); assertEquals(1, responses.length); assertEquals(d1.getXMLString(), responses[0].getDocument().getXMLString()); // not matching: none of the metadata fields nor file name // match all keywords in search term responses = keywordIndex.query(queryRequestFactory.createQuery("variance median deviation")); assertEquals(0, responses.length); // not matching: String contains full metadata but has additional text responses = keywordIndex.query(queryRequestFactory.createQuery("Sammy B XYZ")); assertEquals(0, responses.length); // not matching: Search contains prefix but also contains additional text responses = keywordIndex.query(queryRequestFactory.createQuery("sammm")); assertEquals(0, responses.length); // search something that is in just the file name prefix responses = keywordIndex.query(queryRequestFactory.createQuery("meaningless")); assertEquals(1, responses.length); assertEquals(d1.getXMLString(), responses[0].getDocument().getXMLString()); // search something that is in both the file name prefix AND the metadata // Make sure there is only 1 search result responses = keywordIndex.query(queryRequestFactory.createQuery("mean")); assertEquals(1, responses.length); assertEquals(d1.getXMLString(), responses[0].getDocument().getXMLString()); // search something that is neither in the file name NOR the metadata responses = keywordIndex.query(queryRequestFactory.createQuery("No Matches")); assertEquals(0, responses.length); // remove file fman.getManagedFileList().remove(f1); // no more matches responses = keywordIndex.query(queryRequestFactory.createQuery("Sammy B")); assertEquals(0, responses.length); // test on album responses = keywordIndex.query(queryRequestFactory.createQuery("Jazz in A minor")); assertEquals(0, responses.length); // prefixes responses = keywordIndex.query(queryRequestFactory.createQuery("Sam")); assertEquals(0, responses.length); } /** * Test plaintext searching with multiple files indexed. The files are in * multiple media types. * * The following scenarios are tested: * * 1. All keywords in search match 1 file name (should return 1 match) * Search term "four six" matches "eight four six.mp3 * 2. All keywords match multiple times for the same document (should return 1 match) * 3. All keywords in search match, but not for the same file. (should return 0 matches) * Search term "seven nine", files "eight four six.txt", "seven.txt" and "nine.avi" * 4. Search with keyword that matches in different metadata fields of different files (matches) * 5. Every keyword in search matches in a metadata field, but not for the same file. (No matches) * 6. Every keyword in search matches for the same file, but not in same metadata field. (1 Match) * 7. Every keyword in search matches in same metadata field name but for different files (No matches) * 8. Search keyword matches prefix of metadata or file name for multiple files. * All files that matched are returned. * 9. Removing file from file manager results in both exact matches * and prefix matches (file name or metadata) NO LONGER MATCHING for the file that was removed * */ public void testPlaintextQueryMultipleFilesMultipleMediaTypes() throws Exception { waitForLoad(); File eightFourSixFile = createNewNamedTestFile(10, "eight four six.mp3"); LimeXMLDocument eightFourSixXml = limeXMLDocumentFactory.createLimeXMLDocument( FileManagerTestUtils.buildAudioXMLString("artist=\"sixty seven\" album=\"zero one\" genre=\"five numerically\" ")); List<LimeXMLDocument> l1 = new ArrayList<LimeXMLDocument>(); l1.add(eightFourSixXml); addIfShared(eightFourSixFile, l1); File f2 = createNewNamedTestFile(10, "seven.txt"); LimeXMLDocument seven = limeXMLDocumentFactory.createLimeXMLDocument( FileManagerTestUtils.buildDocumentXMLString("title=\"front page stuff\" author=\"special writer\" " + "topic=\"interesting stuff\"")); List<LimeXMLDocument> l2 = new ArrayList<LimeXMLDocument>(); l2.add(seven); addIfShared(f2, l2); File f3 = createNewNamedTestFile(10, "nine.avi"); LimeXMLDocument nine = limeXMLDocumentFactory.createLimeXMLDocument( FileManagerTestUtils.buildVideoXMLString("director=\"one interesting tree\" title=\"Eight Four David\"")); List<LimeXMLDocument> l3 = new ArrayList<LimeXMLDocument>(); l3.add(nine); addIfShared(f3, l3); File algebraFile = createNewNamedTestFile(10, "class time.txt"); LimeXMLDocument algebraXml = limeXMLDocumentFactory.createLimeXMLDocument( FileManagerTestUtils.buildDocumentXMLString("title=\"plus minus\" " + "author=\"equals\" " + "topic=\"matrix eigenvalue\"")); List<LimeXMLDocument> l4 = new ArrayList<LimeXMLDocument>(); l4.add(algebraXml); addIfShared(algebraFile, l4); // 1. All keywords in search term match file name responses = keywordIndex.query(queryRequestFactory.createQuery("four six")); assertEquals(1, responses.length); assertEquals(eightFourSixXml.getXMLString(), responses[0].getDocument().getXMLString()); // 2. keyword matches multiple times for the same document responses = keywordIndex.query(queryRequestFactory.createQuery("six")); assertEquals(1, responses.length); assertTrue(responsesContain(eightFourSixXml)); // 3. Every keyword in search matches, but not for the same file. responses = keywordIndex.query(queryRequestFactory.createQuery("seven nine")); assertEquals(0, responses.length); // 4. search with 1 keyword that matches in different metadata fields of different files responses = keywordIndex.query(queryRequestFactory.createQuery("interesting")); assertEquals(2, responses.length); assertTrue(responsesContain(seven, nine)); // 5. Every keyword in search matches in a metadata field, but not for the same file. responses = keywordIndex.query(queryRequestFactory.createQuery("plus special writer")); assertEquals(0, responses.length); // 6. Every keyword in search matches for same file, but not in same metadata field responses = keywordIndex.query(queryRequestFactory.createQuery("interesting front page stuff")); assertEquals(1, responses.length); // 7. Every keyword in search matches in same metadata field name but for different files (No matches) responses = keywordIndex.query(queryRequestFactory.createQuery("front plus minus")); assertEquals(0, responses.length); // 8. Search keyword matches prefix of metadata or file name for multiple files. // All files that matched are returned. responses = keywordIndex.query(queryRequestFactory.createQuery("eig")); assertEquals(3, responses.length); assertTrue(responsesContain(algebraXml, nine, eightFourSixXml)); // remove a file for which "eig" matches in the metadata fman.getManagedFileList().remove(algebraFile); // 9. Perform same query as before, and while the other files should still match, // the removed file should no longer match responses = keywordIndex.query(queryRequestFactory.createQuery("eig")); assertEquals(2, responses.length); assertTrue(responsesContain(eightFourSixXml, nine)); assertFalse(responsesContain(algebraXml)); } /** * Tests metadata keyword searching. * * 1. If a file's metadata has an attribute "title='one six eight'", a metadata search * for "title='six eight'" should succeed because it matches all keywords for that attribute. * * 2. Given a file with metadata of "title='one six eight'", a metadata search * for "title='six eight ten'" should fail because although 2 keywords match that attribute, * 1 keyword does not match. The keyword that does not match for "title" may match in another metadata * field such as "artist" or "album". */ public void testMetaQueryKeywordMatching() throws Exception { waitForLoad(); File eightFourSixFile = createNewNamedTestFile(10, "eight four six.mp3"); LimeXMLDocument eightFourSixXml = limeXMLDocumentFactory.createLimeXMLDocument( FileManagerTestUtils.buildAudioXMLString("artist=\"sixty seven\" album=\"zero one\" genre=\"five nine sixty\" ")); List<LimeXMLDocument> l1 = new ArrayList<LimeXMLDocument>(); l1.add(eightFourSixXml); addIfShared(eightFourSixFile, l1); responses = keywordIndex.query(queryRequestFactory.createQuery("", FileManagerTestUtils.buildAudioXMLString("genre=\"nine\""))); assertEquals(1, responses.length); assertTrue(responsesContain(eightFourSixXml)); responses = keywordIndex.query(queryRequestFactory.createQuery("", FileManagerTestUtils.buildAudioXMLString("genre=\"five nine one\""))); assertEquals(0, responses.length); } /** * Given the following shared files: * * #1. An audio file with title "one two three four" * #2. A video file with title "one two three four" * * A query request with query string "one two three four" and * media type "audio" should only match file #1. * */ public void testMetadataResultsForPlaintextQueryWithSpecificMimeType() throws Exception { waitForLoad(); File f1 = createNewNamedTestFile(10, "audioFile"); LimeXMLDocument audioMetaData = limeXMLDocumentFactory.createLimeXMLDocument(FileManagerTestUtils.buildAudioXMLString( "artist=\"one two tree\" album=\"Jazz in A minor\" genre=\"mean\" ")); List<LimeXMLDocument> l1 = new ArrayList<LimeXMLDocument>(); File f2 = createNewNamedTestFile(10, "videoFile"); LimeXMLDocument videoMetaData = limeXMLDocumentFactory.createLimeXMLDocument( FileManagerTestUtils.buildVideoXMLString("director=\"one two tree\" title=\"Four five Six\"")); List<LimeXMLDocument> l2 = new ArrayList<LimeXMLDocument>(); l1.add(audioMetaData); l2.add(videoMetaData); addIfShared(f1, l1); addIfShared(f2, l2); // A query request with query string "one two three four" and // media type "audio" should only match the file named "audioFile". String queryString = "one two tree"; QueryRequest queryAudio = queryRequestFactory.createQuery(GUID.makeGuid(), queryString, "", MediaType.getAudioMediaType()); Response[] responses = keywordIndex.query(queryAudio); assertEquals(1, responses.length); assertEquals(audioMetaData.getXMLString(), responses[0].getDocument().getXMLString()); // A query request with query string "one two three four" and // media type "video" should only match the file named "videoFile". QueryRequest queryVideo = queryRequestFactory.createQuery(GUID.makeGuid(), queryString, "", MediaType.getVideoMediaType()); responses = keywordIndex.query(queryVideo); assertEquals(1, responses.length); assertEquals(videoMetaData.getXMLString(), responses[0].getDocument().getXMLString()); // A query request with query string "one two three four" and // media type "video" should only match the file named "videoFile". QueryRequest queryPrograms = queryRequestFactory.createQuery(GUID.makeGuid(), queryString, "", MediaType.getProgramMediaType()); responses = keywordIndex.query(queryPrograms); assertEquals(0, responses.length); } /** * Test that if the search setting "INCLUDE_METADATA_IN_PLAINTEXT_SEARCH" is set to false, * plaintext queries that match the metadata of shared files will not show up as results. * */ public void testMetadataResultsForPlaintextQueryWithSearchSettingTurnedOff() throws Exception { waitForLoad(); // test a query where the filename is meaningless but XML matches. File f1 = createNewNamedTestFile(10, "meaningless"); LimeXMLDocument d1 = limeXMLDocumentFactory.createLimeXMLDocument(FileManagerTestUtils.buildAudioXMLString( "artist=\"Sammy B\" album=\"Jazz in A minor\" genre=\"mean\" ")); List<LimeXMLDocument> l1 = new ArrayList<LimeXMLDocument>(); l1.add(d1); addIfShared(f1, l1); assertTrue(SearchSettings.INCLUDE_METADATA_IN_PLAINTEXT_SEARCH.getValue()); SearchSettings.INCLUDE_METADATA_IN_PLAINTEXT_SEARCH.setValue(false); // test that with the setting set to false, plaintext queries on the metadata // do not succeed, but file name searches still succeed // file search should succeed responses = keywordIndex.query(queryRequestFactory.createQuery("meaningle")); assertEquals(1, responses.length); assertEquals(d1.getXMLString(), responses[0].getDocument().getXMLString()); // plaintext search of metadata should fail responses = keywordIndex.query(queryRequestFactory.createQuery("Sammy")); assertEquals(0, responses.length); // turn the setting back on, and plaintext searches of metadata should succeed. SearchSettings.INCLUDE_METADATA_IN_PLAINTEXT_SEARCH.setValue(true); // file search should still succeed responses = keywordIndex.query(queryRequestFactory.createQuery("meaning")); assertEquals(1, responses.length); assertEquals(d1.getXMLString(), responses[0].getDocument().getXMLString()); // plaintext search of metadata should succeed responses = keywordIndex.query(queryRequestFactory.createQuery("Sammy")); assertEquals(1, responses.length); assertEquals(d1.getXMLString(), responses[0].getDocument().getXMLString()); } /** * Make sure a "What is New" query does not search the meta data, * nor should it search file names. It should only get the 3 files that were most * recently shared. */ public void testWhatIsNewQueryDoesNotSearchMetaData() throws Exception { waitForLoad(); // create and add files to file manager with associated metadata // // This file contains the "whatisnewxoxo" string in the metadata addFileWithMetaDataToFileManager("fileShouldNotShowUpInWhat-Is-New.txt", FileManagerTestUtils.buildAudioXMLString( "artist=\"WhatIsNewXOXO\" album=\"Badd in A minor\" genre=\"mean\" ")); addFileWithMetaDataToFileManager("145random", FileManagerTestUtils.buildAudioXMLString( "artist=\"should not show up\" album=\"Radd on A minor\" genre=\"mean\" ")); addFileWithMetaDataToFileManager("987abctrees", FileManagerTestUtils.buildAudioXMLString( "artist=\"should not show up\" album=\"Faze in A minor\" genre=\"mean\" ")); addFileWithMetaDataToFileManager("search123.txt", FileManagerTestUtils.buildAudioXMLString( "artist=\"lll two tree\" album=\"Raze in A minor\" genre=\"mean\" ")); addFileWithMetaDataToFileManager("456search.txt", FileManagerTestUtils.buildAudioXMLString( "artist=\"nnn two tree\" album=\"Daze in A minor\" genre=\"mean\" ")); addFileWithMetaDataToFileManager("678attempt.txt", FileManagerTestUtils.buildAudioXMLString( "artist=\"ooo two tree\" album=\"Paze in A minor\" genre=\"mean\" ")); QueryRequest query = queryRequestFactory.createWhatIsNewQuery(GUID.makeGuid(), (byte)3); // sanity check! assertTrue(query.isWhatIsNewRequest()); responses = keywordIndex.query(query); assertEquals(3, responses.length); // make sure that none of the "what is new" responses correspond to the // older file which contained "whatisnewxoxo" in its metadata for (Response response : responses) { assertFalse(response.getName().startsWith("fileShouldNotShowUpInWhat-Is-New.txt")); } // create query with "whatisnewxoxo" as query string, and // make sure "fileShouldNotShowUpInWhat-Is-New.txt" shows up as a result. responses = keywordIndex.query(queryRequestFactory.createQuery("WhatIsNewXOXO")); assertEquals(1, responses.length); assertTrue(responses[0].getName().startsWith("fileShouldNotShowUpInWhat-Is-New.txt")); } /** * Make sure the response to a "What is New" query contains metadata. */ public void testWhatsNewSearchResponseContainsMetaData() throws Exception { waitForLoad(); addFileWithMetaDataToFileManager("678attempt.txt", FileManagerTestUtils.buildAudioXMLString( "artist=\"ooo two tree\" album=\"Paze in A minor\" genre=\"mean\" ")); QueryRequest query = queryRequestFactory.createWhatIsNewQuery(GUID.makeGuid(), (byte)3); responses = keywordIndex.query(query); assertEquals(1, responses.length); assertNotNull(responses[0].getDocument()); } private void addFileWithMetaDataToFileManager(String name, String xml) throws Exception { File f1 = createNewNamedTestFile(10, name); LimeXMLDocument metaData = limeXMLDocumentFactory.createLimeXMLDocument(xml); List<LimeXMLDocument> l1 = new ArrayList<LimeXMLDocument>(); l1.add(metaData); addIfShared(f1, l1); Thread.sleep(500); } }