Files
grafana/pkg/storage/unified/migrations/folders_dashboards_test.go
Rafael Bortolon Paulovic 4c869a21a4 feat(unified): data migration integration tests (#114418)
* feat: unified storage migrations integration tests

* chore: add comment and adjust db path name

* chore: refactor test cases into interface
2025-11-27 13:35:49 +01:00

209 lines
5.7 KiB
Go

package migrations_test
import (
"fmt"
"net/http"
"testing"
authlib "github.com/grafana/authlib/types"
"github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/tests/apis"
"github.com/stretchr/testify/require"
"k8s.io/apimachinery/pkg/runtime/schema"
)
// foldersAndDashboardsTestCase tests the "folders-dashboards" ResourceMigration
type foldersAndDashboardsTestCase struct {
parentFolderUID string
childFolderUID string
dashboardUID string
libPanelUID string
}
// newFoldersAndDashboardsTestCase creates a test case for the compound folders+dashboards migrator
func newFoldersAndDashboardsTestCase() resourceMigratorTestCase {
return &foldersAndDashboardsTestCase{
parentFolderUID: "parent-folder-uid",
childFolderUID: "child-folder-uid",
dashboardUID: "", // Will be generated during setup
libPanelUID: "", // Will be generated during setup
}
}
func (tc *foldersAndDashboardsTestCase) name() string {
return "folders-dashboards"
}
func (tc *foldersAndDashboardsTestCase) resources() []schema.GroupVersionResource {
return []schema.GroupVersionResource{
{
Group: "folder.grafana.app",
Version: "v1beta1",
Resource: "folders",
},
{
Group: "dashboard.grafana.app",
Version: "v1beta1",
Resource: "dashboards",
},
}
}
func (tc *foldersAndDashboardsTestCase) setup(t *testing.T, helper *apis.K8sTestHelper) {
t.Helper()
// Create parent folder
parent := createTestFolder(t, helper, tc.parentFolderUID, "parent-folder", "")
// Create child folder (nested under parent)
child := createTestFolder(t, helper, tc.childFolderUID, "child-folder", parent.UID)
// Create library panel in child folder
tc.libPanelUID = createTestLibraryPanel(t, helper, "Test Library Panel", child.UID)
// Create dashboard with library panel in child folder
tc.dashboardUID = createTestDashboardWithLibraryPanel(t, helper, "dashboard-with-library-panel",
tc.libPanelUID, "Test LP in dashboard", child.UID)
}
func (tc *foldersAndDashboardsTestCase) verify(t *testing.T, helper *apis.K8sTestHelper, shouldExist bool) {
t.Helper()
// Build maps of UIDs by resource type
folderUIDs := []string{tc.parentFolderUID, tc.childFolderUID}
dashboardUIDs := []string{tc.dashboardUID}
expectedFolderCount := 0
if shouldExist {
expectedFolderCount = len(folderUIDs)
}
orgID := helper.Org1.OrgID
namespace := authlib.OrgNamespaceFormatter(orgID)
// Verify folders
folderCli := helper.GetResourceClient(apis.ResourceClientArgs{
User: helper.Org1.Admin,
Namespace: namespace,
GVR: schema.GroupVersionResource{
Group: "folder.grafana.app",
Version: "v1beta1",
Resource: "folders",
},
})
verifyResourceCount(t, folderCli, expectedFolderCount)
for _, uid := range folderUIDs {
verifyResource(t, folderCli, uid, shouldExist)
}
// Verify dashboards
expectedDashboardCount := 0
if shouldExist {
expectedDashboardCount = len(dashboardUIDs)
}
dashboardCli := helper.GetResourceClient(apis.ResourceClientArgs{
User: helper.Org1.Admin,
Namespace: namespace,
GVR: schema.GroupVersionResource{
Group: "dashboard.grafana.app",
Version: "v1beta1",
Resource: "dashboards",
},
})
verifyResourceCount(t, dashboardCli, expectedDashboardCount)
for _, uid := range dashboardUIDs {
verifyResource(t, dashboardCli, uid, shouldExist)
}
}
// createTestFolder creates a folder with specified UID and optional parent
func createTestFolder(t *testing.T, helper *apis.K8sTestHelper, uid, title, parentUID string) *folder.Folder {
t.Helper()
payload := fmt.Sprintf(`{
"title": "%s",
"uid": "%s"`, title, uid)
if parentUID != "" {
payload += fmt.Sprintf(`,
"parentUid": "%s"`, parentUID)
}
payload += "}"
folderCreate := apis.DoRequest(helper, apis.RequestParams{
User: helper.Org1.Admin,
Method: http.MethodPost,
Path: "/api/folders",
Body: []byte(payload),
}, &folder.Folder{})
require.NotNil(t, folderCreate.Result)
require.Equal(t, uid, folderCreate.Result.UID)
return folderCreate.Result
}
// createTestLibraryPanel creates a library panel in a folder
func createTestLibraryPanel(t *testing.T, helper *apis.K8sTestHelper, name, folderUID string) string {
t.Helper()
libPanelPayload := fmt.Sprintf(`{
"kind": 1,
"name": "%s",
"folderUid": "%s",
"model": {
"type": "text",
"title": "%s"
}
}`, name, folderUID, name)
libCreate := apis.DoRequest(helper, apis.RequestParams{
User: helper.Org1.Admin,
Method: http.MethodPost,
Path: "/api/library-elements",
Body: []byte(libPanelPayload),
}, &map[string]interface{}{})
require.NotNil(t, libCreate.Response)
require.Equal(t, http.StatusOK, libCreate.Response.StatusCode)
libPanelUID := (*libCreate.Result)["result"].(map[string]interface{})["uid"].(string)
require.NotEmpty(t, libPanelUID)
return libPanelUID
}
// createTestDashboardWithLibraryPanel creates a dashboard that uses a library panel
func createTestDashboardWithLibraryPanel(t *testing.T, helper *apis.K8sTestHelper, dashTitle, libPanelUID, libPanelName, folderUID string) string {
t.Helper()
dashPayload := fmt.Sprintf(`{
"dashboard": {
"title": "%s",
"panels": [{
"id": 1,
"libraryPanel": {
"uid": "%s",
"name": "%s"
}
}]
},
"folderUid": "%s",
"overwrite": false
}`, dashTitle, libPanelUID, libPanelName, folderUID)
dashCreate := apis.DoRequest(helper, apis.RequestParams{
User: helper.Org1.Admin,
Method: http.MethodPost,
Path: "/api/dashboards/db",
Body: []byte(dashPayload),
}, &map[string]interface{}{})
require.NotNil(t, dashCreate.Response)
require.Equal(t, http.StatusOK, dashCreate.Response.StatusCode)
dashUID := (*dashCreate.Result)["uid"].(string)
require.NotEmpty(t, dashUID)
return dashUID
}