* wip: trying to understand how to get the ds info from migrator * add datasource info provider * Use DS service to fetch DS data * add more tests cases to match with migrator cases * Add snapshots * Non-existing DS * Add different DS for snapshots * fix import * Fix tests: guard against double initialization * don't use full datasource package in test * min version should be 35 * fix test * fix conversion test * Dashboards: Support schemaVersion v35 migration in backend * Dashboards: Support schemaVersion v34 migration in backend * Dashboards: Support schemaVersion v33 migration in backend * Apply suggestions from code review Co-authored-by: Stephanie Hingtgen <stephanie.hingtgen@grafana.com> * Apply feedback * Remove unused parameters * Refactor to follow Go patterns * Update logic * Only write final migration result as output * Compare backend and frontend results * Improve snapshots to cover all possible use cases * Linter * wip make it consistent v33 * apply feedback * Return default when the ref cannot be found * Update apps/dashboard/pkg/migration/schemaversion/v33.go Co-authored-by: Stephanie Hingtgen <stephanie.hingtgen@grafana.com> * apply feedback * Use same mocks backend/frontend * restore migrations * update snapshots * Adapt migration tests to use min versions * Ensure v40-v41 works * Ensure v39-v40 works * Simplify the naming of the files * adjust jest to new input convention * Ensure every migration v36-v41 works * Improve v38 naming * Ensure v36 migrates correctly * Skip v36 refs migrations on rows * Treat rows as frontend and ensure same results for v36 * Ensure v34 runs with the same logic than the frontend * Leave empty stadistics as valid option * ensure v33 is working as the frontend * Update tests * Undo frontend changes for legend handling * Remove filtering by version in the frontend * linter * Clean up v33 input JSON --------- Co-authored-by: Todd Treece <360020+toddtreece@users.noreply.github.com> Co-authored-by: Haris Rozajac <haris.rozajac12@gmail.com> Co-authored-by: Stephanie Hingtgen <stephanie.hingtgen@grafana.com>
117 lines
3.7 KiB
Go
117 lines
3.7 KiB
Go
package migration_test
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/grafana/grafana/apps/dashboard/pkg/migration"
|
|
"github.com/grafana/grafana/apps/dashboard/pkg/migration/schemaversion"
|
|
"github.com/grafana/grafana/apps/dashboard/pkg/migration/testutil"
|
|
)
|
|
|
|
const INPUT_DIR = "testdata/input"
|
|
const OUTPUT_DIR = "testdata/output"
|
|
|
|
func TestMigrate(t *testing.T) {
|
|
files, err := os.ReadDir(INPUT_DIR)
|
|
require.NoError(t, err)
|
|
|
|
// Use the same datasource provider as the frontend test to ensure consistency
|
|
migration.Initialize(testutil.GetTestProvider())
|
|
|
|
t.Run("minimum version check", func(t *testing.T) {
|
|
err := migration.Migrate(map[string]interface{}{
|
|
"schemaVersion": schemaversion.MIN_VERSION - 1,
|
|
}, schemaversion.MIN_VERSION)
|
|
|
|
var minVersionErr = schemaversion.NewMinimumVersionError(schemaversion.MIN_VERSION - 1)
|
|
require.ErrorAs(t, err, &minVersionErr)
|
|
})
|
|
|
|
for _, f := range files {
|
|
if f.IsDir() {
|
|
continue
|
|
}
|
|
|
|
// Validate filename format
|
|
if !strings.HasPrefix(f.Name(), "v") || !strings.HasSuffix(f.Name(), ".json") {
|
|
t.Fatalf("input filename must use v{N}.{name}.json format, got: %s", f.Name())
|
|
}
|
|
|
|
inputDash := loadDashboard(t, filepath.Join(INPUT_DIR, f.Name()))
|
|
inputVersion := getSchemaVersion(t, inputDash)
|
|
|
|
t.Run("input check "+f.Name(), func(t *testing.T) {
|
|
// use input version as the target version to ensure there are no changes
|
|
require.NoError(t, migration.Migrate(inputDash, inputVersion), "input check migration failed")
|
|
outBytes, err := json.MarshalIndent(inputDash, "", " ")
|
|
require.NoError(t, err, "failed to marshal migrated dashboard")
|
|
// We can ignore gosec G304 here since it's a test
|
|
// nolint:gosec
|
|
expectedDash, err := os.ReadFile(filepath.Join(INPUT_DIR, f.Name()))
|
|
require.NoError(t, err, "failed to read expected output file")
|
|
require.JSONEq(t, string(expectedDash), string(outBytes), "%s input check did not match", f.Name())
|
|
})
|
|
|
|
testName := fmt.Sprintf("%s v%d to v%d", f.Name(), inputVersion, schemaversion.LATEST_VERSION)
|
|
t.Run(testName, func(t *testing.T) {
|
|
testMigration(t, inputDash, f.Name(), inputVersion, schemaversion.LATEST_VERSION)
|
|
})
|
|
}
|
|
}
|
|
|
|
func testMigration(t *testing.T, dash map[string]interface{}, inputFileName string, inputVersion, targetVersion int) {
|
|
t.Helper()
|
|
require.NoError(t, migration.Migrate(dash, targetVersion), "%d migration failed", targetVersion)
|
|
|
|
outPath := filepath.Join(OUTPUT_DIR, inputFileName)
|
|
outBytes, err := json.MarshalIndent(dash, "", " ")
|
|
require.NoError(t, err, "failed to marshal migrated dashboard")
|
|
|
|
if _, err := os.Stat(outPath); os.IsNotExist(err) {
|
|
err = os.WriteFile(outPath, outBytes, 0644)
|
|
require.NoError(t, err, "failed to write new output file", outPath)
|
|
return
|
|
}
|
|
|
|
// We can ignore gosec G304 here since it's a test
|
|
// nolint:gosec
|
|
existingBytes, err := os.ReadFile(outPath)
|
|
require.NoError(t, err, "failed to read existing output file")
|
|
require.JSONEq(t, string(existingBytes), string(outBytes), "%s did not match", outPath)
|
|
}
|
|
|
|
func getSchemaVersion(t *testing.T, dash map[string]interface{}) int {
|
|
t.Helper()
|
|
version, ok := dash["schemaVersion"]
|
|
require.True(t, ok, "dashboard missing schemaVersion")
|
|
|
|
switch v := version.(type) {
|
|
case int:
|
|
return v
|
|
case float64:
|
|
return int(v)
|
|
default:
|
|
t.Fatalf("invalid schemaVersion type: %T", version)
|
|
return 0
|
|
}
|
|
}
|
|
|
|
func loadDashboard(t *testing.T, path string) map[string]interface{} {
|
|
t.Helper()
|
|
// We can ignore gosec G304 here since it's a test
|
|
// nolint:gosec
|
|
inputBytes, err := os.ReadFile(path)
|
|
require.NoError(t, err, "failed to read input file")
|
|
|
|
var dash map[string]interface{}
|
|
require.NoError(t, json.Unmarshal(inputBytes, &dash), "failed to unmarshal dashboard JSON")
|
|
return dash
|
|
}
|