mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
tests: for skipping with hidden folders
This commit is contained in:
@@ -18,12 +18,18 @@ import (
|
|||||||
gocache "github.com/patrickmn/go-cache"
|
gocache "github.com/patrickmn/go-cache"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
checkDiskForChangesInterval time.Duration = time.Second * 3
|
||||||
|
)
|
||||||
|
|
||||||
type fileReader struct {
|
type fileReader struct {
|
||||||
Cfg *DashboardsAsConfig
|
Cfg *DashboardsAsConfig
|
||||||
Path string
|
Path string
|
||||||
log log.Logger
|
FolderId int64
|
||||||
dashboardRepo dashboards.Repository
|
log log.Logger
|
||||||
cache *gocache.Cache
|
dashboardRepo dashboards.Repository
|
||||||
|
cache *gocache.Cache
|
||||||
|
createWalkFunc func(fr *fileReader) filepath.WalkFunc
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewDashboardFileReader(cfg *DashboardsAsConfig, log log.Logger) (*fileReader, error) {
|
func NewDashboardFileReader(cfg *DashboardsAsConfig, log log.Logger) (*fileReader, error) {
|
||||||
@@ -37,34 +43,17 @@ func NewDashboardFileReader(cfg *DashboardsAsConfig, log log.Logger) (*fileReade
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &fileReader{
|
return &fileReader{
|
||||||
Cfg: cfg,
|
Cfg: cfg,
|
||||||
Path: path,
|
Path: path,
|
||||||
log: log,
|
log: log,
|
||||||
dashboardRepo: dashboards.GetRepository(),
|
dashboardRepo: dashboards.GetRepository(),
|
||||||
cache: gocache.New(5*time.Minute, 30*time.Minute),
|
cache: gocache.New(5*time.Minute, 30*time.Minute),
|
||||||
|
createWalkFunc: createWalkFn,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fr *fileReader) addCache(key string, json *dashboards.SaveDashboardItem) {
|
|
||||||
fr.cache.Add(key, json, time.Minute*10)
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fr *fileReader) getCache(key string) (*dashboards.SaveDashboardItem, bool) {
|
|
||||||
obj, exist := fr.cache.Get(key)
|
|
||||||
if !exist {
|
|
||||||
return nil, exist
|
|
||||||
}
|
|
||||||
|
|
||||||
dash, ok := obj.(*dashboards.SaveDashboardItem)
|
|
||||||
if !ok {
|
|
||||||
return nil, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
return dash, ok
|
|
||||||
}
|
|
||||||
|
|
||||||
func (fr *fileReader) ReadAndListen(ctx context.Context) error {
|
func (fr *fileReader) ReadAndListen(ctx context.Context) error {
|
||||||
ticker := time.NewTicker(time.Second * 3)
|
ticker := time.NewTicker(checkDiskForChangesInterval)
|
||||||
|
|
||||||
if err := fr.walkFolder(); err != nil {
|
if err := fr.walkFolder(); err != nil {
|
||||||
fr.log.Error("failed to search for dashboards", "error", err)
|
fr.log.Error("failed to search for dashboards", "error", err)
|
||||||
@@ -95,7 +84,11 @@ func (fr *fileReader) walkFolder() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return filepath.Walk(fr.Path, func(path string, fileInfo os.FileInfo, err error) error {
|
return filepath.Walk(fr.Path, fr.createWalkFunc(fr)) //omg this is so ugly :(
|
||||||
|
}
|
||||||
|
|
||||||
|
func createWalkFn(fr *fileReader) filepath.WalkFunc {
|
||||||
|
return func(path string, fileInfo os.FileInfo, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@@ -147,7 +140,7 @@ func (fr *fileReader) walkFolder() error {
|
|||||||
fr.log.Debug("loading dashboard from disk into database.", "file", path)
|
fr.log.Debug("loading dashboard from disk into database.", "file", path)
|
||||||
_, err = fr.dashboardRepo.SaveDashboard(dash)
|
_, err = fr.dashboardRepo.SaveDashboard(dash)
|
||||||
return err
|
return err
|
||||||
})
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fr *fileReader) readDashboardFromFile(path string) (*dashboards.SaveDashboardItem, error) {
|
func (fr *fileReader) readDashboardFromFile(path string) (*dashboards.SaveDashboardItem, error) {
|
||||||
@@ -172,7 +165,25 @@ func (fr *fileReader) readDashboardFromFile(path string) (*dashboards.SaveDashbo
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
fr.addCache(path, dash)
|
fr.addDashboardCache(path, dash)
|
||||||
|
|
||||||
return dash, nil
|
return dash, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (fr *fileReader) addDashboardCache(key string, json *dashboards.SaveDashboardItem) {
|
||||||
|
fr.cache.Add(key, json, time.Minute*10)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (fr *fileReader) getCache(key string) (*dashboards.SaveDashboardItem, bool) {
|
||||||
|
obj, exist := fr.cache.Get(key)
|
||||||
|
if !exist {
|
||||||
|
return nil, exist
|
||||||
|
}
|
||||||
|
|
||||||
|
dash, ok := obj.(*dashboards.SaveDashboardItem)
|
||||||
|
if !ok {
|
||||||
|
return nil, ok
|
||||||
|
}
|
||||||
|
|
||||||
|
return dash, ok
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package dashboards
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
@@ -22,99 +23,156 @@ var (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func TestDashboardFileReader(t *testing.T) {
|
func TestDashboardFileReader(t *testing.T) {
|
||||||
Convey("Reading dashboards from disk", t, func() {
|
Convey("Dashboard file reader", t, func() {
|
||||||
bus.ClearBusHandlers()
|
Convey("Reading dashboards from disk", func() {
|
||||||
fakeRepo = &fakeDashboardRepo{}
|
|
||||||
|
|
||||||
bus.AddHandler("test", mockGetDashboardQuery)
|
bus.ClearBusHandlers()
|
||||||
dashboards.SetRepository(fakeRepo)
|
fakeRepo = &fakeDashboardRepo{}
|
||||||
logger := log.New("test.logger")
|
|
||||||
|
|
||||||
cfg := &DashboardsAsConfig{
|
bus.AddHandler("test", mockGetDashboardQuery)
|
||||||
Name: "Default",
|
dashboards.SetRepository(fakeRepo)
|
||||||
Type: "file",
|
logger := log.New("test.logger")
|
||||||
OrgId: 1,
|
|
||||||
Folder: "",
|
|
||||||
Options: map[string]interface{}{},
|
|
||||||
}
|
|
||||||
|
|
||||||
Convey("Can read default dashboard", func() {
|
|
||||||
cfg.Options["folder"] = defaultDashboards
|
|
||||||
|
|
||||||
reader, err := NewDashboardFileReader(cfg, logger)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
err = reader.walkFolder()
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
So(len(fakeRepo.inserted), ShouldEqual, 2)
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("Should not update dashboards when db is newer", func() {
|
|
||||||
cfg.Options["folder"] = oneDashboard
|
|
||||||
|
|
||||||
fakeRepo.getDashboard = append(fakeRepo.getDashboard, &models.Dashboard{
|
|
||||||
Updated: time.Now().Add(time.Hour),
|
|
||||||
Slug: "grafana",
|
|
||||||
})
|
|
||||||
|
|
||||||
reader, err := NewDashboardFileReader(cfg, logger)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
err = reader.walkFolder()
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
So(len(fakeRepo.inserted), ShouldEqual, 0)
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("Can read default dashboard and replace old version in database", func() {
|
|
||||||
cfg.Options["folder"] = oneDashboard
|
|
||||||
|
|
||||||
stat, _ := os.Stat(oneDashboard + "/dashboard1.json")
|
|
||||||
|
|
||||||
fakeRepo.getDashboard = append(fakeRepo.getDashboard, &models.Dashboard{
|
|
||||||
Updated: stat.ModTime().AddDate(0, 0, -1),
|
|
||||||
Slug: "grafana",
|
|
||||||
})
|
|
||||||
|
|
||||||
reader, err := NewDashboardFileReader(cfg, logger)
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
err = reader.walkFolder()
|
|
||||||
So(err, ShouldBeNil)
|
|
||||||
|
|
||||||
So(len(fakeRepo.inserted), ShouldEqual, 1)
|
|
||||||
})
|
|
||||||
|
|
||||||
Convey("Invalid configuration should return error", func() {
|
|
||||||
cfg := &DashboardsAsConfig{
|
cfg := &DashboardsAsConfig{
|
||||||
Name: "Default",
|
Name: "Default",
|
||||||
Type: "file",
|
Type: "file",
|
||||||
OrgId: 1,
|
OrgId: 1,
|
||||||
Folder: "",
|
Folder: "",
|
||||||
|
Options: map[string]interface{}{},
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := NewDashboardFileReader(cfg, logger)
|
Convey("Can read default dashboard", func() {
|
||||||
So(err, ShouldNotBeNil)
|
cfg.Options["folder"] = defaultDashboards
|
||||||
|
|
||||||
|
reader, err := NewDashboardFileReader(cfg, logger)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
err = reader.walkFolder()
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
So(len(fakeRepo.inserted), ShouldEqual, 2)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Should not update dashboards when db is newer", func() {
|
||||||
|
cfg.Options["folder"] = oneDashboard
|
||||||
|
|
||||||
|
fakeRepo.getDashboard = append(fakeRepo.getDashboard, &models.Dashboard{
|
||||||
|
Updated: time.Now().Add(time.Hour),
|
||||||
|
Slug: "grafana",
|
||||||
|
})
|
||||||
|
|
||||||
|
reader, err := NewDashboardFileReader(cfg, logger)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
err = reader.walkFolder()
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
So(len(fakeRepo.inserted), ShouldEqual, 0)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Can read default dashboard and replace old version in database", func() {
|
||||||
|
cfg.Options["folder"] = oneDashboard
|
||||||
|
|
||||||
|
stat, _ := os.Stat(oneDashboard + "/dashboard1.json")
|
||||||
|
|
||||||
|
fakeRepo.getDashboard = append(fakeRepo.getDashboard, &models.Dashboard{
|
||||||
|
Updated: stat.ModTime().AddDate(0, 0, -1),
|
||||||
|
Slug: "grafana",
|
||||||
|
})
|
||||||
|
|
||||||
|
reader, err := NewDashboardFileReader(cfg, logger)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
err = reader.walkFolder()
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
So(len(fakeRepo.inserted), ShouldEqual, 1)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Invalid configuration should return error", func() {
|
||||||
|
cfg := &DashboardsAsConfig{
|
||||||
|
Name: "Default",
|
||||||
|
Type: "file",
|
||||||
|
OrgId: 1,
|
||||||
|
Folder: "",
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := NewDashboardFileReader(cfg, logger)
|
||||||
|
So(err, ShouldNotBeNil)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("Broken dashboards should not cause error", func() {
|
||||||
|
cfg := &DashboardsAsConfig{
|
||||||
|
Name: "Default",
|
||||||
|
Type: "file",
|
||||||
|
OrgId: 1,
|
||||||
|
Folder: "",
|
||||||
|
Options: map[string]interface{}{
|
||||||
|
"folder": brokenDashboards,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err := NewDashboardFileReader(cfg, logger)
|
||||||
|
So(err, ShouldBeNil)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
Convey("Broken dashboards should not cause error", func() {
|
Convey("Walking", func() {
|
||||||
cfg := &DashboardsAsConfig{
|
cfg := &DashboardsAsConfig{
|
||||||
Name: "Default",
|
Name: "Default",
|
||||||
Type: "file",
|
Type: "file",
|
||||||
OrgId: 1,
|
OrgId: 1,
|
||||||
Folder: "",
|
Folder: "",
|
||||||
Options: map[string]interface{}{
|
Options: map[string]interface{}{
|
||||||
"folder": brokenDashboards,
|
"folder": defaultDashboards,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err := NewDashboardFileReader(cfg, logger)
|
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"))
|
||||||
So(err, ShouldBeNil)
|
So(err, ShouldBeNil)
|
||||||
|
|
||||||
|
Convey("should skip dirs that starts with .", func() {
|
||||||
|
shouldSkip := reader.createWalkFunc(reader)("path", &FakeFileInfo{isDirectory: true, name: ".folder"}, nil)
|
||||||
|
So(shouldSkip, ShouldEqual, filepath.SkipDir)
|
||||||
|
})
|
||||||
|
|
||||||
|
Convey("should keep walking if file is not .json", func() {
|
||||||
|
shouldSkip := reader.createWalkFunc(reader)("path", &FakeFileInfo{isDirectory: true, name: "folder"}, nil)
|
||||||
|
So(shouldSkip, ShouldBeNil)
|
||||||
|
})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type FakeFileInfo struct {
|
||||||
|
isDirectory bool
|
||||||
|
name string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ffi *FakeFileInfo) IsDir() bool {
|
||||||
|
return ffi.isDirectory
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ffi FakeFileInfo) Size() int64 {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ffi FakeFileInfo) Mode() os.FileMode {
|
||||||
|
return 0777
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ffi FakeFileInfo) Name() string {
|
||||||
|
return ffi.name
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ffi FakeFileInfo) ModTime() time.Time {
|
||||||
|
return time.Time{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (ffi FakeFileInfo) Sys() interface{} {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
type fakeDashboardRepo struct {
|
type fakeDashboardRepo struct {
|
||||||
inserted []*dashboards.SaveDashboardItem
|
inserted []*dashboards.SaveDashboardItem
|
||||||
getDashboard []*models.Dashboard
|
getDashboard []*models.Dashboard
|
||||||
|
|||||||
Reference in New Issue
Block a user