2026-03-14 10:03:29 +00:00
|
|
|
// SPDX-Licence-Identifier: EUPL-1.2
|
|
|
|
|
|
|
|
|
|
package provider_test
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"testing"
|
|
|
|
|
|
2026-03-21 23:50:37 +00:00
|
|
|
"dappco.re/go/core/api"
|
|
|
|
|
"dappco.re/go/core/api/pkg/provider"
|
2026-03-14 10:03:29 +00:00
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// -- Test helpers (minimal providers) -----------------------------------------
|
|
|
|
|
|
|
|
|
|
type stubProvider struct{}
|
|
|
|
|
|
|
|
|
|
func (s *stubProvider) Name() string { return "stub" }
|
|
|
|
|
func (s *stubProvider) BasePath() string { return "/api/stub" }
|
|
|
|
|
func (s *stubProvider) RegisterRoutes(rg *gin.RouterGroup) {}
|
|
|
|
|
|
|
|
|
|
type streamableProvider struct{ stubProvider }
|
|
|
|
|
|
|
|
|
|
func (s *streamableProvider) Channels() []string { return []string{"stub.event"} }
|
|
|
|
|
|
|
|
|
|
type describableProvider struct{ stubProvider }
|
|
|
|
|
|
|
|
|
|
func (d *describableProvider) Describe() []api.RouteDescription {
|
|
|
|
|
return []api.RouteDescription{
|
|
|
|
|
{Method: "GET", Path: "/items", Summary: "List items", Tags: []string{"stub"}},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
type renderableProvider struct{ stubProvider }
|
|
|
|
|
|
|
|
|
|
func (r *renderableProvider) Element() provider.ElementSpec {
|
|
|
|
|
return provider.ElementSpec{Tag: "core-stub-panel", Source: "/assets/stub.js"}
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-01 14:38:45 +00:00
|
|
|
type specFileProvider struct {
|
|
|
|
|
stubProvider
|
|
|
|
|
specFile string
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (s *specFileProvider) SpecFile() string { return s.specFile }
|
|
|
|
|
|
2026-03-14 10:03:29 +00:00
|
|
|
type fullProvider struct {
|
|
|
|
|
streamableProvider
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (f *fullProvider) Name() string { return "full" }
|
|
|
|
|
func (f *fullProvider) BasePath() string { return "/api/full" }
|
|
|
|
|
func (f *fullProvider) Describe() []api.RouteDescription {
|
|
|
|
|
return []api.RouteDescription{
|
|
|
|
|
{Method: "GET", Path: "/status", Summary: "Status", Tags: []string{"full"}},
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
func (f *fullProvider) Element() provider.ElementSpec {
|
|
|
|
|
return provider.ElementSpec{Tag: "core-full-panel", Source: "/assets/full.js"}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// -- Tests --------------------------------------------------------------------
|
|
|
|
|
|
|
|
|
|
func TestRegistry_Add_Good(t *testing.T) {
|
|
|
|
|
reg := provider.NewRegistry()
|
|
|
|
|
assert.Equal(t, 0, reg.Len())
|
|
|
|
|
|
|
|
|
|
reg.Add(&stubProvider{})
|
|
|
|
|
assert.Equal(t, 1, reg.Len())
|
|
|
|
|
|
|
|
|
|
reg.Add(&streamableProvider{})
|
|
|
|
|
assert.Equal(t, 2, reg.Len())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestRegistry_Get_Good(t *testing.T) {
|
|
|
|
|
reg := provider.NewRegistry()
|
|
|
|
|
reg.Add(&stubProvider{})
|
|
|
|
|
|
|
|
|
|
p := reg.Get("stub")
|
|
|
|
|
require.NotNil(t, p)
|
|
|
|
|
assert.Equal(t, "stub", p.Name())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestRegistry_Get_Bad(t *testing.T) {
|
|
|
|
|
reg := provider.NewRegistry()
|
|
|
|
|
p := reg.Get("nonexistent")
|
|
|
|
|
assert.Nil(t, p)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestRegistry_List_Good(t *testing.T) {
|
|
|
|
|
reg := provider.NewRegistry()
|
|
|
|
|
reg.Add(&stubProvider{})
|
|
|
|
|
reg.Add(&streamableProvider{})
|
|
|
|
|
|
|
|
|
|
list := reg.List()
|
|
|
|
|
assert.Len(t, list, 2)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestRegistry_MountAll_Good(t *testing.T) {
|
|
|
|
|
reg := provider.NewRegistry()
|
|
|
|
|
reg.Add(&stubProvider{})
|
|
|
|
|
reg.Add(&streamableProvider{})
|
|
|
|
|
|
|
|
|
|
engine, err := api.New()
|
|
|
|
|
require.NoError(t, err)
|
|
|
|
|
|
|
|
|
|
reg.MountAll(engine)
|
|
|
|
|
assert.Len(t, engine.Groups(), 2)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestRegistry_Streamable_Good(t *testing.T) {
|
|
|
|
|
reg := provider.NewRegistry()
|
|
|
|
|
reg.Add(&stubProvider{}) // not streamable
|
|
|
|
|
reg.Add(&streamableProvider{}) // streamable
|
|
|
|
|
|
|
|
|
|
s := reg.Streamable()
|
|
|
|
|
assert.Len(t, s, 1)
|
|
|
|
|
assert.Equal(t, []string{"stub.event"}, s[0].Channels())
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-02 00:52:21 +00:00
|
|
|
func TestRegistry_StreamableIter_Good(t *testing.T) {
|
|
|
|
|
reg := provider.NewRegistry()
|
|
|
|
|
reg.Add(&stubProvider{})
|
|
|
|
|
reg.Add(&streamableProvider{})
|
|
|
|
|
|
|
|
|
|
var streamables []provider.Streamable
|
|
|
|
|
for s := range reg.StreamableIter() {
|
|
|
|
|
streamables = append(streamables, s)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert.Len(t, streamables, 1)
|
|
|
|
|
assert.Equal(t, []string{"stub.event"}, streamables[0].Channels())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestRegistry_StreamableIter_Good_SnapshotCurrentProviders(t *testing.T) {
|
|
|
|
|
reg := provider.NewRegistry()
|
|
|
|
|
reg.Add(&streamableProvider{})
|
|
|
|
|
|
|
|
|
|
iter := reg.StreamableIter()
|
|
|
|
|
reg.Add(&streamableProvider{})
|
|
|
|
|
|
|
|
|
|
var streamables []provider.Streamable
|
|
|
|
|
for s := range iter {
|
|
|
|
|
streamables = append(streamables, s)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert.Len(t, streamables, 1)
|
|
|
|
|
assert.Equal(t, []string{"stub.event"}, streamables[0].Channels())
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-14 10:03:29 +00:00
|
|
|
func TestRegistry_Describable_Good(t *testing.T) {
|
|
|
|
|
reg := provider.NewRegistry()
|
2026-04-01 07:08:19 +00:00
|
|
|
reg.Add(&stubProvider{}) // not describable
|
2026-03-14 10:03:29 +00:00
|
|
|
reg.Add(&describableProvider{}) // describable
|
|
|
|
|
|
|
|
|
|
d := reg.Describable()
|
|
|
|
|
assert.Len(t, d, 1)
|
|
|
|
|
assert.Len(t, d[0].Describe(), 1)
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-02 00:52:21 +00:00
|
|
|
func TestRegistry_DescribableIter_Good(t *testing.T) {
|
|
|
|
|
reg := provider.NewRegistry()
|
|
|
|
|
reg.Add(&stubProvider{})
|
|
|
|
|
reg.Add(&describableProvider{})
|
|
|
|
|
|
|
|
|
|
var describables []provider.Describable
|
|
|
|
|
for d := range reg.DescribableIter() {
|
|
|
|
|
describables = append(describables, d)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert.Len(t, describables, 1)
|
|
|
|
|
assert.Len(t, describables[0].Describe(), 1)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestRegistry_DescribableIter_Good_SnapshotCurrentProviders(t *testing.T) {
|
|
|
|
|
reg := provider.NewRegistry()
|
|
|
|
|
reg.Add(&describableProvider{})
|
|
|
|
|
|
|
|
|
|
iter := reg.DescribableIter()
|
|
|
|
|
reg.Add(&describableProvider{})
|
|
|
|
|
|
|
|
|
|
var describables []provider.Describable
|
|
|
|
|
for d := range iter {
|
|
|
|
|
describables = append(describables, d)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert.Len(t, describables, 1)
|
|
|
|
|
assert.Len(t, describables[0].Describe(), 1)
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-14 10:03:29 +00:00
|
|
|
func TestRegistry_Renderable_Good(t *testing.T) {
|
|
|
|
|
reg := provider.NewRegistry()
|
|
|
|
|
reg.Add(&stubProvider{}) // not renderable
|
|
|
|
|
reg.Add(&renderableProvider{}) // renderable
|
|
|
|
|
|
|
|
|
|
r := reg.Renderable()
|
|
|
|
|
assert.Len(t, r, 1)
|
|
|
|
|
assert.Equal(t, "core-stub-panel", r[0].Element().Tag)
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-02 00:52:21 +00:00
|
|
|
func TestRegistry_RenderableIter_Good(t *testing.T) {
|
|
|
|
|
reg := provider.NewRegistry()
|
|
|
|
|
reg.Add(&stubProvider{})
|
|
|
|
|
reg.Add(&renderableProvider{})
|
|
|
|
|
|
|
|
|
|
var renderables []provider.Renderable
|
|
|
|
|
for r := range reg.RenderableIter() {
|
|
|
|
|
renderables = append(renderables, r)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert.Len(t, renderables, 1)
|
|
|
|
|
assert.Equal(t, "core-stub-panel", renderables[0].Element().Tag)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestRegistry_RenderableIter_Good_SnapshotCurrentProviders(t *testing.T) {
|
|
|
|
|
reg := provider.NewRegistry()
|
|
|
|
|
reg.Add(&renderableProvider{})
|
|
|
|
|
|
|
|
|
|
iter := reg.RenderableIter()
|
|
|
|
|
reg.Add(&renderableProvider{})
|
|
|
|
|
|
|
|
|
|
var renderables []provider.Renderable
|
|
|
|
|
for r := range iter {
|
|
|
|
|
renderables = append(renderables, r)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert.Len(t, renderables, 1)
|
|
|
|
|
assert.Equal(t, "core-stub-panel", renderables[0].Element().Tag)
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-14 10:03:29 +00:00
|
|
|
func TestRegistry_Info_Good(t *testing.T) {
|
|
|
|
|
reg := provider.NewRegistry()
|
|
|
|
|
reg.Add(&fullProvider{})
|
|
|
|
|
|
|
|
|
|
infos := reg.Info()
|
|
|
|
|
require.Len(t, infos, 1)
|
|
|
|
|
|
|
|
|
|
info := infos[0]
|
|
|
|
|
assert.Equal(t, "full", info.Name)
|
|
|
|
|
assert.Equal(t, "/api/full", info.BasePath)
|
|
|
|
|
assert.Equal(t, []string{"stub.event"}, info.Channels)
|
|
|
|
|
require.NotNil(t, info.Element)
|
|
|
|
|
assert.Equal(t, "core-full-panel", info.Element.Tag)
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-01 07:08:19 +00:00
|
|
|
func TestRegistry_Info_Good_ProxyMetadata(t *testing.T) {
|
|
|
|
|
reg := provider.NewRegistry()
|
|
|
|
|
reg.Add(provider.NewProxy(provider.ProxyConfig{
|
|
|
|
|
Name: "proxy",
|
|
|
|
|
BasePath: "/api/proxy",
|
|
|
|
|
Upstream: "http://127.0.0.1:9999",
|
|
|
|
|
SpecFile: "/tmp/proxy-openapi.json",
|
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
infos := reg.Info()
|
|
|
|
|
require.Len(t, infos, 1)
|
|
|
|
|
|
|
|
|
|
info := infos[0]
|
|
|
|
|
assert.Equal(t, "proxy", info.Name)
|
|
|
|
|
assert.Equal(t, "/api/proxy", info.BasePath)
|
|
|
|
|
assert.Equal(t, "/tmp/proxy-openapi.json", info.SpecFile)
|
|
|
|
|
assert.Equal(t, "http://127.0.0.1:9999", info.Upstream)
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-01 22:19:56 +00:00
|
|
|
func TestRegistry_InfoIter_Good(t *testing.T) {
|
|
|
|
|
reg := provider.NewRegistry()
|
|
|
|
|
reg.Add(&fullProvider{})
|
|
|
|
|
|
|
|
|
|
var infos []provider.ProviderInfo
|
|
|
|
|
for info := range reg.InfoIter() {
|
|
|
|
|
infos = append(infos, info)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
require.Len(t, infos, 1)
|
|
|
|
|
info := infos[0]
|
|
|
|
|
assert.Equal(t, "full", info.Name)
|
|
|
|
|
assert.Equal(t, "/api/full", info.BasePath)
|
|
|
|
|
assert.Equal(t, []string{"stub.event"}, info.Channels)
|
|
|
|
|
require.NotNil(t, info.Element)
|
|
|
|
|
assert.Equal(t, "core-full-panel", info.Element.Tag)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestRegistry_InfoIter_Good_SnapshotCurrentProviders(t *testing.T) {
|
|
|
|
|
reg := provider.NewRegistry()
|
|
|
|
|
reg.Add(&fullProvider{})
|
|
|
|
|
|
|
|
|
|
iter := reg.InfoIter()
|
|
|
|
|
reg.Add(&specFileProvider{specFile: "/tmp/later.json"})
|
|
|
|
|
|
|
|
|
|
var infos []provider.ProviderInfo
|
|
|
|
|
for info := range iter {
|
|
|
|
|
infos = append(infos, info)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
require.Len(t, infos, 1)
|
|
|
|
|
assert.Equal(t, "full", infos[0].Name)
|
|
|
|
|
}
|
|
|
|
|
|
2026-03-14 10:03:29 +00:00
|
|
|
func TestRegistry_Iter_Good(t *testing.T) {
|
|
|
|
|
reg := provider.NewRegistry()
|
|
|
|
|
reg.Add(&stubProvider{})
|
|
|
|
|
reg.Add(&streamableProvider{})
|
|
|
|
|
|
|
|
|
|
count := 0
|
|
|
|
|
for range reg.Iter() {
|
|
|
|
|
count++
|
|
|
|
|
}
|
|
|
|
|
assert.Equal(t, 2, count)
|
|
|
|
|
}
|
2026-04-01 14:38:45 +00:00
|
|
|
|
|
|
|
|
func TestRegistry_SpecFiles_Good(t *testing.T) {
|
|
|
|
|
reg := provider.NewRegistry()
|
|
|
|
|
reg.Add(&stubProvider{})
|
|
|
|
|
reg.Add(&specFileProvider{specFile: "/tmp/b.json"})
|
|
|
|
|
reg.Add(&specFileProvider{specFile: "/tmp/a.yaml"})
|
|
|
|
|
reg.Add(&specFileProvider{specFile: "/tmp/a.yaml"})
|
|
|
|
|
reg.Add(&specFileProvider{specFile: ""})
|
|
|
|
|
|
|
|
|
|
assert.Equal(t, []string{"/tmp/a.yaml", "/tmp/b.json"}, reg.SpecFiles())
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func TestRegistry_SpecFilesIter_Good(t *testing.T) {
|
|
|
|
|
reg := provider.NewRegistry()
|
|
|
|
|
reg.Add(&specFileProvider{specFile: "/tmp/z.json"})
|
|
|
|
|
reg.Add(&specFileProvider{specFile: "/tmp/x.json"})
|
|
|
|
|
|
|
|
|
|
var files []string
|
|
|
|
|
for file := range reg.SpecFilesIter() {
|
|
|
|
|
files = append(files, file)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert.Equal(t, []string{"/tmp/x.json", "/tmp/z.json"}, files)
|
|
|
|
|
}
|