navidrome/scanner/scanner_test.go
Deluan 1e4c759d93 test: fix flaky scanner tests by setting maximum open connections to 1
Signed-off-by: Deluan <deluan@navidrome.org>
2025-05-23 15:39:44 -04:00

641 lines
23 KiB
Go

package scanner_test
import (
"context"
"errors"
"path/filepath"
"testing/fstest"
"github.com/Masterminds/squirrel"
"github.com/google/uuid"
"github.com/navidrome/navidrome/conf"
"github.com/navidrome/navidrome/conf/configtest"
"github.com/navidrome/navidrome/consts"
"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"
)
// Easy aliases for the storagetest package
type _t = map[string]any
var template = storagetest.Template
var track = storagetest.Track
var _ = Describe("Scanner", Ordered, func() {
var ctx context.Context
var lib model.Library
var ds *tests.MockDataStore
var mfRepo *mockMediaFileRepo
var s scanner.Scanner
createFS := func(files fstest.MapFS) storagetest.FakeFS {
fs := storagetest.FakeFS{}
fs.SetFiles(files)
storagetest.Register("fake", &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.db?_journal_mode=WAL")
log.Warn("Using DB at " + conf.Server.DbPath)
//conf.Server.DbPath = ":memory:"
db.Db().SetMaxOpenConns(1)
})
BeforeEach(func() {
db.Init(ctx)
DeferCleanup(func() {
Expect(tests.ClearDB()).To(Succeed())
})
DeferCleanup(configtest.SetupConfig())
conf.Server.DevExternalScanner = false
ds = &tests.MockDataStore{RealDS: persistence.New(db.Db())}
mfRepo = &mockMediaFileRepo{
MediaFileRepository: ds.RealDS.MediaFile(ctx),
}
ds.MockedMediaFile = mfRepo
s = scanner.New(ctx, ds, artwork.NoopCacheWarmer(), events.NoopBroker(),
core.NewPlaylists(ds), metrics.NewNoopInstance())
lib = model.Library{ID: 1, Name: "Fake Library", Path: "fake:///music"}
Expect(ds.Library(ctx).Put(&lib)).To(Succeed())
})
runScanner := func(ctx context.Context, fullScan bool) error {
_, err := s.ScanAll(ctx, fullScan)
return err
}
Context("Simple library, 'artis/album/track - title.mp3'", func() {
var help, revolver func(...map[string]any) *fstest.MapFile
var fsys storagetest.FakeFS
BeforeEach(func() {
revolver = template(_t{"albumartist": "The Beatles", "album": "Revolver", "year": 1966})
help = template(_t{"albumartist": "The Beatles", "album": "Help!", "year": 1965})
fsys = createFS(fstest.MapFS{
"The Beatles/Revolver/01 - Taxman.mp3": revolver(track(1, "Taxman")),
"The Beatles/Revolver/02 - Eleanor Rigby.mp3": revolver(track(2, "Eleanor Rigby")),
"The Beatles/Revolver/03 - I'm Only Sleeping.mp3": revolver(track(3, "I'm Only Sleeping")),
"The Beatles/Revolver/04 - Love You To.mp3": revolver(track(4, "Love You To")),
"The Beatles/Help!/01 - Help!.mp3": help(track(1, "Help!")),
"The Beatles/Help!/02 - The Night Before.mp3": help(track(2, "The Night Before")),
"The Beatles/Help!/03 - You've Got to Hide Your Love Away.mp3": help(track(3, "You've Got to Hide Your Love Away")),
})
})
When("it is the first scan", func() {
It("should import all folders", func() {
Expect(runScanner(ctx, true)).To(Succeed())
folders, _ := ds.Folder(ctx).GetAll(model.QueryOptions{Filters: squirrel.Eq{"library_id": lib.ID}})
paths := slice.Map(folders, func(f model.Folder) string { return f.Name })
Expect(paths).To(SatisfyAll(
HaveLen(4),
ContainElements(".", "The Beatles", "Revolver", "Help!"),
))
})
It("should import all mediafiles", func() {
Expect(runScanner(ctx, true)).To(Succeed())
mfs, _ := ds.MediaFile(ctx).GetAll()
paths := slice.Map(mfs, func(f model.MediaFile) string { return f.Title })
Expect(paths).To(SatisfyAll(
HaveLen(7),
ContainElements(
"Taxman", "Eleanor Rigby", "I'm Only Sleeping", "Love You To",
"Help!", "The Night Before", "You've Got to Hide Your Love Away",
),
))
})
It("should import all albums", func() {
Expect(runScanner(ctx, true)).To(Succeed())
albums, _ := ds.Album(ctx).GetAll(model.QueryOptions{Sort: "name"})
Expect(albums).To(HaveLen(2))
Expect(albums[0]).To(SatisfyAll(
HaveField("Name", Equal("Help!")),
HaveField("SongCount", Equal(3)),
))
Expect(albums[1]).To(SatisfyAll(
HaveField("Name", Equal("Revolver")),
HaveField("SongCount", Equal(4)),
))
})
})
When("a file was changed", func() {
It("should update the media_file", func() {
Expect(runScanner(ctx, true)).To(Succeed())
mf, err := ds.MediaFile(ctx).GetAll(model.QueryOptions{Filters: squirrel.Eq{"title": "Help!"}})
Expect(err).ToNot(HaveOccurred())
Expect(mf[0].Tags).ToNot(HaveKey("barcode"))
fsys.UpdateTags("The Beatles/Help!/01 - Help!.mp3", _t{"barcode": "123"})
Expect(runScanner(ctx, true)).To(Succeed())
mf, err = ds.MediaFile(ctx).GetAll(model.QueryOptions{Filters: squirrel.Eq{"title": "Help!"}})
Expect(err).ToNot(HaveOccurred())
Expect(mf[0].Tags).To(HaveKeyWithValue(model.TagName("barcode"), []string{"123"}))
})
It("should update the album", func() {
Expect(runScanner(ctx, true)).To(Succeed())
albums, err := ds.Album(ctx).GetAll(model.QueryOptions{Filters: squirrel.Eq{"album.name": "Help!"}})
Expect(err).ToNot(HaveOccurred())
Expect(albums).ToNot(BeEmpty())
Expect(albums[0].Participants.First(model.RoleProducer).Name).To(BeEmpty())
Expect(albums[0].SongCount).To(Equal(3))
fsys.UpdateTags("The Beatles/Help!/01 - Help!.mp3", _t{"producer": "George Martin"})
Expect(runScanner(ctx, false)).To(Succeed())
albums, err = ds.Album(ctx).GetAll(model.QueryOptions{Filters: squirrel.Eq{"album.name": "Help!"}})
Expect(err).ToNot(HaveOccurred())
Expect(albums[0].Participants.First(model.RoleProducer).Name).To(Equal("George Martin"))
Expect(albums[0].SongCount).To(Equal(3))
})
})
})
Context("Ignored entries", func() {
BeforeEach(func() {
revolver := template(_t{"albumartist": "The Beatles", "album": "Revolver", "year": 1966})
createFS(fstest.MapFS{
"The Beatles/Revolver/01 - Taxman.mp3": revolver(track(1, "Taxman")),
"The Beatles/Revolver/._01 - Taxman.mp3": &fstest.MapFile{Data: []byte("garbage data")},
})
})
It("should not import the ignored file", func() {
Expect(runScanner(ctx, true)).To(Succeed())
mfs, err := ds.MediaFile(ctx).GetAll()
Expect(err).ToNot(HaveOccurred())
Expect(mfs).To(HaveLen(1))
for _, mf := range mfs {
Expect(mf.Title).To(Equal("Taxman"))
Expect(mf.Path).To(Equal("The Beatles/Revolver/01 - Taxman.mp3"))
}
})
})
Context("Same album in two different folders", func() {
BeforeEach(func() {
revolver := template(_t{"albumartist": "The Beatles", "album": "Revolver", "year": 1966})
createFS(fstest.MapFS{
"The Beatles/Revolver/01 - Taxman.mp3": revolver(track(1, "Taxman")),
"The Beatles/Revolver2/02 - Eleanor Rigby.mp3": revolver(track(2, "Eleanor Rigby")),
})
})
It("should import as one album", func() {
Expect(runScanner(ctx, true)).To(Succeed())
albums, err := ds.Album(ctx).GetAll()
Expect(err).ToNot(HaveOccurred())
Expect(albums).To(HaveLen(1))
mfs, err := ds.MediaFile(ctx).GetAll()
Expect(err).ToNot(HaveOccurred())
Expect(mfs).To(HaveLen(2))
for _, mf := range mfs {
Expect(mf.AlbumID).To(Equal(albums[0].ID))
}
})
})
Context("Same album, different release dates", func() {
BeforeEach(func() {
help := template(_t{"albumartist": "The Beatles", "album": "Help!", "releasedate": 1965})
help2 := template(_t{"albumartist": "The Beatles", "album": "Help!", "releasedate": 2000})
createFS(fstest.MapFS{
"The Beatles/Help!/01 - Help!.mp3": help(track(1, "Help!")),
"The Beatles/Help! (remaster)/01 - Help!.mp3": help2(track(1, "Help!")),
})
})
It("should import as two distinct albums", func() {
Expect(runScanner(ctx, true)).To(Succeed())
albums, err := ds.Album(ctx).GetAll(model.QueryOptions{Sort: "release_date"})
Expect(err).ToNot(HaveOccurred())
Expect(albums).To(HaveLen(2))
Expect(albums[0]).To(SatisfyAll(
HaveField("Name", Equal("Help!")),
HaveField("ReleaseDate", Equal("1965")),
))
Expect(albums[1]).To(SatisfyAll(
HaveField("Name", Equal("Help!")),
HaveField("ReleaseDate", Equal("2000")),
))
})
})
Describe("Library changes'", func() {
var help, revolver func(...map[string]any) *fstest.MapFile
var fsys storagetest.FakeFS
var findByPath func(string) (*model.MediaFile, error)
var beatlesMBID = uuid.NewString()
BeforeEach(func() {
By("Having two MP3 albums")
beatles := _t{
"artist": "The Beatles",
"artistsort": "Beatles, The",
"musicbrainz_artistid": beatlesMBID,
}
help = template(beatles, _t{"album": "Help!", "year": 1965})
revolver = template(beatles, _t{"album": "Revolver", "year": 1966})
fsys = createFS(fstest.MapFS{
"The Beatles/Help!/01 - Help!.mp3": help(track(1, "Help!")),
"The Beatles/Help!/02 - The Night Before.mp3": help(track(2, "The Night Before")),
"The Beatles/Revolver/01 - Taxman.mp3": revolver(track(1, "Taxman")),
"The Beatles/Revolver/02 - Eleanor Rigby.mp3": revolver(track(2, "Eleanor Rigby")),
})
By("Doing a full scan")
Expect(runScanner(ctx, true)).To(Succeed())
Expect(ds.MediaFile(ctx).CountAll()).To(Equal(int64(4)))
findByPath = createFindByPath(ctx, ds)
})
It("adds new files to the library", func() {
fsys.Add("The Beatles/Revolver/03 - I'm Only Sleeping.mp3", revolver(track(3, "I'm Only Sleeping")))
Expect(runScanner(ctx, false)).To(Succeed())
Expect(ds.MediaFile(ctx).CountAll()).To(Equal(int64(5)))
mf, err := findByPath("The Beatles/Revolver/03 - I'm Only Sleeping.mp3")
Expect(err).ToNot(HaveOccurred())
Expect(mf.Title).To(Equal("I'm Only Sleeping"))
})
It("updates tags of a file in the library", func() {
fsys.UpdateTags("The Beatles/Revolver/02 - Eleanor Rigby.mp3", _t{"title": "Eleanor Rigby (remix)"})
Expect(runScanner(ctx, false)).To(Succeed())
Expect(ds.MediaFile(ctx).CountAll()).To(Equal(int64(4)))
mf, _ := findByPath("The Beatles/Revolver/02 - Eleanor Rigby.mp3")
Expect(mf.Title).To(Equal("Eleanor Rigby (remix)"))
})
It("upgrades file with same format in the library", func() {
fsys.Add("The Beatles/Revolver/01 - Taxman.mp3", revolver(track(1, "Taxman", _t{"bitrate": 640})))
Expect(runScanner(ctx, false)).To(Succeed())
Expect(ds.MediaFile(ctx).CountAll()).To(Equal(int64(4)))
mf, _ := findByPath("The Beatles/Revolver/01 - Taxman.mp3")
Expect(mf.BitRate).To(Equal(640))
})
It("detects a file was removed from the library", func() {
By("Removing a file")
fsys.Remove("The Beatles/Revolver/02 - Eleanor Rigby.mp3")
By("Rescanning the library")
Expect(runScanner(ctx, false)).To(Succeed())
By("Checking the file is marked as missing")
Expect(ds.MediaFile(ctx).CountAll(model.QueryOptions{
Filters: squirrel.Eq{"missing": false},
})).To(Equal(int64(3)))
mf, err := findByPath("The Beatles/Revolver/02 - Eleanor Rigby.mp3")
Expect(err).ToNot(HaveOccurred())
Expect(mf.Missing).To(BeTrue())
})
It("detects a file was moved to a different folder", func() {
By("Storing the original ID")
original, err := findByPath("The Beatles/Revolver/02 - Eleanor Rigby.mp3")
Expect(err).ToNot(HaveOccurred())
originalId := original.ID
By("Moving the file to a different folder")
fsys.Move("The Beatles/Revolver/02 - Eleanor Rigby.mp3", "The Beatles/Help!/02 - Eleanor Rigby.mp3")
By("Rescanning the library")
Expect(runScanner(ctx, false)).To(Succeed())
By("Checking the old file is not in the library")
Expect(ds.MediaFile(ctx).CountAll(model.QueryOptions{
Filters: squirrel.Eq{"missing": false},
})).To(Equal(int64(4)))
_, err = findByPath("The Beatles/Revolver/02 - Eleanor Rigby.mp3")
Expect(err).To(MatchError(model.ErrNotFound))
By("Checking the new file is in the library")
Expect(ds.MediaFile(ctx).CountAll(model.QueryOptions{
Filters: squirrel.Eq{"missing": true},
})).To(BeZero())
mf, err := findByPath("The Beatles/Help!/02 - Eleanor Rigby.mp3")
Expect(err).ToNot(HaveOccurred())
Expect(mf.Title).To(Equal("Eleanor Rigby"))
Expect(mf.Missing).To(BeFalse())
By("Checking the new file has the same ID as the original")
Expect(mf.ID).To(Equal(originalId))
})
It("detects a move after a scan is interrupted by an error", func() {
By("Storing the original ID")
By("Moving the file to a different folder")
fsys.Move("The Beatles/Revolver/01 - Taxman.mp3", "The Beatles/Help!/01 - Taxman.mp3")
By("Interrupting the scan with an error before the move is processed")
mfRepo.GetMissingAndMatchingError = errors.New("I/O read error")
Expect(runScanner(ctx, false)).To(MatchError(ContainSubstring("I/O read error")))
By("Checking the both instances of the file are in the lib")
Expect(ds.MediaFile(ctx).CountAll(model.QueryOptions{
Filters: squirrel.Eq{"title": "Taxman"},
})).To(Equal(int64(2)))
By("Rescanning the library without error")
mfRepo.GetMissingAndMatchingError = nil
Expect(runScanner(ctx, false)).To(Succeed())
By("Checking the old file is not in the library")
mfs, err := ds.MediaFile(ctx).GetAll(model.QueryOptions{
Filters: squirrel.Eq{"title": "Taxman"},
})
Expect(err).ToNot(HaveOccurred())
Expect(mfs).To(HaveLen(1))
Expect(mfs[0].Path).To(Equal("The Beatles/Help!/01 - Taxman.mp3"))
})
It("detects file format upgrades", func() {
By("Storing the original ID")
original, err := findByPath("The Beatles/Revolver/02 - Eleanor Rigby.mp3")
Expect(err).ToNot(HaveOccurred())
originalId := original.ID
By("Replacing the file with a different format")
fsys.Move("The Beatles/Revolver/02 - Eleanor Rigby.mp3", "The Beatles/Revolver/02 - Eleanor Rigby.flac")
By("Rescanning the library")
Expect(runScanner(ctx, false)).To(Succeed())
By("Checking the old file is not in the library")
Expect(ds.MediaFile(ctx).CountAll(model.QueryOptions{
Filters: squirrel.Eq{"missing": true},
})).To(BeZero())
_, err = findByPath("The Beatles/Revolver/02 - Eleanor Rigby.mp3")
Expect(err).To(MatchError(model.ErrNotFound))
By("Checking the new file is in the library")
Expect(ds.MediaFile(ctx).CountAll(model.QueryOptions{
Filters: squirrel.Eq{"missing": false},
})).To(Equal(int64(4)))
mf, err := findByPath("The Beatles/Revolver/02 - Eleanor Rigby.flac")
Expect(err).ToNot(HaveOccurred())
Expect(mf.Title).To(Equal("Eleanor Rigby"))
Expect(mf.Missing).To(BeFalse())
By("Checking the new file has the same ID as the original")
Expect(mf.ID).To(Equal(originalId))
})
It("detects old missing tracks being added back", func() {
By("Removing a file")
origFile := fsys.Remove("The Beatles/Revolver/02 - Eleanor Rigby.mp3")
By("Rescanning the library")
Expect(runScanner(ctx, false)).To(Succeed())
By("Checking the file is marked as missing")
Expect(ds.MediaFile(ctx).CountAll(model.QueryOptions{
Filters: squirrel.Eq{"missing": false},
})).To(Equal(int64(3)))
mf, err := findByPath("The Beatles/Revolver/02 - Eleanor Rigby.mp3")
Expect(err).ToNot(HaveOccurred())
Expect(mf.Missing).To(BeTrue())
By("Adding the file back")
fsys.Add("The Beatles/Revolver/02 - Eleanor Rigby.mp3", origFile)
By("Rescanning the library again")
Expect(runScanner(ctx, false)).To(Succeed())
By("Checking the file is not marked as missing")
Expect(ds.MediaFile(ctx).CountAll(model.QueryOptions{
Filters: squirrel.Eq{"missing": false},
})).To(Equal(int64(4)))
mf, err = findByPath("The Beatles/Revolver/02 - Eleanor Rigby.mp3")
Expect(err).ToNot(HaveOccurred())
Expect(mf.Missing).To(BeFalse())
By("Removing it again")
fsys.Remove("The Beatles/Revolver/02 - Eleanor Rigby.mp3")
By("Rescanning the library again")
Expect(runScanner(ctx, false)).To(Succeed())
By("Checking the file is marked as missing")
mf, err = findByPath("The Beatles/Revolver/02 - Eleanor Rigby.mp3")
Expect(err).ToNot(HaveOccurred())
Expect(mf.Missing).To(BeTrue())
By("Adding the file back in a different folder")
fsys.Add("The Beatles/Help!/02 - Eleanor Rigby.mp3", origFile)
By("Rescanning the library once more")
Expect(runScanner(ctx, false)).To(Succeed())
By("Checking the file was found in the new folder")
Expect(ds.MediaFile(ctx).CountAll(model.QueryOptions{
Filters: squirrel.Eq{"missing": false},
})).To(Equal(int64(4)))
mf, err = findByPath("The Beatles/Help!/02 - Eleanor Rigby.mp3")
Expect(err).ToNot(HaveOccurred())
Expect(mf.Missing).To(BeFalse())
})
It("does not override artist fields when importing an undertagged file", func() {
By("Making sure artist in the DB contains MBID and sort name")
aa, err := ds.Artist(ctx).GetAll(model.QueryOptions{
Filters: squirrel.Eq{"name": "The Beatles"},
})
Expect(err).ToNot(HaveOccurred())
Expect(aa).To(HaveLen(1))
Expect(aa[0].Name).To(Equal("The Beatles"))
Expect(aa[0].MbzArtistID).To(Equal(beatlesMBID))
Expect(aa[0].SortArtistName).To(Equal("Beatles, The"))
By("Adding a new undertagged file (no MBID or sort name)")
newTrack := revolver(track(4, "Love You Too",
_t{"artist": "The Beatles", "musicbrainz_artistid": "", "artistsort": ""}),
)
fsys.Add("The Beatles/Revolver/04 - Love You Too.mp3", newTrack)
By("Doing a partial scan")
Expect(runScanner(ctx, false)).To(Succeed())
By("Asserting MediaFile have the artist name, but not the MBID or sort name")
mf, err := findByPath("The Beatles/Revolver/04 - Love You Too.mp3")
Expect(err).ToNot(HaveOccurred())
Expect(mf.Title).To(Equal("Love You Too"))
Expect(mf.AlbumArtist).To(Equal("The Beatles"))
Expect(mf.MbzAlbumArtistID).To(BeEmpty())
Expect(mf.SortArtistName).To(BeEmpty())
By("Makingsure the artist in the DB has not changed")
aa, err = ds.Artist(ctx).GetAll(model.QueryOptions{
Filters: squirrel.Eq{"name": "The Beatles"},
})
Expect(err).ToNot(HaveOccurred())
Expect(aa).To(HaveLen(1))
Expect(aa[0].Name).To(Equal("The Beatles"))
Expect(aa[0].MbzArtistID).To(Equal(beatlesMBID))
Expect(aa[0].SortArtistName).To(Equal("Beatles, The"))
})
Context("When PurgeMissing is configured", func() {
When("PurgeMissing is set to 'never'", func() {
BeforeEach(func() {
DeferCleanup(configtest.SetupConfig())
conf.Server.Scanner.PurgeMissing = consts.PurgeMissingNever
})
It("should mark files as missing but not delete them", func() {
By("Running initial scan")
Expect(runScanner(ctx, true)).To(Succeed())
By("Removing a file")
fsys.Remove("The Beatles/Revolver/02 - Eleanor Rigby.mp3")
By("Running another scan")
Expect(runScanner(ctx, true)).To(Succeed())
By("Checking files are marked as missing but not deleted")
count, err := ds.MediaFile(ctx).CountAll(model.QueryOptions{
Filters: squirrel.Eq{"missing": true},
})
Expect(err).ToNot(HaveOccurred())
Expect(count).To(Equal(int64(1)))
mf, err := findByPath("The Beatles/Revolver/02 - Eleanor Rigby.mp3")
Expect(err).ToNot(HaveOccurred())
Expect(mf.Missing).To(BeTrue())
})
})
When("PurgeMissing is set to 'always'", func() {
BeforeEach(func() {
conf.Server.Scanner.PurgeMissing = consts.PurgeMissingAlways
})
It("should purge missing files on any scan", func() {
By("Running initial scan")
Expect(runScanner(ctx, false)).To(Succeed())
By("Removing a file")
fsys.Remove("The Beatles/Revolver/02 - Eleanor Rigby.mp3")
By("Running an incremental scan")
Expect(runScanner(ctx, false)).To(Succeed())
By("Checking missing files are deleted")
count, err := ds.MediaFile(ctx).CountAll(model.QueryOptions{
Filters: squirrel.Eq{"missing": true},
})
Expect(err).ToNot(HaveOccurred())
Expect(count).To(BeZero())
_, err = findByPath("The Beatles/Revolver/02 - Eleanor Rigby.mp3")
Expect(err).To(MatchError(model.ErrNotFound))
})
})
When("PurgeMissing is set to 'full'", func() {
BeforeEach(func() {
conf.Server.Scanner.PurgeMissing = consts.PurgeMissingFull
})
It("should not purge missing files on incremental scans", func() {
By("Running initial scan")
Expect(runScanner(ctx, true)).To(Succeed())
By("Removing a file")
fsys.Remove("The Beatles/Revolver/02 - Eleanor Rigby.mp3")
By("Running an incremental scan")
Expect(runScanner(ctx, false)).To(Succeed())
By("Checking files are marked as missing but not deleted")
count, err := ds.MediaFile(ctx).CountAll(model.QueryOptions{
Filters: squirrel.Eq{"missing": true},
})
Expect(err).ToNot(HaveOccurred())
Expect(count).To(Equal(int64(1)))
mf, err := findByPath("The Beatles/Revolver/02 - Eleanor Rigby.mp3")
Expect(err).ToNot(HaveOccurred())
Expect(mf.Missing).To(BeTrue())
})
It("should purge missing files only on full scans", func() {
By("Running initial scan")
Expect(runScanner(ctx, true)).To(Succeed())
By("Removing a file")
fsys.Remove("The Beatles/Revolver/02 - Eleanor Rigby.mp3")
By("Running a full scan")
Expect(runScanner(ctx, true)).To(Succeed())
By("Checking missing files are deleted")
count, err := ds.MediaFile(ctx).CountAll(model.QueryOptions{
Filters: squirrel.Eq{"missing": true},
})
Expect(err).ToNot(HaveOccurred())
Expect(count).To(BeZero())
_, err = findByPath("The Beatles/Revolver/02 - Eleanor Rigby.mp3")
Expect(err).To(MatchError(model.ErrNotFound))
})
})
})
})
})
func createFindByPath(ctx context.Context, ds model.DataStore) func(string) (*model.MediaFile, error) {
return func(path string) (*model.MediaFile, error) {
list, err := ds.MediaFile(ctx).FindByPaths([]string{path})
if err != nil {
return nil, err
}
if len(list) == 0 {
return nil, model.ErrNotFound
}
return &list[0], nil
}
}
type mockMediaFileRepo struct {
model.MediaFileRepository
GetMissingAndMatchingError error
}
func (m *mockMediaFileRepo) GetMissingAndMatching(libId int) (model.MediaFileCursor, error) {
if m.GetMissingAndMatchingError != nil {
return nil, m.GetMissingAndMatchingError
}
return m.MediaFileRepository.GetMissingAndMatching(libId)
}