Chore: Refactor GoConvey in provisioning package (#40892)

* refactor goconvey in some provisioning subpackages

* fix goconvey in provisioning/datasources

* remove goconvey from notifiers subpackage

* finally resolve goconvey in dashboards subpackage
pull/41138/head
Serge Zaitsev 4 years ago committed by GitHub
parent b80fbe03f0
commit 7b15cd0ed2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 270
      pkg/services/provisioning/dashboards/file_reader_test.go
  2. 191
      pkg/services/provisioning/datasources/config_reader_test.go
  3. 240
      pkg/services/provisioning/notifiers/config_reader_test.go
  4. 15
      pkg/services/provisioning/utils/utils_test.go
  5. 171
      pkg/services/provisioning/values/values_test.go

@ -17,7 +17,8 @@ import (
"github.com/grafana/grafana/pkg/util"
"github.com/grafana/grafana/pkg/infra/log"
. "github.com/smartystreets/goconvey/convey"
"github.com/stretchr/testify/require"
)
const (
@ -32,38 +33,43 @@ const (
var fakeService *fakeDashboardProvisioningService
func TestCreatingNewDashboardFileReader(t *testing.T) {
Convey("creating new dashboard file reader", t, func() {
cfg := &config{
setup := func() *config {
return &config{
Name: "Default",
Type: "file",
OrgID: 1,
Folder: "",
Options: map[string]interface{}{},
}
}
Convey("using path parameter", func() {
t.Run("using path parameter", func(t *testing.T) {
cfg := setup()
cfg.Options["path"] = defaultDashboards
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"), nil)
So(err, ShouldBeNil)
So(reader.Path, ShouldNotEqual, "")
require.NoError(t, err)
require.NotEqual(t, reader.Path, "")
})
Convey("using folder as options", func() {
t.Run("using folder as options", func(t *testing.T) {
cfg := setup()
cfg.Options["folder"] = defaultDashboards
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"), nil)
So(err, ShouldBeNil)
So(reader.Path, ShouldNotEqual, "")
require.NoError(t, err)
require.NotEqual(t, reader.Path, "")
})
Convey("using foldersFromFilesStructure as options", func() {
t.Run("using foldersFromFilesStructure as options", func(t *testing.T) {
cfg := setup()
cfg.Options["path"] = foldersFromFilesStructure
cfg.Options["foldersFromFilesStructure"] = true
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"), nil)
So(err, ShouldBeNil)
So(reader.Path, ShouldNotEqual, "")
require.NoError(t, err)
require.NotEqual(t, reader.Path, "")
})
Convey("using full path", func() {
t.Run("using full path", func(t *testing.T) {
cfg := setup()
fullPath := "/var/lib/grafana/dashboards"
if runtime.GOOS == "windows" {
fullPath = `c:\var\lib\grafana`
@ -71,53 +77,56 @@ func TestCreatingNewDashboardFileReader(t *testing.T) {
cfg.Options["folder"] = fullPath
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"), nil)
So(err, ShouldBeNil)
require.NoError(t, err)
So(reader.Path, ShouldEqual, fullPath)
So(filepath.IsAbs(reader.Path), ShouldBeTrue)
require.Equal(t, reader.Path, fullPath)
require.True(t, filepath.IsAbs(reader.Path))
})
Convey("using relative path", func() {
t.Run("using relative path", func(t *testing.T) {
cfg := setup()
cfg.Options["folder"] = defaultDashboards
reader, err := NewDashboardFileReader(cfg, log.New("test-logger"), nil)
So(err, ShouldBeNil)
require.NoError(t, err)
resolvedPath := reader.resolvedPath()
So(filepath.IsAbs(resolvedPath), ShouldBeTrue)
})
require.True(t, filepath.IsAbs(resolvedPath))
})
}
func TestDashboardFileReader(t *testing.T) {
Convey("Dashboard file reader", t, func() {
bus.ClearBusHandlers()
logger := log.New("test.logger")
cfg := &config{}
origNewDashboardProvisioningService := dashboards.NewProvisioningService
Reset(func() {
defer func() {
dashboards.NewProvisioningService = origNewDashboardProvisioningService
})
fakeService = mockDashboardProvisioningService()
}()
setup := func() {
bus.ClearBusHandlers()
fakeService = mockDashboardProvisioningService()
bus.AddHandler("test", mockGetDashboardQuery)
logger := log.New("test.logger")
Convey("Reading dashboards from disk", func() {
cfg := &config{
cfg = &config{
Name: "Default",
Type: "file",
OrgID: 1,
Folder: "",
Options: map[string]interface{}{},
}
}
Convey("Can read default dashboard", func() {
t.Run("Reading dashboards from disk", func(t *testing.T) {
t.Run("Can read default dashboard", func(t *testing.T) {
setup()
cfg.Options["path"] = defaultDashboards
cfg.Folder = "Team A"
reader, err := NewDashboardFileReader(cfg, logger, nil)
So(err, ShouldBeNil)
require.NoError(t, err)
err = reader.walkDisk(context.Background())
So(err, ShouldBeNil)
require.NoError(t, err)
folders := 0
dashboards := 0
@ -130,11 +139,12 @@ func TestDashboardFileReader(t *testing.T) {
}
}
So(folders, ShouldEqual, 1)
So(dashboards, ShouldEqual, 2)
require.Equal(t, folders, 1)
require.Equal(t, dashboards, 2)
})
Convey("Can read default dashboard and replace old version in database", func() {
t.Run("Can read default dashboard and replace old version in database", func(t *testing.T) {
setup()
cfg.Options["path"] = oneDashboard
stat, _ := os.Stat(oneDashboard + "/dashboard1.json")
@ -145,28 +155,29 @@ func TestDashboardFileReader(t *testing.T) {
})
reader, err := NewDashboardFileReader(cfg, logger, nil)
So(err, ShouldBeNil)
require.NoError(t, err)
err = reader.walkDisk(context.Background())
So(err, ShouldBeNil)
require.NoError(t, err)
So(len(fakeService.inserted), ShouldEqual, 1)
require.Equal(t, len(fakeService.inserted), 1)
})
Convey("Dashboard with older timestamp and the same checksum will not replace imported dashboard", func() {
t.Run("Dashboard with older timestamp and the same checksum will not replace imported dashboard", func(t *testing.T) {
setup()
cfg.Options["path"] = oneDashboard
absPath, err := filepath.Abs(oneDashboard + "/dashboard1.json")
So(err, ShouldBeNil)
require.NoError(t, err)
stat, err := os.Stat(oneDashboard + "/dashboard1.json")
So(err, ShouldBeNil)
require.NoError(t, err)
file, err := os.Open(filepath.Clean(absPath))
So(err, ShouldBeNil)
require.NoError(t, err)
t.Cleanup(func() {
_ = file.Close()
})
checksum, err := util.Md5Sum(file)
So(err, ShouldBeNil)
require.NoError(t, err)
fakeService.provisioned = map[string][]*models.DashboardProvisioning{
"Default": {
@ -180,19 +191,20 @@ func TestDashboardFileReader(t *testing.T) {
}
reader, err := NewDashboardFileReader(cfg, logger, nil)
So(err, ShouldBeNil)
require.NoError(t, err)
err = reader.walkDisk(context.Background())
So(err, ShouldBeNil)
So(len(fakeService.inserted), ShouldEqual, 0)
require.NoError(t, err)
require.Equal(t, len(fakeService.inserted), 0)
})
Convey("Dashboard with older timestamp and different checksum will replace imported dashboard", func() {
t.Run("Dashboard with older timestamp and different checksum will replace imported dashboard", func(t *testing.T) {
setup()
cfg.Options["path"] = oneDashboard
absPath, err := filepath.Abs(oneDashboard + "/dashboard1.json")
So(err, ShouldBeNil)
require.NoError(t, err)
stat, err := os.Stat(oneDashboard + "/dashboard1.json")
So(err, ShouldBeNil)
require.NoError(t, err)
fakeService.provisioned = map[string][]*models.DashboardProvisioning{
"Default": {
@ -206,27 +218,28 @@ func TestDashboardFileReader(t *testing.T) {
}
reader, err := NewDashboardFileReader(cfg, logger, nil)
So(err, ShouldBeNil)
require.NoError(t, err)
err = reader.walkDisk(context.Background())
So(err, ShouldBeNil)
So(len(fakeService.inserted), ShouldEqual, 1)
require.NoError(t, err)
require.Equal(t, len(fakeService.inserted), 1)
})
Convey("Dashboard with newer timestamp and the same checksum will not replace imported dashboard", func() {
t.Run("Dashboard with newer timestamp and the same checksum will not replace imported dashboard", func(t *testing.T) {
setup()
cfg.Options["path"] = oneDashboard
absPath, err := filepath.Abs(oneDashboard + "/dashboard1.json")
So(err, ShouldBeNil)
require.NoError(t, err)
stat, err := os.Stat(oneDashboard + "/dashboard1.json")
So(err, ShouldBeNil)
require.NoError(t, err)
file, err := os.Open(filepath.Clean(absPath))
So(err, ShouldBeNil)
require.NoError(t, err)
t.Cleanup(func() {
_ = file.Close()
})
checksum, err := util.Md5Sum(file)
So(err, ShouldBeNil)
require.NoError(t, err)
fakeService.provisioned = map[string][]*models.DashboardProvisioning{
"Default": {
@ -240,19 +253,20 @@ func TestDashboardFileReader(t *testing.T) {
}
reader, err := NewDashboardFileReader(cfg, logger, nil)
So(err, ShouldBeNil)
require.NoError(t, err)
err = reader.walkDisk(context.Background())
So(err, ShouldBeNil)
So(len(fakeService.inserted), ShouldEqual, 0)
require.NoError(t, err)
require.Equal(t, len(fakeService.inserted), 0)
})
Convey("Dashboard with newer timestamp and different checksum should replace imported dashboard", func() {
t.Run("Dashboard with newer timestamp and different checksum should replace imported dashboard", func(t *testing.T) {
setup()
cfg.Options["path"] = oneDashboard
absPath, err := filepath.Abs(oneDashboard + "/dashboard1.json")
So(err, ShouldBeNil)
require.NoError(t, err)
stat, err := os.Stat(oneDashboard + "/dashboard1.json")
So(err, ShouldBeNil)
require.NoError(t, err)
fakeService.provisioned = map[string][]*models.DashboardProvisioning{
"Default": {
@ -266,36 +280,38 @@ func TestDashboardFileReader(t *testing.T) {
}
reader, err := NewDashboardFileReader(cfg, logger, nil)
So(err, ShouldBeNil)
require.NoError(t, err)
err = reader.walkDisk(context.Background())
So(err, ShouldBeNil)
So(len(fakeService.inserted), ShouldEqual, 1)
require.NoError(t, err)
require.Equal(t, len(fakeService.inserted), 1)
})
Convey("Overrides id from dashboard.json files", func() {
t.Run("Overrides id from dashboard.json files", func(t *testing.T) {
setup()
cfg.Options["path"] = containingID
reader, err := NewDashboardFileReader(cfg, logger, nil)
So(err, ShouldBeNil)
require.NoError(t, err)
err = reader.walkDisk(context.Background())
So(err, ShouldBeNil)
require.NoError(t, err)
So(len(fakeService.inserted), ShouldEqual, 1)
require.Equal(t, len(fakeService.inserted), 1)
})
Convey("Get folder from files structure", func() {
t.Run("Get folder from files structure", func(t *testing.T) {
setup()
cfg.Options["path"] = foldersFromFilesStructure
cfg.Options["foldersFromFilesStructure"] = true
reader, err := NewDashboardFileReader(cfg, logger, nil)
So(err, ShouldBeNil)
require.NoError(t, err)
err = reader.walkDisk(context.Background())
So(err, ShouldBeNil)
require.NoError(t, err)
So(len(fakeService.inserted), ShouldEqual, 5)
require.Equal(t, len(fakeService.inserted), 5)
foldersCount := 0
for _, d := range fakeService.inserted {
@ -303,29 +319,30 @@ func TestDashboardFileReader(t *testing.T) {
foldersCount++
}
}
So(foldersCount, ShouldEqual, 2)
require.Equal(t, foldersCount, 2)
foldersAndDashboards := make(map[string]struct{}, 5)
for _, d := range fakeService.inserted {
title := d.Dashboard.Title
if _, ok := foldersAndDashboards[title]; ok {
So(fmt.Errorf("dashboard title %q already exists", title), ShouldBeNil)
require.Nil(t, fmt.Errorf("dashboard title %q already exists", title))
}
switch title {
case "folderOne", "folderTwo":
So(d.Dashboard.IsFolder, ShouldBeTrue)
require.True(t, d.Dashboard.IsFolder)
case "Grafana1", "Grafana2", "RootDashboard":
So(d.Dashboard.IsFolder, ShouldBeFalse)
require.False(t, d.Dashboard.IsFolder)
default:
So(fmt.Errorf("unknown dashboard title %q", title), ShouldBeNil)
require.Nil(t, fmt.Errorf("unknown dashboard title %q", title))
}
foldersAndDashboards[title] = struct{}{}
}
})
Convey("Invalid configuration should return error", func() {
t.Run("Invalid configuration should return error", func(t *testing.T) {
setup()
cfg := &config{
Name: "Default",
Type: "file",
@ -334,31 +351,33 @@ func TestDashboardFileReader(t *testing.T) {
}
_, err := NewDashboardFileReader(cfg, logger, nil)
So(err, ShouldNotBeNil)
require.NotNil(t, err)
})
Convey("Broken dashboards should not cause error", func() {
t.Run("Broken dashboards should not cause error", func(t *testing.T) {
setup()
cfg.Options["path"] = brokenDashboards
_, err := NewDashboardFileReader(cfg, logger, nil)
So(err, ShouldBeNil)
require.NoError(t, err)
})
Convey("Two dashboard providers should be able to provisioned the same dashboard without uid", func() {
t.Run("Two dashboard providers should be able to provisioned the same dashboard without uid", func(t *testing.T) {
setup()
cfg1 := &config{Name: "1", Type: "file", OrgID: 1, Folder: "f1", Options: map[string]interface{}{"path": containingID}}
cfg2 := &config{Name: "2", Type: "file", OrgID: 1, Folder: "f2", Options: map[string]interface{}{"path": containingID}}
reader1, err := NewDashboardFileReader(cfg1, logger, nil)
So(err, ShouldBeNil)
require.NoError(t, err)
err = reader1.walkDisk(context.Background())
So(err, ShouldBeNil)
require.NoError(t, err)
reader2, err := NewDashboardFileReader(cfg2, logger, nil)
So(err, ShouldBeNil)
require.NoError(t, err)
err = reader2.walkDisk(context.Background())
So(err, ShouldBeNil)
require.NoError(t, err)
var folderCount int
var dashCount int
@ -370,12 +389,13 @@ func TestDashboardFileReader(t *testing.T) {
}
}
So(folderCount, ShouldEqual, 2)
So(dashCount, ShouldEqual, 2)
require.Equal(t, folderCount, 2)
require.Equal(t, dashCount, 2)
})
})
Convey("Should not create new folder if folder name is missing", func() {
t.Run("Should not create new folder if folder name is missing", func(t *testing.T) {
setup()
cfg := &config{
Name: "Default",
Type: "file",
@ -387,10 +407,11 @@ func TestDashboardFileReader(t *testing.T) {
}
_, err := getOrCreateFolderID(context.Background(), cfg, fakeService, cfg.Folder)
So(err, ShouldEqual, ErrFolderNameMissing)
require.Equal(t, err, ErrFolderNameMissing)
})
Convey("can get or Create dashboard folder", func() {
t.Run("can get or Create dashboard folder", func(t *testing.T) {
setup()
cfg := &config{
Name: "Default",
Type: "file",
@ -402,33 +423,42 @@ func TestDashboardFileReader(t *testing.T) {
}
folderID, err := getOrCreateFolderID(context.Background(), cfg, fakeService, cfg.Folder)
So(err, ShouldBeNil)
require.NoError(t, err)
inserted := false
for _, d := range fakeService.inserted {
if d.Dashboard.IsFolder && d.Dashboard.Id == folderID {
inserted = true
}
}
So(len(fakeService.inserted), ShouldEqual, 1)
So(inserted, ShouldBeTrue)
require.Equal(t, len(fakeService.inserted), 1)
require.True(t, inserted)
})
Convey("Walking the folder with dashboards", func() {
t.Run("Walking the folder with dashboards", func(t *testing.T) {
setup()
noFiles := map[string]os.FileInfo{}
Convey("should skip dirs that starts with .", func() {
t.Run("should skip dirs that starts with .", func(t *testing.T) {
shouldSkip := createWalkFn(noFiles)("path", &FakeFileInfo{isDirectory: true, name: ".folder"}, nil)
So(shouldSkip, ShouldEqual, filepath.SkipDir)
require.Equal(t, shouldSkip, filepath.SkipDir)
})
Convey("should keep walking if file is not .json", func() {
t.Run("should keep walking if file is not .json", func(t *testing.T) {
shouldSkip := createWalkFn(noFiles)("path", &FakeFileInfo{isDirectory: true, name: "folder"}, nil)
So(shouldSkip, ShouldBeNil)
require.Nil(t, shouldSkip)
})
})
Convey("Given missing dashboard file", func() {
cfg := &config{
t.Run("Given missing dashboard file", func(t *testing.T) {
absPath1, err := filepath.Abs(unprovision + "/dashboard1.json")
require.NoError(t, err)
// This one does not exist on disk, simulating a deleted file
absPath2, err := filepath.Abs(unprovision + "/dashboard2.json")
require.NoError(t, err)
setupFakeService := func() {
setup()
cfg = &config{
Name: "Default",
Type: "file",
OrgID: 1,
@ -442,44 +472,40 @@ func TestDashboardFileReader(t *testing.T) {
{Dashboard: &models.Dashboard{Id: 2}},
}
absPath1, err := filepath.Abs(unprovision + "/dashboard1.json")
So(err, ShouldBeNil)
// This one does not exist on disk, simulating a deleted file
absPath2, err := filepath.Abs(unprovision + "/dashboard2.json")
So(err, ShouldBeNil)
fakeService.provisioned = map[string][]*models.DashboardProvisioning{
"Default": {
{DashboardId: 1, Name: "Default", ExternalId: absPath1},
{DashboardId: 2, Name: "Default", ExternalId: absPath2},
},
}
}
Convey("Missing dashboard should be unprovisioned if DisableDeletion = true", func() {
t.Run("Missing dashboard should be unprovisioned if DisableDeletion = true", func(t *testing.T) {
setupFakeService()
cfg.DisableDeletion = true
reader, err := NewDashboardFileReader(cfg, logger, nil)
So(err, ShouldBeNil)
require.NoError(t, err)
err = reader.walkDisk(context.Background())
So(err, ShouldBeNil)
require.NoError(t, err)
So(len(fakeService.provisioned["Default"]), ShouldEqual, 1)
So(fakeService.provisioned["Default"][0].ExternalId, ShouldEqual, absPath1)
require.Equal(t, len(fakeService.provisioned["Default"]), 1)
require.Equal(t, fakeService.provisioned["Default"][0].ExternalId, absPath1)
})
Convey("Missing dashboard should be deleted if DisableDeletion = false", func() {
t.Run("Missing dashboard should be deleted if DisableDeletion = false", func(t *testing.T) {
setupFakeService()
reader, err := NewDashboardFileReader(cfg, logger, nil)
So(err, ShouldBeNil)
require.NoError(t, err)
err = reader.walkDisk(context.Background())
So(err, ShouldBeNil)
require.NoError(t, err)
So(len(fakeService.provisioned["Default"]), ShouldEqual, 1)
So(fakeService.provisioned["Default"][0].ExternalId, ShouldEqual, absPath1)
So(len(fakeService.inserted), ShouldEqual, 1)
So(fakeService.inserted[0].Dashboard.Id, ShouldEqual, 1)
})
require.Equal(t, len(fakeService.provisioned["Default"]), 1)
require.Equal(t, fakeService.provisioned["Default"][0].ExternalId, absPath1)
require.Equal(t, len(fakeService.inserted), 1)
require.Equal(t, fakeService.inserted[0].Dashboard.Id, int64(1))
})
})
}

@ -9,7 +9,7 @@ import (
"github.com/grafana/grafana/pkg/infra/log"
"github.com/grafana/grafana/pkg/models"
. "github.com/smartystreets/goconvey/convey"
"github.com/stretchr/testify/require"
)
var (
@ -29,7 +29,7 @@ var (
)
func TestDatasourceAsConfig(t *testing.T) {
Convey("Testing datasource as configuration", t, func() {
setup := func() {
fakeRepo = &fakeRepository{}
bus.ClearBusHandlers()
bus.AddHandler("test", mockDelete)
@ -37,138 +37,142 @@ func TestDatasourceAsConfig(t *testing.T) {
bus.AddHandler("test", mockUpdate)
bus.AddHandler("test", mockGet)
bus.AddHandler("test", mockGetOrg)
}
Convey("apply default values when missing", func() {
t.Run("apply default values when missing", func(t *testing.T) {
setup()
dc := newDatasourceProvisioner(logger)
err := dc.applyChanges(context.Background(), withoutDefaults)
if err != nil {
t.Fatalf("applyChanges return an error %v", err)
}
So(len(fakeRepo.inserted), ShouldEqual, 1)
So(fakeRepo.inserted[0].OrgId, ShouldEqual, 1)
So(fakeRepo.inserted[0].Access, ShouldEqual, "proxy")
require.Equal(t, len(fakeRepo.inserted), 1)
require.Equal(t, fakeRepo.inserted[0].OrgId, int64(1))
require.Equal(t, fakeRepo.inserted[0].Access, models.DsAccess("proxy"))
})
Convey("One configured datasource", func() {
Convey("no datasource in database", func() {
t.Run("no datasource in database", func(t *testing.T) {
setup()
dc := newDatasourceProvisioner(logger)
err := dc.applyChanges(context.Background(), twoDatasourcesConfig)
if err != nil {
t.Fatalf("applyChanges return an error %v", err)
}
So(len(fakeRepo.deleted), ShouldEqual, 0)
So(len(fakeRepo.inserted), ShouldEqual, 2)
So(len(fakeRepo.updated), ShouldEqual, 0)
require.Equal(t, len(fakeRepo.deleted), 0)
require.Equal(t, len(fakeRepo.inserted), 2)
require.Equal(t, len(fakeRepo.updated), 0)
})
Convey("One datasource in database with same name", func() {
t.Run("One datasource in database with same name", func(t *testing.T) {
setup()
fakeRepo.loadAll = []*models.DataSource{
{Name: "Graphite", OrgId: 1, Id: 1},
}
Convey("should update one datasource", func() {
t.Run("should update one datasource", func(t *testing.T) {
dc := newDatasourceProvisioner(logger)
err := dc.applyChanges(context.Background(), twoDatasourcesConfig)
if err != nil {
t.Fatalf("applyChanges return an error %v", err)
}
So(len(fakeRepo.deleted), ShouldEqual, 0)
So(len(fakeRepo.inserted), ShouldEqual, 1)
So(len(fakeRepo.updated), ShouldEqual, 1)
require.Equal(t, len(fakeRepo.deleted), 0)
require.Equal(t, len(fakeRepo.inserted), 1)
require.Equal(t, len(fakeRepo.updated), 1)
})
})
Convey("Two datasources with is_default", func() {
t.Run("Two datasources with is_default", func(t *testing.T) {
setup()
dc := newDatasourceProvisioner(logger)
err := dc.applyChanges(context.Background(), doubleDatasourcesConfig)
Convey("should raise error", func() {
So(err, ShouldEqual, ErrInvalidConfigToManyDefault)
})
})
t.Run("should raise error", func(t *testing.T) { require.Equal(t, err, ErrInvalidConfigToManyDefault) })
})
Convey("Multiple datasources in different organizations with isDefault in each organization", func() {
t.Run("Multiple datasources in different organizations with isDefault in each organization", func(t *testing.T) {
setup()
dc := newDatasourceProvisioner(logger)
err := dc.applyChanges(context.Background(), multipleOrgsWithDefault)
Convey("should not raise error", func() {
So(err, ShouldBeNil)
So(len(fakeRepo.inserted), ShouldEqual, 4)
So(fakeRepo.inserted[0].IsDefault, ShouldBeTrue)
So(fakeRepo.inserted[0].OrgId, ShouldEqual, 1)
So(fakeRepo.inserted[2].IsDefault, ShouldBeTrue)
So(fakeRepo.inserted[2].OrgId, ShouldEqual, 2)
t.Run("should not raise error", func(t *testing.T) {
require.NoError(t, err)
require.Equal(t, len(fakeRepo.inserted), 4)
require.True(t, fakeRepo.inserted[0].IsDefault)
require.Equal(t, fakeRepo.inserted[0].OrgId, int64(1))
require.True(t, fakeRepo.inserted[2].IsDefault)
require.Equal(t, fakeRepo.inserted[2].OrgId, int64(2))
})
})
Convey("Two configured datasource and purge others ", func() {
Convey("two other datasources in database", func() {
t.Run("Two configured datasource and purge others ", func(t *testing.T) {
setup()
t.Run("two other datasources in database", func(t *testing.T) {
fakeRepo.loadAll = []*models.DataSource{
{Name: "old-graphite", OrgId: 1, Id: 1},
{Name: "old-graphite2", OrgId: 1, Id: 2},
}
Convey("should have two new datasources", func() {
t.Run("should have two new datasources", func(t *testing.T) {
dc := newDatasourceProvisioner(logger)
err := dc.applyChanges(context.Background(), twoDatasourcesConfigPurgeOthers)
if err != nil {
t.Fatalf("applyChanges return an error %v", err)
}
So(len(fakeRepo.deleted), ShouldEqual, 2)
So(len(fakeRepo.inserted), ShouldEqual, 2)
So(len(fakeRepo.updated), ShouldEqual, 0)
require.Equal(t, len(fakeRepo.deleted), 2)
require.Equal(t, len(fakeRepo.inserted), 2)
require.Equal(t, len(fakeRepo.updated), 0)
})
})
})
Convey("Two configured datasource and purge others = false", func() {
Convey("two other datasources in database", func() {
t.Run("Two configured datasource and purge others = false", func(t *testing.T) {
setup()
t.Run("two other datasources in database", func(t *testing.T) {
fakeRepo.loadAll = []*models.DataSource{
{Name: "Graphite", OrgId: 1, Id: 1},
{Name: "old-graphite2", OrgId: 1, Id: 2},
}
Convey("should have two new datasources", func() {
t.Run("should have two new datasources", func(t *testing.T) {
dc := newDatasourceProvisioner(logger)
err := dc.applyChanges(context.Background(), twoDatasourcesConfig)
if err != nil {
t.Fatalf("applyChanges return an error %v", err)
}
So(len(fakeRepo.deleted), ShouldEqual, 0)
So(len(fakeRepo.inserted), ShouldEqual, 1)
So(len(fakeRepo.updated), ShouldEqual, 1)
require.Equal(t, len(fakeRepo.deleted), 0)
require.Equal(t, len(fakeRepo.inserted), 1)
require.Equal(t, len(fakeRepo.updated), 1)
})
})
})
Convey("broken yaml should return error", func() {
t.Run("broken yaml should return error", func(t *testing.T) {
reader := &configReader{}
_, err := reader.readConfig(brokenYaml)
So(err, ShouldNotBeNil)
require.NotNil(t, err)
})
Convey("invalid access should warn about invalid value and return 'proxy'", func() {
t.Run("invalid access should warn about invalid value and return 'proxy'", func(t *testing.T) {
reader := &configReader{log: logger}
configs, err := reader.readConfig(invalidAccess)
So(err, ShouldBeNil)
So(configs[0].Datasources[0].Access, ShouldEqual, models.DS_ACCESS_PROXY)
require.NoError(t, err)
require.Equal(t, configs[0].Datasources[0].Access, models.DS_ACCESS_PROXY)
})
Convey("skip invalid directory", func() {
t.Run("skip invalid directory", func(t *testing.T) {
cfgProvider := &configReader{log: log.New("test logger")}
cfg, err := cfgProvider.readConfig("./invalid-directory")
if err != nil {
t.Fatalf("readConfig return an error %v", err)
}
So(len(cfg), ShouldEqual, 0)
require.Equal(t, len(cfg), 0)
})
Convey("can read all properties from version 1", func() {
t.Run("can read all properties from version 1", func(t *testing.T) {
_ = os.Setenv("TEST_VAR", "name")
cfgProvider := &configReader{log: log.New("test logger")}
cfg, err := cfgProvider.readConfig(allProperties)
@ -177,14 +181,14 @@ func TestDatasourceAsConfig(t *testing.T) {
t.Fatalf("readConfig return an error %v", err)
}
So(len(cfg), ShouldEqual, 3)
require.Equal(t, len(cfg), 3)
dsCfg := cfg[0]
So(dsCfg.APIVersion, ShouldEqual, 1)
require.Equal(t, dsCfg.APIVersion, int64(1))
validateDatasourceV1(dsCfg)
validateDeleteDatasources(dsCfg)
validateDatasourceV1(t, dsCfg)
validateDeleteDatasources(t, dsCfg)
dsCount := 0
delDsCount := 0
@ -194,69 +198,68 @@ func TestDatasourceAsConfig(t *testing.T) {
delDsCount += len(c.DeleteDatasources)
}
So(dsCount, ShouldEqual, 2)
So(delDsCount, ShouldEqual, 1)
require.Equal(t, dsCount, 2)
require.Equal(t, delDsCount, 1)
})
Convey("can read all properties from version 0", func() {
t.Run("can read all properties from version 0", func(t *testing.T) {
cfgProvider := &configReader{log: log.New("test logger")}
cfg, err := cfgProvider.readConfig(versionZero)
if err != nil {
t.Fatalf("readConfig return an error %v", err)
}
So(len(cfg), ShouldEqual, 1)
require.Equal(t, len(cfg), 1)
dsCfg := cfg[0]
So(dsCfg.APIVersion, ShouldEqual, 0)
require.Equal(t, dsCfg.APIVersion, int64(0))
validateDatasource(dsCfg)
validateDeleteDatasources(dsCfg)
})
validateDatasource(t, dsCfg)
validateDeleteDatasources(t, dsCfg)
})
}
func validateDeleteDatasources(dsCfg *configs) {
So(len(dsCfg.DeleteDatasources), ShouldEqual, 1)
func validateDeleteDatasources(t *testing.T, dsCfg *configs) {
require.Equal(t, len(dsCfg.DeleteDatasources), 1)
deleteDs := dsCfg.DeleteDatasources[0]
So(deleteDs.Name, ShouldEqual, "old-graphite3")
So(deleteDs.OrgID, ShouldEqual, 2)
require.Equal(t, deleteDs.Name, "old-graphite3")
require.Equal(t, deleteDs.OrgID, int64(2))
}
func validateDatasource(dsCfg *configs) {
func validateDatasource(t *testing.T, dsCfg *configs) {
ds := dsCfg.Datasources[0]
So(ds.Name, ShouldEqual, "name")
So(ds.Type, ShouldEqual, "type")
So(ds.Access, ShouldEqual, models.DS_ACCESS_PROXY)
So(ds.OrgID, ShouldEqual, 2)
So(ds.URL, ShouldEqual, "url")
So(ds.User, ShouldEqual, "user")
So(ds.Password, ShouldEqual, "password")
So(ds.Database, ShouldEqual, "database")
So(ds.BasicAuth, ShouldBeTrue)
So(ds.BasicAuthUser, ShouldEqual, "basic_auth_user")
So(ds.BasicAuthPassword, ShouldEqual, "basic_auth_password")
So(ds.WithCredentials, ShouldBeTrue)
So(ds.IsDefault, ShouldBeTrue)
So(ds.Editable, ShouldBeTrue)
So(ds.Version, ShouldEqual, 10)
So(len(ds.JSONData), ShouldBeGreaterThan, 2)
So(ds.JSONData["graphiteVersion"], ShouldEqual, "1.1")
So(ds.JSONData["tlsAuth"], ShouldEqual, true)
So(ds.JSONData["tlsAuthWithCACert"], ShouldEqual, true)
So(len(ds.SecureJSONData), ShouldBeGreaterThan, 2)
So(ds.SecureJSONData["tlsCACert"], ShouldEqual, "MjNOcW9RdkbUDHZmpco2HCYzVq9dE+i6Yi+gmUJotq5CDA==")
So(ds.SecureJSONData["tlsClientCert"], ShouldEqual, "ckN0dGlyMXN503YNfjTcf9CV+GGQneN+xmAclQ==")
So(ds.SecureJSONData["tlsClientKey"], ShouldEqual, "ZkN4aG1aNkja/gKAB1wlnKFIsy2SRDq4slrM0A==")
require.Equal(t, ds.Name, "name")
require.Equal(t, ds.Type, "type")
require.Equal(t, ds.Access, models.DS_ACCESS_PROXY)
require.Equal(t, ds.OrgID, int64(2))
require.Equal(t, ds.URL, "url")
require.Equal(t, ds.User, "user")
require.Equal(t, ds.Password, "password")
require.Equal(t, ds.Database, "database")
require.True(t, ds.BasicAuth)
require.Equal(t, ds.BasicAuthUser, "basic_auth_user")
require.Equal(t, ds.BasicAuthPassword, "basic_auth_password")
require.True(t, ds.WithCredentials)
require.True(t, ds.IsDefault)
require.True(t, ds.Editable)
require.Equal(t, ds.Version, 10)
require.Greater(t, len(ds.JSONData), 2)
require.Equal(t, ds.JSONData["graphiteVersion"], "1.1")
require.Equal(t, ds.JSONData["tlsAuth"], true)
require.Equal(t, ds.JSONData["tlsAuthWithCACert"], true)
require.Greater(t, len(ds.SecureJSONData), 2)
require.Equal(t, ds.SecureJSONData["tlsCACert"], "MjNOcW9RdkbUDHZmpco2HCYzVq9dE+i6Yi+gmUJotq5CDA==")
require.Equal(t, ds.SecureJSONData["tlsClientCert"], "ckN0dGlyMXN503YNfjTcf9CV+GGQneN+xmAclQ==")
require.Equal(t, ds.SecureJSONData["tlsClientKey"], "ZkN4aG1aNkja/gKAB1wlnKFIsy2SRDq4slrM0A==")
}
func validateDatasourceV1(dsCfg *configs) {
validateDatasource(dsCfg)
func validateDatasourceV1(t *testing.T, dsCfg *configs) {
validateDatasource(t, dsCfg)
ds := dsCfg.Datasources[0]
So(ds.UID, ShouldEqual, "test_uid")
require.Equal(t, ds.UID, "test_uid")
}
type fakeRepository struct {

@ -12,7 +12,8 @@ import (
"github.com/grafana/grafana/pkg/services/alerting/notifiers"
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
"github.com/grafana/grafana/pkg/services/sqlstore"
. "github.com/smartystreets/goconvey/convey"
"github.com/stretchr/testify/require"
)
var (
@ -29,16 +30,18 @@ var (
)
func TestNotificationAsConfig(t *testing.T) {
var sqlStore *sqlstore.SQLStore
logger := log.New("fake.log")
Convey("Testing notification as configuration", t, func() {
sqlStore := sqlstore.InitTestDB(t)
t.Run("Testing notification as configuration", func(t *testing.T) {
setup := func() {
sqlStore = sqlstore.InitTestDB(t)
setupBusHandlers(sqlStore)
for i := 1; i < 5; i++ {
orgCommand := models.CreateOrgCommand{Name: fmt.Sprintf("Main Org. %v", i)}
err := sqlstore.CreateOrg(&orgCommand)
So(err, ShouldBeNil)
require.NoError(t, err)
}
alerting.RegisterNotifier(&alerting.NotifierPlugin{
@ -52,8 +55,10 @@ func TestNotificationAsConfig(t *testing.T) {
Name: "email",
Factory: notifiers.NewEmailNotifier,
})
}
Convey("Can read correct properties", func() {
t.Run("Can read correct properties", func(t *testing.T) {
setup()
_ = os.Setenv("TEST_VAR", "default")
cfgProvider := &configReader{
encryptionService: ossencryption.ProvideService(),
@ -65,73 +70,74 @@ func TestNotificationAsConfig(t *testing.T) {
if err != nil {
t.Fatalf("readConfig return an error %v", err)
}
So(len(cfg), ShouldEqual, 1)
require.Equal(t, len(cfg), 1)
ntCfg := cfg[0]
nts := ntCfg.Notifications
So(len(nts), ShouldEqual, 4)
require.Equal(t, len(nts), 4)
nt := nts[0]
So(nt.Name, ShouldEqual, "default-slack-notification")
So(nt.Type, ShouldEqual, "slack")
So(nt.OrgID, ShouldEqual, 2)
So(nt.UID, ShouldEqual, "notifier1")
So(nt.IsDefault, ShouldBeTrue)
So(nt.Settings, ShouldResemble, map[string]interface{}{
require.Equal(t, nt.Name, "default-slack-notification")
require.Equal(t, nt.Type, "slack")
require.Equal(t, nt.OrgID, int64(2))
require.Equal(t, nt.UID, "notifier1")
require.True(t, nt.IsDefault)
require.Equal(t, nt.Settings, map[string]interface{}{
"recipient": "XXX", "token": "xoxb", "uploadImage": true, "url": "https://slack.com",
})
So(nt.SecureSettings, ShouldResemble, map[string]string{
require.Equal(t, nt.SecureSettings, map[string]string{
"token": "xoxbsecure", "url": "https://slack.com/secure",
})
So(nt.SendReminder, ShouldBeTrue)
So(nt.Frequency, ShouldEqual, "1h")
require.True(t, nt.SendReminder)
require.Equal(t, nt.Frequency, "1h")
nt = nts[1]
So(nt.Name, ShouldEqual, "another-not-default-notification")
So(nt.Type, ShouldEqual, "email")
So(nt.OrgID, ShouldEqual, 3)
So(nt.UID, ShouldEqual, "notifier2")
So(nt.IsDefault, ShouldBeFalse)
require.Equal(t, nt.Name, "another-not-default-notification")
require.Equal(t, nt.Type, "email")
require.Equal(t, nt.OrgID, int64(3))
require.Equal(t, nt.UID, "notifier2")
require.False(t, nt.IsDefault)
nt = nts[2]
So(nt.Name, ShouldEqual, "check-unset-is_default-is-false")
So(nt.Type, ShouldEqual, "slack")
So(nt.OrgID, ShouldEqual, 3)
So(nt.UID, ShouldEqual, "notifier3")
So(nt.IsDefault, ShouldBeFalse)
require.Equal(t, nt.Name, "check-unset-is_default-is-false")
require.Equal(t, nt.Type, "slack")
require.Equal(t, nt.OrgID, int64(3))
require.Equal(t, nt.UID, "notifier3")
require.False(t, nt.IsDefault)
nt = nts[3]
So(nt.Name, ShouldEqual, "Added notification with whitespaces in name")
So(nt.Type, ShouldEqual, "email")
So(nt.UID, ShouldEqual, "notifier4")
So(nt.OrgID, ShouldEqual, 3)
require.Equal(t, nt.Name, "Added notification with whitespaces in name")
require.Equal(t, nt.Type, "email")
require.Equal(t, nt.UID, "notifier4")
require.Equal(t, nt.OrgID, int64(3))
deleteNts := ntCfg.DeleteNotifications
So(len(deleteNts), ShouldEqual, 4)
require.Equal(t, len(deleteNts), 4)
deleteNt := deleteNts[0]
So(deleteNt.Name, ShouldEqual, "default-slack-notification")
So(deleteNt.UID, ShouldEqual, "notifier1")
So(deleteNt.OrgID, ShouldEqual, 2)
require.Equal(t, deleteNt.Name, "default-slack-notification")
require.Equal(t, deleteNt.UID, "notifier1")
require.Equal(t, deleteNt.OrgID, int64(2))
deleteNt = deleteNts[1]
So(deleteNt.Name, ShouldEqual, "deleted-notification-without-orgId")
So(deleteNt.OrgID, ShouldEqual, 1)
So(deleteNt.UID, ShouldEqual, "notifier2")
require.Equal(t, deleteNt.Name, "deleted-notification-without-orgId")
require.Equal(t, deleteNt.OrgID, int64(1))
require.Equal(t, deleteNt.UID, "notifier2")
deleteNt = deleteNts[2]
So(deleteNt.Name, ShouldEqual, "deleted-notification-with-0-orgId")
So(deleteNt.OrgID, ShouldEqual, 1)
So(deleteNt.UID, ShouldEqual, "notifier3")
require.Equal(t, deleteNt.Name, "deleted-notification-with-0-orgId")
require.Equal(t, deleteNt.OrgID, int64(1))
require.Equal(t, deleteNt.UID, "notifier3")
deleteNt = deleteNts[3]
So(deleteNt.Name, ShouldEqual, "Deleted notification with whitespaces in name")
So(deleteNt.OrgID, ShouldEqual, 1)
So(deleteNt.UID, ShouldEqual, "notifier4")
require.Equal(t, deleteNt.Name, "Deleted notification with whitespaces in name")
require.Equal(t, deleteNt.OrgID, int64(1))
require.Equal(t, deleteNt.UID, "notifier4")
})
Convey("One configured notification", func() {
Convey("no notification in database", func() {
t.Run("One configured notification", func(t *testing.T) {
t.Run("no notification in database", func(t *testing.T) {
setup()
dc := newNotificationProvisioner(ossencryption.ProvideService(), logger)
err := dc.applyChanges(twoNotificationsConfig)
@ -140,12 +146,13 @@ func TestNotificationAsConfig(t *testing.T) {
}
notificationsQuery := models.GetAllAlertNotificationsQuery{OrgId: 1}
err = sqlStore.GetAllAlertNotifications(&notificationsQuery)
So(err, ShouldBeNil)
So(notificationsQuery.Result, ShouldNotBeNil)
So(len(notificationsQuery.Result), ShouldEqual, 2)
require.NoError(t, err)
require.NotNil(t, notificationsQuery.Result)
require.Equal(t, len(notificationsQuery.Result), 2)
})
Convey("One notification in database with same name and uid", func() {
t.Run("One notification in database with same name and uid", func(t *testing.T) {
setup()
existingNotificationCmd := models.CreateAlertNotificationCommand{
Name: "channel1",
OrgId: 1,
@ -153,56 +160,58 @@ func TestNotificationAsConfig(t *testing.T) {
Type: "slack",
}
err := sqlStore.CreateAlertNotificationCommand(&existingNotificationCmd)
So(err, ShouldBeNil)
So(existingNotificationCmd.Result, ShouldNotBeNil)
require.NoError(t, err)
require.NotNil(t, existingNotificationCmd.Result)
notificationsQuery := models.GetAllAlertNotificationsQuery{OrgId: 1}
err = sqlStore.GetAllAlertNotifications(&notificationsQuery)
So(err, ShouldBeNil)
So(notificationsQuery.Result, ShouldNotBeNil)
So(len(notificationsQuery.Result), ShouldEqual, 1)
require.NoError(t, err)
require.NotNil(t, notificationsQuery.Result)
require.Equal(t, len(notificationsQuery.Result), 1)
Convey("should update one notification", func() {
t.Run("should update one notification", func(t *testing.T) {
dc := newNotificationProvisioner(ossencryption.ProvideService(), logger)
err = dc.applyChanges(twoNotificationsConfig)
if err != nil {
t.Fatalf("applyChanges return an error %v", err)
}
err = sqlStore.GetAllAlertNotifications(&notificationsQuery)
So(err, ShouldBeNil)
So(notificationsQuery.Result, ShouldNotBeNil)
So(len(notificationsQuery.Result), ShouldEqual, 2)
require.NoError(t, err)
require.NotNil(t, notificationsQuery.Result)
require.Equal(t, len(notificationsQuery.Result), 2)
nts := notificationsQuery.Result
nt1 := nts[0]
So(nt1.Type, ShouldEqual, "email")
So(nt1.Name, ShouldEqual, "channel1")
So(nt1.Uid, ShouldEqual, "notifier1")
require.Equal(t, nt1.Type, "email")
require.Equal(t, nt1.Name, "channel1")
require.Equal(t, nt1.Uid, "notifier1")
nt2 := nts[1]
So(nt2.Type, ShouldEqual, "slack")
So(nt2.Name, ShouldEqual, "channel2")
So(nt2.Uid, ShouldEqual, "notifier2")
require.Equal(t, nt2.Type, "slack")
require.Equal(t, nt2.Name, "channel2")
require.Equal(t, nt2.Uid, "notifier2")
})
})
Convey("Two notifications with is_default", func() {
t.Run("Two notifications with is_default", func(t *testing.T) {
setup()
dc := newNotificationProvisioner(ossencryption.ProvideService(), logger)
err := dc.applyChanges(doubleNotificationsConfig)
Convey("should both be inserted", func() {
So(err, ShouldBeNil)
t.Run("should both be inserted", func(t *testing.T) {
require.NoError(t, err)
notificationsQuery := models.GetAllAlertNotificationsQuery{OrgId: 1}
err = sqlStore.GetAllAlertNotifications(&notificationsQuery)
So(err, ShouldBeNil)
So(notificationsQuery.Result, ShouldNotBeNil)
So(len(notificationsQuery.Result), ShouldEqual, 2)
require.NoError(t, err)
require.NotNil(t, notificationsQuery.Result)
require.Equal(t, len(notificationsQuery.Result), 2)
So(notificationsQuery.Result[0].IsDefault, ShouldBeTrue)
So(notificationsQuery.Result[1].IsDefault, ShouldBeTrue)
require.True(t, notificationsQuery.Result[0].IsDefault)
require.True(t, notificationsQuery.Result[1].IsDefault)
})
})
})
Convey("Two configured notification", func() {
Convey("two other notifications in database", func() {
t.Run("Two configured notification", func(t *testing.T) {
t.Run("two other notifications in database", func(t *testing.T) {
setup()
existingNotificationCmd := models.CreateAlertNotificationCommand{
Name: "channel0",
OrgId: 1,
@ -210,7 +219,7 @@ func TestNotificationAsConfig(t *testing.T) {
Type: "slack",
}
err := sqlStore.CreateAlertNotificationCommand(&existingNotificationCmd)
So(err, ShouldBeNil)
require.NoError(t, err)
existingNotificationCmd = models.CreateAlertNotificationCommand{
Name: "channel3",
OrgId: 1,
@ -218,15 +227,15 @@ func TestNotificationAsConfig(t *testing.T) {
Type: "slack",
}
err = sqlStore.CreateAlertNotificationCommand(&existingNotificationCmd)
So(err, ShouldBeNil)
require.NoError(t, err)
notificationsQuery := models.GetAllAlertNotificationsQuery{OrgId: 1}
err = sqlStore.GetAllAlertNotifications(&notificationsQuery)
So(err, ShouldBeNil)
So(notificationsQuery.Result, ShouldNotBeNil)
So(len(notificationsQuery.Result), ShouldEqual, 2)
require.NoError(t, err)
require.NotNil(t, notificationsQuery.Result)
require.Equal(t, len(notificationsQuery.Result), 2)
Convey("should have two new notifications", func() {
t.Run("should have two new notifications", func(t *testing.T) {
dc := newNotificationProvisioner(ossencryption.ProvideService(), logger)
err := dc.applyChanges(twoNotificationsConfig)
if err != nil {
@ -234,22 +243,23 @@ func TestNotificationAsConfig(t *testing.T) {
}
notificationsQuery = models.GetAllAlertNotificationsQuery{OrgId: 1}
err = sqlStore.GetAllAlertNotifications(&notificationsQuery)
So(err, ShouldBeNil)
So(notificationsQuery.Result, ShouldNotBeNil)
So(len(notificationsQuery.Result), ShouldEqual, 4)
require.NoError(t, err)
require.NotNil(t, notificationsQuery.Result)
require.Equal(t, len(notificationsQuery.Result), 4)
})
})
})
Convey("Can read correct properties with orgName instead of orgId", func() {
t.Run("Can read correct properties with orgName instead of orgId", func(t *testing.T) {
setup()
existingOrg1 := models.GetOrgByNameQuery{Name: "Main Org. 1"}
err := sqlstore.GetOrgByName(&existingOrg1)
So(err, ShouldBeNil)
So(existingOrg1.Result, ShouldNotBeNil)
require.NoError(t, err)
require.NotNil(t, existingOrg1.Result)
existingOrg2 := models.GetOrgByNameQuery{Name: "Main Org. 2"}
err = sqlstore.GetOrgByName(&existingOrg2)
So(err, ShouldBeNil)
So(existingOrg2.Result, ShouldNotBeNil)
require.NoError(t, err)
require.NotNil(t, existingOrg2.Result)
existingNotificationCmd := models.CreateAlertNotificationCommand{
Name: "default-notification-delete",
@ -258,7 +268,7 @@ func TestNotificationAsConfig(t *testing.T) {
Type: "slack",
}
err = sqlStore.CreateAlertNotificationCommand(&existingNotificationCmd)
So(err, ShouldBeNil)
require.NoError(t, err)
dc := newNotificationProvisioner(ossencryption.ProvideService(), logger)
err = dc.applyChanges(correctPropertiesWithOrgName)
@ -268,29 +278,31 @@ func TestNotificationAsConfig(t *testing.T) {
notificationsQuery := models.GetAllAlertNotificationsQuery{OrgId: existingOrg2.Result.Id}
err = sqlStore.GetAllAlertNotifications(&notificationsQuery)
So(err, ShouldBeNil)
So(notificationsQuery.Result, ShouldNotBeNil)
So(len(notificationsQuery.Result), ShouldEqual, 1)
require.NoError(t, err)
require.NotNil(t, notificationsQuery.Result)
require.Equal(t, len(notificationsQuery.Result), 1)
nt := notificationsQuery.Result[0]
So(nt.Name, ShouldEqual, "default-notification-create")
So(nt.OrgId, ShouldEqual, existingOrg2.Result.Id)
require.Equal(t, nt.Name, "default-notification-create")
require.Equal(t, nt.OrgId, existingOrg2.Result.Id)
})
Convey("Config doesn't contain required field", func() {
t.Run("Config doesn't contain required field", func(t *testing.T) {
setup()
dc := newNotificationProvisioner(ossencryption.ProvideService(), logger)
err := dc.applyChanges(noRequiredFields)
So(err, ShouldNotBeNil)
require.NotNil(t, err)
errString := err.Error()
So(errString, ShouldContainSubstring, "Deleted alert notification item 1 in configuration doesn't contain required field uid")
So(errString, ShouldContainSubstring, "Deleted alert notification item 2 in configuration doesn't contain required field name")
So(errString, ShouldContainSubstring, "Added alert notification item 1 in configuration doesn't contain required field name")
So(errString, ShouldContainSubstring, "Added alert notification item 2 in configuration doesn't contain required field uid")
require.Contains(t, errString, "Deleted alert notification item 1 in configuration doesn't contain required field uid")
require.Contains(t, errString, "Deleted alert notification item 2 in configuration doesn't contain required field name")
require.Contains(t, errString, "Added alert notification item 1 in configuration doesn't contain required field name")
require.Contains(t, errString, "Added alert notification item 2 in configuration doesn't contain required field uid")
})
Convey("Empty yaml file", func() {
Convey("should have not changed repo", func() {
t.Run("Empty yaml file", func(t *testing.T) {
t.Run("should have not changed repo", func(t *testing.T) {
setup()
dc := newNotificationProvisioner(ossencryption.ProvideService(), logger)
err := dc.applyChanges(emptyFile)
if err != nil {
@ -298,22 +310,22 @@ func TestNotificationAsConfig(t *testing.T) {
}
notificationsQuery := models.GetAllAlertNotificationsQuery{OrgId: 1}
err = sqlStore.GetAllAlertNotifications(&notificationsQuery)
So(err, ShouldBeNil)
So(notificationsQuery.Result, ShouldBeEmpty)
require.NoError(t, err)
require.Empty(t, notificationsQuery.Result)
})
})
Convey("Broken yaml should return error", func() {
t.Run("Broken yaml should return error", func(t *testing.T) {
reader := &configReader{
encryptionService: ossencryption.ProvideService(),
log: log.New("test logger"),
}
_, err := reader.readConfig(brokenYaml)
So(err, ShouldNotBeNil)
require.NotNil(t, err)
})
Convey("Skip invalid directory", func() {
t.Run("Skip invalid directory", func(t *testing.T) {
cfgProvider := &configReader{
encryptionService: ossencryption.ProvideService(),
log: log.New("test logger"),
@ -323,27 +335,27 @@ func TestNotificationAsConfig(t *testing.T) {
if err != nil {
t.Fatalf("readConfig return an error %v", err)
}
So(len(cfg), ShouldEqual, 0)
require.Equal(t, len(cfg), 0)
})
Convey("Unknown notifier should return error", func() {
t.Run("Unknown notifier should return error", func(t *testing.T) {
cfgProvider := &configReader{
encryptionService: ossencryption.ProvideService(),
log: log.New("test logger"),
}
_, err := cfgProvider.readConfig(unknownNotifier)
So(err, ShouldNotBeNil)
So(err.Error(), ShouldEqual, `unsupported notification type "nonexisting"`)
require.NotNil(t, err)
require.Equal(t, err.Error(), `unsupported notification type "nonexisting"`)
})
Convey("Read incorrect properties", func() {
t.Run("Read incorrect properties", func(t *testing.T) {
cfgProvider := &configReader{
encryptionService: ossencryption.ProvideService(),
log: log.New("test logger"),
}
_, err := cfgProvider.readConfig(incorrectSettings)
So(err, ShouldNotBeNil)
So(err.Error(), ShouldEqual, "alert validation error: token must be specified when using the Slack chat API")
require.NotNil(t, err)
require.Equal(t, err.Error(), "alert validation error: token must be specified when using the Slack chat API")
})
})
}

@ -5,25 +5,26 @@ import (
"github.com/grafana/grafana/pkg/models"
"github.com/grafana/grafana/pkg/services/sqlstore"
. "github.com/smartystreets/goconvey/convey"
"github.com/stretchr/testify/require"
)
func TestCheckOrgExists(t *testing.T) {
Convey("with default org in database", t, func() {
t.Run("with default org in database", func(t *testing.T) {
sqlstore.InitTestDB(t)
defaultOrg := models.CreateOrgCommand{Name: "Main Org."}
err := sqlstore.CreateOrg(&defaultOrg)
So(err, ShouldBeNil)
require.NoError(t, err)
Convey("default org exists", func() {
t.Run("default org exists", func(t *testing.T) {
err := CheckOrgExists(defaultOrg.Result.Id)
So(err, ShouldBeNil)
require.NoError(t, err)
})
Convey("other org doesn't exist", func() {
t.Run("other org doesn't exist", func(t *testing.T) {
err := CheckOrgExists(defaultOrg.Result.Id + 1)
So(err, ShouldEqual, models.ErrOrgNotFound)
require.Equal(t, err, models.ErrOrgNotFound)
})
})
}

@ -8,132 +8,140 @@ import (
"testing"
"github.com/grafana/grafana/pkg/setting"
"gopkg.in/ini.v1"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
. "github.com/smartystreets/goconvey/convey"
"gopkg.in/ini.v1"
"gopkg.in/yaml.v2"
)
func TestValues(t *testing.T) {
Convey("Values", t, func() {
t.Run("Values", func(t *testing.T) {
err := os.Setenv("INT", "1")
So(err, ShouldBeNil)
require.NoError(t, err)
err = os.Setenv("STRING", "test")
So(err, ShouldBeNil)
require.NoError(t, err)
err = os.Setenv("EMPTYSTRING", "")
So(err, ShouldBeNil)
require.NoError(t, err)
err = os.Setenv("BOOL", "true")
So(err, ShouldBeNil)
require.NoError(t, err)
defer func() {
err := os.Unsetenv("INT")
require.NoError(t, err)
err = os.Unsetenv("STRING")
require.NoError(t, err)
err = os.Unsetenv("EMPTYSTRING")
require.NoError(t, err)
err = os.Unsetenv("BOOL")
require.NoError(t, err)
}()
Convey("IntValue", func() {
t.Run("IntValue", func(t *testing.T) {
type Data struct {
Val IntValue `yaml:"val"`
}
d := &Data{}
Convey("Should unmarshal simple number", func() {
unmarshalingTest(`val: 1`, d)
So(d.Val.Value(), ShouldEqual, 1)
So(d.Val.Raw, ShouldEqual, "1")
t.Run("Should unmarshal simple number", func(t *testing.T) {
unmarshalingTest(t, `val: 1`, d)
require.Equal(t, d.Val.Value(), 1)
require.Equal(t, d.Val.Raw, "1")
})
Convey("Should unmarshal env var", func() {
unmarshalingTest(`val: $INT`, d)
So(d.Val.Value(), ShouldEqual, 1)
So(d.Val.Raw, ShouldEqual, "$INT")
t.Run("Should unmarshal env var", func(t *testing.T) {
unmarshalingTest(t, `val: $INT`, d)
require.Equal(t, d.Val.Value(), 1)
require.Equal(t, d.Val.Raw, "$INT")
})
Convey("Should ignore empty value", func() {
unmarshalingTest(`val: `, d)
So(d.Val.Value(), ShouldEqual, 0)
So(d.Val.Raw, ShouldEqual, "")
t.Run("Should ignore empty value", func(t *testing.T) {
unmarshalingTest(t, `val: `, d)
require.Equal(t, d.Val.Value(), 0)
require.Equal(t, d.Val.Raw, "")
})
})
Convey("StringValue", func() {
t.Run("StringValue", func(t *testing.T) {
type Data struct {
Val StringValue `yaml:"val"`
}
d := &Data{}
Convey("Should unmarshal simple string", func() {
unmarshalingTest(`val: test`, d)
So(d.Val.Value(), ShouldEqual, "test")
So(d.Val.Raw, ShouldEqual, "test")
t.Run("Should unmarshal simple string", func(t *testing.T) {
unmarshalingTest(t, `val: test`, d)
require.Equal(t, d.Val.Value(), "test")
require.Equal(t, d.Val.Raw, "test")
})
Convey("Should unmarshal env var", func() {
unmarshalingTest(`val: $STRING`, d)
So(d.Val.Value(), ShouldEqual, "test")
So(d.Val.Raw, ShouldEqual, "$STRING")
t.Run("Should unmarshal env var", func(t *testing.T) {
unmarshalingTest(t, `val: $STRING`, d)
require.Equal(t, d.Val.Value(), "test")
require.Equal(t, d.Val.Raw, "$STRING")
})
Convey("Should ignore empty value", func() {
unmarshalingTest(`val: `, d)
So(d.Val.Value(), ShouldEqual, "")
So(d.Val.Raw, ShouldEqual, "")
t.Run("Should ignore empty value", func(t *testing.T) {
unmarshalingTest(t, `val: `, d)
require.Equal(t, d.Val.Value(), "")
require.Equal(t, d.Val.Raw, "")
})
Convey("empty var should have empty value", func() {
unmarshalingTest(`val: $EMPTYSTRING`, d)
So(d.Val.Value(), ShouldEqual, "")
So(d.Val.Raw, ShouldEqual, "$EMPTYSTRING")
t.Run("empty var should have empty value", func(t *testing.T) {
unmarshalingTest(t, `val: $EMPTYSTRING`, d)
require.Equal(t, d.Val.Value(), "")
require.Equal(t, d.Val.Raw, "$EMPTYSTRING")
})
Convey("$$ should be a literal $", func() {
unmarshalingTest(`val: $$`, d)
So(d.Val.Value(), ShouldEqual, "$")
So(d.Val.Raw, ShouldEqual, "$$")
t.Run("$$ should be a literal $", func(t *testing.T) {
unmarshalingTest(t, `val: $$`, d)
require.Equal(t, d.Val.Value(), "$")
require.Equal(t, d.Val.Raw, "$$")
})
Convey("$$ should be a literal $ and not expanded within a string", func() {
unmarshalingTest(`val: mY,Passwo$$rd`, d)
So(d.Val.Value(), ShouldEqual, "mY,Passwo$rd")
So(d.Val.Raw, ShouldEqual, "mY,Passwo$$rd")
t.Run("$$ should be a literal $ and not expanded within a string", func(t *testing.T) {
unmarshalingTest(t, `val: mY,Passwo$$rd`, d)
require.Equal(t, d.Val.Value(), "mY,Passwo$rd")
require.Equal(t, d.Val.Raw, "mY,Passwo$$rd")
})
})
Convey("BoolValue", func() {
t.Run("BoolValue", func(t *testing.T) {
type Data struct {
Val BoolValue `yaml:"val"`
}
d := &Data{}
Convey("Should unmarshal bool value", func() {
unmarshalingTest(`val: true`, d)
So(d.Val.Value(), ShouldBeTrue)
So(d.Val.Raw, ShouldEqual, "true")
t.Run("Should unmarshal bool value", func(t *testing.T) {
unmarshalingTest(t, `val: true`, d)
require.True(t, d.Val.Value())
require.Equal(t, d.Val.Raw, "true")
})
Convey("Should unmarshal explicit string", func() {
unmarshalingTest(`val: "true"`, d)
So(d.Val.Value(), ShouldBeTrue)
So(d.Val.Raw, ShouldEqual, "true")
t.Run("Should unmarshal explicit string", func(t *testing.T) {
unmarshalingTest(t, `val: "true"`, d)
require.True(t, d.Val.Value())
require.Equal(t, d.Val.Raw, "true")
})
Convey("Should unmarshal env var", func() {
unmarshalingTest(`val: $BOOL`, d)
So(d.Val.Value(), ShouldBeTrue)
So(d.Val.Raw, ShouldEqual, "$BOOL")
t.Run("Should unmarshal env var", func(t *testing.T) {
unmarshalingTest(t, `val: $BOOL`, d)
require.True(t, d.Val.Value())
require.Equal(t, d.Val.Raw, "$BOOL")
})
Convey("Should ignore empty value", func() {
unmarshalingTest(`val: `, d)
So(d.Val.Value(), ShouldBeFalse)
So(d.Val.Raw, ShouldEqual, "")
t.Run("Should ignore empty value", func(t *testing.T) {
unmarshalingTest(t, `val: `, d)
require.False(t, d.Val.Value())
require.Equal(t, d.Val.Raw, "")
})
})
Convey("JSONValue", func() {
t.Run("JSONValue", func(t *testing.T) {
type Data struct {
Val JSONValue `yaml:"val"`
}
d := &Data{}
Convey("Should unmarshal variable nesting", func() {
t.Run("Should unmarshal variable nesting", func(t *testing.T) {
doc := `
val:
one: 1
@ -153,10 +161,10 @@ func TestValues(t *testing.T) {
anchor: &label $INT
anchored: *label
`
unmarshalingTest(doc, d)
unmarshalingTest(t, doc, d)
type stringMap = map[string]interface{}
So(d.Val.Value(), ShouldResemble, stringMap{
require.Equal(t, d.Val.Value(), stringMap{
"one": 1,
"two": "test",
"three": []interface{}{
@ -183,7 +191,7 @@ func TestValues(t *testing.T) {
"anchored": "1",
})
So(d.Val.Raw, ShouldResemble, stringMap{
require.Equal(t, d.Val.Raw, stringMap{
"one": 1,
"two": "$STRING",
"three": []interface{}{
@ -212,13 +220,13 @@ func TestValues(t *testing.T) {
})
})
Convey("StringMapValue", func() {
t.Run("StringMapValue", func(t *testing.T) {
type Data struct {
Val StringMapValue `yaml:"val"`
}
d := &Data{}
Convey("Should unmarshal mapping", func() {
t.Run("Should unmarshal mapping", func(t *testing.T) {
doc := `
val:
one: 1
@ -226,15 +234,15 @@ func TestValues(t *testing.T) {
three: $STRING
four: true
`
unmarshalingTest(doc, d)
So(d.Val.Value(), ShouldResemble, map[string]string{
unmarshalingTest(t, doc, d)
require.Equal(t, d.Val.Value(), map[string]string{
"one": "1",
"two": "test string",
"three": "test",
"four": "true",
})
So(d.Val.Raw, ShouldResemble, map[string]string{
require.Equal(t, d.Val.Raw, map[string]string{
"one": "1",
"two": "test string",
"three": "$STRING",
@ -242,23 +250,12 @@ func TestValues(t *testing.T) {
})
})
})
Reset(func() {
err := os.Unsetenv("INT")
So(err, ShouldBeNil)
err = os.Unsetenv("STRING")
So(err, ShouldBeNil)
err = os.Unsetenv("EMPTYSTRING")
So(err, ShouldBeNil)
err = os.Unsetenv("BOOL")
So(err, ShouldBeNil)
})
})
}
func unmarshalingTest(document string, out interface{}) {
func unmarshalingTest(t *testing.T, document string, out interface{}) {
err := yaml.Unmarshal([]byte(document), out)
So(err, ShouldBeNil)
require.NoError(t, err)
}
func TestValues_readFile(t *testing.T) {

Loading…
Cancel
Save