mirror of
https://github.com/navidrome/navidrome.git
synced 2026-10-26 10:17:09 +01:00
test(scanner): add tests for multi-library scanning and validation
Signed-off-by: Deluan <deluan@navidrome.org>
This commit is contained in:
parent
daa3648b06
commit
4c06cd2ac8
2 changed files with 512 additions and 0 deletions
509
scanner/scanner_multilibrary_test.go
Normal file
509
scanner/scanner_multilibrary_test.go
Normal file
|
|
@ -0,0 +1,509 @@
|
|||
package scanner_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"path/filepath"
|
||||
"testing/fstest"
|
||||
|
||||
"github.com/Masterminds/squirrel"
|
||||
"github.com/navidrome/navidrome/conf"
|
||||
"github.com/navidrome/navidrome/conf/configtest"
|
||||
"github.com/navidrome/navidrome/core"
|
||||
"github.com/navidrome/navidrome/core/artwork"
|
||||
"github.com/navidrome/navidrome/core/metrics"
|
||||
"github.com/navidrome/navidrome/core/storage/storagetest"
|
||||
"github.com/navidrome/navidrome/db"
|
||||
"github.com/navidrome/navidrome/log"
|
||||
"github.com/navidrome/navidrome/model"
|
||||
"github.com/navidrome/navidrome/model/request"
|
||||
"github.com/navidrome/navidrome/persistence"
|
||||
"github.com/navidrome/navidrome/scanner"
|
||||
"github.com/navidrome/navidrome/server/events"
|
||||
"github.com/navidrome/navidrome/tests"
|
||||
"github.com/navidrome/navidrome/utils/slice"
|
||||
. "github.com/onsi/ginkgo/v2"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
|
||||
var _ = Describe("Scanner - Multi-Library", Ordered, func() {
|
||||
var ctx context.Context
|
||||
var lib1, lib2 model.Library
|
||||
var ds *tests.MockDataStore
|
||||
var s scanner.Scanner
|
||||
|
||||
createFS := func(path string, files fstest.MapFS) storagetest.FakeFS {
|
||||
fs := storagetest.FakeFS{}
|
||||
fs.SetFiles(files)
|
||||
storagetest.Register(path, &fs)
|
||||
return fs
|
||||
}
|
||||
|
||||
BeforeAll(func() {
|
||||
ctx = request.WithUser(GinkgoT().Context(), model.User{ID: "123", IsAdmin: true})
|
||||
tmpDir := GinkgoT().TempDir()
|
||||
conf.Server.DbPath = filepath.Join(tmpDir, "test-scanner-multilibrary.db?_journal_mode=WAL")
|
||||
log.Warn("Using DB at " + conf.Server.DbPath)
|
||||
db.Db().SetMaxOpenConns(1)
|
||||
})
|
||||
|
||||
BeforeEach(func() {
|
||||
DeferCleanup(configtest.SetupConfig())
|
||||
conf.Server.DevExternalScanner = false
|
||||
|
||||
db.Init(ctx)
|
||||
DeferCleanup(func() {
|
||||
Expect(tests.ClearDB()).To(Succeed())
|
||||
})
|
||||
|
||||
ds = &tests.MockDataStore{RealDS: persistence.New(db.Db())}
|
||||
|
||||
// Create the admin user in the database to match the context
|
||||
adminUser := model.User{
|
||||
ID: "123",
|
||||
UserName: "admin",
|
||||
Name: "Admin User",
|
||||
IsAdmin: true,
|
||||
NewPassword: "password",
|
||||
}
|
||||
Expect(ds.User(ctx).Put(&adminUser)).To(Succeed())
|
||||
|
||||
s = scanner.New(ctx, ds, artwork.NoopCacheWarmer(), events.NoopBroker(),
|
||||
core.NewPlaylists(ds), metrics.NewNoopInstance())
|
||||
|
||||
// Create two test libraries (let DB auto-assign IDs)
|
||||
lib1 = model.Library{Name: "Rock Collection", Path: "rock:///music"}
|
||||
lib2 = model.Library{Name: "Jazz Collection", Path: "jazz:///music"}
|
||||
Expect(ds.Library(ctx).Put(&lib1)).To(Succeed())
|
||||
Expect(ds.Library(ctx).Put(&lib2)).To(Succeed())
|
||||
})
|
||||
|
||||
runScanner := func(ctx context.Context, fullScan bool) error {
|
||||
_, err := s.ScanAll(ctx, fullScan)
|
||||
return err
|
||||
}
|
||||
|
||||
Context("Two Libraries with Different Content", func() {
|
||||
BeforeEach(func() {
|
||||
// Rock library content
|
||||
beatles := template(_t{"albumartist": "The Beatles", "album": "Abbey Road", "year": 1969, "genre": "Rock"})
|
||||
zeppelin := template(_t{"albumartist": "Led Zeppelin", "album": "IV", "year": 1971, "genre": "Rock"})
|
||||
|
||||
_ = createFS("rock", fstest.MapFS{
|
||||
"The Beatles/Abbey Road/01 - Come Together.mp3": beatles(track(1, "Come Together")),
|
||||
"The Beatles/Abbey Road/02 - Something.mp3": beatles(track(2, "Something")),
|
||||
"Led Zeppelin/IV/01 - Black Dog.mp3": zeppelin(track(1, "Black Dog")),
|
||||
"Led Zeppelin/IV/02 - Rock and Roll.mp3": zeppelin(track(2, "Rock and Roll")),
|
||||
})
|
||||
|
||||
// Jazz library content
|
||||
miles := template(_t{"albumartist": "Miles Davis", "album": "Kind of Blue", "year": 1959, "genre": "Jazz"})
|
||||
coltrane := template(_t{"albumartist": "John Coltrane", "album": "Giant Steps", "year": 1960, "genre": "Jazz"})
|
||||
|
||||
_ = createFS("jazz", fstest.MapFS{
|
||||
"Miles Davis/Kind of Blue/01 - So What.mp3": miles(track(1, "So What")),
|
||||
"Miles Davis/Kind of Blue/02 - Freddie Freeloader.mp3": miles(track(2, "Freddie Freeloader")),
|
||||
"John Coltrane/Giant Steps/01 - Giant Steps.mp3": coltrane(track(1, "Giant Steps")),
|
||||
"John Coltrane/Giant Steps/02 - Cousin Mary.mp3": coltrane(track(2, "Cousin Mary")),
|
||||
})
|
||||
})
|
||||
|
||||
When("scanning both libraries", func() {
|
||||
It("should import files with correct library_id", func() {
|
||||
Expect(runScanner(ctx, true)).To(Succeed())
|
||||
|
||||
// Check Rock library media files
|
||||
rockFiles, err := ds.MediaFile(ctx).GetAll(model.QueryOptions{
|
||||
Filters: squirrel.Eq{"library_id": lib1.ID},
|
||||
Sort: "title",
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(rockFiles).To(HaveLen(4))
|
||||
|
||||
rockTitles := slice.Map(rockFiles, func(f model.MediaFile) string { return f.Title })
|
||||
Expect(rockTitles).To(ContainElements("Come Together", "Something", "Black Dog", "Rock and Roll"))
|
||||
|
||||
// Verify all rock files have correct library_id
|
||||
for _, mf := range rockFiles {
|
||||
Expect(mf.LibraryID).To(Equal(lib1.ID), "Rock file %s should have library_id %d", mf.Title, lib1.ID)
|
||||
}
|
||||
|
||||
// Check Jazz library media files
|
||||
jazzFiles, err := ds.MediaFile(ctx).GetAll(model.QueryOptions{
|
||||
Filters: squirrel.Eq{"library_id": lib2.ID},
|
||||
Sort: "title",
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(jazzFiles).To(HaveLen(4))
|
||||
|
||||
jazzTitles := slice.Map(jazzFiles, func(f model.MediaFile) string { return f.Title })
|
||||
Expect(jazzTitles).To(ContainElements("So What", "Freddie Freeloader", "Giant Steps", "Cousin Mary"))
|
||||
|
||||
// Verify all jazz files have correct library_id
|
||||
for _, mf := range jazzFiles {
|
||||
Expect(mf.LibraryID).To(Equal(lib2.ID), "Jazz file %s should have library_id %d", mf.Title, lib2.ID)
|
||||
}
|
||||
})
|
||||
|
||||
It("should create albums with correct library_id", func() {
|
||||
Expect(runScanner(ctx, true)).To(Succeed())
|
||||
|
||||
// Check Rock library albums
|
||||
rockAlbums, err := ds.Album(ctx).GetAll(model.QueryOptions{
|
||||
Filters: squirrel.Eq{"library_id": lib1.ID},
|
||||
Sort: "name",
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(rockAlbums).To(HaveLen(2))
|
||||
Expect(rockAlbums[0].Name).To(Equal("Abbey Road"))
|
||||
Expect(rockAlbums[0].LibraryID).To(Equal(lib1.ID))
|
||||
Expect(rockAlbums[0].SongCount).To(Equal(2))
|
||||
Expect(rockAlbums[1].Name).To(Equal("IV"))
|
||||
Expect(rockAlbums[1].LibraryID).To(Equal(lib1.ID))
|
||||
Expect(rockAlbums[1].SongCount).To(Equal(2))
|
||||
|
||||
// Check Jazz library albums
|
||||
jazzAlbums, err := ds.Album(ctx).GetAll(model.QueryOptions{
|
||||
Filters: squirrel.Eq{"library_id": lib2.ID},
|
||||
Sort: "name",
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(jazzAlbums).To(HaveLen(2))
|
||||
Expect(jazzAlbums[0].Name).To(Equal("Giant Steps"))
|
||||
Expect(jazzAlbums[0].LibraryID).To(Equal(lib2.ID))
|
||||
Expect(jazzAlbums[0].SongCount).To(Equal(2))
|
||||
Expect(jazzAlbums[1].Name).To(Equal("Kind of Blue"))
|
||||
Expect(jazzAlbums[1].LibraryID).To(Equal(lib2.ID))
|
||||
Expect(jazzAlbums[1].SongCount).To(Equal(2))
|
||||
})
|
||||
|
||||
It("should create folders with correct library_id", func() {
|
||||
Expect(runScanner(ctx, true)).To(Succeed())
|
||||
|
||||
// Check Rock library folders
|
||||
rockFolders, err := ds.Folder(ctx).GetAll(model.QueryOptions{
|
||||
Filters: squirrel.Eq{"library_id": lib1.ID},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(rockFolders).To(HaveLen(5)) // ., The Beatles, Led Zeppelin, Abbey Road, IV
|
||||
|
||||
for _, folder := range rockFolders {
|
||||
Expect(folder.LibraryID).To(Equal(lib1.ID), "Rock folder %s should have library_id %d", folder.Name, lib1.ID)
|
||||
}
|
||||
|
||||
// Check Jazz library folders
|
||||
jazzFolders, err := ds.Folder(ctx).GetAll(model.QueryOptions{
|
||||
Filters: squirrel.Eq{"library_id": lib2.ID},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(jazzFolders).To(HaveLen(5)) // ., Miles Davis, John Coltrane, Kind of Blue, Giant Steps
|
||||
|
||||
for _, folder := range jazzFolders {
|
||||
Expect(folder.LibraryID).To(Equal(lib2.ID), "Jazz folder %s should have library_id %d", folder.Name, lib2.ID)
|
||||
}
|
||||
})
|
||||
|
||||
It("should create library-artist associations correctly", func() {
|
||||
Expect(runScanner(ctx, true)).To(Succeed())
|
||||
|
||||
// Check library-artist associations
|
||||
|
||||
// Get all artists and check library associations
|
||||
allArtists, err := ds.Artist(ctx).GetAll()
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
|
||||
rockArtistNames := []string{}
|
||||
jazzArtistNames := []string{}
|
||||
|
||||
for _, artist := range allArtists {
|
||||
// Check if artist is associated with rock library
|
||||
var count int64
|
||||
err := db.Db().QueryRow(
|
||||
"SELECT COUNT(*) FROM library_artist WHERE library_id = ? AND artist_id = ?",
|
||||
lib1.ID, artist.ID,
|
||||
).Scan(&count)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
if count > 0 {
|
||||
rockArtistNames = append(rockArtistNames, artist.Name)
|
||||
}
|
||||
|
||||
// Check if artist is associated with jazz library
|
||||
err = db.Db().QueryRow(
|
||||
"SELECT COUNT(*) FROM library_artist WHERE library_id = ? AND artist_id = ?",
|
||||
lib2.ID, artist.ID,
|
||||
).Scan(&count)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
if count > 0 {
|
||||
jazzArtistNames = append(jazzArtistNames, artist.Name)
|
||||
}
|
||||
}
|
||||
|
||||
Expect(rockArtistNames).To(ContainElements("The Beatles", "Led Zeppelin"))
|
||||
Expect(jazzArtistNames).To(ContainElements("Miles Davis", "John Coltrane"))
|
||||
|
||||
// Artists should not be shared between libraries (except [Unknown Artist])
|
||||
for _, name := range rockArtistNames {
|
||||
if name != "[Unknown Artist]" {
|
||||
Expect(jazzArtistNames).ToNot(ContainElement(name))
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
It("should update library statistics correctly", func() {
|
||||
Expect(runScanner(ctx, true)).To(Succeed())
|
||||
|
||||
// Check Rock library stats
|
||||
rockLib, err := ds.Library(ctx).Get(lib1.ID)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(rockLib.TotalSongs).To(Equal(4))
|
||||
Expect(rockLib.TotalAlbums).To(Equal(2))
|
||||
Expect(rockLib.TotalArtists).To(BeNumerically(">=", 2))
|
||||
Expect(rockLib.TotalFolders).To(BeNumerically(">=", 2))
|
||||
|
||||
// Check Jazz library stats
|
||||
jazzLib, err := ds.Library(ctx).Get(lib2.ID)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(jazzLib.TotalSongs).To(Equal(4))
|
||||
Expect(jazzLib.TotalAlbums).To(Equal(2))
|
||||
Expect(jazzLib.TotalArtists).To(BeNumerically(">=", 2))
|
||||
Expect(jazzLib.TotalFolders).To(BeNumerically(">=", 2))
|
||||
})
|
||||
})
|
||||
|
||||
When("libraries have different content", func() {
|
||||
It("should maintain separate statistics per library", func() {
|
||||
Expect(runScanner(ctx, true)).To(Succeed())
|
||||
|
||||
// Verify rock library stats
|
||||
rockLib, err := ds.Library(ctx).Get(lib1.ID)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(rockLib.TotalSongs).To(Equal(4))
|
||||
Expect(rockLib.TotalAlbums).To(Equal(2))
|
||||
|
||||
// Verify jazz library stats
|
||||
jazzLib, err := ds.Library(ctx).Get(lib2.ID)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(jazzLib.TotalSongs).To(Equal(4))
|
||||
Expect(jazzLib.TotalAlbums).To(Equal(2))
|
||||
|
||||
// Verify that libraries don't interfere with each other
|
||||
rockFiles, err := ds.MediaFile(ctx).GetAll(model.QueryOptions{
|
||||
Filters: squirrel.Eq{"library_id": lib1.ID},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(rockFiles).To(HaveLen(4))
|
||||
|
||||
jazzFiles, err := ds.MediaFile(ctx).GetAll(model.QueryOptions{
|
||||
Filters: squirrel.Eq{"library_id": lib2.ID},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(jazzFiles).To(HaveLen(4))
|
||||
})
|
||||
})
|
||||
|
||||
When("verifying library isolation", func() {
|
||||
It("should keep library data completely separate", func() {
|
||||
Expect(runScanner(ctx, true)).To(Succeed())
|
||||
|
||||
// Verify that rock library only contains rock content
|
||||
rockAlbums, err := ds.Album(ctx).GetAll(model.QueryOptions{
|
||||
Filters: squirrel.Eq{"library_id": lib1.ID},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
rockAlbumNames := slice.Map(rockAlbums, func(a model.Album) string { return a.Name })
|
||||
Expect(rockAlbumNames).To(ContainElements("Abbey Road", "IV"))
|
||||
Expect(rockAlbumNames).ToNot(ContainElements("Kind of Blue", "Giant Steps"))
|
||||
|
||||
// Verify that jazz library only contains jazz content
|
||||
jazzAlbums, err := ds.Album(ctx).GetAll(model.QueryOptions{
|
||||
Filters: squirrel.Eq{"library_id": lib2.ID},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
jazzAlbumNames := slice.Map(jazzAlbums, func(a model.Album) string { return a.Name })
|
||||
Expect(jazzAlbumNames).To(ContainElements("Kind of Blue", "Giant Steps"))
|
||||
Expect(jazzAlbumNames).ToNot(ContainElements("Abbey Road", "IV"))
|
||||
})
|
||||
})
|
||||
|
||||
When("same artist appears in different libraries", func() {
|
||||
It("should associate artist with both libraries correctly", func() {
|
||||
// Create libraries with Jeff Beck albums in both
|
||||
jeffRock := template(_t{"albumartist": "Jeff Beck", "album": "Truth", "year": 1968, "genre": "Rock"})
|
||||
jeffJazz := template(_t{"albumartist": "Jeff Beck", "album": "Blow by Blow", "year": 1975, "genre": "Jazz"})
|
||||
beatles := template(_t{"albumartist": "The Beatles", "album": "Abbey Road", "year": 1969, "genre": "Rock"})
|
||||
miles := template(_t{"albumartist": "Miles Davis", "album": "Kind of Blue", "year": 1959, "genre": "Jazz"})
|
||||
|
||||
// Create rock library with Jeff Beck's Truth album
|
||||
_ = createFS("rock", fstest.MapFS{
|
||||
"The Beatles/Abbey Road/01 - Come Together.mp3": beatles(track(1, "Come Together")),
|
||||
"The Beatles/Abbey Road/02 - Something.mp3": beatles(track(2, "Something")),
|
||||
"Jeff Beck/Truth/01 - Beck's Bolero.mp3": jeffRock(track(1, "Beck's Bolero")),
|
||||
"Jeff Beck/Truth/02 - Ol' Man River.mp3": jeffRock(track(2, "Ol' Man River")),
|
||||
})
|
||||
|
||||
// Create jazz library with Jeff Beck's Blow by Blow album
|
||||
_ = createFS("jazz", fstest.MapFS{
|
||||
"Miles Davis/Kind of Blue/01 - So What.mp3": miles(track(1, "So What")),
|
||||
"Miles Davis/Kind of Blue/02 - Freddie Freeloader.mp3": miles(track(2, "Freddie Freeloader")),
|
||||
"Jeff Beck/Blow by Blow/01 - You Know What I Mean.mp3": jeffJazz(track(1, "You Know What I Mean")),
|
||||
"Jeff Beck/Blow by Blow/02 - She's a Woman.mp3": jeffJazz(track(2, "She's a Woman")),
|
||||
})
|
||||
|
||||
Expect(runScanner(ctx, true)).To(Succeed())
|
||||
|
||||
// Jeff Beck should be associated with both libraries
|
||||
var rockCount, jazzCount int64
|
||||
|
||||
// Get Jeff Beck artist ID
|
||||
jeffArtists, err := ds.Artist(ctx).GetAll(model.QueryOptions{
|
||||
Filters: squirrel.Eq{"name": "Jeff Beck"},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(jeffArtists).To(HaveLen(1))
|
||||
jeffID := jeffArtists[0].ID
|
||||
|
||||
// Check rock library association
|
||||
err = db.Db().QueryRow(
|
||||
"SELECT COUNT(*) FROM library_artist WHERE library_id = ? AND artist_id = ?",
|
||||
lib1.ID, jeffID,
|
||||
).Scan(&rockCount)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(rockCount).To(Equal(int64(1)))
|
||||
|
||||
// Check jazz library association
|
||||
err = db.Db().QueryRow(
|
||||
"SELECT COUNT(*) FROM library_artist WHERE library_id = ? AND artist_id = ?",
|
||||
lib2.ID, jeffID,
|
||||
).Scan(&jazzCount)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(jazzCount).To(Equal(int64(1)))
|
||||
|
||||
// Verify Jeff Beck albums are in correct libraries
|
||||
rockAlbums, err := ds.Album(ctx).GetAll(model.QueryOptions{
|
||||
Filters: squirrel.Eq{"library_id": lib1.ID, "album_artist": "Jeff Beck"},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(rockAlbums).To(HaveLen(1))
|
||||
Expect(rockAlbums[0].Name).To(Equal("Truth"))
|
||||
|
||||
jazzAlbums, err := ds.Album(ctx).GetAll(model.QueryOptions{
|
||||
Filters: squirrel.Eq{"library_id": lib2.ID, "album_artist": "Jeff Beck"},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(jazzAlbums).To(HaveLen(1))
|
||||
Expect(jazzAlbums[0].Name).To(Equal("Blow by Blow"))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
Context("Incremental Scan Behavior", func() {
|
||||
BeforeEach(func() {
|
||||
// Start with minimal content in both libraries
|
||||
rock := template(_t{"albumartist": "Queen", "album": "News of the World", "year": 1977, "genre": "Rock"})
|
||||
jazz := template(_t{"albumartist": "Bill Evans", "album": "Waltz for Debby", "year": 1961, "genre": "Jazz"})
|
||||
|
||||
createFS("rock", fstest.MapFS{
|
||||
"Queen/News of the World/01 - We Will Rock You.mp3": rock(track(1, "We Will Rock You")),
|
||||
})
|
||||
|
||||
createFS("jazz", fstest.MapFS{
|
||||
"Bill Evans/Waltz for Debby/01 - My Foolish Heart.mp3": jazz(track(1, "My Foolish Heart")),
|
||||
})
|
||||
})
|
||||
|
||||
It("should handle incremental scans per library correctly", func() {
|
||||
// Initial full scan
|
||||
Expect(runScanner(ctx, true)).To(Succeed())
|
||||
|
||||
// Verify initial state
|
||||
rockFiles, err := ds.MediaFile(ctx).GetAll(model.QueryOptions{
|
||||
Filters: squirrel.Eq{"library_id": lib1.ID},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(rockFiles).To(HaveLen(1))
|
||||
|
||||
jazzFiles, err := ds.MediaFile(ctx).GetAll(model.QueryOptions{
|
||||
Filters: squirrel.Eq{"library_id": lib2.ID},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(jazzFiles).To(HaveLen(1))
|
||||
|
||||
// Incremental scan should not duplicate existing files
|
||||
Expect(runScanner(ctx, false)).To(Succeed())
|
||||
|
||||
// Verify counts remain the same
|
||||
rockFiles, err = ds.MediaFile(ctx).GetAll(model.QueryOptions{
|
||||
Filters: squirrel.Eq{"library_id": lib1.ID},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(rockFiles).To(HaveLen(1))
|
||||
|
||||
jazzFiles, err = ds.MediaFile(ctx).GetAll(model.QueryOptions{
|
||||
Filters: squirrel.Eq{"library_id": lib2.ID},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(jazzFiles).To(HaveLen(1))
|
||||
})
|
||||
})
|
||||
|
||||
Context("Missing Files Handling", func() {
|
||||
var rockFS storagetest.FakeFS
|
||||
|
||||
BeforeEach(func() {
|
||||
rock := template(_t{"albumartist": "AC/DC", "album": "Back in Black", "year": 1980, "genre": "Rock"})
|
||||
|
||||
rockFS = createFS("rock", fstest.MapFS{
|
||||
"AC-DC/Back in Black/01 - Hells Bells.mp3": rock(track(1, "Hells Bells")),
|
||||
"AC-DC/Back in Black/02 - Shoot to Thrill.mp3": rock(track(2, "Shoot to Thrill")),
|
||||
})
|
||||
|
||||
createFS("jazz", fstest.MapFS{
|
||||
"Herbie Hancock/Head Hunters/01 - Chameleon.mp3": template(_t{
|
||||
"albumartist": "Herbie Hancock", "album": "Head Hunters", "year": 1973, "genre": "Jazz",
|
||||
})(track(1, "Chameleon")),
|
||||
})
|
||||
})
|
||||
|
||||
It("should mark missing files correctly per library", func() {
|
||||
// Initial scan
|
||||
Expect(runScanner(ctx, true)).To(Succeed())
|
||||
|
||||
// Remove one file from rock library only
|
||||
rockFS.Remove("AC-DC/Back in Black/02 - Shoot to Thrill.mp3")
|
||||
|
||||
// Rescan
|
||||
Expect(runScanner(ctx, false)).To(Succeed())
|
||||
|
||||
// Check that only the rock library file is marked as missing
|
||||
missingRockFiles, err := ds.MediaFile(ctx).GetAll(model.QueryOptions{
|
||||
Filters: squirrel.And{
|
||||
squirrel.Eq{"library_id": lib1.ID},
|
||||
squirrel.Eq{"missing": true},
|
||||
},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(missingRockFiles).To(HaveLen(1))
|
||||
Expect(missingRockFiles[0].Title).To(Equal("Shoot to Thrill"))
|
||||
|
||||
// Check that jazz library files are not affected
|
||||
missingJazzFiles, err := ds.MediaFile(ctx).GetAll(model.QueryOptions{
|
||||
Filters: squirrel.And{
|
||||
squirrel.Eq{"library_id": lib2.ID},
|
||||
squirrel.Eq{"missing": true},
|
||||
},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(missingJazzFiles).To(HaveLen(0))
|
||||
|
||||
// Verify non-missing files
|
||||
presentRockFiles, err := ds.MediaFile(ctx).GetAll(model.QueryOptions{
|
||||
Filters: squirrel.And{
|
||||
squirrel.Eq{"library_id": lib1.ID},
|
||||
squirrel.Eq{"missing": false},
|
||||
},
|
||||
})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(presentRockFiles).To(HaveLen(1))
|
||||
Expect(presentRockFiles[0].Title).To(Equal("Hells Bells"))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
@ -27,6 +27,7 @@ type MockDataStore struct {
|
|||
MockedScrobbleBuffer model.ScrobbleBufferRepository
|
||||
MockedRadio model.RadioRepository
|
||||
scrobbleBufferMu sync.Mutex
|
||||
repoMu sync.Mutex
|
||||
}
|
||||
|
||||
func (db *MockDataStore) Library(ctx context.Context) model.LibraryRepository {
|
||||
|
|
@ -85,6 +86,8 @@ func (db *MockDataStore) Artist(ctx context.Context) model.ArtistRepository {
|
|||
}
|
||||
|
||||
func (db *MockDataStore) MediaFile(ctx context.Context) model.MediaFileRepository {
|
||||
db.repoMu.Lock()
|
||||
defer db.repoMu.Unlock()
|
||||
if db.MockedMediaFile == nil {
|
||||
if db.RealDS != nil {
|
||||
db.MockedMediaFile = db.RealDS.MediaFile(ctx)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue