2022-10-21 09:37:38 -03:00
package service
import (
"context"
"errors"
2023-06-14 17:35:01 -03:00
"strconv"
2022-10-21 09:37:38 -03:00
"testing"
2023-06-14 17:35:01 -03:00
"time"
2022-10-21 09:37:38 -03:00
"github.com/grafana/grafana-plugin-sdk-go/backend"
2024-06-05 22:31:06 +02:00
"github.com/grafana/grafana-plugin-sdk-go/backend/gtime"
2022-10-21 09:37:38 -03:00
"github.com/grafana/grafana-plugin-sdk-go/data"
2023-11-13 07:55:15 -08:00
2022-10-21 09:37:38 -03:00
"github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/infra/db"
Reconcile coremodels, entities, objects under new kind framework (#56492)
* Update thema to latest
* Deal with s/Library/*Runtime/
* Commit new, working results of codegen
* We like pointers now
* Always take runtime arg for NewBase()
* Sketchy handwavy pass at entity meta framework
* Little nibbles
* Update pkg/framework/coremodel/entityframework.cue
Co-authored-by: Artur Wierzbicki <wierzbicki.artur.94@gmail.com>
* Move file into new framework location
* Introduce loaders, Go code
* Complete rename to kind
* Flesh out framework, add svg/dashboard examples
* Cruft removal
* Remove generated kind go files from gitignore
* Refine maturity concept, add SlotKind
* Update embed and go deps
* Export PrefixWithGrafanaCUE
* Make the loader actually work, holy crap
* Many small tweaks to type.cue
* Add Apache 2 licensing exceptions for kinds
* Add new kinds dir, start of generator
* Roll back to earlier oapi-codegen
* Introduce new grafana-specific CUE loaders
* Introduce new tidy code generators framework
* Catch up kind framework with tinkering
* Add slices for the generators
* Add write/verify step to main generator
* Many renames
* Split up kind framework cue files
* Use kind.Decl within generated kinds
* Create kind.SomeDecl wrapper type to cache lineages
* Better names again
* Get one generated implemented, hopefully
* Copy dashboard schema into new kind.cue
* Small fixes to make the initial gen work
* Put svg kind in its new home
* Add generated Go dashboard type
* More renames and cleanups
* Add base kind registry and generator
* Stop blacklisting *_gen.go files
This is not the Go best practice, anyway. All we actually want to ignore
for enterprise is generated wire files.
* Change codegen output directories
pkg/kind -> pkg/kinds
pkg/registry/kindreg -> pkg/registry/corekind
* Rename pkg/framework/kind to pkg/kindsys
* Add core structured kind generator
* Add plural and machine names to kind spec
* Copy playlist over to kind system
* Consolidate kindsys files
* Add raw kind generator
* Update CODEOWNERS for kind framework
* Touch up comments a bit
* More docs tweaks
* Remove generated types to reduce noise for review
* Split each generator into its own file
* Rename Slot kind to Composable kind
* Add handwavy types for customkind loading
* Guard against init calls to framework loader
* First pass at doc on extending the kind system
* Improve attribute example in docs
* Fix wire imports
* Add basic TS types generator
* Fix composable kind category def
* No need for a separate file with generate directive
* Catch dashboard schema up
* Rename generator types to something saner and generic
* Make version configurable in ts/go generators
* Add CommonMeta to ease property access
* Add kindsys prop indicating whether lineage is group
* Put all kind categories back in a single file
* Finish with kindsys group props
* Refactor maturity progression per discussion
- Replace "committed" with "merged"
- All kindcats can use all maturity levels, at least for now
* Convert ts veneer index generator to modular system
* Move over to new jennywrites framework
* Strip down old coremodel generator
* Use public version of jennywrites
* Pull latest thema
* Commit generated Go types
* Add header injection postprocessor
* Move sdboyer/jennywrites to grafana/codejen
* Tweak header output
* Remove dashboard and playlist coremodels
* Fix up backend dashboards devenv test
* Fix TS import patterns to new gen filename
* Update internal imports, remove coremodel registry
* Fix compilation errors, wire generation
* Export and replace the prefix dropper
* More Go struct and field name changes
* Last name fixes, hopefully
* Fix lint errors
* Last lint error
Co-authored-by: Artur Wierzbicki <wierzbicki.artur.94@gmail.com>
2022-11-10 15:36:40 -05:00
dashboard2 "github.com/grafana/grafana/pkg/kinds/dashboard"
2022-10-21 09:37:38 -03:00
"github.com/grafana/grafana/pkg/services/annotations"
2023-01-16 16:33:55 +01:00
"github.com/grafana/grafana/pkg/services/dashboards"
2022-10-21 09:37:38 -03:00
dashboardsDB "github.com/grafana/grafana/pkg/services/dashboards/database"
"github.com/grafana/grafana/pkg/services/featuremgmt"
. "github.com/grafana/grafana/pkg/services/publicdashboards"
"github.com/grafana/grafana/pkg/services/publicdashboards/internal"
. "github.com/grafana/grafana/pkg/services/publicdashboards/models"
2023-03-16 15:39:17 -03:00
"github.com/grafana/grafana/pkg/services/query"
2022-11-14 21:08:10 +02:00
"github.com/grafana/grafana/pkg/services/quota/quotatest"
2022-10-21 09:37:38 -03:00
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
2023-04-18 13:39:30 -07:00
"github.com/grafana/grafana/pkg/util"
2022-10-21 09:37:38 -03:00
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
)
const (
dashboardWithNoQueries = `
{
"panels" : [
{
"id" : 2 ,
"title" : "Panel Title" ,
"type" : "timeseries"
}
] ,
"schemaVersion" : 35
} `
dashboardWithTargetsWithNoDatasources = `
{
"panels" : [
{
"id" : 2 ,
"datasource" : {
"type" : "postgres" ,
"uid" : "abc123"
} ,
"targets" : [
{
"expr" : "go_goroutines{job=\"$job\"}" ,
"interval" : "" ,
"legendFormat" : "" ,
"refId" : "A"
} ,
{
"exemplar" : true ,
"expr" : "query2" ,
"interval" : "" ,
"legendFormat" : "" ,
"refId" : "B"
}
] ,
"title" : "Panel Title" ,
"type" : "timeseries"
}
] ,
"schemaVersion" : 35
} `
dashboardWithQueriesExemplarEnabled = `
{
"panels" : [
{
"id" : 2 ,
"targets" : [
{
"datasource" : {
"type" : "prometheus" ,
"uid" : "_yxMP8Ynk"
} ,
"exemplar" : true ,
"expr" : "go_goroutines{job=\"$job\"}" ,
"interval" : "" ,
"legendFormat" : "" ,
"refId" : "A"
} ,
{
"datasource" : {
"type" : "prometheus" ,
"uid" : "promds2"
} ,
"exemplar" : true ,
"expr" : "query2" ,
"interval" : "" ,
"legendFormat" : "" ,
"refId" : "B"
}
] ,
"title" : "Panel Title" ,
"type" : "timeseries"
}
] ,
"schemaVersion" : 35
} `
dashboardWithMixedDatasource = `
{
"panels" : [
{
"datasource" : {
"type" : "datasource" ,
"uid" : "-- Mixed --"
} ,
"id" : 1 ,
"targets" : [
{
"datasource" : {
"type" : "prometheus" ,
"uid" : "abc123"
} ,
"exemplar" : true ,
"expr" : "go_goroutines{job=\"$job\"}" ,
"interval" : "" ,
"legendFormat" : "" ,
"refId" : "A"
2023-06-15 10:28:34 -03:00
} ,
{
"datasource" : "6SOeCRrVk" ,
"exemplar" : true ,
"expr" : "test{id=\"f0dd9b69-ad04-4342-8e79-ced8c245683b\", name=\"test\"}" ,
"hide" : false ,
"interval" : "" ,
"legendFormat" : "" ,
"refId" : "B"
2022-10-21 09:37:38 -03:00
}
] ,
"title" : "Panel Title" ,
"type" : "timeseries"
} ,
{
"datasource" : {
"type" : "prometheus" ,
"uid" : "_yxMP8Ynk"
} ,
"id" : 2 ,
"targets" : [
{
"datasource" : {
"type" : "prometheus" ,
"uid" : "_yxMP8Ynk"
} ,
"exemplar" : true ,
"expr" : "go_goroutines{job=\"$job\"}" ,
"interval" : "" ,
"legendFormat" : "" ,
"refId" : "A"
}
] ,
"title" : "Panel Title" ,
"type" : "timeseries"
} ,
{
"datasource" : {
"type" : "prometheus" ,
"uid" : "_yxMP8Ynk"
} ,
"id" : 3 ,
"targets" : [
{
"datasource" : {
"type" : "prometheus" ,
"uid" : "_yxMP8Ynk"
} ,
"exemplar" : true ,
"expr" : "go_goroutines{job=\"$job\"}" ,
"interval" : "" ,
"legendFormat" : "" ,
"refId" : "A"
}
] ,
"title" : "Panel Title" ,
"type" : "timeseries"
}
] ,
"schemaVersion" : 35
} `
dashboardWithDuplicateDatasources = `
{
"panels" : [
{
"datasource" : {
"type" : "prometheus" ,
"uid" : "abc123"
} ,
"id" : 1 ,
"targets" : [
{
"datasource" : {
"type" : "prometheus" ,
"uid" : "abc123"
} ,
"exemplar" : true ,
"expr" : "go_goroutines{job=\"$job\"}" ,
"interval" : "" ,
"legendFormat" : "" ,
"refId" : "A"
}
] ,
"title" : "Panel Title" ,
"type" : "timeseries"
} ,
{
"datasource" : {
"type" : "prometheus" ,
"uid" : "_yxMP8Ynk"
} ,
"id" : 2 ,
"targets" : [
{
"datasource" : {
"type" : "prometheus" ,
"uid" : "_yxMP8Ynk"
} ,
"exemplar" : true ,
"expr" : "go_goroutines{job=\"$job\"}" ,
"interval" : "" ,
"legendFormat" : "" ,
"refId" : "A"
}
] ,
"title" : "Panel Title" ,
"type" : "timeseries"
} ,
{
"datasource" : {
"type" : "prometheus" ,
"uid" : "_yxMP8Ynk"
} ,
"id" : 3 ,
"targets" : [
{
"datasource" : {
"type" : "prometheus" ,
"uid" : "_yxMP8Ynk"
} ,
"exemplar" : true ,
"expr" : "go_goroutines{job=\"$job\"}" ,
"interval" : "" ,
"legendFormat" : "" ,
"refId" : "A"
}
] ,
"title" : "Panel Title" ,
"type" : "timeseries"
}
] ,
"schemaVersion" : 35
} `
oldStyleDashboard = `
{
"panels" : [
{
"datasource" : "_yxMP8Ynk" ,
"id" : 2 ,
"targets" : [
{
"exemplar" : true ,
"expr" : "go_goroutines{job=\"$job\"}" ,
"interval" : "" ,
"legendFormat" : "" ,
"refId" : "A"
}
] ,
"title" : "Panel Title" ,
"type" : "timeseries"
}
] ,
"schemaVersion" : 21
} `
dashboardWithOneHiddenQuery = `
{
"panels" : [
{
"id" : 2 ,
"targets" : [
{
"datasource" : {
"type" : "prometheus" ,
"uid" : "_yxMP8Ynk"
} ,
"exemplar" : true ,
"expr" : "go_goroutines{job=\"$job\"}" ,
"interval" : "" ,
"legendFormat" : "" ,
"refId" : "A" ,
"hide" : true
} ,
{
"datasource" : {
"type" : "prometheus" ,
"uid" : "promds2"
} ,
"exemplar" : true ,
"expr" : "query2" ,
"interval" : "" ,
"legendFormat" : "" ,
"refId" : "B"
2023-07-31 10:54:54 -03:00
} ,
{
"datasource" : {
"name" : "Expression" ,
"type" : "__expr__" ,
"uid" : "__expr__"
} ,
"expression" : "$A + $B" ,
"refId" : "C" ,
"type" : "math"
2022-10-21 09:37:38 -03:00
}
] ,
"title" : "Panel Title" ,
"type" : "timeseries"
}
] ,
"schemaVersion" : 35
} `
dashboardWithAllHiddenQueries = `
{
"panels" : [
{
"id" : 2 ,
"targets" : [
{
"datasource" : {
"type" : "prometheus" ,
"uid" : "_yxMP8Ynk"
} ,
"exemplar" : true ,
"expr" : "go_goroutines{job=\"$job\"}" ,
"interval" : "" ,
"legendFormat" : "" ,
"refId" : "A" ,
"hide" : true
} ,
{
"datasource" : {
"type" : "prometheus" ,
"uid" : "promds2"
} ,
"exemplar" : true ,
"expr" : "query2" ,
"interval" : "" ,
"legendFormat" : "" ,
"refId" : "B" ,
"hide" : true
2023-07-31 10:54:54 -03:00
} ,
{
"datasource" : {
"name" : "Expression" ,
"type" : "__expr__" ,
"uid" : "__expr__"
} ,
"expression" : "$A + $B" ,
"refId" : "C" ,
"type" : "math"
2022-10-21 09:37:38 -03:00
}
] ,
"title" : "Panel Title" ,
"type" : "timeseries"
}
] ,
"schemaVersion" : 35
} `
2023-03-15 12:44:17 -03:00
2023-07-31 10:54:54 -03:00
dashboardWithRowsAndOneHiddenQuery = `
2023-03-15 12:44:17 -03:00
{
"panels" : [
{
"id" : 2 ,
"targets" : [
{
"datasource" : {
"type" : "prometheus" ,
"uid" : "_yxMP8Ynk"
} ,
"exemplar" : true ,
"expr" : "go_goroutines{job=\"$job\"}" ,
"interval" : "" ,
"legendFormat" : "" ,
"refId" : "A"
} ,
{
"datasource" : {
"type" : "prometheus" ,
"uid" : "promds2"
} ,
"exemplar" : true ,
"expr" : "query2" ,
"interval" : "" ,
"legendFormat" : "" ,
2023-07-31 10:54:54 -03:00
"hide" : true ,
2023-03-15 12:44:17 -03:00
"refId" : "B"
}
] ,
"title" : "Panel Title" ,
"type" : "timeseries"
} ,
{
"id" : 3 ,
"collapsed" : true ,
"gridPos" : {
"h" : 1 ,
"w" : 24 ,
"x" : 0 ,
"y" : 9
} ,
"title" : "This panel is a Row" ,
"type" : "row" ,
"panels" : [
{
"id" : 4 ,
"targets" : [
{
"datasource" : {
"type" : "prometheus" ,
"uid" : "_yxMP8Ynk"
} ,
"exemplar" : true ,
"expr" : "go_goroutines{job=\"$job\"}" ,
"interval" : "" ,
"legendFormat" : "" ,
"refId" : "A"
} ,
{
"datasource" : {
"type" : "prometheus" ,
"uid" : "promds2"
} ,
"exemplar" : true ,
"expr" : "query2" ,
"interval" : "" ,
"legendFormat" : "" ,
"refId" : "B"
}
] ,
"title" : "Panel inside a row" ,
"type" : "timeseries"
}
]
}
] ,
"schemaVersion" : 35
} `
2023-04-05 10:35:00 -03:00
dashboardWithCollapsedRows = `
{
"panels" : [
{
"gridPos" : {
"h" : 1 ,
"w" : 24 ,
"x" : 0 ,
"y" : 0
} ,
"id" : 12 ,
"title" : "Row title" ,
"type" : "row"
} ,
{
"datasource" : {
"type" : "prometheus" ,
"uid" : "qCbTUC37k"
} ,
"fieldConfig" : {
"defaults" : {
"color" : {
"mode" : "palette-classic"
} ,
"custom" : {
"axisCenteredZero" : false ,
"axisColorMode" : "text" ,
"axisLabel" : "" ,
"axisPlacement" : "auto" ,
"barAlignment" : 0 ,
"drawStyle" : "line" ,
"fillOpacity" : 0 ,
"gradientMode" : "none" ,
"hideFrom" : {
"legend" : false ,
"tooltip" : false ,
"viz" : false
} ,
"lineInterpolation" : "linear" ,
"lineWidth" : 1 ,
"pointSize" : 5 ,
"scaleDistribution" : {
"type" : "linear"
} ,
"showPoints" : "auto" ,
"spanNulls" : false ,
"stacking" : {
"group" : "A" ,
"mode" : "none"
} ,
"thresholdsStyle" : {
"mode" : "off"
}
} ,
"mappings" : [ ] ,
"thresholds" : {
"mode" : "absolute" ,
"steps" : [
{
"color" : "green" ,
"value" : null
} ,
{
"color" : "red" ,
"value" : 80
}
]
}
} ,
"overrides" : [ ]
} ,
"gridPos" : {
"h" : 8 ,
"w" : 12 ,
"x" : 0 ,
"y" : 1
} ,
"id" : 11 ,
"options" : {
"legend" : {
"calcs" : [ ] ,
"displayMode" : "list" ,
"placement" : "bottom" ,
"showLegend" : true
} ,
"tooltip" : {
"mode" : "single" ,
"sort" : "none"
}
} ,
"targets" : [
{
"datasource" : {
"type" : "prometheus" ,
"uid" : "qCbTUC37k"
} ,
"editorMode" : "builder" ,
"expr" : "access_evaluation_duration_bucket" ,
"legendFormat" : "__auto" ,
"range" : true ,
"refId" : "A"
}
] ,
"title" : "Panel Title" ,
"type" : "timeseries"
} ,
{
"collapsed" : true ,
"gridPos" : {
"h" : 1 ,
"w" : 24 ,
"x" : 0 ,
"y" : 9
} ,
"id" : 10 ,
"panels" : [
{
"datasource" : {
"type" : "influxdb" ,
"uid" : "P49A45DF074423DFB"
} ,
"fieldConfig" : {
"defaults" : {
"color" : {
"mode" : "palette-classic"
} ,
"custom" : {
"axisCenteredZero" : false ,
"axisColorMode" : "text" ,
"axisLabel" : "" ,
"axisPlacement" : "auto" ,
"barAlignment" : 0 ,
"drawStyle" : "line" ,
"fillOpacity" : 0 ,
"gradientMode" : "none" ,
"hideFrom" : {
"legend" : false ,
"tooltip" : false ,
"viz" : false
} ,
"lineInterpolation" : "linear" ,
"lineWidth" : 1 ,
"pointSize" : 5 ,
"scaleDistribution" : {
"type" : "linear"
} ,
"showPoints" : "auto" ,
"spanNulls" : false ,
"stacking" : {
"group" : "A" ,
"mode" : "none"
} ,
"thresholdsStyle" : {
"mode" : "off"
}
} ,
"mappings" : [ ] ,
"thresholds" : {
"mode" : "absolute" ,
"steps" : [
{
"color" : "green"
} ,
{
"color" : "red" ,
"value" : 80
}
]
}
} ,
"overrides" : [ ]
} ,
"gridPos" : {
"h" : 9 ,
"w" : 12 ,
"x" : 0 ,
"y" : 10
} ,
"id" : 8 ,
"options" : {
"legend" : {
"calcs" : [ ] ,
"displayMode" : "list" ,
"placement" : "bottom" ,
"showLegend" : true
} ,
"tooltip" : {
"mode" : "single" ,
"sort" : "none"
}
} ,
"pluginVersion" : "9.4.0-pre" ,
"targets" : [
{
"datasource" : {
"type" : "influxdb" ,
"uid" : "P49A45DF074423DFB"
} ,
"query" : "// v.bucket, v.timeRangeStart, and v.timeRange stop are all variables supported by the flux plugin and influxdb\nfrom(bucket: v.bucket)\n |> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"_value\"] >= 10 and r[\"_value\"] <= 20)" ,
"refId" : "A"
}
] ,
"title" : "Panel Title" ,
"type" : "timeseries"
}
] ,
"title" : "Row title 1" ,
"type" : "row"
}
]
} `
2022-10-21 09:37:38 -03:00
)
func TestGetQueryDataResponse ( t * testing . T ) {
2024-02-22 09:34:14 +01:00
fakeDashboardService := & dashboards . FakeDashboardService { }
2024-04-04 15:04:47 +02:00
service , sqlStore , _ := newPublicDashboardServiceImpl ( t , nil , fakeDashboardService , nil )
2023-03-16 15:39:17 -03:00
fakeQueryService := & query . FakeQueryService { }
fakeQueryService . On ( "QueryData" , mock . Anything , mock . Anything , mock . Anything , mock . Anything ) . Return ( & backend . QueryDataResponse { } , nil )
2024-02-22 09:34:14 +01:00
service . QueryDataService = fakeQueryService
2023-03-16 15:39:17 -03:00
2024-04-04 15:04:47 +02:00
dashboardStore , err := dashboardsDB . ProvideDashboardStore ( sqlStore , service . cfg , featuremgmt . WithFeatures ( ) , tagimpl . ProvideService ( sqlStore ) , quotatest . New ( false , nil ) )
2024-02-22 09:34:14 +01:00
require . NoError ( t , err )
2022-10-21 09:37:38 -03:00
publicDashboardQueryDTO := PublicDashboardQueryDTO {
IntervalMs : int64 ( 1 ) ,
MaxDataPoints : int64 ( 1 ) ,
}
2023-03-16 15:39:17 -03:00
t . Run ( "Returns query data even when the query is hidden" , func ( t * testing . T ) {
2022-10-21 09:37:38 -03:00
hiddenQuery := map [ string ] interface { } {
"datasource" : map [ string ] interface { } {
2023-07-31 10:54:54 -03:00
"name" : "Expression" ,
"type" : "__expr__" ,
"uid" : "__expr__" ,
2022-10-21 09:37:38 -03:00
} ,
"hide" : true ,
"refId" : "A" ,
}
customPanels := [ ] interface { } {
map [ string ] interface { } {
"id" : 1 ,
"datasource" : map [ string ] interface { } {
"uid" : "ds1" ,
} ,
"targets" : [ ] interface { } { hiddenQuery } ,
} }
2023-10-24 10:04:45 +03:00
dashboard := insertTestDashboard ( t , dashboardStore , "testDashWithHiddenQuery" , 1 , 0 , "" , true , [ ] map [ string ] interface { } { } , customPanels )
2023-12-05 18:09:21 -03:00
fakeDashboardService . On ( "GetDashboard" , mock . Anything , mock . Anything , mock . Anything ) . Return ( dashboard , nil )
2023-05-29 12:59:29 -03:00
isEnabled := true
2022-10-27 17:08:11 -08:00
dto := & SavePublicDashboardDTO {
2023-01-16 16:33:55 +01:00
DashboardUid : dashboard . UID ,
2022-10-21 09:37:38 -03:00
UserId : 7 ,
2023-06-29 14:35:23 -03:00
OrgID : dashboard . OrgID ,
2023-05-29 12:59:29 -03:00
PublicDashboard : & PublicDashboardDTO {
2023-06-29 18:28:30 -03:00
IsEnabled : & isEnabled ,
2022-10-21 09:37:38 -03:00
} ,
}
2022-11-03 11:30:12 -08:00
pubdashDto , err := service . Create ( context . Background ( ) , SignedInUser , dto )
2022-10-21 09:37:38 -03:00
require . NoError ( t , err )
resp , _ := service . GetQueryDataResponse ( context . Background ( ) , true , publicDashboardQueryDTO , 1 , pubdashDto . AccessToken )
2023-03-16 15:39:17 -03:00
require . NotNil ( t , resp )
2022-10-21 09:37:38 -03:00
} )
}
2023-03-31 19:13:06 -03:00
func TestFindAnnotations ( t * testing . T ) {
2022-10-21 13:42:14 -06:00
color := "red"
name := "annoName"
2024-03-25 17:42:40 +00:00
features := featuremgmt . WithFeatures ( featuremgmt . FlagAnnotationPermissionUpdate )
2022-10-21 09:37:38 -03:00
t . Run ( "will build anonymous user with correct permissions to get annotations" , func ( t * testing . T ) {
2024-02-22 09:34:14 +01:00
fakeStore := & FakePublicDashboardStore { }
2022-10-26 12:53:33 -03:00
fakeStore . On ( "FindByAccessToken" , mock . Anything , mock . AnythingOfType ( "string" ) ) .
Return ( & PublicDashboard { Uid : "uid1" , IsEnabled : true } , nil )
2023-12-05 18:09:21 -03:00
fakeDashboardService := & dashboards . FakeDashboardService { }
fakeDashboardService . On ( "GetDashboard" , mock . Anything , mock . Anything , mock . Anything ) . Return ( dashboards . NewDashboard ( "dash1" ) , nil )
2024-04-04 15:04:47 +02:00
service , _ , _ := newPublicDashboardServiceImpl ( t , fakeStore , fakeDashboardService , nil )
2022-10-21 18:25:20 -03:00
2022-10-21 09:37:38 -03:00
reqDTO := AnnotationsQueryDTO {
From : 1 ,
To : 2 ,
}
2023-01-16 16:33:55 +01:00
dash := dashboards . NewDashboard ( "testDashboard" )
2022-10-21 09:37:38 -03:00
2022-10-25 21:40:42 -03:00
items , _ := service . FindAnnotations ( context . Background ( ) , reqDTO , "abc123" )
2024-03-25 17:42:40 +00:00
anonUser := buildAnonymousUser ( context . Background ( ) , dash , features )
2022-10-21 09:37:38 -03:00
assert . Equal ( t , "dashboards:*" , anonUser . Permissions [ 0 ] [ "dashboards:read" ] [ 0 ] )
assert . Len ( t , items , 0 )
} )
t . Run ( "Test events from tag queries overwrite built-in annotation queries and duplicate events are not returned" , func ( t * testing . T ) {
2023-01-16 16:33:55 +01:00
dash := dashboards . NewDashboard ( "test" )
2022-10-21 09:37:38 -03:00
grafanaAnnotation := DashAnnotation {
Datasource : CreateDatasource ( "grafana" , "grafana" ) ,
Enable : true ,
2023-04-18 13:39:30 -07:00
Name : name ,
IconColor : color ,
2022-10-21 09:37:38 -03:00
Target : & dashboard2 . AnnotationTarget {
Limit : 100 ,
MatchAny : false ,
Tags : nil ,
Type : "dashboard" ,
} ,
2023-04-18 13:39:30 -07:00
Type : util . Pointer ( "dashboard" ) ,
2022-10-21 09:37:38 -03:00
}
grafanaTagAnnotation := DashAnnotation {
Datasource : CreateDatasource ( "grafana" , "grafana" ) ,
Enable : true ,
2023-04-18 13:39:30 -07:00
Name : name ,
IconColor : color ,
2022-10-21 09:37:38 -03:00
Target : & dashboard2 . AnnotationTarget {
Limit : 100 ,
MatchAny : false ,
Tags : [ ] string { "tag1" } ,
Type : "tags" ,
} ,
}
annos := [ ] DashAnnotation { grafanaAnnotation , grafanaTagAnnotation }
dashboard := AddAnnotationsToDashboard ( t , dash , annos )
2023-01-16 16:33:55 +01:00
pubdash := & PublicDashboard { Uid : "uid1" , IsEnabled : true , OrgId : 1 , DashboardUid : dashboard . UID , AnnotationsEnabled : true }
2022-10-26 12:53:33 -03:00
2024-02-22 09:34:14 +01:00
annotationsRepo := & annotations . FakeAnnotationsRepo { }
fakeStore := & FakePublicDashboardStore { }
2022-10-26 12:53:33 -03:00
fakeStore . On ( "FindByAccessToken" , mock . Anything , mock . AnythingOfType ( "string" ) ) . Return ( pubdash , nil )
2023-12-05 18:09:21 -03:00
fakeDashboardService := & dashboards . FakeDashboardService { }
fakeDashboardService . On ( "GetDashboard" , mock . Anything , mock . Anything , mock . Anything ) . Return ( dashboard , nil )
2024-04-04 15:04:47 +02:00
service , _ , _ := newPublicDashboardServiceImpl ( t , fakeStore , fakeDashboardService , annotationsRepo )
2022-10-26 12:53:33 -03:00
2022-10-21 09:37:38 -03:00
annotationsRepo . On ( "Find" , mock . Anything , mock . Anything ) . Return ( [ ] * annotations . ItemDTO {
{
2023-02-03 17:23:09 +01:00
ID : 1 ,
DashboardID : 1 ,
PanelID : 1 ,
2022-10-21 09:37:38 -03:00
Tags : [ ] string { "tag1" } ,
TimeEnd : 2 ,
Time : 2 ,
Text : "text" ,
} ,
} , nil ) . Maybe ( )
2022-10-25 21:40:42 -03:00
items , err := service . FindAnnotations ( context . Background ( ) , AnnotationsQueryDTO { } , "abc123" )
2022-10-21 09:37:38 -03:00
expected := AnnotationEvent {
Id : 1 ,
DashboardId : 1 ,
PanelId : 0 ,
Tags : [ ] string { "tag1" } ,
IsRegion : false ,
Text : "text" ,
Color : color ,
Time : 2 ,
TimeEnd : 2 ,
Source : grafanaTagAnnotation ,
}
require . NoError ( t , err )
assert . Len ( t , items , 1 )
assert . Equal ( t , expected , items [ 0 ] )
} )
t . Run ( "Test panelId set to zero when annotation event is for a tags query" , func ( t * testing . T ) {
2023-01-16 16:33:55 +01:00
dash := dashboards . NewDashboard ( "test" )
2022-10-21 09:37:38 -03:00
grafanaAnnotation := DashAnnotation {
Datasource : CreateDatasource ( "grafana" , "grafana" ) ,
Enable : true ,
2023-04-18 13:39:30 -07:00
Name : name ,
IconColor : color ,
2022-10-21 09:37:38 -03:00
Target : & dashboard2 . AnnotationTarget {
Limit : 100 ,
MatchAny : false ,
Tags : [ ] string { "tag1" } ,
Type : "tags" ,
} ,
}
annos := [ ] DashAnnotation { grafanaAnnotation }
dashboard := AddAnnotationsToDashboard ( t , dash , annos )
2024-02-22 09:34:14 +01:00
annotationsRepo := & annotations . FakeAnnotationsRepo { }
fakeStore := & FakePublicDashboardStore { }
2023-01-16 16:33:55 +01:00
pubdash := & PublicDashboard { Uid : "uid1" , IsEnabled : true , OrgId : 1 , DashboardUid : dashboard . UID , AnnotationsEnabled : true }
2022-10-26 12:53:33 -03:00
fakeStore . On ( "FindByAccessToken" , mock . Anything , mock . AnythingOfType ( "string" ) ) . Return ( pubdash , nil )
2023-12-05 18:09:21 -03:00
fakeDashboardService := & dashboards . FakeDashboardService { }
fakeDashboardService . On ( "GetDashboard" , mock . Anything , mock . Anything , mock . Anything ) . Return ( dashboard , nil )
2024-04-04 15:04:47 +02:00
service , _ , _ := newPublicDashboardServiceImpl ( t , fakeStore , fakeDashboardService , annotationsRepo )
2022-10-26 12:53:33 -03:00
2022-10-21 09:37:38 -03:00
annotationsRepo . On ( "Find" , mock . Anything , mock . Anything ) . Return ( [ ] * annotations . ItemDTO {
{
2023-02-03 17:23:09 +01:00
ID : 1 ,
DashboardID : 1 ,
PanelID : 1 ,
2022-10-21 09:37:38 -03:00
Tags : [ ] string { } ,
TimeEnd : 1 ,
Time : 2 ,
Text : "text" ,
} ,
} , nil ) . Maybe ( )
2022-10-25 21:40:42 -03:00
items , err := service . FindAnnotations ( context . Background ( ) , AnnotationsQueryDTO { } , "abc123" )
2022-10-21 09:37:38 -03:00
expected := AnnotationEvent {
Id : 1 ,
DashboardId : 1 ,
PanelId : 0 ,
Tags : [ ] string { } ,
IsRegion : true ,
Text : "text" ,
Color : color ,
Time : 2 ,
TimeEnd : 1 ,
Source : grafanaAnnotation ,
}
require . NoError ( t , err )
assert . Len ( t , items , 1 )
assert . Equal ( t , expected , items [ 0 ] )
} )
t . Run ( "Test can get grafana annotations and will skip annotation queries and disabled annotations" , func ( t * testing . T ) {
2023-01-16 16:33:55 +01:00
dash := dashboards . NewDashboard ( "test" )
2022-10-21 09:37:38 -03:00
disabledGrafanaAnnotation := DashAnnotation {
Datasource : CreateDatasource ( "grafana" , "grafana" ) ,
Enable : false ,
2023-04-18 13:39:30 -07:00
Name : name ,
IconColor : color ,
2022-10-21 09:37:38 -03:00
}
grafanaAnnotation := DashAnnotation {
Datasource : CreateDatasource ( "grafana" , "grafana" ) ,
Enable : true ,
2023-04-18 13:39:30 -07:00
Name : name ,
IconColor : color ,
2022-10-21 09:37:38 -03:00
Target : & dashboard2 . AnnotationTarget {
Limit : 100 ,
MatchAny : true ,
Tags : nil ,
Type : "dashboard" ,
} ,
2023-04-18 13:39:30 -07:00
Type : util . Pointer ( "dashboard" ) ,
2022-10-21 09:37:38 -03:00
}
queryAnnotation := DashAnnotation {
Datasource : CreateDatasource ( "prometheus" , "abc123" ) ,
Enable : true ,
2023-04-18 13:39:30 -07:00
Name : name ,
2022-10-21 09:37:38 -03:00
}
annos := [ ] DashAnnotation { grafanaAnnotation , queryAnnotation , disabledGrafanaAnnotation }
dashboard := AddAnnotationsToDashboard ( t , dash , annos )
2024-02-22 09:34:14 +01:00
annotationsRepo := & annotations . FakeAnnotationsRepo { }
2023-12-05 18:09:21 -03:00
pubdash := & PublicDashboard { Uid : "uid1" , IsEnabled : true , OrgId : 1 , DashboardUid : dashboard . UID , AnnotationsEnabled : true }
2024-02-22 09:34:14 +01:00
fakeStore := & FakePublicDashboardStore { }
2023-12-05 18:09:21 -03:00
fakeStore . On ( "FindByAccessToken" , mock . Anything , mock . AnythingOfType ( "string" ) ) . Return ( pubdash , nil )
fakeDashboardService := & dashboards . FakeDashboardService { }
fakeDashboardService . On ( "GetDashboard" , mock . Anything , mock . Anything , mock . Anything ) . Return ( dashboard , nil )
2024-04-04 15:04:47 +02:00
service , _ , _ := newPublicDashboardServiceImpl ( t , fakeStore , fakeDashboardService , annotationsRepo )
2022-10-26 12:53:33 -03:00
2022-10-21 09:37:38 -03:00
annotationsRepo . On ( "Find" , mock . Anything , mock . Anything ) . Return ( [ ] * annotations . ItemDTO {
{
2023-02-03 17:23:09 +01:00
ID : 1 ,
DashboardID : 1 ,
PanelID : 1 ,
2022-10-21 09:37:38 -03:00
Tags : [ ] string { } ,
TimeEnd : 1 ,
Time : 2 ,
Text : "text" ,
} ,
} , nil ) . Maybe ( )
2022-10-25 21:40:42 -03:00
items , err := service . FindAnnotations ( context . Background ( ) , AnnotationsQueryDTO { } , "abc123" )
2022-10-21 09:37:38 -03:00
expected := AnnotationEvent {
Id : 1 ,
DashboardId : 1 ,
PanelId : 1 ,
Tags : [ ] string { } ,
IsRegion : true ,
Text : "text" ,
Color : color ,
Time : 2 ,
TimeEnd : 1 ,
Source : grafanaAnnotation ,
}
require . NoError ( t , err )
assert . Len ( t , items , 1 )
assert . Equal ( t , expected , items [ 0 ] )
} )
t . Run ( "test will return nothing when dashboard has no annotations" , func ( t * testing . T ) {
2023-01-16 16:33:55 +01:00
dashboard := dashboards . NewDashboard ( "dashWithNoAnnotations" )
pubdash := & PublicDashboard { Uid : "uid1" , IsEnabled : true , OrgId : 1 , DashboardUid : dashboard . UID , AnnotationsEnabled : true }
2024-02-22 09:34:14 +01:00
fakeStore := & FakePublicDashboardStore { }
2022-10-26 12:53:33 -03:00
fakeStore . On ( "FindByAccessToken" , mock . Anything , mock . AnythingOfType ( "string" ) ) . Return ( pubdash , nil )
2023-12-05 18:09:21 -03:00
fakeDashboardService := & dashboards . FakeDashboardService { }
fakeDashboardService . On ( "GetDashboard" , mock . Anything , mock . Anything , mock . Anything ) . Return ( dashboard , nil )
2024-04-04 15:04:47 +02:00
service , _ , _ := newPublicDashboardServiceImpl ( t , fakeStore , fakeDashboardService , nil )
2022-10-21 13:42:14 -06:00
2022-10-25 21:40:42 -03:00
items , err := service . FindAnnotations ( context . Background ( ) , AnnotationsQueryDTO { } , "abc123" )
2022-10-21 13:42:14 -06:00
require . NoError ( t , err )
assert . Empty ( t , items )
} )
t . Run ( "test will return nothing when pubdash annotations are disabled" , func ( t * testing . T ) {
2023-01-16 16:33:55 +01:00
dash := dashboards . NewDashboard ( "test" )
2022-10-21 13:42:14 -06:00
grafanaAnnotation := DashAnnotation {
Datasource : CreateDatasource ( "grafana" , "grafana" ) ,
Enable : true ,
2023-04-18 13:39:30 -07:00
Name : name ,
IconColor : color ,
2022-10-21 13:42:14 -06:00
Target : & dashboard2 . AnnotationTarget {
Limit : 100 ,
MatchAny : false ,
Tags : nil ,
Type : "dashboard" ,
} ,
2023-04-18 13:39:30 -07:00
Type : util . Pointer ( "dashboard" ) ,
2022-10-21 13:42:14 -06:00
}
annos := [ ] DashAnnotation { grafanaAnnotation }
dashboard := AddAnnotationsToDashboard ( t , dash , annos )
2023-01-16 16:33:55 +01:00
pubdash := & PublicDashboard { Uid : "uid1" , IsEnabled : true , OrgId : 1 , DashboardUid : dashboard . UID , AnnotationsEnabled : false }
2024-02-22 09:34:14 +01:00
fakeStore := & FakePublicDashboardStore { }
2022-10-26 12:53:33 -03:00
fakeStore . On ( "FindByAccessToken" , mock . Anything , mock . AnythingOfType ( "string" ) ) . Return ( pubdash , nil )
2023-12-05 18:09:21 -03:00
fakeDashboardService := & dashboards . FakeDashboardService { }
fakeDashboardService . On ( "GetDashboard" , mock . Anything , mock . Anything , mock . Anything ) . Return ( dashboard , nil )
2024-04-04 15:04:47 +02:00
service , _ , _ := newPublicDashboardServiceImpl ( t , fakeStore , fakeDashboardService , nil )
2022-10-21 09:37:38 -03:00
2022-10-25 21:40:42 -03:00
items , err := service . FindAnnotations ( context . Background ( ) , AnnotationsQueryDTO { } , "abc123" )
2022-10-21 09:37:38 -03:00
require . NoError ( t , err )
assert . Empty ( t , items )
} )
t . Run ( "test will error when annotations repo returns an error" , func ( t * testing . T ) {
grafanaAnnotation := DashAnnotation {
Datasource : CreateDatasource ( "grafana" , "grafana" ) ,
Enable : true ,
2023-04-18 13:39:30 -07:00
Name : name ,
IconColor : color ,
2022-10-21 09:37:38 -03:00
Target : & dashboard2 . AnnotationTarget {
Limit : 100 ,
MatchAny : false ,
Tags : [ ] string { "tag1" } ,
Type : "tags" ,
} ,
}
2023-12-05 18:09:21 -03:00
dash := dashboards . NewDashboard ( "test" )
2024-02-22 09:34:14 +01:00
annotationsRepo := & annotations . FakeAnnotationsRepo { }
annotationsRepo . On ( "Find" , mock . Anything , mock . Anything ) . Return ( nil , errors . New ( "failed" ) ) . Maybe ( )
2022-10-21 09:37:38 -03:00
annos := [ ] DashAnnotation { grafanaAnnotation }
dash = AddAnnotationsToDashboard ( t , dash , annos )
2023-01-16 16:33:55 +01:00
pubdash := & PublicDashboard { Uid : "uid1" , IsEnabled : true , OrgId : 1 , DashboardUid : dash . UID , AnnotationsEnabled : true }
2024-02-22 09:34:14 +01:00
fakeStore := & FakePublicDashboardStore { }
2022-10-26 12:53:33 -03:00
fakeStore . On ( "FindByAccessToken" , mock . Anything , mock . AnythingOfType ( "string" ) ) . Return ( pubdash , nil )
2023-12-05 18:09:21 -03:00
fakeDashboardService := & dashboards . FakeDashboardService { }
fakeDashboardService . On ( "GetDashboard" , mock . Anything , mock . Anything , mock . Anything ) . Return ( dash , nil )
2024-04-04 15:04:47 +02:00
service , _ , _ := newPublicDashboardServiceImpl ( t , fakeStore , fakeDashboardService , annotationsRepo )
2022-10-21 09:37:38 -03:00
2022-10-25 21:40:42 -03:00
items , err := service . FindAnnotations ( context . Background ( ) , AnnotationsQueryDTO { } , "abc123" )
2022-10-21 09:37:38 -03:00
require . Error ( t , err )
require . Nil ( t , items )
} )
2023-03-31 19:13:06 -03:00
t . Run ( "Test find annotations does not panics when Target in datasource is nil" , func ( t * testing . T ) {
dash := dashboards . NewDashboard ( "test" )
grafanaAnnotation := DashAnnotation {
Datasource : CreateDatasource ( "grafana" , "grafana" ) ,
Enable : true ,
2023-04-18 13:39:30 -07:00
Name : name ,
IconColor : color ,
Type : util . Pointer ( "dashboard" ) ,
2023-03-31 19:13:06 -03:00
Target : nil ,
}
annos := [ ] DashAnnotation { grafanaAnnotation }
dashboard := AddAnnotationsToDashboard ( t , dash , annos )
pubdash := & PublicDashboard { Uid : "uid1" , IsEnabled : true , OrgId : 1 , DashboardUid : dashboard . UID , AnnotationsEnabled : true }
2024-02-22 09:34:14 +01:00
fakeStore := & FakePublicDashboardStore { }
2023-03-31 19:13:06 -03:00
fakeStore . On ( "FindByAccessToken" , mock . Anything , mock . AnythingOfType ( "string" ) ) . Return ( pubdash , nil )
2023-12-05 18:09:21 -03:00
fakeStore . On ( "FindByAccessToken" , mock . Anything , mock . AnythingOfType ( "string" ) ) . Return ( pubdash , nil )
fakeDashboardService := & dashboards . FakeDashboardService { }
fakeDashboardService . On ( "GetDashboard" , mock . Anything , mock . Anything , mock . Anything ) . Return ( dashboard , nil )
2024-02-22 09:34:14 +01:00
annotationsRepo := & annotations . FakeAnnotationsRepo { }
2023-03-31 19:13:06 -03:00
annotationsRepo . On ( "Find" , mock . Anything , mock . Anything ) . Return ( [ ] * annotations . ItemDTO {
{
ID : 1 ,
DashboardID : 1 ,
PanelID : 1 ,
Tags : [ ] string { "tag1" } ,
TimeEnd : 2 ,
Time : 2 ,
Text : "this is an annotation" ,
} ,
} , nil ) . Maybe ( )
2024-04-04 15:04:47 +02:00
service , _ , _ := newPublicDashboardServiceImpl ( t , fakeStore , fakeDashboardService , annotationsRepo )
2023-12-05 18:09:21 -03:00
2023-03-31 19:13:06 -03:00
items , err := service . FindAnnotations ( context . Background ( ) , AnnotationsQueryDTO { } , "abc123" )
expected := AnnotationEvent {
Id : 1 ,
DashboardId : 1 ,
PanelId : 1 ,
Tags : [ ] string { "tag1" } ,
IsRegion : false ,
Text : "this is an annotation" ,
Color : color ,
Time : 2 ,
TimeEnd : 2 ,
Source : grafanaAnnotation ,
}
require . NoError ( t , err )
assert . Len ( t , items , 1 )
assert . Equal ( t , expected , items [ 0 ] )
} )
2022-10-21 09:37:38 -03:00
}
func TestGetMetricRequest ( t * testing . T ) {
2024-04-04 15:04:47 +02:00
service , sqlStore , cfg := newPublicDashboardServiceImpl ( t , nil , nil , nil )
dashboardStore , err := dashboardsDB . ProvideDashboardStore ( sqlStore , cfg , featuremgmt . WithFeatures ( ) , tagimpl . ProvideService ( sqlStore ) , quotatest . New ( false , nil ) )
2022-11-14 21:08:10 +02:00
require . NoError ( t , err )
2023-10-24 10:04:45 +03:00
dashboard := insertTestDashboard ( t , dashboardStore , "testDashie" , 1 , 0 , "" , true , [ ] map [ string ] interface { } { } , nil )
2024-02-22 09:34:14 +01:00
2022-10-21 09:37:38 -03:00
publicDashboard := & PublicDashboard {
Uid : "1" ,
2023-01-16 16:33:55 +01:00
DashboardUid : dashboard . UID ,
2022-10-21 09:37:38 -03:00
IsEnabled : true ,
AccessToken : "abc123" ,
}
t . Run ( "will return an error when validation fails" , func ( t * testing . T ) {
publicDashboardQueryDTO := PublicDashboardQueryDTO {
IntervalMs : int64 ( - 1 ) ,
MaxDataPoints : int64 ( - 1 ) ,
}
_ , err := service . GetMetricRequest ( context . Background ( ) , dashboard , publicDashboard , 1 , publicDashboardQueryDTO )
require . Error ( t , err )
} )
t . Run ( "will not return an error when validation succeeds" , func ( t * testing . T ) {
publicDashboardQueryDTO := PublicDashboardQueryDTO {
IntervalMs : int64 ( 1 ) ,
MaxDataPoints : int64 ( 1 ) ,
}
from , to := internal . GetTimeRangeFromDashboard ( t , dashboard . Data )
metricReq , err := service . GetMetricRequest ( context . Background ( ) , dashboard , publicDashboard , 1 , publicDashboardQueryDTO )
require . NoError ( t , err )
require . Equal ( t , from , metricReq . From )
require . Equal ( t , to , metricReq . To )
} )
}
func TestGetUniqueDashboardDatasourceUids ( t * testing . T ) {
t . Run ( "can get unique datasource ids from dashboard" , func ( t * testing . T ) {
json , err := simplejson . NewJson ( [ ] byte ( dashboardWithDuplicateDatasources ) )
require . NoError ( t , err )
uids := getUniqueDashboardDatasourceUids ( json )
require . Len ( t , uids , 2 )
require . Equal ( t , "abc123" , uids [ 0 ] )
require . Equal ( t , "_yxMP8Ynk" , uids [ 1 ] )
} )
t . Run ( "can get unique datasource ids from dashboard with a mixed datasource" , func ( t * testing . T ) {
json , err := simplejson . NewJson ( [ ] byte ( dashboardWithMixedDatasource ) )
require . NoError ( t , err )
uids := getUniqueDashboardDatasourceUids ( json )
2023-06-15 10:28:34 -03:00
require . Len ( t , uids , 3 )
2022-10-21 09:37:38 -03:00
require . Equal ( t , "abc123" , uids [ 0 ] )
2023-06-15 10:28:34 -03:00
require . Equal ( t , "6SOeCRrVk" , uids [ 1 ] )
require . Equal ( t , "_yxMP8Ynk" , uids [ 2 ] )
2022-10-21 09:37:38 -03:00
} )
t . Run ( "can get no datasource uids from empty dashboard" , func ( t * testing . T ) {
json , err := simplejson . NewJson ( [ ] byte ( ` { "panels": { }} ` ) )
require . NoError ( t , err )
uids := getUniqueDashboardDatasourceUids ( json )
require . Len ( t , uids , 0 )
} )
2023-04-05 10:35:00 -03:00
t . Run ( "can get unique datasource ids from dashboard with rows" , func ( t * testing . T ) {
json , err := simplejson . NewJson ( [ ] byte ( dashboardWithCollapsedRows ) )
require . NoError ( t , err )
uids := getUniqueDashboardDatasourceUids ( json )
require . Len ( t , uids , 2 )
require . Equal ( t , "qCbTUC37k" , uids [ 0 ] )
require . Equal ( t , "P49A45DF074423DFB" , uids [ 1 ] )
} )
2022-10-21 09:37:38 -03:00
}
func TestBuildMetricRequest ( t * testing . T ) {
2024-02-22 09:34:14 +01:00
fakeDashboardService := & dashboards . FakeDashboardService { }
2024-04-04 15:04:47 +02:00
service , sqlStore , cfg := newPublicDashboardServiceImpl ( t , nil , fakeDashboardService , nil )
2024-02-22 09:34:14 +01:00
2024-04-04 15:04:47 +02:00
dashboardStore , err := dashboardsDB . ProvideDashboardStore ( sqlStore , cfg , featuremgmt . WithFeatures ( ) , tagimpl . ProvideService ( sqlStore ) , quotatest . New ( false , nil ) )
2022-11-14 21:08:10 +02:00
require . NoError ( t , err )
2023-10-24 10:04:45 +03:00
publicDashboard := insertTestDashboard ( t , dashboardStore , "testDashie" , 1 , 0 , "" , true , [ ] map [ string ] interface { } { } , nil )
nonPublicDashboard := insertTestDashboard ( t , dashboardStore , "testNonPublicDashie" , 1 , 0 , "" , true , [ ] map [ string ] interface { } { } , nil )
2022-10-21 09:37:38 -03:00
from , to := internal . GetTimeRangeFromDashboard ( t , publicDashboard . Data )
2024-02-22 09:34:14 +01:00
fakeDashboardService . On ( "GetDashboard" , mock . Anything , mock . Anything , mock . Anything ) . Return ( publicDashboard , nil )
2022-10-21 09:37:38 -03:00
publicDashboardQueryDTO := PublicDashboardQueryDTO {
IntervalMs : int64 ( 10000000 ) ,
MaxDataPoints : int64 ( 200 ) ,
}
2023-05-29 12:59:29 -03:00
isEnabled := true
2022-10-27 17:08:11 -08:00
dto := & SavePublicDashboardDTO {
2023-01-16 16:33:55 +01:00
DashboardUid : publicDashboard . UID ,
2023-06-29 14:35:23 -03:00
OrgID : 9999999 ,
2023-05-29 12:59:29 -03:00
PublicDashboard : & PublicDashboardDTO {
2023-06-29 18:28:30 -03:00
IsEnabled : & isEnabled ,
2022-10-21 09:37:38 -03:00
} ,
}
2022-11-03 11:30:12 -08:00
publicDashboardPD , err := service . Create ( context . Background ( ) , SignedInUser , dto )
2022-10-21 09:37:38 -03:00
require . NoError ( t , err )
2023-05-29 12:59:29 -03:00
isEnabled = false
2022-10-27 17:08:11 -08:00
nonPublicDto := & SavePublicDashboardDTO {
2023-01-16 16:33:55 +01:00
DashboardUid : nonPublicDashboard . UID ,
2023-06-29 14:35:23 -03:00
OrgID : 9999999 ,
2023-05-29 12:59:29 -03:00
PublicDashboard : & PublicDashboardDTO {
2023-06-29 18:28:30 -03:00
IsEnabled : & isEnabled ,
2022-10-21 09:37:38 -03:00
} ,
}
2022-11-03 11:30:12 -08:00
_ , err = service . Create ( context . Background ( ) , SignedInUser , nonPublicDto )
2022-10-21 09:37:38 -03:00
require . NoError ( t , err )
t . Run ( "extracts queries from provided dashboard" , func ( t * testing . T ) {
reqDTO , err := service . buildMetricRequest (
publicDashboard ,
publicDashboardPD ,
1 ,
publicDashboardQueryDTO ,
)
require . NoError ( t , err )
require . Equal ( t , from , reqDTO . From )
require . Equal ( t , to , reqDTO . To )
for i := range reqDTO . Queries {
require . Equal ( t , publicDashboardQueryDTO . IntervalMs , reqDTO . Queries [ i ] . Get ( "intervalMs" ) . MustInt64 ( ) )
require . Equal ( t , publicDashboardQueryDTO . MaxDataPoints , reqDTO . Queries [ i ] . Get ( "maxDataPoints" ) . MustInt64 ( ) )
}
require . Len ( t , reqDTO . Queries , 2 )
require . Equal (
t ,
simplejson . NewFromAny ( map [ string ] interface { } {
"datasource" : map [ string ] interface { } {
"type" : "mysql" ,
"uid" : "ds1" ,
} ,
2023-02-02 23:39:54 -05:00
"intervalMs" : int64 ( 10000000 ) ,
"maxDataPoints" : int64 ( 200 ) ,
"queryCachingTTL" : int64 ( 0 ) ,
"refId" : "A" ,
2022-10-21 09:37:38 -03:00
} ) ,
reqDTO . Queries [ 0 ] ,
)
require . Equal (
t ,
simplejson . NewFromAny ( map [ string ] interface { } {
"datasource" : map [ string ] interface { } {
"type" : "prometheus" ,
"uid" : "ds2" ,
} ,
2023-02-02 23:39:54 -05:00
"intervalMs" : int64 ( 10000000 ) ,
"maxDataPoints" : int64 ( 200 ) ,
"queryCachingTTL" : int64 ( 0 ) ,
"refId" : "B" ,
2022-10-21 09:37:38 -03:00
} ) ,
reqDTO . Queries [ 1 ] ,
)
} )
t . Run ( "returns an error when panel missing" , func ( t * testing . T ) {
_ , err := service . buildMetricRequest (
publicDashboard ,
publicDashboardPD ,
49 ,
publicDashboardQueryDTO ,
)
2022-11-04 14:14:32 -03:00
require . ErrorContains ( t , err , ErrPanelNotFound . Error ( ) )
2022-10-21 09:37:38 -03:00
} )
2023-03-16 15:39:17 -03:00
t . Run ( "metric request built with hidden query" , func ( t * testing . T ) {
2022-10-21 09:37:38 -03:00
hiddenQuery := map [ string ] interface { } {
"datasource" : map [ string ] interface { } {
"type" : "mysql" ,
"uid" : "ds1" ,
} ,
"hide" : true ,
"refId" : "A" ,
}
nonHiddenQuery := map [ string ] interface { } {
"datasource" : map [ string ] interface { } {
"type" : "prometheus" ,
"uid" : "ds2" ,
} ,
"refId" : "B" ,
}
customPanels := [ ] interface { } {
map [ string ] interface { } {
"id" : 1 ,
"datasource" : map [ string ] interface { } {
"uid" : "ds1" ,
} ,
"targets" : [ ] interface { } { hiddenQuery , nonHiddenQuery } ,
} }
2023-10-24 10:04:45 +03:00
publicDashboard := insertTestDashboard ( t , dashboardStore , "testDashWithHiddenQuery" , 1 , 0 , "" , true , [ ] map [ string ] interface { } { } , customPanels )
2022-10-21 09:37:38 -03:00
reqDTO , err := service . buildMetricRequest (
publicDashboard ,
publicDashboardPD ,
1 ,
publicDashboardQueryDTO ,
)
require . NoError ( t , err )
require . Equal ( t , from , reqDTO . From )
require . Equal ( t , to , reqDTO . To )
for i := range reqDTO . Queries {
require . Equal ( t , publicDashboardQueryDTO . IntervalMs , reqDTO . Queries [ i ] . Get ( "intervalMs" ) . MustInt64 ( ) )
require . Equal ( t , publicDashboardQueryDTO . MaxDataPoints , reqDTO . Queries [ i ] . Get ( "maxDataPoints" ) . MustInt64 ( ) )
}
2023-07-31 10:54:54 -03:00
require . Len ( t , reqDTO . Queries , 1 )
2022-10-21 09:37:38 -03:00
require . Equal (
t ,
simplejson . NewFromAny ( nonHiddenQuery ) ,
2023-07-31 10:54:54 -03:00
reqDTO . Queries [ 0 ] ,
2022-10-21 09:37:38 -03:00
)
} )
}
func TestBuildAnonymousUser ( t * testing . T ) {
2024-04-24 10:38:40 +02:00
sqlStore , cfg := db . InitTestDBWithCfg ( t )
dashboardStore , err := dashboardsDB . ProvideDashboardStore ( sqlStore , cfg , featuremgmt . WithFeatures ( ) , tagimpl . ProvideService ( sqlStore ) , quotatest . New ( false , nil ) )
2022-11-14 21:08:10 +02:00
require . NoError ( t , err )
2023-10-24 10:04:45 +03:00
dashboard := insertTestDashboard ( t , dashboardStore , "testDashie" , 1 , 0 , "" , true , [ ] map [ string ] interface { } { } , nil )
2024-03-25 17:42:40 +00:00
features := featuremgmt . WithFeatures ( )
2022-10-21 09:37:38 -03:00
t . Run ( "will add datasource read and query permissions to user for each datasource in dashboard" , func ( t * testing . T ) {
2024-03-25 17:42:40 +00:00
user := buildAnonymousUser ( context . Background ( ) , dashboard , features )
2022-10-21 09:37:38 -03:00
2023-01-16 16:33:55 +01:00
require . Equal ( t , dashboard . OrgID , user . OrgID )
2022-10-21 09:37:38 -03:00
require . Equal ( t , "datasources:uid:ds1" , user . Permissions [ user . OrgID ] [ "datasources:query" ] [ 0 ] )
require . Equal ( t , "datasources:uid:ds3" , user . Permissions [ user . OrgID ] [ "datasources:query" ] [ 1 ] )
require . Equal ( t , "datasources:uid:ds1" , user . Permissions [ user . OrgID ] [ "datasources:read" ] [ 0 ] )
require . Equal ( t , "datasources:uid:ds3" , user . Permissions [ user . OrgID ] [ "datasources:read" ] [ 1 ] )
} )
t . Run ( "will add dashboard and annotation permissions needed for getting annotations" , func ( t * testing . T ) {
2024-03-25 17:42:40 +00:00
user := buildAnonymousUser ( context . Background ( ) , dashboard , features )
2022-10-21 09:37:38 -03:00
2023-01-16 16:33:55 +01:00
require . Equal ( t , dashboard . OrgID , user . OrgID )
2022-10-21 09:37:38 -03:00
require . Equal ( t , "annotations:type:dashboard" , user . Permissions [ user . OrgID ] [ "annotations:read" ] [ 0 ] )
require . Equal ( t , "dashboards:*" , user . Permissions [ user . OrgID ] [ "dashboards:read" ] [ 0 ] )
} )
2024-03-25 17:42:40 +00:00
t . Run ( "will add dashboard and annotation permissions needed for getting annotations when FlagAnnotationPermissionUpdate is enabled" , func ( t * testing . T ) {
features = featuremgmt . WithFeatures ( featuremgmt . FlagAnnotationPermissionUpdate )
user := buildAnonymousUser ( context . Background ( ) , dashboard , features )
require . Equal ( t , dashboard . OrgID , user . OrgID )
require . Equal ( t , "dashboards:*" , user . Permissions [ user . OrgID ] [ "annotations:read" ] [ 0 ] )
require . Equal ( t , "dashboards:*" , user . Permissions [ user . OrgID ] [ "dashboards:read" ] [ 0 ] )
} )
2022-10-21 09:37:38 -03:00
}
func TestGroupQueriesByPanelId ( t * testing . T ) {
t . Run ( "can extract queries from dashboard with panel datasource string that has no datasource on panel targets" , func ( t * testing . T ) {
json , err := simplejson . NewJson ( [ ] byte ( oldStyleDashboard ) )
require . NoError ( t , err )
queries := groupQueriesByPanelId ( json )
panelId := int64 ( 2 )
queriesByDatasource := groupQueriesByDataSource ( t , queries [ panelId ] )
require . Len ( t , queriesByDatasource [ 0 ] , 1 )
} )
t . Run ( "will delete exemplar property from target if exists" , func ( t * testing . T ) {
json , err := simplejson . NewJson ( [ ] byte ( dashboardWithQueriesExemplarEnabled ) )
require . NoError ( t , err )
queries := groupQueriesByPanelId ( json )
panelId := int64 ( 2 )
queriesByDatasource := groupQueriesByDataSource ( t , queries [ panelId ] )
for _ , query := range queriesByDatasource [ 0 ] {
_ , ok := query . CheckGet ( "exemplar" )
require . False ( t , ok )
}
} )
t . Run ( "can extract queries from dashboard with panel json datasource that has no datasource on panel targets" , func ( t * testing . T ) {
json , err := simplejson . NewJson ( [ ] byte ( dashboardWithTargetsWithNoDatasources ) )
require . NoError ( t , err )
queries := groupQueriesByPanelId ( json )
panelId := int64 ( 2 )
queriesByDatasource := groupQueriesByDataSource ( t , queries [ panelId ] )
require . Len ( t , queriesByDatasource [ 0 ] , 2 )
} )
t . Run ( "can extract no queries from empty dashboard" , func ( t * testing . T ) {
json , err := simplejson . NewJson ( [ ] byte ( ` { "panels": { }} ` ) )
require . NoError ( t , err )
queries := groupQueriesByPanelId ( json )
require . Len ( t , queries , 0 )
} )
t . Run ( "can extract no queries from empty panel" , func ( t * testing . T ) {
json , err := simplejson . NewJson ( [ ] byte ( dashboardWithNoQueries ) )
require . NoError ( t , err )
queries := groupQueriesByPanelId ( json )
require . Len ( t , queries , 1 )
require . Contains ( t , queries , int64 ( 2 ) )
require . Len ( t , queries [ 2 ] , 0 )
} )
t . Run ( "can extract queries from panels" , func ( t * testing . T ) {
json , err := simplejson . NewJson ( [ ] byte ( dashboardWithQueriesExemplarEnabled ) )
require . NoError ( t , err )
queries := groupQueriesByPanelId ( json )
require . Len ( t , queries , 1 )
require . Contains ( t , queries , int64 ( 2 ) )
require . Len ( t , queries [ 2 ] , 2 )
query , err := queries [ 2 ] [ 0 ] . MarshalJSON ( )
require . NoError ( t , err )
require . JSONEq ( t , ` {
"datasource" : {
"type" : "prometheus" ,
"uid" : "_yxMP8Ynk"
} ,
"expr" : "go_goroutines{job=\"$job\"}" ,
"interval" : "" ,
"legendFormat" : "" ,
"refId" : "A"
} ` , string ( query ) )
query , err = queries [ 2 ] [ 1 ] . MarshalJSON ( )
require . NoError ( t , err )
require . JSONEq ( t , ` {
"datasource" : {
"type" : "prometheus" ,
"uid" : "promds2"
} ,
"expr" : "query2" ,
"interval" : "" ,
"legendFormat" : "" ,
"refId" : "B"
} ` , string ( query ) )
} )
t . Run ( "can extract queries from old-style panels" , func ( t * testing . T ) {
json , err := simplejson . NewJson ( [ ] byte ( oldStyleDashboard ) )
require . NoError ( t , err )
queries := groupQueriesByPanelId ( json )
require . Len ( t , queries , 1 )
require . Contains ( t , queries , int64 ( 2 ) )
require . Len ( t , queries [ 2 ] , 1 )
query , err := queries [ 2 ] [ 0 ] . MarshalJSON ( )
require . NoError ( t , err )
require . JSONEq ( t , ` {
"datasource" : {
"uid" : "_yxMP8Ynk" ,
"type" : "public-ds"
} ,
"expr" : "go_goroutines{job=\"$job\"}" ,
"interval" : "" ,
"legendFormat" : "" ,
"refId" : "A"
} ` , string ( query ) )
} )
2023-07-31 10:54:54 -03:00
t . Run ( "hidden queries in a panel with an expression not filtered" , func ( t * testing . T ) {
2022-10-21 09:37:38 -03:00
json , err := simplejson . NewJson ( [ ] byte ( dashboardWithOneHiddenQuery ) )
require . NoError ( t , err )
queries := groupQueriesByPanelId ( json ) [ 2 ]
2023-07-31 10:54:54 -03:00
require . Len ( t , queries , 3 )
2022-10-21 09:37:38 -03:00
} )
2023-07-31 10:54:54 -03:00
t . Run ( "all hidden queries in a panel with an expression not filtered" , func ( t * testing . T ) {
2022-10-21 09:37:38 -03:00
json , err := simplejson . NewJson ( [ ] byte ( dashboardWithAllHiddenQueries ) )
require . NoError ( t , err )
queries := groupQueriesByPanelId ( json ) [ 2 ]
2023-07-31 10:54:54 -03:00
require . Len ( t , queries , 3 )
2022-10-21 09:37:38 -03:00
} )
2023-03-15 12:44:17 -03:00
t . Run ( "queries inside panels inside rows are returned" , func ( t * testing . T ) {
2023-07-31 10:54:54 -03:00
json , err := simplejson . NewJson ( [ ] byte ( dashboardWithRowsAndOneHiddenQuery ) )
2023-03-15 12:44:17 -03:00
require . NoError ( t , err )
queries := groupQueriesByPanelId ( json )
for idx := range queries {
assert . NotNil ( t , queries [ idx ] )
}
assert . Len ( t , queries , 2 )
} )
2023-07-31 10:54:54 -03:00
t . Run ( "hidden queries are not returned" , func ( t * testing . T ) {
json , err := simplejson . NewJson ( [ ] byte ( dashboardWithRowsAndOneHiddenQuery ) )
require . NoError ( t , err )
queries := groupQueriesByPanelId ( json )
var totalQueries int
for idx := range queries {
totalQueries += len ( queries [ idx ] )
assert . NotNil ( t , queries [ idx ] )
}
assert . Equal ( t , 3 , totalQueries )
} )
2022-10-21 09:37:38 -03:00
}
func TestGroupQueriesByDataSource ( t * testing . T ) {
t . Run ( "can divide queries by datasource" , func ( t * testing . T ) {
queries := [ ] * simplejson . Json {
simplejson . MustJson ( [ ] byte ( ` {
"datasource" : {
"type" : "prometheus" ,
"uid" : "_yxMP8Ynk"
} ,
"exemplar" : true ,
"expr" : "go_goroutines{job=\"$job\"}" ,
"interval" : "" ,
"legendFormat" : "" ,
"refId" : "A"
} ` ) ) ,
simplejson . MustJson ( [ ] byte ( ` {
"datasource" : {
"type" : "prometheus" ,
"uid" : "promds2"
} ,
"exemplar" : true ,
"expr" : "query2" ,
"interval" : "" ,
"legendFormat" : "" ,
"refId" : "B"
} ` ) ) ,
}
queriesByDatasource := groupQueriesByDataSource ( t , queries )
require . Len ( t , queriesByDatasource , 2 )
require . Contains ( t , queriesByDatasource , [ ] * simplejson . Json { simplejson . MustJson ( [ ] byte ( ` {
"datasource" : {
"type" : "prometheus" ,
"uid" : "_yxMP8Ynk"
} ,
"exemplar" : true ,
"expr" : "go_goroutines{job=\"$job\"}" ,
"interval" : "" ,
"legendFormat" : "" ,
"refId" : "A"
} ` ) ) } )
require . Contains ( t , queriesByDatasource , [ ] * simplejson . Json { simplejson . MustJson ( [ ] byte ( ` {
"datasource" : {
"type" : "prometheus" ,
"uid" : "promds2"
} ,
"exemplar" : true ,
"expr" : "query2" ,
"interval" : "" ,
"legendFormat" : "" ,
"refId" : "B"
} ` ) ) } )
} )
}
func TestSanitizeMetadataFromQueryData ( t * testing . T ) {
2023-04-28 15:03:30 -03:00
t . Run ( "can remove ExecutedQueryString from metadata" , func ( t * testing . T ) {
2022-10-21 09:37:38 -03:00
fakeResponse := & backend . QueryDataResponse {
Responses : backend . Responses {
"A" : backend . DataResponse {
Frames : data . Frames {
& data . Frame {
Name : "1" ,
Meta : & data . FrameMeta {
ExecutedQueryString : "Test1" ,
Custom : map [ string ] string {
"test1" : "test1" ,
} ,
} ,
} ,
& data . Frame {
Name : "2" ,
Meta : & data . FrameMeta {
ExecutedQueryString : "Test2" ,
Custom : map [ string ] string {
"test2" : "test2" ,
} ,
} ,
} ,
} ,
} ,
"B" : backend . DataResponse {
Frames : data . Frames {
& data . Frame {
Name : "3" ,
Meta : & data . FrameMeta {
ExecutedQueryString : "Test3" ,
} ,
} ,
} ,
} ,
} ,
}
sanitizeMetadataFromQueryData ( fakeResponse )
2023-04-28 15:03:30 -03:00
assert . Equal ( t , fakeResponse . Responses [ "A" ] . Frames [ 0 ] . Meta . ExecutedQueryString , "" )
assert . Equal ( t , fakeResponse . Responses [ "A" ] . Frames [ 0 ] . Meta . Custom , map [ string ] string { "test1" : "test1" } )
assert . Equal ( t , fakeResponse . Responses [ "A" ] . Frames [ 1 ] . Meta . ExecutedQueryString , "" )
assert . Equal ( t , fakeResponse . Responses [ "A" ] . Frames [ 1 ] . Meta . Custom , map [ string ] string { "test2" : "test2" } )
assert . Equal ( t , fakeResponse . Responses [ "B" ] . Frames [ 0 ] . Meta . ExecutedQueryString , "" )
assert . Nil ( t , fakeResponse . Responses [ "B" ] . Frames [ 0 ] . Meta . Custom )
2022-10-21 09:37:38 -03:00
} )
}
2023-06-14 17:35:01 -03:00
func TestBuildTimeSettings ( t * testing . T ) {
var defaultDashboardData = simplejson . NewFromAny ( map [ string ] interface { } {
"time" : map [ string ] interface { } {
"from" : "2022-09-01T00:00:00.000Z" , "to" : "2022-09-01T12:00:00.000Z" ,
} ,
"timezone" : "America/Argentina/Mendoza" ,
} )
defaultFromMs , defaultToMs := internal . GetTimeRangeFromDashboard ( t , defaultDashboardData )
fakeTimezone , _ := time . LoadLocation ( "Europe/Madrid" )
fakeNow := time . Date ( 2018 , 12 , 9 , 20 , 30 , 0 , 0 , fakeTimezone )
// stub time range construction to have a fixed time.Now and be able to tests relative time ranges
2024-06-05 22:31:06 +02:00
NewTimeRange = func ( from , to string ) gtime . TimeRange {
return gtime . TimeRange {
2023-06-14 17:35:01 -03:00
From : from ,
To : to ,
Now : fakeNow ,
}
}
startOfYesterdayMadrid , endOfYesterdayMadrid := getStartAndEndOfTheDayBefore ( fakeNow , "Europe/Madrid" )
// the day before fakeNow in Australia/Sydney timezone is not the same day before as in Europe/Madrid
startOfYesterdaySydney , endOfYesterdaySydney := getStartAndEndOfTheDayBefore ( fakeNow , "Australia/Sydney" )
startOfYesterdayUTC , endOfYesterdayUTC := getStartAndEndOfTheDayBefore ( fakeNow , "UTC" )
selectionFromMs := strconv . FormatInt ( time . Now ( ) . UnixMilli ( ) , 10 )
selectionToMs := strconv . FormatInt ( time . Now ( ) . Add ( time . Hour ) . UnixMilli ( ) , 10 )
testCases := [ ] struct {
name string
dashboard * dashboards . Dashboard
pubdash * PublicDashboard
reqDTO PublicDashboardQueryDTO
want TimeSettings
} {
{
name : "should return default time range with timezone with relative time range" ,
dashboard : & dashboards . Dashboard { Data : buildJsonDataWithTimeRange ( "now-1d/d" , "now-1d/d" , "Australia/Sydney" ) } ,
pubdash : & PublicDashboard { TimeSelectionEnabled : false } ,
reqDTO : PublicDashboardQueryDTO { } ,
want : TimeSettings {
From : strconv . FormatInt ( startOfYesterdaySydney . UnixMilli ( ) , 10 ) ,
To : strconv . FormatInt ( endOfYesterdaySydney . UnixMilli ( ) , 10 ) ,
} ,
} ,
{
name : "should return default time range with UTC timezone with relative time range with unknown timezone" ,
dashboard : & dashboards . Dashboard { Data : buildJsonDataWithTimeRange ( "now-1d/d" , "now-1d/d" , "browser" ) } ,
pubdash : & PublicDashboard { TimeSelectionEnabled : false } ,
reqDTO : PublicDashboardQueryDTO { } ,
want : TimeSettings {
From : strconv . FormatInt ( startOfYesterdayUTC . UnixMilli ( ) , 10 ) ,
To : strconv . FormatInt ( endOfYesterdayUTC . UnixMilli ( ) , 10 ) ,
} ,
} ,
{
name : "should return default time range with timezone with relative time range if time selection is not enabled" ,
dashboard : & dashboards . Dashboard { Data : buildJsonDataWithTimeRange ( "now-1d/d" , "now-1d/d" , "Australia/Sydney" ) } ,
pubdash : & PublicDashboard { TimeSelectionEnabled : false } ,
reqDTO : PublicDashboardQueryDTO {
TimeRange : TimeRangeDTO {
Timezone : "Europe/Madrid" ,
} } ,
want : TimeSettings {
From : strconv . FormatInt ( startOfYesterdaySydney . UnixMilli ( ) , 10 ) ,
To : strconv . FormatInt ( endOfYesterdaySydney . UnixMilli ( ) , 10 ) ,
} ,
} ,
{
name : "should return user time range with dashboard timezone with relative time range" ,
dashboard : & dashboards . Dashboard { Data : buildJsonDataWithTimeRange ( "now-1d/d" , "now-1d/d" , "Europe/Madrid" ) } ,
pubdash : & PublicDashboard { TimeSelectionEnabled : false } ,
reqDTO : PublicDashboardQueryDTO { } ,
want : TimeSettings {
From : strconv . FormatInt ( startOfYesterdayMadrid . UnixMilli ( ) , 10 ) ,
To : strconv . FormatInt ( endOfYesterdayMadrid . UnixMilli ( ) , 10 ) ,
} ,
} ,
{
name : "should return user time range with dashboard timezone with relative time range for the last hour" ,
dashboard : & dashboards . Dashboard { Data : buildJsonDataWithTimeRange ( "now-1h" , "now" , "Europe/Madrid" ) } ,
pubdash : & PublicDashboard { TimeSelectionEnabled : false } ,
reqDTO : PublicDashboardQueryDTO { } ,
want : TimeSettings {
From : strconv . FormatInt ( fakeNow . Add ( - time . Hour ) . UnixMilli ( ) , 10 ) ,
To : strconv . FormatInt ( fakeNow . UnixMilli ( ) , 10 ) ,
} ,
} ,
{
name : "should use dashboard time if pubdash time empty" ,
dashboard : & dashboards . Dashboard { Data : defaultDashboardData } ,
pubdash : & PublicDashboard { TimeSelectionEnabled : false } ,
reqDTO : PublicDashboardQueryDTO { } ,
want : TimeSettings {
From : defaultFromMs ,
To : defaultToMs ,
} ,
} ,
{
name : "should use dashboard time when time selection is disabled" ,
dashboard : & dashboards . Dashboard { Data : defaultDashboardData } ,
pubdash : & PublicDashboard { TimeSelectionEnabled : false } ,
reqDTO : PublicDashboardQueryDTO {
TimeRange : TimeRangeDTO {
From : selectionFromMs ,
To : selectionToMs ,
} ,
} ,
want : TimeSettings {
From : defaultFromMs ,
To : defaultToMs ,
} ,
} ,
{
name : "should use selected values if time selection is enabled" ,
dashboard : & dashboards . Dashboard { Data : defaultDashboardData } ,
pubdash : & PublicDashboard { TimeSelectionEnabled : true } ,
reqDTO : PublicDashboardQueryDTO {
TimeRange : TimeRangeDTO {
From : selectionFromMs ,
To : selectionToMs ,
} ,
} ,
want : TimeSettings {
From : selectionFromMs ,
To : selectionToMs ,
} ,
} ,
{
name : "should use default values if time selection is enabled but the time range is empty" ,
dashboard : & dashboards . Dashboard { Data : defaultDashboardData } ,
pubdash : & PublicDashboard { TimeSelectionEnabled : true } ,
reqDTO : PublicDashboardQueryDTO {
TimeRange : TimeRangeDTO { } ,
} ,
want : TimeSettings {
From : defaultFromMs ,
To : defaultToMs ,
} ,
} ,
}
for _ , test := range testCases {
t . Run ( test . name , func ( t * testing . T ) {
assert . Equal ( t , test . want , buildTimeSettings ( test . dashboard , test . reqDTO , test . pubdash ) )
} )
}
}
2022-10-21 09:37:38 -03:00
func groupQueriesByDataSource ( t * testing . T , queries [ ] * simplejson . Json ) ( result [ ] [ ] * simplejson . Json ) {
t . Helper ( )
byDataSource := make ( map [ string ] [ ] * simplejson . Json )
for _ , query := range queries {
uid := getDataSourceUidFromJson ( query )
byDataSource [ uid ] = append ( byDataSource [ uid ] , query )
}
for _ , queries := range byDataSource {
result = append ( result , queries )
}
return
}
2023-06-14 17:35:01 -03:00
func getStartAndEndOfTheDayBefore ( fakeNow time . Time , timezoneName string ) ( time . Time , time . Time ) {
timezone , _ := time . LoadLocation ( timezoneName )
fakeNowWithTimezone := fakeNow . In ( timezone )
yy , mm , dd := fakeNowWithTimezone . Add ( - 24 * time . Hour ) . Date ( )
startOfYesterdaySydney := time . Date ( yy , mm , dd , 0 , 0 , 0 , 0 , timezone )
endOfYesterdaySydney := time . Date ( yy , mm , dd , 23 , 59 , 59 , 999999999 , timezone )
return startOfYesterdaySydney , endOfYesterdaySydney
}
func buildJsonDataWithTimeRange ( from , to , timezone string ) * simplejson . Json {
return simplejson . NewFromAny ( map [ string ] interface { } {
"time" : map [ string ] interface { } {
"from" : from , "to" : to ,
} ,
"timezone" : timezone ,
} )
}