diff --git a/libresonic-main/pom.xml b/libresonic-main/pom.xml index 0d0a6234..c708318b 100644 --- a/libresonic-main/pom.xml +++ b/libresonic-main/pom.xml @@ -26,6 +26,15 @@ ${project.version} + + + io.dropwizard.metrics + metrics-core + ${metrics.version} + test + + + org.springframework spring-webmvc diff --git a/libresonic-main/src/main/java/org/libresonic/player/service/MediaScannerService.java b/libresonic-main/src/main/java/org/libresonic/player/service/MediaScannerService.java index 9b81e11e..445e79b5 100644 --- a/libresonic-main/src/main/java/org/libresonic/player/service/MediaScannerService.java +++ b/libresonic-main/src/main/java/org/libresonic/player/service/MediaScannerService.java @@ -70,6 +70,11 @@ public class MediaScannerService { schedule(); } + public void initNoSchedule() { + deleteOldIndexFiles(); + statistics = settingsService.getMediaLibraryStatistics(); + } + /** * Schedule background execution of media library scanning. */ diff --git a/libresonic-main/src/test/java/org/libresonic/player/TestCaseUtils.java b/libresonic-main/src/test/java/org/libresonic/player/TestCaseUtils.java new file mode 100644 index 00000000..7ef165a0 --- /dev/null +++ b/libresonic-main/src/test/java/org/libresonic/player/TestCaseUtils.java @@ -0,0 +1,93 @@ +package org.libresonic.player; + +import org.libresonic.player.dao.DaoHelper; +import org.libresonic.player.service.MediaScannerService; +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class TestCaseUtils { + + /** + * Constructs a map of records count per table. + * + * @param daoHelper DaoHelper object + * @return Map table name -> records count + */ + public static Map recordsInAllTables(DaoHelper daoHelper) { + List tableNames = daoHelper.getJdbcTemplate().queryForList("" + + "select table_name " + + "from information_schema.system_tables " + + "where table_name not like 'SYSTEM%'" + , String.class); + Map nbRecords = + tableNames.stream() + .collect(Collectors.toMap(table -> table, table -> recordsInTable(table,daoHelper))); + + return nbRecords; + } + + /** + * Counts records in a table. + * + * @param tableName + * @param daoHelper + * @return + */ + public static Integer recordsInTable(String tableName, DaoHelper daoHelper) { + return daoHelper.getJdbcTemplate().queryForInt("select count(1) from " + tableName); + } + + + /** + * Constructs the path of a resource according to the path of the current class. + * + * @param baseResources + * @return + */ + private static String basePath(String baseResources) { + String basePath = TestCaseUtils.class.getResource(baseResources).toString(); + if (basePath.startsWith("file:")) { + return TestCaseUtils.class.getResource(baseResources).toString().replace("file:",""); + } + return basePath; + } + + + public static void setLibresonicHome(String baseResources) { + String subsoncicHome = basePath(baseResources); + System.setProperty("libresonic.home",subsoncicHome); + } + + public static ApplicationContext loadSpringApplicationContext(String baseResources) { + String applicationContextService = baseResources + "applicationContext-service.xml"; + String applicationContextCache = baseResources + "applicationContext-cache.xml"; + + String[] configLocations = new String[]{ + TestCaseUtils.class.getClass().getResource(applicationContextCache).toString(), + TestCaseUtils.class.getClass().getResource(applicationContextService).toString() + }; + return new ClassPathXmlApplicationContext(configLocations); + } + + + /** + * Scans the music library * @param mediaScannerService + */ + public static void execScan(MediaScannerService mediaScannerService) { + mediaScannerService.scanLibrary(); + + while (mediaScannerService.isScanning()) { + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + + } + +} diff --git a/libresonic-main/src/test/java/org/libresonic/player/dao/MusicFolderDaoMock.java b/libresonic-main/src/test/java/org/libresonic/player/dao/MusicFolderDaoMock.java new file mode 100644 index 00000000..f4127d44 --- /dev/null +++ b/libresonic-main/src/test/java/org/libresonic/player/dao/MusicFolderDaoMock.java @@ -0,0 +1,39 @@ +package org.libresonic.player.dao; + +import org.libresonic.player.domain.MusicFolder; + +import java.io.File; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +public class MusicFolderDaoMock extends MusicFolderDao { + + private static String baseResources = "/MEDIAS/"; + + public static String resolveBaseMediaPath() { + String baseDir = MusicFolderDaoMock.class.getResource(baseResources).toString().replace("file:",""); + return baseDir; + } + + public static String resolveMusicFolderPath() { + return (MusicFolderDaoMock.resolveBaseMediaPath() + "Music"); + } + + public static String resolveMusic2FolderPath() { + return (MusicFolderDaoMock.resolveBaseMediaPath() + "Music2"); + } + + @Override + public List getAllMusicFolders() { + List liste = new ArrayList<>(); + File musicDir = new File(MusicFolderDaoMock.resolveMusicFolderPath()); + MusicFolder musicFolder = new MusicFolder(1,musicDir,"Music",true,new Date()); + liste.add(musicFolder); + + File music2Dir = new File(MusicFolderDaoMock.resolveMusic2FolderPath()); + MusicFolder musicFolder2 = new MusicFolder(2,music2Dir,"Music2",true,new Date()); + liste.add(musicFolder2); + return liste; + } +} diff --git a/libresonic-main/src/test/java/org/libresonic/player/service/MediaScannerServiceTestCase.java b/libresonic-main/src/test/java/org/libresonic/player/service/MediaScannerServiceTestCase.java new file mode 100644 index 00000000..1b361d6c --- /dev/null +++ b/libresonic-main/src/test/java/org/libresonic/player/service/MediaScannerServiceTestCase.java @@ -0,0 +1,141 @@ +package org.libresonic.player.service; + +import com.codahale.metrics.ConsoleReporter; +import com.codahale.metrics.JmxReporter; +import com.codahale.metrics.MetricRegistry; +import com.codahale.metrics.Timer; +import junit.framework.Assert; +import junit.framework.TestCase; +import org.libresonic.player.TestCaseUtils; +import org.libresonic.player.dao.*; +import org.libresonic.player.domain.Album; +import org.libresonic.player.domain.Artist; +import org.libresonic.player.domain.MediaFile; +import org.springframework.context.ApplicationContext; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +/** + * A unit test class to test the MediaScannerService. + * + * This class uses the Spring application context configuration present in the + * /org/libresonic/player/service/mediaScannerServiceTestCase/ directory. + * + * The media library is found in the /MEDIAS directory. + * It is composed of 2 musicFolders (Music and Music2) and several little weight audio files. + * + * At runtime, the subsonic_home dir is set to target/test-classes/org/libresonic/player/service/mediaScannerServiceTestCase. + * An empty database is created on the fly. + * + */ +public class MediaScannerServiceTestCase extends TestCase { + + private static String baseResources = "/org/libresonic/player/service/mediaScannerServiceTestCase/"; + + private final MetricRegistry metrics = new MetricRegistry(); + + + private MediaScannerService mediaScannerService = null; + private MediaFileDao mediaFileDao = null; + private MusicFolderDao musicFolderDao = null; + private DaoHelper daoHelper = null; + private MediaFileService mediaFileService = null; + private ArtistDao artistDao = null; + private AlbumDao albumDao = null; + + + @Override + protected void setUp() throws Exception { + super.setUp(); + + TestCaseUtils.setLibresonicHome(baseResources); + + // load spring context + ApplicationContext context = TestCaseUtils.loadSpringApplicationContext(baseResources); + + mediaScannerService = (MediaScannerService)context.getBean("mediaScannerService"); + mediaFileDao = (MediaFileDao)context.getBean("mediaFileDao"); + musicFolderDao = (MusicFolderDao) context.getBean("musicFolderDao"); + daoHelper = (DaoHelper) context.getBean("daoHelper"); + mediaFileService = (MediaFileService) context.getBean("mediaFileService"); + artistDao = (ArtistDao) context.getBean("artistDao"); + albumDao = (AlbumDao) context.getBean("albumDao"); + } + + + /** + * Tests the MediaScannerService by scanning the test media library into an empty database. + */ + public void testScanLibrary() { + + //startMetricsReport(); + + + Timer globalTimer = metrics.timer(MetricRegistry.name(MediaScannerServiceTestCase.class, "Timer.global")); + + Timer.Context globalTimerContext = globalTimer.time(); + TestCaseUtils.execScan(mediaScannerService); + globalTimerContext.stop(); + + System.out.println("--- Report of records count per table ---"); + Map records = TestCaseUtils.recordsInAllTables(daoHelper); + records.keySet().forEach(tableName -> System.out.println(tableName+" : "+records.get(tableName).toString() )); + System.out.println("--- *********************** ---"); + + + // Music Folder Music must have 3 children + List listeMusicChildren = mediaFileDao.getChildrenOf(MusicFolderDaoMock.resolveMusicFolderPath()); + Assert.assertEquals(3,listeMusicChildren.size()); + // Music Folder Music2 must have 1 children + List listeMusic2Children = mediaFileDao.getChildrenOf(MusicFolderDaoMock.resolveMusic2FolderPath()); + Assert.assertEquals(1,listeMusic2Children.size()); + + System.out.println("--- List of all artists ---"); + System.out.println("artistName#albumCount"); + List allArtists = artistDao.getAlphabetialArtists(0,0,musicFolderDao.getAllMusicFolders()); + allArtists.forEach(artist -> System.out.println(artist.getName()+"#"+artist.getAlbumCount())); + System.out.println("--- *********************** ---"); + + System.out.println("--- List of all albums ---"); + System.out.println("name#artist"); + List allAlbums = albumDao.getAlphabetialAlbums(0,0,true,musicFolderDao.getAllMusicFolders()); + allAlbums.forEach(album -> System.out.println(album.getName()+"#"+album.getArtist())); + Assert.assertEquals(5,allAlbums.size()); + System.out.println("--- *********************** ---"); + + + + List listeSongs = mediaFileDao.getSongsByGenre("Baroque Instrumental",0,0,musicFolderDao.getAllMusicFolders()); + + // display out metrics report + ConsoleReporter reporter = ConsoleReporter.forRegistry(metrics) + .convertRatesTo(TimeUnit.SECONDS.SECONDS) + .convertDurationsTo(TimeUnit.MILLISECONDS) + .build(); + reporter.report(); + + System.out.print("End"); + } + + /** + * Starts a Metrics Console and JMX reporter. + */ + private void startMetricsReport() { + + // Reporter console + ConsoleReporter reporter = ConsoleReporter.forRegistry(metrics) + .convertRatesTo(TimeUnit.SECONDS.SECONDS) + .convertDurationsTo(TimeUnit.MILLISECONDS) + .build(); + reporter.start(10, TimeUnit.SECONDS); + + // Jmx reporter + final JmxReporter jmxReporter = JmxReporter.forRegistry(metrics).build(); + jmxReporter.start(); + } + + + +} diff --git a/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Céline Frisch- Café Zimmermann - Bach- Goldberg Variations, Canons [Disc 1]/01 - Bach- Goldberg Variations, BWV 988 - Aria.flac b/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Céline Frisch- Café Zimmermann - Bach- Goldberg Variations, Canons [Disc 1]/01 - Bach- Goldberg Variations, BWV 988 - Aria.flac new file mode 100755 index 00000000..f0bdbc69 Binary files /dev/null and b/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Céline Frisch- Café Zimmermann - Bach- Goldberg Variations, Canons [Disc 1]/01 - Bach- Goldberg Variations, BWV 988 - Aria.flac differ diff --git a/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Céline Frisch- Café Zimmermann - Bach- Goldberg Variations, Canons [Disc 1]/02 - Bach- Goldberg Variations, BWV 988 - Variatio 1 A 1 Clav..flac b/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Céline Frisch- Café Zimmermann - Bach- Goldberg Variations, Canons [Disc 1]/02 - Bach- Goldberg Variations, BWV 988 - Variatio 1 A 1 Clav..flac new file mode 100755 index 00000000..09ca1c75 Binary files /dev/null and b/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Céline Frisch- Café Zimmermann - Bach- Goldberg Variations, Canons [Disc 1]/02 - Bach- Goldberg Variations, BWV 988 - Variatio 1 A 1 Clav..flac differ diff --git a/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Céline Frisch- Café Zimmermann - Bach- Goldberg Variations, Canons [Disc 1]/Folder.jpg b/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Céline Frisch- Café Zimmermann - Bach- Goldberg Variations, Canons [Disc 1]/Folder.jpg new file mode 100644 index 00000000..f1222e13 Binary files /dev/null and b/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Céline Frisch- Café Zimmermann - Bach- Goldberg Variations, Canons [Disc 1]/Folder.jpg differ diff --git a/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Ravel/_DIR_ Ravel - Chamber Music With Voice/01 - Sonata Violin & Cello I. Allegro.ogg b/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Ravel/_DIR_ Ravel - Chamber Music With Voice/01 - Sonata Violin & Cello I. Allegro.ogg new file mode 100755 index 00000000..62199cfa Binary files /dev/null and b/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Ravel/_DIR_ Ravel - Chamber Music With Voice/01 - Sonata Violin & Cello I. Allegro.ogg differ diff --git a/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Ravel/_DIR_ Ravel - Chamber Music With Voice/02 - Sonata Violin & Cello II. Tres Vif.ogg b/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Ravel/_DIR_ Ravel - Chamber Music With Voice/02 - Sonata Violin & Cello II. Tres Vif.ogg new file mode 100755 index 00000000..7f8f91cd Binary files /dev/null and b/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Ravel/_DIR_ Ravel - Chamber Music With Voice/02 - Sonata Violin & Cello II. Tres Vif.ogg differ diff --git a/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Ravel/_DIR_ Ravel - Chamber Music With Voice/Folder.jpg b/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Ravel/_DIR_ Ravel - Chamber Music With Voice/Folder.jpg new file mode 100644 index 00000000..b902207b Binary files /dev/null and b/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Ravel/_DIR_ Ravel - Chamber Music With Voice/Folder.jpg differ diff --git a/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Ravel/_DIR_ Ravel - Complete Piano Works/01 - Gaspard de la Nuit - i. Ondine.mp3 b/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Ravel/_DIR_ Ravel - Complete Piano Works/01 - Gaspard de la Nuit - i. Ondine.mp3 new file mode 100644 index 00000000..fcbea827 Binary files /dev/null and b/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Ravel/_DIR_ Ravel - Complete Piano Works/01 - Gaspard de la Nuit - i. Ondine.mp3 differ diff --git a/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Ravel/_DIR_ Ravel - Complete Piano Works/02 - Gaspard de la Nuit - ii. Le Gibet.mp3 b/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Ravel/_DIR_ Ravel - Complete Piano Works/02 - Gaspard de la Nuit - ii. Le Gibet.mp3 new file mode 100644 index 00000000..85ce05ef Binary files /dev/null and b/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Ravel/_DIR_ Ravel - Complete Piano Works/02 - Gaspard de la Nuit - ii. Le Gibet.mp3 differ diff --git a/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Ravel/_DIR_ Ravel - Complete Piano Works/Folder.jpeg b/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Ravel/_DIR_ Ravel - Complete Piano Works/Folder.jpeg new file mode 100644 index 00000000..6542198c Binary files /dev/null and b/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Ravel/_DIR_ Ravel - Complete Piano Works/Folder.jpeg differ diff --git a/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Sixteen Horsepower/_DIR_ Sackcloth 'n' Ashes/Sixteen Horsepower - 01 I Seen What I Saw.mp3 b/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Sixteen Horsepower/_DIR_ Sackcloth 'n' Ashes/Sixteen Horsepower - 01 I Seen What I Saw.mp3 new file mode 100755 index 00000000..31aec22b Binary files /dev/null and b/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Sixteen Horsepower/_DIR_ Sackcloth 'n' Ashes/Sixteen Horsepower - 01 I Seen What I Saw.mp3 differ diff --git a/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Sixteen Horsepower/_DIR_ Sackcloth 'n' Ashes/Sixteen Horsepower - 02 Black Soul Choir.mp3 b/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Sixteen Horsepower/_DIR_ Sackcloth 'n' Ashes/Sixteen Horsepower - 02 Black Soul Choir.mp3 new file mode 100755 index 00000000..1eae1f7c Binary files /dev/null and b/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Sixteen Horsepower/_DIR_ Sackcloth 'n' Ashes/Sixteen Horsepower - 02 Black Soul Choir.mp3 differ diff --git a/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Sixteen Horsepower/_DIR_ Sackcloth 'n' Ashes/Sixteen Horsepower - 10 Reed Neck Reel.mp3 b/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Sixteen Horsepower/_DIR_ Sackcloth 'n' Ashes/Sixteen Horsepower - 10 Reed Neck Reel.mp3 new file mode 100755 index 00000000..5f47ebad Binary files /dev/null and b/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Sixteen Horsepower/_DIR_ Sackcloth 'n' Ashes/Sixteen Horsepower - 10 Reed Neck Reel.mp3 differ diff --git a/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Sixteen Horsepower/_DIR_ Sackcloth 'n' Ashes/cover.jpg b/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Sixteen Horsepower/_DIR_ Sackcloth 'n' Ashes/cover.jpg new file mode 100644 index 00000000..0c2e6181 Binary files /dev/null and b/libresonic-main/src/test/resources/MEDIAS/Music/_DIR_ Sixteen Horsepower/_DIR_ Sackcloth 'n' Ashes/cover.jpg differ diff --git a/libresonic-main/src/test/resources/MEDIAS/Music2/_DIR_ chrome hoof - 2004/02 eyes like dull hazlenuts.mp3 b/libresonic-main/src/test/resources/MEDIAS/Music2/_DIR_ chrome hoof - 2004/02 eyes like dull hazlenuts.mp3 new file mode 100755 index 00000000..d9d3fc99 Binary files /dev/null and b/libresonic-main/src/test/resources/MEDIAS/Music2/_DIR_ chrome hoof - 2004/02 eyes like dull hazlenuts.mp3 differ diff --git a/libresonic-main/src/test/resources/MEDIAS/Music2/_DIR_ chrome hoof - 2004/10 telegraph hill.mp3 b/libresonic-main/src/test/resources/MEDIAS/Music2/_DIR_ chrome hoof - 2004/10 telegraph hill.mp3 new file mode 100755 index 00000000..1acc2726 Binary files /dev/null and b/libresonic-main/src/test/resources/MEDIAS/Music2/_DIR_ chrome hoof - 2004/10 telegraph hill.mp3 differ diff --git a/libresonic-main/src/test/resources/MEDIAS/Music2/_DIR_ chrome hoof - 2004/Folder.jpg b/libresonic-main/src/test/resources/MEDIAS/Music2/_DIR_ chrome hoof - 2004/Folder.jpg new file mode 100644 index 00000000..3bdbd8b3 Binary files /dev/null and b/libresonic-main/src/test/resources/MEDIAS/Music2/_DIR_ chrome hoof - 2004/Folder.jpg differ diff --git a/libresonic-main/src/test/resources/org/libresonic/player/service/mediaScannerServiceTestCase/applicationContext-cache.xml b/libresonic-main/src/test/resources/org/libresonic/player/service/mediaScannerServiceTestCase/applicationContext-cache.xml new file mode 100644 index 00000000..da4c296a --- /dev/null +++ b/libresonic-main/src/test/resources/org/libresonic/player/service/mediaScannerServiceTestCase/applicationContext-cache.xml @@ -0,0 +1,17 @@ + + + + + + + + + + + + + + + diff --git a/libresonic-main/src/test/resources/org/libresonic/player/service/mediaScannerServiceTestCase/applicationContext-service.xml b/libresonic-main/src/test/resources/org/libresonic/player/service/mediaScannerServiceTestCase/applicationContext-service.xml new file mode 100644 index 00000000..2d0b320f --- /dev/null +++ b/libresonic-main/src/test/resources/org/libresonic/player/service/mediaScannerServiceTestCase/applicationContext-service.xml @@ -0,0 +1,186 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +