fix: updating songs from S3 might create duplicates

This commit is contained in:
Phan An 2024-01-15 14:32:44 +01:00
parent fdc780eb43
commit 3a3a84164d
2 changed files with 86 additions and 5 deletions

View file

@ -49,7 +49,6 @@ class S3Service implements ObjectStorageInterface
string $lyrics string $lyrics
): Song { ): Song {
$path = Song::getPathFromS3BucketAndKey($bucket, $key); $path = Song::getPathFromS3BucketAndKey($bucket, $key);
$artist = Artist::getOrCreate($artistName); $artist = Artist::getOrCreate($artistName);
$albumArtist = $albumArtistName && $albumArtistName !== $artistName $albumArtist = $albumArtistName && $albumArtistName !== $artistName
@ -66,8 +65,8 @@ class S3Service implements ObjectStorageInterface
); );
} }
$song = Song::query()->updateOrCreate(['id' => Helper::getFileHash($path)], [ /** @var Song $song */
'path' => $path, $song = Song::query()->updateOrCreate(['path' => $path], [
'album_id' => $album->id, 'album_id' => $album->id,
'artist_id' => $artist->id, 'artist_id' => $artist->id,
'title' => $title, 'title' => $title,

View file

@ -2,6 +2,7 @@
namespace Tests\Unit\Services; namespace Tests\Unit\Services;
use App\Events\LibraryChanged;
use App\Models\Song; use App\Models\Song;
use App\Repositories\SongRepository; use App\Repositories\SongRepository;
use App\Services\MediaMetadataService; use App\Services\MediaMetadataService;
@ -19,6 +20,7 @@ class S3ServiceTest extends TestCase
{ {
private S3ClientInterface|LegacyMockInterface|MockInterface $s3Client; private S3ClientInterface|LegacyMockInterface|MockInterface $s3Client;
private Cache|LegacyMockInterface|MockInterface $cache; private Cache|LegacyMockInterface|MockInterface $cache;
private SongRepository|LegacyMockInterface|MockInterface $songRepository;
private S3Service $s3Service; private S3Service $s3Service;
public function setUp(): void public function setUp(): void
@ -29,9 +31,89 @@ class S3ServiceTest extends TestCase
$this->cache = Mockery::mock(Cache::class); $this->cache = Mockery::mock(Cache::class);
$metadataService = Mockery::mock(MediaMetadataService::class); $metadataService = Mockery::mock(MediaMetadataService::class);
$songRepository = Mockery::mock(SongRepository::class); $this->songRepository = Mockery::mock(SongRepository::class);
$this->s3Service = new S3Service($this->s3Client, $this->cache, $metadataService, $songRepository); $this->s3Service = new S3Service($this->s3Client, $this->cache, $metadataService, $this->songRepository);
}
public function testCreateSongEntry(): void
{
$this->expectsEvents(LibraryChanged::class);
$song = $this->s3Service->createSongEntry(
bucket: 'foo',
key: 'bar',
artistName: 'Queen',
albumName: 'A Night at the Opera',
albumArtistName: 'Queen',
cover: [],
title: 'Bohemian Rhapsody',
duration: 355.5,
track: 1,
lyrics: 'Is this the real life?'
);
self::assertSame('Queen', $song->artist->name);
self::assertSame('A Night at the Opera', $song->album->name);
self::assertSame('Queen', $song->album_artist->name);
self::assertSame('Bohemian Rhapsody', $song->title);
self::assertSame(355.5, $song->length);
self::assertSame('Is this the real life?', $song->lyrics);
self::assertSame(1, $song->track);
}
public function testUpdateSongEntry(): void
{
$this->expectsEvents(LibraryChanged::class);
/** @var Song $song */
$song = Song::factory()->create([
'path' => 's3://foo/bar',
]);
$this->s3Service->createSongEntry(
bucket: 'foo',
key: 'bar',
artistName: 'Queen',
albumName: 'A Night at the Opera',
albumArtistName: 'Queen',
cover: [],
title: 'Bohemian Rhapsody',
duration: 355.5,
track: 1,
lyrics: 'Is this the real life?'
);
self::assertSame(1, Song::query()->count());
$song->refresh();
self::assertSame('Queen', $song->artist->name);
self::assertSame('A Night at the Opera', $song->album->name);
self::assertSame('Queen', $song->album_artist->name);
self::assertSame('Bohemian Rhapsody', $song->title);
self::assertSame(355.5, $song->length);
self::assertSame('Is this the real life?', $song->lyrics);
self::assertSame(1, $song->track);
}
public function testDeleteSong(): void
{
$this->expectsEvents(LibraryChanged::class);
/** @var Song $song */
$song = Song::factory()->create([
'path' => 's3://foo/bar',
]);
$this->songRepository->shouldReceive('getOneByPath')
->with('s3://foo/bar')
->once()
->andReturn($song);
$this->s3Service->deleteSongEntry('foo', 'bar');
self::assertModelMissing($song);
} }
public function testGetSongPublicUrl(): void public function testGetSongPublicUrl(): void