From a68f8107df71a21398e65173fe7b14939462b63e Mon Sep 17 00:00:00 2001 From: "Arati R." <33031346+suntala@users.noreply.github.com> Date: Thu, 3 Jul 2025 07:13:56 +0200 Subject: [PATCH] Unified Storage/Large Object Support: Add test for dashboardv2 support (#107470) * Add more unit tests to cover dashboardv2 and cross version unmarshalling Signed-off-by: Bruno Abrantes * Change import name of meta v1 * Rename TestLargeDashboardSupport since there are tests for multiple versions * Simplify TestLargeDashboardSupportV2 * Use v1 in TestLargeDashboardSupportCrossVersion, simplify original dash * Marshal spec in TestLargeDashboardSupportCrossVersion * Remove TestLargeDashboardSupportCrossVersion --------- Signed-off-by: Bruno Abrantes Co-authored-by: Bruno Abrantes --- pkg/registry/apis/dashboard/large_test.go | 118 +++++++++++++++++++++- 1 file changed, 114 insertions(+), 4 deletions(-) diff --git a/pkg/registry/apis/dashboard/large_test.go b/pkg/registry/apis/dashboard/large_test.go index 9b86adf4011..cdeeb0310f8 100644 --- a/pkg/registry/apis/dashboard/large_test.go +++ b/pkg/registry/apis/dashboard/large_test.go @@ -6,14 +6,15 @@ import ( "testing" "github.com/stretchr/testify/require" - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" "k8s.io/apimachinery/pkg/runtime" dashv1 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v1beta1" + dashv2 "github.com/grafana/grafana/apps/dashboard/pkg/apis/dashboard/v2alpha1" ) -func TestLargeDashboardSupport(t *testing.T) { +func TestLargeDashboardSupportV1(t *testing.T) { devdash := "../../../../devenv/dev-dashboards/all-panels.json" // nolint:gosec @@ -22,7 +23,7 @@ func TestLargeDashboardSupport(t *testing.T) { require.NoError(t, err) dash := &dashv1.Dashboard{ - ObjectMeta: v1.ObjectMeta{ + ObjectMeta: metav1.ObjectMeta{ Name: "test", Namespace: "test", }, @@ -57,7 +58,7 @@ func TestLargeDashboardSupport(t *testing.T) { // Now make it big again rehydratedDash := &dashv1.Dashboard{ - ObjectMeta: v1.ObjectMeta{ + ObjectMeta: metav1.ObjectMeta{ Name: "test", Namespace: "test", }, @@ -71,3 +72,112 @@ func TestLargeDashboardSupport(t *testing.T) { require.True(t, found) require.Len(t, panels, expectedPanelCount) } + +func TestLargeDashboardSupportV2(t *testing.T) { + // Test RebuildSpec functionality specifically for v2 dashboards + // This tests the json.Unmarshal(blob, &dash.Spec) path for structured specs + // unlike v0/v1 which use the UnmarshalJSON path for unstructured specs + + // Create a v2 dashboard with structured spec + originalV2Dash := &dashv2.Dashboard{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-v2", + Namespace: "test", + }, + Spec: dashv2.DashboardSpec{ + Title: "Test V2 Dashboard", + Description: stringPtr("A test dashboard for v2 large object support"), + Tags: []string{"test", "v2", "large-object"}, + Editable: boolPtr(true), + LiveNow: boolPtr(false), + Preload: false, + Annotations: []dashv2.DashboardAnnotationQueryKind{ + { + Kind: "AnnotationQuery", + Spec: dashv2.DashboardAnnotationQuerySpec{ + Name: "Test Annotation", + }, + }, + }, + Elements: map[string]dashv2.DashboardElement{ + "panel-1": { + PanelKind: &dashv2.DashboardPanelKind{}, + }, + }, + Layout: dashv2.DashboardGridLayoutKindOrRowsLayoutKindOrAutoGridLayoutKindOrTabsLayoutKind{}, + TimeSettings: dashv2.DashboardTimeSettingsSpec{}, + CursorSync: dashv2.DashboardDashboardCursorSyncOff, + Variables: []dashv2.DashboardVariableKind{}, + Links: []dashv2.DashboardDashboardLink{}, + }, + } + + scheme := runtime.NewScheme() + err := dashv2.AddToScheme(scheme) + require.NoError(t, err) + + largeObject := NewDashboardLargeObjectSupport(scheme, 0) + + // Marshal the original spec to use as our "blob" data + originalSpecBlob, err := json.Marshal(originalV2Dash.Spec) + require.NoError(t, err) + + // Create a copy to test reduction + dashToReduce := originalV2Dash.DeepCopy() + + // Convert the dashboard to a small value (ReduceSpec) + err = largeObject.ReduceSpec(dashToReduce) + require.NoError(t, err) + + // Verify only essential fields remain after reduction + require.Equal(t, "Test V2 Dashboard", dashToReduce.Spec.Title) + require.Equal(t, stringPtr("A test dashboard for v2 large object support"), dashToReduce.Spec.Description) + require.Equal(t, []string{"test", "v2", "large-object"}, dashToReduce.Spec.Tags) + + // Everything else should be empty/default + require.Empty(t, dashToReduce.Spec.Annotations) + require.Empty(t, dashToReduce.Spec.Elements) + require.Nil(t, dashToReduce.Spec.Layout.GridLayoutKind) + require.Empty(t, dashToReduce.Spec.Variables) + require.Empty(t, dashToReduce.Spec.Links) + + // Now test RebuildSpec - this is the key test for v2! + rehydratedDash := &dashv2.Dashboard{ + ObjectMeta: metav1.ObjectMeta{ + Name: "test-v2-rehydrated", + Namespace: "test", + }, + } + + // This tests the json.Unmarshal(blob, &dash.Spec) path for v2 dashboards + err = largeObject.RebuildSpec(rehydratedDash, originalSpecBlob) + require.NoError(t, err) + + // Verify the full dashboard spec is restored correctly + require.Equal(t, originalV2Dash.Spec.Title, rehydratedDash.Spec.Title) + require.Equal(t, originalV2Dash.Spec.Description, rehydratedDash.Spec.Description) + require.Equal(t, originalV2Dash.Spec.Tags, rehydratedDash.Spec.Tags) + require.Equal(t, originalV2Dash.Spec.Editable, rehydratedDash.Spec.Editable) + require.Equal(t, originalV2Dash.Spec.LiveNow, rehydratedDash.Spec.LiveNow) + require.Equal(t, originalV2Dash.Spec.Preload, rehydratedDash.Spec.Preload) + + // Verify annotations are restored + require.Len(t, rehydratedDash.Spec.Annotations, 1) + annotation := rehydratedDash.Spec.Annotations[0] + require.Equal(t, "AnnotationQuery", annotation.Kind) + require.Equal(t, "Test Annotation", annotation.Spec.Name) + + // Verify elements are restored + require.Len(t, rehydratedDash.Spec.Elements, 1) + _, exists := rehydratedDash.Spec.Elements["panel-1"] + require.True(t, exists) +} + +// Helper functions for pointer types +func stringPtr(s string) *string { + return &s +} + +func boolPtr(b bool) *bool { + return &b +}