Some checks failed
Pipeline: Test, Lint, Build / Get version info (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test Go code (push) Has been cancelled
Pipeline: Test, Lint, Build / Test JS code (push) Has been cancelled
Pipeline: Test, Lint, Build / Lint i18n files (push) Has been cancelled
Pipeline: Test, Lint, Build / Check Docker configuration (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (darwin/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v5) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v6) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm/v7) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (linux/arm64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/386) (push) Has been cancelled
Pipeline: Test, Lint, Build / Build (windows/amd64) (push) Has been cancelled
Pipeline: Test, Lint, Build / Push to GHCR (push) Has been cancelled
Pipeline: Test, Lint, Build / Push to Docker Hub (push) Has been cancelled
Pipeline: Test, Lint, Build / Cleanup digest artifacts (push) Has been cancelled
Pipeline: Test, Lint, Build / Build Windows installers (push) Has been cancelled
Pipeline: Test, Lint, Build / Package/Release (push) Has been cancelled
Pipeline: Test, Lint, Build / Upload Linux PKG (push) Has been cancelled
Close stale issues and PRs / stale (push) Has been cancelled
POEditor import / update-translations (push) Has been cancelled
230 lines
6.8 KiB
Go
230 lines
6.8 KiB
Go
package plugins
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"time"
|
|
|
|
"github.com/navidrome/navidrome/conf"
|
|
"github.com/navidrome/navidrome/conf/configtest"
|
|
"github.com/navidrome/navidrome/core/agents"
|
|
"github.com/navidrome/navidrome/core/metrics"
|
|
"github.com/navidrome/navidrome/plugins/api"
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
)
|
|
|
|
var _ = Describe("Adapter Media Agent", func() {
|
|
var ctx context.Context
|
|
var mgr *managerImpl
|
|
|
|
BeforeEach(func() {
|
|
ctx = GinkgoT().Context()
|
|
|
|
// Ensure plugins folder is set to testdata
|
|
DeferCleanup(configtest.SetupConfig())
|
|
conf.Server.Plugins.Folder = testDataDir
|
|
conf.Server.DevPluginCompilationTimeout = 2 * time.Minute
|
|
|
|
mgr = createManager(nil, metrics.NewNoopInstance())
|
|
mgr.ScanPlugins()
|
|
|
|
// Wait for all plugins to compile to avoid race conditions
|
|
err := mgr.EnsureCompiled("multi_plugin")
|
|
Expect(err).NotTo(HaveOccurred(), "multi_plugin should compile successfully")
|
|
err = mgr.EnsureCompiled("fake_album_agent")
|
|
Expect(err).NotTo(HaveOccurred(), "fake_album_agent should compile successfully")
|
|
})
|
|
|
|
Describe("AgentName and PluginName", func() {
|
|
It("should return the plugin name", func() {
|
|
agent := mgr.LoadPlugin("multi_plugin", "MetadataAgent")
|
|
Expect(agent).NotTo(BeNil(), "multi_plugin should be loaded")
|
|
Expect(agent.PluginID()).To(Equal("multi_plugin"))
|
|
})
|
|
It("should return the agent name", func() {
|
|
agent, ok := mgr.LoadMediaAgent("multi_plugin")
|
|
Expect(ok).To(BeTrue(), "multi_plugin should be loaded as media agent")
|
|
Expect(agent.AgentName()).To(Equal("multi_plugin"))
|
|
})
|
|
})
|
|
|
|
Describe("Album methods", func() {
|
|
var agent *wasmMediaAgent
|
|
|
|
BeforeEach(func() {
|
|
a, ok := mgr.LoadMediaAgent("fake_album_agent")
|
|
Expect(ok).To(BeTrue(), "fake_album_agent should be loaded")
|
|
agent = a.(*wasmMediaAgent)
|
|
})
|
|
|
|
Context("GetAlbumInfo", func() {
|
|
It("should return album information", func() {
|
|
info, err := agent.GetAlbumInfo(ctx, "Test Album", "Test Artist", "mbid")
|
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(info).NotTo(BeNil())
|
|
Expect(info.Name).To(Equal("Test Album"))
|
|
Expect(info.MBID).To(Equal("album-mbid-123"))
|
|
Expect(info.Description).To(Equal("This is a test album description"))
|
|
Expect(info.URL).To(Equal("https://example.com/album"))
|
|
})
|
|
|
|
It("should return ErrNotFound when plugin returns not found", func() {
|
|
_, err := agent.GetAlbumInfo(ctx, "Test Album", "", "mbid")
|
|
|
|
Expect(err).To(Equal(agents.ErrNotFound))
|
|
})
|
|
|
|
It("should return ErrNotFound when plugin returns nil response", func() {
|
|
_, err := agent.GetAlbumInfo(ctx, "", "", "")
|
|
|
|
Expect(err).To(Equal(agents.ErrNotFound))
|
|
})
|
|
})
|
|
|
|
Context("GetAlbumImages", func() {
|
|
It("should return album images", func() {
|
|
images, err := agent.GetAlbumImages(ctx, "Test Album", "Test Artist", "mbid")
|
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(images).To(Equal([]agents.ExternalImage{
|
|
{URL: "https://example.com/album1.jpg", Size: 300},
|
|
{URL: "https://example.com/album2.jpg", Size: 400},
|
|
}))
|
|
})
|
|
})
|
|
})
|
|
|
|
Describe("Artist methods", func() {
|
|
var agent *wasmMediaAgent
|
|
|
|
BeforeEach(func() {
|
|
a, ok := mgr.LoadMediaAgent("fake_artist_agent")
|
|
Expect(ok).To(BeTrue(), "fake_artist_agent should be loaded")
|
|
agent = a.(*wasmMediaAgent)
|
|
})
|
|
|
|
Context("GetArtistMBID", func() {
|
|
It("should return artist MBID", func() {
|
|
mbid, err := agent.GetArtistMBID(ctx, "artist-id", "Test Artist")
|
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(mbid).To(Equal("1234567890"))
|
|
})
|
|
|
|
It("should return ErrNotFound when plugin returns not found", func() {
|
|
_, err := agent.GetArtistMBID(ctx, "artist-id", "")
|
|
|
|
Expect(err).To(Equal(agents.ErrNotFound))
|
|
})
|
|
})
|
|
|
|
Context("GetArtistURL", func() {
|
|
It("should return artist URL", func() {
|
|
url, err := agent.GetArtistURL(ctx, "artist-id", "Test Artist", "mbid")
|
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(url).To(Equal("https://example.com"))
|
|
})
|
|
})
|
|
|
|
Context("GetArtistBiography", func() {
|
|
It("should return artist biography", func() {
|
|
bio, err := agent.GetArtistBiography(ctx, "artist-id", "Test Artist", "mbid")
|
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(bio).To(Equal("This is a test biography"))
|
|
})
|
|
})
|
|
|
|
Context("GetSimilarArtists", func() {
|
|
It("should return similar artists", func() {
|
|
artists, err := agent.GetSimilarArtists(ctx, "artist-id", "Test Artist", "mbid", 10)
|
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(artists).To(Equal([]agents.Artist{
|
|
{Name: "Similar Artist 1", MBID: "mbid1"},
|
|
{Name: "Similar Artist 2", MBID: "mbid2"},
|
|
}))
|
|
})
|
|
})
|
|
|
|
Context("GetArtistImages", func() {
|
|
It("should return artist images", func() {
|
|
images, err := agent.GetArtistImages(ctx, "artist-id", "Test Artist", "mbid")
|
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(images).To(Equal([]agents.ExternalImage{
|
|
{URL: "https://example.com/image1.jpg", Size: 100},
|
|
{URL: "https://example.com/image2.jpg", Size: 200},
|
|
}))
|
|
})
|
|
})
|
|
|
|
Context("GetArtistTopSongs", func() {
|
|
It("should return artist top songs", func() {
|
|
songs, err := agent.GetArtistTopSongs(ctx, "artist-id", "Test Artist", "mbid", 10)
|
|
|
|
Expect(err).NotTo(HaveOccurred())
|
|
Expect(songs).To(Equal([]agents.Song{
|
|
{Name: "Song 1", MBID: "mbid1"},
|
|
{Name: "Song 2", MBID: "mbid2"},
|
|
}))
|
|
})
|
|
})
|
|
})
|
|
|
|
Describe("Helper functions", func() {
|
|
It("convertExternalImages should convert API image objects to agent image objects", func() {
|
|
apiImages := []*api.ExternalImage{
|
|
{Url: "https://example.com/image1.jpg", Size: 100},
|
|
{Url: "https://example.com/image2.jpg", Size: 200},
|
|
}
|
|
|
|
agentImages := convertExternalImages(apiImages)
|
|
Expect(agentImages).To(HaveLen(2))
|
|
|
|
for i, img := range agentImages {
|
|
Expect(img.URL).To(Equal(apiImages[i].Url))
|
|
Expect(img.Size).To(Equal(int(apiImages[i].Size)))
|
|
}
|
|
})
|
|
|
|
It("convertExternalImages should handle empty slice", func() {
|
|
agentImages := convertExternalImages([]*api.ExternalImage{})
|
|
Expect(agentImages).To(BeEmpty())
|
|
})
|
|
|
|
It("convertExternalImages should handle nil", func() {
|
|
agentImages := convertExternalImages(nil)
|
|
Expect(agentImages).To(BeEmpty())
|
|
})
|
|
})
|
|
|
|
Describe("Error mapping", func() {
|
|
var agent wasmMediaAgent
|
|
|
|
It("should map API ErrNotFound to agents.ErrNotFound", func() {
|
|
err := agent.mapError(api.ErrNotFound)
|
|
Expect(err).To(Equal(agents.ErrNotFound))
|
|
})
|
|
|
|
It("should map API ErrNotImplemented to agents.ErrNotFound", func() {
|
|
err := agent.mapError(api.ErrNotImplemented)
|
|
Expect(err).To(Equal(agents.ErrNotFound))
|
|
})
|
|
|
|
It("should pass through other errors", func() {
|
|
testErr := errors.New("test error")
|
|
err := agent.mapError(testErr)
|
|
Expect(err).To(Equal(testErr))
|
|
})
|
|
|
|
It("should handle nil error", func() {
|
|
err := agent.mapError(nil)
|
|
Expect(err).To(BeNil())
|
|
})
|
|
})
|
|
})
|