327 lines
8.9 KiB
Go
327 lines
8.9 KiB
Go
// SPDX-License-Identifier: EUPL-1.2
|
|
|
|
package api_test
|
|
|
|
import (
|
|
"bytes"
|
|
filepath "dappco.re/go/core/scm/internal/ax/filepathx"
|
|
json "dappco.re/go/core/scm/internal/ax/jsonx"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"testing"
|
|
|
|
goapi "dappco.re/go/core/api"
|
|
"dappco.re/go/core/io"
|
|
"dappco.re/go/core/scm/marketplace"
|
|
scmapi "dappco.re/go/core/scm/pkg/api"
|
|
"dappco.re/go/core/scm/repos"
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
func init() {
|
|
gin.SetMode(gin.TestMode)
|
|
}
|
|
|
|
// -- Provider Identity --------------------------------------------------------
|
|
|
|
func TestScmProvider_Name_Good(t *testing.T) {
|
|
p := scmapi.NewProvider(nil, nil, nil, nil)
|
|
assert.Equal(t, "scm", p.Name())
|
|
}
|
|
|
|
func TestScmProvider_BasePath_Good(t *testing.T) {
|
|
p := scmapi.NewProvider(nil, nil, nil, nil)
|
|
assert.Equal(t, "/api/v1/scm", p.BasePath())
|
|
}
|
|
|
|
func TestScmProvider_Channels_Good(t *testing.T) {
|
|
p := scmapi.NewProvider(nil, nil, nil, nil)
|
|
channels := p.Channels()
|
|
assert.Contains(t, channels, "scm.marketplace.refreshed")
|
|
assert.Contains(t, channels, "scm.marketplace.installed")
|
|
assert.Contains(t, channels, "scm.marketplace.removed")
|
|
assert.Contains(t, channels, "scm.manifest.verified")
|
|
assert.Contains(t, channels, "scm.registry.changed")
|
|
}
|
|
|
|
func TestScmProvider_Element_Good(t *testing.T) {
|
|
p := scmapi.NewProvider(nil, nil, nil, nil)
|
|
el := p.Element()
|
|
assert.Equal(t, "core-scm-panel", el.Tag)
|
|
assert.Equal(t, "/assets/core-scm.js", el.Source)
|
|
}
|
|
|
|
func TestScmProvider_Describe_Good(t *testing.T) {
|
|
p := scmapi.NewProvider(nil, nil, nil, nil)
|
|
descs := p.Describe()
|
|
assert.GreaterOrEqual(t, len(descs), 11)
|
|
|
|
for _, d := range descs {
|
|
assert.NotEmpty(t, d.Method)
|
|
assert.NotEmpty(t, d.Path)
|
|
assert.NotEmpty(t, d.Summary)
|
|
assert.NotEmpty(t, d.Tags)
|
|
}
|
|
}
|
|
|
|
// -- Marketplace Endpoints ----------------------------------------------------
|
|
|
|
func TestScmProvider_ListMarketplace_Good(t *testing.T) {
|
|
idx := &marketplace.Index{
|
|
Version: 1,
|
|
Modules: []marketplace.Module{
|
|
{Code: "analytics", Name: "Analytics", Category: "product"},
|
|
{Code: "bio", Name: "Bio Links", Category: "product"},
|
|
},
|
|
Categories: []string{"product"},
|
|
}
|
|
p := scmapi.NewProvider(idx, nil, nil, nil)
|
|
|
|
r := setupRouter(p)
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/api/v1/scm/marketplace", nil)
|
|
r.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
|
|
var resp goapi.Response[[]marketplace.Module]
|
|
err := json.Unmarshal(w.Body.Bytes(), &resp)
|
|
require.NoError(t, err)
|
|
assert.True(t, resp.Success)
|
|
assert.Len(t, resp.Data, 2)
|
|
}
|
|
|
|
func TestScmProvider_ListMarketplace_Search_Good(t *testing.T) {
|
|
idx := &marketplace.Index{
|
|
Version: 1,
|
|
Modules: []marketplace.Module{
|
|
{Code: "analytics", Name: "Analytics", Category: "product"},
|
|
{Code: "bio", Name: "Bio Links", Category: "product"},
|
|
},
|
|
}
|
|
p := scmapi.NewProvider(idx, nil, nil, nil)
|
|
|
|
r := setupRouter(p)
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/api/v1/scm/marketplace?q=bio", nil)
|
|
r.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
|
|
var resp goapi.Response[[]marketplace.Module]
|
|
err := json.Unmarshal(w.Body.Bytes(), &resp)
|
|
require.NoError(t, err)
|
|
assert.Len(t, resp.Data, 1)
|
|
assert.Equal(t, "bio", resp.Data[0].Code)
|
|
}
|
|
|
|
func TestScmProvider_ListMarketplace_NilIndex_Good(t *testing.T) {
|
|
p := scmapi.NewProvider(nil, nil, nil, nil)
|
|
|
|
r := setupRouter(p)
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/api/v1/scm/marketplace", nil)
|
|
r.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
|
|
var resp goapi.Response[[]marketplace.Module]
|
|
err := json.Unmarshal(w.Body.Bytes(), &resp)
|
|
require.NoError(t, err)
|
|
assert.True(t, resp.Success)
|
|
assert.Empty(t, resp.Data)
|
|
}
|
|
|
|
func TestScmProvider_GetMarketplaceItem_Good(t *testing.T) {
|
|
idx := &marketplace.Index{
|
|
Version: 1,
|
|
Modules: []marketplace.Module{
|
|
{Code: "analytics", Name: "Analytics", Category: "product"},
|
|
},
|
|
}
|
|
p := scmapi.NewProvider(idx, nil, nil, nil)
|
|
|
|
r := setupRouter(p)
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/api/v1/scm/marketplace/analytics", nil)
|
|
r.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
|
|
var resp goapi.Response[marketplace.Module]
|
|
err := json.Unmarshal(w.Body.Bytes(), &resp)
|
|
require.NoError(t, err)
|
|
assert.Equal(t, "analytics", resp.Data.Code)
|
|
}
|
|
|
|
func TestScmProvider_GetMarketplaceItem_Bad(t *testing.T) {
|
|
idx := &marketplace.Index{Version: 1}
|
|
p := scmapi.NewProvider(idx, nil, nil, nil)
|
|
|
|
r := setupRouter(p)
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/api/v1/scm/marketplace/nonexistent", nil)
|
|
r.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusNotFound, w.Code)
|
|
}
|
|
|
|
func TestScmProvider_GetMarketplaceItem_Bad_PathTraversal_Good(t *testing.T) {
|
|
idx := &marketplace.Index{Version: 1}
|
|
p := scmapi.NewProvider(idx, nil, nil, nil)
|
|
|
|
r := setupRouter(p)
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/api/v1/scm/marketplace/%2e%2e", nil)
|
|
r.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusBadRequest, w.Code)
|
|
}
|
|
|
|
// -- Installed Endpoints ------------------------------------------------------
|
|
|
|
func TestScmProvider_ListInstalled_NilInstaller_Good(t *testing.T) {
|
|
p := scmapi.NewProvider(nil, nil, nil, nil)
|
|
|
|
r := setupRouter(p)
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/api/v1/scm/installed", nil)
|
|
r.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
|
|
var resp goapi.Response[[]marketplace.InstalledModule]
|
|
err := json.Unmarshal(w.Body.Bytes(), &resp)
|
|
require.NoError(t, err)
|
|
assert.True(t, resp.Success)
|
|
assert.Empty(t, resp.Data)
|
|
}
|
|
|
|
// -- Registry Endpoints -------------------------------------------------------
|
|
|
|
func TestScmProvider_ListRegistry_NilRegistry_Good(t *testing.T) {
|
|
p := scmapi.NewProvider(nil, nil, nil, nil)
|
|
|
|
r := setupRouter(p)
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/api/v1/scm/registry", nil)
|
|
r.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
|
|
var resp goapi.Response[[]any]
|
|
err := json.Unmarshal(w.Body.Bytes(), &resp)
|
|
require.NoError(t, err)
|
|
assert.True(t, resp.Success)
|
|
assert.Empty(t, resp.Data)
|
|
}
|
|
|
|
func TestScmProvider_ListRegistry_TopologicalOrder_Good(t *testing.T) {
|
|
medium := io.NewMockMedium()
|
|
require.NoError(t, medium.Write("/tmp/repos.yaml", `
|
|
version: 1
|
|
org: host-uk
|
|
base_path: /tmp/repos
|
|
repos:
|
|
core-php:
|
|
type: foundation
|
|
core-admin:
|
|
type: module
|
|
depends_on: [core-php]
|
|
`))
|
|
|
|
reg, err := repos.LoadRegistry(medium, "/tmp/repos.yaml")
|
|
require.NoError(t, err)
|
|
|
|
p := scmapi.NewProvider(nil, nil, reg, nil)
|
|
r := setupRouter(p)
|
|
w := httptest.NewRecorder()
|
|
req, _ := http.NewRequest("GET", "/api/v1/scm/registry", nil)
|
|
r.ServeHTTP(w, req)
|
|
|
|
require.Equal(t, http.StatusOK, w.Code)
|
|
|
|
var resp goapi.Response[[]map[string]any]
|
|
err = json.Unmarshal(w.Body.Bytes(), &resp)
|
|
require.NoError(t, err)
|
|
require.Len(t, resp.Data, 2)
|
|
assert.Equal(t, "core-php", resp.Data[0]["name"])
|
|
assert.Equal(t, "core-admin", resp.Data[1]["name"])
|
|
}
|
|
|
|
func TestScmProvider_RefreshMarketplace_Good(t *testing.T) {
|
|
dir := t.TempDir()
|
|
indexPath := filepath.Join(dir, "index.json")
|
|
|
|
idx := &marketplace.Index{
|
|
Version: 1,
|
|
Modules: []marketplace.Module{
|
|
{Code: "refreshed", Name: "Refreshed Module"},
|
|
},
|
|
}
|
|
require.NoError(t, marketplace.WriteIndex(indexPath, idx))
|
|
|
|
p := scmapi.NewProvider(nil, nil, nil, nil)
|
|
r := setupRouter(p)
|
|
|
|
w := httptest.NewRecorder()
|
|
body := []byte(`{"index_path":"` + indexPath + `"}`)
|
|
req, _ := http.NewRequest("POST", "/api/v1/scm/marketplace/refresh", bytes.NewReader(body))
|
|
req.Header.Set("Content-Type", "application/json")
|
|
r.ServeHTTP(w, req)
|
|
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
|
|
var resp goapi.Response[map[string]any]
|
|
err := json.Unmarshal(w.Body.Bytes(), &resp)
|
|
require.NoError(t, err)
|
|
assert.True(t, resp.Success)
|
|
assert.Equal(t, float64(1), resp.Data["modules"])
|
|
|
|
w = httptest.NewRecorder()
|
|
req, _ = http.NewRequest("GET", "/api/v1/scm/marketplace", nil)
|
|
r.ServeHTTP(w, req)
|
|
assert.Equal(t, http.StatusOK, w.Code)
|
|
|
|
var listed goapi.Response[[]marketplace.Module]
|
|
err = json.Unmarshal(w.Body.Bytes(), &listed)
|
|
require.NoError(t, err)
|
|
require.Len(t, listed.Data, 1)
|
|
assert.Equal(t, "refreshed", listed.Data[0].Code)
|
|
}
|
|
|
|
// -- Route Registration -------------------------------------------------------
|
|
|
|
func TestScmProvider_RegistersAsRouteGroup_Good(t *testing.T) {
|
|
p := scmapi.NewProvider(nil, nil, nil, nil)
|
|
|
|
engine, err := goapi.New()
|
|
require.NoError(t, err)
|
|
|
|
engine.Register(p)
|
|
assert.Len(t, engine.Groups(), 1)
|
|
assert.Equal(t, "scm", engine.Groups()[0].Name())
|
|
}
|
|
|
|
func TestScmProvider_Channels_RegisterAsStreamGroup_Good(t *testing.T) {
|
|
p := scmapi.NewProvider(nil, nil, nil, nil)
|
|
|
|
engine, err := goapi.New()
|
|
require.NoError(t, err)
|
|
|
|
engine.Register(p)
|
|
|
|
channels := engine.Channels()
|
|
assert.Contains(t, channels, "scm.marketplace.refreshed")
|
|
}
|
|
|
|
// -- Test helpers -------------------------------------------------------------
|
|
|
|
func setupRouter(p *scmapi.ScmProvider) *gin.Engine {
|
|
r := gin.New()
|
|
rg := r.Group(p.BasePath())
|
|
p.RegisterRoutes(rg)
|
|
return r
|
|
}
|