2020-12-09 06:10:18 -06:00
package librarypanels
import (
2021-02-01 23:25:35 -06:00
"context"
2020-12-21 02:40:27 -06:00
"encoding/json"
2021-01-20 02:28:10 -06:00
"fmt"
2021-02-16 06:00:56 -06:00
"net/http"
2020-12-09 06:10:18 -06:00
"testing"
"time"
2020-12-23 05:42:52 -06:00
"github.com/google/go-cmp/cmp"
2020-12-09 06:10:18 -06:00
"github.com/stretchr/testify/require"
2020-12-23 05:42:52 -06:00
"gopkg.in/macaron.v1"
2020-12-09 06:10:18 -06:00
2021-02-24 07:06:22 -06:00
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/bus"
2021-02-01 23:25:35 -06:00
"github.com/grafana/grafana/pkg/components/simplejson"
2020-12-09 06:10:18 -06:00
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/registry"
2021-02-24 07:06:22 -06:00
"github.com/grafana/grafana/pkg/services/dashboards"
2020-12-09 06:10:18 -06:00
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/grafana/grafana/pkg/setting"
)
2021-03-01 08:33:17 -06:00
const UserInDbName = "user_in_db"
const UserInDbAvatar = "/avatar/402d08de060496d6b6874495fe20f5ad"
2020-12-23 05:42:52 -06:00
2021-01-20 02:28:10 -06:00
func TestLoadLibraryPanelsForDashboard ( t * testing . T ) {
2021-02-24 07:06:22 -06:00
scenarioWithLibraryPanel ( t , "When an admin tries to load a dashboard with a library panel, it should copy JSON properties from library panel" ,
2021-01-20 02:28:10 -06:00
func ( t * testing . T , sc scenarioContext ) {
2021-02-24 07:06:22 -06:00
sc . reqContext . ReplaceAllParams ( map [ string ] string { ":uid" : sc . initialResult . Result . UID , ":dashboardId" : "1" } )
resp := sc . service . connectHandler ( sc . reqContext )
require . Equal ( t , 200 , resp . Status ( ) )
2021-01-20 02:28:10 -06:00
dashJSON := map [ string ] interface { } {
"panels" : [ ] interface { } {
map [ string ] interface { } {
"id" : int64 ( 1 ) ,
"gridPos" : map [ string ] interface { } {
"h" : 6 ,
"w" : 6 ,
"x" : 0 ,
"y" : 0 ,
} ,
} ,
map [ string ] interface { } {
"id" : int64 ( 2 ) ,
"gridPos" : map [ string ] interface { } {
"h" : 6 ,
"w" : 6 ,
"x" : 6 ,
"y" : 0 ,
} ,
"libraryPanel" : map [ string ] interface { } {
2021-02-24 07:06:22 -06:00
"uid" : sc . initialResult . Result . UID ,
"name" : sc . initialResult . Result . Name ,
2021-01-20 02:28:10 -06:00
} ,
} ,
} ,
}
dash := models . Dashboard {
Id : 1 ,
Data : simplejson . NewFromAny ( dashJSON ) ,
}
2021-02-24 07:06:22 -06:00
err := sc . service . LoadLibraryPanelsForDashboard ( sc . reqContext , & dash )
2021-01-20 02:28:10 -06:00
require . NoError ( t , err )
expectedJSON := map [ string ] interface { } {
"panels" : [ ] interface { } {
map [ string ] interface { } {
"id" : int64 ( 1 ) ,
"gridPos" : map [ string ] interface { } {
"h" : 6 ,
"w" : 6 ,
"x" : 0 ,
"y" : 0 ,
} ,
} ,
map [ string ] interface { } {
"id" : int64 ( 2 ) ,
"gridPos" : map [ string ] interface { } {
"h" : 6 ,
"w" : 6 ,
"x" : 6 ,
"y" : 0 ,
} ,
"datasource" : "${DS_GDEV-TESTDATA}" ,
"libraryPanel" : map [ string ] interface { } {
2021-03-02 06:33:26 -06:00
"uid" : sc . initialResult . Result . UID ,
"name" : sc . initialResult . Result . Name ,
"version" : sc . initialResult . Result . Version ,
2021-02-01 23:25:35 -06:00
"meta" : map [ string ] interface { } {
"canEdit" : false ,
"connectedDashboards" : int64 ( 1 ) ,
2021-02-24 07:06:22 -06:00
"created" : sc . initialResult . Result . Meta . Created ,
"updated" : sc . initialResult . Result . Meta . Updated ,
2021-02-01 23:25:35 -06:00
"createdBy" : map [ string ] interface { } {
2021-02-24 07:06:22 -06:00
"id" : sc . initialResult . Result . Meta . CreatedBy . ID ,
2021-03-01 08:33:17 -06:00
"name" : UserInDbName ,
"avatarUrl" : UserInDbAvatar ,
2021-02-01 23:25:35 -06:00
} ,
"updatedBy" : map [ string ] interface { } {
2021-02-24 07:06:22 -06:00
"id" : sc . initialResult . Result . Meta . UpdatedBy . ID ,
2021-03-01 08:33:17 -06:00
"name" : UserInDbName ,
"avatarUrl" : UserInDbAvatar ,
2021-02-01 23:25:35 -06:00
} ,
} ,
2021-01-20 02:28:10 -06:00
} ,
2021-02-24 07:06:22 -06:00
"title" : "Text - Library Panel" ,
2021-01-20 02:28:10 -06:00
"type" : "text" ,
} ,
} ,
}
expected := simplejson . NewFromAny ( expectedJSON )
if diff := cmp . Diff ( expected . Interface ( ) , dash . Data . Interface ( ) , getCompareOptions ( ) ... ) ; diff != "" {
t . Fatalf ( "Result mismatch (-want +got):\n%s" , diff )
}
} )
2021-02-24 07:06:22 -06:00
scenarioWithLibraryPanel ( t , "When an admin tries to load a dashboard with a library panel without uid, it should fail" ,
2021-01-20 02:28:10 -06:00
func ( t * testing . T , sc scenarioContext ) {
2021-02-24 07:06:22 -06:00
sc . reqContext . ReplaceAllParams ( map [ string ] string { ":uid" : sc . initialResult . Result . UID , ":dashboardId" : "1" } )
resp := sc . service . connectHandler ( sc . reqContext )
require . Equal ( t , 200 , resp . Status ( ) )
2021-01-20 02:28:10 -06:00
dashJSON := map [ string ] interface { } {
"panels" : [ ] interface { } {
map [ string ] interface { } {
"id" : int64 ( 1 ) ,
"gridPos" : map [ string ] interface { } {
"h" : 6 ,
"w" : 6 ,
"x" : 0 ,
"y" : 0 ,
} ,
} ,
map [ string ] interface { } {
"id" : int64 ( 2 ) ,
"gridPos" : map [ string ] interface { } {
"h" : 6 ,
"w" : 6 ,
"x" : 6 ,
"y" : 0 ,
} ,
"libraryPanel" : map [ string ] interface { } {
2021-02-24 07:06:22 -06:00
"name" : sc . initialResult . Result . Name ,
2021-01-20 02:28:10 -06:00
} ,
} ,
} ,
}
dash := models . Dashboard {
Id : 1 ,
Data : simplejson . NewFromAny ( dashJSON ) ,
}
2021-02-24 07:06:22 -06:00
err := sc . service . LoadLibraryPanelsForDashboard ( sc . reqContext , & dash )
2021-01-20 02:28:10 -06:00
require . EqualError ( t , err , errLibraryPanelHeaderUIDMissing . Error ( ) )
} )
2021-02-24 07:06:22 -06:00
scenarioWithLibraryPanel ( t , "When an admin tries to load a dashboard with a library panel that is not connected, it should set correct JSON and continue" ,
2021-01-20 02:28:10 -06:00
func ( t * testing . T , sc scenarioContext ) {
dashJSON := map [ string ] interface { } {
"panels" : [ ] interface { } {
map [ string ] interface { } {
"id" : int64 ( 1 ) ,
"gridPos" : map [ string ] interface { } {
"h" : 6 ,
"w" : 6 ,
"x" : 0 ,
"y" : 0 ,
} ,
} ,
map [ string ] interface { } {
"id" : int64 ( 2 ) ,
"gridPos" : map [ string ] interface { } {
"h" : 6 ,
"w" : 6 ,
"x" : 6 ,
"y" : 0 ,
} ,
"libraryPanel" : map [ string ] interface { } {
2021-02-24 07:06:22 -06:00
"uid" : sc . initialResult . Result . UID ,
"name" : sc . initialResult . Result . Name ,
2021-01-20 02:28:10 -06:00
} ,
} ,
} ,
}
dash := models . Dashboard {
Id : 1 ,
Data : simplejson . NewFromAny ( dashJSON ) ,
}
2021-02-24 07:06:22 -06:00
err := sc . service . LoadLibraryPanelsForDashboard ( sc . reqContext , & dash )
2021-01-28 23:11:13 -06:00
require . NoError ( t , err )
expectedJSON := map [ string ] interface { } {
"panels" : [ ] interface { } {
map [ string ] interface { } {
"id" : int64 ( 1 ) ,
"gridPos" : map [ string ] interface { } {
"h" : 6 ,
"w" : 6 ,
"x" : 0 ,
"y" : 0 ,
} ,
} ,
map [ string ] interface { } {
"id" : int64 ( 2 ) ,
"gridPos" : map [ string ] interface { } {
"h" : 6 ,
"w" : 6 ,
"x" : 6 ,
"y" : 0 ,
} ,
"libraryPanel" : map [ string ] interface { } {
2021-02-24 07:06:22 -06:00
"uid" : sc . initialResult . Result . UID ,
"name" : sc . initialResult . Result . Name ,
2021-01-28 23:11:13 -06:00
} ,
2021-02-24 07:06:22 -06:00
"type" : fmt . Sprintf ( "Name: \"%s\", UID: \"%s\"" , sc . initialResult . Result . Name , sc . initialResult . Result . UID ) ,
2021-01-28 23:11:13 -06:00
} ,
} ,
}
expected := simplejson . NewFromAny ( expectedJSON )
if diff := cmp . Diff ( expected . Interface ( ) , dash . Data . Interface ( ) , getCompareOptions ( ) ... ) ; diff != "" {
t . Fatalf ( "Result mismatch (-want +got):\n%s" , diff )
}
2021-01-20 02:28:10 -06:00
} )
}
func TestCleanLibraryPanelsForDashboard ( t * testing . T ) {
2021-02-24 07:06:22 -06:00
scenarioWithLibraryPanel ( t , "When an admin tries to store a dashboard with a library panel, it should just keep the correct JSON properties in library panel" ,
2021-01-20 02:28:10 -06:00
func ( t * testing . T , sc scenarioContext ) {
dashJSON := map [ string ] interface { } {
"panels" : [ ] interface { } {
map [ string ] interface { } {
"id" : int64 ( 1 ) ,
"gridPos" : map [ string ] interface { } {
"h" : 6 ,
"w" : 6 ,
"x" : 0 ,
"y" : 0 ,
} ,
} ,
map [ string ] interface { } {
"id" : int64 ( 2 ) ,
"gridPos" : map [ string ] interface { } {
"h" : 6 ,
"w" : 6 ,
"x" : 6 ,
"y" : 0 ,
} ,
"datasource" : "${DS_GDEV-TESTDATA}" ,
"libraryPanel" : map [ string ] interface { } {
2021-02-24 07:06:22 -06:00
"uid" : sc . initialResult . Result . UID ,
"name" : sc . initialResult . Result . Name ,
2021-01-20 02:28:10 -06:00
} ,
"title" : "Text - Library Panel" ,
"type" : "text" ,
} ,
} ,
}
dash := models . Dashboard {
Id : 1 ,
Data : simplejson . NewFromAny ( dashJSON ) ,
}
2021-02-24 07:06:22 -06:00
err := sc . service . CleanLibraryPanelsForDashboard ( & dash )
2021-01-20 02:28:10 -06:00
require . NoError ( t , err )
expectedJSON := map [ string ] interface { } {
"panels" : [ ] interface { } {
map [ string ] interface { } {
"id" : int64 ( 1 ) ,
"gridPos" : map [ string ] interface { } {
"h" : 6 ,
"w" : 6 ,
"x" : 0 ,
"y" : 0 ,
} ,
} ,
map [ string ] interface { } {
"id" : int64 ( 2 ) ,
"gridPos" : map [ string ] interface { } {
"h" : 6 ,
"w" : 6 ,
"x" : 6 ,
"y" : 0 ,
} ,
"libraryPanel" : map [ string ] interface { } {
2021-02-24 07:06:22 -06:00
"uid" : sc . initialResult . Result . UID ,
"name" : sc . initialResult . Result . Name ,
2021-01-20 02:28:10 -06:00
} ,
} ,
} ,
}
expected := simplejson . NewFromAny ( expectedJSON )
if diff := cmp . Diff ( expected . Interface ( ) , dash . Data . Interface ( ) , getCompareOptions ( ) ... ) ; diff != "" {
t . Fatalf ( "Result mismatch (-want +got):\n%s" , diff )
}
} )
2021-02-24 07:06:22 -06:00
scenarioWithLibraryPanel ( t , "When an admin tries to store a dashboard with a library panel without uid, it should fail" ,
2021-01-20 02:28:10 -06:00
func ( t * testing . T , sc scenarioContext ) {
dashJSON := map [ string ] interface { } {
"panels" : [ ] interface { } {
map [ string ] interface { } {
"id" : int64 ( 1 ) ,
"gridPos" : map [ string ] interface { } {
"h" : 6 ,
"w" : 6 ,
"x" : 0 ,
"y" : 0 ,
} ,
} ,
map [ string ] interface { } {
"id" : int64 ( 2 ) ,
"gridPos" : map [ string ] interface { } {
"h" : 6 ,
"w" : 6 ,
"x" : 6 ,
"y" : 0 ,
} ,
"datasource" : "${DS_GDEV-TESTDATA}" ,
"libraryPanel" : map [ string ] interface { } {
2021-02-24 07:06:22 -06:00
"name" : sc . initialResult . Result . Name ,
2021-01-20 02:28:10 -06:00
} ,
"title" : "Text - Library Panel" ,
"type" : "text" ,
} ,
} ,
}
dash := models . Dashboard {
Id : 1 ,
Data : simplejson . NewFromAny ( dashJSON ) ,
}
2021-02-24 07:06:22 -06:00
err := sc . service . CleanLibraryPanelsForDashboard ( & dash )
2021-01-20 02:28:10 -06:00
require . EqualError ( t , err , errLibraryPanelHeaderUIDMissing . Error ( ) )
} )
2021-02-24 07:06:22 -06:00
scenarioWithLibraryPanel ( t , "When an admin tries to store a dashboard with a library panel without name, it should fail" ,
2021-01-20 02:28:10 -06:00
func ( t * testing . T , sc scenarioContext ) {
dashJSON := map [ string ] interface { } {
"panels" : [ ] interface { } {
map [ string ] interface { } {
"id" : int64 ( 1 ) ,
"gridPos" : map [ string ] interface { } {
"h" : 6 ,
"w" : 6 ,
"x" : 0 ,
"y" : 0 ,
} ,
} ,
map [ string ] interface { } {
"id" : int64 ( 2 ) ,
"gridPos" : map [ string ] interface { } {
"h" : 6 ,
"w" : 6 ,
"x" : 6 ,
"y" : 0 ,
} ,
"datasource" : "${DS_GDEV-TESTDATA}" ,
"libraryPanel" : map [ string ] interface { } {
2021-02-24 07:06:22 -06:00
"uid" : sc . initialResult . Result . UID ,
2021-01-20 02:28:10 -06:00
} ,
"title" : "Text - Library Panel" ,
"type" : "text" ,
} ,
} ,
}
dash := models . Dashboard {
Id : 1 ,
Data : simplejson . NewFromAny ( dashJSON ) ,
}
2021-02-24 07:06:22 -06:00
err := sc . service . CleanLibraryPanelsForDashboard ( & dash )
2021-01-20 02:28:10 -06:00
require . EqualError ( t , err , errLibraryPanelHeaderNameMissing . Error ( ) )
} )
}
func TestConnectLibraryPanelsForDashboard ( t * testing . T ) {
2021-02-24 07:06:22 -06:00
scenarioWithLibraryPanel ( t , "When an admin tries to store a dashboard with a library panel, it should connect the two" ,
2021-01-20 02:28:10 -06:00
func ( t * testing . T , sc scenarioContext ) {
dashJSON := map [ string ] interface { } {
"panels" : [ ] interface { } {
map [ string ] interface { } {
"id" : int64 ( 1 ) ,
"gridPos" : map [ string ] interface { } {
"h" : 6 ,
"w" : 6 ,
"x" : 0 ,
"y" : 0 ,
} ,
} ,
map [ string ] interface { } {
"id" : int64 ( 2 ) ,
"gridPos" : map [ string ] interface { } {
"h" : 6 ,
"w" : 6 ,
"x" : 6 ,
"y" : 0 ,
} ,
"datasource" : "${DS_GDEV-TESTDATA}" ,
"libraryPanel" : map [ string ] interface { } {
2021-02-24 07:06:22 -06:00
"uid" : sc . initialResult . Result . UID ,
"name" : sc . initialResult . Result . Name ,
2021-01-20 02:28:10 -06:00
} ,
"title" : "Text - Library Panel" ,
"type" : "text" ,
} ,
} ,
}
dash := models . Dashboard {
Id : int64 ( 1 ) ,
Data : simplejson . NewFromAny ( dashJSON ) ,
}
2021-02-24 07:06:22 -06:00
err := sc . service . ConnectLibraryPanelsForDashboard ( sc . reqContext , & dash )
2021-01-20 02:28:10 -06:00
require . NoError ( t , err )
2021-02-24 07:06:22 -06:00
sc . reqContext . ReplaceAllParams ( map [ string ] string { ":uid" : sc . initialResult . Result . UID } )
resp := sc . service . getConnectedDashboardsHandler ( sc . reqContext )
require . Equal ( t , 200 , resp . Status ( ) )
2021-01-20 02:28:10 -06:00
var dashResult libraryPanelDashboardsResult
2021-02-24 07:06:22 -06:00
err = json . Unmarshal ( resp . Body ( ) , & dashResult )
2021-01-20 02:28:10 -06:00
require . NoError ( t , err )
require . Len ( t , dashResult . Result , 1 )
require . Equal ( t , int64 ( 1 ) , dashResult . Result [ 0 ] )
} )
2021-02-24 07:06:22 -06:00
scenarioWithLibraryPanel ( t , "When an admin tries to store a dashboard with a library panel without uid, it should fail" ,
2021-01-20 02:28:10 -06:00
func ( t * testing . T , sc scenarioContext ) {
dashJSON := map [ string ] interface { } {
"panels" : [ ] interface { } {
map [ string ] interface { } {
"id" : int64 ( 1 ) ,
"gridPos" : map [ string ] interface { } {
"h" : 6 ,
"w" : 6 ,
"x" : 0 ,
"y" : 0 ,
} ,
} ,
map [ string ] interface { } {
"id" : int64 ( 2 ) ,
"gridPos" : map [ string ] interface { } {
"h" : 6 ,
"w" : 6 ,
"x" : 6 ,
"y" : 0 ,
} ,
"datasource" : "${DS_GDEV-TESTDATA}" ,
"libraryPanel" : map [ string ] interface { } {
2021-02-24 07:06:22 -06:00
"name" : sc . initialResult . Result . Name ,
2021-01-20 02:28:10 -06:00
} ,
"title" : "Text - Library Panel" ,
"type" : "text" ,
} ,
} ,
}
dash := models . Dashboard {
Id : int64 ( 1 ) ,
Data : simplejson . NewFromAny ( dashJSON ) ,
}
2021-02-24 07:06:22 -06:00
err := sc . service . ConnectLibraryPanelsForDashboard ( sc . reqContext , & dash )
2021-01-20 02:28:10 -06:00
require . EqualError ( t , err , errLibraryPanelHeaderUIDMissing . Error ( ) )
} )
2021-02-16 06:00:56 -06:00
2021-02-24 07:06:22 -06:00
scenarioWithLibraryPanel ( t , "When an admin tries to store a dashboard with unused/removed library panels, it should disconnect unused/removed library panels" ,
2021-02-16 06:00:56 -06:00
func ( t * testing . T , sc scenarioContext ) {
2021-02-24 07:06:22 -06:00
command := getCreateCommand ( sc . folder . Id , "Unused Libray Panel" )
resp := sc . service . createHandler ( sc . reqContext , command )
var unused = validateAndUnMarshalResponse ( t , resp )
2021-02-16 06:00:56 -06:00
sc . reqContext . ReplaceAllParams ( map [ string ] string { ":uid" : unused . Result . UID , ":dashboardId" : "1" } )
2021-02-24 07:06:22 -06:00
resp = sc . service . connectHandler ( sc . reqContext )
require . Equal ( t , 200 , resp . Status ( ) )
2021-02-16 06:00:56 -06:00
dashJSON := map [ string ] interface { } {
"panels" : [ ] interface { } {
map [ string ] interface { } {
"id" : int64 ( 1 ) ,
"gridPos" : map [ string ] interface { } {
"h" : 6 ,
"w" : 6 ,
"x" : 0 ,
"y" : 0 ,
} ,
} ,
map [ string ] interface { } {
"id" : int64 ( 2 ) ,
"gridPos" : map [ string ] interface { } {
"h" : 6 ,
"w" : 6 ,
"x" : 6 ,
"y" : 0 ,
} ,
"datasource" : "${DS_GDEV-TESTDATA}" ,
"libraryPanel" : map [ string ] interface { } {
2021-02-24 07:06:22 -06:00
"uid" : sc . initialResult . Result . UID ,
"name" : sc . initialResult . Result . Name ,
2021-02-16 06:00:56 -06:00
} ,
"title" : "Text - Library Panel" ,
"type" : "text" ,
} ,
} ,
}
dash := models . Dashboard {
Id : int64 ( 1 ) ,
Data : simplejson . NewFromAny ( dashJSON ) ,
}
2021-02-24 07:06:22 -06:00
err := sc . service . ConnectLibraryPanelsForDashboard ( sc . reqContext , & dash )
2021-02-16 06:00:56 -06:00
require . NoError ( t , err )
2021-02-24 07:06:22 -06:00
sc . reqContext . ReplaceAllParams ( map [ string ] string { ":uid" : sc . initialResult . Result . UID } )
resp = sc . service . getConnectedDashboardsHandler ( sc . reqContext )
require . Equal ( t , 200 , resp . Status ( ) )
2021-02-16 06:00:56 -06:00
var existingResult libraryPanelDashboardsResult
2021-02-24 07:06:22 -06:00
err = json . Unmarshal ( resp . Body ( ) , & existingResult )
2021-02-16 06:00:56 -06:00
require . NoError ( t , err )
require . Len ( t , existingResult . Result , 1 )
require . Equal ( t , int64 ( 1 ) , existingResult . Result [ 0 ] )
sc . reqContext . ReplaceAllParams ( map [ string ] string { ":uid" : unused . Result . UID } )
2021-02-24 07:06:22 -06:00
resp = sc . service . getConnectedDashboardsHandler ( sc . reqContext )
require . Equal ( t , 200 , resp . Status ( ) )
2021-02-16 06:00:56 -06:00
var unusedResult libraryPanelDashboardsResult
2021-02-24 07:06:22 -06:00
err = json . Unmarshal ( resp . Body ( ) , & unusedResult )
2021-02-16 06:00:56 -06:00
require . NoError ( t , err )
require . Len ( t , unusedResult . Result , 0 )
} )
2021-01-20 02:28:10 -06:00
}
func TestDisconnectLibraryPanelsForDashboard ( t * testing . T ) {
2021-02-24 07:06:22 -06:00
scenarioWithLibraryPanel ( t , "When an admin tries to delete a dashboard with a library panel, it should disconnect the two" ,
2021-01-20 02:28:10 -06:00
func ( t * testing . T , sc scenarioContext ) {
2021-02-24 07:06:22 -06:00
sc . reqContext . ReplaceAllParams ( map [ string ] string { ":uid" : sc . initialResult . Result . UID , ":dashboardId" : "1" } )
resp := sc . service . connectHandler ( sc . reqContext )
require . Equal ( t , 200 , resp . Status ( ) )
2021-01-20 02:28:10 -06:00
dashJSON := map [ string ] interface { } {
"panels" : [ ] interface { } {
map [ string ] interface { } {
"id" : int64 ( 1 ) ,
"gridPos" : map [ string ] interface { } {
"h" : 6 ,
"w" : 6 ,
"x" : 0 ,
"y" : 0 ,
} ,
} ,
map [ string ] interface { } {
"id" : int64 ( 2 ) ,
"gridPos" : map [ string ] interface { } {
"h" : 6 ,
"w" : 6 ,
"x" : 6 ,
"y" : 0 ,
} ,
"datasource" : "${DS_GDEV-TESTDATA}" ,
"libraryPanel" : map [ string ] interface { } {
2021-02-24 07:06:22 -06:00
"uid" : sc . initialResult . Result . UID ,
"name" : sc . initialResult . Result . Name ,
2021-01-20 02:28:10 -06:00
} ,
"title" : "Text - Library Panel" ,
"type" : "text" ,
} ,
} ,
}
dash := models . Dashboard {
Id : int64 ( 1 ) ,
Data : simplejson . NewFromAny ( dashJSON ) ,
}
2021-02-24 07:06:22 -06:00
err := sc . service . DisconnectLibraryPanelsForDashboard ( sc . reqContext , & dash )
2021-01-20 02:28:10 -06:00
require . NoError ( t , err )
2021-02-24 07:06:22 -06:00
sc . reqContext . ReplaceAllParams ( map [ string ] string { ":uid" : sc . initialResult . Result . UID } )
resp = sc . service . getConnectedDashboardsHandler ( sc . reqContext )
require . Equal ( t , 200 , resp . Status ( ) )
2021-01-20 02:28:10 -06:00
var dashResult libraryPanelDashboardsResult
2021-02-24 07:06:22 -06:00
err = json . Unmarshal ( resp . Body ( ) , & dashResult )
2021-01-20 02:28:10 -06:00
require . NoError ( t , err )
require . Empty ( t , dashResult . Result )
} )
2021-02-24 07:06:22 -06:00
scenarioWithLibraryPanel ( t , "When an admin tries to delete a dashboard with a library panel without uid, it should fail" ,
2021-01-20 02:28:10 -06:00
func ( t * testing . T , sc scenarioContext ) {
2021-02-24 07:06:22 -06:00
sc . reqContext . ReplaceAllParams ( map [ string ] string { ":uid" : sc . initialResult . Result . UID , ":dashboardId" : "1" } )
resp := sc . service . connectHandler ( sc . reqContext )
require . Equal ( t , 200 , resp . Status ( ) )
2021-01-20 02:28:10 -06:00
dashJSON := map [ string ] interface { } {
"panels" : [ ] interface { } {
map [ string ] interface { } {
"id" : int64 ( 1 ) ,
"gridPos" : map [ string ] interface { } {
"h" : 6 ,
"w" : 6 ,
"x" : 0 ,
"y" : 0 ,
} ,
} ,
map [ string ] interface { } {
"id" : int64 ( 2 ) ,
"gridPos" : map [ string ] interface { } {
"h" : 6 ,
"w" : 6 ,
"x" : 6 ,
"y" : 0 ,
} ,
"datasource" : "${DS_GDEV-TESTDATA}" ,
"libraryPanel" : map [ string ] interface { } {
2021-02-24 07:06:22 -06:00
"name" : sc . initialResult . Result . Name ,
2021-01-20 02:28:10 -06:00
} ,
"title" : "Text - Library Panel" ,
"type" : "text" ,
} ,
} ,
}
dash := models . Dashboard {
Id : int64 ( 1 ) ,
Data : simplejson . NewFromAny ( dashJSON ) ,
}
2021-02-24 07:06:22 -06:00
err := sc . service . DisconnectLibraryPanelsForDashboard ( sc . reqContext , & dash )
2021-01-20 02:28:10 -06:00
require . EqualError ( t , err , errLibraryPanelHeaderUIDMissing . Error ( ) )
} )
}
2021-03-02 03:34:01 -06:00
func TestDeleteLibraryPanelsInFolder ( t * testing . T ) {
scenarioWithLibraryPanel ( t , "When an admin tries to delete a folder that contains connected library panels, it should fail" ,
func ( t * testing . T , sc scenarioContext ) {
sc . reqContext . ReplaceAllParams ( map [ string ] string { ":uid" : sc . initialResult . Result . UID , ":dashboardId" : "1" } )
resp := sc . service . connectHandler ( sc . reqContext )
require . Equal ( t , 200 , resp . Status ( ) )
err := sc . service . DeleteLibraryPanelsInFolder ( sc . reqContext , sc . folder . Uid )
require . EqualError ( t , err , ErrFolderHasConnectedLibraryPanels . Error ( ) )
} )
scenarioWithLibraryPanel ( t , "When an admin tries to delete a folder that contains disconnected library panels, it should delete all disconnected library panels too" ,
func ( t * testing . T , sc scenarioContext ) {
resp := sc . service . getAllHandler ( sc . reqContext )
require . Equal ( t , 200 , resp . Status ( ) )
var result libraryPanelsResult
err := json . Unmarshal ( resp . Body ( ) , & result )
require . NoError ( t , err )
require . NotNil ( t , result . Result )
require . Equal ( t , 1 , len ( result . Result ) )
err = sc . service . DeleteLibraryPanelsInFolder ( sc . reqContext , sc . folder . Uid )
require . NoError ( t , err )
resp = sc . service . getAllHandler ( sc . reqContext )
require . Equal ( t , 200 , resp . Status ( ) )
err = json . Unmarshal ( resp . Body ( ) , & result )
require . NoError ( t , err )
require . NotNil ( t , result . Result )
require . Equal ( t , 0 , len ( result . Result ) )
} )
}
2020-12-21 02:40:27 -06:00
type libraryPanel struct {
2021-01-28 05:36:28 -06:00
ID int64 ` json:"id" `
OrgID int64 ` json:"orgId" `
FolderID int64 ` json:"folderId" `
UID string ` json:"uid" `
Name string ` json:"name" `
Model map [ string ] interface { } ` json:"model" `
2021-03-02 06:33:26 -06:00
Version int64 ` json:"version" `
2021-01-28 05:36:28 -06:00
Meta LibraryPanelDTOMeta ` json:"meta" `
2020-12-21 02:40:27 -06:00
}
2020-12-10 23:08:32 -06:00
2020-12-21 02:40:27 -06:00
type libraryPanelResult struct {
Result libraryPanel ` json:"result" `
}
2020-12-10 23:08:32 -06:00
2020-12-21 02:40:27 -06:00
type libraryPanelsResult struct {
Result [ ] libraryPanel ` json:"result" `
2020-12-10 23:08:32 -06:00
}
2021-01-12 05:57:40 -06:00
type libraryPanelDashboardsResult struct {
Result [ ] int64 ` json:"result" `
}
2020-12-10 23:08:32 -06:00
func overrideLibraryPanelServiceInRegistry ( cfg * setting . Cfg ) LibraryPanelService {
2020-12-09 06:10:18 -06:00
lps := LibraryPanelService {
SQLStore : nil ,
Cfg : cfg ,
}
overrideServiceFunc := func ( d registry . Descriptor ) ( * registry . Descriptor , bool ) {
descriptor := registry . Descriptor {
Name : "LibraryPanelService" ,
Instance : & lps ,
InitPriority : 0 ,
}
return & descriptor , true
}
registry . RegisterOverride ( overrideServiceFunc )
return lps
}
2020-12-22 05:00:41 -06:00
func getCreateCommand ( folderID int64 , name string ) createLibraryPanelCommand {
2020-12-21 02:40:27 -06:00
command := createLibraryPanelCommand {
2020-12-10 23:08:32 -06:00
FolderID : folderID ,
2020-12-22 05:00:41 -06:00
Name : name ,
2020-12-10 23:08:32 -06:00
Model : [ ] byte ( `
{
"datasource" : "${DS_GDEV-TESTDATA}" ,
"id" : 1 ,
2021-01-20 02:28:10 -06:00
"title" : "Text - Library Panel" ,
2020-12-10 23:08:32 -06:00
"type" : "text"
}
` ) ,
2020-12-09 06:10:18 -06:00
}
2020-12-10 23:08:32 -06:00
return command
2020-12-09 06:10:18 -06:00
}
2020-12-21 02:40:27 -06:00
type scenarioContext struct {
2021-02-24 07:06:22 -06:00
ctx * macaron . Context
service * LibraryPanelService
reqContext * models . ReqContext
user models . SignedInUser
folder * models . Folder
initialResult libraryPanelResult
}
2021-03-01 08:33:17 -06:00
type folderACLItem struct {
roleType models . RoleType
permission models . PermissionType
}
func createDashboard ( t * testing . T , user models . SignedInUser , title string , folderID int64 ) * models . Dashboard {
dash := models . NewDashboard ( title )
dash . FolderId = folderID
dashItem := & dashboards . SaveDashboardDTO {
Dashboard : dash ,
Message : "" ,
OrgId : user . OrgId ,
User : & user ,
Overwrite : false ,
}
bus . AddHandler ( "test" , func ( cmd * models . ValidateDashboardAlertsCommand ) error {
return nil
} )
bus . AddHandler ( "test" , func ( cmd * models . ValidateDashboardBeforeSaveCommand ) error {
cmd . Result = & models . ValidateDashboardBeforeSaveResult { }
return nil
} )
bus . AddHandler ( "test" , func ( cmd * models . GetProvisionedDashboardDataByIdQuery ) error {
cmd . Result = nil
return nil
} )
bus . AddHandler ( "test" , func ( cmd * models . UpdateDashboardAlertsCommand ) error {
return nil
} )
2021-03-12 04:51:02 -06:00
dashboard , err := dashboards . NewService ( ) . SaveDashboard ( dashItem , true )
2021-02-24 07:06:22 -06:00
require . NoError ( t , err )
2021-03-01 08:33:17 -06:00
return dashboard
}
func createFolderWithACL ( t * testing . T , title string , user models . SignedInUser , items [ ] folderACLItem ) * models . Folder {
s := dashboards . NewFolderService ( user . OrgId , & user )
folderCmd := models . CreateFolderCommand {
Uid : title ,
Title : title ,
}
err := s . CreateFolder ( & folderCmd )
require . NoError ( t , err )
updateFolderACL ( t , folderCmd . Result . Id , items )
return folderCmd . Result
2021-02-24 07:06:22 -06:00
}
2021-03-01 08:33:17 -06:00
func updateFolderACL ( t * testing . T , folderID int64 , items [ ] folderACLItem ) {
if len ( items ) == 0 {
return
}
2021-02-24 07:06:22 -06:00
cmd := models . UpdateDashboardAclCommand {
2021-03-01 08:33:17 -06:00
DashboardID : folderID ,
2021-02-24 07:06:22 -06:00
}
2021-03-01 08:33:17 -06:00
for _ , item := range items {
role := item . roleType
permission := item . permission
cmd . Items = append ( cmd . Items , & models . DashboardAcl {
DashboardID : folderID ,
Role : & role ,
Permission : permission ,
Created : time . Now ( ) ,
Updated : time . Now ( ) ,
} )
}
2021-02-24 07:06:22 -06:00
err := bus . Dispatch ( & cmd )
require . NoError ( t , err )
}
func validateAndUnMarshalResponse ( t * testing . T , resp response . Response ) libraryPanelResult {
require . Equal ( t , 200 , resp . Status ( ) )
var result = libraryPanelResult { }
err := json . Unmarshal ( resp . Body ( ) , & result )
require . NoError ( t , err )
return result
}
func scenarioWithLibraryPanel ( t * testing . T , desc string , fn func ( t * testing . T , sc scenarioContext ) ) {
testScenario ( t , desc , func ( t * testing . T , sc scenarioContext ) {
command := getCreateCommand ( sc . folder . Id , "Text - Library Panel" )
resp := sc . service . createHandler ( sc . reqContext , command )
sc . initialResult = validateAndUnMarshalResponse ( t , resp )
fn ( t , sc )
} )
2020-12-21 02:40:27 -06:00
}
// testScenario is a wrapper around t.Run performing common setup for library panel tests.
// It takes your real test function as a callback.
2020-12-22 05:00:41 -06:00
func testScenario ( t * testing . T , desc string , fn func ( t * testing . T , sc scenarioContext ) ) {
2020-12-21 02:40:27 -06:00
t . Helper ( )
t . Run ( desc , func ( t * testing . T ) {
t . Cleanup ( registry . ClearOverrides )
2021-02-16 06:00:56 -06:00
ctx := macaron . Context {
Req : macaron . Request { Request : & http . Request { } } ,
}
2020-12-21 02:40:27 -06:00
orgID := int64 ( 1 )
role := models . ROLE_ADMIN
cfg := setting . NewCfg ( )
// Everything in this service is behind the feature toggle "panelLibrary"
cfg . FeatureToggles = map [ string ] bool { "panelLibrary" : true }
// Because the LibraryPanelService is behind a feature toggle, we need to override the service in the registry
// with a Cfg that contains the feature toggle so migrations are run properly
service := overrideLibraryPanelServiceInRegistry ( cfg )
// We need to assign SQLStore after the override and migrations are done
sqlStore := sqlstore . InitTestDB ( t )
service . SQLStore = sqlStore
user := models . SignedInUser {
UserId : 1 ,
2021-02-01 23:25:35 -06:00
Name : "Signed In User" ,
Login : "signed_in_user" ,
Email : "signed.in.user@test.com" ,
2020-12-21 02:40:27 -06:00
OrgId : orgID ,
OrgRole : role ,
LastSeenAt : time . Now ( ) ,
}
2021-02-24 07:06:22 -06:00
2021-02-01 23:25:35 -06:00
// deliberate difference between signed in user and user in db to make it crystal clear
// what to expect in the tests
// In the real world these are identical
cmd := & models . CreateUserCommand {
Email : "user.in.db@test.com" ,
Name : "User In DB" ,
2021-03-01 08:33:17 -06:00
Login : UserInDbName ,
2021-02-01 23:25:35 -06:00
}
err := sqlstore . CreateUser ( context . Background ( ) , cmd )
require . NoError ( t , err )
2020-12-21 02:40:27 -06:00
sc := scenarioContext {
user : user ,
ctx : & ctx ,
service : & service ,
reqContext : & models . ReqContext {
Context : & ctx ,
SignedInUser : & user ,
} ,
}
2021-02-24 07:06:22 -06:00
2021-03-01 08:33:17 -06:00
sc . folder = createFolderWithACL ( t , "ScenarioFolder" , sc . user , [ ] folderACLItem { } )
2021-02-24 07:06:22 -06:00
2020-12-21 02:40:27 -06:00
fn ( t , sc )
} )
}
2020-12-23 05:42:52 -06:00
func getCompareOptions ( ) [ ] cmp . Option {
return [ ] cmp . Option {
cmp . Transformer ( "Time" , func ( in time . Time ) int64 {
return in . UTC ( ) . Unix ( )
} ) ,
}
}