package dashboard_test import ( "encoding/json" "io" "io/fs" "os" "path/filepath" "strings" "testing" "cuelang.org/go/cue/errors" "github.com/stretchr/testify/require" "github.com/grafana/grafana/pkg/coremodel/dashboard" "github.com/grafana/grafana/pkg/cuectx" ) func TestDevenvDashboardValidity(t *testing.T) { path, err := filepath.Abs("../../../devenv/dev-dashboards") require.NoError(t, err) m, err := themaTestableDashboards(os.DirFS(path)) require.NoError(t, err) cm, err := dashboard.New(cuectx.GrafanaThemaRuntime()) require.NoError(t, err) for path, b := range m { t.Run(path, func(t *testing.T) { // The path arg here only matters for error output cv, err := cuectx.JSONtoCUE(path, b) require.NoError(t, err, "error while decoding dashboard JSON into a CUE value") _, err = cm.CurrentSchema().Validate(cv) 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() } }) } } func themaTestableDashboards(in fs.FS) (map[string][]byte, error) { m := make(map[string][]byte) err := fs.WalkDir(in, ".", func(path string, d fs.DirEntry, err error) error { if err != nil { return err } if d.IsDir() || filepath.Ext(d.Name()) != ".json" { return nil } // nolint:gosec f, err := in.Open(path) if err != nil { return err } defer f.Close() //nolint:errcheck b, err := io.ReadAll(f) if err != nil { return err } jtree := make(map[string]interface{}) err = json.Unmarshal(b, &jtree) if err != nil { return err } if oldschemav, has := jtree["schemaVersion"]; !has || !(oldschemav.(float64) > dashboard.HandoffSchemaVersion-1) { return nil } m[path] = b return nil }) if err != nil { return nil, err } return m, nil }