navidrome/plugins/manager_call_test.go
Deluan Quintão 30df004d4d
test(plugins): speed up integration tests (~45% improvement) (#5137)
* test(plugins): speed up integration tests with shared wazero cache

Reduce plugin test suite runtime from ~22s to ~12s by:

- Creating a shared wazero compilation cache directory in TestPlugins()
  and setting conf.Server.CacheFolder globally so all test Manager
  instances reuse compiled WASM binaries from disk cache
- Moving 6 createTestManager* calls from inside It blocks to BeforeAll
  blocks in scrobbler_adapter_test.go and manager_call_test.go
- Replacing time.Sleep(2s) in KVStore TTL test with Eventually polling
- Reducing WebSocket callback sleeps from 100ms to 10ms

Signed-off-by: Deluan <deluan@navidrome.org>

* test(plugins): enhance websocket tests by storing server messages for verification

Signed-off-by: Deluan <deluan@navidrome.org>

---------

Signed-off-by: Deluan <deluan@navidrome.org>
2026-03-02 16:18:30 -05:00

147 lines
3.8 KiB
Go

//go:build !windows
package plugins
import (
"context"
"sync"
"github.com/navidrome/navidrome/core/agents"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)
// mockMetricsRecorder tracks calls to RecordPluginRequest for testing
type mockMetricsRecorder struct {
mu sync.Mutex
calls []metricsCall
}
type metricsCall struct {
plugin string
method string
ok bool
elapsed int64
}
func (m *mockMetricsRecorder) RecordPluginRequest(_ context.Context, plugin, method string, ok bool, elapsed int64) {
m.mu.Lock()
defer m.mu.Unlock()
m.calls = append(m.calls, metricsCall{plugin: plugin, method: method, ok: ok, elapsed: elapsed})
}
func (m *mockMetricsRecorder) getCalls() []metricsCall {
m.mu.Lock()
defer m.mu.Unlock()
return append([]metricsCall{}, m.calls...)
}
func (m *mockMetricsRecorder) reset() {
m.mu.Lock()
defer m.mu.Unlock()
m.calls = nil
}
var _ = Describe("callPluginFunction metrics", Ordered, func() {
var (
metricsManager *Manager
metricsRecorder *mockMetricsRecorder
agent agents.Interface
)
BeforeAll(func() {
metricsRecorder = &mockMetricsRecorder{}
// Create a manager with the metrics recorder
metricsManager, _ = createTestManagerWithPluginsAndMetrics(
nil,
metricsRecorder,
"test-metadata-agent"+PackageExtension,
)
var ok bool
agent, ok = metricsManager.LoadMediaAgent("test-metadata-agent")
Expect(ok).To(BeTrue())
})
BeforeEach(func() {
metricsRecorder.reset()
})
It("records metrics for successful plugin calls", func() {
retriever := agent.(agents.ArtistBiographyRetriever)
_, err := retriever.GetArtistBiography(GinkgoT().Context(), "artist-1", "Test Artist", "mbid")
Expect(err).ToNot(HaveOccurred())
calls := metricsRecorder.getCalls()
Expect(calls).To(HaveLen(1))
Expect(calls[0].plugin).To(Equal("test-metadata-agent"))
Expect(calls[0].method).To(Equal(FuncGetArtistBiography))
Expect(calls[0].ok).To(BeTrue())
Expect(calls[0].elapsed).To(BeNumerically(">=", 0))
})
Context("with error config", Ordered, func() {
var (
errorRecorder *mockMetricsRecorder
errorAgent agents.Interface
)
BeforeAll(func() {
errorRecorder = &mockMetricsRecorder{}
errorManager, _ := createTestManagerWithPluginsAndMetrics(
map[string]map[string]string{
"test-metadata-agent": {"error": "simulated error"},
},
errorRecorder,
"test-metadata-agent"+PackageExtension,
)
var ok bool
errorAgent, ok = errorManager.LoadMediaAgent("test-metadata-agent")
Expect(ok).To(BeTrue())
})
It("records metrics for failed plugin calls (error returned)", func() {
retriever := errorAgent.(agents.ArtistBiographyRetriever)
_, err := retriever.GetArtistBiography(GinkgoT().Context(), "artist-1", "Test Artist", "mbid")
Expect(err).To(HaveOccurred())
calls := errorRecorder.getCalls()
Expect(calls).To(HaveLen(1))
Expect(calls[0].plugin).To(Equal("test-metadata-agent"))
Expect(calls[0].method).To(Equal(FuncGetArtistBiography))
Expect(calls[0].ok).To(BeFalse())
})
})
Context("with partial metadata agent", Ordered, func() {
var (
partialRecorder *mockMetricsRecorder
partialAgent agents.Interface
)
BeforeAll(func() {
partialRecorder = &mockMetricsRecorder{}
partialManager, _ := createTestManagerWithPluginsAndMetrics(
nil,
partialRecorder,
"partial-metadata-agent"+PackageExtension,
)
var ok bool
partialAgent, ok = partialManager.LoadMediaAgent("partial-metadata-agent")
Expect(ok).To(BeTrue())
})
It("does not record metrics for not-implemented functions", func() {
retriever := partialAgent.(agents.ArtistMBIDRetriever)
_, err := retriever.GetArtistMBID(GinkgoT().Context(), "artist-1", "Test Artist")
Expect(err).To(MatchError(errNotImplemented))
calls := partialRecorder.getCalls()
Expect(calls).To(HaveLen(0))
})
})
})