mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
* Re-enable devenv dashboard validation * Open up dashboard schema composition points * Introduce composition space at front of scuemata * Refactor go code to use new composition structure * Bunch of small cleanups in dashboard.cue * Enable both base and dist tests of devenv * Get rid of obsolete CUE loading hacks * Skip weird failures on these tests Really don't seem to be testing for what we intend them to be testing for.
178 lines
5.2 KiB
Go
178 lines
5.2 KiB
Go
package load
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"io/fs"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"testing/fstest"
|
|
|
|
"cuelang.org/go/cue/errors"
|
|
"github.com/grafana/grafana/pkg/schema"
|
|
"github.com/laher/mergefs"
|
|
"github.com/stretchr/testify/require"
|
|
)
|
|
|
|
var p = GetDefaultLoadPaths()
|
|
|
|
// Basic well-formedness tests on core scuemata.
|
|
func TestScuemataBasics(t *testing.T) {
|
|
all := make(map[string]schema.VersionedCueSchema)
|
|
|
|
dash, err := BaseDashboardFamily(p)
|
|
require.NoError(t, err, "error while loading base dashboard scuemata")
|
|
all["basedash"] = dash
|
|
|
|
ddash, err := DistDashboardFamily(p)
|
|
require.NoError(t, err, "error while loading dist dashboard scuemata")
|
|
all["distdash"] = ddash
|
|
|
|
for set, sch := range all {
|
|
t.Run(set, func(t *testing.T) {
|
|
require.NotNil(t, sch, "scuemata for %q linked to empty chain", set)
|
|
|
|
maj, min := sch.Version()
|
|
t.Run(fmt.Sprintf("%v.%v", maj, min), func(t *testing.T) {
|
|
cv := sch.CUE()
|
|
t.Run("Exists", func(t *testing.T) {
|
|
require.True(t, cv.Exists(), "cue value for schema does not exist")
|
|
})
|
|
t.Run("Validate", func(t *testing.T) {
|
|
require.NoError(t, cv.Validate(), "all schema should be valid with respect to basic CUE rules")
|
|
})
|
|
})
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestDevenvDashboardValidity(t *testing.T) {
|
|
validdir := filepath.Join("..", "..", "..", "devenv", "dev-dashboards")
|
|
|
|
doTest := func(sch schema.VersionedCueSchema) func(t *testing.T) {
|
|
return func(t *testing.T) {
|
|
t.Parallel()
|
|
require.NoError(t, filepath.Walk(validdir, func(path string, d fs.FileInfo, err error) error {
|
|
require.NoError(t, err)
|
|
|
|
if d.IsDir() || filepath.Ext(d.Name()) != ".json" {
|
|
return nil
|
|
}
|
|
|
|
// Ignore gosec warning G304 since it's a test
|
|
// nolint:gosec
|
|
b, err := os.Open(path)
|
|
require.NoError(t, err, "failed to open dashboard file")
|
|
|
|
// Only try to validate dashboards with schemaVersion >= 30
|
|
jtree := make(map[string]interface{})
|
|
byt, err := io.ReadAll(b)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
require.NoError(t, json.Unmarshal(byt, &jtree))
|
|
if oldschemav, has := jtree["schemaVersion"]; !has {
|
|
t.Logf("no schemaVersion in %s", path)
|
|
return nil
|
|
} else {
|
|
if !(oldschemav.(float64) > 29) {
|
|
if testing.Verbose() {
|
|
t.Logf("schemaVersion is %v, older than 30, skipping %s", oldschemav, path)
|
|
}
|
|
return nil
|
|
}
|
|
}
|
|
|
|
t.Run(filepath.Base(path), func(t *testing.T) {
|
|
err := sch.Validate(schema.Resource{Value: byt, Name: path})
|
|
if err != nil {
|
|
// Testify trims errors to short length. We want the full text
|
|
errstr := errors.Details(err, nil)
|
|
t.Log(errstr)
|
|
if strings.Contains(errstr, "null") {
|
|
t.Log("validation failure appears to involve nulls - see if scripts/stripnulls.sh has any effect?")
|
|
}
|
|
t.FailNow()
|
|
}
|
|
})
|
|
|
|
return nil
|
|
}))
|
|
}
|
|
}
|
|
|
|
// TODO will need to expand this appropriately when the scuemata contain
|
|
// more than one schema
|
|
|
|
dash, err := BaseDashboardFamily(p)
|
|
require.NoError(t, err, "error while loading base dashboard scuemata")
|
|
t.Run("base", doTest(dash))
|
|
|
|
ddash, err := DistDashboardFamily(p)
|
|
require.NoError(t, err, "error while loading dist dashboard scuemata")
|
|
t.Run("dist", doTest(ddash))
|
|
}
|
|
|
|
func TestPanelValidity(t *testing.T) {
|
|
t.Skip()
|
|
validdir := os.DirFS(filepath.Join("testdata", "artifacts", "panels"))
|
|
|
|
ddash, err := DistDashboardFamily(p)
|
|
require.NoError(t, err, "error while loading dist dashboard scuemata")
|
|
|
|
// TODO hmm, it's awkward for this test's structure to have to pick just one
|
|
// type of panel plugin, but we can change the test structure. However, is
|
|
// there any other situation where we want the panel subschema with all
|
|
// possible disjunctions? If so, maybe the interface needs work. Or maybe
|
|
// just defer that until the proper generic composite scuemata impl.
|
|
dpan, err := ddash.(CompositeDashboardSchema).LatestPanelSchemaFor("table")
|
|
require.NoError(t, err, "error while loading panel subschema")
|
|
|
|
require.NoError(t, fs.WalkDir(validdir, ".", func(path string, d fs.DirEntry, err error) error {
|
|
require.NoError(t, err)
|
|
|
|
if d.IsDir() || filepath.Ext(d.Name()) != ".json" {
|
|
return nil
|
|
}
|
|
|
|
t.Run(path, func(t *testing.T) {
|
|
// TODO FIXME stop skipping once we actually have the schema filled in
|
|
// enough that the tests pass, lol
|
|
|
|
b, err := validdir.Open(path)
|
|
require.NoError(t, err, "failed to open panel file")
|
|
|
|
err = dpan.Validate(schema.Resource{Value: b})
|
|
require.NoError(t, err, "panel failed validation")
|
|
})
|
|
|
|
return nil
|
|
}))
|
|
}
|
|
|
|
func TestCueErrorWrapper(t *testing.T) {
|
|
a := fstest.MapFS{
|
|
filepath.Join(dashboardDir, "dashboard.cue"): &fstest.MapFile{Data: []byte("package dashboard\n{;;;;;;;;}")},
|
|
}
|
|
|
|
filesystem := mergefs.Merge(a, GetDefaultLoadPaths().BaseCueFS)
|
|
|
|
var baseLoadPaths = BaseLoadPaths{
|
|
BaseCueFS: filesystem,
|
|
DistPluginCueFS: GetDefaultLoadPaths().DistPluginCueFS,
|
|
}
|
|
|
|
_, err := BaseDashboardFamily(baseLoadPaths)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "in file")
|
|
require.Contains(t, err.Error(), "line: ")
|
|
|
|
_, err = DistDashboardFamily(baseLoadPaths)
|
|
require.Error(t, err)
|
|
require.Contains(t, err.Error(), "in file")
|
|
require.Contains(t, err.Error(), "line: ")
|
|
}
|