Files
grafana/pkg/storage/unified/federated/stats_test.go
Steve Simpson d50e2a94a3 Alerting: Implement setting of version message in convert API. (#114331)
Part 2 of adding version messages to the `alert_rule_version` able. This allows
setting the message via a header when using the Prometheus conversion API,
which can be useful for e.g. linking changes back to source control.
2025-11-25 11:20:28 +01:00

283 lines
8.0 KiB
Go

package federated
import (
"context"
"encoding/json"
"testing"
"time"
"github.com/stretchr/testify/require"
"k8s.io/apiserver/pkg/endpoints/request"
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/expr"
"github.com/grafana/grafana/pkg/infra/db"
"github.com/grafana/grafana/pkg/services/dashboards"
"github.com/grafana/grafana/pkg/services/dashboards/database"
"github.com/grafana/grafana/pkg/services/featuremgmt"
"github.com/grafana/grafana/pkg/services/folder"
"github.com/grafana/grafana/pkg/services/folder/folderimpl"
ngmodels "github.com/grafana/grafana/pkg/services/ngalert/models"
ngalertstore "github.com/grafana/grafana/pkg/services/ngalert/store"
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
"github.com/grafana/grafana/pkg/services/user"
"github.com/grafana/grafana/pkg/storage/legacysql"
"github.com/grafana/grafana/pkg/storage/unified/resourcepb"
"github.com/grafana/grafana/pkg/tests/testsuite"
"github.com/grafana/grafana/pkg/util/testutil"
)
func TestMain(m *testing.M) {
testsuite.Run(m)
}
func TestIntegrationDirectSQLStats(t *testing.T) {
testutil.SkipIntegrationTestInShortMode(t)
db, cfg := db.InitTestDBWithCfg(t)
ctx := context.Background()
dashStore, err := database.ProvideDashboardStore(db, cfg, featuremgmt.WithFeatures(), tagimpl.ProvideService(db))
require.NoError(t, err)
fStore := folderimpl.ProvideStore(db)
tempUser := &user.SignedInUser{UserID: 1, OrgID: 1, Permissions: map[int64]map[string][]string{}}
folder1UID := "test1"
now := time.Now()
dashFolder1 := dashboards.NewDashboardFolder("test1")
dashFolder1.SetUID(folder1UID)
dashFolder1.OrgID = 1
dashFolder1.CreatedBy = tempUser.UserID
dashFolder1.UpdatedBy = tempUser.UserID
_, err = dashStore.SaveDashboard(ctx, dashboards.SaveDashboardCommand{
Dashboard: dashFolder1.Data,
OrgID: 1,
UserID: tempUser.UserID,
IsFolder: true,
})
require.NoError(t, err)
_, err = fStore.Create(ctx, folder.CreateFolderCommand{Title: "test1", UID: folder1UID, OrgID: 1, SignedInUser: tempUser})
require.NoError(t, err)
folder2UID := "test2"
dashFolder2 := dashboards.NewDashboardFolder("test2")
dashFolder2.SetUID(folder2UID)
dashFolder2.OrgID = 1
dashFolder2.FolderUID = folder1UID
dashFolder2.CreatedBy = tempUser.UserID
dashFolder2.UpdatedBy = tempUser.UserID
_, err = dashStore.SaveDashboard(ctx, dashboards.SaveDashboardCommand{
Dashboard: dashFolder2.Data,
OrgID: 1,
UserID: tempUser.UserID,
IsFolder: true,
FolderUID: folder1UID,
})
require.NoError(t, err)
_, err = fStore.Create(ctx, folder.CreateFolderCommand{Title: "test2", UID: folder2UID, OrgID: 1, ParentUID: folder1UID, SignedInUser: tempUser})
require.NoError(t, err)
ruleStore := ngalertstore.SetupStoreForTesting(t, db)
dashboardUID := "test"
_, err = ruleStore.InsertAlertRules(context.Background(), ngmodels.NewUserUID(tempUser), []ngmodels.InsertRule{{
AlertRule: ngmodels.AlertRule{
DashboardUID: &dashboardUID,
UID: "test",
Title: "test",
OrgID: 1,
Data: []ngmodels.AlertQuery{
{
RefID: "A",
Model: json.RawMessage("{}"),
DatasourceUID: expr.DatasourceUID,
RelativeTimeRange: ngmodels.RelativeTimeRange{
From: ngmodels.Duration(60),
To: ngmodels.Duration(0),
},
},
},
Condition: "ok",
Updated: now,
NamespaceUID: folder2UID,
ExecErrState: ngmodels.ExecutionErrorState(ngmodels.Alerting),
NoDataState: ngmodels.Alerting,
IntervalSeconds: 60,
}}})
require.NoError(t, err)
_, err = dashStore.SaveDashboard(ctx, dashboards.SaveDashboardCommand{
Dashboard: simplejson.New(),
FolderUID: folder1UID,
OrgID: 1,
})
require.NoError(t, err)
store := &LegacyStatsGetter{
SQL: legacysql.NewDatabaseProvider(db),
}
t.Run("GetStatsForFolder1", func(t *testing.T) {
ctx := context.Background()
ctx = request.WithNamespace(ctx, "default")
stats, err := store.GetStats(ctx, &resourcepb.ResourceStatsRequest{
Namespace: "default",
Folder: folder1UID,
})
require.NoError(t, err)
jj, _ := json.MarshalIndent(stats.Stats, "", " ")
require.JSONEq(t, `[
{
"group": "sql-fallback",
"resource": "alertrules"
},
{
"group": "sql-fallback",
"resource": "dashboards",
"count": 1
},
{
"group": "sql-fallback",
"resource": "folders",
"count": 1
},
{
"group": "sql-fallback",
"resource": "library_elements"
}
]`, string(jj))
})
// New tests to verify per-resource fallback disabling
t.Run("GetStatsForFolder1_DisableDashboardsFallback", func(t *testing.T) {
ctx := context.Background()
ctx = request.WithNamespace(ctx, "default")
store := &LegacyStatsGetter{
SQL: legacysql.NewDatabaseProvider(db),
DisableSQLFallbackDashboards: true,
DisableSQLFallbackFolders: false,
}
stats, err := store.GetStats(ctx, &resourcepb.ResourceStatsRequest{
Namespace: "default",
Folder: folder1UID,
})
require.NoError(t, err)
var hasDashboards, hasFolders bool
for _, s := range stats.Stats {
if s.Resource == "dashboards" {
hasDashboards = true
}
if s.Resource == "folders" {
hasFolders = true
require.EqualValues(t, 1, s.Count)
}
}
require.False(t, hasDashboards, "dashboards stats should be disabled")
require.True(t, hasFolders, "folders stats should be present")
})
t.Run("GetStatsForFolder1_DisableFoldersFallback", func(t *testing.T) {
ctx := context.Background()
ctx = request.WithNamespace(ctx, "default")
store := &LegacyStatsGetter{
SQL: legacysql.NewDatabaseProvider(db),
DisableSQLFallbackDashboards: false,
DisableSQLFallbackFolders: true,
}
stats, err := store.GetStats(ctx, &resourcepb.ResourceStatsRequest{
Namespace: "default",
Folder: folder1UID,
})
require.NoError(t, err)
var hasDashboards, hasFolders bool
for _, s := range stats.Stats {
if s.Resource == "dashboards" {
hasDashboards = true
require.EqualValues(t, 1, s.Count)
}
if s.Resource == "folders" {
hasFolders = true
}
}
require.True(t, hasDashboards, "dashboards stats should be present")
require.False(t, hasFolders, "folders stats should be disabled")
})
t.Run("GetStatsForFolder1_DisableBothFallbacks", func(t *testing.T) {
ctx := context.Background()
ctx = request.WithNamespace(ctx, "default")
store := &LegacyStatsGetter{
SQL: legacysql.NewDatabaseProvider(db),
DisableSQLFallbackDashboards: true,
DisableSQLFallbackFolders: true,
}
stats, err := store.GetStats(ctx, &resourcepb.ResourceStatsRequest{
Namespace: "default",
Folder: folder1UID,
})
require.NoError(t, err)
var hasDashboards, hasFolders bool
var hasAlertRules, hasLibrary bool
for _, s := range stats.Stats {
if s.Resource == "dashboards" {
hasDashboards = true
}
if s.Resource == "folders" {
hasFolders = true
}
if s.Resource == "alertrules" {
hasAlertRules = true
}
if s.Resource == "library_elements" {
hasLibrary = true
}
}
require.False(t, hasDashboards, "dashboards stats should be disabled")
require.False(t, hasFolders, "folders stats should be disabled")
require.True(t, hasAlertRules, "alertrules should still be present")
require.True(t, hasLibrary, "library_elements should still be present")
})
t.Run("GetStatsForFolder2", func(t *testing.T) {
ctx := context.Background()
ctx = request.WithNamespace(ctx, "default")
stats, err := store.GetStats(ctx, &resourcepb.ResourceStatsRequest{
Namespace: "default",
Folder: folder2UID,
})
require.NoError(t, err)
jj, _ := json.MarshalIndent(stats.Stats, "", " ")
require.JSONEq(t, `[
{
"group": "sql-fallback",
"resource": "alertrules",
"count": 1
},
{
"group": "sql-fallback",
"resource": "dashboards"
},
{
"group": "sql-fallback",
"resource": "folders"
},
{
"group": "sql-fallback",
"resource": "library_elements"
}
]`, string(jj))
})
}