2017-06-12 15:48:55 +02:00
package api
import (
2021-06-15 16:08:27 +02:00
"context"
2017-06-12 15:48:55 +02:00
"encoding/json"
2018-02-19 11:12:56 +01:00
"fmt"
2021-07-16 12:40:03 +02:00
"net/http"
2022-08-10 13:37:51 +00:00
"os"
2017-06-12 15:48:55 +02:00
"testing"
2023-03-30 17:31:53 +03:00
"time"
2017-06-12 15:48:55 +02:00
2022-03-10 12:19:50 -05:00
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
2017-06-12 15:48:55 +02:00
"github.com/grafana/grafana/pkg/api/dtos"
2021-01-15 14:43:20 +01:00
"github.com/grafana/grafana/pkg/api/response"
"github.com/grafana/grafana/pkg/api/routing"
2024-06-13 07:11:35 +03:00
"github.com/grafana/grafana/pkg/apimachinery/identity"
2023-01-26 10:21:10 +02:00
"github.com/grafana/grafana/pkg/bus"
2017-06-12 23:05:32 +02:00
"github.com/grafana/grafana/pkg/components/simplejson"
2022-10-19 09:02:15 -04:00
"github.com/grafana/grafana/pkg/infra/db"
2023-01-17 14:17:54 +01:00
"github.com/grafana/grafana/pkg/infra/db/dbtest"
2023-03-30 17:31:53 +03:00
"github.com/grafana/grafana/pkg/infra/localcache"
"github.com/grafana/grafana/pkg/infra/log"
2023-01-26 10:21:10 +02:00
"github.com/grafana/grafana/pkg/infra/tracing"
2021-09-22 16:28:40 +02:00
"github.com/grafana/grafana/pkg/infra/usagestats"
2023-08-29 15:09:09 +02:00
"github.com/grafana/grafana/pkg/services/accesscontrol"
2023-01-23 10:54:29 +01:00
"github.com/grafana/grafana/pkg/services/accesscontrol/acimpl"
2022-11-24 14:38:55 +00:00
"github.com/grafana/grafana/pkg/services/accesscontrol/actest"
2022-03-10 12:58:18 +01:00
accesscontrolmock "github.com/grafana/grafana/pkg/services/accesscontrol/mock"
2022-09-19 10:54:37 +03:00
"github.com/grafana/grafana/pkg/services/annotations/annotationstest"
2024-07-05 11:31:23 +02:00
"github.com/grafana/grafana/pkg/services/authz/zanzana"
2023-01-27 08:50:36 +01:00
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model"
2017-12-12 16:15:24 +01:00
"github.com/grafana/grafana/pkg/services/dashboards"
2022-02-16 14:15:44 +01:00
"github.com/grafana/grafana/pkg/services/dashboards/database"
2022-05-21 20:44:12 -04:00
"github.com/grafana/grafana/pkg/services/dashboards/service"
2022-05-25 10:41:51 +02:00
dashver "github.com/grafana/grafana/pkg/services/dashboardversion"
"github.com/grafana/grafana/pkg/services/dashboardversion/dashvertest"
2022-01-26 09:44:20 -08:00
"github.com/grafana/grafana/pkg/services/featuremgmt"
2022-10-10 21:47:53 +02:00
"github.com/grafana/grafana/pkg/services/folder"
2023-01-26 10:21:10 +02:00
"github.com/grafana/grafana/pkg/services/folder/folderimpl"
2022-11-11 14:28:24 +01:00
"github.com/grafana/grafana/pkg/services/folder/foldertest"
2022-03-21 10:49:49 +01:00
"github.com/grafana/grafana/pkg/services/guardian"
2024-09-27 14:22:29 +02:00
libraryelementsfake "github.com/grafana/grafana/pkg/services/libraryelements/fake"
2023-09-06 11:16:10 +02:00
"github.com/grafana/grafana/pkg/services/librarypanels"
2024-02-22 09:34:14 +01:00
"github.com/grafana/grafana/pkg/services/licensing/licensingtest"
2020-10-28 08:36:57 +00:00
"github.com/grafana/grafana/pkg/services/live"
2022-08-10 11:56:48 +02:00
"github.com/grafana/grafana/pkg/services/org"
2023-09-11 13:59:24 +02:00
"github.com/grafana/grafana/pkg/services/pluginsintegration/pluginstore"
2022-04-21 15:03:17 +02:00
pref "github.com/grafana/grafana/pkg/services/preference"
"github.com/grafana/grafana/pkg/services/preference/preftest"
2019-04-30 13:32:18 +02:00
"github.com/grafana/grafana/pkg/services/provisioning"
2023-07-17 12:21:44 +02:00
"github.com/grafana/grafana/pkg/services/publicdashboards"
"github.com/grafana/grafana/pkg/services/publicdashboards/api"
2024-02-22 09:34:14 +01:00
publicdashboardModels "github.com/grafana/grafana/pkg/services/publicdashboards/models"
2022-11-14 21:08:10 +02:00
"github.com/grafana/grafana/pkg/services/quota/quotatest"
2023-08-09 08:54:52 +02:00
"github.com/grafana/grafana/pkg/services/star/startest"
2024-02-26 11:27:22 +01:00
"github.com/grafana/grafana/pkg/services/supportbundles/supportbundlestest"
2022-09-21 14:04:01 +02:00
"github.com/grafana/grafana/pkg/services/tag/tagimpl"
2022-08-10 11:56:48 +02:00
"github.com/grafana/grafana/pkg/services/user"
2023-07-17 12:21:44 +02:00
"github.com/grafana/grafana/pkg/services/user/usertest"
2017-12-15 14:19:49 +01:00
"github.com/grafana/grafana/pkg/setting"
2021-10-11 14:30:59 +02:00
"github.com/grafana/grafana/pkg/web"
2023-08-29 15:09:09 +02:00
"github.com/grafana/grafana/pkg/web/webtest"
2017-06-12 15:48:55 +02:00
)
2020-06-22 18:00:39 +02:00
func TestGetHomeDashboard ( t * testing . T ) {
2021-07-16 12:40:03 +02:00
httpReq , err := http . NewRequest ( http . MethodGet , "" , nil )
require . NoError ( t , err )
2022-02-09 13:44:38 +01:00
httpReq . Header . Add ( "Content-Type" , "application/json" )
2023-01-27 08:50:36 +01:00
req := & contextmodel . ReqContext { SignedInUser : & user . SignedInUser {}, Context : & web . Context { Req : httpReq }}
2020-06-22 18:00:39 +02:00
cfg := setting . NewCfg ()
cfg . StaticRootPath = "../../public/"
2022-04-21 15:03:17 +02:00
prefService := preftest . NewPreferenceServiceFake ()
2022-05-25 10:41:51 +02:00
dashboardVersionService := dashvertest . NewDashboardVersionServiceFake ()
2020-06-22 18:00:39 +02:00
2021-03-17 16:06:10 +01:00
hs := & HTTPServer {
2022-05-25 10:41:51 +02:00
Cfg : cfg ,
2023-09-11 13:59:24 +02:00
pluginStore : & pluginstore . FakePluginStore {},
2023-01-17 14:17:54 +01:00
SQLStore : dbtest . NewFakeDB (),
2022-05-25 10:41:51 +02:00
preferenceService : prefService ,
dashboardVersionService : dashboardVersionService ,
2023-08-30 16:51:18 +02:00
log : log . New ( "test-logger" ),
2024-06-26 12:03:13 -08:00
tracer : tracing . InitializeTracerForTest (),
2021-03-17 16:06:10 +01:00
}
2020-06-22 18:00:39 +02:00
tests := [] struct {
name string
defaultSetting string
expectedDashboardPath string
}{
{ name : "using default config" , defaultSetting : "" , expectedDashboardPath : "../../public/dashboards/home.json" },
{ name : "custom path" , defaultSetting : "../../public/dashboards/default.json" , expectedDashboardPath : "../../public/dashboards/default.json" },
}
for _ , tc := range tests {
t . Run ( tc . name , func ( t * testing . T ) {
dash := dtos . DashboardFullWithMeta {}
dash . Meta . FolderTitle = "General"
2022-08-10 13:37:51 +00:00
homeDashJSON , err := os . ReadFile ( tc . expectedDashboardPath )
2020-06-22 18:00:39 +02:00
require . NoError ( t , err , "must be able to read expected dashboard file" )
hs . Cfg . DefaultHomeDashboardPath = tc . defaultSetting
bytes , err := simplejson . NewJson ( homeDashJSON )
require . NoError ( t , err , "must be able to encode file as JSON" )
2022-04-21 15:03:17 +02:00
prefService . ExpectedPreference = & pref . Preference {}
2020-06-22 18:00:39 +02:00
dash . Dashboard = bytes
b , err := json . Marshal ( dash )
require . NoError ( t , err , "must be able to marshal object to JSON" )
res := hs . GetHomeDashboard ( req )
2021-01-15 14:43:20 +01:00
nr , ok := res .( * response . NormalResponse )
2020-06-22 18:00:39 +02:00
require . True ( t , ok , "should return *NormalResponse" )
2021-01-15 14:43:20 +01:00
require . Equal ( t , b , nr . Body (), "default home dashboard should equal content on disk" )
2020-06-22 18:00:39 +02:00
})
}
}
2022-10-14 15:33:06 -04:00
func newTestLive ( t * testing . T , store db . DB ) * live . GrafanaLive {
2022-01-26 09:44:20 -08:00
features := featuremgmt . WithFeatures ()
2023-11-13 07:55:15 -08:00
cfg := setting . NewCfg ()
cfg . AppURL = "http://localhost:3000/"
2022-01-26 09:44:20 -08:00
gLive , err := live . ProvideService ( nil , cfg ,
routing . NewRouteRegister (),
2023-02-27 18:48:18 +00:00
nil , nil , nil , nil ,
2022-03-22 20:48:32 +01:00
store ,
2022-01-26 09:44:20 -08:00
nil ,
& usagestats . UsageStatsMock { T : t },
nil ,
2024-07-05 11:31:23 +02:00
features , acimpl . ProvideAccessControl ( features , zanzana . NewNoopClient ()), & dashboards . FakeDashboardService {}, annotationstest . NewFakeAnnotationsRepo (), nil )
2021-05-04 08:44:55 -07:00
require . NoError ( t , err )
return gLive
}
2023-08-29 15:09:09 +02:00
func TestHTTPServer_GetDashboard_AccessControl ( t * testing . T ) {
setup := func () * webtest . Server {
return SetupAPITestServer ( t , func ( hs * HTTPServer ) {
dash := dashboards . NewDashboard ( "some dash" )
dash . ID = 1
dash . UID = "1"
2018-01-30 14:09:30 +01:00
2023-08-29 15:09:09 +02:00
dashSvc := dashboards . NewFakeDashboardService ( t )
dashSvc . On ( "GetDashboard" , mock . Anything , mock . Anything ). Return ( dash , nil ). Maybe ()
hs . DashboardService = dashSvc
2018-01-31 16:51:06 +01:00
2023-08-29 15:09:09 +02:00
hs . Cfg = setting . NewCfg ()
2024-07-05 11:31:23 +02:00
hs . AccessControl = acimpl . ProvideAccessControl ( featuremgmt . WithFeatures (), zanzana . NewNoopClient ())
2023-08-29 15:09:09 +02:00
hs . starService = startest . NewStarServiceFake ()
hs . dashboardProvisioningService = mockDashboardProvisioningService {}
2018-01-29 21:23:07 +01:00
2023-08-29 15:09:09 +02:00
guardian . InitAccessControlGuardian ( hs . Cfg , hs . AccessControl , hs . DashboardService )
})
}
2017-06-22 17:43:55 -04:00
2023-08-29 15:09:09 +02:00
getDashboard := func ( server * webtest . Server , permissions [] accesscontrol . Permission ) ( * http . Response , error ) {
return server . Send ( webtest . RequestWithSignedInUser ( server . NewGetRequest ( "/api/dashboards/uid/1" ), userWithPermissions ( 1 , permissions )))
}
2018-01-30 14:09:30 +01:00
2023-08-29 15:09:09 +02:00
t . Run ( "Should not be able to get dashboard without correct permission" , func ( t * testing . T ) {
server := setup ()
2017-06-12 15:48:55 +02:00
2023-08-29 15:09:09 +02:00
res , err := getDashboard ( server , nil )
require . NoError ( t , err )
assert . Equal ( t , http . StatusForbidden , res . StatusCode )
require . NoError ( t , res . Body . Close ())
2017-06-12 15:48:55 +02:00
})
2023-08-29 15:09:09 +02:00
t . Run ( "Should be able to get when user has permission to read dashboard" , func ( t * testing . T ) {
server := setup ()
2023-01-25 10:36:26 +01:00
2023-08-29 15:09:09 +02:00
permissions := [] accesscontrol . Permission {{ Action : dashboards . ActionDashboardsRead , Scope : "dashboards:uid:1" }}
res , err := getDashboard ( server , permissions )
require . NoError ( t , err )
2022-02-07 12:43:43 +01:00
2023-08-29 15:09:09 +02:00
assert . Equal ( t , http . StatusOK , res . StatusCode )
var data dtos . DashboardFullWithMeta
require . NoError ( t , json . NewDecoder ( res . Body ). Decode ( & data ))
2022-05-17 14:52:22 -04:00
2023-08-29 15:09:09 +02:00
assert . Equal ( t , data . Meta . CanSave , false )
assert . Equal ( t , data . Meta . CanEdit , false )
assert . Equal ( t , data . Meta . CanDelete , false )
assert . Equal ( t , data . Meta . CanAdmin , false )
2017-06-12 15:48:55 +02:00
2023-08-29 15:09:09 +02:00
require . NoError ( t , res . Body . Close ())
})
2019-04-30 13:32:18 +02:00
2023-08-29 15:09:09 +02:00
t . Run ( "Should set CanSave and CanEdit with correct permissions" , func ( t * testing . T ) {
server := setup ()
2018-01-30 14:09:30 +01:00
2023-08-29 15:09:09 +02:00
res , err := getDashboard ( server , [] accesscontrol . Permission {
{ Action : dashboards . ActionDashboardsRead , Scope : "dashboards:uid:1" },
{ Action : dashboards . ActionDashboardsWrite , Scope : "dashboards:uid:1" },
2017-06-12 15:48:55 +02:00
})
2023-08-29 15:09:09 +02:00
require . NoError ( t , err )
2017-06-12 15:48:55 +02:00
2023-08-29 15:09:09 +02:00
assert . Equal ( t , http . StatusOK , res . StatusCode )
var data dtos . DashboardFullWithMeta
require . NoError ( t , json . NewDecoder ( res . Body ). Decode ( & data ))
2017-06-12 15:48:55 +02:00
2023-08-29 15:09:09 +02:00
assert . Equal ( t , data . Meta . CanSave , true )
assert . Equal ( t , data . Meta . CanEdit , true )
assert . Equal ( t , data . Meta . CanDelete , false )
assert . Equal ( t , data . Meta . CanAdmin , false )
2017-06-12 23:05:32 +02:00
2023-08-29 15:09:09 +02:00
require . NoError ( t , res . Body . Close ())
})
2022-06-01 14:16:26 -04:00
2023-08-29 15:09:09 +02:00
t . Run ( "Should set canDelete with correct permissions" , func ( t * testing . T ) {
server := setup ()
res , err := getDashboard ( server , [] accesscontrol . Permission {
{ Action : dashboards . ActionDashboardsRead , Scope : "dashboards:uid:1" },
{ Action : dashboards . ActionDashboardsDelete , Scope : "dashboards:uid:1" },
})
require . NoError ( t , err )
2022-02-07 12:43:43 +01:00
2023-08-29 15:09:09 +02:00
assert . Equal ( t , http . StatusOK , res . StatusCode )
var data dtos . DashboardFullWithMeta
require . NoError ( t , json . NewDecoder ( res . Body ). Decode ( & data ))
2018-01-29 21:23:07 +01:00
2023-08-29 15:09:09 +02:00
assert . Equal ( t , data . Meta . CanSave , false )
assert . Equal ( t , data . Meta . CanEdit , false )
assert . Equal ( t , data . Meta . CanDelete , true )
assert . Equal ( t , data . Meta . CanAdmin , false )
2017-06-23 00:34:19 +02:00
2023-08-29 15:09:09 +02:00
require . NoError ( t , res . Body . Close ())
})
2022-02-07 12:43:43 +01:00
2023-08-29 15:09:09 +02:00
t . Run ( "Should set canAdmin with correct permissions" , func ( t * testing . T ) {
server := setup ()
2020-11-13 09:52:38 +01:00
2023-08-29 15:09:09 +02:00
res , err := getDashboard ( server , [] accesscontrol . Permission {
{ Action : dashboards . ActionDashboardsRead , Scope : "dashboards:uid:1" },
{ Action : dashboards . ActionDashboardsPermissionsRead , Scope : "dashboards:uid:1" },
{ Action : dashboards . ActionDashboardsPermissionsWrite , Scope : "dashboards:uid:1" },
2017-06-23 00:34:19 +02:00
})
2023-08-29 15:09:09 +02:00
require . NoError ( t , err )
2017-06-23 00:34:19 +02:00
2023-08-29 15:09:09 +02:00
assert . Equal ( t , http . StatusOK , res . StatusCode )
var data dtos . DashboardFullWithMeta
require . NoError ( t , json . NewDecoder ( res . Body ). Decode ( & data ))
2022-06-01 14:16:26 -04:00
2023-08-29 15:09:09 +02:00
assert . Equal ( t , data . Meta . CanSave , false )
assert . Equal ( t , data . Meta . CanEdit , false )
assert . Equal ( t , data . Meta . CanDelete , false )
assert . Equal ( t , data . Meta . CanAdmin , true )
2022-02-07 12:43:43 +01:00
2023-08-29 15:09:09 +02:00
require . NoError ( t , res . Body . Close ())
})
}
2017-12-15 14:19:49 +01:00
2023-08-29 15:09:09 +02:00
func TestHTTPServer_DeleteDashboardByUID_AccessControl ( t * testing . T ) {
setup := func () * webtest . Server {
return SetupAPITestServer ( t , func ( hs * HTTPServer ) {
dash := dashboards . NewDashboard ( "some dash" )
dash . ID = 1
dash . UID = "1"
2018-01-29 21:23:07 +01:00
2023-08-29 15:09:09 +02:00
dashSvc := dashboards . NewFakeDashboardService ( t )
dashSvc . On ( "GetDashboard" , mock . Anything , mock . Anything ). Return ( dash , nil ). Maybe ()
dashSvc . On ( "DeleteDashboard" , mock . Anything , mock . Anything , mock . Anything ). Return ( nil ). Maybe ()
hs . DashboardService = dashSvc
2017-12-15 14:19:49 +01:00
2023-08-29 15:09:09 +02:00
hs . Cfg = setting . NewCfg ()
2024-07-05 11:31:23 +02:00
hs . AccessControl = acimpl . ProvideAccessControl ( featuremgmt . WithFeatures (), zanzana . NewNoopClient ())
2023-08-29 15:09:09 +02:00
hs . starService = startest . NewStarServiceFake ()
2018-01-31 16:46:31 +01:00
2023-08-29 15:09:09 +02:00
hs . LibraryPanelService = & mockLibraryPanelService {}
2024-09-27 14:22:29 +02:00
hs . LibraryElementService = & libraryelementsfake . LibraryElementService {}
2017-12-15 14:19:49 +01:00
2023-08-29 15:09:09 +02:00
pubDashService := publicdashboards . NewFakePublicDashboardService ( t )
pubDashService . On ( "DeleteByDashboard" , mock . Anything , mock . Anything ). Return ( nil ). Maybe ()
2023-11-21 17:56:36 -03:00
middleware := publicdashboards . NewFakePublicDashboardMiddleware ( t )
2024-02-22 09:34:14 +01:00
license := licensingtest . NewFakeLicensing ()
license . On ( "FeatureEnabled" , publicdashboardModels . FeaturePublicDashboardsEmailSharing ). Return ( false )
hs . PublicDashboardsApi = api . ProvideApi ( pubDashService , nil , hs . AccessControl , featuremgmt . WithFeatures (), middleware , hs . Cfg , license )
2017-06-23 00:34:19 +02:00
2023-08-29 15:09:09 +02:00
guardian . InitAccessControlGuardian ( hs . Cfg , hs . AccessControl , hs . DashboardService )
})
}
deleteDashboard := func ( server * webtest . Server , permissions [] accesscontrol . Permission ) ( * http . Response , error ) {
return server . Send ( webtest . RequestWithSignedInUser ( server . NewRequest ( http . MethodDelete , "/api/dashboards/uid/1" , nil ), userWithPermissions ( 1 , permissions )))
}
2020-11-13 09:52:38 +01:00
2023-08-29 15:09:09 +02:00
t . Run ( "Should not be able to delete dashboard without correct permission" , func ( t * testing . T ) {
server := setup ()
res , err := deleteDashboard ( server , [] accesscontrol . Permission {
{ Action : dashboards . ActionDashboardsDelete , Scope : "dashboards:uid:2" },
})
require . NoError ( t , err )
2017-06-23 00:34:19 +02:00
2023-08-29 15:09:09 +02:00
assert . Equal ( t , http . StatusForbidden , res . StatusCode )
require . NoError ( t , res . Body . Close ())
})
2018-01-29 21:23:07 +01:00
2023-08-29 15:09:09 +02:00
t . Run ( "Should be able to delete dashboard with correct permission" , func ( t * testing . T ) {
server := setup ()
res , err := deleteDashboard ( server , [] accesscontrol . Permission {
{ Action : dashboards . ActionDashboardsDelete , Scope : "dashboards:uid:1" },
})
require . NoError ( t , err )
2017-06-12 23:05:32 +02:00
2023-08-29 15:09:09 +02:00
assert . Equal ( t , http . StatusOK , res . StatusCode )
require . NoError ( t , res . Body . Close ())
})
}
2018-01-29 21:23:07 +01:00
2023-08-29 15:09:09 +02:00
func TestHTTPServer_GetDashboardVersions_AccessControl ( t * testing . T ) {
setup := func () * webtest . Server {
return SetupAPITestServer ( t , func ( hs * HTTPServer ) {
dash := dashboards . NewDashboard ( "some dash" )
dash . ID = 1
dash . UID = "1"
2017-06-12 23:05:32 +02:00
2023-08-29 15:09:09 +02:00
dashSvc := dashboards . NewFakeDashboardService ( t )
dashSvc . On ( "GetDashboard" , mock . Anything , mock . Anything ). Return ( dash , nil ). Maybe ()
dashSvc . On ( "DeleteDashboard" , mock . Anything , mock . Anything , mock . Anything ). Return ( nil ). Maybe ()
hs . DashboardService = dashSvc
2018-01-31 16:46:31 +01:00
2023-08-29 15:09:09 +02:00
hs . Cfg = setting . NewCfg ()
2024-07-05 11:31:23 +02:00
hs . AccessControl = acimpl . ProvideAccessControl ( featuremgmt . WithFeatures (), zanzana . NewNoopClient ())
2023-08-29 15:09:09 +02:00
hs . starService = startest . NewStarServiceFake ()
2017-06-12 23:05:32 +02:00
2023-08-29 15:09:09 +02:00
hs . dashboardVersionService = & dashvertest . FakeDashboardVersionService {
ExpectedListDashboarVersions : [] * dashver . DashboardVersionDTO {},
ExpectedDashboardVersion : & dashver . DashboardVersionDTO {},
}
2017-06-14 00:28:34 +02:00
2023-08-29 15:09:09 +02:00
guardian . InitAccessControlGuardian ( hs . Cfg , hs . AccessControl , hs . DashboardService )
2017-06-12 15:48:55 +02:00
})
2023-08-29 15:09:09 +02:00
}
2017-06-12 15:48:55 +02:00
2023-08-29 15:09:09 +02:00
getVersion := func ( server * webtest . Server , permissions [] accesscontrol . Permission ) ( * http . Response , error ) {
return server . Send ( webtest . RequestWithSignedInUser ( server . NewGetRequest ( "/api/dashboards/uid/1/versions/1" ), userWithPermissions ( 1 , permissions )))
}
2017-06-12 23:05:32 +02:00
2023-08-29 15:09:09 +02:00
getVersions := func ( server * webtest . Server , permissions [] accesscontrol . Permission ) ( * http . Response , error ) {
return server . Send ( webtest . RequestWithSignedInUser ( server . NewGetRequest ( "/api/dashboards/uid/1/versions" ), userWithPermissions ( 1 , permissions )))
}
2017-06-12 15:48:55 +02:00
2023-08-29 15:09:09 +02:00
t . Run ( "Should not be able to list dashboard versions without correct permission" , func ( t * testing . T ) {
server := setup ()
2022-02-07 12:43:43 +01:00
2023-08-29 15:09:09 +02:00
res , err := getVersions ( server , [] accesscontrol . Permission {})
require . NoError ( t , err )
assert . Equal ( t , http . StatusForbidden , res . StatusCode )
require . NoError ( t , res . Body . Close ())
2017-06-12 23:05:32 +02:00
2023-08-29 15:09:09 +02:00
res , err = getVersion ( server , [] accesscontrol . Permission {})
require . NoError ( t , err )
assert . Equal ( t , http . StatusForbidden , res . StatusCode )
2018-01-31 16:46:31 +01:00
2023-08-29 15:09:09 +02:00
require . NoError ( t , res . Body . Close ())
})
2017-06-12 23:05:32 +02:00
2023-08-29 15:09:09 +02:00
t . Run ( "Should be able to list dashboard versions with correct permission" , func ( t * testing . T ) {
server := setup ()
2020-11-13 09:52:38 +01:00
2023-08-29 15:09:09 +02:00
permissions := [] accesscontrol . Permission {
{ Action : dashboards . ActionDashboardsRead , Scope : "dashboards:uid:1" },
{ Action : dashboards . ActionDashboardsWrite , Scope : "dashboards:uid:1" },
}
2017-06-14 00:28:34 +02:00
2023-08-29 15:09:09 +02:00
res , err := getVersions ( server , permissions )
require . NoError ( t , err )
assert . Equal ( t , http . StatusOK , res . StatusCode )
require . NoError ( t , res . Body . Close ())
2020-11-13 09:52:38 +01:00
2023-08-29 15:09:09 +02:00
res , err = getVersion ( server , permissions )
require . NoError ( t , err )
assert . Equal ( t , http . StatusOK , res . StatusCode )
require . NoError ( t , res . Body . Close ())
2017-06-12 15:48:55 +02:00
})
2023-08-29 15:09:09 +02:00
}
2018-01-31 16:51:06 +01:00
2023-08-29 15:09:09 +02:00
func TestDashboardAPIEndpoint ( t * testing . T ) {
2020-11-13 09:52:38 +01:00
t . Run ( "Given two dashboards with the same title in different folders" , func ( t * testing . T ) {
2023-01-18 13:52:41 +01:00
dashOne := dashboards . NewDashboard ( "dash" )
dashOne . ID = 2
2023-12-20 15:12:05 +01:00
dashOne . FolderUID = "folderUID"
2022-07-18 15:14:58 +02:00
dashOne . HasACL = false
2018-01-31 16:51:06 +01:00
2023-01-18 13:52:41 +01:00
dashTwo := dashboards . NewDashboard ( "dash" )
dashTwo . ID = 4
2023-12-20 15:12:05 +01:00
dashTwo . FolderUID = "folderUID2"
2022-07-18 15:14:58 +02:00
dashTwo . HasACL = false
2018-01-31 16:51:06 +01:00
})
2018-02-19 11:12:56 +01:00
2020-11-13 09:52:38 +01:00
t . Run ( "Post dashboard response tests" , func ( t * testing . T ) {
2022-03-10 12:19:50 -05:00
dashboardStore := & dashboards . FakeDashboardStore {}
2022-02-16 14:15:44 +01:00
defer dashboardStore . AssertExpectations ( t )
2018-02-19 11:12:56 +01:00
// This tests that a valid request returns correct response
2020-11-13 09:52:38 +01:00
t . Run ( "Given a correct request for creating a dashboard" , func ( t * testing . T ) {
2023-10-24 10:04:45 +03:00
folderUID := "Folder"
2020-11-13 09:52:38 +01:00
const dashID int64 = 2
2018-02-19 11:12:56 +01:00
2023-01-18 13:52:41 +01:00
cmd := dashboards . SaveDashboardCommand {
OrgID : 1 ,
UserID : 5 ,
2023-08-30 08:46:47 -07:00
Dashboard : simplejson . NewFromAny ( map [ string ] any {
2018-02-19 11:12:56 +01:00
"title" : "Dash" ,
}),
Overwrite : true ,
2023-10-24 10:04:45 +03:00
FolderUID : folderUID ,
2018-02-19 11:12:56 +01:00
IsFolder : false ,
Message : "msg" ,
}
2022-05-23 11:14:27 -04:00
dashboardService := dashboards . NewFakeDashboardService ( t )
dashboardService . On ( "SaveDashboard" , mock . Anything , mock . AnythingOfType ( "*dashboards.SaveDashboardDTO" ), mock . AnythingOfType ( "bool" )).
2023-12-20 15:12:05 +01:00
Return ( & dashboards . Dashboard { ID : dashID , UID : "uid" , Title : "Dash" , Slug : "dash" , Version : 2 , FolderUID : folderUID }, nil )
2023-10-24 10:04:45 +03:00
mockFolderService := & foldertest . FakeService {
2023-12-20 15:12:05 +01:00
ExpectedFolder : & folder . Folder { UID : folderUID , Title : "Folder" },
2023-10-24 10:04:45 +03:00
}
2018-02-19 11:12:56 +01:00
2023-10-24 10:04:45 +03:00
postDashboardScenario ( t , "When calling POST on" , "/api/dashboards" , "/api/dashboards" , cmd , dashboardService , mockFolderService , func ( sc * scenarioContext ) {
2020-11-13 09:52:38 +01:00
callPostDashboardShouldReturnSuccess ( sc )
2018-02-19 11:12:56 +01:00
2020-11-13 09:52:38 +01:00
result := sc . ToJSON ()
assert . Equal ( t , "success" , result . Get ( "status" ). MustString ())
assert . Equal ( t , dashID , result . Get ( "id" ). MustInt64 ())
assert . Equal ( t , "uid" , result . Get ( "uid" ). MustString ())
assert . Equal ( t , "dash" , result . Get ( "slug" ). MustString ())
assert . Equal ( t , "/d/uid/dash" , result . Get ( "url" ). MustString ())
2018-02-19 11:12:56 +01:00
})
})
2021-05-26 16:20:13 +02:00
t . Run ( "Given a correct request for creating a dashboard with folder uid" , func ( t * testing . T ) {
const folderUid string = "folderUID"
const dashID int64 = 2
2023-01-18 13:52:41 +01:00
cmd := dashboards . SaveDashboardCommand {
OrgID : 1 ,
UserID : 5 ,
2023-08-30 08:46:47 -07:00
Dashboard : simplejson . NewFromAny ( map [ string ] any {
2021-05-26 16:20:13 +02:00
"title" : "Dash" ,
}),
Overwrite : true ,
2023-01-18 13:52:41 +01:00
FolderUID : folderUid ,
2021-05-26 16:20:13 +02:00
IsFolder : false ,
Message : "msg" ,
}
2022-05-23 11:14:27 -04:00
dashboardService := dashboards . NewFakeDashboardService ( t )
dashboardService . On ( "SaveDashboard" , mock . Anything , mock . AnythingOfType ( "*dashboards.SaveDashboardDTO" ), mock . AnythingOfType ( "bool" )).
2023-01-16 16:33:55 +01:00
Return ( & dashboards . Dashboard { ID : dashID , UID : "uid" , Title : "Dash" , Slug : "dash" , Version : 2 }, nil )
2021-05-26 16:20:13 +02:00
2022-11-11 14:28:24 +01:00
mockFolder := & foldertest . FakeService {
2023-12-20 15:12:05 +01:00
ExpectedFolder : & folder . Folder { UID : "folderUID" , Title : "Folder" },
2021-05-26 16:20:13 +02:00
}
2022-05-23 11:14:27 -04:00
postDashboardScenario ( t , "When calling POST on" , "/api/dashboards" , "/api/dashboards" , cmd , dashboardService , mockFolder , func ( sc * scenarioContext ) {
2021-05-26 16:20:13 +02:00
callPostDashboardShouldReturnSuccess ( sc )
result := sc . ToJSON ()
assert . Equal ( t , "success" , result . Get ( "status" ). MustString ())
assert . Equal ( t , dashID , result . Get ( "id" ). MustInt64 ())
assert . Equal ( t , "uid" , result . Get ( "uid" ). MustString ())
assert . Equal ( t , "dash" , result . Get ( "slug" ). MustString ())
assert . Equal ( t , "/d/uid/dash" , result . Get ( "url" ). MustString ())
})
})
2018-02-19 11:12:56 +01:00
// This tests that invalid requests returns expected error responses
2020-11-13 09:52:38 +01:00
t . Run ( "Given incorrect requests for creating a dashboard" , func ( t * testing . T ) {
2018-02-19 11:12:56 +01:00
testCases := [] struct {
SaveError error
ExpectedStatusCode int
}{
2023-08-30 16:51:18 +02:00
{ SaveError : dashboards . ErrDashboardNotFound , ExpectedStatusCode : http . StatusNotFound },
{ SaveError : dashboards . ErrFolderNotFound , ExpectedStatusCode : http . StatusBadRequest },
{ SaveError : dashboards . ErrDashboardWithSameUIDExists , ExpectedStatusCode : http . StatusBadRequest },
{ SaveError : dashboards . ErrDashboardWithSameNameInFolderExists , ExpectedStatusCode : http . StatusPreconditionFailed },
{ SaveError : dashboards . ErrDashboardVersionMismatch , ExpectedStatusCode : http . StatusPreconditionFailed },
{ SaveError : dashboards . ErrDashboardTitleEmpty , ExpectedStatusCode : http . StatusBadRequest },
{ SaveError : dashboards . ErrDashboardFolderCannotHaveParent , ExpectedStatusCode : http . StatusBadRequest },
{ SaveError : dashboards . ErrDashboardTypeMismatch , ExpectedStatusCode : http . StatusBadRequest },
{ SaveError : dashboards . ErrDashboardFolderWithSameNameAsDashboard , ExpectedStatusCode : http . StatusBadRequest },
{ SaveError : dashboards . ErrDashboardWithSameNameAsFolder , ExpectedStatusCode : http . StatusBadRequest },
{ SaveError : dashboards . ErrDashboardFolderNameExists , ExpectedStatusCode : http . StatusBadRequest },
{ SaveError : dashboards . ErrDashboardUpdateAccessDenied , ExpectedStatusCode : http . StatusForbidden },
{ SaveError : dashboards . ErrDashboardInvalidUid , ExpectedStatusCode : http . StatusBadRequest },
{ SaveError : dashboards . ErrDashboardUidTooLong , ExpectedStatusCode : http . StatusBadRequest },
{ SaveError : dashboards . ErrDashboardCannotSaveProvisionedDashboard , ExpectedStatusCode : http . StatusBadRequest },
{ SaveError : dashboards . UpdatePluginDashboardError { PluginId : "plug" }, ExpectedStatusCode : http . StatusPreconditionFailed },
2018-02-19 11:12:56 +01:00
}
2023-01-18 13:52:41 +01:00
cmd := dashboards . SaveDashboardCommand {
OrgID : 1 ,
2023-08-30 08:46:47 -07:00
Dashboard : simplejson . NewFromAny ( map [ string ] any {
2018-02-19 11:12:56 +01:00
"title" : "" ,
}),
}
for _ , tc := range testCases {
2022-05-23 11:14:27 -04:00
dashboardService := dashboards . NewFakeDashboardService ( t )
dashboardService . On ( "SaveDashboard" , mock . Anything , mock . AnythingOfType ( "*dashboards.SaveDashboardDTO" ), mock . AnythingOfType ( "bool" )). Return ( nil , tc . SaveError )
2018-02-19 11:12:56 +01:00
2020-11-13 09:52:38 +01:00
postDashboardScenario ( t , fmt . Sprintf ( "Expect '%s' error when calling POST on" , tc . SaveError . Error ()),
2022-05-23 11:14:27 -04:00
"/api/dashboards" , "/api/dashboards" , cmd , dashboardService , nil , func ( sc * scenarioContext ) {
2020-11-13 09:52:38 +01:00
callPostDashboard ( sc )
2023-08-30 16:51:18 +02:00
assert . Equal ( t , tc . ExpectedStatusCode , sc . resp . Code , sc . resp . Body . String ())
2020-11-13 09:52:38 +01:00
})
2018-02-19 11:12:56 +01:00
}
})
})
2018-02-27 17:53:30 +01:00
2020-11-13 09:52:38 +01:00
t . Run ( "Given two dashboards being compared" , func ( t * testing . T ) {
2022-05-25 10:41:51 +02:00
fakeDashboardVersionService := dashvertest . NewDashboardVersionServiceFake ()
2022-12-27 17:17:24 +01:00
fakeDashboardVersionService . ExpectedDashboardVersions = [] * dashver . DashboardVersionDTO {
2022-05-25 10:41:51 +02:00
{
DashboardID : 1 ,
Version : 1 ,
2023-08-30 08:46:47 -07:00
Data : simplejson . NewFromAny ( map [ string ] any {
2022-05-25 10:41:51 +02:00
"title" : "Dash1" ,
}),
},
{
DashboardID : 2 ,
Version : 2 ,
2023-08-30 08:46:47 -07:00
Data : simplejson . NewFromAny ( map [ string ] any {
2022-05-25 10:41:51 +02:00
"title" : "Dash2" ,
}),
},
}
2023-01-17 14:17:54 +01:00
sqlmock := dbtest . NewFakeDB ()
2018-02-27 17:53:30 +01:00
cmd := dtos . CalculateDiffOptions {
Base : dtos . CalculateDiffTarget {
DashboardId : 1 ,
Version : 1 ,
},
New : dtos . CalculateDiffTarget {
DashboardId : 2 ,
Version : 2 ,
},
DiffType : "basic" ,
}
2020-11-13 09:52:38 +01:00
t . Run ( "when user does not have permission" , func ( t * testing . T ) {
2022-08-10 11:56:48 +02:00
role := org . RoleViewer
2020-11-13 09:52:38 +01:00
postDiffScenario ( t , "When calling POST on" , "/api/dashboards/calculate-diff" , "/api/dashboards/calculate-diff" , cmd , role , func ( sc * scenarioContext ) {
2023-08-29 15:09:09 +02:00
guardian . MockDashboardGuardian ( & guardian . FakeDashboardGuardian { CanSaveValue : false })
2020-11-13 09:52:38 +01:00
callPostDashboard ( sc )
2023-08-30 16:51:18 +02:00
assert . Equal ( t , http . StatusForbidden , sc . resp . Code )
2023-01-17 14:17:54 +01:00
}, sqlmock , fakeDashboardVersionService )
2018-02-27 17:53:30 +01:00
})
2020-11-13 09:52:38 +01:00
t . Run ( "when user does have permission" , func ( t * testing . T ) {
2022-08-10 11:56:48 +02:00
role := org . RoleAdmin
2020-11-13 09:52:38 +01:00
postDiffScenario ( t , "When calling POST on" , "/api/dashboards/calculate-diff" , "/api/dashboards/calculate-diff" , cmd , role , func ( sc * scenarioContext ) {
2023-08-29 15:09:09 +02:00
guardian . MockDashboardGuardian ( & guardian . FakeDashboardGuardian { CanSaveValue : true })
2022-07-18 15:14:58 +02:00
// This test shouldn't hit GetDashboardACLInfoList, so no setup needed
2022-05-25 10:41:51 +02:00
sc . dashboardVersionService = fakeDashboardVersionService
2020-11-13 09:52:38 +01:00
callPostDashboard ( sc )
2023-08-30 16:51:18 +02:00
assert . Equal ( t , http . StatusOK , sc . resp . Code )
2023-01-17 14:17:54 +01:00
}, sqlmock , fakeDashboardVersionService )
2018-02-27 17:53:30 +01:00
})
})
2019-03-06 14:38:40 +01:00
2020-11-13 09:52:38 +01:00
t . Run ( "Given dashboard in folder being restored should restore to folder" , func ( t * testing . T ) {
2023-01-16 16:33:55 +01:00
fakeDash := dashboards . NewDashboard ( "Child dash" )
fakeDash . ID = 2
2022-07-18 15:14:58 +02:00
fakeDash . HasACL = false
2019-03-06 14:38:40 +01:00
2022-05-23 11:14:27 -04:00
dashboardService := dashboards . NewFakeDashboardService ( t )
2023-01-25 10:36:26 +01:00
dashboardService . On ( "GetDashboard" , mock . Anything , mock . AnythingOfType ( "*dashboards.GetDashboardQuery" )). Return ( fakeDash , nil )
2022-05-23 11:14:27 -04:00
dashboardService . On ( "SaveDashboard" , mock . Anything , mock . AnythingOfType ( "*dashboards.SaveDashboardDTO" ), mock . AnythingOfType ( "bool" )). Run ( func ( args mock . Arguments ) {
cmd := args . Get ( 1 ).( * dashboards . SaveDashboardDTO )
2023-01-16 16:33:55 +01:00
cmd . Dashboard = & dashboards . Dashboard {
ID : 2 , UID : "uid" , Title : "Dash" , Slug : "dash" , Version : 1 ,
2022-05-23 11:14:27 -04:00
}
}). Return ( nil , nil )
2019-03-06 14:38:40 +01:00
cmd := dtos . RestoreDashboardVersionCommand {
Version : 1 ,
}
2022-05-25 10:41:51 +02:00
fakeDashboardVersionService := dashvertest . NewDashboardVersionServiceFake ()
2022-12-27 17:17:24 +01:00
fakeDashboardVersionService . ExpectedDashboardVersions = [] * dashver . DashboardVersionDTO {
2022-02-10 16:58:52 +08:00
{
2022-05-25 10:41:51 +02:00
DashboardID : 2 ,
2022-02-10 16:58:52 +08:00
Version : 1 ,
Data : fakeDash . Data ,
2024-06-26 12:03:13 -08:00
},
}
2023-01-18 16:01:25 +01:00
mockSQLStore := dbtest . NewFakeDB ()
2023-10-24 10:04:45 +03:00
origNewGuardian := guardian . New
guardian . MockDashboardGuardian ( & guardian . FakeDashboardGuardian { CanSaveValue : true })
t . Cleanup ( func () {
guardian . New = origNewGuardian
})
2020-11-13 09:52:38 +01:00
restoreDashboardVersionScenario ( t , "When calling POST on" , "/api/dashboards/id/1/restore" ,
2022-05-25 10:41:51 +02:00
"/api/dashboards/id/:dashboardId/restore" , dashboardService , fakeDashboardVersionService , cmd , func ( sc * scenarioContext ) {
sc . dashboardVersionService = fakeDashboardVersionService
2020-11-13 09:52:38 +01:00
callRestoreDashboardVersion ( sc )
2023-08-30 16:51:18 +02:00
assert . Equal ( t , http . StatusOK , sc . resp . Code )
2022-02-07 12:43:43 +01:00
}, mockSQLStore )
2019-03-06 14:38:40 +01:00
})
2020-11-13 09:52:38 +01:00
t . Run ( "Given dashboard in general folder being restored should restore to general folder" , func ( t * testing . T ) {
2023-01-16 16:33:55 +01:00
fakeDash := dashboards . NewDashboard ( "Child dash" )
fakeDash . ID = 2
2022-07-18 15:14:58 +02:00
fakeDash . HasACL = false
2019-03-06 14:38:40 +01:00
2022-05-23 11:14:27 -04:00
dashboardService := dashboards . NewFakeDashboardService ( t )
2023-01-25 10:36:26 +01:00
dashboardService . On ( "GetDashboard" , mock . Anything , mock . AnythingOfType ( "*dashboards.GetDashboardQuery" )). Return ( fakeDash , nil )
2022-05-23 11:14:27 -04:00
dashboardService . On ( "SaveDashboard" , mock . Anything , mock . AnythingOfType ( "*dashboards.SaveDashboardDTO" ), mock . AnythingOfType ( "bool" )). Run ( func ( args mock . Arguments ) {
cmd := args . Get ( 1 ).( * dashboards . SaveDashboardDTO )
2023-01-16 16:33:55 +01:00
cmd . Dashboard = & dashboards . Dashboard {
ID : 2 , UID : "uid" , Title : "Dash" , Slug : "dash" , Version : 1 ,
2022-05-23 11:14:27 -04:00
}
}). Return ( nil , nil )
2019-03-06 14:38:40 +01:00
2022-05-25 10:41:51 +02:00
fakeDashboardVersionService := dashvertest . NewDashboardVersionServiceFake ()
2022-12-27 17:17:24 +01:00
fakeDashboardVersionService . ExpectedDashboardVersions = [] * dashver . DashboardVersionDTO {
2022-05-25 10:41:51 +02:00
{
DashboardID : 2 ,
Version : 1 ,
Data : fakeDash . Data ,
2024-06-26 12:03:13 -08:00
},
}
2022-05-25 10:41:51 +02:00
2019-03-06 14:38:40 +01:00
cmd := dtos . RestoreDashboardVersionCommand {
Version : 1 ,
}
2023-01-18 16:01:25 +01:00
mockSQLStore := dbtest . NewFakeDB ()
2020-11-13 09:52:38 +01:00
restoreDashboardVersionScenario ( t , "When calling POST on" , "/api/dashboards/id/1/restore" ,
2022-05-25 10:41:51 +02:00
"/api/dashboards/id/:dashboardId/restore" , dashboardService , fakeDashboardVersionService , cmd , func ( sc * scenarioContext ) {
2020-11-13 09:52:38 +01:00
callRestoreDashboardVersion ( sc )
2023-08-30 16:51:18 +02:00
assert . Equal ( t , http . StatusOK , sc . resp . Code )
2022-02-07 12:43:43 +01:00
}, mockSQLStore )
2019-03-06 14:38:40 +01:00
})
2019-04-10 13:29:10 +02:00
2020-11-13 09:52:38 +01:00
t . Run ( "Given provisioned dashboard" , func ( t * testing . T ) {
2023-01-18 16:01:25 +01:00
mockSQLStore := dbtest . NewFakeDB ()
2022-06-01 14:16:26 -04:00
dashboardStore := dashboards . NewFakeDashboardStore ( t )
2023-01-18 13:52:41 +01:00
dashboardStore . On ( "GetProvisionedDataByDashboardID" , mock . Anything , mock . AnythingOfType ( "int64" )). Return ( & dashboards . DashboardProvisioning { ExternalID : "/dashboard1.json" }, nil ). Once ()
2022-06-01 14:16:26 -04:00
dashboardService := dashboards . NewFakeDashboardService ( t )
2022-02-16 14:15:44 +01:00
2022-02-07 12:43:43 +01:00
dataValue , err := simplejson . NewJson ([] byte ( `{"id": 1, "editable": true, "style": "dark"}` ))
require . NoError ( t , err )
2023-01-25 10:36:26 +01:00
qResult := & dashboards . Dashboard { ID : 1 , Data : dataValue }
dashboardService . On ( "GetDashboard" , mock . Anything , mock . AnythingOfType ( "*dashboards.GetDashboardQuery" )). Return ( qResult , nil )
2023-08-29 15:09:09 +02:00
guardian . MockDashboardGuardian ( & guardian . FakeDashboardGuardian { CanViewValue : true })
2019-04-30 13:32:18 +02:00
2022-08-10 11:56:48 +02:00
loggedInUserScenarioWithRole ( t , "When calling GET on" , "GET" , "/api/dashboards/uid/dash" , "/api/dashboards/uid/:uid" , org . RoleEditor , func ( sc * scenarioContext ) {
2022-02-16 14:15:44 +01:00
fakeProvisioningService := provisioning . NewProvisioningServiceMock ( context . Background ())
fakeProvisioningService . GetDashboardProvisionerResolvedPathFunc = func ( name string ) string {
2019-04-30 13:32:18 +02:00
return "/tmp/grafana/dashboards"
}
2023-01-19 18:38:07 +02:00
dash := getDashboardShouldReturn200WithConfig ( t , sc , fakeProvisioningService , dashboardStore , dashboardService , nil )
2022-02-16 14:15:44 +01:00
assert . Equal ( t , "../../../dashboard1.json" , dash . Meta . ProvisionedExternalId , mockSQLStore )
2022-02-07 12:43:43 +01:00
}, mockSQLStore )
2019-10-31 14:27:31 +01:00
2022-08-10 11:56:48 +02:00
loggedInUserScenarioWithRole ( t , "When allowUiUpdates is true and calling GET on" , "GET" , "/api/dashboards/uid/dash" , "/api/dashboards/uid/:uid" , org . RoleEditor , func ( sc * scenarioContext ) {
2022-02-16 14:15:44 +01:00
fakeProvisioningService := provisioning . NewProvisioningServiceMock ( context . Background ())
fakeProvisioningService . GetDashboardProvisionerResolvedPathFunc = func ( name string ) string {
2019-10-31 14:27:31 +01:00
return "/tmp/grafana/dashboards"
}
2022-02-16 14:15:44 +01:00
fakeProvisioningService . GetAllowUIUpdatesFromConfigFunc = func ( name string ) bool {
2019-10-31 14:27:31 +01:00
return true
}
hs := & HTTPServer {
2022-02-16 14:15:44 +01:00
Cfg : setting . NewCfg (),
ProvisioningService : fakeProvisioningService ,
LibraryPanelService : & mockLibraryPanelService {},
2024-09-27 14:22:29 +02:00
LibraryElementService : & libraryelementsfake . LibraryElementService {},
2022-02-16 14:15:44 +01:00
dashboardProvisioningService : mockDashboardProvisioningService {},
SQLStore : mockSQLStore ,
2022-04-04 11:57:43 -03:00
AccessControl : accesscontrolmock . New (),
2022-07-06 12:42:39 -06:00
DashboardService : dashboardService ,
2022-07-19 17:44:41 -06:00
Features : featuremgmt . WithFeatures (),
2023-08-09 08:54:52 +02:00
starService : startest . NewStarServiceFake (),
2024-06-26 12:03:13 -08:00
tracer : tracing . InitializeTracerForTest (),
2019-10-31 14:27:31 +01:00
}
2022-02-07 12:43:43 +01:00
hs . callGetDashboard ( sc )
2019-10-31 14:27:31 +01:00
2023-08-30 16:51:18 +02:00
assert . Equal ( t , http . StatusOK , sc . resp . Code )
2019-10-31 14:27:31 +01:00
dash := dtos . DashboardFullWithMeta {}
err := json . NewDecoder ( sc . resp . Body ). Decode ( & dash )
2020-11-13 09:52:38 +01:00
require . NoError ( t , err )
2019-10-31 14:27:31 +01:00
2020-11-13 09:52:38 +01:00
assert . Equal ( t , false , dash . Meta . Provisioned )
2022-02-07 12:43:43 +01:00
}, mockSQLStore )
2019-04-10 13:29:10 +02:00
})
2017-06-12 15:48:55 +02:00
}
2017-06-12 23:05:32 +02:00
2023-03-30 17:31:53 +03:00
func TestDashboardVersionsAPIEndpoint ( t * testing . T ) {
fakeDash := dashboards . NewDashboard ( "Child dash" )
fakeDashboardVersionService := dashvertest . NewDashboardVersionServiceFake ()
dashboardService := dashboards . NewFakeDashboardService ( t )
dashboardService . On ( "GetDashboard" , mock . Anything , mock . AnythingOfType ( "*dashboards.GetDashboardQuery" )). Return ( fakeDash , nil )
mockSQLStore := dbtest . NewFakeDB ()
cfg := setting . NewCfg ()
getHS := func ( userSvc * usertest . FakeUserService ) * HTTPServer {
return & HTTPServer {
Cfg : cfg ,
2023-09-11 13:59:24 +02:00
pluginStore : & pluginstore . FakePluginStore {},
2023-03-30 17:31:53 +03:00
SQLStore : mockSQLStore ,
AccessControl : accesscontrolmock . New (),
Features : featuremgmt . WithFeatures (),
DashboardService : dashboardService ,
dashboardVersionService : fakeDashboardVersionService ,
QuotaService : quotatest . New ( false , nil ),
userService : userSvc ,
CacheService : localcache . New ( 5 * time . Minute , 10 * time . Minute ),
log : log . New (),
2024-06-26 12:03:13 -08:00
tracer : tracing . InitializeTracerForTest (),
2023-03-30 17:31:53 +03:00
}
}
setUp := func () {
2023-08-29 15:09:09 +02:00
guardian . MockDashboardGuardian ( & guardian . FakeDashboardGuardian { CanSaveValue : true })
2023-03-30 17:31:53 +03:00
}
loggedInUserScenarioWithRole ( t , "When user exists and calling GET on" , "GET" , "/api/dashboards/id/2/versions" ,
"/api/dashboards/id/:dashboardId/versions" , org . RoleEditor , func ( sc * scenarioContext ) {
setUp ()
fakeDashboardVersionService . ExpectedListDashboarVersions = [] * dashver . DashboardVersionDTO {
{
Version : 1 ,
CreatedBy : 1 ,
},
{
Version : 2 ,
CreatedBy : 1 ,
},
}
getHS ( & usertest . FakeUserService {
ExpectedUser : & user . User { ID : 1 , Login : "test-user" },
}). callGetDashboardVersions ( sc )
2023-08-30 16:51:18 +02:00
assert . Equal ( t , http . StatusOK , sc . resp . Code )
2023-03-30 17:31:53 +03:00
var versions [] dashver . DashboardVersionMeta
err := json . NewDecoder ( sc . resp . Body ). Decode ( & versions )
require . NoError ( t , err )
for _ , v := range versions {
assert . Equal ( t , "test-user" , v . CreatedBy )
}
}, mockSQLStore )
loggedInUserScenarioWithRole ( t , "When user does not exist and calling GET on" , "GET" , "/api/dashboards/id/2/versions" ,
"/api/dashboards/id/:dashboardId/versions" , org . RoleEditor , func ( sc * scenarioContext ) {
setUp ()
fakeDashboardVersionService . ExpectedListDashboarVersions = [] * dashver . DashboardVersionDTO {
{
Version : 1 ,
CreatedBy : 1 ,
},
{
Version : 2 ,
CreatedBy : 1 ,
},
}
getHS ( & usertest . FakeUserService {
ExpectedError : user . ErrUserNotFound ,
}). callGetDashboardVersions ( sc )
2023-08-30 16:51:18 +02:00
assert . Equal ( t , http . StatusOK , sc . resp . Code )
2023-03-30 17:31:53 +03:00
var versions [] dashver . DashboardVersionMeta
err := json . NewDecoder ( sc . resp . Body ). Decode ( & versions )
require . NoError ( t , err )
for _ , v := range versions {
assert . Equal ( t , anonString , v . CreatedBy )
}
}, mockSQLStore )
loggedInUserScenarioWithRole ( t , "When failing to get user and calling GET on" , "GET" , "/api/dashboards/id/2/versions" ,
"/api/dashboards/id/:dashboardId/versions" , org . RoleEditor , func ( sc * scenarioContext ) {
setUp ()
fakeDashboardVersionService . ExpectedListDashboarVersions = [] * dashver . DashboardVersionDTO {
{
Version : 1 ,
CreatedBy : 1 ,
},
{
Version : 2 ,
CreatedBy : 1 ,
},
}
getHS ( & usertest . FakeUserService {
ExpectedError : fmt . Errorf ( "some error" ),
}). callGetDashboardVersions ( sc )
2023-08-30 16:51:18 +02:00
assert . Equal ( t , http . StatusOK , sc . resp . Code )
2023-03-30 17:31:53 +03:00
var versions [] dashver . DashboardVersionMeta
err := json . NewDecoder ( sc . resp . Body ). Decode ( & versions )
require . NoError ( t , err )
for _ , v := range versions {
assert . Equal ( t , anonString , v . CreatedBy )
}
}, mockSQLStore )
}
2023-02-01 15:43:21 +02:00
func getDashboardShouldReturn200WithConfig ( t * testing . T , sc * scenarioContext , provisioningService provisioning . ProvisioningService , dashboardStore dashboards . Store , dashboardService dashboards . DashboardService , folderStore folder . FolderStore ) dtos . DashboardFullWithMeta {
2022-02-16 14:15:44 +01:00
t . Helper ()
2019-04-30 13:32:18 +02:00
if provisioningService == nil {
2021-11-03 11:31:56 +01:00
provisioningService = provisioning . NewProvisioningServiceMock ( context . Background ())
2019-04-30 13:32:18 +02:00
}
2023-11-13 07:55:15 -08:00
features := featuremgmt . WithFeatures ()
2022-11-14 21:08:10 +02:00
var err error
2022-02-16 14:15:44 +01:00
if dashboardStore == nil {
2024-09-25 15:21:39 -08:00
sql , cfg := db . InitTestDBWithCfg ( t )
2022-11-14 21:08:10 +02:00
quotaService := quotatest . New ( false , nil )
2024-04-24 10:38:40 +02:00
dashboardStore , err = database . ProvideDashboardStore ( sql , cfg , features , tagimpl . ProvideService ( sql ), quotaService )
2022-11-14 21:08:10 +02:00
require . NoError ( t , err )
2022-02-16 14:15:44 +01:00
}
2021-05-12 08:48:17 +02:00
libraryPanelsService := mockLibraryPanelService {}
2024-09-27 14:22:29 +02:00
libraryElementsService := libraryelementsfake . LibraryElementService {}
2022-03-10 12:58:18 +01:00
cfg := setting . NewCfg ()
2022-06-07 11:02:20 +02:00
ac := accesscontrolmock . New ()
folderPermissions := accesscontrolmock . NewMockedPermissionsService ()
dashboardPermissions := accesscontrolmock . NewMockedPermissionsService ()
2021-05-12 08:48:17 +02:00
2024-09-30 10:28:47 +02:00
db := db . InitTestDB ( t )
fStore := folderimpl . ProvideStore ( db )
folderSvc := folderimpl . ProvideService ( fStore , ac , bus . ProvideBus ( tracing . InitializeTracerForTest ()),
2024-10-01 14:03:02 +02:00
dashboardStore , folderStore , db , features , cfg , folderPermissions ,
2024-09-30 10:28:47 +02:00
supportbundlestest . NewFakeBundleService (), nil , tracing . InitializeTracerForTest ())
2022-05-23 11:14:27 -04:00
if dashboardService == nil {
2023-04-14 11:17:23 +02:00
dashboardService , err = service . ProvideDashboardServiceImpl (
2024-03-14 15:36:35 +01:00
cfg , dashboardStore , folderStore , features , folderPermissions , dashboardPermissions ,
2024-09-30 10:28:47 +02:00
ac , folderSvc , fStore , nil ,
2022-06-07 11:02:20 +02:00
)
2023-04-14 11:17:23 +02:00
require . NoError ( t , err )
2022-05-23 11:14:27 -04:00
}
2023-04-14 11:17:23 +02:00
dashboardProvisioningService , err := service . ProvideDashboardServiceImpl (
2024-03-14 15:36:35 +01:00
cfg , dashboardStore , folderStore , features , folderPermissions , dashboardPermissions ,
2024-09-30 10:28:47 +02:00
ac , folderSvc , fStore , nil ,
2023-04-14 11:17:23 +02:00
)
require . NoError ( t , err )
2019-04-30 13:32:18 +02:00
hs := & HTTPServer {
2023-04-14 11:17:23 +02:00
Cfg : cfg ,
LibraryPanelService : & libraryPanelsService ,
LibraryElementService : & libraryElementsService ,
SQLStore : sc . sqlStore ,
ProvisioningService : provisioningService ,
AccessControl : accesscontrolmock . New (),
dashboardProvisioningService : dashboardProvisioningService ,
DashboardService : dashboardService ,
Features : featuremgmt . WithFeatures (),
2023-08-09 08:54:52 +02:00
starService : startest . NewStarServiceFake (),
2024-06-26 12:03:13 -08:00
tracer : tracing . InitializeTracerForTest (),
2019-04-30 13:32:18 +02:00
}
2021-05-12 08:48:17 +02:00
2022-02-07 12:43:43 +01:00
hs . callGetDashboard ( sc )
2017-06-12 23:05:32 +02:00
2020-11-13 09:52:38 +01:00
require . Equal ( sc . t , 200 , sc . resp . Code )
2017-06-12 23:05:32 +02:00
dash := dtos . DashboardFullWithMeta {}
2022-11-14 21:08:10 +02:00
err = json . NewDecoder ( sc . resp . Body ). Decode ( & dash )
2020-11-13 09:52:38 +01:00
require . NoError ( sc . t , err )
2017-06-12 23:05:32 +02:00
return dash
}
2022-02-07 12:43:43 +01:00
func ( hs * HTTPServer ) callGetDashboard ( sc * scenarioContext ) {
2019-04-30 13:32:18 +02:00
sc . handlerFunc = hs . GetDashboard
2018-01-29 13:51:01 +01:00
sc . fakeReqWithParams ( "GET" , sc . url , map [ string ] string {}). exec ()
}
2022-02-07 12:43:43 +01:00
func ( hs * HTTPServer ) callGetDashboardVersions ( sc * scenarioContext ) {
sc . handlerFunc = hs . GetDashboardVersions
2017-06-14 00:28:34 +02:00
sc . fakeReqWithParams ( "GET" , sc . url , map [ string ] string {}). exec ()
}
2020-11-13 09:52:38 +01:00
func callPostDashboard ( sc * scenarioContext ) {
2017-06-12 23:05:32 +02:00
sc . fakeReqWithParams ( "POST" , sc . url , map [ string ] string {}). exec ()
}
2020-11-13 09:52:38 +01:00
func callRestoreDashboardVersion ( sc * scenarioContext ) {
2019-03-06 14:38:40 +01:00
sc . fakeReqWithParams ( "POST" , sc . url , map [ string ] string {}). exec ()
}
2020-11-13 09:52:38 +01:00
func callPostDashboardShouldReturnSuccess ( sc * scenarioContext ) {
callPostDashboard ( sc )
2018-01-30 23:37:54 +01:00
2020-11-13 09:52:38 +01:00
assert . Equal ( sc . t , 200 , sc . resp . Code )
2018-01-30 23:37:54 +01:00
}
2023-01-18 13:52:41 +01:00
func postDashboardScenario ( t * testing . T , desc string , url string , routePattern string , cmd dashboards . SaveDashboardCommand , dashboardService dashboards . DashboardService , folderService folder . Service , fn scenarioFunc ) {
2020-11-13 09:52:38 +01:00
t . Run ( fmt . Sprintf ( "%s %s" , desc , url ), func ( t * testing . T ) {
2020-12-15 19:09:04 +01:00
cfg := setting . NewCfg ()
2019-02-11 21:12:01 +01:00
hs := HTTPServer {
2022-11-14 21:08:10 +02:00
Cfg : cfg ,
ProvisioningService : provisioning . NewProvisioningServiceMock ( context . Background ()),
Live : newTestLive ( t , db . InitTestDB ( t )),
QuotaService : quotatest . New ( false , nil ),
2023-09-11 13:59:24 +02:00
pluginStore : & pluginstore . FakePluginStore {},
2021-05-12 08:48:17 +02:00
LibraryPanelService : & mockLibraryPanelService {},
2024-09-27 14:22:29 +02:00
LibraryElementService : & libraryelementsfake . LibraryElementService {},
2022-07-06 12:42:39 -06:00
DashboardService : dashboardService ,
2022-02-16 14:15:44 +01:00
folderService : folderService ,
2022-03-03 15:05:47 +01:00
Features : featuremgmt . WithFeatures (),
2022-11-24 14:38:55 +00:00
accesscontrolService : actest . FakeService {},
2023-08-30 16:51:18 +02:00
log : log . New ( "test-logger" ),
2024-06-26 12:03:13 -08:00
tracer : tracing . InitializeTracerForTest (),
2019-02-11 21:12:01 +01:00
}
2020-11-13 09:52:38 +01:00
sc := setupScenarioContext ( t , url )
2023-01-27 08:50:36 +01:00
sc . defaultHandler = routing . Wrap ( func ( c * contextmodel . ReqContext ) response . Response {
2021-11-29 10:18:01 +01:00
c . Req . Body = mockRequestBody ( cmd )
2022-02-09 13:44:38 +01:00
c . Req . Header . Add ( "Content-Type" , "application/json" )
2017-06-12 23:05:32 +02:00
sc . context = c
2023-01-18 13:52:41 +01:00
sc . context . SignedInUser = & user . SignedInUser { OrgID : cmd . OrgID , UserID : cmd . UserID }
2017-06-12 23:05:32 +02:00
2021-11-29 10:18:01 +01:00
return hs . PostDashboard ( c )
2017-06-12 23:05:32 +02:00
})
sc . m . Post ( routePattern , sc . defaultHandler )
fn ( sc )
})
}
2018-01-29 19:27:53 +01:00
2022-05-25 10:41:51 +02:00
func postDiffScenario ( t * testing . T , desc string , url string , routePattern string , cmd dtos . CalculateDiffOptions ,
2024-06-26 12:03:13 -08:00
role org . RoleType , fn scenarioFunc , sqlmock db . DB , fakeDashboardVersionService * dashvertest . FakeDashboardVersionService ,
) {
2020-11-13 09:52:38 +01:00
t . Run ( fmt . Sprintf ( "%s %s" , desc , url ), func ( t * testing . T ) {
2022-02-10 16:58:52 +08:00
cfg := setting . NewCfg ()
2022-12-15 16:34:17 +02:00
dashSvc := dashboards . NewFakeDashboardService ( t )
2022-02-10 16:58:52 +08:00
hs := HTTPServer {
2022-05-25 10:41:51 +02:00
Cfg : cfg ,
ProvisioningService : provisioning . NewProvisioningServiceMock ( context . Background ()),
2022-10-19 09:02:15 -04:00
Live : newTestLive ( t , db . InitTestDB ( t )),
2022-11-14 21:08:10 +02:00
QuotaService : quotatest . New ( false , nil ),
2022-05-25 10:41:51 +02:00
LibraryPanelService : & mockLibraryPanelService {},
2024-09-27 14:22:29 +02:00
LibraryElementService : & libraryelementsfake . LibraryElementService {},
2022-05-25 10:41:51 +02:00
SQLStore : sqlmock ,
dashboardVersionService : fakeDashboardVersionService ,
2022-07-19 17:44:41 -06:00
Features : featuremgmt . WithFeatures (),
2022-12-15 16:34:17 +02:00
DashboardService : dashSvc ,
2024-06-26 12:03:13 -08:00
tracer : tracing . InitializeTracerForTest (),
2022-02-10 16:58:52 +08:00
}
2020-11-13 09:52:38 +01:00
sc := setupScenarioContext ( t , url )
2023-01-27 08:50:36 +01:00
sc . defaultHandler = routing . Wrap ( func ( c * contextmodel . ReqContext ) response . Response {
2021-11-29 10:18:01 +01:00
c . Req . Body = mockRequestBody ( cmd )
2022-02-09 13:44:38 +01:00
c . Req . Header . Add ( "Content-Type" , "application/json" )
2018-02-27 17:53:30 +01:00
sc . context = c
2022-08-10 11:56:48 +02:00
sc . context . SignedInUser = & user . SignedInUser {
2022-08-11 13:28:55 +02:00
OrgID : testOrgID ,
UserID : testUserID ,
2018-02-27 17:53:30 +01:00
}
sc . context . OrgRole = role
2022-02-10 16:58:52 +08:00
return hs . CalculateDashboardDiff ( c )
2018-02-27 17:53:30 +01:00
})
sc . m . Post ( routePattern , sc . defaultHandler )
fn ( sc )
})
}
2022-05-25 10:41:51 +02:00
func restoreDashboardVersionScenario ( t * testing . T , desc string , url string , routePattern string ,
mock * dashboards . FakeDashboardService , fakeDashboardVersionService * dashvertest . FakeDashboardVersionService ,
2024-06-26 12:03:13 -08:00
cmd dtos . RestoreDashboardVersionCommand , fn scenarioFunc , sqlStore db . DB ,
) {
2020-11-13 09:52:38 +01:00
t . Run ( fmt . Sprintf ( "%s %s" , desc , url ), func ( t * testing . T ) {
2020-12-15 19:09:04 +01:00
cfg := setting . NewCfg ()
2023-10-24 10:04:45 +03:00
folderSvc := foldertest . NewFakeService ()
folderSvc . ExpectedFolder = & folder . Folder {}
2019-03-06 14:38:40 +01:00
hs := HTTPServer {
2022-05-25 10:41:51 +02:00
Cfg : cfg ,
ProvisioningService : provisioning . NewProvisioningServiceMock ( context . Background ()),
2022-10-19 09:02:15 -04:00
Live : newTestLive ( t , db . InitTestDB ( t )),
2022-11-14 21:08:10 +02:00
QuotaService : quotatest . New ( false , nil ),
2022-05-25 10:41:51 +02:00
LibraryPanelService : & mockLibraryPanelService {},
2024-09-27 14:22:29 +02:00
LibraryElementService : & libraryelementsfake . LibraryElementService {},
2022-07-06 12:42:39 -06:00
DashboardService : mock ,
2022-05-25 10:41:51 +02:00
SQLStore : sqlStore ,
Features : featuremgmt . WithFeatures (),
dashboardVersionService : fakeDashboardVersionService ,
2022-11-24 14:38:55 +00:00
accesscontrolService : actest . FakeService {},
2023-10-24 10:04:45 +03:00
folderService : folderSvc ,
2024-06-26 12:03:13 -08:00
tracer : tracing . InitializeTracerForTest (),
2019-03-06 14:38:40 +01:00
}
2020-11-13 09:52:38 +01:00
sc := setupScenarioContext ( t , url )
2022-05-17 12:57:27 -04:00
sc . sqlStore = sqlStore
2022-05-25 10:41:51 +02:00
sc . dashboardVersionService = fakeDashboardVersionService
2023-01-27 08:50:36 +01:00
sc . defaultHandler = routing . Wrap ( func ( c * contextmodel . ReqContext ) response . Response {
2021-11-29 10:18:01 +01:00
c . Req . Body = mockRequestBody ( cmd )
2022-02-09 13:44:38 +01:00
c . Req . Header . Add ( "Content-Type" , "application/json" )
2019-03-06 14:38:40 +01:00
sc . context = c
2022-08-10 11:56:48 +02:00
sc . context . SignedInUser = & user . SignedInUser {
2022-08-11 13:28:55 +02:00
OrgID : testOrgID ,
UserID : testUserID ,
2019-03-06 14:38:40 +01:00
}
2022-08-10 11:56:48 +02:00
sc . context . OrgRole = org . RoleAdmin
2019-03-06 14:38:40 +01:00
2021-11-29 10:18:01 +01:00
return hs . RestoreDashboardVersion ( c )
2019-03-06 14:38:40 +01:00
})
sc . m . Post ( routePattern , sc . defaultHandler )
fn ( sc )
})
}
2018-03-22 22:13:46 +01:00
func ( sc * scenarioContext ) ToJSON () * simplejson . Json {
2022-04-12 09:30:34 +02:00
result := simplejson . New ()
err := json . NewDecoder ( sc . resp . Body ). Decode ( result )
2020-11-13 09:52:38 +01:00
require . NoError ( sc . t , err )
2018-01-29 19:27:53 +01:00
return result
}
2019-10-31 14:27:31 +01:00
type mockDashboardProvisioningService struct {
2021-03-12 11:51:02 +01:00
dashboards . DashboardProvisioningService
2019-10-31 14:27:31 +01:00
}
2022-09-21 14:04:01 +02:00
func ( s mockDashboardProvisioningService ) GetProvisionedDashboardDataByDashboardID ( ctx context . Context , dashboardID int64 ) (
2024-06-26 12:03:13 -08:00
* dashboards . DashboardProvisioning , error ,
) {
2021-03-17 16:06:10 +01:00
return nil , nil
2019-10-31 14:27:31 +01:00
}
2021-05-12 08:48:17 +02:00
2024-06-26 12:03:13 -08:00
type mockLibraryPanelService struct {}
2021-05-12 08:48:17 +02:00
2023-09-06 11:16:10 +02:00
var _ librarypanels . Service = ( * mockLibraryPanelService )( nil )
func ( m * mockLibraryPanelService ) ConnectLibraryPanelsForDashboard ( c context . Context , signedInUser identity . Requester , dash * dashboards . Dashboard ) error {
2021-05-12 08:48:17 +02:00
return nil
}
2024-04-09 12:27:43 +02:00
func ( m * mockLibraryPanelService ) ImportLibraryPanelsForDashboard ( c context . Context , signedInUser identity . Requester , libraryPanels * simplejson . Json , panels [] any , folderID int64 , folderUID string ) error {
2021-09-20 10:58:24 +02:00
return nil
}