grafana/pkg/services/sqlstore/dashboard_thumbs_test.go
Artur Wierzbicki 6c76aa71e8
Previews: capability check (#44601)
* add SQL migrations

* dashboard previews from sql: poc

* added todos

* refactor: use the same enums where possible

* use useEffect, always return json

* added todo

* refactor + delete files after use

* refactor + fix manual thumbnail upload

* refactor: move all interactions with sqlStore to thumbnail repo

* refactor: remove file operations in thumb crawler/service

* refactor: fix dashboard_thumbs sql store

* refactor: extracted thumbnail fetching/updating to a hook

* refactor: store thumbnails in redux store

* refactor: store thumbnails in redux store

* refactor: private'd repo methods

* removed redux storage, saving images as blobs

* allow for configurable rendering timeouts

* added 1) query for dashboards with stale thumbnails, 2) command for marking thumbnails as stale

* use sql-based queue in crawler

* ui for marking thumbnails as stale

* replaced `stale` boolean prop with `state` enum

* introduce rendering session

* compilation errors

* fix crawler stop button

* rename thumbnail state frozen to locked

* #44449: fix merge conflicts

* #44449: remove thumb methods from `Store` interface

* #44449: clean filepath, defer file closing

* #44449: fix rendering.Theme cyclic import

* #44449: linting

* #44449: linting

* #44449: mutex'd crawlerStatus access

* #44449: added integration tests for `sqlstore.dashboard_thumbs`

* #44449: added comments to explain the `ThumbnailState` enum

* #44449: use os.ReadFile rather then os.Open

* #44449: always enable dashboardPreviews feature during integration tests

* #44449: add /previews/system-requirements API

* #44449: remove sleep time, adjust number of threads

* #44449: review fix: add `orgId` to `DashboardThumbnailMeta`

* #44449: review fix: automatic parsing of thumbnailState

* #44449: update returned json

* #44449: UI changes - dashboard previews sytem req check

* #44449: lint fixes

* #44449: fix tests

* #44449: typo

* #44449: fix getSystemRequirements API: return 200 even if we plugin version is invalid

* #44449: fix getSystemRequirements API: don't return SemverConstraint on error

* #44449: fix getSystemRequirements API

* #44449: fix previews sytem requirements text

* #44449: add `doThumbnailsExist` to repo

* #44449: remove redux api

* #44449: add missing model

* #44449: implement frontedsettings-driven capability check

* #44449: simplify

* #44449: revert test changes

* #44449: add dummy setup settings

* #44449: implicit typing over `FC<Props>`

* #44449: refactor conditionals

* #44449: replace `getText` with a react component

* #44449: fix component interface

* #44449: add onRemove to `PreviewsSystemRequirements` alert

* #44449: add bottom/top margin to previewSystemRequirements modal

* #44449: merge conflict fix

* #44449: remove console.log

Co-authored-by: Ryan McKinley <ryantxu@gmail.com>
Co-authored-by: Alexander Emelin <frvzmb@gmail.com>
2022-02-16 21:49:50 +04:00

260 lines
8.9 KiB
Go

//go:build integration
// +build integration
package sqlstore
import (
"context"
"testing"
"github.com/grafana/grafana/pkg/models"
"github.com/stretchr/testify/require"
)
var theme = models.ThemeDark
var kind = models.ThumbnailKindDefault
func TestSqlStorage(t *testing.T) {
var sqlStore *SQLStore
var savedFolder *models.Dashboard
setup := func() {
sqlStore = InitTestDB(t)
savedFolder = insertTestDashboard(t, sqlStore, "1 test dash folder", 1, 0, true, "prod", "webapp")
}
t.Run("Should insert dashboard in default state", func(t *testing.T) {
setup()
dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp")
upsertTestDashboardThumbnail(t, sqlStore, dash.Uid, dash.OrgId, dash.Version)
thumb := getThumbnail(t, sqlStore, dash.Uid, dash.OrgId)
require.Positive(t, thumb.Id)
require.Equal(t, models.ThumbnailStateDefault, thumb.State)
require.Equal(t, dash.Version, thumb.DashboardVersion)
})
t.Run("Should be able to update the thumbnail", func(t *testing.T) {
setup()
dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp")
upsertTestDashboardThumbnail(t, sqlStore, dash.Uid, dash.OrgId, dash.Version)
thumb := getThumbnail(t, sqlStore, dash.Uid, dash.OrgId)
insertedThumbnailId := thumb.Id
upsertTestDashboardThumbnail(t, sqlStore, dash.Uid, dash.OrgId, dash.Version+1)
updatedThumb := getThumbnail(t, sqlStore, dash.Uid, dash.OrgId)
require.Equal(t, insertedThumbnailId, updatedThumb.Id)
require.Equal(t, dash.Version+1, updatedThumb.DashboardVersion)
})
t.Run("Should return empty array if all dashboards have thumbnails", func(t *testing.T) {
setup()
dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp")
upsertTestDashboardThumbnail(t, sqlStore, dash.Uid, dash.OrgId, dash.Version)
cmd := models.FindDashboardsWithStaleThumbnailsCommand{
Kind: kind,
Theme: theme,
}
res, err := sqlStore.FindDashboardsWithStaleThumbnails(context.Background(), &cmd)
require.NoError(t, err)
require.Len(t, res, 0)
})
t.Run("Should return dashboards with thumbnails marked as stale", func(t *testing.T) {
setup()
dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp")
upsertTestDashboardThumbnail(t, sqlStore, dash.Uid, dash.OrgId, dash.Version)
updateThumbnailState(t, sqlStore, dash.Uid, dash.OrgId, models.ThumbnailStateStale)
cmd := models.FindDashboardsWithStaleThumbnailsCommand{
Kind: kind,
Theme: theme,
}
res, err := sqlStore.FindDashboardsWithStaleThumbnails(context.Background(), &cmd)
require.NoError(t, err)
require.Len(t, res, 1)
require.Equal(t, dash.Id, res[0].Id)
})
t.Run("Should not return dashboards with updated thumbnails that had been marked as stale", func(t *testing.T) {
setup()
dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp")
upsertTestDashboardThumbnail(t, sqlStore, dash.Uid, dash.OrgId, dash.Version)
updateThumbnailState(t, sqlStore, dash.Uid, dash.OrgId, models.ThumbnailStateStale)
upsertTestDashboardThumbnail(t, sqlStore, dash.Uid, dash.OrgId, dash.Version)
cmd := models.FindDashboardsWithStaleThumbnailsCommand{
Kind: kind,
Theme: theme,
}
res, err := sqlStore.FindDashboardsWithStaleThumbnails(context.Background(), &cmd)
require.NoError(t, err)
require.Len(t, res, 0)
})
t.Run("Should find dashboards without thumbnails", func(t *testing.T) {
setup()
dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp")
cmd := models.FindDashboardsWithStaleThumbnailsCommand{
Kind: kind,
Theme: theme,
}
res, err := sqlStore.FindDashboardsWithStaleThumbnails(context.Background(), &cmd)
require.NoError(t, err)
require.Len(t, res, 1)
require.Equal(t, dash.Id, res[0].Id)
})
t.Run("Should find dashboards with outdated thumbnails", func(t *testing.T) {
setup()
dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp")
upsertTestDashboardThumbnail(t, sqlStore, dash.Uid, dash.OrgId, dash.Version)
updateTestDashboard(t, sqlStore, dash, map[string]interface{}{
"tags": "different-tag",
})
cmd := models.FindDashboardsWithStaleThumbnailsCommand{
Kind: kind,
Theme: theme,
}
res, err := sqlStore.FindDashboardsWithStaleThumbnails(context.Background(), &cmd)
require.NoError(t, err)
require.Len(t, res, 1)
require.Equal(t, dash.Id, res[0].Id)
})
t.Run("Should not return dashboards with locked thumbnails even if they are outdated", func(t *testing.T) {
setup()
dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp")
upsertTestDashboardThumbnail(t, sqlStore, dash.Uid, dash.OrgId, dash.Version)
updateThumbnailState(t, sqlStore, dash.Uid, dash.OrgId, models.ThumbnailStateLocked)
updateTestDashboard(t, sqlStore, dash, map[string]interface{}{
"tags": "different-tag",
})
cmd := models.FindDashboardsWithStaleThumbnailsCommand{
Kind: kind,
Theme: theme,
}
res, err := sqlStore.FindDashboardsWithStaleThumbnails(context.Background(), &cmd)
require.NoError(t, err)
require.Len(t, res, 0)
})
t.Run("Should not return dashboards with manually uploaded thumbnails by default", func(t *testing.T) {
setup()
dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp")
upsertTestDashboardThumbnail(t, sqlStore, dash.Uid, dash.OrgId, models.DashboardVersionForManualThumbnailUpload)
updateTestDashboard(t, sqlStore, dash, map[string]interface{}{
"tags": "different-tag",
})
cmd := models.FindDashboardsWithStaleThumbnailsCommand{
Kind: kind,
Theme: theme,
}
res, err := sqlStore.FindDashboardsWithStaleThumbnails(context.Background(), &cmd)
require.NoError(t, err)
require.Len(t, res, 0)
})
t.Run("Should return dashboards with manually uploaded thumbnails if requested", func(t *testing.T) {
setup()
dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp")
upsertTestDashboardThumbnail(t, sqlStore, dash.Uid, dash.OrgId, models.DashboardVersionForManualThumbnailUpload)
updateTestDashboard(t, sqlStore, dash, map[string]interface{}{
"tags": "different-tag",
})
cmd := models.FindDashboardsWithStaleThumbnailsCommand{
Kind: kind,
Theme: theme,
IncludeManuallyUploadedThumbnails: true,
}
res, err := sqlStore.FindDashboardsWithStaleThumbnails(context.Background(), &cmd)
require.NoError(t, err)
require.Len(t, res, 1)
require.Equal(t, dash.Id, res[0].Id)
})
t.Run("Should count all dashboard thumbnails", func(t *testing.T) {
setup()
dash := insertTestDashboard(t, sqlStore, "test dash 23", 1, savedFolder.Id, false, "prod", "webapp")
upsertTestDashboardThumbnail(t, sqlStore, dash.Uid, dash.OrgId, 1)
dash2 := insertTestDashboard(t, sqlStore, "test dash 23", 2, savedFolder.Id, false, "prod", "webapp")
upsertTestDashboardThumbnail(t, sqlStore, dash2.Uid, dash2.OrgId, 1)
updateTestDashboard(t, sqlStore, dash, map[string]interface{}{
"tags": "different-tag",
})
cmd := models.FindDashboardThumbnailCountCommand{}
res, err := sqlStore.FindThumbnailCount(context.Background(), &cmd)
require.NoError(t, err)
require.Equal(t, res, int64(2))
})
}
func getThumbnail(t *testing.T, sqlStore *SQLStore, dashboardUID string, orgId int64) *models.DashboardThumbnail {
t.Helper()
cmd := models.GetDashboardThumbnailCommand{
DashboardThumbnailMeta: models.DashboardThumbnailMeta{
DashboardUID: dashboardUID,
OrgId: orgId,
PanelID: 0,
Kind: kind,
Theme: theme,
},
}
thumb, err := sqlStore.GetThumbnail(context.Background(), &cmd)
require.NoError(t, err)
return thumb
}
func upsertTestDashboardThumbnail(t *testing.T, sqlStore *SQLStore, dashboardUID string, orgId int64, dashboardVersion int) *models.DashboardThumbnail {
t.Helper()
cmd := models.SaveDashboardThumbnailCommand{
DashboardThumbnailMeta: models.DashboardThumbnailMeta{
DashboardUID: dashboardUID,
OrgId: orgId,
PanelID: 0,
Kind: kind,
Theme: theme,
},
DashboardVersion: dashboardVersion,
Image: make([]byte, 0),
MimeType: "image/png",
}
dash, err := sqlStore.SaveThumbnail(context.Background(), &cmd)
require.NoError(t, err)
require.NotNil(t, dash)
return dash
}
func updateThumbnailState(t *testing.T, sqlStore *SQLStore, dashboardUID string, orgId int64, state models.ThumbnailState) {
t.Helper()
cmd := models.UpdateThumbnailStateCommand{
DashboardThumbnailMeta: models.DashboardThumbnailMeta{
DashboardUID: dashboardUID,
OrgId: orgId,
PanelID: 0,
Kind: kind,
Theme: theme,
},
State: state,
}
err := sqlStore.UpdateThumbnailState(context.Background(), &cmd)
require.NoError(t, err)
}