koel/tests/Feature/MediaSyncTest.php

242 lines
8.4 KiB
PHP
Raw Normal View History

2015-12-13 04:42:28 +00:00
<?php
2017-02-14 06:53:02 +00:00
namespace Tests\Feature;
2016-02-02 07:47:00 +00:00
use App\Events\LibraryChanged;
2016-02-04 15:04:53 +00:00
use App\Libraries\WatchRecord\InotifyWatchRecord;
2015-12-13 04:42:28 +00:00
use App\Models\Album;
2016-04-24 04:37:04 +00:00
use App\Models\Artist;
2015-12-13 04:42:28 +00:00
use App\Models\Song;
use App\Services\FileSynchronizer;
2018-08-19 15:26:34 +00:00
use App\Services\MediaSyncService;
use getID3;
2015-12-14 13:22:39 +00:00
use Illuminate\Foundation\Testing\WithoutMiddleware;
2020-12-22 23:01:49 +00:00
use Mockery;
2015-12-13 04:42:28 +00:00
2018-08-19 09:05:33 +00:00
class MediaSyncTest extends TestCase
2015-12-13 04:42:28 +00:00
{
2017-08-05 16:56:11 +00:00
use WithoutMiddleware;
2015-12-13 04:42:28 +00:00
2018-08-19 15:26:34 +00:00
/** @var MediaSyncService */
2018-08-19 09:05:33 +00:00
private $mediaService;
2019-07-22 07:03:23 +00:00
public function setUp(): void
2018-08-19 09:05:33 +00:00
{
parent::setUp();
2018-08-19 15:26:34 +00:00
$this->mediaService = app(MediaSyncService::class);
2018-08-19 09:05:33 +00:00
}
public function testSync(): void
2015-12-13 04:42:28 +00:00
{
2016-02-02 07:47:00 +00:00
$this->expectsEvents(LibraryChanged::class);
2018-08-19 09:05:33 +00:00
$this->mediaService->sync($this->mediaPath);
2015-12-13 04:42:28 +00:00
// Standard mp3 files under root path should be recognized
2020-09-06 18:21:39 +00:00
self::assertDatabaseHas('songs', [
2020-12-22 20:11:22 +00:00
'path' => $this->mediaPath . '/full.mp3',
2016-03-20 14:14:02 +00:00
// Track # should be recognized
'track' => 5,
]);
2015-12-13 04:42:28 +00:00
// Ogg files and audio files in subdirectories should be recognized
2020-12-22 20:11:22 +00:00
self::assertDatabaseHas('songs', ['path' => $this->mediaPath . '/subdir/back-in-black.ogg']);
2015-12-13 04:42:28 +00:00
// GitHub issue #380. folder.png should be copied and used as the cover for files
// under subdir/
2020-12-22 20:11:22 +00:00
$song = Song::wherePath($this->mediaPath . '/subdir/back-in-black.ogg')->first();
2020-09-06 18:21:39 +00:00
self::assertNotNull($song->album->cover);
// File search shouldn't be case-sensitive.
2020-12-22 20:11:22 +00:00
self::assertDatabaseHas('songs', ['path' => $this->mediaPath . '/subdir/no-name.mp3']);
2015-12-13 04:42:28 +00:00
// Non-audio files shouldn't be recognized
2020-12-22 20:11:22 +00:00
self::assertDatabaseMissing('songs', ['path' => $this->mediaPath . '/rubbish.log']);
2015-12-13 04:42:28 +00:00
// Broken/corrupted audio files shouldn't be recognized
2020-12-22 20:11:22 +00:00
self::assertDatabaseMissing('songs', ['path' => $this->mediaPath . '/fake.mp3']);
2015-12-13 04:42:28 +00:00
// Artists should be created
2020-09-06 18:21:39 +00:00
self::assertDatabaseHas('artists', ['name' => 'Cuckoo']);
self::assertDatabaseHas('artists', ['name' => 'Koel']);
2015-12-13 04:42:28 +00:00
// Albums should be created
2020-09-06 18:21:39 +00:00
self::assertDatabaseHas('albums', ['name' => 'Koel Testing Vol. 1']);
2015-12-13 04:42:28 +00:00
// Albums and artists should be correctly linked
$album = Album::whereName('Koel Testing Vol. 1')->first();
2020-09-06 18:21:39 +00:00
self::assertEquals('Koel', $album->artist->name);
2015-12-13 04:42:28 +00:00
2016-04-24 04:37:04 +00:00
// Compilation albums, artists and songs must be recognized
$song = Song::whereTitle('This song belongs to a compilation')->first();
2020-09-06 18:21:39 +00:00
self::assertNotNull($song->artist_id);
self::assertTrue($song->album->is_compilation);
self::assertEquals(Artist::VARIOUS_ID, $song->album->artist_id);
2016-04-24 04:37:04 +00:00
2015-12-13 04:42:28 +00:00
$currentCover = $album->cover;
$song = Song::orderBy('id', 'desc')->first();
// Modified file should be recognized
touch($song->path, $time = time());
2018-08-19 09:05:33 +00:00
$this->mediaService->sync($this->mediaPath);
2015-12-13 04:42:28 +00:00
$song = Song::find($song->id);
2020-09-06 18:21:39 +00:00
self::assertEquals($time, $song->mtime);
2015-12-13 04:42:28 +00:00
// Albums with a non-default cover should have their covers overwritten
2020-09-06 18:21:39 +00:00
self::assertEquals($currentCover, Album::find($album->id)->cover);
2015-12-13 04:42:28 +00:00
}
2016-02-02 07:47:00 +00:00
public function testForceSync(): void
2016-03-22 08:22:39 +00:00
{
$this->expectsEvents(LibraryChanged::class);
2018-08-19 09:05:33 +00:00
$this->mediaService->sync($this->mediaPath);
2016-03-22 08:22:39 +00:00
// Make some modification to the records
$song = Song::orderBy('id', 'desc')->first();
2016-11-24 04:07:57 +00:00
$originalTitle = $song->title;
$originalLyrics = $song->lyrics;
2016-03-22 08:22:39 +00:00
$song->update([
'title' => "It's John Cena!",
'lyrics' => 'Booom Wroooom',
]);
// Resync without forcing
2018-08-19 09:05:33 +00:00
$this->mediaService->sync($this->mediaPath);
2016-03-22 08:22:39 +00:00
// Validate that the changes are not lost
$song = Song::orderBy('id', 'desc')->first();
2020-09-06 18:21:39 +00:00
self::assertEquals("It's John Cena!", $song->title);
self::assertEquals('Booom Wroooom', $song->lyrics);
2016-03-22 08:22:39 +00:00
// Resync with force
2018-08-19 09:05:33 +00:00
$this->mediaService->sync($this->mediaPath, [], true);
2016-03-22 08:22:39 +00:00
// All is lost.
$song = Song::orderBy('id', 'desc')->first();
2020-09-06 18:21:39 +00:00
self::assertEquals($originalTitle, $song->title);
self::assertEquals($originalLyrics, $song->lyrics);
2016-03-22 08:22:39 +00:00
}
public function testSelectiveSync(): void
2016-03-22 08:22:39 +00:00
{
$this->expectsEvents(LibraryChanged::class);
2018-08-19 09:05:33 +00:00
$this->mediaService->sync($this->mediaPath);
2016-03-22 08:22:39 +00:00
// Make some modification to the records
$song = Song::orderBy('id', 'desc')->first();
2016-11-24 04:07:57 +00:00
$originalTitle = $song->title;
2016-03-22 08:22:39 +00:00
$song->update([
'title' => "It's John Cena!",
'lyrics' => 'Booom Wroooom',
]);
// Sync only the selective tags
2018-08-19 09:05:33 +00:00
$this->mediaService->sync($this->mediaPath, ['title'], true);
2016-03-22 08:22:39 +00:00
// Validate that the specified tags are changed, other remains the same
$song = Song::orderBy('id', 'desc')->first();
2020-09-06 18:21:39 +00:00
self::assertEquals($originalTitle, $song->title);
self::assertEquals('Booom Wroooom', $song->lyrics);
2016-03-22 08:22:39 +00:00
}
public function testSyncAllTagsForNewFiles(): void
2016-07-05 10:14:12 +00:00
{
2017-08-05 21:20:05 +00:00
// First we sync the test directory to get the data
2018-08-19 09:05:33 +00:00
$this->mediaService->sync($this->mediaPath);
2017-08-05 21:20:05 +00:00
// Now delete the first song.
2016-07-05 10:14:12 +00:00
$song = Song::orderBy('id')->first();
$song->delete();
2017-08-05 21:20:05 +00:00
// Selectively sync only one tag
2018-08-19 09:05:33 +00:00
$this->mediaService->sync($this->mediaPath, ['track'], true);
2017-06-03 16:21:53 +00:00
2017-08-05 21:20:05 +00:00
// but we still expect the whole song to be added back with all info
$addedSong = Song::findOrFail($song->id)->toArray();
2017-06-03 16:21:53 +00:00
$song = $song->toArray();
2017-08-05 21:20:05 +00:00
array_forget($addedSong, 'created_at');
2017-06-09 23:46:12 +00:00
array_forget($song, 'created_at');
2020-09-06 18:21:39 +00:00
self::assertEquals($song, $addedSong);
2016-07-05 10:14:12 +00:00
}
public function testSyncAddedSongViaWatch(): void
2016-02-02 07:47:00 +00:00
{
2017-01-06 03:04:08 +00:00
$this->expectsEvents(LibraryChanged::class);
2020-12-22 20:11:22 +00:00
$path = $this->mediaPath . '/blank.mp3';
2018-08-19 09:05:33 +00:00
$this->mediaService->syncByWatchRecord(new InotifyWatchRecord("CLOSE_WRITE,CLOSE $path"));
2016-02-02 07:47:00 +00:00
2020-09-06 18:21:39 +00:00
self::assertDatabaseHas('songs', ['path' => $path]);
2016-02-02 07:47:00 +00:00
}
public function testSyncDeletedSongViaWatch(): void
2016-02-02 07:47:00 +00:00
{
$this->expectsEvents(LibraryChanged::class);
static::createSampleMediaSet();
2016-02-02 07:47:00 +00:00
$song = Song::orderBy('id', 'desc')->first();
2018-08-19 09:05:33 +00:00
$this->mediaService->syncByWatchRecord(new InotifyWatchRecord("DELETE {$song->path}"));
2016-02-02 07:47:00 +00:00
2020-09-06 18:21:39 +00:00
self::assertDatabaseMissing('songs', ['id' => $song->id]);
2016-02-02 07:47:00 +00:00
}
public function testSyncDeletedDirectoryViaWatch(): void
2016-02-02 07:47:00 +00:00
{
$this->expectsEvents(LibraryChanged::class);
2018-08-19 09:05:33 +00:00
$this->mediaService->sync($this->mediaPath);
2016-02-02 07:47:00 +00:00
2018-08-19 09:05:33 +00:00
$this->mediaService->syncByWatchRecord(new InotifyWatchRecord("MOVED_FROM,ISDIR {$this->mediaPath}/subdir"));
2016-02-02 07:47:00 +00:00
2020-12-22 20:11:22 +00:00
self::assertDatabaseMissing('songs', ['path' => $this->mediaPath . '/subdir/sic.mp3']);
self::assertDatabaseMissing('songs', ['path' => $this->mediaPath . '/subdir/no-name.mp3']);
self::assertDatabaseMissing('songs', ['path' => $this->mediaPath . '/subdir/back-in-black.mp3']);
2016-02-02 07:47:00 +00:00
}
2016-05-05 15:03:30 +00:00
public function testHtmlEntities(): void
2016-05-05 15:03:30 +00:00
{
2020-12-22 23:01:49 +00:00
$this->swap(
getID3::class,
Mockery::mock(getID3::class, [
'analyze' => [
'tags' => [
'id3v2' => [
'title' => ['&#27700;&#35895;&#24195;&#23455;'],
'album' => ['&#23567;&#23721;&#20117;&#12371; Random'],
'artist' => ['&#20304;&#20489;&#32190;&#38899; Unknown'],
],
2016-05-05 15:03:30 +00:00
],
2020-12-22 23:01:49 +00:00
'encoding' => 'UTF-8',
'playtime_seconds' => 100,
2016-05-05 15:03:30 +00:00
],
2020-12-22 23:01:49 +00:00
])
);
2016-05-05 15:03:30 +00:00
/** @var FileSynchronizer $fileSynchronizer */
$fileSynchronizer = app(FileSynchronizer::class);
2020-12-22 20:11:22 +00:00
$info = $fileSynchronizer->setFile(__DIR__ . '/songs/blank.mp3')->getFileInfo();
2016-05-05 15:03:30 +00:00
self::assertEquals('佐倉綾音 Unknown', $info['artist']);
self::assertEquals('小岩井こ Random', $info['album']);
self::assertEquals('水谷広実', $info['title']);
2016-05-05 15:03:30 +00:00
}
public function testOptionallyIgnoreHiddenFiles(): void
{
2016-09-19 02:08:50 +00:00
config(['koel.ignore_dot_files' => false]);
2018-08-19 09:05:33 +00:00
$this->mediaService->sync($this->mediaPath);
2020-09-06 18:21:39 +00:00
self::assertDatabaseHas('albums', ['name' => 'Hidden Album']);
2016-09-19 02:08:50 +00:00
config(['koel.ignore_dot_files' => true]);
2018-08-19 09:05:33 +00:00
$this->mediaService->sync($this->mediaPath);
2020-09-06 18:21:39 +00:00
self::assertDatabaseMissing('albums', ['name' => 'Hidden Album']);
}
2015-12-13 04:42:28 +00:00
}