navidrome/core/image_upload_test.go

154 lines
5.0 KiB
Go

package core_test
import (
"context"
"os"
"path/filepath"
"strings"
"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/model"
"github.com/navidrome/navidrome/tests"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
var _ = Describe("ImageUploadService", func() {
var svc core.ImageUploadService
var tmpDir string
var artRepo *tests.MockArtworkRepo
var queueRepo *tests.MockArtworkQueueRepo
BeforeEach(func() {
DeferCleanup(configtest.SetupConfig())
tmpDir = GinkgoT().TempDir()
conf.Server.DataFolder = conf.NewDir(tmpDir)
artRepo = tests.CreateMockArtworkRepo()
queueRepo = tests.CreateMockArtworkQueueRepo()
ds := &tests.MockDataStore{MockedArtwork: artRepo, MockedArtworkQueue: queueRepo}
svc = core.NewImageUploadService(ds)
})
Describe("SetImage", func() {
It("creates directory and saves image file", func() {
ctx := context.Background()
reader := strings.NewReader("fake image data")
filename, err := svc.SetImage(ctx, consts.EntityArtist, "ar-1", "Pink Floyd", "", reader, ".jpg")
Expect(err).ToNot(HaveOccurred())
Expect(filename).To(Equal("ar-1_pink_floyd.jpg"))
absPath := filepath.Join(tmpDir, "artwork", "artist", "ar-1_pink_floyd.jpg")
data, err := os.ReadFile(absPath)
Expect(err).ToNot(HaveOccurred())
Expect(string(data)).To(Equal("fake image data"))
})
It("falls back to ID-only filename when name cleans to empty", func() {
ctx := context.Background()
reader := strings.NewReader("data")
filename, err := svc.SetImage(ctx, consts.EntityPlaylist, "pl-1", "!!!", "", reader, ".png")
Expect(err).ToNot(HaveOccurred())
Expect(filename).To(Equal("pl-1.png"))
})
It("removes old image when replacing", func() {
ctx := context.Background()
oldDir := filepath.Join(tmpDir, "artwork", "artist")
Expect(os.MkdirAll(oldDir, 0755)).To(Succeed())
oldFile := filepath.Join(oldDir, "ar-1_old.png")
Expect(os.WriteFile(oldFile, []byte("old"), 0600)).To(Succeed())
reader := strings.NewReader("new image")
_, err := svc.SetImage(ctx, consts.EntityArtist, "ar-1", "New Name", oldFile, reader, ".jpg")
Expect(err).ToNot(HaveOccurred())
Expect(oldFile).ToNot(BeAnExistingFile())
newPath := filepath.Join(oldDir, "ar-1_new_name.jpg")
Expect(newPath).To(BeAnExistingFile())
})
It("ignores missing old file without error", func() {
ctx := context.Background()
reader := strings.NewReader("data")
_, err := svc.SetImage(ctx, consts.EntityArtist, "ar-1", "Name", "/nonexistent/path.jpg", reader, ".jpg")
Expect(err).ToNot(HaveOccurred())
})
It("clears artwork state and enqueues a Bump on success", func() {
ctx := context.Background()
Expect(artRepo.PutItemArtwork(&model.ItemArtwork{
ItemKind: "ar", ItemID: "ar-1", Hash: "oldhash", Source: "external",
})).To(Succeed())
_, err := svc.SetImage(ctx, consts.EntityArtist, "ar-1", "Pink Floyd", "", strings.NewReader("img"), ".jpg")
Expect(err).ToNot(HaveOccurred())
_, err = artRepo.GetItemArtwork("ar", "ar-1", model.ImageTypePrimary)
Expect(err).To(MatchError(model.ErrNotFound))
queued, err := queueRepo.DequeueBatch(1000)
Expect(err).ToNot(HaveOccurred())
Expect(queued).To(ContainElement(SatisfyAll(
HaveField("ItemKind", "ar"),
HaveField("ItemID", "ar-1"),
HaveField("Priority", model.ArtworkPriorityBump),
)))
})
})
Describe("RemoveImage", func() {
It("removes the file at the given path", func() {
ctx := context.Background()
dir := filepath.Join(tmpDir, "artwork", "artist")
Expect(os.MkdirAll(dir, 0755)).To(Succeed())
path := filepath.Join(dir, "ar-1_test.jpg")
Expect(os.WriteFile(path, []byte("img"), 0600)).To(Succeed())
err := svc.RemoveImage(ctx, path)
Expect(err).ToNot(HaveOccurred())
Expect(path).ToNot(BeAnExistingFile())
})
It("succeeds when file does not exist", func() {
ctx := context.Background()
err := svc.RemoveImage(ctx, "/nonexistent/file.jpg")
Expect(err).ToNot(HaveOccurred())
})
It("succeeds with empty path", func() {
ctx := context.Background()
err := svc.RemoveImage(ctx, "")
Expect(err).ToNot(HaveOccurred())
})
})
})
var _ = Describe("MaxImageUploadSize", func() {
BeforeEach(func() {
DeferCleanup(configtest.SetupConfig())
})
It("returns the configured size when valid", func() {
conf.Server.MaxImageUploadSize = "20MB"
Expect(core.MaxImageUploadSize()).To(Equal(int64(20_000_000)))
})
It("returns the default size when config is empty", func() {
conf.Server.MaxImageUploadSize = ""
Expect(core.MaxImageUploadSize()).To(Equal(int64(10_000_000)))
})
It("returns the default size when config is invalid", func() {
conf.Server.MaxImageUploadSize = "not-a-size"
Expect(core.MaxImageUploadSize()).To(Equal(int64(10_000_000)))
})
It("parses raw byte values", func() {
conf.Server.MaxImageUploadSize = "52428800"
Expect(core.MaxImageUploadSize()).To(Equal(int64(52_428_800)))
})
})