|
|
|
|
|
package org.airsonic.player.service.search;
|
|
|
|
|
|
import com.codahale.metrics.ConsoleReporter;
|
|
|
import com.codahale.metrics.MetricRegistry;
|
|
|
import com.codahale.metrics.Timer;
|
|
|
import org.airsonic.player.dao.AlbumDao;
|
|
|
import org.airsonic.player.dao.MusicFolderDao;
|
|
|
import org.airsonic.player.domain.Album;
|
|
|
import org.airsonic.player.domain.Artist;
|
|
|
import org.airsonic.player.domain.MediaFile;
|
|
|
import org.airsonic.player.domain.MediaFile.MediaType;
|
|
|
import org.airsonic.player.domain.MusicFolder;
|
|
|
import org.airsonic.player.domain.ParamSearchResult;
|
|
|
import org.airsonic.player.domain.RandomSearchCriteria;
|
|
|
import org.airsonic.player.domain.SearchCriteria;
|
|
|
import org.airsonic.player.domain.SearchResult;
|
|
|
import org.airsonic.player.service.SearchService;
|
|
|
import org.junit.Assert;
|
|
|
import org.junit.Before;
|
|
|
import org.junit.Test;
|
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
|
import org.subsonic.restapi.ArtistID3;
|
|
|
|
|
|
import java.util.Arrays;
|
|
|
import java.util.List;
|
|
|
import java.util.Random;
|
|
|
import java.util.concurrent.TimeUnit;
|
|
|
|
|
|
public class SearchServiceTestCase extends AbstractAirsonicHomeTest {
|
|
|
|
|
|
@Autowired
|
|
|
private AlbumDao albumDao;
|
|
|
|
|
|
private final MetricRegistry metrics = new MetricRegistry();
|
|
|
|
|
|
@Autowired
|
|
|
private MusicFolderDao musicFolderDao;
|
|
|
|
|
|
@Autowired
|
|
|
private SearchService searchService;
|
|
|
|
|
|
@Before
|
|
|
public void setup() {
|
|
|
populateDatabaseOnlyOnce();
|
|
|
}
|
|
|
|
|
|
@Test
|
|
|
public void testSearchTypical() {
|
|
|
|
|
|
/*
|
|
|
* A simple test that is expected to easily detect API syntax differences when updating lucene.
|
|
|
* Complete route coverage and data coverage in this case alone are not conscious.
|
|
|
*/
|
|
|
|
|
|
List<MusicFolder> allMusicFolders = musicFolderDao.getAllMusicFolders();
|
|
|
Assert.assertEquals(3, allMusicFolders.size());
|
|
|
|
|
|
// *** testSearch() ***
|
|
|
|
|
|
String query = "Sarah Walker";
|
|
|
final SearchCriteria searchCriteria = new SearchCriteria();
|
|
|
searchCriteria.setQuery(query);
|
|
|
searchCriteria.setCount(Integer.MAX_VALUE);
|
|
|
searchCriteria.setOffset(0);
|
|
|
|
|
|
/*
|
|
|
* _ID3_ALBUMARTIST_ Sarah Walker/Nash Ensemble
|
|
|
* Should find any version of Lucene.
|
|
|
*/
|
|
|
SearchResult result = searchService.search(searchCriteria, allMusicFolders,
|
|
|
IndexType.ALBUM);
|
|
|
Assert.assertEquals("(0) Specify '" + query + "' as query, total Hits is", 1,
|
|
|
result.getTotalHits());
|
|
|
Assert.assertEquals("(1) Specify artist '" + query + "' as query. Artist SIZE is", 0,
|
|
|
result.getArtists().size());
|
|
|
Assert.assertEquals("(2) Specify artist '" + query + "' as query. Album SIZE is", 0,
|
|
|
result.getAlbums().size());
|
|
|
Assert.assertEquals("(3) Specify artist '" + query + "' as query, MediaFile SIZE is", 1,
|
|
|
result.getMediaFiles().size());
|
|
|
Assert.assertEquals("(4) ", MediaType.ALBUM, result.getMediaFiles().get(0).getMediaType());
|
|
|
Assert.assertEquals(
|
|
|
"(5) Specify artist '" + query + "' as query, and get a album. Name is ",
|
|
|
"_ID3_ALBUMARTIST_ Sarah Walker/Nash Ensemble",
|
|
|
result.getMediaFiles().get(0).getArtist());
|
|
|
Assert.assertEquals(
|
|
|
"(6) Specify artist '" + query + "' as query, and get a album. Name is ",
|
|
|
"_ID3_ALBUM_ Ravel - Chamber Music With Voice",
|
|
|
result.getMediaFiles().get(0).getAlbumName());
|
|
|
|
|
|
/*
|
|
|
* _ID3_ALBUM_ Ravel - Chamber Music With Voice
|
|
|
* Should find any version of Lucene.
|
|
|
*/
|
|
|
query = "music";
|
|
|
searchCriteria.setQuery(query);
|
|
|
result = searchService.search(searchCriteria, allMusicFolders, IndexType.ALBUM_ID3);
|
|
|
Assert.assertEquals("Specify '" + query + "' as query, total Hits is", 1,
|
|
|
result.getTotalHits());
|
|
|
Assert.assertEquals("(7) Specify '" + query + "' as query, and get a song. Artist SIZE is ",
|
|
|
0, result.getArtists().size());
|
|
|
Assert.assertEquals("(8) Specify '" + query + "' as query, and get a song. Album SIZE is ",
|
|
|
1, result.getAlbums().size());
|
|
|
Assert.assertEquals(
|
|
|
"(9) Specify '" + query + "' as query, and get a song. MediaFile SIZE is ", 0,
|
|
|
result.getMediaFiles().size());
|
|
|
Assert.assertEquals("(9) Specify '" + query + "' as query, and get a album. Name is ",
|
|
|
"_ID3_ALBUMARTIST_ Sarah Walker/Nash Ensemble",
|
|
|
result.getAlbums().get(0).getArtist());
|
|
|
Assert.assertEquals("(10) Specify '" + query + "' as query, and get a album. Name is ",
|
|
|
"_ID3_ALBUM_ Ravel - Chamber Music With Voice",
|
|
|
result.getAlbums().get(0).getName());
|
|
|
|
|
|
/*
|
|
|
* _ID3_ALBUM_ Ravel - Chamber Music With Voice
|
|
|
* Should find any version of Lucene.
|
|
|
*/
|
|
|
query = "Ravel - Chamber Music";
|
|
|
searchCriteria.setQuery(query);
|
|
|
result = searchService.search(searchCriteria, allMusicFolders, IndexType.SONG);
|
|
|
Assert.assertEquals("(11) Specify album '" + query + "' as query, total Hits is", 2,
|
|
|
result.getTotalHits());
|
|
|
Assert.assertEquals("(12) Specify album '" + query + "', and get a song. Artist SIZE is", 0,
|
|
|
result.getArtists().size());
|
|
|
Assert.assertEquals("(13) Specify album '" + query + "', and get a song. Album SIZE is", 0,
|
|
|
result.getAlbums().size());
|
|
|
Assert.assertEquals("(14) Specify album '" + query + "', and get a song. MediaFile SIZE is",
|
|
|
2, result.getMediaFiles().size());
|
|
|
Assert.assertEquals("(15) Specify album '" + query + "', and get songs. The first song is ",
|
|
|
"01 - Gaspard de la Nuit - i. Ondine", result.getMediaFiles().get(0).getTitle());
|
|
|
Assert.assertEquals(
|
|
|
"(16) Specify album '" + query + "', and get songs. The second song is ",
|
|
|
"02 - Gaspard de la Nuit - ii. Le Gibet", result.getMediaFiles().get(1).getTitle());
|
|
|
|
|
|
// *** testSearchByName() ***
|
|
|
|
|
|
/*
|
|
|
* _ID3_ALBUM_ Sackcloth 'n' Ashes
|
|
|
* Should be 1 in Lucene 3.0(Because Single quate is not a delimiter).
|
|
|
*/
|
|
|
query = "Sackcloth 'n' Ashes";
|
|
|
ParamSearchResult<Album> albumResult = searchService.searchByName(query, 0,
|
|
|
Integer.MAX_VALUE, allMusicFolders, Album.class);
|
|
|
Assert.assertEquals(
|
|
|
"(17) Specify album name '" + query + "' as the name, and get an album.", 1,
|
|
|
albumResult.getItems().size());
|
|
|
Assert.assertEquals("(18) Specify '" + query + "' as the name, The album name is ",
|
|
|
"_ID3_ALBUM_ Sackcloth 'n' Ashes", albumResult.getItems().get(0).getName());
|
|
|
Assert.assertEquals(
|
|
|
"(19) Whether the acquired album contains data of the specified album name", 1L,
|
|
|
albumResult.getItems().stream()
|
|
|
.filter(r -> "_ID3_ALBUM_ Sackcloth \'n\' Ashes".equals(r.getName()))
|
|
|
.count());
|
|
|
|
|
|
/*
|
|
|
* Should be 0 in Lucene 3.0(Since the slash is not a delimiter).
|
|
|
*/
|
|
|
query = "lker/Nash";
|
|
|
ParamSearchResult<ArtistID3> artistId3Result = searchService.searchByName(query, 0,
|
|
|
Integer.MAX_VALUE, allMusicFolders, ArtistID3.class);
|
|
|
Assert.assertEquals("(20) Specify '" + query + "' as the name, and get an artist.", 0,
|
|
|
artistId3Result.getItems().size());
|
|
|
ParamSearchResult<Artist> artistResult = searchService.searchByName(query, 0,
|
|
|
Integer.MAX_VALUE, allMusicFolders, Artist.class);
|
|
|
|
|
|
/*
|
|
|
* // XXX 3.x -> 8.x :
|
|
|
* Hit 'Nash*' as the slash becomes a delimiter.
|
|
|
*/
|
|
|
Assert.assertEquals("(21) Specify '" + query + "' as the name, and get an artist.", 1,
|
|
|
artistResult.getItems().size());
|
|
|
|
|
|
// *** testGetRandomSongs() ***
|
|
|
|
|
|
/*
|
|
|
* Regardless of the Lucene version,
|
|
|
* RandomSearchCriteria can specify null and means the maximum range.
|
|
|
* 11 should be obtainable.
|
|
|
*/
|
|
|
RandomSearchCriteria randomSearchCriteria = new RandomSearchCriteria(Integer.MAX_VALUE, // count
|
|
|
null, // genre,
|
|
|
null, // fromYear
|
|
|
null, // toYear
|
|
|
allMusicFolders // musicFolders
|
|
|
);
|
|
|
List<MediaFile> allRandomSongs = searchService.getRandomSongs(randomSearchCriteria);
|
|
|
Assert.assertEquals(
|
|
|
"(22) Specify MAX_VALUE as the upper limit, and randomly acquire songs.", 11,
|
|
|
allRandomSongs.size());
|
|
|
|
|
|
/*
|
|
|
* Regardless of the Lucene version,
|
|
|
* 7 should be obtainable.
|
|
|
*/
|
|
|
randomSearchCriteria = new RandomSearchCriteria(Integer.MAX_VALUE, // count
|
|
|
null, // genre,
|
|
|
1900, // fromYear
|
|
|
null, // toYear
|
|
|
allMusicFolders // musicFolders
|
|
|
);
|
|
|
allRandomSongs = searchService.getRandomSongs(randomSearchCriteria);
|
|
|
Assert.assertEquals("(23) Specify 1900 as 'fromYear', and randomly acquire songs.", 7,
|
|
|
allRandomSongs.size());
|
|
|
|
|
|
/*
|
|
|
* Regardless of the Lucene version,
|
|
|
* It should be 0 because it is a non-existent genre.
|
|
|
*/
|
|
|
randomSearchCriteria = new RandomSearchCriteria(Integer.MAX_VALUE, // count
|
|
|
"Chamber Music", // genre,
|
|
|
null, // fromYear
|
|
|
null, // toYear
|
|
|
allMusicFolders // musicFolders
|
|
|
);
|
|
|
allRandomSongs = searchService.getRandomSongs(randomSearchCriteria);
|
|
|
Assert.assertEquals("(24) Specify music as 'genre', and randomly acquire songs.", 0,
|
|
|
allRandomSongs.size());
|
|
|
|
|
|
/*
|
|
|
* Genre including blank.
|
|
|
* Regardless of the Lucene version, It should be 2.
|
|
|
*/
|
|
|
randomSearchCriteria = new RandomSearchCriteria(Integer.MAX_VALUE, // count
|
|
|
"Baroque Instrumental", // genre,
|
|
|
null, // fromYear
|
|
|
null, // toYear
|
|
|
allMusicFolders // musicFolders
|
|
|
);
|
|
|
allRandomSongs = searchService.getRandomSongs(randomSearchCriteria);
|
|
|
Assert.assertEquals("(25) Search by specifying genres including spaces and hyphens.", 2,
|
|
|
allRandomSongs.size());
|
|
|
|
|
|
// *** testGetRandomAlbums() ***
|
|
|
|
|
|
/*
|
|
|
* Acquisition of maximum number(5).
|
|
|
*/
|
|
|
List<Album> allAlbums = albumDao.getAlphabeticalAlbums(0, Integer.MAX_VALUE, true, true, allMusicFolders);
|
|
|
Assert.assertEquals("(26) Get all albums with Dao.", 5, allAlbums.size());
|
|
|
List<MediaFile> allRandomAlbums = searchService.getRandomAlbums(Integer.MAX_VALUE,
|
|
|
allMusicFolders);
|
|
|
Assert.assertEquals("(27) Specify Integer.MAX_VALUE as the upper limit,"
|
|
|
+ "and randomly acquire albums(file struct).", 5, allRandomAlbums.size());
|
|
|
|
|
|
/*
|
|
|
* Acquisition of maximum number(5).
|
|
|
*/
|
|
|
List<Album> allRandomAlbumsId3 = searchService.getRandomAlbumsId3(Integer.MAX_VALUE,
|
|
|
allMusicFolders);
|
|
|
Assert.assertEquals(
|
|
|
"(28) Specify Integer.MAX_VALUE as the upper limit, and randomly acquire albums(ID3).",
|
|
|
5, allRandomAlbumsId3.size());
|
|
|
|
|
|
/*
|
|
|
* Total is 4.
|
|
|
*/
|
|
|
query = "ID 3 ARTIST";
|
|
|
searchCriteria.setQuery(query);
|
|
|
result = searchService.search(searchCriteria, allMusicFolders, IndexType.ARTIST_ID3);
|
|
|
Assert.assertEquals("(29) Specify '" + query + "', total Hits is", 4,
|
|
|
result.getTotalHits());
|
|
|
Assert.assertEquals("(30) Specify '" + query + "', and get an artists. Artist SIZE is ", 4,
|
|
|
result.getArtists().size());
|
|
|
Assert.assertEquals("(31) Specify '" + query + "', and get a artists. Album SIZE is ", 0,
|
|
|
result.getAlbums().size());
|
|
|
Assert.assertEquals("(32) Specify '" + query + "', and get a artists. MediaFile SIZE is ",
|
|
|
0, result.getMediaFiles().size());
|
|
|
|
|
|
/*
|
|
|
* Three hits to the artist.
|
|
|
* ALBUMARTIST is not registered with these.
|
|
|
* Therefore, the registered value of ARTIST is substituted in ALBUMARTIST.
|
|
|
*/
|
|
|
long count = result.getArtists().stream()
|
|
|
.filter(a -> a.getName().startsWith("_ID3_ARTIST_")).count();
|
|
|
Assert.assertEquals("(33) Artist whose name contains \\\"_ID3_ARTIST_\\\" is 3 records.",
|
|
|
3L, count);
|
|
|
|
|
|
/*
|
|
|
* The structure of "01 - Sonata Violin & Cello I. Allegro.ogg"
|
|
|
* ARTIST -> _ID3_ARTIST_ Sarah Walker/Nash Ensemble
|
|
|
* ALBUMARTIST -> _ID3_ALBUMARTIST_ Sarah Walker/Nash Ensemble
|
|
|
* (The result must not contain duplicates. And ALBUMARTIST must be returned correctly.)
|
|
|
*/
|
|
|
count = result.getArtists().stream()
|
|
|
.filter(a -> a.getName().startsWith("_ID3_ALBUMARTIST_")).count();
|
|
|
Assert.assertEquals("(34) Artist whose name is \"_ID3_ARTIST_\" is 1 records.", 1L, count);
|
|
|
|
|
|
/*
|
|
|
* Below is a simple loop test.
|
|
|
* How long is the total time?
|
|
|
*/
|
|
|
int countForEachMethod = 500;
|
|
|
String[] randomWords4Search = createRandomWords(countForEachMethod);
|
|
|
String[] randomWords4SearchByName = createRandomWords(countForEachMethod);
|
|
|
|
|
|
Timer globalTimer = metrics
|
|
|
.timer(MetricRegistry.name(SearchServiceTestCase.class, "Timer.global"));
|
|
|
final Timer.Context globalTimerContext = globalTimer.time();
|
|
|
|
|
|
System.out.println("--- Random search (" + countForEachMethod * 5 + " times) ---");
|
|
|
|
|
|
// testSearch()
|
|
|
Arrays.stream(randomWords4Search).forEach(w -> {
|
|
|
searchCriteria.setQuery(w);
|
|
|
searchService.search(searchCriteria, allMusicFolders, IndexType.ALBUM);
|
|
|
});
|
|
|
|
|
|
// testSearchByName()
|
|
|
Arrays.stream(randomWords4SearchByName).forEach(w -> {
|
|
|
searchService.searchByName(w, 0, Integer.MAX_VALUE, allMusicFolders, Artist.class);
|
|
|
});
|
|
|
|
|
|
// testGetRandomSongs()
|
|
|
RandomSearchCriteria criteria = new RandomSearchCriteria(Integer.MAX_VALUE, // count
|
|
|
null, // genre,
|
|
|
null, // fromYear
|
|
|
null, // toYear
|
|
|
allMusicFolders // musicFolders
|
|
|
);
|
|
|
for (int i = 0; i < countForEachMethod; i++) {
|
|
|
searchService.getRandomSongs(criteria);
|
|
|
}
|
|
|
|
|
|
// testGetRandomAlbums()
|
|
|
for (int i = 0; i < countForEachMethod; i++) {
|
|
|
searchService.getRandomAlbums(Integer.MAX_VALUE, allMusicFolders);
|
|
|
}
|
|
|
|
|
|
// testGetRandomAlbumsId3()
|
|
|
for (int i = 0; i < countForEachMethod; i++) {
|
|
|
searchService.getRandomAlbumsId3(Integer.MAX_VALUE, allMusicFolders);
|
|
|
}
|
|
|
|
|
|
globalTimerContext.stop();
|
|
|
|
|
|
/*
|
|
|
* Whether or not IndexReader is exhausted.
|
|
|
*/
|
|
|
query = "Sarah Walker";
|
|
|
searchCriteria.setQuery(query);
|
|
|
result = searchService.search(searchCriteria, allMusicFolders, IndexType.ALBUM);
|
|
|
Assert.assertEquals("(35) Can the normal case be implemented.", 0,
|
|
|
result.getArtists().size());
|
|
|
Assert.assertEquals("(36) Can the normal case be implemented.", 0,
|
|
|
result.getAlbums().size());
|
|
|
Assert.assertEquals("(37) Can the normal case be implemented.", 1,
|
|
|
result.getMediaFiles().size());
|
|
|
Assert.assertEquals("(38) Can the normal case be implemented.", MediaType.ALBUM,
|
|
|
result.getMediaFiles().get(0).getMediaType());
|
|
|
Assert.assertEquals("(39) Can the normal case be implemented.",
|
|
|
"_ID3_ALBUMARTIST_ Sarah Walker/Nash Ensemble",
|
|
|
result.getMediaFiles().get(0).getArtist());
|
|
|
|
|
|
System.out.println("--- SUCCESS ---");
|
|
|
|
|
|
ConsoleReporter reporter = ConsoleReporter.forRegistry(metrics)
|
|
|
.convertRatesTo(TimeUnit.SECONDS).convertDurationsTo(TimeUnit.MILLISECONDS).build();
|
|
|
reporter.report();
|
|
|
|
|
|
System.out.println("End. ");
|
|
|
}
|
|
|
|
|
|
private static String[] createRandomWords(int count) {
|
|
|
String[] randomStrings = new String[count];
|
|
|
Random random = new Random();
|
|
|
for (int i = 0; i < count; i++) {
|
|
|
char[] word = new char[random.nextInt(8) + 3];
|
|
|
for (int j = 0; j < word.length; j++) {
|
|
|
word[j] = (char) ('a' + random.nextInt(26));
|
|
|
}
|
|
|
randomStrings[i] = new String(word);
|
|
|
}
|
|
|
return randomStrings;
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|